Mercurial > pidgin
view libpurple/mediamanager.c @ 29475:6d2ba42595fe
oscar: Fix a race condition that leads to a crash.
With SSL enabled, if we start connecting and something calls
purple_account_disconnect between when an SSL flap connection is started
and when the connection is actually established, it isn't properly
cleaned up (and we try to close the flap), which leads to free-after-use.
You can simulate this by adding a timeout-triggered disconnect to the
end of oscar_connect_to_bos.
[02/22/10 17:11:51] <libpurple/oscar> Destroying oscar connection of type 0x0002. Disconnect reason is 0
[02/22/10 17:11:51] <libpurple/oscar> Disconnected. Code is 0x0000 and msg is
(hiicq:17126): GLib-WARNING **: giounix.c:400Error while getting flags for FD: Bad file descriptor (9)
[02/22/10 17:11:51] <libpurple/oscar> Scheduling destruction of FLAP connection of type 0x0002
[02/22/10 17:11:51] <libpurple/oscar> Signed off.
...
[02/22/10 17:11:51] <libpurple/oscar> Destroying oscar connection of type 0x7261. Disconnect reason is 1668179315
author | Paul Aurich <paul@darkrain42.org> |
---|---|
date | Mon, 22 Feb 2010 17:53:38 +0000 |
parents | 2b2b930281a0 |
children | a8cc50c2279f |
line wrap: on
line source
/** * @file mediamanager.c Media Manager API * @ingroup core */ /* purple * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ #include "internal.h" #include "account.h" #include "debug.h" #include "media.h" #include "mediamanager.h" #ifdef USE_GSTREAMER #include "marshallers.h" #include "media-gst.h" #endif #ifdef USE_VV #include <media/backend-fs2.h> #include <gst/farsight/fs-element-added-notifier.h> #include <gst/interfaces/xoverlay.h> /** @copydoc _PurpleMediaManagerPrivate */ typedef struct _PurpleMediaManagerPrivate PurpleMediaManagerPrivate; /** @copydoc _PurpleMediaOutputWindow */ typedef struct _PurpleMediaOutputWindow PurpleMediaOutputWindow; /** @copydoc _PurpleMediaManagerPrivate */ typedef struct _PurpleMediaElementInfoPrivate PurpleMediaElementInfoPrivate; /** The media manager class. */ struct _PurpleMediaManagerClass { GObjectClass parent_class; /**< The parent class. */ }; /** The media manager's data. */ struct _PurpleMediaManager { GObject parent; /**< The parent of this manager. */ PurpleMediaManagerPrivate *priv; /**< Private data for the manager. */ }; struct _PurpleMediaOutputWindow { gulong id; PurpleMedia *media; gchar *session_id; gchar *participant; gulong window_id; GstElement *sink; }; struct _PurpleMediaManagerPrivate { GstElement *pipeline; PurpleMediaCaps ui_caps; GList *medias; GList *elements; GList *output_windows; gulong next_output_window_id; GType backend_type; PurpleMediaElementInfo *video_src; PurpleMediaElementInfo *video_sink; PurpleMediaElementInfo *audio_src; PurpleMediaElementInfo *audio_sink; }; #define PURPLE_MEDIA_MANAGER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_MEDIA_MANAGER, PurpleMediaManagerPrivate)) #define PURPLE_MEDIA_ELEMENT_INFO_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_MEDIA_ELEMENT_INFO, PurpleMediaElementInfoPrivate)) static void purple_media_manager_class_init (PurpleMediaManagerClass *klass); static void purple_media_manager_init (PurpleMediaManager *media); static void purple_media_manager_finalize (GObject *object); static GObjectClass *parent_class = NULL; enum { INIT_MEDIA, UI_CAPS_CHANGED, LAST_SIGNAL }; static guint purple_media_manager_signals[LAST_SIGNAL] = {0}; #endif GType purple_media_manager_get_type() { #ifdef USE_VV static GType type = 0; if (type == 0) { static const GTypeInfo info = { sizeof(PurpleMediaManagerClass), NULL, NULL, (GClassInitFunc) purple_media_manager_class_init, NULL, NULL, sizeof(PurpleMediaManager), 0, (GInstanceInitFunc) purple_media_manager_init, NULL }; type = g_type_register_static(G_TYPE_OBJECT, "PurpleMediaManager", &info, 0); } return type; #else return G_TYPE_NONE; #endif } #ifdef USE_VV static void purple_media_manager_class_init (PurpleMediaManagerClass *klass) { GObjectClass *gobject_class = (GObjectClass*)klass; parent_class = g_type_class_peek_parent(klass); gobject_class->finalize = purple_media_manager_finalize; purple_media_manager_signals[INIT_MEDIA] = g_signal_new ("init-media", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, purple_smarshal_BOOLEAN__OBJECT_POINTER_STRING, G_TYPE_BOOLEAN, 3, PURPLE_TYPE_MEDIA, G_TYPE_POINTER, G_TYPE_STRING); purple_media_manager_signals[UI_CAPS_CHANGED] = g_signal_new ("ui-caps-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, purple_smarshal_VOID__FLAGS_FLAGS, G_TYPE_NONE, 2, PURPLE_MEDIA_TYPE_CAPS, PURPLE_MEDIA_TYPE_CAPS); g_type_class_add_private(klass, sizeof(PurpleMediaManagerPrivate)); } static void purple_media_manager_init (PurpleMediaManager *media) { media->priv = PURPLE_MEDIA_MANAGER_GET_PRIVATE(media); media->priv->medias = NULL; media->priv->next_output_window_id = 1; #ifdef USE_VV media->priv->backend_type = PURPLE_TYPE_MEDIA_BACKEND_FS2; #endif purple_prefs_add_none("/purple/media"); purple_prefs_add_none("/purple/media/audio"); purple_prefs_add_none("/purple/media/audio/volume"); purple_prefs_add_int("/purple/media/audio/volume/input", 10); purple_prefs_add_int("/purple/media/audio/volume/output", 10); } static void purple_media_manager_finalize (GObject *media) { PurpleMediaManagerPrivate *priv = PURPLE_MEDIA_MANAGER_GET_PRIVATE(media); for (; priv->medias; priv->medias = g_list_delete_link(priv->medias, priv->medias)) { g_object_unref(priv->medias->data); } for (; priv->elements; priv->elements = g_list_delete_link(priv->elements, priv->elements)) { g_object_unref(priv->elements->data); } parent_class->finalize(media); } #endif PurpleMediaManager * purple_media_manager_get() { #ifdef USE_VV static PurpleMediaManager *manager = NULL; if (manager == NULL) manager = PURPLE_MEDIA_MANAGER(g_object_new(purple_media_manager_get_type(), NULL)); return manager; #else return NULL; #endif } #ifdef USE_VV static gboolean pipeline_bus_call(GstBus *bus, GstMessage *msg, PurpleMediaManager *manager) { switch(GST_MESSAGE_TYPE(msg)) { case GST_MESSAGE_EOS: purple_debug_info("mediamanager", "End of Stream\n"); break; case GST_MESSAGE_ERROR: { gchar *debug = NULL; GError *err = NULL; gst_message_parse_error(msg, &err, &debug); purple_debug_error("mediamanager", "gst pipeline error: %s\n", err->message); g_error_free(err); if (debug) { purple_debug_error("mediamanager", "Debug details: %s\n", debug); g_free (debug); } break; } default: break; } return TRUE; } #endif #ifdef USE_GSTREAMER GstElement * purple_media_manager_get_pipeline(PurpleMediaManager *manager) { #ifdef USE_VV g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), NULL); if (manager->priv->pipeline == NULL) { FsElementAddedNotifier *notifier; gchar *filename; GError *err = NULL; GKeyFile *keyfile; GstBus *bus; manager->priv->pipeline = gst_pipeline_new(NULL); bus = gst_pipeline_get_bus( GST_PIPELINE(manager->priv->pipeline)); gst_bus_add_signal_watch(GST_BUS(bus)); g_signal_connect(G_OBJECT(bus), "message", G_CALLBACK(pipeline_bus_call), manager); gst_bus_set_sync_handler(bus, gst_bus_sync_signal_handler, NULL); gst_object_unref(bus); filename = g_build_filename(purple_user_dir(), "fs-element.conf", NULL); keyfile = g_key_file_new(); if (!g_key_file_load_from_file(keyfile, filename, G_KEY_FILE_NONE, &err)) { if (err->code == 4) purple_debug_info("mediamanager", "Couldn't read " "fs-element.conf: %s\n", err->message); else purple_debug_error("mediamanager", "Error reading " "fs-element.conf: %s\n", err->message); g_error_free(err); } g_free(filename); /* Hack to make alsasrc stop messing up audio timestamps */ if (!g_key_file_has_key(keyfile, "alsasrc", "slave-method", NULL)) { g_key_file_set_integer(keyfile, "alsasrc", "slave-method", 2); } notifier = fs_element_added_notifier_new(); fs_element_added_notifier_add(notifier, GST_BIN(manager->priv->pipeline)); fs_element_added_notifier_set_properties_from_keyfile( notifier, keyfile); gst_element_set_state(manager->priv->pipeline, GST_STATE_PLAYING); } return manager->priv->pipeline; #else return NULL; #endif } #endif /* USE_GSTREAMER */ PurpleMedia * purple_media_manager_create_media(PurpleMediaManager *manager, PurpleAccount *account, const char *conference_type, const char *remote_user, gboolean initiator) { #ifdef USE_VV PurpleMedia *media; gboolean signal_ret; media = PURPLE_MEDIA(g_object_new(purple_media_get_type(), "manager", manager, "account", account, "conference-type", conference_type, "initiator", initiator, NULL)); g_signal_emit(manager, purple_media_manager_signals[INIT_MEDIA], 0, media, account, remote_user, &signal_ret); if (signal_ret == FALSE) { g_object_unref(media); return NULL; } manager->priv->medias = g_list_append(manager->priv->medias, media); return media; #else return NULL; #endif } GList * purple_media_manager_get_media(PurpleMediaManager *manager) { #ifdef USE_VV return manager->priv->medias; #else return NULL; #endif } GList * purple_media_manager_get_media_by_account(PurpleMediaManager *manager, PurpleAccount *account) { #ifdef USE_VV GList *media = NULL; GList *iter; g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), NULL); iter = manager->priv->medias; for (; iter; iter = g_list_next(iter)) { if (purple_media_get_account(iter->data) == account) { media = g_list_prepend(media, iter->data); } } return media; #else return NULL; #endif } void purple_media_manager_remove_media(PurpleMediaManager *manager, PurpleMedia *media) { #ifdef USE_VV GList *list = g_list_find(manager->priv->medias, media); if (list) manager->priv->medias = g_list_delete_link(manager->priv->medias, list); #endif } #ifdef USE_VV static void request_pad_unlinked_cb(GstPad *pad, GstPad *peer, gpointer user_data) { GstElement *parent = GST_ELEMENT_PARENT(pad); GstIterator *iter; GstPad *remaining_pad; GstIteratorResult result; gst_element_release_request_pad(GST_ELEMENT_PARENT(pad), pad); iter = gst_element_iterate_src_pads(parent); result = gst_iterator_next(iter, (gpointer)&remaining_pad); if (result == GST_ITERATOR_DONE) { gst_element_set_locked_state(parent, TRUE); gst_element_set_state(parent, GST_STATE_NULL); gst_bin_remove(GST_BIN(GST_ELEMENT_PARENT(parent)), parent); } else if (result == GST_ITERATOR_OK) { gst_object_unref(remaining_pad); } gst_iterator_free(iter); } #endif #ifdef USE_GSTREAMER GstElement * purple_media_manager_get_element(PurpleMediaManager *manager, PurpleMediaSessionType type, PurpleMedia *media, const gchar *session_id, const gchar *participant) { #ifdef USE_VV GstElement *ret = NULL; PurpleMediaElementInfo *info = NULL; PurpleMediaElementType element_type; if (type & PURPLE_MEDIA_SEND_AUDIO) info = manager->priv->audio_src; else if (type & PURPLE_MEDIA_RECV_AUDIO) info = manager->priv->audio_sink; else if (type & PURPLE_MEDIA_SEND_VIDEO) info = manager->priv->video_src; else if (type & PURPLE_MEDIA_RECV_VIDEO) info = manager->priv->video_sink; if (info == NULL) return NULL; element_type = purple_media_element_info_get_element_type(info); if (element_type & PURPLE_MEDIA_ELEMENT_UNIQUE && element_type & PURPLE_MEDIA_ELEMENT_SRC) { GstElement *tee; GstPad *pad; GstPad *ghost; gchar *id = purple_media_element_info_get_id(info); ret = gst_bin_get_by_name(GST_BIN( purple_media_manager_get_pipeline( manager)), id); if (ret == NULL) { GstElement *bin, *fakesink; ret = purple_media_element_info_call_create(info, media, session_id, participant); bin = gst_bin_new(id); tee = gst_element_factory_make("tee", "tee"); gst_bin_add_many(GST_BIN(bin), ret, tee, NULL); gst_element_link(ret, tee); /* * This shouldn't be necessary, but it stops it from * giving a not-linked error upon destruction */ fakesink = gst_element_factory_make("fakesink", NULL); g_object_set(fakesink, "sync", FALSE, NULL); gst_bin_add(GST_BIN(bin), fakesink); gst_element_link(tee, fakesink); ret = bin; gst_object_ref(ret); gst_bin_add(GST_BIN(purple_media_manager_get_pipeline( manager)), ret); } g_free(id); tee = gst_bin_get_by_name(GST_BIN(ret), "tee"); pad = gst_element_get_request_pad(tee, "src%d"); gst_object_unref(tee); ghost = gst_ghost_pad_new(NULL, pad); gst_object_unref(pad); g_signal_connect(GST_PAD(ghost), "unlinked", G_CALLBACK(request_pad_unlinked_cb), NULL); gst_pad_set_active(ghost, TRUE); gst_element_add_pad(ret, ghost); } else { ret = purple_media_element_info_call_create(info, media, session_id, participant); } if (ret == NULL) purple_debug_error("media", "Error creating source or sink\n"); return ret; #else return NULL; #endif } PurpleMediaElementInfo * purple_media_manager_get_element_info(PurpleMediaManager *manager, const gchar *id) { #ifdef USE_VV GList *iter; g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), NULL); iter = manager->priv->elements; for (; iter; iter = g_list_next(iter)) { gchar *element_id = purple_media_element_info_get_id(iter->data); if (!strcmp(element_id, id)) { g_free(element_id); g_object_ref(iter->data); return iter->data; } g_free(element_id); } #endif return NULL; } gboolean purple_media_manager_register_element(PurpleMediaManager *manager, PurpleMediaElementInfo *info) { #ifdef USE_VV PurpleMediaElementInfo *info2; gchar *id; g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), FALSE); g_return_val_if_fail(info != NULL, FALSE); id = purple_media_element_info_get_id(info); info2 = purple_media_manager_get_element_info(manager, id); g_free(id); if (info2 != NULL) { g_object_unref(info2); return FALSE; } manager->priv->elements = g_list_prepend(manager->priv->elements, info); return TRUE; #else return FALSE; #endif } gboolean purple_media_manager_unregister_element(PurpleMediaManager *manager, const gchar *id) { #ifdef USE_VV PurpleMediaElementInfo *info; g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), FALSE); info = purple_media_manager_get_element_info(manager, id); if (info == NULL) { g_object_unref(info); return FALSE; } if (manager->priv->audio_src == info) manager->priv->audio_src = NULL; if (manager->priv->audio_sink == info) manager->priv->audio_sink = NULL; if (manager->priv->video_src == info) manager->priv->video_src = NULL; if (manager->priv->video_sink == info) manager->priv->video_sink = NULL; manager->priv->elements = g_list_remove( manager->priv->elements, info); g_object_unref(info); return TRUE; #else return FALSE; #endif } gboolean purple_media_manager_set_active_element(PurpleMediaManager *manager, PurpleMediaElementInfo *info) { #ifdef USE_VV PurpleMediaElementInfo *info2; PurpleMediaElementType type; gboolean ret = FALSE; gchar *id; g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), FALSE); g_return_val_if_fail(info != NULL, FALSE); id = purple_media_element_info_get_id(info); info2 = purple_media_manager_get_element_info(manager, id); g_free(id); if (info2 == NULL) purple_media_manager_register_element(manager, info); else g_object_unref(info2); type = purple_media_element_info_get_element_type(info); if (type & PURPLE_MEDIA_ELEMENT_SRC) { if (type & PURPLE_MEDIA_ELEMENT_AUDIO) { manager->priv->audio_src = info; ret = TRUE; } if (type & PURPLE_MEDIA_ELEMENT_VIDEO) { manager->priv->video_src = info; ret = TRUE; } } if (type & PURPLE_MEDIA_ELEMENT_SINK) { if (type & PURPLE_MEDIA_ELEMENT_AUDIO) { manager->priv->audio_sink = info; ret = TRUE; } if (type & PURPLE_MEDIA_ELEMENT_VIDEO) { manager->priv->video_sink = info; ret = TRUE; } } return ret; #else return FALSE; #endif } PurpleMediaElementInfo * purple_media_manager_get_active_element(PurpleMediaManager *manager, PurpleMediaElementType type) { #ifdef USE_VV g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), NULL); if (type & PURPLE_MEDIA_ELEMENT_SRC) { if (type & PURPLE_MEDIA_ELEMENT_AUDIO) return manager->priv->audio_src; else if (type & PURPLE_MEDIA_ELEMENT_VIDEO) return manager->priv->video_src; } else if (type & PURPLE_MEDIA_ELEMENT_SINK) { if (type & PURPLE_MEDIA_ELEMENT_AUDIO) return manager->priv->audio_sink; else if (type & PURPLE_MEDIA_ELEMENT_VIDEO) return manager->priv->video_sink; } #endif return NULL; } #endif /* USE_GSTREAMER */ #ifdef USE_VV static void window_id_cb(GstBus *bus, GstMessage *msg, PurpleMediaOutputWindow *ow) { GstElement *sink; if (GST_MESSAGE_TYPE(msg) != GST_MESSAGE_ELEMENT || !gst_structure_has_name(msg->structure, "prepare-xwindow-id")) return; sink = GST_ELEMENT(GST_MESSAGE_SRC(msg)); while (sink != ow->sink) { if (sink == NULL) return; sink = GST_ELEMENT_PARENT(sink); } g_signal_handlers_disconnect_matched(bus, G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0, 0, NULL, window_id_cb, ow); gst_x_overlay_set_xwindow_id(GST_X_OVERLAY( GST_MESSAGE_SRC(msg)), ow->window_id); } #endif gboolean purple_media_manager_create_output_window(PurpleMediaManager *manager, PurpleMedia *media, const gchar *session_id, const gchar *participant) { #ifdef USE_VV GList *iter; g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE); iter = manager->priv->output_windows; for(; iter; iter = g_list_next(iter)) { PurpleMediaOutputWindow *ow = iter->data; if (ow->sink == NULL && ow->media == media && ((participant != NULL && ow->participant != NULL && !strcmp(participant, ow->participant)) || (participant == ow->participant)) && !strcmp(session_id, ow->session_id)) { GstBus *bus; GstElement *queue, *colorspace; GstElement *tee = purple_media_get_tee(media, session_id, participant); if (tee == NULL) continue; queue = gst_element_factory_make( "queue", NULL); colorspace = gst_element_factory_make( "ffmpegcolorspace", NULL); ow->sink = purple_media_manager_get_element( manager, PURPLE_MEDIA_RECV_VIDEO, ow->media, ow->session_id, ow->participant); if (participant == NULL) { /* aka this is a preview sink */ GObjectClass *klass = G_OBJECT_GET_CLASS(ow->sink); if (g_object_class_find_property(klass, "sync")) g_object_set(G_OBJECT(ow->sink), "sync", "FALSE", NULL); if (g_object_class_find_property(klass, "async")) g_object_set(G_OBJECT(ow->sink), "async", FALSE, NULL); } gst_bin_add_many(GST_BIN(GST_ELEMENT_PARENT(tee)), queue, colorspace, ow->sink, NULL); bus = gst_pipeline_get_bus(GST_PIPELINE( manager->priv->pipeline)); g_signal_connect(bus, "sync-message::element", G_CALLBACK(window_id_cb), ow); gst_object_unref(bus); gst_element_set_state(ow->sink, GST_STATE_PLAYING); gst_element_set_state(colorspace, GST_STATE_PLAYING); gst_element_set_state(queue, GST_STATE_PLAYING); gst_element_link(colorspace, ow->sink); gst_element_link(queue, colorspace); gst_element_link(tee, queue); } } return TRUE; #else return FALSE; #endif } gulong purple_media_manager_set_output_window(PurpleMediaManager *manager, PurpleMedia *media, const gchar *session_id, const gchar *participant, gulong window_id) { #ifdef USE_VV PurpleMediaOutputWindow *output_window; g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), FALSE); g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE); output_window = g_new0(PurpleMediaOutputWindow, 1); output_window->id = manager->priv->next_output_window_id++; output_window->media = media; output_window->session_id = g_strdup(session_id); output_window->participant = g_strdup(participant); output_window->window_id = window_id; manager->priv->output_windows = g_list_prepend( manager->priv->output_windows, output_window); if (purple_media_get_tee(media, session_id, participant) != NULL) purple_media_manager_create_output_window(manager, media, session_id, participant); return output_window->id; #else return 0; #endif } gboolean purple_media_manager_remove_output_window(PurpleMediaManager *manager, gulong output_window_id) { #ifdef USE_VV PurpleMediaOutputWindow *output_window = NULL; GList *iter; g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), FALSE); iter = manager->priv->output_windows; for (; iter; iter = g_list_next(iter)) { PurpleMediaOutputWindow *ow = iter->data; if (ow->id == output_window_id) { manager->priv->output_windows = g_list_delete_link( manager->priv->output_windows, iter); output_window = ow; break; } } if (output_window == NULL) return FALSE; if (output_window->sink != NULL) { GstPad *pad = gst_element_get_static_pad( output_window->sink, "sink"); GstPad *peer = gst_pad_get_peer(pad); GstElement *colorspace = GST_ELEMENT_PARENT(peer), *queue; gst_object_unref(pad); gst_object_unref(peer); pad = gst_element_get_static_pad(colorspace, "sink"); peer = gst_pad_get_peer(pad); queue = GST_ELEMENT_PARENT(peer); gst_object_unref(pad); gst_object_unref(peer); pad = gst_element_get_static_pad(queue, "sink"); peer = gst_pad_get_peer(pad); gst_object_unref(pad); if (peer != NULL) gst_element_release_request_pad(GST_ELEMENT_PARENT(peer), peer); gst_element_set_locked_state(queue, TRUE); gst_element_set_state(queue, GST_STATE_NULL); gst_bin_remove(GST_BIN(GST_ELEMENT_PARENT(queue)), queue); gst_element_set_locked_state(colorspace, TRUE); gst_element_set_state(colorspace, GST_STATE_NULL); gst_bin_remove(GST_BIN(GST_ELEMENT_PARENT(colorspace)), colorspace); gst_element_set_locked_state(output_window->sink, TRUE); gst_element_set_state(output_window->sink, GST_STATE_NULL); gst_bin_remove(GST_BIN(GST_ELEMENT_PARENT(output_window->sink)), output_window->sink); } g_free(output_window->session_id); g_free(output_window->participant); g_free(output_window); return TRUE; #else return FALSE; #endif } void purple_media_manager_remove_output_windows(PurpleMediaManager *manager, PurpleMedia *media, const gchar *session_id, const gchar *participant) { #ifdef USE_VV GList *iter; g_return_if_fail(PURPLE_IS_MEDIA(media)); iter = manager->priv->output_windows; for (; iter;) { PurpleMediaOutputWindow *ow = iter->data; iter = g_list_next(iter); if (media == ow->media && ((session_id != NULL && ow->session_id != NULL && !strcmp(session_id, ow->session_id)) || (session_id == ow->session_id)) && ((participant != NULL && ow->participant != NULL && !strcmp(participant, ow->participant)) || (participant == ow->participant))) purple_media_manager_remove_output_window( manager, ow->id); } #endif } void purple_media_manager_set_ui_caps(PurpleMediaManager *manager, PurpleMediaCaps caps) { #ifdef USE_VV PurpleMediaCaps oldcaps; g_return_if_fail(PURPLE_IS_MEDIA_MANAGER(manager)); oldcaps = manager->priv->ui_caps; manager->priv->ui_caps = caps; if (caps != oldcaps) g_signal_emit(manager, purple_media_manager_signals[UI_CAPS_CHANGED], 0, caps, oldcaps); #endif } PurpleMediaCaps purple_media_manager_get_ui_caps(PurpleMediaManager *manager) { #ifdef USE_VV g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), PURPLE_MEDIA_CAPS_NONE); return manager->priv->ui_caps; #else return PURPLE_MEDIA_CAPS_NONE; #endif } void purple_media_manager_set_backend_type(PurpleMediaManager *manager, GType backend_type) { #ifdef USE_VV g_return_if_fail(PURPLE_IS_MEDIA_MANAGER(manager)); manager->priv->backend_type = backend_type; #endif } GType purple_media_manager_get_backend_type(PurpleMediaManager *manager) { #ifdef USE_VV g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), PURPLE_MEDIA_CAPS_NONE); return manager->priv->backend_type; #else return G_TYPE_NONE; #endif } #ifdef USE_GSTREAMER /* * PurpleMediaElementType */ GType purple_media_element_type_get_type() { static GType type = 0; if (type == 0) { static const GFlagsValue values[] = { { PURPLE_MEDIA_ELEMENT_NONE, "PURPLE_MEDIA_ELEMENT_NONE", "none" }, { PURPLE_MEDIA_ELEMENT_AUDIO, "PURPLE_MEDIA_ELEMENT_AUDIO", "audio" }, { PURPLE_MEDIA_ELEMENT_VIDEO, "PURPLE_MEDIA_ELEMENT_VIDEO", "video" }, { PURPLE_MEDIA_ELEMENT_AUDIO_VIDEO, "PURPLE_MEDIA_ELEMENT_AUDIO_VIDEO", "audio-video" }, { PURPLE_MEDIA_ELEMENT_NO_SRCS, "PURPLE_MEDIA_ELEMENT_NO_SRCS", "no-srcs" }, { PURPLE_MEDIA_ELEMENT_ONE_SRC, "PURPLE_MEDIA_ELEMENT_ONE_SRC", "one-src" }, { PURPLE_MEDIA_ELEMENT_MULTI_SRC, "PURPLE_MEDIA_ELEMENT_MULTI_SRC", "multi-src" }, { PURPLE_MEDIA_ELEMENT_REQUEST_SRC, "PURPLE_MEDIA_ELEMENT_REQUEST_SRC", "request-src" }, { PURPLE_MEDIA_ELEMENT_NO_SINKS, "PURPLE_MEDIA_ELEMENT_NO_SINKS", "no-sinks" }, { PURPLE_MEDIA_ELEMENT_ONE_SINK, "PURPLE_MEDIA_ELEMENT_ONE_SINK", "one-sink" }, { PURPLE_MEDIA_ELEMENT_MULTI_SINK, "PURPLE_MEDIA_ELEMENT_MULTI_SINK", "multi-sink" }, { PURPLE_MEDIA_ELEMENT_REQUEST_SINK, "PURPLE_MEDIA_ELEMENT_REQUEST_SINK", "request-sink" }, { PURPLE_MEDIA_ELEMENT_UNIQUE, "PURPLE_MEDIA_ELEMENT_UNIQUE", "unique" }, { PURPLE_MEDIA_ELEMENT_SRC, "PURPLE_MEDIA_ELEMENT_SRC", "src" }, { PURPLE_MEDIA_ELEMENT_SINK, "PURPLE_MEDIA_ELEMENT_SINK", "sink" }, { 0, NULL, NULL } }; type = g_flags_register_static( "PurpleMediaElementType", values); } return type; } /* * PurpleMediaElementInfo */ struct _PurpleMediaElementInfoClass { GObjectClass parent_class; }; struct _PurpleMediaElementInfo { GObject parent; }; #ifdef USE_VV struct _PurpleMediaElementInfoPrivate { gchar *id; gchar *name; PurpleMediaElementType type; PurpleMediaElementCreateCallback create; }; enum { PROP_0, PROP_ID, PROP_NAME, PROP_TYPE, PROP_CREATE_CB, }; static void purple_media_element_info_init(PurpleMediaElementInfo *info) { PurpleMediaElementInfoPrivate *priv = PURPLE_MEDIA_ELEMENT_INFO_GET_PRIVATE(info); priv->id = NULL; priv->name = NULL; priv->type = PURPLE_MEDIA_ELEMENT_NONE; priv->create = NULL; } static void purple_media_element_info_finalize(GObject *info) { PurpleMediaElementInfoPrivate *priv = PURPLE_MEDIA_ELEMENT_INFO_GET_PRIVATE(info); g_free(priv->id); g_free(priv->name); } static void purple_media_element_info_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { PurpleMediaElementInfoPrivate *priv; g_return_if_fail(PURPLE_IS_MEDIA_ELEMENT_INFO(object)); priv = PURPLE_MEDIA_ELEMENT_INFO_GET_PRIVATE(object); switch (prop_id) { case PROP_ID: g_free(priv->id); priv->id = g_value_dup_string(value); break; case PROP_NAME: g_free(priv->name); priv->name = g_value_dup_string(value); break; case PROP_TYPE: { priv->type = g_value_get_flags(value); break; } case PROP_CREATE_CB: priv->create = g_value_get_pointer(value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec); break; } } static void purple_media_element_info_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { PurpleMediaElementInfoPrivate *priv; g_return_if_fail(PURPLE_IS_MEDIA_ELEMENT_INFO(object)); priv = PURPLE_MEDIA_ELEMENT_INFO_GET_PRIVATE(object); switch (prop_id) { case PROP_ID: g_value_set_string(value, priv->id); break; case PROP_NAME: g_value_set_string(value, priv->name); break; case PROP_TYPE: g_value_set_flags(value, priv->type); break; case PROP_CREATE_CB: g_value_set_pointer(value, priv->create); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec); break; } } static void purple_media_element_info_class_init(PurpleMediaElementInfoClass *klass) { GObjectClass *gobject_class = (GObjectClass*)klass; gobject_class->finalize = purple_media_element_info_finalize; gobject_class->set_property = purple_media_element_info_set_property; gobject_class->get_property = purple_media_element_info_get_property; g_object_class_install_property(gobject_class, PROP_ID, g_param_spec_string("id", "ID", "The unique identifier of the element.", NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); g_object_class_install_property(gobject_class, PROP_NAME, g_param_spec_string("name", "Name", "The friendly/display name of this element.", NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); g_object_class_install_property(gobject_class, PROP_TYPE, g_param_spec_flags("type", "Element Type", "The type of element this is.", PURPLE_TYPE_MEDIA_ELEMENT_TYPE, PURPLE_MEDIA_ELEMENT_NONE, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); g_object_class_install_property(gobject_class, PROP_CREATE_CB, g_param_spec_pointer("create-cb", "Create Callback", "The function called to create this element.", G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); g_type_class_add_private(klass, sizeof(PurpleMediaElementInfoPrivate)); } G_DEFINE_TYPE(PurpleMediaElementInfo, purple_media_element_info, G_TYPE_OBJECT); #else GType purple_media_element_info_get_type() { return G_TYPE_NONE; } #endif gchar * purple_media_element_info_get_id(PurpleMediaElementInfo *info) { #ifdef USE_VV gchar *id; g_return_val_if_fail(PURPLE_IS_MEDIA_ELEMENT_INFO(info), NULL); g_object_get(info, "id", &id, NULL); return id; #else return NULL; #endif } gchar * purple_media_element_info_get_name(PurpleMediaElementInfo *info) { #ifdef USE_VV gchar *name; g_return_val_if_fail(PURPLE_IS_MEDIA_ELEMENT_INFO(info), NULL); g_object_get(info, "name", &name, NULL); return name; #else return NULL; #endif } PurpleMediaElementType purple_media_element_info_get_element_type(PurpleMediaElementInfo *info) { #ifdef USE_VV PurpleMediaElementType type; g_return_val_if_fail(PURPLE_IS_MEDIA_ELEMENT_INFO(info), PURPLE_MEDIA_ELEMENT_NONE); g_object_get(info, "type", &type, NULL); return type; #else return PURPLE_MEDIA_ELEMENT_NONE; #endif } GstElement * purple_media_element_info_call_create(PurpleMediaElementInfo *info, PurpleMedia *media, const gchar *session_id, const gchar *participant) { #ifdef USE_VV PurpleMediaElementCreateCallback create; g_return_val_if_fail(PURPLE_IS_MEDIA_ELEMENT_INFO(info), NULL); g_object_get(info, "create-cb", &create, NULL); if (create) return create(media, session_id, participant); #endif return NULL; } #endif /* USE_GSTREAMER */