| |
1 /** |
| |
2 * @file media.c Account API |
| |
3 * @ingroup core |
| |
4 * |
| |
5 * Pidgin |
| |
6 * |
| |
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 |
| |
9 * source distribution. |
| |
10 * |
| |
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. |
| |
15 * |
| |
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. |
| |
20 * |
| |
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| |
24 */ |
| |
25 |
| |
26 #include <string.h> |
| |
27 #include "internal.h" |
| |
28 #include "connection.h" |
| |
29 #include "media.h" |
| |
30 |
| |
31 #include "gtkmedia.h" |
| |
32 |
| |
33 #ifdef USE_FARSIGHT |
| |
34 |
| |
35 #include <farsight/farsight.h> |
| |
36 |
| |
37 struct _PidginMediaPrivate |
| |
38 { |
| |
39 PurpleMedia *media; |
| |
40 GstElement *send_level; |
| |
41 GstElement *recv_level; |
| |
42 |
| |
43 GtkWidget *accept; |
| |
44 GtkWidget *reject; |
| |
45 GtkWidget *hangup; |
| |
46 |
| |
47 GtkWidget *send_progress; |
| |
48 GtkWidget *recv_progress; |
| |
49 }; |
| |
50 |
| |
51 #define PIDGIN_MEDIA_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), PIDGIN_TYPE_MEDIA, PidginMediaPrivate)) |
| |
52 |
| |
53 static void pidgin_media_class_init (PidginMediaClass *klass); |
| |
54 static void pidgin_media_init (PidginMedia *media); |
| |
55 static void pidgin_media_finalize (GObject *object); |
| |
56 static void pidgin_media_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); |
| |
57 static void pidgin_media_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); |
| |
58 |
| |
59 static GtkHBoxClass *parent_class = NULL; |
| |
60 |
| |
61 |
| |
62 |
| |
63 enum { |
| |
64 MESSAGE, |
| |
65 LAST_SIGNAL |
| |
66 }; |
| |
67 static guint pidgin_media_signals[LAST_SIGNAL] = {0}; |
| |
68 |
| |
69 enum { |
| |
70 PROP_0, |
| |
71 PROP_MEDIA, |
| |
72 PROP_SEND_LEVEL, |
| |
73 PROP_RECV_LEVEL |
| |
74 }; |
| |
75 |
| |
76 GType |
| |
77 pidgin_media_get_type() |
| |
78 { |
| |
79 static GType type = 0; |
| |
80 |
| |
81 if (type == 0) { |
| |
82 static const GTypeInfo info = { |
| |
83 sizeof(PidginMediaClass), |
| |
84 NULL, |
| |
85 NULL, |
| |
86 (GClassInitFunc) pidgin_media_class_init, |
| |
87 NULL, |
| |
88 NULL, |
| |
89 sizeof(PidginMedia), |
| |
90 0, |
| |
91 (GInstanceInitFunc) pidgin_media_init |
| |
92 }; |
| |
93 type = g_type_register_static(GTK_TYPE_HBOX, "PidginMedia", &info, 0); |
| |
94 } |
| |
95 return type; |
| |
96 } |
| |
97 |
| |
98 |
| |
99 static void |
| |
100 pidgin_media_class_init (PidginMediaClass *klass) |
| |
101 { |
| |
102 GObjectClass *gobject_class = (GObjectClass*)klass; |
| |
103 GtkContainerClass *container_class = (GtkContainerClass*)klass; |
| |
104 parent_class = g_type_class_peek_parent(klass); |
| |
105 |
| |
106 gobject_class->finalize = pidgin_media_finalize; |
| |
107 gobject_class->set_property = pidgin_media_set_property; |
| |
108 gobject_class->get_property = pidgin_media_get_property; |
| |
109 |
| |
110 g_object_class_install_property(gobject_class, PROP_MEDIA, |
| |
111 g_param_spec_object("media", |
| |
112 "PurpleMedia", |
| |
113 "The PurpleMedia associated with this media.", |
| |
114 PURPLE_TYPE_MEDIA, |
| |
115 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); |
| |
116 g_object_class_install_property(gobject_class, PROP_SEND_LEVEL, |
| |
117 g_param_spec_object("send-level", |
| |
118 "Send level", |
| |
119 "The GstElement of this media's send 'level'", |
| |
120 GST_TYPE_ELEMENT, |
| |
121 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); |
| |
122 g_object_class_install_property(gobject_class, PROP_RECV_LEVEL, |
| |
123 g_param_spec_object("recv-level", |
| |
124 "Receive level", |
| |
125 "The GstElement of this media's recv 'level'", |
| |
126 GST_TYPE_ELEMENT, |
| |
127 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); |
| |
128 |
| |
129 pidgin_media_signals[MESSAGE] = g_signal_new("message", G_TYPE_FROM_CLASS(klass), |
| |
130 G_SIGNAL_RUN_LAST, 0, NULL, NULL, |
| |
131 g_cclosure_marshal_VOID__STRING, |
| |
132 G_TYPE_NONE, 1, G_TYPE_STRING); |
| |
133 |
| |
134 g_type_class_add_private(klass, sizeof(PidginMediaPrivate)); |
| |
135 } |
| |
136 |
| |
137 |
| |
138 static void |
| |
139 pidgin_media_init (PidginMedia *media) |
| |
140 { |
| |
141 media->priv = PIDGIN_MEDIA_GET_PRIVATE(media); |
| |
142 media->priv->hangup = gtk_button_new_with_label("Hangup"); |
| |
143 media->priv->accept = gtk_button_new_with_label("Accept"); |
| |
144 media->priv->reject = gtk_button_new_with_label("Reject"); |
| |
145 media->priv->send_progress = gtk_progress_bar_new(); |
| |
146 media->priv->recv_progress = gtk_progress_bar_new(); |
| |
147 |
| |
148 gtk_widget_set_size_request(media->priv->send_progress, 70, 5); |
| |
149 gtk_widget_set_size_request(media->priv->recv_progress, 70, 5); |
| |
150 |
| |
151 gtk_box_pack_start(GTK_BOX(media), media->priv->hangup, FALSE, FALSE, 0); |
| |
152 gtk_box_pack_start(GTK_BOX(media), media->priv->accept, FALSE, FALSE, 0); |
| |
153 gtk_box_pack_start(GTK_BOX(media), media->priv->reject, FALSE, FALSE, 0); |
| |
154 |
| |
155 gtk_box_pack_start(GTK_BOX(media), media->priv->send_progress, FALSE, FALSE, 6); |
| |
156 gtk_box_pack_start(GTK_BOX(media), media->priv->recv_progress, FALSE, FALSE, 6); |
| |
157 |
| |
158 gtk_widget_show(media->priv->send_progress); |
| |
159 gtk_widget_show(media->priv->recv_progress); |
| |
160 gtk_widget_show_all(media->priv->accept); |
| |
161 gtk_widget_show_all(media->priv->reject); |
| |
162 } |
| |
163 |
| |
164 static void |
| |
165 pidgin_media_finalize (GObject *media) |
| |
166 { |
| |
167 } |
| |
168 |
| |
169 static void |
| |
170 pidgin_media_emit_message(PidginMedia *gtkmedia, const char *msg) |
| |
171 { |
| |
172 g_signal_emit(gtkmedia, pidgin_media_signals[MESSAGE], 0, msg); |
| |
173 } |
| |
174 |
| |
175 static gboolean |
| |
176 level_message_cb(GstBus *bus, GstMessage *message, PidginMedia *gtkmedia) |
| |
177 { |
| |
178 const GstStructure *s; |
| |
179 const gchar *name; |
| |
180 |
| |
181 int channels; |
| |
182 gdouble rms_db, peak_db, decay_db; |
| |
183 gdouble rms; |
| |
184 const GValue *list; |
| |
185 const GValue *value; |
| |
186 |
| |
187 GstElement *src = GST_MESSAGE_SRC(message); |
| |
188 |
| |
189 if (message->type != GST_MESSAGE_ELEMENT) |
| |
190 return TRUE; |
| |
191 |
| |
192 s = gst_message_get_structure(message); |
| |
193 name = gst_structure_get_name(s); |
| |
194 |
| |
195 if (strcmp(name, "level")) |
| |
196 return TRUE; |
| |
197 |
| |
198 list = gst_structure_get_value(s, "rms"); |
| |
199 |
| |
200 /* Only bother with the first channel. */ |
| |
201 value = gst_value_list_get_value(list, 0); |
| |
202 rms_db = g_value_get_double(value); |
| |
203 |
| |
204 if (!strcmp(gst_element_get_name(src), "sendlevel")) |
| |
205 gtk_progress_bar_set_fraction(gtkmedia->priv->send_progress, pow(10, rms_db / 20) * 5); |
| |
206 else |
| |
207 gtk_progress_bar_set_fraction(gtkmedia->priv->recv_progress, pow(10, rms_db / 20) * 5); |
| |
208 |
| |
209 return TRUE; |
| |
210 } |
| |
211 |
| |
212 static void |
| |
213 pidgin_media_ready_cb(PurpleMedia *media, PidginMedia *gtkmedia) |
| |
214 { |
| |
215 GstElement *element = purple_media_get_audio_pipeline(media); |
| |
216 gst_bus_add_signal_watch(gst_pipeline_get_bus(element)); |
| |
217 g_signal_connect(G_OBJECT(gst_pipeline_get_bus(GST_PIPELINE(element))), "message", level_message_cb, gtkmedia); |
| |
218 printf("\n\nbus: %d\n", gst_pipeline_get_bus(GST_PIPELINE(element))); |
| |
219 } |
| |
220 |
| |
221 static void |
| |
222 pidgin_media_accept_cb(PurpleMedia *media, PidginMedia *gtkmedia) |
| |
223 { |
| |
224 pidgin_media_emit_message(gtkmedia, _("Call in progress.")); |
| |
225 gtk_widget_show(gtkmedia->priv->hangup); |
| |
226 gtk_widget_hide(gtkmedia->priv->accept); |
| |
227 gtk_widget_hide(gtkmedia->priv->reject); |
| |
228 } |
| |
229 |
| |
230 static void |
| |
231 pidgin_media_hangup_cb(PurpleMedia *media, PidginMedia *gtkmedia) |
| |
232 { |
| |
233 pidgin_media_emit_message(gtkmedia, _("You have ended the call.")); |
| |
234 gtk_widget_destroy(gtkmedia); |
| |
235 } |
| |
236 |
| |
237 static void |
| |
238 pidgin_media_reject_cb(PurpleMedia *media, PidginMedia *gtkmedia) |
| |
239 { |
| |
240 pidgin_media_emit_message(gtkmedia, _("You have rejected the call.")); |
| |
241 gtk_widget_destroy(gtkmedia); |
| |
242 } |
| |
243 |
| |
244 static void |
| |
245 pidgin_media_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) |
| |
246 { |
| |
247 PidginMedia *media; |
| |
248 g_return_if_fail(PIDGIN_IS_MEDIA(object)); |
| |
249 |
| |
250 media = PIDGIN_MEDIA(object); |
| |
251 switch (prop_id) { |
| |
252 case PROP_MEDIA: |
| |
253 if (media->priv->media) |
| |
254 g_object_unref(media->priv->media); |
| |
255 media->priv->media = g_value_get_object(value); |
| |
256 g_object_ref(media->priv->media); |
| |
257 g_signal_connect_swapped(G_OBJECT(media->priv->accept), "clicked", |
| |
258 G_CALLBACK(purple_media_accept), media->priv->media); |
| |
259 g_signal_connect_swapped(G_OBJECT(media->priv->reject), "clicked", |
| |
260 G_CALLBACK(purple_media_reject), media->priv->media); |
| |
261 g_signal_connect_swapped(G_OBJECT(media->priv->hangup), "clicked", |
| |
262 G_CALLBACK(purple_media_hangup), media->priv->media); |
| |
263 |
| |
264 g_signal_connect(G_OBJECT(media->priv->media), "accepted", |
| |
265 G_CALLBACK(pidgin_media_accept_cb), media); |
| |
266 g_signal_connect(G_OBJECT(media->priv->media) ,"ready", |
| |
267 G_CALLBACK(pidgin_media_ready_cb), media); |
| |
268 g_signal_connect(G_OBJECT(media->priv->media), "hangup", |
| |
269 G_CALLBACK(pidgin_media_hangup_cb), media); |
| |
270 g_signal_connect(G_OBJECT(media->priv->media), "reject", |
| |
271 G_CALLBACK(pidgin_media_reject_cb), media); |
| |
272 break; |
| |
273 case PROP_SEND_LEVEL: |
| |
274 if (media->priv->send_level) |
| |
275 gst_object_unref(media->priv->send_level); |
| |
276 media->priv->send_level = g_value_get_object(value); |
| |
277 g_object_ref(media->priv->send_level); |
| |
278 break; |
| |
279 case PROP_RECV_LEVEL: |
| |
280 if (media->priv->recv_level) |
| |
281 gst_object_unref(media->priv->recv_level); |
| |
282 media->priv->recv_level = g_value_get_object(value); |
| |
283 g_object_ref(media->priv->recv_level); |
| |
284 break; |
| |
285 default: |
| |
286 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
| |
287 break; |
| |
288 } |
| |
289 } |
| |
290 |
| |
291 static void |
| |
292 pidgin_media_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) |
| |
293 { |
| |
294 PidginMedia *media; |
| |
295 g_return_if_fail(PIDGIN_IS_MEDIA(object)); |
| |
296 |
| |
297 media = PIDGIN_MEDIA(object); |
| |
298 |
| |
299 switch (prop_id) { |
| |
300 case PROP_MEDIA: |
| |
301 g_value_set_object(value, media->priv->media); |
| |
302 break; |
| |
303 case PROP_SEND_LEVEL: |
| |
304 g_value_set_object(value, media->priv->send_level); |
| |
305 break; |
| |
306 case PROP_RECV_LEVEL: |
| |
307 g_value_set_object(value, media->priv->recv_level); |
| |
308 break; |
| |
309 default: |
| |
310 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
| |
311 break; |
| |
312 } |
| |
313 } |
| |
314 |
| |
315 GtkWidget * |
| |
316 pidgin_media_new(PurpleMedia *media, GstElement *sendlevel, GstElement *recvlevel) |
| |
317 { |
| |
318 return GTK_WIDGET(g_object_new(pidgin_media_get_type(), "media", media, "send-level", sendlevel, "recv-level", recvlevel, NULL)); |
| |
319 } |
| |
320 |
| |
321 #endif /* USE_FARSIGHT */ |