2 * @file media.c Account API
7 * Pidgin is the legal property of its developers, whose names are too numerous
8 * to list here. Please refer to the COPYRIGHT file distributed with this
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
28 #include "connection.h"
30 #include "mediamanager.h"
36 #include "pidginstock.h"
39 #include "media-gst.h"
42 #include <gdk/gdkwin32.h>
44 #include <gdk/gdkkeysyms.h>
46 #if !GST_CHECK_VERSION(1,0,0)
47 #include <gst/interfaces/xoverlay.h>
50 #define PIDGIN_TYPE_MEDIA (pidgin_media_get_type())
51 #define PIDGIN_MEDIA(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PIDGIN_TYPE_MEDIA, PidginMedia))
52 #define PIDGIN_MEDIA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), PIDGIN_TYPE_MEDIA, PidginMediaClass))
53 #define PIDGIN_IS_MEDIA(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), PIDGIN_TYPE_MEDIA))
54 #define PIDGIN_IS_MEDIA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PIDGIN_TYPE_MEDIA))
55 #define PIDGIN_MEDIA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PIDGIN_TYPE_MEDIA, PidginMediaClass))
57 typedef struct _PidginMedia PidginMedia
;
58 typedef struct _PidginMediaClass PidginMediaClass
;
59 typedef struct _PidginMediaPrivate PidginMediaPrivate
;
63 /* Waiting for response */
64 PIDGIN_MEDIA_WAITING
= 1,
66 PIDGIN_MEDIA_REQUESTED
,
68 PIDGIN_MEDIA_ACCEPTED
,
70 PIDGIN_MEDIA_REJECTED
,
73 struct _PidginMediaClass
75 GtkWindowClass parent_class
;
81 PidginMediaPrivate
*priv
;
84 struct _PidginMediaPrivate
88 gulong level_handler_id
;
98 GtkWidget
*send_progress
;
99 GHashTable
*recv_progressbars
;
101 PidginMediaState state
;
104 GtkWidget
*send_widget
;
105 GtkWidget
*recv_widget
;
106 GtkWidget
*button_widget
;
107 GtkWidget
*local_video
;
108 GHashTable
*remote_videos
;
111 PurpleMediaSessionType request_type
;
114 #define PIDGIN_MEDIA_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), PIDGIN_TYPE_MEDIA, PidginMediaPrivate))
116 static void pidgin_media_class_init (PidginMediaClass
*klass
);
117 static void pidgin_media_init (PidginMedia
*media
);
118 static void pidgin_media_dispose (GObject
*object
);
119 static void pidgin_media_finalize (GObject
*object
);
120 static void pidgin_media_get_property (GObject
*object
, guint prop_id
, GValue
*value
, GParamSpec
*pspec
);
121 static void pidgin_media_set_property (GObject
*object
, guint prop_id
, const GValue
*value
, GParamSpec
*pspec
);
122 static void pidgin_media_set_state(PidginMedia
*gtkmedia
, PidginMediaState state
);
124 static GtkWindowClass
*parent_class
= NULL
;
131 static guint pidgin_media_signals
[LAST_SIGNAL
] = {0};
141 pidgin_media_get_type(void)
143 static GType type
= 0;
146 static const GTypeInfo info
= {
147 sizeof(PidginMediaClass
),
150 (GClassInitFunc
) pidgin_media_class_init
,
155 (GInstanceInitFunc
) pidgin_media_init
,
158 type
= g_type_register_static(GTK_TYPE_WINDOW
, "PidginMedia", &info
, 0);
165 pidgin_media_class_init (PidginMediaClass
*klass
)
167 GObjectClass
*gobject_class
= (GObjectClass
*)klass
;
168 /* GtkContainerClass *container_class = (GtkContainerClass*)klass; */
169 parent_class
= g_type_class_peek_parent(klass
);
171 gobject_class
->dispose
= pidgin_media_dispose
;
172 gobject_class
->finalize
= pidgin_media_finalize
;
173 gobject_class
->set_property
= pidgin_media_set_property
;
174 gobject_class
->get_property
= pidgin_media_get_property
;
176 g_object_class_install_property(gobject_class
, PROP_MEDIA
,
177 g_param_spec_object("media",
179 "The PurpleMedia associated with this media.",
181 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
));
182 g_object_class_install_property(gobject_class
, PROP_SCREENNAME
,
183 g_param_spec_string("screenname",
185 "The screenname of the user this session is with.",
187 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
));
189 g_type_class_add_private(klass
, sizeof(PidginMediaPrivate
));
193 pidgin_media_hold_toggled(GtkToggleButton
*toggle
, PidginMedia
*media
)
195 purple_media_stream_info(media
->priv
->media
,
196 gtk_toggle_button_get_active(toggle
) ?
197 PURPLE_MEDIA_INFO_HOLD
: PURPLE_MEDIA_INFO_UNHOLD
,
202 pidgin_media_mute_toggled(GtkToggleButton
*toggle
, PidginMedia
*media
)
204 purple_media_stream_info(media
->priv
->media
,
205 gtk_toggle_button_get_active(toggle
) ?
206 PURPLE_MEDIA_INFO_MUTE
: PURPLE_MEDIA_INFO_UNMUTE
,
211 pidgin_media_pause_toggled(GtkToggleButton
*toggle
, PidginMedia
*media
)
213 purple_media_stream_info(media
->priv
->media
,
214 gtk_toggle_button_get_active(toggle
) ?
215 PURPLE_MEDIA_INFO_PAUSE
: PURPLE_MEDIA_INFO_UNPAUSE
,
220 pidgin_media_delete_event_cb(GtkWidget
*widget
,
221 GdkEvent
*event
, PidginMedia
*media
)
223 if (media
->priv
->media
)
224 purple_media_stream_info(media
->priv
->media
,
225 PURPLE_MEDIA_INFO_HANGUP
, NULL
, NULL
, TRUE
);
231 pidgin_x_error_handler(Display
*display
, XErrorEvent
*event
)
233 const gchar
*error_type
;
234 switch (event
->error_code
) {
235 #define XERRORCASE(type) case type: error_type = #type; break
236 XERRORCASE(BadAccess
);
237 XERRORCASE(BadAlloc
);
239 XERRORCASE(BadColor
);
240 XERRORCASE(BadCursor
);
241 XERRORCASE(BadDrawable
);
244 XERRORCASE(BadIDChoice
);
245 XERRORCASE(BadImplementation
);
246 XERRORCASE(BadLength
);
247 XERRORCASE(BadMatch
);
249 XERRORCASE(BadPixmap
);
250 XERRORCASE(BadRequest
);
251 XERRORCASE(BadValue
);
252 XERRORCASE(BadWindow
);
255 error_type
= "unknown";
258 purple_debug_error("media", "A %s Xlib error has occurred. "
259 "The program would normally crash now.\n",
266 menu_hangup(GtkAction
*action
, gpointer data
)
268 PidginMedia
*gtkmedia
= PIDGIN_MEDIA(data
);
269 purple_media_stream_info(gtkmedia
->priv
->media
,
270 PURPLE_MEDIA_INFO_HANGUP
, NULL
, NULL
, TRUE
);
273 static const GtkActionEntry menu_entries
[] = {
274 { "MediaMenu", NULL
, N_("_Media"), NULL
, NULL
, NULL
},
275 { "Hangup", NULL
, N_("_Hangup"), NULL
, NULL
, G_CALLBACK(menu_hangup
) },
278 static const char *media_menu
=
280 "<menubar name='Media'>"
281 "<menu action='MediaMenu'>"
282 "<menuitem action='Hangup'/>"
288 setup_menubar(PidginMedia
*window
)
290 GtkActionGroup
*action_group
;
292 GtkAccelGroup
*accel_group
;
295 action_group
= gtk_action_group_new("MediaActions");
297 gtk_action_group_set_translation_domain(action_group
,
300 gtk_action_group_add_actions(action_group
,
302 G_N_ELEMENTS(menu_entries
),
305 window
->priv
->ui
= gtk_ui_manager_new();
306 gtk_ui_manager_insert_action_group(window
->priv
->ui
, action_group
, 0);
308 accel_group
= gtk_ui_manager_get_accel_group(window
->priv
->ui
);
309 gtk_window_add_accel_group(GTK_WINDOW(window
), accel_group
);
312 if (!gtk_ui_manager_add_ui_from_string(window
->priv
->ui
, media_menu
, -1, &error
))
314 g_message("building menus failed: %s", error
->message
);
319 menu
= gtk_ui_manager_get_widget(window
->priv
->ui
, "/Media");
321 gtk_widget_show(menu
);
326 pidgin_media_init (PidginMedia
*media
)
329 media
->priv
= PIDGIN_MEDIA_GET_PRIVATE(media
);
332 XSetErrorHandler(pidgin_x_error_handler
);
335 vbox
= gtk_vbox_new(FALSE
, 0);
336 gtk_container_add(GTK_CONTAINER(media
), vbox
);
338 media
->priv
->statusbar
= gtk_statusbar_new();
339 gtk_box_pack_end(GTK_BOX(vbox
), media
->priv
->statusbar
,
341 gtk_statusbar_push(GTK_STATUSBAR(media
->priv
->statusbar
),
343 gtk_widget_show(media
->priv
->statusbar
);
345 media
->priv
->menubar
= setup_menubar(media
);
346 gtk_box_pack_start(GTK_BOX(vbox
), media
->priv
->menubar
,
349 media
->priv
->display
= gtk_hbox_new(FALSE
, PIDGIN_HIG_BOX_SPACE
);
350 gtk_container_set_border_width(GTK_CONTAINER(media
->priv
->display
),
351 PIDGIN_HIG_BOX_SPACE
);
352 gtk_box_pack_start(GTK_BOX(vbox
), media
->priv
->display
,
353 TRUE
, TRUE
, PIDGIN_HIG_BOX_SPACE
);
354 gtk_widget_show(vbox
);
356 g_signal_connect(G_OBJECT(media
), "delete-event",
357 G_CALLBACK(pidgin_media_delete_event_cb
), media
);
359 media
->priv
->recv_progressbars
=
360 g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, NULL
);
361 media
->priv
->remote_videos
=
362 g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, NULL
);
366 create_key(const gchar
*session_id
, const gchar
*participant
)
368 return g_strdup_printf("%s_%s", session_id
, participant
);
372 pidgin_media_insert_widget(PidginMedia
*gtkmedia
, GtkWidget
*widget
,
373 const gchar
*session_id
, const gchar
*participant
)
375 gchar
*key
= create_key(session_id
, participant
);
376 PurpleMediaSessionType type
=
377 purple_media_get_session_type(gtkmedia
->priv
->media
, session_id
);
379 if (type
& PURPLE_MEDIA_AUDIO
)
380 g_hash_table_insert(gtkmedia
->priv
->recv_progressbars
, key
, widget
);
381 else if (type
& PURPLE_MEDIA_VIDEO
)
382 g_hash_table_insert(gtkmedia
->priv
->remote_videos
, key
, widget
);
386 pidgin_media_get_widget(PidginMedia
*gtkmedia
,
387 const gchar
*session_id
, const gchar
*participant
)
389 GtkWidget
*widget
= NULL
;
390 gchar
*key
= create_key(session_id
, participant
);
391 PurpleMediaSessionType type
=
392 purple_media_get_session_type(gtkmedia
->priv
->media
, session_id
);
394 if (type
& PURPLE_MEDIA_AUDIO
)
395 widget
= g_hash_table_lookup(gtkmedia
->priv
->recv_progressbars
, key
);
396 else if (type
& PURPLE_MEDIA_VIDEO
)
397 widget
= g_hash_table_lookup(gtkmedia
->priv
->remote_videos
, key
);
404 pidgin_media_remove_widget(PidginMedia
*gtkmedia
,
405 const gchar
*session_id
, const gchar
*participant
)
407 GtkWidget
*widget
= pidgin_media_get_widget(gtkmedia
, session_id
, participant
);
410 PurpleMediaSessionType type
=
411 purple_media_get_session_type(gtkmedia
->priv
->media
, session_id
);
412 gchar
*key
= create_key(session_id
, participant
);
415 if (type
& PURPLE_MEDIA_AUDIO
) {
416 g_hash_table_remove(gtkmedia
->priv
->recv_progressbars
, key
);
418 if (g_hash_table_size(gtkmedia
->priv
->recv_progressbars
) == 0 &&
419 gtkmedia
->priv
->send_progress
) {
421 gtk_widget_destroy(gtkmedia
->priv
->send_progress
);
422 gtkmedia
->priv
->send_progress
= NULL
;
424 gtk_widget_destroy(gtkmedia
->priv
->mute
);
425 gtkmedia
->priv
->mute
= NULL
;
427 } else if (type
& PURPLE_MEDIA_VIDEO
) {
428 g_hash_table_remove(gtkmedia
->priv
->remote_videos
, key
);
430 if (g_hash_table_size(gtkmedia
->priv
->remote_videos
) == 0 &&
431 gtkmedia
->priv
->local_video
) {
433 gtk_widget_destroy(gtkmedia
->priv
->local_video
);
434 gtkmedia
->priv
->local_video
= NULL
;
436 gtk_widget_destroy(gtkmedia
->priv
->pause
);
437 gtkmedia
->priv
->pause
= NULL
;
443 gtk_widget_destroy(widget
);
445 gtk_widget_size_request(GTK_WIDGET(gtkmedia
), &req
);
446 gtk_window_resize(GTK_WINDOW(gtkmedia
), req
.width
, req
.height
);
451 level_message_cb(PurpleMedia
*media
, gchar
*session_id
, gchar
*participant
,
452 double level
, PidginMedia
*gtkmedia
)
454 GtkWidget
*progress
= NULL
;
455 if (participant
== NULL
)
456 progress
= gtkmedia
->priv
->send_progress
;
458 progress
= pidgin_media_get_widget(gtkmedia
, session_id
, participant
);
461 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress
), level
* 5);
466 pidgin_media_disconnect_levels(PurpleMedia
*media
, PidginMedia
*gtkmedia
)
468 PurpleMediaManager
*manager
= purple_media_get_manager(media
);
469 GstElement
*element
= purple_media_manager_get_pipeline(manager
);
470 gulong handler_id
= g_signal_handler_find(G_OBJECT(gst_pipeline_get_bus(GST_PIPELINE(element
))),
471 G_SIGNAL_MATCH_FUNC
| G_SIGNAL_MATCH_DATA
, 0, 0,
472 NULL
, G_CALLBACK(level_message_cb
), gtkmedia
);
474 g_signal_handler_disconnect(G_OBJECT(gst_pipeline_get_bus(GST_PIPELINE(element
))),
479 pidgin_media_dispose(GObject
*media
)
481 PidginMedia
*gtkmedia
= PIDGIN_MEDIA(media
);
482 purple_debug_info("gtkmedia", "pidgin_media_dispose\n");
484 if (gtkmedia
->priv
->media
) {
485 purple_request_close_with_handle(gtkmedia
);
486 purple_media_remove_output_windows(gtkmedia
->priv
->media
);
487 pidgin_media_disconnect_levels(gtkmedia
->priv
->media
, gtkmedia
);
488 g_object_unref(gtkmedia
->priv
->media
);
489 gtkmedia
->priv
->media
= NULL
;
492 if (gtkmedia
->priv
->ui
) {
493 g_object_unref(gtkmedia
->priv
->ui
);
494 gtkmedia
->priv
->ui
= NULL
;
497 if (gtkmedia
->priv
->timeout_id
!= 0)
498 g_source_remove(gtkmedia
->priv
->timeout_id
);
500 if (gtkmedia
->priv
->recv_progressbars
) {
501 g_hash_table_destroy(gtkmedia
->priv
->recv_progressbars
);
502 g_hash_table_destroy(gtkmedia
->priv
->remote_videos
);
503 gtkmedia
->priv
->recv_progressbars
= NULL
;
504 gtkmedia
->priv
->remote_videos
= NULL
;
507 G_OBJECT_CLASS(parent_class
)->dispose(media
);
511 pidgin_media_finalize(GObject
*media
)
513 /* PidginMedia *gtkmedia = PIDGIN_MEDIA(media); */
514 purple_debug_info("gtkmedia", "pidgin_media_finalize\n");
516 G_OBJECT_CLASS(parent_class
)->finalize(media
);
520 pidgin_media_emit_message(PidginMedia
*gtkmedia
, const char *msg
)
522 PurpleConversation
*conv
= purple_find_conversation_with_account(
523 PURPLE_CONV_TYPE_ANY
, gtkmedia
->priv
->screenname
,
524 purple_media_get_account(gtkmedia
->priv
->media
));
526 purple_conversation_write(conv
, NULL
, msg
,
527 PURPLE_MESSAGE_SYSTEM
, time(NULL
));
532 PidginMedia
*gtkmedia
;
535 } PidginMediaRealizeData
;
538 realize_cb_cb(PidginMediaRealizeData
*data
)
540 PidginMediaPrivate
*priv
= data
->gtkmedia
->priv
;
541 GdkWindow
*window
= NULL
;
543 if (data
->participant
== NULL
)
544 #if GTK_CHECK_VERSION(2, 14, 0)
545 window
= gtk_widget_get_window(priv
->local_video
);
547 window
= (priv
->local_video
)->window
;
550 GtkWidget
*widget
= pidgin_media_get_widget(data
->gtkmedia
,
551 data
->session_id
, data
->participant
);
553 #if GTK_CHECK_VERSION(2, 14, 0)
554 window
= gtk_widget_get_window(widget
);
556 window
= widget
->window
;
563 window_id
= GDK_WINDOW_HWND(window
);
564 #elif defined(HAVE_X11)
565 window_id
= GDK_WINDOW_XWINDOW(window
);
567 # error "Unsupported windowing system"
570 purple_media_set_output_window(priv
->media
, data
->session_id
,
571 data
->participant
, window_id
);
574 g_free(data
->session_id
);
575 g_free(data
->participant
);
581 realize_cb(GtkWidget
*widget
, PidginMediaRealizeData
*data
)
583 g_timeout_add(0, (GSourceFunc
)realize_cb_cb
, data
);
587 pidgin_media_error_cb(PidginMedia
*media
, const char *error
, PidginMedia
*gtkmedia
)
589 PurpleConversation
*conv
= purple_find_conversation_with_account(
590 PURPLE_CONV_TYPE_ANY
, gtkmedia
->priv
->screenname
,
591 purple_media_get_account(gtkmedia
->priv
->media
));
593 purple_conversation_write(conv
, NULL
, error
,
594 PURPLE_MESSAGE_ERROR
, time(NULL
));
596 purple_notify_error(NULL
, NULL
, _("Media error"), error
);
598 gtk_statusbar_push(GTK_STATUSBAR(gtkmedia
->priv
->statusbar
),
603 pidgin_media_accept_cb(PurpleMedia
*media
, int index
)
605 purple_media_stream_info(media
, PURPLE_MEDIA_INFO_ACCEPT
,
610 pidgin_media_reject_cb(PurpleMedia
*media
, int index
)
612 GList
*iter
= purple_media_get_session_ids(media
);
613 for (; iter
; iter
= g_list_delete_link(iter
, iter
)) {
614 const gchar
*sessionid
= iter
->data
;
615 if (!purple_media_accepted(media
, sessionid
, NULL
))
616 purple_media_stream_info(media
, PURPLE_MEDIA_INFO_REJECT
,
617 sessionid
, NULL
, TRUE
);
622 pidgin_request_timeout_cb(PidginMedia
*gtkmedia
)
624 PurpleAccount
*account
;
627 PurpleMediaSessionType type
;
628 gchar
*message
= NULL
;
630 account
= purple_media_get_account(gtkmedia
->priv
->media
);
631 buddy
= purple_find_buddy(account
, gtkmedia
->priv
->screenname
);
632 alias
= buddy
? purple_buddy_get_contact_alias(buddy
) :
633 gtkmedia
->priv
->screenname
;
634 type
= gtkmedia
->priv
->request_type
;
635 gtkmedia
->priv
->timeout_id
= 0;
637 if (type
& PURPLE_MEDIA_AUDIO
&& type
& PURPLE_MEDIA_VIDEO
) {
638 message
= g_strdup_printf(_("%s wishes to start an audio/video session with you."),
640 } else if (type
& PURPLE_MEDIA_AUDIO
) {
641 message
= g_strdup_printf(_("%s wishes to start an audio session with you."),
643 } else if (type
& PURPLE_MEDIA_VIDEO
) {
644 message
= g_strdup_printf(_("%s wishes to start a video session with you."),
648 gtkmedia
->priv
->request_type
= PURPLE_MEDIA_NONE
;
649 if (!purple_media_accepted(gtkmedia
->priv
->media
, NULL
, NULL
)) {
650 purple_request_accept_cancel(gtkmedia
, _("Incoming Call"),
651 message
, NULL
, PURPLE_DEFAULT_ACTION_NONE
,
652 (void*)account
, gtkmedia
->priv
->screenname
,
653 NULL
, gtkmedia
->priv
->media
,
654 pidgin_media_accept_cb
,
655 pidgin_media_reject_cb
);
657 pidgin_media_emit_message(gtkmedia
, message
);
663 #if GTK_CHECK_VERSION(2,12,0)
664 pidgin_media_input_volume_changed(GtkScaleButton
*range
, double value
,
667 double val
= (double)value
* 100.0;
669 pidgin_media_input_volume_changed(GtkRange
*range
, PurpleMedia
*media
)
671 double val
= (double)gtk_range_get_value(GTK_RANGE(range
));
673 purple_media_set_input_volume(media
, NULL
, val
);
677 #if GTK_CHECK_VERSION(2,12,0)
678 pidgin_media_output_volume_changed(GtkScaleButton
*range
, double value
,
681 double val
= (double)value
* 100.0;
683 pidgin_media_output_volume_changed(GtkRange
*range
, PurpleMedia
*media
)
685 double val
= (double)gtk_range_get_value(GTK_RANGE(range
));
687 purple_media_set_output_volume(media
, NULL
, NULL
, val
);
691 destroy_parent_widget_cb(GtkWidget
*widget
, GtkWidget
*parent
)
693 g_return_if_fail(GTK_IS_WIDGET(parent
));
695 gtk_widget_destroy(parent
);
699 pidgin_media_add_audio_widget(PidginMedia
*gtkmedia
,
700 PurpleMediaSessionType type
, const gchar
*sid
)
702 GtkWidget
*volume_widget
, *progress_parent
, *volume
, *progress
;
705 if (type
& PURPLE_MEDIA_SEND_AUDIO
) {
706 value
= purple_prefs_get_int(
707 "/purple/media/audio/volume/input");
708 } else if (type
& PURPLE_MEDIA_RECV_AUDIO
) {
709 value
= purple_prefs_get_int(
710 "/purple/media/audio/volume/output");
712 g_return_val_if_reached(NULL
);
714 #if GTK_CHECK_VERSION(2,12,0)
715 /* Setup widget structure */
716 volume_widget
= gtk_hbox_new(FALSE
, PIDGIN_HIG_BOX_SPACE
);
717 progress_parent
= gtk_vbox_new(FALSE
, 0);
718 gtk_box_pack_start(GTK_BOX(volume_widget
),
719 progress_parent
, TRUE
, TRUE
, 0);
722 volume
= gtk_volume_button_new();
723 gtk_scale_button_set_value(GTK_SCALE_BUTTON(volume
), value
/100.0);
724 gtk_box_pack_end(GTK_BOX(volume_widget
),
725 volume
, FALSE
, FALSE
, 0);
727 /* Setup widget structure */
728 volume_widget
= gtk_vbox_new(FALSE
, 0);
729 progress_parent
= volume_widget
;
732 volume
= gtk_hscale_new_with_range(0.0, 100.0, 5.0);
733 gtk_range_set_increments(GTK_RANGE(volume
), 5.0, 25.0);
734 gtk_range_set_value(GTK_RANGE(volume
), value
);
735 gtk_scale_set_draw_value(GTK_SCALE(volume
), FALSE
);
736 gtk_box_pack_end(GTK_BOX(volume_widget
),
737 volume
, TRUE
, FALSE
, 0);
740 /* Volume level indicator */
741 progress
= gtk_progress_bar_new();
742 gtk_widget_set_size_request(progress
, 250, 10);
743 gtk_box_pack_end(GTK_BOX(progress_parent
), progress
, TRUE
, FALSE
, 0);
745 if (type
& PURPLE_MEDIA_SEND_AUDIO
) {
746 g_signal_connect (G_OBJECT(volume
), "value-changed",
747 G_CALLBACK(pidgin_media_input_volume_changed
),
748 gtkmedia
->priv
->media
);
749 gtkmedia
->priv
->send_progress
= progress
;
750 } else if (type
& PURPLE_MEDIA_RECV_AUDIO
) {
751 g_signal_connect (G_OBJECT(volume
), "value-changed",
752 G_CALLBACK(pidgin_media_output_volume_changed
),
753 gtkmedia
->priv
->media
);
755 pidgin_media_insert_widget(gtkmedia
, progress
, sid
, gtkmedia
->priv
->screenname
);
758 g_signal_connect(G_OBJECT(progress
), "destroy",
759 G_CALLBACK(destroy_parent_widget_cb
),
762 gtk_widget_show_all(volume_widget
);
764 return volume_widget
;
768 phone_dtmf_pressed_cb(GtkButton
*button
, gpointer user_data
)
770 PidginMedia
*gtkmedia
= user_data
;
774 num
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button
), "dtmf-digit"));
775 sid
= g_object_get_data(G_OBJECT(button
), "session-id");
777 purple_media_send_dtmf(gtkmedia
->priv
->media
, sid
, num
, 25, 50);
780 static inline GtkWidget
*
781 phone_create_button(const gchar
*text_hi
, const gchar
*text_lo
)
787 const gchar
*text_hi_local
;
790 text_hi_local
= _(text_hi
);
794 grid
= gtk_vbox_new(TRUE
, 0);
796 button
= gtk_button_new();
797 label_hi
= gtk_label_new(text_hi_local
);
798 gtk_misc_set_alignment(GTK_MISC(label_hi
), 0.5, 0.5);
799 gtk_box_pack_end(GTK_BOX(grid
), label_hi
, FALSE
, TRUE
, 0);
800 label_lo
= gtk_label_new(text_lo
);
801 gtk_misc_set_alignment(GTK_MISC(label_lo
), 0.5, 0.5);
802 gtk_label_set_use_markup(GTK_LABEL(label_lo
), TRUE
);
803 gtk_box_pack_end(GTK_BOX(grid
), label_lo
, FALSE
, TRUE
, 0);
804 gtk_container_add(GTK_CONTAINER(button
), grid
);
809 static struct phone_label
{
814 {"<b>1</b>", NULL
, '1'},
815 /* Translators note: These are the letters on the keys of a numeric
816 keypad; translate according to the tables in §7 of ETSI ES 202 130:
817 http://webapp.etsi.org/WorkProgram/Report_WorkItem.asp?WKI_ID=11730
819 /* Letters on the '2' key of a numeric keypad */
820 {"<b>2</b>", N_("ABC"), '2'},
821 /* Letters on the '3' key of a numeric keypad */
822 {"<b>3</b>", N_("DEF"), '3'},
823 /* Letters on the '4' key of a numeric keypad */
824 {"<b>4</b>", N_("GHI"), '4'},
825 /* Letters on the '5' key of a numeric keypad */
826 {"<b>5</b>", N_("JKL"), '5'},
827 /* Letters on the '6' key of a numeric keypad */
828 {"<b>6</b>", N_("MNO"), '6'},
829 /* Letters on the '7' key of a numeric keypad */
830 {"<b>7</b>", N_("PQRS"), '7'},
831 /* Letters on the '8' key of a numeric keypad */
832 {"<b>8</b>", N_("TUV"), '8'},
833 /* Letters on the '9' key of a numeric keypad */
834 {"<b>9</b>", N_("WXYZ"), '9'},
835 {"<b>*</b>", NULL
, '*'},
836 {"<b>0</b>", NULL
, '0'},
837 {"<b>#</b>", NULL
, '#'},
842 pidgin_media_dtmf_key_press_event_cb(GtkWidget
*widget
,
843 GdkEvent
*event
, gpointer user_data
)
845 PidginMedia
*gtkmedia
= user_data
;
846 GdkEventKey
*key
= (GdkEventKey
*) event
;
848 if (event
->type
!= GDK_KEY_PRESS
) {
852 if ((key
->keyval
>= GDK_KEY_0
&& key
->keyval
<= GDK_KEY_9
) ||
853 key
->keyval
== GDK_KEY_asterisk
||
854 key
->keyval
== GDK_KEY_numbersign
) {
855 gchar
*sid
= g_object_get_data(G_OBJECT(widget
), "session-id");
857 purple_media_send_dtmf(gtkmedia
->priv
->media
, sid
, key
->keyval
, 25, 50);
864 pidgin_media_add_dtmf_widget(PidginMedia
*gtkmedia
,
865 PurpleMediaSessionType type
, const gchar
*_sid
)
867 GtkWidget
*grid
= gtk_table_new(4, 3, TRUE
);
870 GtkWindow
*win
= >kmedia
->parent
;
873 for (index
= 0; phone_labels
[index
].subtext
!= NULL
; index
++) {
874 button
= phone_create_button(phone_labels
[index
].text
,
875 phone_labels
[index
].subtext
);
876 g_signal_connect(button
, "pressed",
877 G_CALLBACK(phone_dtmf_pressed_cb
), gtkmedia
);
878 g_object_set_data(G_OBJECT(button
), "dtmf-digit",
879 GINT_TO_POINTER(phone_labels
[index
].chr
));
880 g_object_set_data_full(G_OBJECT(button
), "session-id",
881 g_strdup(_sid
), g_free
);
882 gtk_table_attach(GTK_TABLE(grid
), button
, index
% 3,
883 index
% 3 + 1, index
/ 3, index
/ 3 + 1,
884 GTK_FILL
| GTK_EXPAND
, GTK_FILL
| GTK_EXPAND
,
888 g_signal_connect(G_OBJECT(win
), "key-press-event",
889 G_CALLBACK(pidgin_media_dtmf_key_press_event_cb
), gtkmedia
);
890 g_object_set_data_full(G_OBJECT(win
), "session-id",
891 g_strdup(_sid
), g_free
);
893 gtk_widget_show_all(grid
);
899 pidgin_media_ready_cb(PurpleMedia
*media
, PidginMedia
*gtkmedia
, const gchar
*sid
)
901 GtkWidget
*send_widget
= NULL
, *recv_widget
= NULL
, *button_widget
= NULL
;
902 PurpleMediaSessionType type
=
903 purple_media_get_session_type(media
, sid
);
904 GdkPixbuf
*icon
= NULL
;
906 if (gtkmedia
->priv
->recv_widget
== NULL
907 && type
& (PURPLE_MEDIA_RECV_VIDEO
|
908 PURPLE_MEDIA_RECV_AUDIO
)) {
909 recv_widget
= gtk_vbox_new(FALSE
, PIDGIN_HIG_BOX_SPACE
);
910 gtk_box_pack_start(GTK_BOX(gtkmedia
->priv
->display
),
911 recv_widget
, TRUE
, TRUE
, 0);
912 gtk_widget_show(recv_widget
);
914 recv_widget
= gtkmedia
->priv
->recv_widget
;
916 if (gtkmedia
->priv
->send_widget
== NULL
917 && type
& (PURPLE_MEDIA_SEND_VIDEO
|
918 PURPLE_MEDIA_SEND_AUDIO
)) {
919 send_widget
= gtk_vbox_new(FALSE
, PIDGIN_HIG_BOX_SPACE
);
920 gtk_box_pack_start(GTK_BOX(gtkmedia
->priv
->display
),
921 send_widget
, FALSE
, TRUE
, 0);
922 button_widget
= gtk_hbox_new(FALSE
, PIDGIN_HIG_BOX_SPACE
);
923 gtk_box_pack_end(GTK_BOX(recv_widget
), button_widget
,
925 gtk_widget_show(send_widget
);
928 gtkmedia
->priv
->hold
=
929 gtk_toggle_button_new_with_mnemonic(_("_Hold"));
930 gtk_box_pack_end(GTK_BOX(button_widget
), gtkmedia
->priv
->hold
,
932 gtk_widget_show(gtkmedia
->priv
->hold
);
933 g_signal_connect(gtkmedia
->priv
->hold
, "toggled",
934 G_CALLBACK(pidgin_media_hold_toggled
),
937 send_widget
= gtkmedia
->priv
->send_widget
;
938 button_widget
= gtkmedia
->priv
->button_widget
;
941 if (type
& PURPLE_MEDIA_RECV_VIDEO
) {
942 PidginMediaRealizeData
*data
;
944 GtkWidget
*remote_video
;
945 GdkColor color
= {0, 0, 0, 0};
947 aspect
= gtk_aspect_frame_new(NULL
, 0, 0, 4.0/3.0, FALSE
);
948 gtk_frame_set_shadow_type(GTK_FRAME(aspect
), GTK_SHADOW_IN
);
949 gtk_box_pack_start(GTK_BOX(recv_widget
), aspect
, TRUE
, TRUE
, 0);
951 data
= g_new0(PidginMediaRealizeData
, 1);
952 data
->gtkmedia
= gtkmedia
;
953 data
->session_id
= g_strdup(sid
);
954 data
->participant
= g_strdup(gtkmedia
->priv
->screenname
);
956 remote_video
= gtk_drawing_area_new();
957 gtk_widget_modify_bg(remote_video
, GTK_STATE_NORMAL
, &color
);
958 g_signal_connect(G_OBJECT(remote_video
), "realize",
959 G_CALLBACK(realize_cb
), data
);
960 gtk_container_add(GTK_CONTAINER(aspect
), remote_video
);
961 gtk_widget_set_size_request (GTK_WIDGET(remote_video
), 320, 240);
962 g_signal_connect(G_OBJECT(remote_video
), "destroy",
963 G_CALLBACK(destroy_parent_widget_cb
), aspect
);
965 gtk_widget_show(remote_video
);
966 gtk_widget_show(aspect
);
968 pidgin_media_insert_widget(gtkmedia
, remote_video
,
969 data
->session_id
, data
->participant
);
972 if (type
& PURPLE_MEDIA_SEND_VIDEO
&& !gtkmedia
->priv
->local_video
) {
973 PidginMediaRealizeData
*data
;
975 GtkWidget
*local_video
;
976 GdkColor color
= {0, 0, 0, 0};
978 aspect
= gtk_aspect_frame_new(NULL
, 0, 0, 4.0/3.0, TRUE
);
979 gtk_frame_set_shadow_type(GTK_FRAME(aspect
), GTK_SHADOW_IN
);
980 gtk_box_pack_start(GTK_BOX(send_widget
), aspect
, FALSE
, TRUE
, 0);
982 data
= g_new0(PidginMediaRealizeData
, 1);
983 data
->gtkmedia
= gtkmedia
;
984 data
->session_id
= g_strdup(sid
);
985 data
->participant
= NULL
;
987 local_video
= gtk_drawing_area_new();
988 gtk_widget_modify_bg(local_video
, GTK_STATE_NORMAL
, &color
);
989 g_signal_connect(G_OBJECT(local_video
), "realize",
990 G_CALLBACK(realize_cb
), data
);
991 gtk_container_add(GTK_CONTAINER(aspect
), local_video
);
992 gtk_widget_set_size_request (GTK_WIDGET(local_video
), 80, 60);
993 g_signal_connect(G_OBJECT(local_video
), "destroy",
994 G_CALLBACK(destroy_parent_widget_cb
), aspect
);
996 gtk_widget_show(local_video
);
997 gtk_widget_show(aspect
);
999 gtkmedia
->priv
->pause
=
1000 gtk_toggle_button_new_with_mnemonic(_("_Pause"));
1001 gtk_box_pack_end(GTK_BOX(button_widget
), gtkmedia
->priv
->pause
,
1003 gtk_widget_show(gtkmedia
->priv
->pause
);
1004 g_signal_connect(gtkmedia
->priv
->pause
, "toggled",
1005 G_CALLBACK(pidgin_media_pause_toggled
),
1008 gtkmedia
->priv
->local_video
= local_video
;
1010 if (type
& PURPLE_MEDIA_RECV_AUDIO
) {
1011 gtk_box_pack_end(GTK_BOX(recv_widget
),
1012 pidgin_media_add_audio_widget(gtkmedia
,
1013 PURPLE_MEDIA_RECV_AUDIO
, sid
), FALSE
, FALSE
, 0);
1016 if (type
& PURPLE_MEDIA_SEND_AUDIO
) {
1017 gtkmedia
->priv
->mute
=
1018 gtk_toggle_button_new_with_mnemonic(_("_Mute"));
1019 gtk_box_pack_end(GTK_BOX(button_widget
), gtkmedia
->priv
->mute
,
1021 gtk_widget_show(gtkmedia
->priv
->mute
);
1022 g_signal_connect(gtkmedia
->priv
->mute
, "toggled",
1023 G_CALLBACK(pidgin_media_mute_toggled
),
1026 gtk_box_pack_end(GTK_BOX(recv_widget
),
1027 pidgin_media_add_audio_widget(gtkmedia
,
1028 PURPLE_MEDIA_SEND_AUDIO
, sid
), FALSE
, FALSE
, 0);
1030 gtk_box_pack_end(GTK_BOX(recv_widget
),
1031 pidgin_media_add_dtmf_widget(gtkmedia
,
1032 PURPLE_MEDIA_SEND_AUDIO
, sid
), FALSE
, FALSE
, 0);
1035 if (type
& PURPLE_MEDIA_AUDIO
&&
1036 gtkmedia
->priv
->level_handler_id
== 0) {
1037 gtkmedia
->priv
->level_handler_id
= g_signal_connect(
1038 media
, "level", G_CALLBACK(level_message_cb
),
1042 if (send_widget
!= NULL
)
1043 gtkmedia
->priv
->send_widget
= send_widget
;
1044 if (recv_widget
!= NULL
)
1045 gtkmedia
->priv
->recv_widget
= recv_widget
;
1046 if (button_widget
!= NULL
) {
1047 gtkmedia
->priv
->button_widget
= button_widget
;
1048 gtk_widget_show(GTK_WIDGET(button_widget
));
1051 if (purple_media_is_initiator(media
, sid
, NULL
) == FALSE
) {
1052 if (gtkmedia
->priv
->timeout_id
!= 0)
1053 g_source_remove(gtkmedia
->priv
->timeout_id
);
1054 gtkmedia
->priv
->request_type
|= type
;
1055 gtkmedia
->priv
->timeout_id
= g_timeout_add(500,
1056 (GSourceFunc
)pidgin_request_timeout_cb
,
1060 /* set the window icon according to the type */
1061 if (type
& PURPLE_MEDIA_VIDEO
) {
1062 icon
= gtk_widget_render_icon(GTK_WIDGET(gtkmedia
),
1063 PIDGIN_STOCK_TOOLBAR_VIDEO_CALL
,
1064 gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_LARGE
), NULL
);
1065 } else if (type
& PURPLE_MEDIA_AUDIO
) {
1066 icon
= gtk_widget_render_icon(GTK_WIDGET(gtkmedia
),
1067 PIDGIN_STOCK_TOOLBAR_AUDIO_CALL
,
1068 gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_LARGE
), NULL
);
1072 gtk_window_set_icon(GTK_WINDOW(gtkmedia
), icon
);
1073 g_object_unref(icon
);
1076 gtk_widget_show(gtkmedia
->priv
->display
);
1080 pidgin_media_state_changed_cb(PurpleMedia
*media
, PurpleMediaState state
,
1081 gchar
*sid
, gchar
*name
, PidginMedia
*gtkmedia
)
1083 purple_debug_info("gtkmedia", "state: %d sid: %s name: %s\n",
1084 state
, sid
? sid
: "(null)", name
? name
: "(null)");
1085 if (state
== PURPLE_MEDIA_STATE_END
) {
1086 if (sid
!= NULL
&& name
!= NULL
) {
1087 pidgin_media_remove_widget(gtkmedia
, sid
, name
);
1088 } else if (sid
== NULL
&& name
== NULL
) {
1089 pidgin_media_emit_message(gtkmedia
,
1090 _("The call has been terminated."));
1091 gtk_widget_destroy(GTK_WIDGET(gtkmedia
));
1093 } else if (state
== PURPLE_MEDIA_STATE_NEW
&&
1094 sid
!= NULL
&& name
!= NULL
) {
1095 pidgin_media_ready_cb(media
, gtkmedia
, sid
);
1100 pidgin_media_stream_info_cb(PurpleMedia
*media
, PurpleMediaInfoType type
,
1101 gchar
*sid
, gchar
*name
, gboolean local
,
1102 PidginMedia
*gtkmedia
)
1104 if (type
== PURPLE_MEDIA_INFO_REJECT
) {
1105 pidgin_media_emit_message(gtkmedia
,
1106 _("You have rejected the call."));
1107 } else if (type
== PURPLE_MEDIA_INFO_ACCEPT
) {
1109 purple_request_close_with_handle(gtkmedia
);
1110 pidgin_media_set_state(gtkmedia
, PIDGIN_MEDIA_ACCEPTED
);
1111 pidgin_media_emit_message(gtkmedia
, _("Call in progress."));
1112 gtk_statusbar_push(GTK_STATUSBAR(gtkmedia
->priv
->statusbar
),
1113 0, _("Call in progress."));
1114 gtk_widget_show(GTK_WIDGET(gtkmedia
));
1119 pidgin_media_set_property (GObject
*object
, guint prop_id
, const GValue
*value
, GParamSpec
*pspec
)
1122 g_return_if_fail(PIDGIN_IS_MEDIA(object
));
1124 media
= PIDGIN_MEDIA(object
);
1128 if (media
->priv
->media
)
1129 g_object_unref(media
->priv
->media
);
1130 media
->priv
->media
= g_value_get_object(value
);
1131 g_object_ref(media
->priv
->media
);
1133 if (purple_media_is_initiator(media
->priv
->media
,
1134 NULL
, NULL
) == TRUE
)
1135 pidgin_media_set_state(media
, PIDGIN_MEDIA_WAITING
);
1137 pidgin_media_set_state(media
, PIDGIN_MEDIA_REQUESTED
);
1139 g_signal_connect(G_OBJECT(media
->priv
->media
), "error",
1140 G_CALLBACK(pidgin_media_error_cb
), media
);
1141 g_signal_connect(G_OBJECT(media
->priv
->media
), "state-changed",
1142 G_CALLBACK(pidgin_media_state_changed_cb
), media
);
1143 g_signal_connect(G_OBJECT(media
->priv
->media
), "stream-info",
1144 G_CALLBACK(pidgin_media_stream_info_cb
), media
);
1147 case PROP_SCREENNAME
:
1148 if (media
->priv
->screenname
)
1149 g_free(media
->priv
->screenname
);
1150 media
->priv
->screenname
= g_value_dup_string(value
);
1153 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
1159 pidgin_media_get_property (GObject
*object
, guint prop_id
, GValue
*value
, GParamSpec
*pspec
)
1162 g_return_if_fail(PIDGIN_IS_MEDIA(object
));
1164 media
= PIDGIN_MEDIA(object
);
1168 g_value_set_object(value
, media
->priv
->media
);
1170 case PROP_SCREENNAME
:
1171 g_value_set_string(value
, media
->priv
->screenname
);
1174 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
1180 pidgin_media_new(PurpleMedia
*media
, const gchar
*screenname
)
1182 PidginMedia
*gtkmedia
= g_object_new(pidgin_media_get_type(),
1184 "screenname", screenname
, NULL
);
1185 return GTK_WIDGET(gtkmedia
);
1189 pidgin_media_set_state(PidginMedia
*gtkmedia
, PidginMediaState state
)
1191 gtkmedia
->priv
->state
= state
;
1195 pidgin_media_new_cb(PurpleMediaManager
*manager
, PurpleMedia
*media
,
1196 PurpleAccount
*account
, gchar
*screenname
, gpointer nul
)
1198 PidginMedia
*gtkmedia
= PIDGIN_MEDIA(
1199 pidgin_media_new(media
, screenname
));
1200 PurpleBuddy
*buddy
= purple_find_buddy(account
, screenname
);
1201 const gchar
*alias
= buddy
?
1202 purple_buddy_get_contact_alias(buddy
) : screenname
;
1203 gtk_window_set_title(GTK_WINDOW(gtkmedia
), alias
);
1205 if (purple_media_is_initiator(media
, NULL
, NULL
) == TRUE
)
1206 gtk_widget_show(GTK_WIDGET(gtkmedia
));
1212 videosink_disable_last_sample(GstElement
*sink
)
1214 GObjectClass
*klass
= G_OBJECT_GET_CLASS(sink
);
1216 if (g_object_class_find_property(klass
, "enable-last-sample")) {
1217 g_object_set(sink
, "enable-last-sample", FALSE
, NULL
);
1222 autovideosink_child_added_cb (GstChildProxy
*child_proxy
, GObject
*object
,
1223 #if GST_CHECK_VERSION(1,0,0)
1228 videosink_disable_last_sample(GST_ELEMENT(object
));
1232 create_default_video_src(PurpleMedia
*media
,
1233 const gchar
*session_id
, const gchar
*participant
)
1235 GstElement
*sendbin
, *src
;
1240 /* autovideosrc doesn't pick ksvideosrc for some reason */
1241 src
= gst_element_factory_make("ksvideosrc", NULL
);
1243 src
= gst_element_factory_make("dshowvideosrc", NULL
);
1245 src
= gst_element_factory_make("autovideosrc", NULL
);
1247 src
= gst_element_factory_make("gconfvideosrc", NULL
);
1249 src
= gst_element_factory_make("autovideosrc", NULL
);
1251 src
= gst_element_factory_make("v4l2src", NULL
);
1253 src
= gst_element_factory_make("v4lsrc", NULL
);
1256 purple_debug_error("gtkmedia", "Unable to find a suitable "
1257 "element for the default video source.\n");
1261 sendbin
= gst_bin_new("pidgindefaultvideosrc");
1263 gst_bin_add(GST_BIN(sendbin
), src
);
1265 pad
= gst_element_get_static_pad(src
, "src");
1266 ghost
= gst_ghost_pad_new("ghostsrc", pad
);
1267 gst_object_unref(pad
);
1268 gst_element_add_pad(sendbin
, ghost
);
1274 create_default_video_sink(PurpleMedia
*media
,
1275 const gchar
*session_id
, const gchar
*participant
)
1277 GstElement
*sink
= gst_element_factory_make("gconfvideosink", NULL
);
1279 sink
= gst_element_factory_make("autovideosink", NULL
);
1281 purple_debug_error("gtkmedia", "Unable to find a suitable "
1282 "element for the default video sink.\n");
1284 g_signal_connect(sink
, "child-added",
1285 G_CALLBACK(autovideosink_child_added_cb
), NULL
);
1290 create_default_audio_src(PurpleMedia
*media
,
1291 const gchar
*session_id
, const gchar
*participant
)
1294 src
= gst_element_factory_make("gconfaudiosrc", NULL
);
1296 src
= gst_element_factory_make("autoaudiosrc", NULL
);
1298 src
= gst_element_factory_make("alsasrc", NULL
);
1300 src
= gst_element_factory_make("osssrc", NULL
);
1302 src
= gst_element_factory_make("dshowaudiosrc", NULL
);
1304 purple_debug_error("gtkmedia", "Unable to find a suitable "
1305 "element for the default audio source.\n");
1308 gst_element_set_name(src
, "pidgindefaultaudiosrc");
1313 create_default_audio_sink(PurpleMedia
*media
,
1314 const gchar
*session_id
, const gchar
*participant
)
1317 sink
= gst_element_factory_make("gconfaudiosink", NULL
);
1319 sink
= gst_element_factory_make("autoaudiosink",NULL
);
1321 purple_debug_error("gtkmedia", "Unable to find a suitable "
1322 "element for the default audio sink.\n");
1330 pidgin_medias_init(void)
1333 PurpleMediaManager
*manager
= purple_media_manager_get();
1334 PurpleMediaElementInfo
*default_video_src
=
1335 g_object_new(PURPLE_TYPE_MEDIA_ELEMENT_INFO
,
1336 "id", "pidgindefaultvideosrc",
1337 "name", "Pidgin Default Video Source",
1338 "type", PURPLE_MEDIA_ELEMENT_VIDEO
1339 | PURPLE_MEDIA_ELEMENT_SRC
1340 | PURPLE_MEDIA_ELEMENT_ONE_SRC
1341 | PURPLE_MEDIA_ELEMENT_UNIQUE
,
1342 "create-cb", create_default_video_src
, NULL
);
1343 PurpleMediaElementInfo
*default_video_sink
=
1344 g_object_new(PURPLE_TYPE_MEDIA_ELEMENT_INFO
,
1345 "id", "pidgindefaultvideosink",
1346 "name", "Pidgin Default Video Sink",
1347 "type", PURPLE_MEDIA_ELEMENT_VIDEO
1348 | PURPLE_MEDIA_ELEMENT_SINK
1349 | PURPLE_MEDIA_ELEMENT_ONE_SINK
,
1350 "create-cb", create_default_video_sink
, NULL
);
1351 PurpleMediaElementInfo
*default_audio_src
=
1352 g_object_new(PURPLE_TYPE_MEDIA_ELEMENT_INFO
,
1353 "id", "pidgindefaultaudiosrc",
1354 "name", "Pidgin Default Audio Source",
1355 "type", PURPLE_MEDIA_ELEMENT_AUDIO
1356 | PURPLE_MEDIA_ELEMENT_SRC
1357 | PURPLE_MEDIA_ELEMENT_ONE_SRC
1358 | PURPLE_MEDIA_ELEMENT_UNIQUE
,
1359 "create-cb", create_default_audio_src
, NULL
);
1360 PurpleMediaElementInfo
*default_audio_sink
=
1361 g_object_new(PURPLE_TYPE_MEDIA_ELEMENT_INFO
,
1362 "id", "pidgindefaultaudiosink",
1363 "name", "Pidgin Default Audio Sink",
1364 "type", PURPLE_MEDIA_ELEMENT_AUDIO
1365 | PURPLE_MEDIA_ELEMENT_SINK
1366 | PURPLE_MEDIA_ELEMENT_ONE_SINK
,
1367 "create-cb", create_default_audio_sink
, NULL
);
1369 g_signal_connect(G_OBJECT(manager
), "init-media",
1370 G_CALLBACK(pidgin_media_new_cb
), NULL
);
1372 purple_media_manager_set_ui_caps(manager
,
1373 PURPLE_MEDIA_CAPS_AUDIO
|
1374 PURPLE_MEDIA_CAPS_AUDIO_SINGLE_DIRECTION
|
1375 PURPLE_MEDIA_CAPS_VIDEO
|
1376 PURPLE_MEDIA_CAPS_VIDEO_SINGLE_DIRECTION
|
1377 PURPLE_MEDIA_CAPS_AUDIO_VIDEO
);
1379 purple_debug_info("gtkmedia", "Registering media element types\n");
1380 purple_media_manager_set_active_element(manager
, default_video_src
);
1381 purple_media_manager_set_active_element(manager
, default_video_sink
);
1382 purple_media_manager_set_active_element(manager
, default_audio_src
);
1383 purple_media_manager_set_active_element(manager
, default_audio_sink
);