Mercurial > pidgin
comparison libpurple/mediamanager.c @ 26346:7b63af454f26
propagate from branch 'im.pidgin.pidgin' (head 5592cb6a8b667422747bafd555fea0aed19931b6)
to branch 'im.pidgin.pidgin.vv' (head ff94dfb7c44b84f5d9b4590cc429d93198703b83)
author | Mike Ruprecht <maiku@soc.pidgin.im> |
---|---|
date | Sun, 22 Mar 2009 23:33:42 +0000 |
parents | 5ee7e8f209bb |
children | 1ae3af12095a |
comparison
equal
deleted
inserted
replaced
26196:399776a9ad98 | 26346:7b63af454f26 |
---|---|
1 /** | |
2 * @file mediamanager.c Media Manager API | |
3 * @ingroup core | |
4 */ | |
5 | |
6 /* purple | |
7 * | |
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. | |
11 * | |
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. | |
16 * | |
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. | |
21 * | |
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
25 */ | |
26 | |
27 #include "internal.h" | |
28 | |
29 #include "connection.h" | |
30 #include "debug.h" | |
31 #include "marshallers.h" | |
32 #include "mediamanager.h" | |
33 #include "media.h" | |
34 | |
35 #ifdef USE_VV | |
36 | |
37 #include <gst/farsight/fs-conference-iface.h> | |
38 #include <gst/interfaces/xoverlay.h> | |
39 | |
40 typedef struct _PurpleMediaOutputWindow PurpleMediaOutputWindow; | |
41 | |
42 struct _PurpleMediaOutputWindow | |
43 { | |
44 gulong id; | |
45 PurpleMedia *media; | |
46 gchar *session_id; | |
47 gchar *participant; | |
48 gulong window_id; | |
49 GstElement *sink; | |
50 }; | |
51 | |
52 struct _PurpleMediaManagerPrivate | |
53 { | |
54 GstElement *pipeline; | |
55 GList *medias; | |
56 GList *elements; | |
57 GList *output_windows; | |
58 gulong next_output_window_id; | |
59 | |
60 PurpleMediaElementInfo *video_src; | |
61 PurpleMediaElementInfo *video_sink; | |
62 PurpleMediaElementInfo *audio_src; | |
63 PurpleMediaElementInfo *audio_sink; | |
64 }; | |
65 | |
66 #define PURPLE_MEDIA_MANAGER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_MEDIA_MANAGER, PurpleMediaManagerPrivate)) | |
67 | |
68 static void purple_media_manager_class_init (PurpleMediaManagerClass *klass); | |
69 static void purple_media_manager_init (PurpleMediaManager *media); | |
70 static void purple_media_manager_finalize (GObject *object); | |
71 | |
72 static GObjectClass *parent_class = NULL; | |
73 | |
74 | |
75 | |
76 enum { | |
77 INIT_MEDIA, | |
78 LAST_SIGNAL | |
79 }; | |
80 static guint purple_media_manager_signals[LAST_SIGNAL] = {0}; | |
81 | |
82 enum { | |
83 PROP_0, | |
84 PROP_FARSIGHT_SESSION, | |
85 PROP_NAME, | |
86 PROP_CONNECTION, | |
87 PROP_MIC_ELEMENT, | |
88 PROP_SPEAKER_ELEMENT, | |
89 }; | |
90 | |
91 GType | |
92 purple_media_manager_get_type() | |
93 { | |
94 static GType type = 0; | |
95 | |
96 if (type == 0) { | |
97 static const GTypeInfo info = { | |
98 sizeof(PurpleMediaManagerClass), | |
99 NULL, | |
100 NULL, | |
101 (GClassInitFunc) purple_media_manager_class_init, | |
102 NULL, | |
103 NULL, | |
104 sizeof(PurpleMediaManager), | |
105 0, | |
106 (GInstanceInitFunc) purple_media_manager_init, | |
107 NULL | |
108 }; | |
109 type = g_type_register_static(G_TYPE_OBJECT, "PurpleMediaManager", &info, 0); | |
110 } | |
111 return type; | |
112 } | |
113 | |
114 | |
115 static void | |
116 purple_media_manager_class_init (PurpleMediaManagerClass *klass) | |
117 { | |
118 GObjectClass *gobject_class = (GObjectClass*)klass; | |
119 parent_class = g_type_class_peek_parent(klass); | |
120 | |
121 gobject_class->finalize = purple_media_manager_finalize; | |
122 | |
123 purple_media_manager_signals[INIT_MEDIA] = g_signal_new ("init-media", | |
124 G_TYPE_FROM_CLASS (klass), | |
125 G_SIGNAL_RUN_LAST, | |
126 0, NULL, NULL, | |
127 purple_smarshal_BOOLEAN__OBJECT_POINTER_STRING, | |
128 G_TYPE_BOOLEAN, 3, PURPLE_TYPE_MEDIA, | |
129 G_TYPE_POINTER, G_TYPE_STRING); | |
130 g_type_class_add_private(klass, sizeof(PurpleMediaManagerPrivate)); | |
131 } | |
132 | |
133 static void | |
134 purple_media_manager_init (PurpleMediaManager *media) | |
135 { | |
136 media->priv = PURPLE_MEDIA_MANAGER_GET_PRIVATE(media); | |
137 media->priv->medias = NULL; | |
138 media->priv->next_output_window_id = 1; | |
139 } | |
140 | |
141 static void | |
142 purple_media_manager_finalize (GObject *media) | |
143 { | |
144 PurpleMediaManagerPrivate *priv = PURPLE_MEDIA_MANAGER_GET_PRIVATE(media); | |
145 for (; priv->medias; priv->medias = | |
146 g_list_delete_link(priv->medias, priv->medias)) { | |
147 g_object_unref(priv->medias->data); | |
148 } | |
149 for (; priv->elements; priv->elements = | |
150 g_list_delete_link(priv->elements, priv->elements)); | |
151 parent_class->finalize(media); | |
152 } | |
153 | |
154 PurpleMediaManager * | |
155 purple_media_manager_get() | |
156 { | |
157 static PurpleMediaManager *manager = NULL; | |
158 | |
159 if (manager == NULL) | |
160 manager = PURPLE_MEDIA_MANAGER(g_object_new(purple_media_manager_get_type(), NULL)); | |
161 return manager; | |
162 } | |
163 | |
164 static gboolean | |
165 pipeline_bus_call(GstBus *bus, GstMessage *msg, PurpleMediaManager *manager) | |
166 { | |
167 switch(GST_MESSAGE_TYPE(msg)) { | |
168 case GST_MESSAGE_EOS: | |
169 purple_debug_info("mediamanager", "End of Stream\n"); | |
170 break; | |
171 case GST_MESSAGE_ERROR: { | |
172 gchar *debug = NULL; | |
173 GError *err = NULL; | |
174 | |
175 gst_message_parse_error(msg, &err, &debug); | |
176 | |
177 purple_debug_error("mediamanager", | |
178 "gst pipeline error: %s\n", | |
179 err->message); | |
180 g_error_free(err); | |
181 | |
182 if (debug) { | |
183 purple_debug_error("mediamanager", | |
184 "Debug details: %s\n", debug); | |
185 g_free (debug); | |
186 } | |
187 break; | |
188 } | |
189 default: | |
190 break; | |
191 } | |
192 return TRUE; | |
193 } | |
194 | |
195 GstElement * | |
196 purple_media_manager_get_pipeline(PurpleMediaManager *manager) | |
197 { | |
198 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), NULL); | |
199 | |
200 if (manager->priv->pipeline == NULL) { | |
201 GstBus *bus; | |
202 manager->priv->pipeline = gst_pipeline_new(NULL); | |
203 | |
204 bus = gst_pipeline_get_bus( | |
205 GST_PIPELINE(manager->priv->pipeline)); | |
206 gst_bus_add_signal_watch(GST_BUS(bus)); | |
207 g_signal_connect(G_OBJECT(bus), "message", | |
208 G_CALLBACK(pipeline_bus_call), manager); | |
209 gst_bus_set_sync_handler(bus, | |
210 gst_bus_sync_signal_handler, NULL); | |
211 gst_object_unref(bus); | |
212 | |
213 gst_element_set_state(manager->priv->pipeline, | |
214 GST_STATE_PLAYING); | |
215 } | |
216 | |
217 return manager->priv->pipeline; | |
218 } | |
219 | |
220 PurpleMedia * | |
221 purple_media_manager_create_media(PurpleMediaManager *manager, | |
222 PurpleConnection *gc, | |
223 const char *conference_type, | |
224 const char *remote_user, | |
225 gboolean initiator) | |
226 { | |
227 PurpleMedia *media; | |
228 FsConference *conference = FS_CONFERENCE(gst_element_factory_make(conference_type, NULL)); | |
229 GstStateChangeReturn ret; | |
230 gboolean signal_ret; | |
231 | |
232 if (conference == NULL) { | |
233 purple_conv_present_error(remote_user, | |
234 purple_connection_get_account(gc), | |
235 _("Error creating conference.")); | |
236 purple_debug_error("media", "Conference == NULL\n"); | |
237 return NULL; | |
238 } | |
239 | |
240 media = PURPLE_MEDIA(g_object_new(purple_media_get_type(), | |
241 "manager", manager, | |
242 "connection", gc, | |
243 "conference", conference, | |
244 "initiator", initiator, | |
245 NULL)); | |
246 | |
247 ret = gst_element_set_state(GST_ELEMENT(conference), GST_STATE_PLAYING); | |
248 | |
249 if (ret == GST_STATE_CHANGE_FAILURE) { | |
250 purple_conv_present_error(remote_user, | |
251 purple_connection_get_account(gc), | |
252 _("Error creating conference.")); | |
253 purple_debug_error("media", "Failed to start conference.\n"); | |
254 g_object_unref(media); | |
255 return NULL; | |
256 } | |
257 | |
258 g_signal_emit(manager, purple_media_manager_signals[INIT_MEDIA], 0, | |
259 media, gc, remote_user, &signal_ret); | |
260 | |
261 if (signal_ret == FALSE) { | |
262 g_object_unref(media); | |
263 return NULL; | |
264 } | |
265 | |
266 manager->priv->medias = g_list_append(manager->priv->medias, media); | |
267 return media; | |
268 } | |
269 | |
270 GList * | |
271 purple_media_manager_get_media(PurpleMediaManager *manager) | |
272 { | |
273 return manager->priv->medias; | |
274 } | |
275 | |
276 GList * | |
277 purple_media_manager_get_media_by_connection(PurpleMediaManager *manager, | |
278 PurpleConnection *pc) | |
279 { | |
280 GList *media = NULL; | |
281 GList *iter; | |
282 | |
283 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), NULL); | |
284 | |
285 iter = manager->priv->medias; | |
286 for (; iter; iter = g_list_next(iter)) { | |
287 if (purple_media_get_connection(iter->data) == pc) { | |
288 media = g_list_prepend(media, iter->data); | |
289 } | |
290 } | |
291 | |
292 return media; | |
293 } | |
294 | |
295 void | |
296 purple_media_manager_remove_media(PurpleMediaManager *manager, | |
297 PurpleMedia *media) | |
298 { | |
299 GList *list = g_list_find(manager->priv->medias, media); | |
300 if (list) | |
301 manager->priv->medias = | |
302 g_list_delete_link(manager->priv->medias, list); | |
303 } | |
304 | |
305 GstElement * | |
306 purple_media_manager_get_element(PurpleMediaManager *manager, | |
307 PurpleMediaSessionType type) | |
308 { | |
309 GstElement *ret = NULL; | |
310 | |
311 /* TODO: If src, retrieve current src */ | |
312 /* TODO: Send a signal here to allow for overriding the source/sink */ | |
313 | |
314 if (type & PURPLE_MEDIA_SEND_AUDIO | |
315 && manager->priv->audio_src != NULL) | |
316 ret = manager->priv->audio_src->create(); | |
317 else if (type & PURPLE_MEDIA_RECV_AUDIO | |
318 && manager->priv->audio_sink != NULL) | |
319 ret = manager->priv->audio_sink->create(); | |
320 else if (type & PURPLE_MEDIA_SEND_VIDEO | |
321 && manager->priv->video_src != NULL) | |
322 ret = manager->priv->video_src->create(); | |
323 else if (type & PURPLE_MEDIA_RECV_VIDEO | |
324 && manager->priv->video_sink != NULL) | |
325 ret = manager->priv->video_sink->create(); | |
326 | |
327 if (ret == NULL) | |
328 purple_debug_error("media", "Error creating source or sink\n"); | |
329 | |
330 return ret; | |
331 } | |
332 | |
333 PurpleMediaElementInfo * | |
334 purple_media_manager_get_element_info(PurpleMediaManager *manager, | |
335 const gchar *id) | |
336 { | |
337 GList *iter; | |
338 | |
339 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), NULL); | |
340 | |
341 iter = manager->priv->elements; | |
342 | |
343 for (; iter; iter = g_list_next(iter)) { | |
344 PurpleMediaElementInfo *info = iter->data; | |
345 if (!strcmp(info->id, id)) | |
346 return info; | |
347 } | |
348 | |
349 return NULL; | |
350 } | |
351 | |
352 gboolean | |
353 purple_media_manager_register_element(PurpleMediaManager *manager, | |
354 PurpleMediaElementInfo *info) | |
355 { | |
356 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), FALSE); | |
357 g_return_val_if_fail(info != NULL, FALSE); | |
358 | |
359 if (purple_media_manager_get_element_info(manager, info->id) != NULL) | |
360 return FALSE; | |
361 | |
362 manager->priv->elements = | |
363 g_list_prepend(manager->priv->elements, info); | |
364 return TRUE; | |
365 } | |
366 | |
367 gboolean | |
368 purple_media_manager_unregister_element(PurpleMediaManager *manager, | |
369 const gchar *id) | |
370 { | |
371 PurpleMediaElementInfo *info; | |
372 | |
373 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), FALSE); | |
374 | |
375 info = purple_media_manager_get_element_info(manager, id); | |
376 | |
377 if (info == NULL) | |
378 return FALSE; | |
379 | |
380 if (manager->priv->audio_src == info) | |
381 manager->priv->audio_src = NULL; | |
382 if (manager->priv->audio_sink == info) | |
383 manager->priv->audio_sink = NULL; | |
384 if (manager->priv->video_src == info) | |
385 manager->priv->video_src = NULL; | |
386 if (manager->priv->video_sink == info) | |
387 manager->priv->video_sink = NULL; | |
388 | |
389 manager->priv->elements = g_list_remove( | |
390 manager->priv->elements, info); | |
391 return TRUE; | |
392 } | |
393 | |
394 gboolean | |
395 purple_media_manager_set_active_element(PurpleMediaManager *manager, | |
396 PurpleMediaElementInfo *info) | |
397 { | |
398 gboolean ret = FALSE; | |
399 | |
400 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), FALSE); | |
401 g_return_val_if_fail(info != NULL, FALSE); | |
402 | |
403 if (purple_media_manager_get_element_info(manager, info->id) == NULL) | |
404 purple_media_manager_register_element(manager, info); | |
405 | |
406 if (info->type & PURPLE_MEDIA_ELEMENT_SRC) { | |
407 if (info->type & PURPLE_MEDIA_ELEMENT_AUDIO) { | |
408 manager->priv->audio_src = info; | |
409 ret = TRUE; | |
410 } | |
411 if (info->type & PURPLE_MEDIA_ELEMENT_VIDEO) { | |
412 manager->priv->video_src = info; | |
413 ret = TRUE; | |
414 } | |
415 } | |
416 if (info->type & PURPLE_MEDIA_ELEMENT_SINK) { | |
417 if (info->type & PURPLE_MEDIA_ELEMENT_AUDIO) { | |
418 manager->priv->audio_sink = info; | |
419 ret = TRUE; | |
420 } | |
421 if (info->type & PURPLE_MEDIA_ELEMENT_VIDEO) { | |
422 manager->priv->video_sink = info; | |
423 ret = TRUE; | |
424 } | |
425 } | |
426 | |
427 return ret; | |
428 } | |
429 | |
430 PurpleMediaElementInfo * | |
431 purple_media_manager_get_active_element(PurpleMediaManager *manager, | |
432 PurpleMediaElementType type) | |
433 { | |
434 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), NULL); | |
435 | |
436 if (type & PURPLE_MEDIA_ELEMENT_SRC) { | |
437 if (type & PURPLE_MEDIA_ELEMENT_AUDIO) | |
438 return manager->priv->audio_src; | |
439 else if (type & PURPLE_MEDIA_ELEMENT_VIDEO) | |
440 return manager->priv->video_src; | |
441 } else if (type & PURPLE_MEDIA_ELEMENT_SINK) { | |
442 if (type & PURPLE_MEDIA_ELEMENT_AUDIO) | |
443 return manager->priv->audio_sink; | |
444 else if (type & PURPLE_MEDIA_ELEMENT_VIDEO) | |
445 return manager->priv->video_sink; | |
446 } | |
447 | |
448 return NULL; | |
449 } | |
450 | |
451 static void | |
452 window_id_cb(GstBus *bus, GstMessage *msg, PurpleMediaOutputWindow *ow) | |
453 { | |
454 if (GST_MESSAGE_TYPE(msg) != GST_MESSAGE_ELEMENT || | |
455 !gst_structure_has_name(msg->structure, | |
456 "prepare-xwindow-id")) | |
457 return; | |
458 | |
459 if (GST_ELEMENT_PARENT(GST_MESSAGE_SRC(msg)) == ow->sink) { | |
460 g_signal_handlers_disconnect_matched(bus, G_SIGNAL_MATCH_FUNC | |
461 | G_SIGNAL_MATCH_DATA, 0, 0, NULL, | |
462 window_id_cb, ow); | |
463 | |
464 gst_x_overlay_set_xwindow_id(GST_X_OVERLAY( | |
465 GST_MESSAGE_SRC(msg)), ow->window_id); | |
466 } | |
467 } | |
468 | |
469 gboolean | |
470 purple_media_manager_create_output_window(PurpleMediaManager *manager, | |
471 PurpleMedia *media, const gchar *session_id, | |
472 const gchar *participant) | |
473 { | |
474 GList *iter; | |
475 | |
476 g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE); | |
477 | |
478 iter = manager->priv->output_windows; | |
479 for(; iter; iter = g_list_next(iter)) { | |
480 PurpleMediaOutputWindow *ow = iter->data; | |
481 | |
482 if (ow->sink == NULL && ow->media == media && | |
483 ((participant != NULL && | |
484 ow->participant != NULL && | |
485 !strcmp(participant, ow->participant)) || | |
486 (participant == ow->participant)) && | |
487 !strcmp(session_id, ow->session_id)) { | |
488 GstBus *bus; | |
489 GstElement *queue; | |
490 GstElement *tee = purple_media_get_tee(media, | |
491 session_id, participant); | |
492 | |
493 if (tee == NULL) | |
494 continue; | |
495 | |
496 queue = gst_element_factory_make( | |
497 "queue", NULL); | |
498 ow->sink = purple_media_manager_get_element( | |
499 manager, PURPLE_MEDIA_RECV_VIDEO); | |
500 | |
501 if (participant == NULL) { | |
502 /* aka this is a preview sink */ | |
503 GObjectClass *klass = | |
504 G_OBJECT_GET_CLASS(ow->sink); | |
505 if (g_object_class_find_property(klass, | |
506 "sync")) | |
507 g_object_set(G_OBJECT(ow->sink), | |
508 "sync", "FALSE", NULL); | |
509 if (g_object_class_find_property(klass, | |
510 "async")) | |
511 g_object_set(G_OBJECT(ow->sink), | |
512 "async", FALSE, NULL); | |
513 } | |
514 | |
515 gst_bin_add_many(GST_BIN(GST_ELEMENT_PARENT(tee)), | |
516 queue, ow->sink, NULL); | |
517 | |
518 bus = gst_pipeline_get_bus(GST_PIPELINE( | |
519 manager->priv->pipeline)); | |
520 g_signal_connect(bus, "sync-message::element", | |
521 G_CALLBACK(window_id_cb), ow); | |
522 gst_object_unref(bus); | |
523 | |
524 gst_element_sync_state_with_parent(ow->sink); | |
525 gst_element_link(queue, ow->sink); | |
526 gst_element_sync_state_with_parent(queue); | |
527 gst_element_link(tee, queue); | |
528 } | |
529 } | |
530 return TRUE; | |
531 } | |
532 | |
533 gulong | |
534 purple_media_manager_set_output_window(PurpleMediaManager *manager, | |
535 PurpleMedia *media, const gchar *session_id, | |
536 const gchar *participant, gulong window_id) | |
537 { | |
538 PurpleMediaOutputWindow *output_window; | |
539 | |
540 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), FALSE); | |
541 g_return_val_if_fail(PURPLE_IS_MEDIA(media), FALSE); | |
542 | |
543 output_window = g_new0(PurpleMediaOutputWindow, 1); | |
544 output_window->id = manager->priv->next_output_window_id++; | |
545 output_window->media = media; | |
546 output_window->session_id = g_strdup(session_id); | |
547 output_window->participant = g_strdup(participant); | |
548 output_window->window_id = window_id; | |
549 | |
550 manager->priv->output_windows = g_list_prepend( | |
551 manager->priv->output_windows, output_window); | |
552 | |
553 if (purple_media_get_tee(media, session_id, participant) != NULL) | |
554 purple_media_manager_create_output_window(manager, | |
555 media, session_id, participant); | |
556 | |
557 return output_window->id; | |
558 } | |
559 | |
560 gboolean | |
561 purple_media_manager_remove_output_window(PurpleMediaManager *manager, | |
562 gulong output_window_id) | |
563 { | |
564 PurpleMediaOutputWindow *output_window = NULL; | |
565 GList *iter; | |
566 | |
567 g_return_val_if_fail(PURPLE_IS_MEDIA_MANAGER(manager), FALSE); | |
568 | |
569 iter = manager->priv->output_windows; | |
570 for (; iter; iter = g_list_next(iter)) { | |
571 PurpleMediaOutputWindow *ow = iter->data; | |
572 if (ow->id == output_window_id) { | |
573 manager->priv->output_windows = g_list_delete_link( | |
574 manager->priv->output_windows, iter); | |
575 output_window = ow; | |
576 break; | |
577 } | |
578 } | |
579 | |
580 if (output_window == NULL) | |
581 return FALSE; | |
582 | |
583 if (output_window->sink != NULL) { | |
584 GstPad *pad = gst_element_get_static_pad( | |
585 output_window->sink, "sink"); | |
586 GstPad *peer = gst_pad_get_peer(pad); | |
587 GstElement *queue = GST_ELEMENT_PARENT(peer); | |
588 gst_object_unref(pad); | |
589 pad = gst_element_get_static_pad(queue, "sink"); | |
590 peer = gst_pad_get_peer(pad); | |
591 gst_object_unref(pad); | |
592 gst_element_release_request_pad(GST_ELEMENT_PARENT(peer), peer); | |
593 gst_element_set_locked_state(queue, TRUE); | |
594 gst_element_set_state(queue, GST_STATE_NULL); | |
595 gst_bin_remove(GST_BIN(GST_ELEMENT_PARENT(queue)), queue); | |
596 gst_element_set_locked_state(output_window->sink, TRUE); | |
597 gst_element_set_state(output_window->sink, GST_STATE_NULL); | |
598 gst_bin_remove(GST_BIN(GST_ELEMENT_PARENT(output_window->sink)), | |
599 output_window->sink); | |
600 } | |
601 | |
602 g_free(output_window->session_id); | |
603 g_free(output_window->participant); | |
604 g_free(output_window); | |
605 | |
606 return TRUE; | |
607 } | |
608 | |
609 void | |
610 purple_media_manager_remove_output_windows(PurpleMediaManager *manager, | |
611 PurpleMedia *media, const gchar *session_id, | |
612 const gchar *participant) | |
613 { | |
614 GList *iter; | |
615 | |
616 g_return_if_fail(PURPLE_IS_MEDIA(media)); | |
617 | |
618 iter = manager->priv->output_windows; | |
619 | |
620 for (; iter;) { | |
621 PurpleMediaOutputWindow *ow = iter->data; | |
622 iter = g_list_next(iter); | |
623 | |
624 if (media == ow->media && | |
625 ((session_id != NULL && ow->session_id != NULL && | |
626 !strcmp(session_id, ow->session_id)) || | |
627 (session_id == ow->session_id)) && | |
628 ((participant != NULL && ow->participant != NULL && | |
629 !strcmp(participant, ow->participant)) || | |
630 (participant == ow->participant))) | |
631 purple_media_manager_remove_output_window( | |
632 manager, ow->id); | |
633 } | |
634 } | |
635 | |
636 #endif /* USE_VV */ |