4 * Finch is the legal property of its developers, whose names are too numerous
5 * to list here. Please refer to the COPYRIGHT file distributed with this
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
29 #include "gntbutton.h"
34 #include "conversation.h"
36 #include "mediamanager.h"
38 /* An incredibly large part of the following is from gtkmedia.c */
40 #include "media-gst.h"
44 #define FINCH_TYPE_MEDIA (finch_media_get_type())
45 #define FINCH_MEDIA(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), FINCH_TYPE_MEDIA, FinchMedia))
46 #define FINCH_MEDIA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), FINCH_TYPE_MEDIA, FinchMediaClass))
47 #define FINCH_IS_MEDIA(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), FINCH_TYPE_MEDIA))
48 #define FINCH_IS_MEDIA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), FINCH_TYPE_MEDIA))
49 #define FINCH_MEDIA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), FINCH_TYPE_MEDIA, FinchMediaClass))
51 typedef struct _FinchMedia FinchMedia
;
52 typedef struct _FinchMediaClass FinchMediaClass
;
53 typedef struct _FinchMediaPrivate FinchMediaPrivate
;
54 typedef enum _FinchMediaState FinchMediaState
;
56 struct _FinchMediaClass
58 GntBoxClass parent_class
;
64 FinchMediaPrivate
*priv
;
67 struct _FinchMediaPrivate
76 PurpleConversation
*conv
;
79 static GType
finch_media_get_type (void);
80 static void finch_media_class_init (FinchMediaClass
*klass
);
81 static void finch_media_init (FinchMedia
*media
);
82 static void finch_media_finalize (GObject
*object
);
83 static void finch_media_get_property (GObject
*object
, guint prop_id
, GValue
*value
, GParamSpec
*pspec
);
84 static void finch_media_set_property (GObject
*object
, guint prop_id
, const GValue
*value
, GParamSpec
*pspec
);
90 static guint finch_media_signals
[LAST_SIGNAL
] = {0};
97 G_DEFINE_TYPE_WITH_PRIVATE(FinchMedia
, finch_media
, GNT_TYPE_BOX
);
100 finch_media_class_init (FinchMediaClass
*klass
)
102 GObjectClass
*gobject_class
= (GObjectClass
*)klass
;
104 gobject_class
->finalize
= finch_media_finalize
;
105 gobject_class
->set_property
= finch_media_set_property
;
106 gobject_class
->get_property
= finch_media_get_property
;
108 g_object_class_install_property(gobject_class
, PROP_MEDIA
,
109 g_param_spec_object("media",
111 "The PurpleMedia associated with this media.",
113 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
| G_PARAM_STATIC_STRINGS
));
115 finch_media_signals
[MESSAGE
] = g_signal_new("message", G_TYPE_FROM_CLASS(klass
),
116 G_SIGNAL_RUN_LAST
, 0, NULL
, NULL
,
117 g_cclosure_marshal_VOID__STRING
,
118 G_TYPE_NONE
, 1, G_TYPE_STRING
);
123 finch_media_init (FinchMedia
*media
)
125 media
->priv
= finch_media_get_instance_private(media
);
127 media
->priv
->calling
= gnt_label_new(_("Calling..."));
128 media
->priv
->hangup
= gnt_button_new(_("Hangup"));
129 media
->priv
->accept
= gnt_button_new(_("Accept"));
130 media
->priv
->reject
= gnt_button_new(_("Reject"));
132 gnt_box_set_alignment(GNT_BOX(media
), GNT_ALIGN_MID
);
134 gnt_box_add_widget(GNT_BOX(media
), media
->priv
->accept
);
135 gnt_box_add_widget(GNT_BOX(media
), media
->priv
->reject
);
139 finch_media_finalize (GObject
*media
)
141 FinchMedia
*gntmedia
= FINCH_MEDIA(media
);
142 purple_debug_info("gntmedia", "finch_media_finalize\n");
143 if (gntmedia
->priv
->media
)
144 g_object_unref(gntmedia
->priv
->media
);
148 finch_media_emit_message(FinchMedia
*gntmedia
, const char *msg
)
150 g_signal_emit(gntmedia
, finch_media_signals
[MESSAGE
], 0, msg
);
154 finch_media_connected_cb(PurpleMedia
*media
, FinchMedia
*gntmedia
)
158 finch_media_emit_message(gntmedia
, _("Call in progress."));
160 gnt_box_remove(GNT_BOX(gntmedia
), gntmedia
->priv
->accept
);
161 gnt_box_remove(GNT_BOX(gntmedia
), gntmedia
->priv
->reject
);
162 gnt_box_remove(GNT_BOX(gntmedia
), gntmedia
->priv
->hangup
);
163 gnt_box_remove(GNT_BOX(gntmedia
), gntmedia
->priv
->calling
);
165 gnt_box_add_widget(GNT_BOX(gntmedia
), gntmedia
->priv
->hangup
);
167 gnt_widget_destroy(gntmedia
->priv
->accept
);
168 gnt_widget_destroy(gntmedia
->priv
->reject
);
169 gnt_widget_destroy(gntmedia
->priv
->calling
);
170 gntmedia
->priv
->accept
= NULL
;
171 gntmedia
->priv
->reject
= NULL
;
172 gntmedia
->priv
->calling
= NULL
;
174 parent
= gnt_widget_get_toplevel(GNT_WIDGET(gntmedia
));
175 gnt_box_readjust(GNT_BOX(parent
));
176 gnt_widget_draw(parent
);
180 finch_media_wait_cb(PurpleMedia
*media
, FinchMedia
*gntmedia
)
184 gnt_box_remove(GNT_BOX(gntmedia
), gntmedia
->priv
->accept
);
185 gnt_box_remove(GNT_BOX(gntmedia
), gntmedia
->priv
->reject
);
186 gnt_box_remove(GNT_BOX(gntmedia
), gntmedia
->priv
->hangup
);
187 gnt_box_remove(GNT_BOX(gntmedia
), gntmedia
->priv
->calling
);
189 gnt_box_add_widget(GNT_BOX(gntmedia
), gntmedia
->priv
->calling
);
190 gnt_box_add_widget(GNT_BOX(gntmedia
), gntmedia
->priv
->hangup
);
192 parent
= gnt_widget_get_toplevel(GNT_WIDGET(gntmedia
));
193 gnt_box_readjust(GNT_BOX(parent
));
194 gnt_widget_draw(parent
);
198 finch_media_state_changed_cb(PurpleMedia
*media
, PurpleMediaState state
,
199 gchar
*sid
, gchar
*name
, FinchMedia
*gntmedia
)
201 purple_debug_info("gntmedia", "state: %d sid: %s name: %s\n",
203 if (sid
== NULL
&& name
== NULL
) {
204 if (state
== PURPLE_MEDIA_STATE_END
) {
205 finch_media_emit_message(gntmedia
,
206 _("The call has been terminated."));
207 finch_conversation_set_info_widget(
208 gntmedia
->priv
->conv
, NULL
);
209 gnt_widget_destroy(GNT_WIDGET(gntmedia
));
211 * XXX: This shouldn't have to be here
212 * to free the FinchMedia widget.
214 g_object_unref(gntmedia
);
216 } else if (state
== PURPLE_MEDIA_STATE_CONNECTED
) {
217 finch_media_connected_cb(media
, gntmedia
);
218 } else if (state
== PURPLE_MEDIA_STATE_NEW
&&
219 sid
!= NULL
&& name
!= NULL
&&
220 purple_media_is_initiator(media
, sid
, name
) == FALSE
) {
221 PurpleAccount
*account
;
224 PurpleMediaSessionType type
=
225 purple_media_get_session_type(media
, sid
);
226 gchar
*message
= NULL
;
228 account
= purple_media_get_account(gntmedia
->priv
->media
);
229 buddy
= purple_blist_find_buddy(account
, name
);
230 alias
= buddy
? purple_buddy_get_contact_alias(buddy
) : name
;
232 if (type
& PURPLE_MEDIA_AUDIO
) {
233 message
= g_strdup_printf(
234 _("%s wishes to start an audio session with you."),
237 message
= g_strdup_printf(
238 _("%s is trying to start an unsupported media session type with you."),
241 finch_media_emit_message(gntmedia
, message
);
247 finch_media_stream_info_cb(PurpleMedia
*media
, PurpleMediaInfoType type
,
248 gchar
*sid
, gchar
*name
, gboolean local
, FinchMedia
*gntmedia
)
250 if (type
== PURPLE_MEDIA_INFO_REJECT
) {
251 finch_media_emit_message(gntmedia
,
252 _("You have rejected the call."));
257 finch_media_accept_cb(PurpleMedia
*media
, GntWidget
*widget
)
259 purple_media_stream_info(media
, PURPLE_MEDIA_INFO_ACCEPT
,
264 finch_media_hangup_cb(PurpleMedia
*media
, GntWidget
*widget
)
266 purple_media_stream_info(media
, PURPLE_MEDIA_INFO_HANGUP
,
271 finch_media_reject_cb(PurpleMedia
*media
, GntWidget
*widget
)
273 purple_media_stream_info(media
, PURPLE_MEDIA_INFO_REJECT
,
278 finch_media_set_property (GObject
*object
, guint prop_id
, const GValue
*value
, GParamSpec
*pspec
)
281 g_return_if_fail(FINCH_IS_MEDIA(object
));
283 media
= FINCH_MEDIA(object
);
287 if (media
->priv
->media
)
288 g_object_unref(media
->priv
->media
);
289 media
->priv
->media
= g_value_dup_object(value
);
290 g_signal_connect_swapped(G_OBJECT(media
->priv
->accept
), "activate",
291 G_CALLBACK(finch_media_accept_cb
), media
->priv
->media
);
292 g_signal_connect_swapped(G_OBJECT(media
->priv
->reject
), "activate",
293 G_CALLBACK(finch_media_reject_cb
), media
->priv
->media
);
294 g_signal_connect_swapped(G_OBJECT(media
->priv
->hangup
), "activate",
295 G_CALLBACK(finch_media_hangup_cb
), media
->priv
->media
);
297 if (purple_media_is_initiator(media
->priv
->media
,
298 NULL
, NULL
) == TRUE
) {
299 finch_media_wait_cb(media
->priv
->media
, media
);
301 g_signal_connect(G_OBJECT(media
->priv
->media
), "state-changed",
302 G_CALLBACK(finch_media_state_changed_cb
), media
);
303 g_signal_connect(G_OBJECT(media
->priv
->media
), "stream-info",
304 G_CALLBACK(finch_media_stream_info_cb
), media
);
308 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
314 finch_media_get_property (GObject
*object
, guint prop_id
, GValue
*value
, GParamSpec
*pspec
)
317 g_return_if_fail(FINCH_IS_MEDIA(object
));
319 media
= FINCH_MEDIA(object
);
323 g_value_set_object(value
, media
->priv
->media
);
326 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
332 finch_media_new(PurpleMedia
*media
)
334 return GNT_WIDGET(g_object_new(finch_media_get_type(),
337 "homogeneous", FALSE
,
342 gntmedia_message_cb(FinchMedia
*gntmedia
, const char *msg
, PurpleConversation
*conv
)
344 if (PURPLE_IS_IM_CONVERSATION(conv
)) {
345 purple_conversation_write_system_message(conv
, msg
, 0);
350 finch_new_media(PurpleMediaManager
*manager
, PurpleMedia
*media
,
351 PurpleAccount
*account
, gchar
*name
, gpointer null
)
354 PurpleConversation
*conv
;
356 conv
= PURPLE_CONVERSATION(purple_im_conversation_new(account
, name
));
358 gntmedia
= finch_media_new(media
);
359 g_signal_connect(G_OBJECT(gntmedia
), "message", G_CALLBACK(gntmedia_message_cb
), conv
);
360 FINCH_MEDIA(gntmedia
)->priv
->conv
= conv
;
361 finch_conversation_set_info_widget(conv
, gntmedia
);
366 call_cmd_cb(PurpleConversation
*conv
, const char *cmd
, char **args
,
367 char **eror
, gpointer data
)
369 PurpleAccount
*account
= purple_conversation_get_account(conv
);
371 if (!purple_protocol_initiate_media(account
,
372 purple_conversation_get_name(conv
),
374 return PURPLE_CMD_RET_FAILED
;
376 return PURPLE_CMD_RET_OK
;
381 void finch_media_manager_init(void)
384 PurpleMediaManager
*manager
= purple_media_manager_get();
385 PurpleMediaElementInfo
*audio_src
= NULL
;
386 PurpleMediaElementInfo
*audio_sink
= NULL
;
389 pref
= purple_prefs_get_string(
390 FINCH_PREFS_ROOT
"/vvconfig/audio/src/device");
392 audio_src
= purple_media_manager_get_element_info(manager
, pref
);
394 pref
= "autoaudiosrc";
395 purple_prefs_set_string(
396 FINCH_PREFS_ROOT
"/vvconfig/audio/src/device", pref
);
397 audio_src
= purple_media_manager_get_element_info(manager
,
401 pref
= purple_prefs_get_string(
402 FINCH_PREFS_ROOT
"/vvconfig/audio/sink/device");
404 audio_sink
= purple_media_manager_get_element_info(manager
, pref
);
406 pref
= "autoaudiosink";
407 purple_prefs_set_string(
408 FINCH_PREFS_ROOT
"/vvconfig/audio/sink/device", pref
);
409 audio_sink
= purple_media_manager_get_element_info(manager
,
413 g_signal_connect(G_OBJECT(manager
), "init-media", G_CALLBACK(finch_new_media
), NULL
);
414 purple_cmd_register("call", "", PURPLE_CMD_P_DEFAULT
,
415 PURPLE_CMD_FLAG_IM
, NULL
,
416 call_cmd_cb
, _("call: Make an audio call."), NULL
);
418 purple_media_manager_set_ui_caps(manager
,
419 PURPLE_MEDIA_CAPS_AUDIO
|
420 PURPLE_MEDIA_CAPS_AUDIO_SINGLE_DIRECTION
);
422 purple_debug_info("gntmedia", "Registering media element types\n");
423 purple_media_manager_set_active_element(manager
, audio_src
);
424 purple_media_manager_set_active_element(manager
, audio_sink
);
428 void finch_media_manager_uninit(void)
431 PurpleMediaManager
*manager
= purple_media_manager_get();
432 g_signal_handlers_disconnect_by_func(G_OBJECT(manager
),
433 G_CALLBACK(finch_new_media
), NULL
);