These changes are reuired to make the Windows installer build.
[pidgin-git.git] / libpurple / mediamanager.c
blob808bba4a7db4e04d088bc4f64e442721fb7bde6a
1 /**
2 * @file mediamanager.c Media Manager API
3 * @ingroup core
4 */
6 /* purple
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
27 #include "internal.h"
29 #include "account.h"
30 #include "debug.h"
31 #include "media.h"
32 #include "mediamanager.h"
34 #ifdef USE_GSTREAMER
35 #include "marshallers.h"
36 #include "media-gst.h"
37 #endif
39 #ifdef USE_VV
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
67 gulong id;
68 PurpleMedia *media;
69 gchar *session_id;
70 gchar *participant;
71 gulong window_id;
72 GstElement *sink;
75 struct _PurpleMediaManagerPrivate
77 GstElement *pipeline;
78 PurpleMediaCaps ui_caps;
79 GList *medias;
80 GList *elements;
81 GList *output_windows;
82 gulong next_output_window_id;
83 GType backend_type;
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;
102 enum {
103 INIT_MEDIA,
104 UI_CAPS_CHANGED,
105 LAST_SIGNAL
107 static guint purple_media_manager_signals[LAST_SIGNAL] = {0};
108 #endif
110 GType
111 purple_media_manager_get_type()
113 #ifdef USE_VV
114 static GType type = 0;
116 if (type == 0) {
117 static const GTypeInfo info = {
118 sizeof(PurpleMediaManagerClass),
119 NULL,
120 NULL,
121 (GClassInitFunc) purple_media_manager_class_init,
122 NULL,
123 NULL,
124 sizeof(PurpleMediaManager),
126 (GInstanceInitFunc) purple_media_manager_init,
127 NULL
129 type = g_type_register_static(G_TYPE_OBJECT, "PurpleMediaManager", &info, 0);
131 return type;
132 #else
133 return G_TYPE_NONE;
134 #endif
137 #ifdef USE_VV
138 static void
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),
148 G_SIGNAL_RUN_LAST,
149 0, NULL, NULL,
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),
156 G_SIGNAL_RUN_LAST,
157 0, NULL, NULL,
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));
165 static void
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;
171 #ifdef USE_VV
172 media->priv->backend_type = PURPLE_TYPE_MEDIA_BACKEND_FS2;
173 #endif
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);
182 static void
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);
196 #endif
198 PurpleMediaManager *
199 purple_media_manager_get()
201 #ifdef USE_VV
202 static PurpleMediaManager *manager = NULL;
204 if (manager == NULL)
205 manager = PURPLE_MEDIA_MANAGER(g_object_new(purple_media_manager_get_type(), NULL));
206 return manager;
207 #else
208 return NULL;
209 #endif
212 #ifdef USE_VV
213 static gboolean
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");
219 break;
220 case GST_MESSAGE_ERROR: {
221 gchar *debug = NULL;
222 GError *err = NULL;
224 gst_message_parse_error(msg, &err, &debug);
226 purple_debug_error("mediamanager",
227 "gst pipeline error: %s\n",
228 err->message);
229 g_error_free(err);
231 if (debug) {
232 purple_debug_error("mediamanager",
233 "Debug details: %s\n", debug);
234 g_free (debug);
236 break;
238 default:
239 break;
241 return TRUE;
243 #endif
245 #ifdef USE_GSTREAMER
246 GstElement *
247 purple_media_manager_get_pipeline(PurpleMediaManager *manager)
249 #ifdef USE_VV
250 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), NULL);
252 if (manager->priv->pipeline == NULL) {
253 FsElementAddedNotifier *notifier;
254 gchar *filename;
255 GError *err = NULL;
256 GKeyFile *keyfile;
257 GstBus *bus;
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)) {
274 if (err->code == 4)
275 purple_debug_info("mediamanager",
276 "Couldn't read "
277 "fs-element.conf: %s\n",
278 err->message);
279 else
280 purple_debug_error("mediamanager",
281 "Error reading "
282 "fs-element.conf: %s\n",
283 err->message);
284 g_error_free(err);
286 g_free(filename);
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(
299 notifier, keyfile);
301 gst_element_set_state(manager->priv->pipeline,
302 GST_STATE_PLAYING);
305 return manager->priv->pipeline;
306 #else
307 return NULL;
308 #endif
310 #endif /* USE_GSTREAMER */
312 PurpleMedia *
313 purple_media_manager_create_media(PurpleMediaManager *manager,
314 PurpleAccount *account,
315 const char *conference_type,
316 const char *remote_user,
317 gboolean initiator)
319 #ifdef USE_VV
320 PurpleMedia *media;
321 gboolean signal_ret;
323 media = PURPLE_MEDIA(g_object_new(purple_media_get_type(),
324 "manager", manager,
325 "account", account,
326 "conference-type", conference_type,
327 "initiator", initiator,
328 NULL));
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);
335 return NULL;
338 manager->priv->medias = g_list_append(manager->priv->medias, media);
339 return media;
340 #else
341 return NULL;
342 #endif
345 GList *
346 purple_media_manager_get_media(PurpleMediaManager *manager)
348 #ifdef USE_VV
349 return manager->priv->medias;
350 #else
351 return NULL;
352 #endif
355 GList *
356 purple_media_manager_get_media_by_account(PurpleMediaManager *manager,
357 PurpleAccount *account)
359 #ifdef USE_VV
360 GList *media = NULL;
361 GList *iter;
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);
372 return media;
373 #else
374 return NULL;
375 #endif
378 void
379 purple_media_manager_remove_media(PurpleMediaManager *manager,
380 PurpleMedia *media)
382 #ifdef USE_VV
383 GList *list = g_list_find(manager->priv->medias, media);
384 if (list)
385 manager->priv->medias =
386 g_list_delete_link(manager->priv->medias, list);
387 #endif
390 #ifdef USE_VV
391 static void
392 request_pad_unlinked_cb(GstPad *pad, GstPad *peer, gpointer user_data)
394 GstElement *parent = GST_ELEMENT_PARENT(pad);
395 GstIterator *iter;
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);
414 #endif
416 #ifdef USE_GSTREAMER
417 GstElement *
418 purple_media_manager_get_element(PurpleMediaManager *manager,
419 PurpleMediaSessionType type, PurpleMedia *media,
420 const gchar *session_id, const gchar *participant)
422 #ifdef USE_VV
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;
436 if (info == NULL)
437 return NULL;
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) {
443 GstElement *tee;
444 GstPad *pad;
445 GstPad *ghost;
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(
450 manager)), id);
452 if (ret == NULL) {
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);
470 ret = bin;
471 gst_object_ref(ret);
472 gst_bin_add(GST_BIN(purple_media_manager_get_pipeline(
473 manager)), ret);
475 g_free(id);
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);
486 } else {
487 ret = purple_media_element_info_call_create(info,
488 media, session_id, participant);
491 if (ret == NULL)
492 purple_debug_error("media", "Error creating source or sink\n");
494 return ret;
495 #else
496 return NULL;
497 #endif
500 PurpleMediaElementInfo *
501 purple_media_manager_get_element_info(PurpleMediaManager *manager,
502 const gchar *id)
504 #ifdef USE_VV
505 GList *iter;
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)) {
512 gchar *element_id =
513 purple_media_element_info_get_id(iter->data);
514 if (!strcmp(element_id, id)) {
515 g_free(element_id);
516 g_object_ref(iter->data);
517 return iter->data;
519 g_free(element_id);
521 #endif
523 return NULL;
526 gboolean
527 purple_media_manager_register_element(PurpleMediaManager *manager,
528 PurpleMediaElementInfo *info)
530 #ifdef USE_VV
531 PurpleMediaElementInfo *info2;
532 gchar *id;
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);
539 g_free(id);
541 if (info2 != NULL) {
542 g_object_unref(info2);
543 return FALSE;
546 manager->priv->elements =
547 g_list_prepend(manager->priv->elements, info);
548 return TRUE;
549 #else
550 return FALSE;
551 #endif
554 gboolean
555 purple_media_manager_unregister_element(PurpleMediaManager *manager,
556 const gchar *id)
558 #ifdef USE_VV
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);
565 if (info == NULL) {
566 g_object_unref(info);
567 return FALSE;
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);
582 return TRUE;
583 #else
584 return FALSE;
585 #endif
588 gboolean
589 purple_media_manager_set_active_element(PurpleMediaManager *manager,
590 PurpleMediaElementInfo *info)
592 #ifdef USE_VV
593 PurpleMediaElementInfo *info2;
594 PurpleMediaElementType type;
595 gboolean ret = FALSE;
596 gchar *id;
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);
603 g_free(id);
605 if (info2 == NULL)
606 purple_media_manager_register_element(manager, info);
607 else
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;
615 ret = TRUE;
617 if (type & PURPLE_MEDIA_ELEMENT_VIDEO) {
618 manager->priv->video_src = info;
619 ret = TRUE;
622 if (type & PURPLE_MEDIA_ELEMENT_SINK) {
623 if (type & PURPLE_MEDIA_ELEMENT_AUDIO) {
624 manager->priv->audio_sink = info;
625 ret = TRUE;
627 if (type & PURPLE_MEDIA_ELEMENT_VIDEO) {
628 manager->priv->video_sink = info;
629 ret = TRUE;
633 return ret;
634 #else
635 return FALSE;
636 #endif
639 PurpleMediaElementInfo *
640 purple_media_manager_get_active_element(PurpleMediaManager *manager,
641 PurpleMediaElementType type)
643 #ifdef USE_VV
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;
657 #endif
659 return NULL;
661 #endif /* USE_GSTREAMER */
663 #ifdef USE_VV
664 static void
665 window_id_cb(GstBus *bus, GstMessage *msg, PurpleMediaOutputWindow *ow)
667 GstElement *sink;
669 if (GST_MESSAGE_TYPE(msg) != GST_MESSAGE_ELEMENT ||
670 !gst_structure_has_name(msg->structure,
671 "prepare-xwindow-id"))
672 return;
674 sink = GST_ELEMENT(GST_MESSAGE_SRC(msg));
675 while (sink != ow->sink) {
676 if (sink == NULL)
677 return;
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,
683 window_id_cb, ow);
685 gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(
686 GST_MESSAGE_SRC(msg)), ow->window_id);
688 #endif
690 gboolean
691 purple_media_manager_create_output_window(PurpleMediaManager *manager,
692 PurpleMedia *media, const gchar *session_id,
693 const gchar *participant)
695 #ifdef USE_VV
696 GList *iter;
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)) {
710 GstBus *bus;
711 GstElement *queue, *colorspace;
712 GstElement *tee = purple_media_get_tee(media,
713 session_id, participant);
715 if (tee == NULL)
716 continue;
718 queue = gst_element_factory_make(
719 "queue", NULL);
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,
725 ow->participant);
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,
732 "sync"))
733 g_object_set(G_OBJECT(ow->sink),
734 "sync", "FALSE", NULL);
735 if (g_object_class_find_property(klass,
736 "async"))
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);
758 return TRUE;
759 #else
760 return FALSE;
761 #endif
764 gulong
765 purple_media_manager_set_output_window(PurpleMediaManager *manager,
766 PurpleMedia *media, const gchar *session_id,
767 const gchar *participant, gulong window_id)
769 #ifdef USE_VV
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;
790 #else
791 return 0;
792 #endif
795 gboolean
796 purple_media_manager_remove_output_window(PurpleMediaManager *manager,
797 gulong output_window_id)
799 #ifdef USE_VV
800 PurpleMediaOutputWindow *output_window = NULL;
801 GList *iter;
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);
811 output_window = ow;
812 break;
816 if (output_window == NULL)
817 return FALSE;
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);
834 if (peer != NULL)
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);
852 return TRUE;
853 #else
854 return FALSE;
855 #endif
858 void
859 purple_media_manager_remove_output_windows(PurpleMediaManager *manager,
860 PurpleMedia *media, const gchar *session_id,
861 const gchar *participant)
863 #ifdef USE_VV
864 GList *iter;
866 g_return_if_fail(PURPLE_IS_MEDIA(media));
868 iter = manager->priv->output_windows;
870 for (; iter;) {
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(
882 manager, ow->id);
884 #endif
887 void
888 purple_media_manager_set_ui_caps(PurpleMediaManager *manager,
889 PurpleMediaCaps caps)
891 #ifdef USE_VV
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;
899 if (caps != oldcaps)
900 g_signal_emit(manager,
901 purple_media_manager_signals[UI_CAPS_CHANGED],
902 0, caps, oldcaps);
903 #endif
906 PurpleMediaCaps
907 purple_media_manager_get_ui_caps(PurpleMediaManager *manager)
909 #ifdef USE_VV
910 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager),
911 PURPLE_MEDIA_CAPS_NONE);
912 return manager->priv->ui_caps;
913 #else
914 return PURPLE_MEDIA_CAPS_NONE;
915 #endif
918 void
919 purple_media_manager_set_backend_type(PurpleMediaManager *manager,
920 GType backend_type)
922 #ifdef USE_VV
923 g_return_if_fail(PURPLE_IS_MEDIA_MANAGER(manager));
925 manager->priv->backend_type = backend_type;
926 #endif
929 GType
930 purple_media_manager_get_backend_type(PurpleMediaManager *manager)
932 #ifdef USE_VV
933 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager),
934 PURPLE_MEDIA_CAPS_NONE);
936 return manager->priv->backend_type;
937 #else
938 return G_TYPE_NONE;
939 #endif
942 #ifdef USE_GSTREAMER
945 * PurpleMediaElementType
948 GType
949 purple_media_element_type_get_type()
951 static GType type = 0;
952 if (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",
962 "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",
969 "multi-src" },
970 { PURPLE_MEDIA_ELEMENT_REQUEST_SRC,
971 "PURPLE_MEDIA_ELEMENT_REQUEST_SRC",
972 "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",
979 "multi-sink" },
980 { PURPLE_MEDIA_ELEMENT_REQUEST_SINK,
981 "PURPLE_MEDIA_ELEMENT_REQUEST_SINK",
982 "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" },
989 { 0, NULL, NULL }
991 type = g_flags_register_static(
992 "PurpleMediaElementType", values);
994 return type;
998 * PurpleMediaElementInfo
1001 struct _PurpleMediaElementInfoClass
1003 GObjectClass parent_class;
1006 struct _PurpleMediaElementInfo
1008 GObject parent;
1011 #ifdef USE_VV
1012 struct _PurpleMediaElementInfoPrivate
1014 gchar *id;
1015 gchar *name;
1016 PurpleMediaElementType type;
1017 PurpleMediaElementCreateCallback create;
1020 enum {
1021 PROP_0,
1022 PROP_ID,
1023 PROP_NAME,
1024 PROP_TYPE,
1025 PROP_CREATE_CB,
1028 static void
1029 purple_media_element_info_init(PurpleMediaElementInfo *info)
1031 PurpleMediaElementInfoPrivate *priv =
1032 PURPLE_MEDIA_ELEMENT_INFO_GET_PRIVATE(info);
1033 priv->id = NULL;
1034 priv->name = NULL;
1035 priv->type = PURPLE_MEDIA_ELEMENT_NONE;
1036 priv->create = NULL;
1039 static void
1040 purple_media_element_info_finalize(GObject *info)
1042 PurpleMediaElementInfoPrivate *priv =
1043 PURPLE_MEDIA_ELEMENT_INFO_GET_PRIVATE(info);
1044 g_free(priv->id);
1045 g_free(priv->name);
1048 static void
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);
1057 switch (prop_id) {
1058 case PROP_ID:
1059 g_free(priv->id);
1060 priv->id = g_value_dup_string(value);
1061 break;
1062 case PROP_NAME:
1063 g_free(priv->name);
1064 priv->name = g_value_dup_string(value);
1065 break;
1066 case PROP_TYPE: {
1067 priv->type = g_value_get_flags(value);
1068 break;
1070 case PROP_CREATE_CB:
1071 priv->create = g_value_get_pointer(value);
1072 break;
1073 default:
1074 G_OBJECT_WARN_INVALID_PROPERTY_ID(
1075 object, prop_id, pspec);
1076 break;
1080 static void
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);
1089 switch (prop_id) {
1090 case PROP_ID:
1091 g_value_set_string(value, priv->id);
1092 break;
1093 case PROP_NAME:
1094 g_value_set_string(value, priv->name);
1095 break;
1096 case PROP_TYPE:
1097 g_value_set_flags(value, priv->type);
1098 break;
1099 case PROP_CREATE_CB:
1100 g_value_set_pointer(value, priv->create);
1101 break;
1102 default:
1103 G_OBJECT_WARN_INVALID_PROPERTY_ID(
1104 object, prop_id, pspec);
1105 break;
1109 static void
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",
1120 "ID",
1121 "The unique identifier of the element.",
1122 NULL,
1123 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
1125 g_object_class_install_property(gobject_class, PROP_NAME,
1126 g_param_spec_string("name",
1127 "Name",
1128 "The friendly/display name of this element.",
1129 NULL,
1130 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
1132 g_object_class_install_property(gobject_class, PROP_TYPE,
1133 g_param_spec_flags("type",
1134 "Element 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",
1142 "Create Callback",
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);
1151 #else
1152 GType
1153 purple_media_element_info_get_type()
1155 return G_TYPE_NONE;
1157 #endif
1159 gchar *
1160 purple_media_element_info_get_id(PurpleMediaElementInfo *info)
1162 #ifdef USE_VV
1163 gchar *id;
1164 g_return_val_if_fail(PURPLE_IS_MEDIA_ELEMENT_INFO(info), NULL);
1165 g_object_get(info, "id", &id, NULL);
1166 return id;
1167 #else
1168 return NULL;
1169 #endif
1172 gchar *
1173 purple_media_element_info_get_name(PurpleMediaElementInfo *info)
1175 #ifdef USE_VV
1176 gchar *name;
1177 g_return_val_if_fail(PURPLE_IS_MEDIA_ELEMENT_INFO(info), NULL);
1178 g_object_get(info, "name", &name, NULL);
1179 return name;
1180 #else
1181 return NULL;
1182 #endif
1185 PurpleMediaElementType
1186 purple_media_element_info_get_element_type(PurpleMediaElementInfo *info)
1188 #ifdef USE_VV
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);
1193 return type;
1194 #else
1195 return PURPLE_MEDIA_ELEMENT_NONE;
1196 #endif
1199 GstElement *
1200 purple_media_element_info_call_create(PurpleMediaElementInfo *info,
1201 PurpleMedia *media, const gchar *session_id,
1202 const gchar *participant)
1204 #ifdef USE_VV
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);
1208 if (create)
1209 return create(media, session_id, participant);
1210 #endif
1211 return NULL;
1214 #endif /* USE_GSTREAMER */