Mercurial > pidgin.yaz
comparison finch/gntmedia.c @ 25639:128f6cb57829
Some media support in finch. This needs to be updated for the got-accept signal.
author | Sadrul Habib Chowdhury <imadil@gmail.com> |
---|---|
date | Sat, 22 Mar 2008 04:51:58 +0000 |
parents | |
children | befeece4dd48 |
comparison
equal
deleted
inserted
replaced
25638:9f36ed35615e | 25639:128f6cb57829 |
---|---|
1 /** | |
2 * @file gntmedia.c GNT Media API | |
3 * @ingroup finch | |
4 */ | |
5 | |
6 /* finch | |
7 * | |
8 * Finch 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA | |
25 */ | |
26 | |
27 #include "finch.h" | |
28 #include "mediamanager.h" | |
29 | |
30 #include "gntconv.h" | |
31 #include "gntmedia.h" | |
32 | |
33 #include "gnt.h" | |
34 #include "gntbutton.h" | |
35 #include "gntbox.h" | |
36 | |
37 #include "cmds.h" | |
38 #include "conversation.h" | |
39 #include "debug.h" | |
40 | |
41 /* An incredibly large part of the following is from gtkmedia.c */ | |
42 #ifdef USE_FARSIGHT | |
43 | |
44 #include <farsight/farsight.h> | |
45 | |
46 #undef hangup | |
47 | |
48 struct _FinchMediaPrivate | |
49 { | |
50 PurpleMedia *media; | |
51 GstElement *send_level; | |
52 GstElement *recv_level; | |
53 | |
54 GntWidget *accept; | |
55 GntWidget *reject; | |
56 GntWidget *hangup; | |
57 | |
58 PurpleConversation *conv; | |
59 }; | |
60 | |
61 #define FINCH_MEDIA_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), FINCH_TYPE_MEDIA, FinchMediaPrivate)) | |
62 | |
63 static void finch_media_class_init (FinchMediaClass *klass); | |
64 static void finch_media_init (FinchMedia *media); | |
65 static void finch_media_finalize (GObject *object); | |
66 static void finch_media_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); | |
67 static void finch_media_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); | |
68 | |
69 static GntBoxClass *parent_class = NULL; | |
70 | |
71 enum { | |
72 MESSAGE, | |
73 LAST_SIGNAL | |
74 }; | |
75 static guint finch_media_signals[LAST_SIGNAL] = {0}; | |
76 | |
77 enum { | |
78 PROP_0, | |
79 PROP_MEDIA, | |
80 PROP_SEND_LEVEL, | |
81 PROP_RECV_LEVEL | |
82 }; | |
83 | |
84 GType | |
85 finch_media_get_type(void) | |
86 { | |
87 static GType type = 0; | |
88 | |
89 if (type == 0) { | |
90 static const GTypeInfo info = { | |
91 sizeof(FinchMediaClass), | |
92 NULL, | |
93 NULL, | |
94 (GClassInitFunc) finch_media_class_init, | |
95 NULL, | |
96 NULL, | |
97 sizeof(FinchMedia), | |
98 0, | |
99 (GInstanceInitFunc) finch_media_init, | |
100 NULL | |
101 }; | |
102 type = g_type_register_static(GNT_TYPE_BOX, "FinchMedia", &info, 0); | |
103 } | |
104 return type; | |
105 } | |
106 | |
107 | |
108 static void | |
109 finch_media_class_init (FinchMediaClass *klass) | |
110 { | |
111 GObjectClass *gobject_class = (GObjectClass*)klass; | |
112 parent_class = g_type_class_peek_parent(klass); | |
113 | |
114 gobject_class->finalize = finch_media_finalize; | |
115 gobject_class->set_property = finch_media_set_property; | |
116 gobject_class->get_property = finch_media_get_property; | |
117 | |
118 g_object_class_install_property(gobject_class, PROP_MEDIA, | |
119 g_param_spec_object("media", | |
120 "PurpleMedia", | |
121 "The PurpleMedia associated with this media.", | |
122 PURPLE_TYPE_MEDIA, | |
123 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); | |
124 g_object_class_install_property(gobject_class, PROP_SEND_LEVEL, | |
125 g_param_spec_object("send-level", | |
126 "Send level", | |
127 "The GstElement of this media's send 'level'", | |
128 GST_TYPE_ELEMENT, | |
129 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); | |
130 g_object_class_install_property(gobject_class, PROP_RECV_LEVEL, | |
131 g_param_spec_object("recv-level", | |
132 "Receive level", | |
133 "The GstElement of this media's recv 'level'", | |
134 GST_TYPE_ELEMENT, | |
135 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); | |
136 | |
137 finch_media_signals[MESSAGE] = g_signal_new("message", G_TYPE_FROM_CLASS(klass), | |
138 G_SIGNAL_RUN_LAST, 0, NULL, NULL, | |
139 g_cclosure_marshal_VOID__STRING, | |
140 G_TYPE_NONE, 1, G_TYPE_STRING); | |
141 | |
142 g_type_class_add_private(klass, sizeof(FinchMediaPrivate)); | |
143 } | |
144 | |
145 | |
146 static void | |
147 finch_media_init (FinchMedia *media) | |
148 { | |
149 media->priv = FINCH_MEDIA_GET_PRIVATE(media); | |
150 | |
151 media->priv->hangup = gnt_button_new("Hangup"); | |
152 media->priv->accept = gnt_button_new("Accept"); | |
153 media->priv->reject = gnt_button_new("Reject"); | |
154 | |
155 gnt_box_set_alignment(GNT_BOX(media), GNT_ALIGN_MID); | |
156 | |
157 gnt_box_add_widget(GNT_BOX(media), media->priv->accept); | |
158 gnt_box_add_widget(GNT_BOX(media), media->priv->reject); | |
159 } | |
160 | |
161 static void | |
162 finch_media_finalize (GObject *media) | |
163 { | |
164 } | |
165 | |
166 static void | |
167 finch_media_emit_message(FinchMedia *gntmedia, const char *msg) | |
168 { | |
169 g_signal_emit(gntmedia, finch_media_signals[MESSAGE], 0, msg); | |
170 } | |
171 | |
172 static gboolean | |
173 level_message_cb(GstBus *bus, GstMessage *message, FinchMedia *gntmedia) | |
174 { | |
175 /* XXX: I am hesitant to just remove this function altogether, because I don't | |
176 * know how necessary it is to have a callback to 'message'. If it isn't essential, | |
177 * I suppose this should be removed. | |
178 */ | |
179 return TRUE; | |
180 #if 0 | |
181 const GstStructure *s; | |
182 const gchar *name; | |
183 | |
184 int channels; | |
185 gdouble rms_db, peak_db, decay_db; | |
186 gdouble rms; | |
187 const GValue *list; | |
188 const GValue *value; | |
189 | |
190 GstElement *src = GST_ELEMENT(message); | |
191 | |
192 if (message->type != GST_MESSAGE_ELEMENT) | |
193 return TRUE; | |
194 | |
195 s = gst_message_get_structure(message); | |
196 name = gst_structure_get_name(s); | |
197 | |
198 if (strcmp(name, "level")) | |
199 return TRUE; | |
200 | |
201 list = gst_structure_get_value(s, "rms"); | |
202 | |
203 /* Only bother with the first channel. */ | |
204 value = gst_value_list_get_value(list, 0); | |
205 rms_db = g_value_get_double(value); | |
206 | |
207 if (!strcmp(gst_element_get_name(src), "sendlevel")) | |
208 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(gntmedia->priv->send_progress), pow(10, rms_db / 20) * 5); | |
209 else | |
210 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(gntmedia->priv->recv_progress), pow(10, rms_db / 20) * 5); | |
211 | |
212 return TRUE; | |
213 #endif | |
214 } | |
215 | |
216 static void | |
217 finch_media_ready_cb(PurpleMedia *media, FinchMedia *gntmedia) | |
218 { | |
219 GstElement *element = purple_media_get_audio_pipeline(media); | |
220 gst_bus_add_signal_watch(GST_BUS(gst_pipeline_get_bus(GST_PIPELINE(element)))); | |
221 g_signal_connect(G_OBJECT(gst_pipeline_get_bus(GST_PIPELINE(element))), "message", G_CALLBACK(level_message_cb), gntmedia); | |
222 } | |
223 | |
224 static void | |
225 finch_media_accept_cb(PurpleMedia *media, FinchMedia *gntmedia) | |
226 { | |
227 GntWidget *parent; | |
228 | |
229 finch_media_emit_message(gntmedia, _("Call in progress.")); | |
230 | |
231 gnt_box_remove(GNT_BOX(gntmedia), gntmedia->priv->accept); | |
232 gnt_box_remove(GNT_BOX(gntmedia), gntmedia->priv->reject); | |
233 gnt_box_add_widget(GNT_BOX(gntmedia), gntmedia->priv->hangup); | |
234 | |
235 gnt_widget_destroy(gntmedia->priv->accept); | |
236 gnt_widget_destroy(gntmedia->priv->reject); | |
237 gntmedia->priv->accept = NULL; | |
238 gntmedia->priv->reject = NULL; | |
239 | |
240 parent = GNT_WIDGET(gntmedia); | |
241 while (parent->parent) | |
242 parent = parent->parent; | |
243 gnt_box_readjust(GNT_BOX(parent)); | |
244 gnt_widget_draw(parent); | |
245 } | |
246 | |
247 static void | |
248 finch_media_hangup_cb(PurpleMedia *media, FinchMedia *gntmedia) | |
249 { | |
250 finch_media_emit_message(gntmedia, _("You have ended the call.")); | |
251 finch_conversation_set_info_widget(gntmedia->priv->conv, NULL); | |
252 gnt_widget_destroy(GNT_WIDGET(gntmedia)); | |
253 } | |
254 | |
255 static void | |
256 finch_media_got_hangup_cb(PurpleMedia *media, FinchMedia *gntmedia) | |
257 { | |
258 finch_media_emit_message(gntmedia, _("The call has been terminated.")); | |
259 finch_conversation_set_info_widget(gntmedia->priv->conv, NULL); | |
260 gnt_widget_destroy(GNT_WIDGET(gntmedia)); | |
261 } | |
262 | |
263 static void | |
264 finch_media_reject_cb(PurpleMedia *media, FinchMedia *gntmedia) | |
265 { | |
266 finch_media_emit_message(gntmedia, _("You have rejected the call.")); | |
267 finch_conversation_set_info_widget(gntmedia->priv->conv, NULL); | |
268 gnt_widget_destroy(GNT_WIDGET(gntmedia)); | |
269 } | |
270 | |
271 static void | |
272 finch_media_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) | |
273 { | |
274 FinchMedia *media; | |
275 g_return_if_fail(FINCH_IS_MEDIA(object)); | |
276 | |
277 media = FINCH_MEDIA(object); | |
278 switch (prop_id) { | |
279 case PROP_MEDIA: | |
280 if (media->priv->media) | |
281 g_object_unref(media->priv->media); | |
282 media->priv->media = g_value_get_object(value); | |
283 g_object_ref(media->priv->media); | |
284 g_signal_connect_swapped(G_OBJECT(media->priv->accept), "activate", | |
285 G_CALLBACK(purple_media_accept), media->priv->media); | |
286 g_signal_connect_swapped(G_OBJECT(media->priv->reject), "activate", | |
287 G_CALLBACK(purple_media_reject), media->priv->media); | |
288 g_signal_connect_swapped(G_OBJECT(media->priv->hangup), "activate", | |
289 G_CALLBACK(purple_media_hangup), media->priv->media); | |
290 | |
291 g_signal_connect(G_OBJECT(media->priv->media), "accepted", | |
292 G_CALLBACK(finch_media_accept_cb), media); | |
293 g_signal_connect(G_OBJECT(media->priv->media) ,"ready", | |
294 G_CALLBACK(finch_media_ready_cb), media); | |
295 g_signal_connect(G_OBJECT(media->priv->media), "hangup", | |
296 G_CALLBACK(finch_media_hangup_cb), media); | |
297 g_signal_connect(G_OBJECT(media->priv->media), "reject", | |
298 G_CALLBACK(finch_media_reject_cb), media); | |
299 g_signal_connect(G_OBJECT(media->priv->media), "got-hangup", | |
300 G_CALLBACK(finch_media_got_hangup_cb), media); | |
301 break; | |
302 case PROP_SEND_LEVEL: | |
303 if (media->priv->send_level) | |
304 gst_object_unref(media->priv->send_level); | |
305 media->priv->send_level = g_value_get_object(value); | |
306 g_object_ref(media->priv->send_level); | |
307 break; | |
308 case PROP_RECV_LEVEL: | |
309 if (media->priv->recv_level) | |
310 gst_object_unref(media->priv->recv_level); | |
311 media->priv->recv_level = g_value_get_object(value); | |
312 g_object_ref(media->priv->recv_level); | |
313 break; | |
314 default: | |
315 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); | |
316 break; | |
317 } | |
318 } | |
319 | |
320 static void | |
321 finch_media_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) | |
322 { | |
323 FinchMedia *media; | |
324 g_return_if_fail(FINCH_IS_MEDIA(object)); | |
325 | |
326 media = FINCH_MEDIA(object); | |
327 | |
328 switch (prop_id) { | |
329 case PROP_MEDIA: | |
330 g_value_set_object(value, media->priv->media); | |
331 break; | |
332 case PROP_SEND_LEVEL: | |
333 g_value_set_object(value, media->priv->send_level); | |
334 break; | |
335 case PROP_RECV_LEVEL: | |
336 g_value_set_object(value, media->priv->recv_level); | |
337 break; | |
338 default: | |
339 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); | |
340 break; | |
341 } | |
342 } | |
343 | |
344 GntWidget * | |
345 finch_media_new(PurpleMedia *media, GstElement *sendlevel, GstElement *recvlevel) | |
346 { | |
347 return GNT_WIDGET(g_object_new(finch_media_get_type(), | |
348 "media", media, | |
349 "send-level", sendlevel, | |
350 "recv-level", recvlevel, | |
351 "vertical", FALSE, | |
352 "homogeneous", FALSE, | |
353 NULL)); | |
354 } | |
355 | |
356 #endif /* USE_FARSIGHT */ | |
357 | |
358 static void | |
359 gntmedia_message_cb(FinchMedia *gntmedia, const char *msg, PurpleConversation *conv) | |
360 { | |
361 if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) { | |
362 purple_conv_im_write(PURPLE_CONV_IM(conv), NULL, msg, PURPLE_MESSAGE_SYSTEM, time(NULL)); | |
363 } | |
364 } | |
365 | |
366 static void | |
367 finch_new_media(PurpleMediaManager *manager, PurpleMedia *media, gpointer null) | |
368 { | |
369 GstElement *sendbin, *sendlevel; | |
370 GstElement *recvbin, *recvlevel; | |
371 GntWidget *gntmedia; | |
372 PurpleConversation *conv; | |
373 | |
374 purple_media_audio_init_src(&sendbin, &sendlevel); | |
375 purple_media_audio_init_recv(&recvbin, &recvlevel); | |
376 | |
377 purple_media_set_audio_src(media, sendbin); | |
378 purple_media_set_audio_sink(media, recvbin); | |
379 | |
380 conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, | |
381 purple_connection_get_account(purple_media_get_connection(media)), | |
382 purple_media_get_screenname(media)); | |
383 | |
384 gntmedia = finch_media_new(media, sendlevel, recvlevel); | |
385 g_signal_connect(G_OBJECT(gntmedia), "message", G_CALLBACK(gntmedia_message_cb), conv); | |
386 FINCH_MEDIA(gntmedia)->priv->conv = conv; | |
387 finch_conversation_set_info_widget(conv, gntmedia); | |
388 } | |
389 | |
390 static PurpleCmdRet | |
391 call_cmd_cb(PurpleConversation *conv, const char *cmd, char **args, | |
392 char **eror, gpointer data) | |
393 { | |
394 PurpleConnection *gc = purple_conversation_get_gc(conv); | |
395 | |
396 PurpleMedia *media = | |
397 serv_initiate_media(gc, | |
398 purple_conversation_get_name(conv), | |
399 PURPLE_MEDIA_RECV_AUDIO & PURPLE_MEDIA_SEND_AUDIO); | |
400 | |
401 if (!media) | |
402 return PURPLE_CMD_STATUS_FAILED; | |
403 | |
404 purple_media_accept(media); | |
405 return PURPLE_CMD_STATUS_OK; | |
406 } | |
407 | |
408 void finch_media_manager_init(void) | |
409 { | |
410 PurpleMediaManager *manager = purple_media_manager_get(); | |
411 g_signal_connect(G_OBJECT(manager), "init-media", G_CALLBACK(finch_new_media), NULL); | |
412 purple_cmd_register("call", "", PURPLE_CMD_P_DEFAULT, | |
413 PURPLE_CMD_FLAG_IM, NULL, | |
414 call_cmd_cb, _("call: Make an audio call."), NULL); | |
415 } | |
416 | |
417 void finch_media_manager_uninit(void) | |
418 { | |
419 PurpleMediaManager *manager = purple_media_manager_get(); | |
420 g_signal_handlers_disconnect_by_func(G_OBJECT(manager), | |
421 G_CALLBACK(finch_new_media), NULL); | |
422 } | |
423 |