2 * @file mediamanager.c Media Manager API
8 * Purple is the legal property of its developers, whose names are too numerous
9 * to list here. Please refer to the COPYRIGHT file distributed with this
10 * source distribution.
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
32 #include "mediamanager.h"
35 #include "marshallers.h"
36 #include "media-gst.h"
40 #include <media/backend-fs2.h>
42 #include <gst/farsight/fs-element-added-notifier.h>
43 #include <gst/interfaces/xoverlay.h>
45 /** @copydoc _PurpleMediaManagerPrivate */
46 typedef struct _PurpleMediaManagerPrivate PurpleMediaManagerPrivate
;
47 /** @copydoc _PurpleMediaOutputWindow */
48 typedef struct _PurpleMediaOutputWindow PurpleMediaOutputWindow
;
49 /** @copydoc _PurpleMediaManagerPrivate */
50 typedef struct _PurpleMediaElementInfoPrivate PurpleMediaElementInfoPrivate
;
52 /** The media manager class. */
53 struct _PurpleMediaManagerClass
55 GObjectClass parent_class
; /**< The parent class. */
58 /** The media manager's data. */
59 struct _PurpleMediaManager
61 GObject parent
; /**< The parent of this manager. */
62 PurpleMediaManagerPrivate
*priv
; /**< Private data for the manager. */
65 struct _PurpleMediaOutputWindow
75 struct _PurpleMediaManagerPrivate
78 PurpleMediaCaps ui_caps
;
81 GList
*output_windows
;
82 gulong next_output_window_id
;
86 PurpleMediaElementInfo
*video_src
;
87 PurpleMediaElementInfo
*video_sink
;
88 PurpleMediaElementInfo
*audio_src
;
89 PurpleMediaElementInfo
*audio_sink
;
92 #define PURPLE_MEDIA_MANAGER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_MEDIA_MANAGER, PurpleMediaManagerPrivate))
93 #define PURPLE_MEDIA_ELEMENT_INFO_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_MEDIA_ELEMENT_INFO, PurpleMediaElementInfoPrivate))
95 static void purple_media_manager_class_init (PurpleMediaManagerClass
*klass
);
96 static void purple_media_manager_init (PurpleMediaManager
*media
);
97 static void purple_media_manager_finalize (GObject
*object
);
99 static GObjectClass
*parent_class
= NULL
;
108 static guint purple_media_manager_signals
[LAST_SIGNAL
] = {0};
112 purple_media_manager_get_type()
115 static GType type
= 0;
118 static const GTypeInfo info
= {
119 sizeof(PurpleMediaManagerClass
),
122 (GClassInitFunc
) purple_media_manager_class_init
,
125 sizeof(PurpleMediaManager
),
127 (GInstanceInitFunc
) purple_media_manager_init
,
130 type
= g_type_register_static(G_TYPE_OBJECT
, "PurpleMediaManager", &info
, 0);
140 purple_media_manager_class_init (PurpleMediaManagerClass
*klass
)
142 GObjectClass
*gobject_class
= (GObjectClass
*)klass
;
143 parent_class
= g_type_class_peek_parent(klass
);
145 gobject_class
->finalize
= purple_media_manager_finalize
;
147 purple_media_manager_signals
[INIT_MEDIA
] = g_signal_new ("init-media",
148 G_TYPE_FROM_CLASS (klass
),
151 purple_smarshal_BOOLEAN__OBJECT_POINTER_STRING
,
152 G_TYPE_BOOLEAN
, 3, PURPLE_TYPE_MEDIA
,
153 G_TYPE_POINTER
, G_TYPE_STRING
);
155 purple_media_manager_signals
[UI_CAPS_CHANGED
] = g_signal_new ("ui-caps-changed",
156 G_TYPE_FROM_CLASS (klass
),
159 purple_smarshal_VOID__FLAGS_FLAGS
,
160 G_TYPE_NONE
, 2, PURPLE_MEDIA_TYPE_CAPS
,
161 PURPLE_MEDIA_TYPE_CAPS
);
163 g_type_class_add_private(klass
, sizeof(PurpleMediaManagerPrivate
));
167 purple_media_manager_init (PurpleMediaManager
*media
)
169 media
->priv
= PURPLE_MEDIA_MANAGER_GET_PRIVATE(media
);
170 media
->priv
->medias
= NULL
;
171 media
->priv
->next_output_window_id
= 1;
173 media
->priv
->backend_type
= PURPLE_TYPE_MEDIA_BACKEND_FS2
;
176 purple_prefs_add_none("/purple/media");
177 purple_prefs_add_none("/purple/media/audio");
178 purple_prefs_add_int("/purple/media/audio/silence_threshold", 5);
179 purple_prefs_add_none("/purple/media/audio/volume");
180 purple_prefs_add_int("/purple/media/audio/volume/input", 10);
181 purple_prefs_add_int("/purple/media/audio/volume/output", 10);
185 purple_media_manager_finalize (GObject
*media
)
187 PurpleMediaManagerPrivate
*priv
= PURPLE_MEDIA_MANAGER_GET_PRIVATE(media
);
188 for (; priv
->medias
; priv
->medias
=
189 g_list_delete_link(priv
->medias
, priv
->medias
)) {
190 g_object_unref(priv
->medias
->data
);
192 for (; priv
->elements
; priv
->elements
=
193 g_list_delete_link(priv
->elements
, priv
->elements
)) {
194 g_object_unref(priv
->elements
->data
);
196 if (priv
->video_caps
)
197 gst_caps_unref(priv
->video_caps
);
198 parent_class
->finalize(media
);
203 purple_media_manager_get()
206 static PurpleMediaManager
*manager
= NULL
;
209 manager
= PURPLE_MEDIA_MANAGER(g_object_new(purple_media_manager_get_type(), NULL
));
218 pipeline_bus_call(GstBus
*bus
, GstMessage
*msg
, PurpleMediaManager
*manager
)
220 switch(GST_MESSAGE_TYPE(msg
)) {
221 case GST_MESSAGE_EOS
:
222 purple_debug_info("mediamanager", "End of Stream\n");
224 case GST_MESSAGE_ERROR
: {
228 gst_message_parse_error(msg
, &err
, &debug
);
230 purple_debug_error("mediamanager",
231 "gst pipeline error: %s\n",
236 purple_debug_error("mediamanager",
237 "Debug details: %s\n", debug
);
251 purple_media_manager_get_pipeline(PurpleMediaManager
*manager
)
254 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager
), NULL
);
256 if (manager
->priv
->pipeline
== NULL
) {
257 FsElementAddedNotifier
*notifier
;
262 manager
->priv
->pipeline
= gst_pipeline_new(NULL
);
264 bus
= gst_pipeline_get_bus(
265 GST_PIPELINE(manager
->priv
->pipeline
));
266 gst_bus_add_signal_watch(GST_BUS(bus
));
267 g_signal_connect(G_OBJECT(bus
), "message",
268 G_CALLBACK(pipeline_bus_call
), manager
);
269 gst_bus_set_sync_handler(bus
,
270 gst_bus_sync_signal_handler
, NULL
);
271 gst_object_unref(bus
);
273 filename
= g_build_filename(purple_user_dir(),
274 "fs-element.conf", NULL
);
275 keyfile
= g_key_file_new();
276 if (!g_key_file_load_from_file(keyfile
, filename
,
277 G_KEY_FILE_NONE
, &err
)) {
279 purple_debug_info("mediamanager",
281 "fs-element.conf: %s\n",
284 purple_debug_error("mediamanager",
286 "fs-element.conf: %s\n",
292 /* Hack to make alsasrc stop messing up audio timestamps */
293 if (!g_key_file_has_key(keyfile
,
294 "alsasrc", "slave-method", NULL
)) {
295 g_key_file_set_integer(keyfile
,
296 "alsasrc", "slave-method", 2);
299 notifier
= fs_element_added_notifier_new();
300 fs_element_added_notifier_add(notifier
,
301 GST_BIN(manager
->priv
->pipeline
));
302 fs_element_added_notifier_set_properties_from_keyfile(
305 gst_element_set_state(manager
->priv
->pipeline
,
309 return manager
->priv
->pipeline
;
314 #endif /* USE_GSTREAMER */
317 purple_media_manager_create_media(PurpleMediaManager
*manager
,
318 PurpleAccount
*account
,
319 const char *conference_type
,
320 const char *remote_user
,
327 media
= PURPLE_MEDIA(g_object_new(purple_media_get_type(),
330 "conference-type", conference_type
,
331 "initiator", initiator
,
334 g_signal_emit(manager
, purple_media_manager_signals
[INIT_MEDIA
], 0,
335 media
, account
, remote_user
, &signal_ret
);
337 if (signal_ret
== FALSE
) {
338 g_object_unref(media
);
342 manager
->priv
->medias
= g_list_append(manager
->priv
->medias
, media
);
350 purple_media_manager_get_media(PurpleMediaManager
*manager
)
353 return manager
->priv
->medias
;
360 purple_media_manager_get_media_by_account(PurpleMediaManager
*manager
,
361 PurpleAccount
*account
)
367 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager
), NULL
);
369 iter
= manager
->priv
->medias
;
370 for (; iter
; iter
= g_list_next(iter
)) {
371 if (purple_media_get_account(iter
->data
) == account
) {
372 media
= g_list_prepend(media
, iter
->data
);
383 purple_media_manager_remove_media(PurpleMediaManager
*manager
,
387 GList
*list
= g_list_find(manager
->priv
->medias
, media
);
389 manager
->priv
->medias
=
390 g_list_delete_link(manager
->priv
->medias
, list
);
396 request_pad_unlinked_cb(GstPad
*pad
, GstPad
*peer
, gpointer user_data
)
398 GstElement
*parent
= GST_ELEMENT_PARENT(pad
);
400 GstPad
*remaining_pad
;
401 GstIteratorResult result
;
403 gst_element_release_request_pad(GST_ELEMENT_PARENT(pad
), pad
);
405 iter
= gst_element_iterate_src_pads(parent
);
407 result
= gst_iterator_next(iter
, (gpointer
)&remaining_pad
);
409 if (result
== GST_ITERATOR_DONE
) {
410 gst_element_set_locked_state(parent
, TRUE
);
411 gst_element_set_state(parent
, GST_STATE_NULL
);
412 gst_bin_remove(GST_BIN(GST_ELEMENT_PARENT(parent
)), parent
);
413 } else if (result
== GST_ITERATOR_OK
) {
414 gst_object_unref(remaining_pad
);
417 gst_iterator_free(iter
);
424 purple_media_manager_set_video_caps(PurpleMediaManager
*manager
, GstCaps
*caps
)
427 if (manager
->priv
->video_caps
)
428 gst_caps_unref(manager
->priv
->video_caps
);
430 manager
->priv
->video_caps
= caps
;
432 if (manager
->priv
->pipeline
&& manager
->priv
->video_src
) {
433 gchar
*id
= purple_media_element_info_get_id(manager
->priv
->video_src
);
434 GstElement
*src
= gst_bin_get_by_name(GST_BIN(manager
->priv
->pipeline
), id
);
437 GstElement
*capsfilter
= gst_bin_get_by_name(GST_BIN(src
), "prpl_video_caps");
438 g_object_set(G_OBJECT(capsfilter
), "caps", caps
, NULL
);
447 purple_media_manager_get_video_caps(PurpleMediaManager
*manager
)
450 if (manager
->priv
->video_caps
== NULL
)
451 manager
->priv
->video_caps
= gst_caps_from_string("video/x-raw-yuv,"
452 "width=[250,352], height=[200,288], framerate=[1/1,20/1]");
453 return manager
->priv
->video_caps
;
460 purple_media_manager_get_element(PurpleMediaManager
*manager
,
461 PurpleMediaSessionType type
, PurpleMedia
*media
,
462 const gchar
*session_id
, const gchar
*participant
)
465 GstElement
*ret
= NULL
;
466 PurpleMediaElementInfo
*info
= NULL
;
467 PurpleMediaElementType element_type
;
469 if (type
& PURPLE_MEDIA_SEND_AUDIO
)
470 info
= manager
->priv
->audio_src
;
471 else if (type
& PURPLE_MEDIA_RECV_AUDIO
)
472 info
= manager
->priv
->audio_sink
;
473 else if (type
& PURPLE_MEDIA_SEND_VIDEO
)
474 info
= manager
->priv
->video_src
;
475 else if (type
& PURPLE_MEDIA_RECV_VIDEO
)
476 info
= manager
->priv
->video_sink
;
481 element_type
= purple_media_element_info_get_element_type(info
);
483 if (element_type
& PURPLE_MEDIA_ELEMENT_UNIQUE
&&
484 element_type
& PURPLE_MEDIA_ELEMENT_SRC
) {
488 gchar
*id
= purple_media_element_info_get_id(info
);
490 ret
= gst_bin_get_by_name(GST_BIN(
491 purple_media_manager_get_pipeline(
495 GstElement
*bin
, *fakesink
;
496 ret
= purple_media_element_info_call_create(info
,
497 media
, session_id
, participant
);
498 bin
= gst_bin_new(id
);
499 tee
= gst_element_factory_make("tee", "tee");
500 gst_bin_add_many(GST_BIN(bin
), ret
, tee
, NULL
);
502 if (type
& PURPLE_MEDIA_SEND_VIDEO
) {
503 GstElement
*videoscale
;
504 GstElement
*capsfilter
;
506 videoscale
= gst_element_factory_make("videoscale", NULL
);
507 capsfilter
= gst_element_factory_make("capsfilter", "prpl_video_caps");
509 g_object_set(G_OBJECT(capsfilter
),
510 "caps", purple_media_manager_get_video_caps(manager
), NULL
);
512 gst_bin_add_many(GST_BIN(bin
), videoscale
, capsfilter
, NULL
);
513 gst_element_link_many(ret
, videoscale
, capsfilter
, tee
, NULL
);
515 gst_element_link(ret
, tee
);
518 * This shouldn't be necessary, but it stops it from
519 * giving a not-linked error upon destruction
521 fakesink
= gst_element_factory_make("fakesink", NULL
);
522 g_object_set(fakesink
, "sync", FALSE
, NULL
);
523 gst_bin_add(GST_BIN(bin
), fakesink
);
524 gst_element_link(tee
, fakesink
);
528 gst_bin_add(GST_BIN(purple_media_manager_get_pipeline(
533 tee
= gst_bin_get_by_name(GST_BIN(ret
), "tee");
534 pad
= gst_element_get_request_pad(tee
, "src%d");
535 gst_object_unref(tee
);
536 ghost
= gst_ghost_pad_new(NULL
, pad
);
537 gst_object_unref(pad
);
538 g_signal_connect(GST_PAD(ghost
), "unlinked",
539 G_CALLBACK(request_pad_unlinked_cb
), NULL
);
540 gst_pad_set_active(ghost
, TRUE
);
541 gst_element_add_pad(ret
, ghost
);
543 ret
= purple_media_element_info_call_create(info
,
544 media
, session_id
, participant
);
548 purple_debug_error("media", "Error creating source or sink\n");
556 PurpleMediaElementInfo
*
557 purple_media_manager_get_element_info(PurpleMediaManager
*manager
,
563 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager
), NULL
);
565 iter
= manager
->priv
->elements
;
567 for (; iter
; iter
= g_list_next(iter
)) {
569 purple_media_element_info_get_id(iter
->data
);
570 if (!strcmp(element_id
, id
)) {
572 g_object_ref(iter
->data
);
583 purple_media_manager_register_element(PurpleMediaManager
*manager
,
584 PurpleMediaElementInfo
*info
)
587 PurpleMediaElementInfo
*info2
;
590 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager
), FALSE
);
591 g_return_val_if_fail(info
!= NULL
, FALSE
);
593 id
= purple_media_element_info_get_id(info
);
594 info2
= purple_media_manager_get_element_info(manager
, id
);
598 g_object_unref(info2
);
602 manager
->priv
->elements
=
603 g_list_prepend(manager
->priv
->elements
, info
);
611 purple_media_manager_unregister_element(PurpleMediaManager
*manager
,
615 PurpleMediaElementInfo
*info
;
617 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager
), FALSE
);
619 info
= purple_media_manager_get_element_info(manager
, id
);
622 g_object_unref(info
);
626 if (manager
->priv
->audio_src
== info
)
627 manager
->priv
->audio_src
= NULL
;
628 if (manager
->priv
->audio_sink
== info
)
629 manager
->priv
->audio_sink
= NULL
;
630 if (manager
->priv
->video_src
== info
)
631 manager
->priv
->video_src
= NULL
;
632 if (manager
->priv
->video_sink
== info
)
633 manager
->priv
->video_sink
= NULL
;
635 manager
->priv
->elements
= g_list_remove(
636 manager
->priv
->elements
, info
);
637 g_object_unref(info
);
645 purple_media_manager_set_active_element(PurpleMediaManager
*manager
,
646 PurpleMediaElementInfo
*info
)
649 PurpleMediaElementInfo
*info2
;
650 PurpleMediaElementType type
;
651 gboolean ret
= FALSE
;
654 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager
), FALSE
);
655 g_return_val_if_fail(info
!= NULL
, FALSE
);
657 id
= purple_media_element_info_get_id(info
);
658 info2
= purple_media_manager_get_element_info(manager
, id
);
662 purple_media_manager_register_element(manager
, info
);
664 g_object_unref(info2
);
666 type
= purple_media_element_info_get_element_type(info
);
668 if (type
& PURPLE_MEDIA_ELEMENT_SRC
) {
669 if (type
& PURPLE_MEDIA_ELEMENT_AUDIO
) {
670 manager
->priv
->audio_src
= info
;
673 if (type
& PURPLE_MEDIA_ELEMENT_VIDEO
) {
674 manager
->priv
->video_src
= info
;
678 if (type
& PURPLE_MEDIA_ELEMENT_SINK
) {
679 if (type
& PURPLE_MEDIA_ELEMENT_AUDIO
) {
680 manager
->priv
->audio_sink
= info
;
683 if (type
& PURPLE_MEDIA_ELEMENT_VIDEO
) {
684 manager
->priv
->video_sink
= info
;
695 PurpleMediaElementInfo
*
696 purple_media_manager_get_active_element(PurpleMediaManager
*manager
,
697 PurpleMediaElementType type
)
700 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager
), NULL
);
702 if (type
& PURPLE_MEDIA_ELEMENT_SRC
) {
703 if (type
& PURPLE_MEDIA_ELEMENT_AUDIO
)
704 return manager
->priv
->audio_src
;
705 else if (type
& PURPLE_MEDIA_ELEMENT_VIDEO
)
706 return manager
->priv
->video_src
;
707 } else if (type
& PURPLE_MEDIA_ELEMENT_SINK
) {
708 if (type
& PURPLE_MEDIA_ELEMENT_AUDIO
)
709 return manager
->priv
->audio_sink
;
710 else if (type
& PURPLE_MEDIA_ELEMENT_VIDEO
)
711 return manager
->priv
->video_sink
;
717 #endif /* USE_GSTREAMER */
721 window_id_cb(GstBus
*bus
, GstMessage
*msg
, PurpleMediaOutputWindow
*ow
)
725 if (GST_MESSAGE_TYPE(msg
) != GST_MESSAGE_ELEMENT
||
726 !gst_structure_has_name(msg
->structure
,
727 "prepare-xwindow-id"))
730 sink
= GST_ELEMENT(GST_MESSAGE_SRC(msg
));
731 while (sink
!= ow
->sink
) {
734 sink
= GST_ELEMENT_PARENT(sink
);
737 g_signal_handlers_disconnect_matched(bus
, G_SIGNAL_MATCH_FUNC
738 | G_SIGNAL_MATCH_DATA
, 0, 0, NULL
,
741 gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(
742 GST_MESSAGE_SRC(msg
)), ow
->window_id
);
747 purple_media_manager_create_output_window(PurpleMediaManager
*manager
,
748 PurpleMedia
*media
, const gchar
*session_id
,
749 const gchar
*participant
)
754 g_return_val_if_fail(PURPLE_IS_MEDIA(media
), FALSE
);
756 iter
= manager
->priv
->output_windows
;
757 for(; iter
; iter
= g_list_next(iter
)) {
758 PurpleMediaOutputWindow
*ow
= iter
->data
;
760 if (ow
->sink
== NULL
&& ow
->media
== media
&&
761 ((participant
!= NULL
&&
762 ow
->participant
!= NULL
&&
763 !strcmp(participant
, ow
->participant
)) ||
764 (participant
== ow
->participant
)) &&
765 !strcmp(session_id
, ow
->session_id
)) {
767 GstElement
*queue
, *colorspace
;
768 GstElement
*tee
= purple_media_get_tee(media
,
769 session_id
, participant
);
774 queue
= gst_element_factory_make(
776 colorspace
= gst_element_factory_make(
777 "ffmpegcolorspace", NULL
);
778 ow
->sink
= purple_media_manager_get_element(
779 manager
, PURPLE_MEDIA_RECV_VIDEO
,
780 ow
->media
, ow
->session_id
,
783 if (participant
== NULL
) {
784 /* aka this is a preview sink */
785 GObjectClass
*klass
=
786 G_OBJECT_GET_CLASS(ow
->sink
);
787 if (g_object_class_find_property(klass
,
789 g_object_set(G_OBJECT(ow
->sink
),
790 "sync", "FALSE", NULL
);
791 if (g_object_class_find_property(klass
,
793 g_object_set(G_OBJECT(ow
->sink
),
794 "async", FALSE
, NULL
);
797 gst_bin_add_many(GST_BIN(GST_ELEMENT_PARENT(tee
)),
798 queue
, colorspace
, ow
->sink
, NULL
);
800 bus
= gst_pipeline_get_bus(GST_PIPELINE(
801 manager
->priv
->pipeline
));
802 g_signal_connect(bus
, "sync-message::element",
803 G_CALLBACK(window_id_cb
), ow
);
804 gst_object_unref(bus
);
806 gst_element_set_state(ow
->sink
, GST_STATE_PLAYING
);
807 gst_element_set_state(colorspace
, GST_STATE_PLAYING
);
808 gst_element_set_state(queue
, GST_STATE_PLAYING
);
809 gst_element_link(colorspace
, ow
->sink
);
810 gst_element_link(queue
, colorspace
);
811 gst_element_link(tee
, queue
);
821 purple_media_manager_set_output_window(PurpleMediaManager
*manager
,
822 PurpleMedia
*media
, const gchar
*session_id
,
823 const gchar
*participant
, gulong window_id
)
826 PurpleMediaOutputWindow
*output_window
;
828 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager
), FALSE
);
829 g_return_val_if_fail(PURPLE_IS_MEDIA(media
), FALSE
);
831 output_window
= g_new0(PurpleMediaOutputWindow
, 1);
832 output_window
->id
= manager
->priv
->next_output_window_id
++;
833 output_window
->media
= media
;
834 output_window
->session_id
= g_strdup(session_id
);
835 output_window
->participant
= g_strdup(participant
);
836 output_window
->window_id
= window_id
;
838 manager
->priv
->output_windows
= g_list_prepend(
839 manager
->priv
->output_windows
, output_window
);
841 if (purple_media_get_tee(media
, session_id
, participant
) != NULL
)
842 purple_media_manager_create_output_window(manager
,
843 media
, session_id
, participant
);
845 return output_window
->id
;
852 purple_media_manager_remove_output_window(PurpleMediaManager
*manager
,
853 gulong output_window_id
)
856 PurpleMediaOutputWindow
*output_window
= NULL
;
859 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager
), FALSE
);
861 iter
= manager
->priv
->output_windows
;
862 for (; iter
; iter
= g_list_next(iter
)) {
863 PurpleMediaOutputWindow
*ow
= iter
->data
;
864 if (ow
->id
== output_window_id
) {
865 manager
->priv
->output_windows
= g_list_delete_link(
866 manager
->priv
->output_windows
, iter
);
872 if (output_window
== NULL
)
875 if (output_window
->sink
!= NULL
) {
876 GstPad
*pad
= gst_element_get_static_pad(
877 output_window
->sink
, "sink");
878 GstPad
*peer
= gst_pad_get_peer(pad
);
879 GstElement
*colorspace
= GST_ELEMENT_PARENT(peer
), *queue
;
880 gst_object_unref(pad
);
881 gst_object_unref(peer
);
882 pad
= gst_element_get_static_pad(colorspace
, "sink");
883 peer
= gst_pad_get_peer(pad
);
884 queue
= GST_ELEMENT_PARENT(peer
);
885 gst_object_unref(pad
);
886 gst_object_unref(peer
);
887 pad
= gst_element_get_static_pad(queue
, "sink");
888 peer
= gst_pad_get_peer(pad
);
889 gst_object_unref(pad
);
891 gst_element_release_request_pad(GST_ELEMENT_PARENT(peer
), peer
);
892 gst_element_set_locked_state(queue
, TRUE
);
893 gst_element_set_state(queue
, GST_STATE_NULL
);
894 gst_bin_remove(GST_BIN(GST_ELEMENT_PARENT(queue
)), queue
);
895 gst_element_set_locked_state(colorspace
, TRUE
);
896 gst_element_set_state(colorspace
, GST_STATE_NULL
);
897 gst_bin_remove(GST_BIN(GST_ELEMENT_PARENT(colorspace
)), colorspace
);
898 gst_element_set_locked_state(output_window
->sink
, TRUE
);
899 gst_element_set_state(output_window
->sink
, GST_STATE_NULL
);
900 gst_bin_remove(GST_BIN(GST_ELEMENT_PARENT(output_window
->sink
)),
901 output_window
->sink
);
904 g_free(output_window
->session_id
);
905 g_free(output_window
->participant
);
906 g_free(output_window
);
915 purple_media_manager_remove_output_windows(PurpleMediaManager
*manager
,
916 PurpleMedia
*media
, const gchar
*session_id
,
917 const gchar
*participant
)
922 g_return_if_fail(PURPLE_IS_MEDIA(media
));
924 iter
= manager
->priv
->output_windows
;
927 PurpleMediaOutputWindow
*ow
= iter
->data
;
928 iter
= g_list_next(iter
);
930 if (media
== ow
->media
&&
931 ((session_id
!= NULL
&& ow
->session_id
!= NULL
&&
932 !strcmp(session_id
, ow
->session_id
)) ||
933 (session_id
== ow
->session_id
)) &&
934 ((participant
!= NULL
&& ow
->participant
!= NULL
&&
935 !strcmp(participant
, ow
->participant
)) ||
936 (participant
== ow
->participant
)))
937 purple_media_manager_remove_output_window(
944 purple_media_manager_set_ui_caps(PurpleMediaManager
*manager
,
945 PurpleMediaCaps caps
)
948 PurpleMediaCaps oldcaps
;
950 g_return_if_fail(PURPLE_IS_MEDIA_MANAGER(manager
));
952 oldcaps
= manager
->priv
->ui_caps
;
953 manager
->priv
->ui_caps
= caps
;
956 g_signal_emit(manager
,
957 purple_media_manager_signals
[UI_CAPS_CHANGED
],
963 purple_media_manager_get_ui_caps(PurpleMediaManager
*manager
)
966 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager
),
967 PURPLE_MEDIA_CAPS_NONE
);
968 return manager
->priv
->ui_caps
;
970 return PURPLE_MEDIA_CAPS_NONE
;
975 purple_media_manager_set_backend_type(PurpleMediaManager
*manager
,
979 g_return_if_fail(PURPLE_IS_MEDIA_MANAGER(manager
));
981 manager
->priv
->backend_type
= backend_type
;
986 purple_media_manager_get_backend_type(PurpleMediaManager
*manager
)
989 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager
),
990 PURPLE_MEDIA_CAPS_NONE
);
992 return manager
->priv
->backend_type
;
1001 * PurpleMediaElementType
1005 purple_media_element_type_get_type()
1007 static GType type
= 0;
1009 static const GFlagsValue values
[] = {
1010 { PURPLE_MEDIA_ELEMENT_NONE
,
1011 "PURPLE_MEDIA_ELEMENT_NONE", "none" },
1012 { PURPLE_MEDIA_ELEMENT_AUDIO
,
1013 "PURPLE_MEDIA_ELEMENT_AUDIO", "audio" },
1014 { PURPLE_MEDIA_ELEMENT_VIDEO
,
1015 "PURPLE_MEDIA_ELEMENT_VIDEO", "video" },
1016 { PURPLE_MEDIA_ELEMENT_AUDIO_VIDEO
,
1017 "PURPLE_MEDIA_ELEMENT_AUDIO_VIDEO",
1019 { PURPLE_MEDIA_ELEMENT_NO_SRCS
,
1020 "PURPLE_MEDIA_ELEMENT_NO_SRCS", "no-srcs" },
1021 { PURPLE_MEDIA_ELEMENT_ONE_SRC
,
1022 "PURPLE_MEDIA_ELEMENT_ONE_SRC", "one-src" },
1023 { PURPLE_MEDIA_ELEMENT_MULTI_SRC
,
1024 "PURPLE_MEDIA_ELEMENT_MULTI_SRC",
1026 { PURPLE_MEDIA_ELEMENT_REQUEST_SRC
,
1027 "PURPLE_MEDIA_ELEMENT_REQUEST_SRC",
1029 { PURPLE_MEDIA_ELEMENT_NO_SINKS
,
1030 "PURPLE_MEDIA_ELEMENT_NO_SINKS", "no-sinks" },
1031 { PURPLE_MEDIA_ELEMENT_ONE_SINK
,
1032 "PURPLE_MEDIA_ELEMENT_ONE_SINK", "one-sink" },
1033 { PURPLE_MEDIA_ELEMENT_MULTI_SINK
,
1034 "PURPLE_MEDIA_ELEMENT_MULTI_SINK",
1036 { PURPLE_MEDIA_ELEMENT_REQUEST_SINK
,
1037 "PURPLE_MEDIA_ELEMENT_REQUEST_SINK",
1039 { PURPLE_MEDIA_ELEMENT_UNIQUE
,
1040 "PURPLE_MEDIA_ELEMENT_UNIQUE", "unique" },
1041 { PURPLE_MEDIA_ELEMENT_SRC
,
1042 "PURPLE_MEDIA_ELEMENT_SRC", "src" },
1043 { PURPLE_MEDIA_ELEMENT_SINK
,
1044 "PURPLE_MEDIA_ELEMENT_SINK", "sink" },
1047 type
= g_flags_register_static(
1048 "PurpleMediaElementType", values
);
1054 * PurpleMediaElementInfo
1057 struct _PurpleMediaElementInfoClass
1059 GObjectClass parent_class
;
1062 struct _PurpleMediaElementInfo
1068 struct _PurpleMediaElementInfoPrivate
1072 PurpleMediaElementType type
;
1073 PurpleMediaElementCreateCallback create
;
1085 purple_media_element_info_init(PurpleMediaElementInfo
*info
)
1087 PurpleMediaElementInfoPrivate
*priv
=
1088 PURPLE_MEDIA_ELEMENT_INFO_GET_PRIVATE(info
);
1091 priv
->type
= PURPLE_MEDIA_ELEMENT_NONE
;
1092 priv
->create
= NULL
;
1096 purple_media_element_info_finalize(GObject
*info
)
1098 PurpleMediaElementInfoPrivate
*priv
=
1099 PURPLE_MEDIA_ELEMENT_INFO_GET_PRIVATE(info
);
1105 purple_media_element_info_set_property (GObject
*object
, guint prop_id
,
1106 const GValue
*value
, GParamSpec
*pspec
)
1108 PurpleMediaElementInfoPrivate
*priv
;
1109 g_return_if_fail(PURPLE_IS_MEDIA_ELEMENT_INFO(object
));
1111 priv
= PURPLE_MEDIA_ELEMENT_INFO_GET_PRIVATE(object
);
1116 priv
->id
= g_value_dup_string(value
);
1120 priv
->name
= g_value_dup_string(value
);
1123 priv
->type
= g_value_get_flags(value
);
1126 case PROP_CREATE_CB
:
1127 priv
->create
= g_value_get_pointer(value
);
1130 G_OBJECT_WARN_INVALID_PROPERTY_ID(
1131 object
, prop_id
, pspec
);
1137 purple_media_element_info_get_property (GObject
*object
, guint prop_id
,
1138 GValue
*value
, GParamSpec
*pspec
)
1140 PurpleMediaElementInfoPrivate
*priv
;
1141 g_return_if_fail(PURPLE_IS_MEDIA_ELEMENT_INFO(object
));
1143 priv
= PURPLE_MEDIA_ELEMENT_INFO_GET_PRIVATE(object
);
1147 g_value_set_string(value
, priv
->id
);
1150 g_value_set_string(value
, priv
->name
);
1153 g_value_set_flags(value
, priv
->type
);
1155 case PROP_CREATE_CB
:
1156 g_value_set_pointer(value
, priv
->create
);
1159 G_OBJECT_WARN_INVALID_PROPERTY_ID(
1160 object
, prop_id
, pspec
);
1166 purple_media_element_info_class_init(PurpleMediaElementInfoClass
*klass
)
1168 GObjectClass
*gobject_class
= (GObjectClass
*)klass
;
1170 gobject_class
->finalize
= purple_media_element_info_finalize
;
1171 gobject_class
->set_property
= purple_media_element_info_set_property
;
1172 gobject_class
->get_property
= purple_media_element_info_get_property
;
1174 g_object_class_install_property(gobject_class
, PROP_ID
,
1175 g_param_spec_string("id",
1177 "The unique identifier of the element.",
1179 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
));
1181 g_object_class_install_property(gobject_class
, PROP_NAME
,
1182 g_param_spec_string("name",
1184 "The friendly/display name of this element.",
1186 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
));
1188 g_object_class_install_property(gobject_class
, PROP_TYPE
,
1189 g_param_spec_flags("type",
1191 "The type of element this is.",
1192 PURPLE_TYPE_MEDIA_ELEMENT_TYPE
,
1193 PURPLE_MEDIA_ELEMENT_NONE
,
1194 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
));
1196 g_object_class_install_property(gobject_class
, PROP_CREATE_CB
,
1197 g_param_spec_pointer("create-cb",
1199 "The function called to create this element.",
1200 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
));
1202 g_type_class_add_private(klass
, sizeof(PurpleMediaElementInfoPrivate
));
1205 G_DEFINE_TYPE(PurpleMediaElementInfo
,
1206 purple_media_element_info
, G_TYPE_OBJECT
);
1209 purple_media_element_info_get_type()
1216 purple_media_element_info_get_id(PurpleMediaElementInfo
*info
)
1220 g_return_val_if_fail(PURPLE_IS_MEDIA_ELEMENT_INFO(info
), NULL
);
1221 g_object_get(info
, "id", &id
, NULL
);
1229 purple_media_element_info_get_name(PurpleMediaElementInfo
*info
)
1233 g_return_val_if_fail(PURPLE_IS_MEDIA_ELEMENT_INFO(info
), NULL
);
1234 g_object_get(info
, "name", &name
, NULL
);
1241 PurpleMediaElementType
1242 purple_media_element_info_get_element_type(PurpleMediaElementInfo
*info
)
1245 PurpleMediaElementType type
;
1246 g_return_val_if_fail(PURPLE_IS_MEDIA_ELEMENT_INFO(info
),
1247 PURPLE_MEDIA_ELEMENT_NONE
);
1248 g_object_get(info
, "type", &type
, NULL
);
1251 return PURPLE_MEDIA_ELEMENT_NONE
;
1256 purple_media_element_info_call_create(PurpleMediaElementInfo
*info
,
1257 PurpleMedia
*media
, const gchar
*session_id
,
1258 const gchar
*participant
)
1261 PurpleMediaElementCreateCallback create
;
1262 g_return_val_if_fail(PURPLE_IS_MEDIA_ELEMENT_INFO(info
), NULL
);
1263 g_object_get(info
, "create-cb", &create
, NULL
);
1265 return create(media
, session_id
, participant
);
1270 #endif /* USE_GSTREAMER */