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
;
85 PurpleMediaElementInfo
*video_src
;
86 PurpleMediaElementInfo
*video_sink
;
87 PurpleMediaElementInfo
*audio_src
;
88 PurpleMediaElementInfo
*audio_sink
;
91 #define PURPLE_MEDIA_MANAGER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_MEDIA_MANAGER, PurpleMediaManagerPrivate))
92 #define PURPLE_MEDIA_ELEMENT_INFO_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_MEDIA_ELEMENT_INFO, PurpleMediaElementInfoPrivate))
94 static void purple_media_manager_class_init (PurpleMediaManagerClass
*klass
);
95 static void purple_media_manager_init (PurpleMediaManager
*media
);
96 static void purple_media_manager_finalize (GObject
*object
);
98 static GObjectClass
*parent_class
= NULL
;
107 static guint purple_media_manager_signals
[LAST_SIGNAL
] = {0};
111 purple_media_manager_get_type()
114 static GType type
= 0;
117 static const GTypeInfo info
= {
118 sizeof(PurpleMediaManagerClass
),
121 (GClassInitFunc
) purple_media_manager_class_init
,
124 sizeof(PurpleMediaManager
),
126 (GInstanceInitFunc
) purple_media_manager_init
,
129 type
= g_type_register_static(G_TYPE_OBJECT
, "PurpleMediaManager", &info
, 0);
139 purple_media_manager_class_init (PurpleMediaManagerClass
*klass
)
141 GObjectClass
*gobject_class
= (GObjectClass
*)klass
;
142 parent_class
= g_type_class_peek_parent(klass
);
144 gobject_class
->finalize
= purple_media_manager_finalize
;
146 purple_media_manager_signals
[INIT_MEDIA
] = g_signal_new ("init-media",
147 G_TYPE_FROM_CLASS (klass
),
150 purple_smarshal_BOOLEAN__OBJECT_POINTER_STRING
,
151 G_TYPE_BOOLEAN
, 3, PURPLE_TYPE_MEDIA
,
152 G_TYPE_POINTER
, G_TYPE_STRING
);
154 purple_media_manager_signals
[UI_CAPS_CHANGED
] = g_signal_new ("ui-caps-changed",
155 G_TYPE_FROM_CLASS (klass
),
158 purple_smarshal_VOID__FLAGS_FLAGS
,
159 G_TYPE_NONE
, 2, PURPLE_MEDIA_TYPE_CAPS
,
160 PURPLE_MEDIA_TYPE_CAPS
);
162 g_type_class_add_private(klass
, sizeof(PurpleMediaManagerPrivate
));
166 purple_media_manager_init (PurpleMediaManager
*media
)
168 media
->priv
= PURPLE_MEDIA_MANAGER_GET_PRIVATE(media
);
169 media
->priv
->medias
= NULL
;
170 media
->priv
->next_output_window_id
= 1;
172 media
->priv
->backend_type
= PURPLE_TYPE_MEDIA_BACKEND_FS2
;
175 purple_prefs_add_none("/purple/media");
176 purple_prefs_add_none("/purple/media/audio");
177 purple_prefs_add_none("/purple/media/audio/volume");
178 purple_prefs_add_int("/purple/media/audio/volume/input", 10);
179 purple_prefs_add_int("/purple/media/audio/volume/output", 10);
183 purple_media_manager_finalize (GObject
*media
)
185 PurpleMediaManagerPrivate
*priv
= PURPLE_MEDIA_MANAGER_GET_PRIVATE(media
);
186 for (; priv
->medias
; priv
->medias
=
187 g_list_delete_link(priv
->medias
, priv
->medias
)) {
188 g_object_unref(priv
->medias
->data
);
190 for (; priv
->elements
; priv
->elements
=
191 g_list_delete_link(priv
->elements
, priv
->elements
)) {
192 g_object_unref(priv
->elements
->data
);
194 parent_class
->finalize(media
);
199 purple_media_manager_get()
202 static PurpleMediaManager
*manager
= NULL
;
205 manager
= PURPLE_MEDIA_MANAGER(g_object_new(purple_media_manager_get_type(), NULL
));
214 pipeline_bus_call(GstBus
*bus
, GstMessage
*msg
, PurpleMediaManager
*manager
)
216 switch(GST_MESSAGE_TYPE(msg
)) {
217 case GST_MESSAGE_EOS
:
218 purple_debug_info("mediamanager", "End of Stream\n");
220 case GST_MESSAGE_ERROR
: {
224 gst_message_parse_error(msg
, &err
, &debug
);
226 purple_debug_error("mediamanager",
227 "gst pipeline error: %s\n",
232 purple_debug_error("mediamanager",
233 "Debug details: %s\n", debug
);
247 purple_media_manager_get_pipeline(PurpleMediaManager
*manager
)
250 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager
), NULL
);
252 if (manager
->priv
->pipeline
== NULL
) {
253 FsElementAddedNotifier
*notifier
;
258 manager
->priv
->pipeline
= gst_pipeline_new(NULL
);
260 bus
= gst_pipeline_get_bus(
261 GST_PIPELINE(manager
->priv
->pipeline
));
262 gst_bus_add_signal_watch(GST_BUS(bus
));
263 g_signal_connect(G_OBJECT(bus
), "message",
264 G_CALLBACK(pipeline_bus_call
), manager
);
265 gst_bus_set_sync_handler(bus
,
266 gst_bus_sync_signal_handler
, NULL
);
267 gst_object_unref(bus
);
269 filename
= g_build_filename(purple_user_dir(),
270 "fs-element.conf", NULL
);
271 keyfile
= g_key_file_new();
272 if (!g_key_file_load_from_file(keyfile
, filename
,
273 G_KEY_FILE_NONE
, &err
)) {
275 purple_debug_info("mediamanager",
277 "fs-element.conf: %s\n",
280 purple_debug_error("mediamanager",
282 "fs-element.conf: %s\n",
288 /* Hack to make alsasrc stop messing up audio timestamps */
289 if (!g_key_file_has_key(keyfile
,
290 "alsasrc", "slave-method", NULL
)) {
291 g_key_file_set_integer(keyfile
,
292 "alsasrc", "slave-method", 2);
295 notifier
= fs_element_added_notifier_new();
296 fs_element_added_notifier_add(notifier
,
297 GST_BIN(manager
->priv
->pipeline
));
298 fs_element_added_notifier_set_properties_from_keyfile(
301 gst_element_set_state(manager
->priv
->pipeline
,
305 return manager
->priv
->pipeline
;
310 #endif /* USE_GSTREAMER */
313 purple_media_manager_create_media(PurpleMediaManager
*manager
,
314 PurpleAccount
*account
,
315 const char *conference_type
,
316 const char *remote_user
,
323 media
= PURPLE_MEDIA(g_object_new(purple_media_get_type(),
326 "conference-type", conference_type
,
327 "initiator", initiator
,
330 g_signal_emit(manager
, purple_media_manager_signals
[INIT_MEDIA
], 0,
331 media
, account
, remote_user
, &signal_ret
);
333 if (signal_ret
== FALSE
) {
334 g_object_unref(media
);
338 manager
->priv
->medias
= g_list_append(manager
->priv
->medias
, media
);
346 purple_media_manager_get_media(PurpleMediaManager
*manager
)
349 return manager
->priv
->medias
;
356 purple_media_manager_get_media_by_account(PurpleMediaManager
*manager
,
357 PurpleAccount
*account
)
363 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager
), NULL
);
365 iter
= manager
->priv
->medias
;
366 for (; iter
; iter
= g_list_next(iter
)) {
367 if (purple_media_get_account(iter
->data
) == account
) {
368 media
= g_list_prepend(media
, iter
->data
);
379 purple_media_manager_remove_media(PurpleMediaManager
*manager
,
383 GList
*list
= g_list_find(manager
->priv
->medias
, media
);
385 manager
->priv
->medias
=
386 g_list_delete_link(manager
->priv
->medias
, list
);
392 request_pad_unlinked_cb(GstPad
*pad
, GstPad
*peer
, gpointer user_data
)
394 GstElement
*parent
= GST_ELEMENT_PARENT(pad
);
396 GstPad
*remaining_pad
;
397 GstIteratorResult result
;
399 gst_element_release_request_pad(GST_ELEMENT_PARENT(pad
), pad
);
400 iter
= gst_element_iterate_src_pads(parent
);
402 result
= gst_iterator_next(iter
, (gpointer
)&remaining_pad
);
404 if (result
== GST_ITERATOR_DONE
) {
405 gst_element_set_locked_state(parent
, TRUE
);
406 gst_element_set_state(parent
, GST_STATE_NULL
);
407 gst_bin_remove(GST_BIN(GST_ELEMENT_PARENT(parent
)), parent
);
408 } else if (result
== GST_ITERATOR_OK
) {
409 gst_object_unref(remaining_pad
);
412 gst_iterator_free(iter
);
418 purple_media_manager_get_element(PurpleMediaManager
*manager
,
419 PurpleMediaSessionType type
, PurpleMedia
*media
,
420 const gchar
*session_id
, const gchar
*participant
)
423 GstElement
*ret
= NULL
;
424 PurpleMediaElementInfo
*info
= NULL
;
425 PurpleMediaElementType element_type
;
427 if (type
& PURPLE_MEDIA_SEND_AUDIO
)
428 info
= manager
->priv
->audio_src
;
429 else if (type
& PURPLE_MEDIA_RECV_AUDIO
)
430 info
= manager
->priv
->audio_sink
;
431 else if (type
& PURPLE_MEDIA_SEND_VIDEO
)
432 info
= manager
->priv
->video_src
;
433 else if (type
& PURPLE_MEDIA_RECV_VIDEO
)
434 info
= manager
->priv
->video_sink
;
439 element_type
= purple_media_element_info_get_element_type(info
);
441 if (element_type
& PURPLE_MEDIA_ELEMENT_UNIQUE
&&
442 element_type
& PURPLE_MEDIA_ELEMENT_SRC
) {
446 gchar
*id
= purple_media_element_info_get_id(info
);
448 ret
= gst_bin_get_by_name(GST_BIN(
449 purple_media_manager_get_pipeline(
453 GstElement
*bin
, *fakesink
;
454 ret
= purple_media_element_info_call_create(info
,
455 media
, session_id
, participant
);
456 bin
= gst_bin_new(id
);
457 tee
= gst_element_factory_make("tee", "tee");
458 gst_bin_add_many(GST_BIN(bin
), ret
, tee
, NULL
);
459 gst_element_link(ret
, tee
);
462 * This shouldn't be necessary, but it stops it from
463 * giving a not-linked error upon destruction
465 fakesink
= gst_element_factory_make("fakesink", NULL
);
466 g_object_set(fakesink
, "sync", FALSE
, NULL
);
467 gst_bin_add(GST_BIN(bin
), fakesink
);
468 gst_element_link(tee
, fakesink
);
472 gst_bin_add(GST_BIN(purple_media_manager_get_pipeline(
477 tee
= gst_bin_get_by_name(GST_BIN(ret
), "tee");
478 pad
= gst_element_get_request_pad(tee
, "src%d");
479 gst_object_unref(tee
);
480 ghost
= gst_ghost_pad_new(NULL
, pad
);
481 gst_object_unref(pad
);
482 g_signal_connect(GST_PAD(ghost
), "unlinked",
483 G_CALLBACK(request_pad_unlinked_cb
), NULL
);
484 gst_pad_set_active(ghost
, TRUE
);
485 gst_element_add_pad(ret
, ghost
);
487 ret
= purple_media_element_info_call_create(info
,
488 media
, session_id
, participant
);
492 purple_debug_error("media", "Error creating source or sink\n");
500 PurpleMediaElementInfo
*
501 purple_media_manager_get_element_info(PurpleMediaManager
*manager
,
507 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager
), NULL
);
509 iter
= manager
->priv
->elements
;
511 for (; iter
; iter
= g_list_next(iter
)) {
513 purple_media_element_info_get_id(iter
->data
);
514 if (!strcmp(element_id
, id
)) {
516 g_object_ref(iter
->data
);
527 purple_media_manager_register_element(PurpleMediaManager
*manager
,
528 PurpleMediaElementInfo
*info
)
531 PurpleMediaElementInfo
*info2
;
534 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager
), FALSE
);
535 g_return_val_if_fail(info
!= NULL
, FALSE
);
537 id
= purple_media_element_info_get_id(info
);
538 info2
= purple_media_manager_get_element_info(manager
, id
);
542 g_object_unref(info2
);
546 manager
->priv
->elements
=
547 g_list_prepend(manager
->priv
->elements
, info
);
555 purple_media_manager_unregister_element(PurpleMediaManager
*manager
,
559 PurpleMediaElementInfo
*info
;
561 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager
), FALSE
);
563 info
= purple_media_manager_get_element_info(manager
, id
);
566 g_object_unref(info
);
570 if (manager
->priv
->audio_src
== info
)
571 manager
->priv
->audio_src
= NULL
;
572 if (manager
->priv
->audio_sink
== info
)
573 manager
->priv
->audio_sink
= NULL
;
574 if (manager
->priv
->video_src
== info
)
575 manager
->priv
->video_src
= NULL
;
576 if (manager
->priv
->video_sink
== info
)
577 manager
->priv
->video_sink
= NULL
;
579 manager
->priv
->elements
= g_list_remove(
580 manager
->priv
->elements
, info
);
581 g_object_unref(info
);
589 purple_media_manager_set_active_element(PurpleMediaManager
*manager
,
590 PurpleMediaElementInfo
*info
)
593 PurpleMediaElementInfo
*info2
;
594 PurpleMediaElementType type
;
595 gboolean ret
= FALSE
;
598 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager
), FALSE
);
599 g_return_val_if_fail(info
!= NULL
, FALSE
);
601 id
= purple_media_element_info_get_id(info
);
602 info2
= purple_media_manager_get_element_info(manager
, id
);
606 purple_media_manager_register_element(manager
, info
);
608 g_object_unref(info2
);
610 type
= purple_media_element_info_get_element_type(info
);
612 if (type
& PURPLE_MEDIA_ELEMENT_SRC
) {
613 if (type
& PURPLE_MEDIA_ELEMENT_AUDIO
) {
614 manager
->priv
->audio_src
= info
;
617 if (type
& PURPLE_MEDIA_ELEMENT_VIDEO
) {
618 manager
->priv
->video_src
= info
;
622 if (type
& PURPLE_MEDIA_ELEMENT_SINK
) {
623 if (type
& PURPLE_MEDIA_ELEMENT_AUDIO
) {
624 manager
->priv
->audio_sink
= info
;
627 if (type
& PURPLE_MEDIA_ELEMENT_VIDEO
) {
628 manager
->priv
->video_sink
= info
;
639 PurpleMediaElementInfo
*
640 purple_media_manager_get_active_element(PurpleMediaManager
*manager
,
641 PurpleMediaElementType type
)
644 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager
), NULL
);
646 if (type
& PURPLE_MEDIA_ELEMENT_SRC
) {
647 if (type
& PURPLE_MEDIA_ELEMENT_AUDIO
)
648 return manager
->priv
->audio_src
;
649 else if (type
& PURPLE_MEDIA_ELEMENT_VIDEO
)
650 return manager
->priv
->video_src
;
651 } else if (type
& PURPLE_MEDIA_ELEMENT_SINK
) {
652 if (type
& PURPLE_MEDIA_ELEMENT_AUDIO
)
653 return manager
->priv
->audio_sink
;
654 else if (type
& PURPLE_MEDIA_ELEMENT_VIDEO
)
655 return manager
->priv
->video_sink
;
661 #endif /* USE_GSTREAMER */
665 window_id_cb(GstBus
*bus
, GstMessage
*msg
, PurpleMediaOutputWindow
*ow
)
669 if (GST_MESSAGE_TYPE(msg
) != GST_MESSAGE_ELEMENT
||
670 !gst_structure_has_name(msg
->structure
,
671 "prepare-xwindow-id"))
674 sink
= GST_ELEMENT(GST_MESSAGE_SRC(msg
));
675 while (sink
!= ow
->sink
) {
678 sink
= GST_ELEMENT_PARENT(sink
);
681 g_signal_handlers_disconnect_matched(bus
, G_SIGNAL_MATCH_FUNC
682 | G_SIGNAL_MATCH_DATA
, 0, 0, NULL
,
685 gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(
686 GST_MESSAGE_SRC(msg
)), ow
->window_id
);
691 purple_media_manager_create_output_window(PurpleMediaManager
*manager
,
692 PurpleMedia
*media
, const gchar
*session_id
,
693 const gchar
*participant
)
698 g_return_val_if_fail(PURPLE_IS_MEDIA(media
), FALSE
);
700 iter
= manager
->priv
->output_windows
;
701 for(; iter
; iter
= g_list_next(iter
)) {
702 PurpleMediaOutputWindow
*ow
= iter
->data
;
704 if (ow
->sink
== NULL
&& ow
->media
== media
&&
705 ((participant
!= NULL
&&
706 ow
->participant
!= NULL
&&
707 !strcmp(participant
, ow
->participant
)) ||
708 (participant
== ow
->participant
)) &&
709 !strcmp(session_id
, ow
->session_id
)) {
711 GstElement
*queue
, *colorspace
;
712 GstElement
*tee
= purple_media_get_tee(media
,
713 session_id
, participant
);
718 queue
= gst_element_factory_make(
720 colorspace
= gst_element_factory_make(
721 "ffmpegcolorspace", NULL
);
722 ow
->sink
= purple_media_manager_get_element(
723 manager
, PURPLE_MEDIA_RECV_VIDEO
,
724 ow
->media
, ow
->session_id
,
727 if (participant
== NULL
) {
728 /* aka this is a preview sink */
729 GObjectClass
*klass
=
730 G_OBJECT_GET_CLASS(ow
->sink
);
731 if (g_object_class_find_property(klass
,
733 g_object_set(G_OBJECT(ow
->sink
),
734 "sync", "FALSE", NULL
);
735 if (g_object_class_find_property(klass
,
737 g_object_set(G_OBJECT(ow
->sink
),
738 "async", FALSE
, NULL
);
741 gst_bin_add_many(GST_BIN(GST_ELEMENT_PARENT(tee
)),
742 queue
, colorspace
, ow
->sink
, NULL
);
744 bus
= gst_pipeline_get_bus(GST_PIPELINE(
745 manager
->priv
->pipeline
));
746 g_signal_connect(bus
, "sync-message::element",
747 G_CALLBACK(window_id_cb
), ow
);
748 gst_object_unref(bus
);
750 gst_element_set_state(ow
->sink
, GST_STATE_PLAYING
);
751 gst_element_set_state(colorspace
, GST_STATE_PLAYING
);
752 gst_element_set_state(queue
, GST_STATE_PLAYING
);
753 gst_element_link(colorspace
, ow
->sink
);
754 gst_element_link(queue
, colorspace
);
755 gst_element_link(tee
, queue
);
765 purple_media_manager_set_output_window(PurpleMediaManager
*manager
,
766 PurpleMedia
*media
, const gchar
*session_id
,
767 const gchar
*participant
, gulong window_id
)
770 PurpleMediaOutputWindow
*output_window
;
772 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager
), FALSE
);
773 g_return_val_if_fail(PURPLE_IS_MEDIA(media
), FALSE
);
775 output_window
= g_new0(PurpleMediaOutputWindow
, 1);
776 output_window
->id
= manager
->priv
->next_output_window_id
++;
777 output_window
->media
= media
;
778 output_window
->session_id
= g_strdup(session_id
);
779 output_window
->participant
= g_strdup(participant
);
780 output_window
->window_id
= window_id
;
782 manager
->priv
->output_windows
= g_list_prepend(
783 manager
->priv
->output_windows
, output_window
);
785 if (purple_media_get_tee(media
, session_id
, participant
) != NULL
)
786 purple_media_manager_create_output_window(manager
,
787 media
, session_id
, participant
);
789 return output_window
->id
;
796 purple_media_manager_remove_output_window(PurpleMediaManager
*manager
,
797 gulong output_window_id
)
800 PurpleMediaOutputWindow
*output_window
= NULL
;
803 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager
), FALSE
);
805 iter
= manager
->priv
->output_windows
;
806 for (; iter
; iter
= g_list_next(iter
)) {
807 PurpleMediaOutputWindow
*ow
= iter
->data
;
808 if (ow
->id
== output_window_id
) {
809 manager
->priv
->output_windows
= g_list_delete_link(
810 manager
->priv
->output_windows
, iter
);
816 if (output_window
== NULL
)
819 if (output_window
->sink
!= NULL
) {
820 GstPad
*pad
= gst_element_get_static_pad(
821 output_window
->sink
, "sink");
822 GstPad
*peer
= gst_pad_get_peer(pad
);
823 GstElement
*colorspace
= GST_ELEMENT_PARENT(peer
), *queue
;
824 gst_object_unref(pad
);
825 gst_object_unref(peer
);
826 pad
= gst_element_get_static_pad(colorspace
, "sink");
827 peer
= gst_pad_get_peer(pad
);
828 queue
= GST_ELEMENT_PARENT(peer
);
829 gst_object_unref(pad
);
830 gst_object_unref(peer
);
831 pad
= gst_element_get_static_pad(queue
, "sink");
832 peer
= gst_pad_get_peer(pad
);
833 gst_object_unref(pad
);
835 gst_element_release_request_pad(GST_ELEMENT_PARENT(peer
), peer
);
836 gst_element_set_locked_state(queue
, TRUE
);
837 gst_element_set_state(queue
, GST_STATE_NULL
);
838 gst_bin_remove(GST_BIN(GST_ELEMENT_PARENT(queue
)), queue
);
839 gst_element_set_locked_state(colorspace
, TRUE
);
840 gst_element_set_state(colorspace
, GST_STATE_NULL
);
841 gst_bin_remove(GST_BIN(GST_ELEMENT_PARENT(colorspace
)), colorspace
);
842 gst_element_set_locked_state(output_window
->sink
, TRUE
);
843 gst_element_set_state(output_window
->sink
, GST_STATE_NULL
);
844 gst_bin_remove(GST_BIN(GST_ELEMENT_PARENT(output_window
->sink
)),
845 output_window
->sink
);
848 g_free(output_window
->session_id
);
849 g_free(output_window
->participant
);
850 g_free(output_window
);
859 purple_media_manager_remove_output_windows(PurpleMediaManager
*manager
,
860 PurpleMedia
*media
, const gchar
*session_id
,
861 const gchar
*participant
)
866 g_return_if_fail(PURPLE_IS_MEDIA(media
));
868 iter
= manager
->priv
->output_windows
;
871 PurpleMediaOutputWindow
*ow
= iter
->data
;
872 iter
= g_list_next(iter
);
874 if (media
== ow
->media
&&
875 ((session_id
!= NULL
&& ow
->session_id
!= NULL
&&
876 !strcmp(session_id
, ow
->session_id
)) ||
877 (session_id
== ow
->session_id
)) &&
878 ((participant
!= NULL
&& ow
->participant
!= NULL
&&
879 !strcmp(participant
, ow
->participant
)) ||
880 (participant
== ow
->participant
)))
881 purple_media_manager_remove_output_window(
888 purple_media_manager_set_ui_caps(PurpleMediaManager
*manager
,
889 PurpleMediaCaps caps
)
892 PurpleMediaCaps oldcaps
;
894 g_return_if_fail(PURPLE_IS_MEDIA_MANAGER(manager
));
896 oldcaps
= manager
->priv
->ui_caps
;
897 manager
->priv
->ui_caps
= caps
;
900 g_signal_emit(manager
,
901 purple_media_manager_signals
[UI_CAPS_CHANGED
],
907 purple_media_manager_get_ui_caps(PurpleMediaManager
*manager
)
910 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager
),
911 PURPLE_MEDIA_CAPS_NONE
);
912 return manager
->priv
->ui_caps
;
914 return PURPLE_MEDIA_CAPS_NONE
;
919 purple_media_manager_set_backend_type(PurpleMediaManager
*manager
,
923 g_return_if_fail(PURPLE_IS_MEDIA_MANAGER(manager
));
925 manager
->priv
->backend_type
= backend_type
;
930 purple_media_manager_get_backend_type(PurpleMediaManager
*manager
)
933 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager
),
934 PURPLE_MEDIA_CAPS_NONE
);
936 return manager
->priv
->backend_type
;
945 * PurpleMediaElementType
949 purple_media_element_type_get_type()
951 static GType type
= 0;
953 static const GFlagsValue values
[] = {
954 { PURPLE_MEDIA_ELEMENT_NONE
,
955 "PURPLE_MEDIA_ELEMENT_NONE", "none" },
956 { PURPLE_MEDIA_ELEMENT_AUDIO
,
957 "PURPLE_MEDIA_ELEMENT_AUDIO", "audio" },
958 { PURPLE_MEDIA_ELEMENT_VIDEO
,
959 "PURPLE_MEDIA_ELEMENT_VIDEO", "video" },
960 { PURPLE_MEDIA_ELEMENT_AUDIO_VIDEO
,
961 "PURPLE_MEDIA_ELEMENT_AUDIO_VIDEO",
963 { PURPLE_MEDIA_ELEMENT_NO_SRCS
,
964 "PURPLE_MEDIA_ELEMENT_NO_SRCS", "no-srcs" },
965 { PURPLE_MEDIA_ELEMENT_ONE_SRC
,
966 "PURPLE_MEDIA_ELEMENT_ONE_SRC", "one-src" },
967 { PURPLE_MEDIA_ELEMENT_MULTI_SRC
,
968 "PURPLE_MEDIA_ELEMENT_MULTI_SRC",
970 { PURPLE_MEDIA_ELEMENT_REQUEST_SRC
,
971 "PURPLE_MEDIA_ELEMENT_REQUEST_SRC",
973 { PURPLE_MEDIA_ELEMENT_NO_SINKS
,
974 "PURPLE_MEDIA_ELEMENT_NO_SINKS", "no-sinks" },
975 { PURPLE_MEDIA_ELEMENT_ONE_SINK
,
976 "PURPLE_MEDIA_ELEMENT_ONE_SINK", "one-sink" },
977 { PURPLE_MEDIA_ELEMENT_MULTI_SINK
,
978 "PURPLE_MEDIA_ELEMENT_MULTI_SINK",
980 { PURPLE_MEDIA_ELEMENT_REQUEST_SINK
,
981 "PURPLE_MEDIA_ELEMENT_REQUEST_SINK",
983 { PURPLE_MEDIA_ELEMENT_UNIQUE
,
984 "PURPLE_MEDIA_ELEMENT_UNIQUE", "unique" },
985 { PURPLE_MEDIA_ELEMENT_SRC
,
986 "PURPLE_MEDIA_ELEMENT_SRC", "src" },
987 { PURPLE_MEDIA_ELEMENT_SINK
,
988 "PURPLE_MEDIA_ELEMENT_SINK", "sink" },
991 type
= g_flags_register_static(
992 "PurpleMediaElementType", values
);
998 * PurpleMediaElementInfo
1001 struct _PurpleMediaElementInfoClass
1003 GObjectClass parent_class
;
1006 struct _PurpleMediaElementInfo
1012 struct _PurpleMediaElementInfoPrivate
1016 PurpleMediaElementType type
;
1017 PurpleMediaElementCreateCallback create
;
1029 purple_media_element_info_init(PurpleMediaElementInfo
*info
)
1031 PurpleMediaElementInfoPrivate
*priv
=
1032 PURPLE_MEDIA_ELEMENT_INFO_GET_PRIVATE(info
);
1035 priv
->type
= PURPLE_MEDIA_ELEMENT_NONE
;
1036 priv
->create
= NULL
;
1040 purple_media_element_info_finalize(GObject
*info
)
1042 PurpleMediaElementInfoPrivate
*priv
=
1043 PURPLE_MEDIA_ELEMENT_INFO_GET_PRIVATE(info
);
1049 purple_media_element_info_set_property (GObject
*object
, guint prop_id
,
1050 const GValue
*value
, GParamSpec
*pspec
)
1052 PurpleMediaElementInfoPrivate
*priv
;
1053 g_return_if_fail(PURPLE_IS_MEDIA_ELEMENT_INFO(object
));
1055 priv
= PURPLE_MEDIA_ELEMENT_INFO_GET_PRIVATE(object
);
1060 priv
->id
= g_value_dup_string(value
);
1064 priv
->name
= g_value_dup_string(value
);
1067 priv
->type
= g_value_get_flags(value
);
1070 case PROP_CREATE_CB
:
1071 priv
->create
= g_value_get_pointer(value
);
1074 G_OBJECT_WARN_INVALID_PROPERTY_ID(
1075 object
, prop_id
, pspec
);
1081 purple_media_element_info_get_property (GObject
*object
, guint prop_id
,
1082 GValue
*value
, GParamSpec
*pspec
)
1084 PurpleMediaElementInfoPrivate
*priv
;
1085 g_return_if_fail(PURPLE_IS_MEDIA_ELEMENT_INFO(object
));
1087 priv
= PURPLE_MEDIA_ELEMENT_INFO_GET_PRIVATE(object
);
1091 g_value_set_string(value
, priv
->id
);
1094 g_value_set_string(value
, priv
->name
);
1097 g_value_set_flags(value
, priv
->type
);
1099 case PROP_CREATE_CB
:
1100 g_value_set_pointer(value
, priv
->create
);
1103 G_OBJECT_WARN_INVALID_PROPERTY_ID(
1104 object
, prop_id
, pspec
);
1110 purple_media_element_info_class_init(PurpleMediaElementInfoClass
*klass
)
1112 GObjectClass
*gobject_class
= (GObjectClass
*)klass
;
1114 gobject_class
->finalize
= purple_media_element_info_finalize
;
1115 gobject_class
->set_property
= purple_media_element_info_set_property
;
1116 gobject_class
->get_property
= purple_media_element_info_get_property
;
1118 g_object_class_install_property(gobject_class
, PROP_ID
,
1119 g_param_spec_string("id",
1121 "The unique identifier of the element.",
1123 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
));
1125 g_object_class_install_property(gobject_class
, PROP_NAME
,
1126 g_param_spec_string("name",
1128 "The friendly/display name of this element.",
1130 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
));
1132 g_object_class_install_property(gobject_class
, PROP_TYPE
,
1133 g_param_spec_flags("type",
1135 "The type of element this is.",
1136 PURPLE_TYPE_MEDIA_ELEMENT_TYPE
,
1137 PURPLE_MEDIA_ELEMENT_NONE
,
1138 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
));
1140 g_object_class_install_property(gobject_class
, PROP_CREATE_CB
,
1141 g_param_spec_pointer("create-cb",
1143 "The function called to create this element.",
1144 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
));
1146 g_type_class_add_private(klass
, sizeof(PurpleMediaElementInfoPrivate
));
1149 G_DEFINE_TYPE(PurpleMediaElementInfo
,
1150 purple_media_element_info
, G_TYPE_OBJECT
);
1153 purple_media_element_info_get_type()
1160 purple_media_element_info_get_id(PurpleMediaElementInfo
*info
)
1164 g_return_val_if_fail(PURPLE_IS_MEDIA_ELEMENT_INFO(info
), NULL
);
1165 g_object_get(info
, "id", &id
, NULL
);
1173 purple_media_element_info_get_name(PurpleMediaElementInfo
*info
)
1177 g_return_val_if_fail(PURPLE_IS_MEDIA_ELEMENT_INFO(info
), NULL
);
1178 g_object_get(info
, "name", &name
, NULL
);
1185 PurpleMediaElementType
1186 purple_media_element_info_get_element_type(PurpleMediaElementInfo
*info
)
1189 PurpleMediaElementType type
;
1190 g_return_val_if_fail(PURPLE_IS_MEDIA_ELEMENT_INFO(info
),
1191 PURPLE_MEDIA_ELEMENT_NONE
);
1192 g_object_get(info
, "type", &type
, NULL
);
1195 return PURPLE_MEDIA_ELEMENT_NONE
;
1200 purple_media_element_info_call_create(PurpleMediaElementInfo
*info
,
1201 PurpleMedia
*media
, const gchar
*session_id
,
1202 const gchar
*participant
)
1205 PurpleMediaElementCreateCallback create
;
1206 g_return_val_if_fail(PURPLE_IS_MEDIA_ELEMENT_INFO(info
), NULL
);
1207 g_object_get(info
, "create-cb", &create
, NULL
);
1209 return create(media
, session_id
, participant
);
1214 #endif /* USE_GSTREAMER */