3 * Finch is the legal property of its developers, whose names are too numerous
4 * to list here. Please refer to the COPYRIGHT file distributed with this
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
28 #include "gntbutton.h"
33 #include "conversation.h"
35 #include "mediamanager.h"
37 /* An incredibly large part of the following is from gtkmedia.c */
39 #include "media-gst.h"
43 #define FINCH_TYPE_MEDIA (finch_media_get_type())
44 #define FINCH_MEDIA(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), FINCH_TYPE_MEDIA, FinchMedia))
45 #define FINCH_MEDIA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), FINCH_TYPE_MEDIA, FinchMediaClass))
46 #define FINCH_IS_MEDIA(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), FINCH_TYPE_MEDIA))
47 #define FINCH_IS_MEDIA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), FINCH_TYPE_MEDIA))
48 #define FINCH_MEDIA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), FINCH_TYPE_MEDIA, FinchMediaClass))
50 typedef struct _FinchMedia FinchMedia
;
51 typedef struct _FinchMediaClass FinchMediaClass
;
52 typedef struct _FinchMediaPrivate FinchMediaPrivate
;
53 typedef enum _FinchMediaState FinchMediaState
;
55 struct _FinchMediaClass
57 GntBoxClass parent_class
;
63 FinchMediaPrivate
*priv
;
66 struct _FinchMediaPrivate
75 PurpleConversation
*conv
;
78 static GType
finch_media_get_type (void);
79 static void finch_media_class_init (FinchMediaClass
*klass
);
80 static void finch_media_init (FinchMedia
*media
);
81 static void finch_media_finalize (GObject
*object
);
82 static void finch_media_get_property (GObject
*object
, guint prop_id
, GValue
*value
, GParamSpec
*pspec
);
83 static void finch_media_set_property (GObject
*object
, guint prop_id
, const GValue
*value
, GParamSpec
*pspec
);
89 static guint finch_media_signals
[LAST_SIGNAL
] = {0};
96 G_DEFINE_TYPE_WITH_PRIVATE(FinchMedia
, finch_media
, GNT_TYPE_BOX
);
99 finch_media_class_init (FinchMediaClass
*klass
)
101 GObjectClass
*gobject_class
= (GObjectClass
*)klass
;
103 gobject_class
->finalize
= finch_media_finalize
;
104 gobject_class
->set_property
= finch_media_set_property
;
105 gobject_class
->get_property
= finch_media_get_property
;
107 g_object_class_install_property(gobject_class
, PROP_MEDIA
,
108 g_param_spec_object("media",
110 "The PurpleMedia associated with this media.",
112 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
| G_PARAM_STATIC_STRINGS
));
114 finch_media_signals
[MESSAGE
] = g_signal_new("message", G_TYPE_FROM_CLASS(klass
),
115 G_SIGNAL_RUN_LAST
, 0, NULL
, NULL
,
116 g_cclosure_marshal_VOID__STRING
,
117 G_TYPE_NONE
, 1, G_TYPE_STRING
);
122 finch_media_init (FinchMedia
*media
)
124 media
->priv
= finch_media_get_instance_private(media
);
126 media
->priv
->calling
= gnt_label_new(_("Calling..."));
127 media
->priv
->hangup
= gnt_button_new(_("Hangup"));
128 media
->priv
->accept
= gnt_button_new(_("Accept"));
129 media
->priv
->reject
= gnt_button_new(_("Reject"));
131 gnt_box_set_alignment(GNT_BOX(media
), GNT_ALIGN_MID
);
133 gnt_box_add_widget(GNT_BOX(media
), media
->priv
->accept
);
134 gnt_box_add_widget(GNT_BOX(media
), media
->priv
->reject
);
138 finch_media_finalize (GObject
*media
)
140 FinchMedia
*gntmedia
= FINCH_MEDIA(media
);
141 purple_debug_info("gntmedia", "finch_media_finalize\n");
142 if (gntmedia
->priv
->media
)
143 g_object_unref(gntmedia
->priv
->media
);
147 finch_media_emit_message(FinchMedia
*gntmedia
, const char *msg
)
149 g_signal_emit(gntmedia
, finch_media_signals
[MESSAGE
], 0, msg
);
153 finch_media_connected_cb(PurpleMedia
*media
, FinchMedia
*gntmedia
)
157 finch_media_emit_message(gntmedia
, _("Call in progress."));
159 gnt_box_remove(GNT_BOX(gntmedia
), gntmedia
->priv
->accept
);
160 gnt_box_remove(GNT_BOX(gntmedia
), gntmedia
->priv
->reject
);
161 gnt_box_remove(GNT_BOX(gntmedia
), gntmedia
->priv
->hangup
);
162 gnt_box_remove(GNT_BOX(gntmedia
), gntmedia
->priv
->calling
);
164 gnt_box_add_widget(GNT_BOX(gntmedia
), gntmedia
->priv
->hangup
);
166 gnt_widget_destroy(gntmedia
->priv
->accept
);
167 gnt_widget_destroy(gntmedia
->priv
->reject
);
168 gnt_widget_destroy(gntmedia
->priv
->calling
);
169 gntmedia
->priv
->accept
= NULL
;
170 gntmedia
->priv
->reject
= NULL
;
171 gntmedia
->priv
->calling
= NULL
;
173 parent
= gnt_widget_get_toplevel(GNT_WIDGET(gntmedia
));
174 gnt_box_readjust(GNT_BOX(parent
));
175 gnt_widget_draw(parent
);
179 finch_media_wait_cb(PurpleMedia
*media
, FinchMedia
*gntmedia
)
183 gnt_box_remove(GNT_BOX(gntmedia
), gntmedia
->priv
->accept
);
184 gnt_box_remove(GNT_BOX(gntmedia
), gntmedia
->priv
->reject
);
185 gnt_box_remove(GNT_BOX(gntmedia
), gntmedia
->priv
->hangup
);
186 gnt_box_remove(GNT_BOX(gntmedia
), gntmedia
->priv
->calling
);
188 gnt_box_add_widget(GNT_BOX(gntmedia
), gntmedia
->priv
->calling
);
189 gnt_box_add_widget(GNT_BOX(gntmedia
), gntmedia
->priv
->hangup
);
191 parent
= gnt_widget_get_toplevel(GNT_WIDGET(gntmedia
));
192 gnt_box_readjust(GNT_BOX(parent
));
193 gnt_widget_draw(parent
);
197 finch_media_state_changed_cb(PurpleMedia
*media
, PurpleMediaState state
,
198 gchar
*sid
, gchar
*name
, FinchMedia
*gntmedia
)
200 purple_debug_info("gntmedia", "state: %d sid: %s name: %s\n",
202 if (sid
== NULL
&& name
== NULL
) {
203 if (state
== PURPLE_MEDIA_STATE_END
) {
204 finch_media_emit_message(gntmedia
,
205 _("The call has been terminated."));
206 finch_conversation_set_info_widget(
207 gntmedia
->priv
->conv
, NULL
);
208 gnt_widget_destroy(GNT_WIDGET(gntmedia
));
210 * XXX: This shouldn't have to be here
211 * to free the FinchMedia widget.
213 g_object_unref(gntmedia
);
215 } else if (state
== PURPLE_MEDIA_STATE_CONNECTED
) {
216 finch_media_connected_cb(media
, gntmedia
);
217 } else if (state
== PURPLE_MEDIA_STATE_NEW
&&
218 sid
!= NULL
&& name
!= NULL
&&
219 purple_media_is_initiator(media
, sid
, name
) == FALSE
) {
220 PurpleAccount
*account
;
223 PurpleMediaSessionType type
=
224 purple_media_get_session_type(media
, sid
);
225 gchar
*message
= NULL
;
227 account
= purple_media_get_account(gntmedia
->priv
->media
);
228 buddy
= purple_blist_find_buddy(account
, name
);
229 alias
= buddy
? purple_buddy_get_contact_alias(buddy
) : name
;
231 if (type
& PURPLE_MEDIA_AUDIO
) {
232 message
= g_strdup_printf(
233 _("%s wishes to start an audio session with you."),
236 message
= g_strdup_printf(
237 _("%s is trying to start an unsupported media session type with you."),
240 finch_media_emit_message(gntmedia
, message
);
246 finch_media_stream_info_cb(PurpleMedia
*media
, PurpleMediaInfoType type
,
247 gchar
*sid
, gchar
*name
, gboolean local
, FinchMedia
*gntmedia
)
249 if (type
== PURPLE_MEDIA_INFO_REJECT
) {
250 finch_media_emit_message(gntmedia
,
251 _("You have rejected the call."));
256 finch_media_accept_cb(PurpleMedia
*media
, GntWidget
*widget
)
258 purple_media_stream_info(media
, PURPLE_MEDIA_INFO_ACCEPT
,
263 finch_media_hangup_cb(PurpleMedia
*media
, GntWidget
*widget
)
265 purple_media_stream_info(media
, PURPLE_MEDIA_INFO_HANGUP
,
270 finch_media_reject_cb(PurpleMedia
*media
, GntWidget
*widget
)
272 purple_media_stream_info(media
, PURPLE_MEDIA_INFO_REJECT
,
277 finch_media_set_property (GObject
*object
, guint prop_id
, const GValue
*value
, GParamSpec
*pspec
)
280 g_return_if_fail(FINCH_IS_MEDIA(object
));
282 media
= FINCH_MEDIA(object
);
286 if (media
->priv
->media
)
287 g_object_unref(media
->priv
->media
);
288 media
->priv
->media
= g_value_dup_object(value
);
289 g_signal_connect_swapped(G_OBJECT(media
->priv
->accept
), "activate",
290 G_CALLBACK(finch_media_accept_cb
), media
->priv
->media
);
291 g_signal_connect_swapped(G_OBJECT(media
->priv
->reject
), "activate",
292 G_CALLBACK(finch_media_reject_cb
), media
->priv
->media
);
293 g_signal_connect_swapped(G_OBJECT(media
->priv
->hangup
), "activate",
294 G_CALLBACK(finch_media_hangup_cb
), media
->priv
->media
);
296 if (purple_media_is_initiator(media
->priv
->media
,
297 NULL
, NULL
) == TRUE
) {
298 finch_media_wait_cb(media
->priv
->media
, media
);
300 g_signal_connect(G_OBJECT(media
->priv
->media
), "state-changed",
301 G_CALLBACK(finch_media_state_changed_cb
), media
);
302 g_signal_connect(G_OBJECT(media
->priv
->media
), "stream-info",
303 G_CALLBACK(finch_media_stream_info_cb
), media
);
307 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
313 finch_media_get_property (GObject
*object
, guint prop_id
, GValue
*value
, GParamSpec
*pspec
)
316 g_return_if_fail(FINCH_IS_MEDIA(object
));
318 media
= FINCH_MEDIA(object
);
322 g_value_set_object(value
, media
->priv
->media
);
325 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
331 finch_media_new(PurpleMedia
*media
)
333 return GNT_WIDGET(g_object_new(finch_media_get_type(),
336 "homogeneous", FALSE
,
341 gntmedia_message_cb(FinchMedia
*gntmedia
, const char *msg
, PurpleConversation
*conv
)
343 if (PURPLE_IS_IM_CONVERSATION(conv
)) {
344 purple_conversation_write_system_message(conv
, msg
, 0);
349 finch_new_media(PurpleMediaManager
*manager
, PurpleMedia
*media
,
350 PurpleAccount
*account
, gchar
*name
, gpointer null
)
353 PurpleConversation
*conv
;
355 conv
= PURPLE_CONVERSATION(purple_im_conversation_new(account
, name
));
357 gntmedia
= finch_media_new(media
);
358 g_signal_connect(G_OBJECT(gntmedia
), "message", G_CALLBACK(gntmedia_message_cb
), conv
);
359 FINCH_MEDIA(gntmedia
)->priv
->conv
= conv
;
360 finch_conversation_set_info_widget(conv
, gntmedia
);
365 call_cmd_cb(PurpleConversation
*conv
, const char *cmd
, char **args
,
366 char **eror
, gpointer data
)
368 PurpleAccount
*account
= purple_conversation_get_account(conv
);
370 if (!purple_protocol_initiate_media(account
,
371 purple_conversation_get_name(conv
),
373 return PURPLE_CMD_RET_FAILED
;
375 return PURPLE_CMD_RET_OK
;
380 void finch_media_manager_init(void)
383 PurpleMediaManager
*manager
= purple_media_manager_get();
384 PurpleMediaElementInfo
*audio_src
= NULL
;
385 PurpleMediaElementInfo
*audio_sink
= NULL
;
388 pref
= purple_prefs_get_string(
389 FINCH_PREFS_ROOT
"/vvconfig/audio/src/device");
391 audio_src
= purple_media_manager_get_element_info(manager
, pref
);
393 pref
= "autoaudiosrc";
394 purple_prefs_set_string(
395 FINCH_PREFS_ROOT
"/vvconfig/audio/src/device", pref
);
396 audio_src
= purple_media_manager_get_element_info(manager
,
400 pref
= purple_prefs_get_string(
401 FINCH_PREFS_ROOT
"/vvconfig/audio/sink/device");
403 audio_sink
= purple_media_manager_get_element_info(manager
, pref
);
405 pref
= "autoaudiosink";
406 purple_prefs_set_string(
407 FINCH_PREFS_ROOT
"/vvconfig/audio/sink/device", pref
);
408 audio_sink
= purple_media_manager_get_element_info(manager
,
412 g_signal_connect(G_OBJECT(manager
), "init-media", G_CALLBACK(finch_new_media
), NULL
);
413 purple_cmd_register("call", "", PURPLE_CMD_P_DEFAULT
,
414 PURPLE_CMD_FLAG_IM
, NULL
,
415 call_cmd_cb
, _("call: Make an audio call."), NULL
);
417 purple_media_manager_set_ui_caps(manager
,
418 PURPLE_MEDIA_CAPS_AUDIO
|
419 PURPLE_MEDIA_CAPS_AUDIO_SINGLE_DIRECTION
);
421 purple_debug_info("gntmedia", "Registering media element types\n");
422 purple_media_manager_set_active_element(manager
, audio_src
);
423 purple_media_manager_set_active_element(manager
, audio_sink
);
427 void finch_media_manager_uninit(void)
430 PurpleMediaManager
*manager
= purple_media_manager_get();
431 g_signal_handlers_disconnect_by_func(G_OBJECT(manager
),
432 G_CALLBACK(finch_new_media
), NULL
);