|
1 /* |
|
2 * gabble-media-stream.c - Source for GabbleMediaStream |
|
3 * Copyright (C) 2006 Collabora Ltd. |
|
4 * |
|
5 * @author Ole Andre Vadla Ravnaas <ole.andre.ravnaas@collabora.co.uk> |
|
6 * |
|
7 * This library is free software; you can redistribute it and/or |
|
8 * modify it under the terms of the GNU Lesser General Public |
|
9 * License as published by the Free Software Foundation; either |
|
10 * version 2.1 of the License, or (at your option) any later version. |
|
11 * |
|
12 * This library 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 GNU |
|
15 * Lesser General Public License for more details. |
|
16 * |
|
17 * You should have received a copy of the GNU Lesser General Public |
|
18 * License along with this library; if not, write to the Free Software |
|
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
|
20 */ |
|
21 |
|
22 #include <dbus/dbus-glib.h> |
|
23 #include <stdio.h> |
|
24 #include <stdlib.h> |
|
25 #include <string.h> |
|
26 |
|
27 |
|
28 #include "ansi.h" |
|
29 #include "debug.h" |
|
30 #include "handles.h" |
|
31 #include "namespaces.h" |
|
32 |
|
33 #include "gabble-connection.h" |
|
34 #include "gabble-media-channel.h" |
|
35 #include "gabble-media-session.h" |
|
36 #include "gabble-media-session-enumtypes.h" |
|
37 |
|
38 #include "telepathy-helpers.h" |
|
39 #include "telepathy-constants.h" |
|
40 |
|
41 #include "gabble-media-stream.h" |
|
42 #include "gabble-media-stream-signals-marshal.h" |
|
43 #include "gabble-media-stream-glue.h" |
|
44 |
|
45 #include "gabble_enums.h" |
|
46 |
|
47 #ifndef EMULATOR |
|
48 G_DEFINE_TYPE(GabbleMediaStream, gabble_media_stream, G_TYPE_OBJECT) |
|
49 #endif |
|
50 |
|
51 #define DEBUG_FLAG GABBLE_DEBUG_MEDIA |
|
52 |
|
53 #ifdef DEBUG_FLAG |
|
54 //#define DEBUG(format, ...) |
|
55 #define DEBUGGING 0 |
|
56 //#define NODE_DEBUG(n, s) ; |
|
57 #endif /* DEBUG_FLAG */ |
|
58 |
|
59 /* signal enum */ |
|
60 enum |
|
61 { |
|
62 DESTROY, |
|
63 |
|
64 ADD_REMOTE_CANDIDATE, |
|
65 CLOSE, |
|
66 REMOVE_REMOTE_CANDIDATE, |
|
67 SET_ACTIVE_CANDIDATE_PAIR, |
|
68 SET_REMOTE_CANDIDATE_LIST, |
|
69 SET_REMOTE_CODECS, |
|
70 SET_STREAM_PLAYING, |
|
71 SET_STREAM_SENDING, |
|
72 |
|
73 NEW_ACTIVE_CANDIDATE_PAIR, |
|
74 NEW_NATIVE_CANDIDATE, |
|
75 SUPPORTED_CODECS, |
|
76 ERROR, |
|
77 |
|
78 LAST_SIGNAL |
|
79 #ifdef EMULATOR |
|
80 = LAST_SIGNAL_MED_STREAM |
|
81 #endif |
|
82 |
|
83 }; |
|
84 |
|
85 #ifdef EMULATOR |
|
86 #include "libgabble_wsd_solution.h" |
|
87 |
|
88 GET_STATIC_ARRAY_FROM_TLS(signals,gabble_med_stream,guint) |
|
89 #define signals (GET_WSD_VAR_NAME(signals,gabble_med_stream, s)()) |
|
90 |
|
91 GET_STATIC_VAR_FROM_TLS(gabble_media_stream_parent_class,gabble_med_stream,gpointer) |
|
92 #define gabble_media_stream_parent_class (*GET_WSD_VAR_NAME(gabble_media_stream_parent_class,gabble_med_stream,s)()) |
|
93 |
|
94 GET_STATIC_VAR_FROM_TLS(g_define_type_id,gabble_med_stream,GType) |
|
95 #define g_define_type_id (*GET_WSD_VAR_NAME(g_define_type_id,gabble_med_stream,s)()) |
|
96 |
|
97 /*gchar** _s_gabble_med_stream_video_codec_params() { return (gchar**)((libgabble_ImpurePtr()->_s_gabble_med_stream_video_codec_params)); } |
|
98 |
|
99 #define video_codec_params (GET_WSD_VAR_NAME(video_codec_params,gabble_med_stream, s)())*/ |
|
100 |
|
101 |
|
102 static void gabble_media_stream_init (GabbleMediaStream *self); |
|
103 static void gabble_media_stream_class_init (GabbleMediaStreamClass *klass); |
|
104 static void gabble_media_stream_class_intern_init (gpointer klass) |
|
105 { |
|
106 gabble_media_stream_parent_class = g_type_class_peek_parent (klass); |
|
107 gabble_media_stream_class_init ((GabbleMediaStreamClass*) klass); |
|
108 } |
|
109 EXPORT_C GType gabble_media_stream_get_type (void) |
|
110 { |
|
111 if ((g_define_type_id == 0)) |
|
112 { |
|
113 static const GTypeInfo g_define_type_info = { sizeof (GabbleMediaStreamClass), (GBaseInitFunc) ((void *)0), (GBaseFinalizeFunc) ((void *)0), (GClassInitFunc) gabble_media_stream_class_intern_init, (GClassFinalizeFunc) ((void *)0), ((void *)0), sizeof (GabbleMediaStream), 0, (GInstanceInitFunc) gabble_media_stream_init, ((void *)0) }; g_define_type_id = g_type_register_static ( ((GType) ((20) << (2))), g_intern_static_string ("GabbleMediaStream"), &g_define_type_info, (GTypeFlags) 0); { {} ; } } return g_define_type_id; |
|
114 }; |
|
115 |
|
116 |
|
117 #else |
|
118 |
|
119 static guint signals[LAST_SIGNAL] = {0}; |
|
120 |
|
121 #endif |
|
122 |
|
123 |
|
124 /* properties */ |
|
125 enum |
|
126 { |
|
127 PROP_CONNECTION = 1, |
|
128 PROP_MEDIA_SESSION, |
|
129 PROP_OBJECT_PATH, |
|
130 PROP_MODE, |
|
131 PROP_NAME, |
|
132 PROP_ID, |
|
133 PROP_INITIATOR, |
|
134 PROP_MEDIA_TYPE, |
|
135 PROP_CONNECTION_STATE, |
|
136 PROP_READY, |
|
137 PROP_GOT_LOCAL_CODECS, |
|
138 PROP_SIGNALLING_STATE, |
|
139 PROP_PLAYING, |
|
140 PROP_COMBINED_DIRECTION, |
|
141 LAST_PROPERTY |
|
142 }; |
|
143 |
|
144 /* private structure */ |
|
145 typedef struct _GabbleMediaStreamPrivate GabbleMediaStreamPrivate; |
|
146 |
|
147 struct _GabbleMediaStreamPrivate |
|
148 { |
|
149 GabbleConnection *conn; |
|
150 GabbleMediaSession *session; |
|
151 GabbleMediaSessionMode mode; |
|
152 gchar *object_path; |
|
153 guint id; |
|
154 guint media_type; |
|
155 |
|
156 gboolean ready; |
|
157 gboolean sending; |
|
158 |
|
159 GValue native_codecs; /* intersected codec list */ |
|
160 GValue native_candidates; |
|
161 |
|
162 GValue remote_codecs; |
|
163 GValue remote_candidates; |
|
164 |
|
165 guint remote_candidate_count; |
|
166 |
|
167 gboolean closed; |
|
168 gboolean dispose_has_run; |
|
169 }; |
|
170 |
|
171 #define GABBLE_MEDIA_STREAM_GET_PRIVATE(obj) \ |
|
172 ((GabbleMediaStreamPrivate *)obj->priv) |
|
173 //Vinod: add below definition |
|
174 #define ENABLE_DEBUG |
|
175 |
|
176 #ifdef ENABLE_DEBUG |
|
177 #if _GMS_DEBUG_LEVEL > 1 |
|
178 static const char *tp_protocols[] = { |
|
179 "TP_MEDIA_STREAM_PROTO_UDP (0)", |
|
180 "TP_MEDIA_STREAM_PROTO_TCP (1)" |
|
181 }; |
|
182 |
|
183 static const char *tp_transports[] = { |
|
184 "TP_MEDIA_STREAM_TRANSPORT_TYPE_LOCAL (0)", |
|
185 "TP_MEDIA_STREAM_TRANSPORT_TYPE_DERIVED (1)", |
|
186 "TP_MEDIA_STREAM_TRANSPORT_TYPE_RELAY (2)" |
|
187 }; |
|
188 #endif |
|
189 #endif |
|
190 |
|
191 static void push_native_candidates (GabbleMediaStream *stream); |
|
192 static void push_remote_codecs (GabbleMediaStream *stream); |
|
193 static void push_remote_candidates (GabbleMediaStream *stream); |
|
194 static void push_playing (GabbleMediaStream *stream); |
|
195 static void push_sending (GabbleMediaStream *stream); |
|
196 |
|
197 static void |
|
198 gabble_media_stream_init (GabbleMediaStream *self) |
|
199 { |
|
200 GabbleMediaStreamPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, |
|
201 GABBLE_TYPE_MEDIA_STREAM, GabbleMediaStreamPrivate); |
|
202 |
|
203 self->priv = priv; |
|
204 |
|
205 g_value_init (&priv->native_codecs, TP_TYPE_CODEC_LIST); |
|
206 g_value_take_boxed (&priv->native_codecs, |
|
207 dbus_g_type_specialized_construct (TP_TYPE_CODEC_LIST)); |
|
208 |
|
209 g_value_init (&priv->native_candidates, TP_TYPE_CANDIDATE_LIST); |
|
210 g_value_take_boxed (&priv->native_candidates, |
|
211 dbus_g_type_specialized_construct (TP_TYPE_CANDIDATE_LIST)); |
|
212 |
|
213 g_value_init (&priv->remote_codecs, TP_TYPE_CODEC_LIST); |
|
214 g_value_take_boxed (&priv->remote_codecs, |
|
215 dbus_g_type_specialized_construct (TP_TYPE_CODEC_LIST)); |
|
216 |
|
217 g_value_init (&priv->remote_candidates, TP_TYPE_CANDIDATE_LIST); |
|
218 g_value_take_boxed (&priv->remote_candidates, |
|
219 dbus_g_type_specialized_construct (TP_TYPE_CANDIDATE_LIST)); |
|
220 } |
|
221 |
|
222 static GObject * |
|
223 gabble_media_stream_constructor (GType type, guint n_props, |
|
224 GObjectConstructParam *props) |
|
225 { |
|
226 GObject *obj; |
|
227 GabbleMediaStreamPrivate *priv; |
|
228 DBusGConnection *bus; |
|
229 |
|
230 /* call base class constructor */ |
|
231 obj = G_OBJECT_CLASS (gabble_media_stream_parent_class)-> |
|
232 constructor (type, n_props, props); |
|
233 priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (GABBLE_MEDIA_STREAM (obj)); |
|
234 |
|
235 /* go for the bus */ |
|
236 bus = tp_get_bus (); |
|
237 dbus_g_connection_register_g_object (bus, priv->object_path, obj); |
|
238 |
|
239 return obj; |
|
240 } |
|
241 |
|
242 static void |
|
243 gabble_media_stream_get_property (GObject *object, |
|
244 guint property_id, |
|
245 GValue *value, |
|
246 GParamSpec *pspec) |
|
247 { |
|
248 GabbleMediaStream *stream = GABBLE_MEDIA_STREAM (object); |
|
249 GabbleMediaStreamPrivate *priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream); |
|
250 |
|
251 switch (property_id) { |
|
252 case PROP_CONNECTION: |
|
253 g_value_set_object (value, priv->conn); |
|
254 break; |
|
255 case PROP_MEDIA_SESSION: |
|
256 g_value_set_object (value, priv->session); |
|
257 break; |
|
258 case PROP_OBJECT_PATH: |
|
259 g_value_set_string (value, priv->object_path); |
|
260 break; |
|
261 case PROP_MODE: |
|
262 g_value_set_enum (value, priv->mode); |
|
263 break; |
|
264 case PROP_NAME: |
|
265 g_value_set_string (value, stream->name); |
|
266 break; |
|
267 case PROP_ID: |
|
268 g_value_set_uint (value, priv->id); |
|
269 break; |
|
270 case PROP_INITIATOR: |
|
271 g_value_set_uint (value, stream->initiator); |
|
272 break; |
|
273 case PROP_MEDIA_TYPE: |
|
274 g_value_set_uint (value, priv->media_type); |
|
275 break; |
|
276 case PROP_CONNECTION_STATE: |
|
277 g_value_set_uint (value, stream->connection_state); |
|
278 break; |
|
279 case PROP_READY: |
|
280 g_value_set_boolean (value, priv->ready); |
|
281 break; |
|
282 case PROP_GOT_LOCAL_CODECS: |
|
283 g_value_set_boolean (value, stream->got_local_codecs); |
|
284 break; |
|
285 case PROP_SIGNALLING_STATE: |
|
286 g_value_set_uint (value, stream->signalling_state); |
|
287 break; |
|
288 case PROP_PLAYING: |
|
289 g_value_set_boolean (value, stream->playing); |
|
290 break; |
|
291 case PROP_COMBINED_DIRECTION: |
|
292 g_value_set_uint (value, stream->combined_direction); |
|
293 break; |
|
294 default: |
|
295 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); |
|
296 break; |
|
297 } |
|
298 } |
|
299 |
|
300 static void |
|
301 gabble_media_stream_set_property (GObject *object, |
|
302 guint property_id, |
|
303 const GValue *value, |
|
304 GParamSpec *pspec) |
|
305 { |
|
306 GabbleMediaStream *stream = GABBLE_MEDIA_STREAM (object); |
|
307 GabbleMediaStreamPrivate *priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream); |
|
308 |
|
309 switch (property_id) { |
|
310 case PROP_CONNECTION: |
|
311 priv->conn = g_value_get_object (value); |
|
312 break; |
|
313 case PROP_MEDIA_SESSION: |
|
314 priv->session = g_value_get_object (value); |
|
315 break; |
|
316 case PROP_OBJECT_PATH: |
|
317 g_free (priv->object_path); |
|
318 priv->object_path = g_value_dup_string (value); |
|
319 break; |
|
320 case PROP_MODE: |
|
321 priv->mode = g_value_get_enum (value); |
|
322 break; |
|
323 case PROP_NAME: |
|
324 g_free (stream->name); |
|
325 stream->name = g_value_dup_string (value); |
|
326 break; |
|
327 case PROP_ID: |
|
328 priv->id = g_value_get_uint (value); |
|
329 break; |
|
330 case PROP_INITIATOR: |
|
331 stream->initiator = g_value_get_uint (value); |
|
332 break; |
|
333 case PROP_MEDIA_TYPE: |
|
334 priv->media_type = g_value_get_uint (value); |
|
335 break; |
|
336 case PROP_CONNECTION_STATE: |
|
337 _gabble_media_session_debug (priv->session, DEBUG_MSG_INFO, DEBUG_MSG_INFO, "stream %s connection state %d", |
|
338 stream->name, stream->connection_state); |
|
339 stream->connection_state = g_value_get_uint (value); |
|
340 break; |
|
341 case PROP_READY: |
|
342 priv->ready = g_value_get_boolean (value); |
|
343 break; |
|
344 case PROP_GOT_LOCAL_CODECS: |
|
345 stream->got_local_codecs = g_value_get_boolean (value); |
|
346 break; |
|
347 case PROP_SIGNALLING_STATE: |
|
348 { |
|
349 StreamSignallingState old = stream->signalling_state; |
|
350 stream->signalling_state = g_value_get_uint (value); |
|
351 _gabble_media_session_debug (priv->session, DEBUG_MSG_INFO, DEBUG_MSG_INFO, "stream %s sig_state %d->%d", |
|
352 stream->name, old, stream->signalling_state); |
|
353 if (stream->signalling_state != old) |
|
354 push_native_candidates (stream); |
|
355 } |
|
356 break; |
|
357 case PROP_PLAYING: |
|
358 { |
|
359 gboolean old = stream->playing; |
|
360 stream->playing = g_value_get_boolean (value); |
|
361 if (stream->playing != old) |
|
362 push_playing (stream); |
|
363 } |
|
364 break; |
|
365 case PROP_COMBINED_DIRECTION: |
|
366 stream->combined_direction = g_value_get_uint (value); |
|
367 break; |
|
368 default: |
|
369 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); |
|
370 break; |
|
371 } |
|
372 } |
|
373 |
|
374 static void gabble_media_stream_dispose (GObject *object); |
|
375 static void gabble_media_stream_finalize (GObject *object); |
|
376 |
|
377 static void |
|
378 gabble_media_stream_class_init (GabbleMediaStreamClass *gabble_media_stream_class) |
|
379 { |
|
380 GObjectClass *object_class = G_OBJECT_CLASS (gabble_media_stream_class); |
|
381 GParamSpec *param_spec; |
|
382 |
|
383 g_type_class_add_private (gabble_media_stream_class, sizeof (GabbleMediaStreamPrivate)); |
|
384 |
|
385 object_class->constructor = gabble_media_stream_constructor; |
|
386 |
|
387 object_class->get_property = gabble_media_stream_get_property; |
|
388 object_class->set_property = gabble_media_stream_set_property; |
|
389 |
|
390 object_class->dispose = gabble_media_stream_dispose; |
|
391 object_class->finalize = gabble_media_stream_finalize; |
|
392 |
|
393 param_spec = g_param_spec_object ("connection", "GabbleConnection object", |
|
394 "Gabble connection object that owns this " |
|
395 "media stream's channel.", |
|
396 GABBLE_TYPE_CONNECTION, |
|
397 G_PARAM_CONSTRUCT_ONLY | |
|
398 G_PARAM_READWRITE | |
|
399 G_PARAM_STATIC_NICK | |
|
400 G_PARAM_STATIC_BLURB); |
|
401 g_object_class_install_property (object_class, PROP_CONNECTION, param_spec); |
|
402 |
|
403 param_spec = g_param_spec_object ("media-session", "GabbleMediaSession object", |
|
404 "Gabble media session object that owns this " |
|
405 "media stream object.", |
|
406 GABBLE_TYPE_MEDIA_SESSION, |
|
407 G_PARAM_CONSTRUCT_ONLY | |
|
408 G_PARAM_READWRITE | |
|
409 G_PARAM_STATIC_NICK | |
|
410 G_PARAM_STATIC_BLURB); |
|
411 g_object_class_install_property (object_class, PROP_MEDIA_SESSION, param_spec); |
|
412 |
|
413 param_spec = g_param_spec_string ("object-path", "D-Bus object path", |
|
414 "The D-Bus object path used for this " |
|
415 "object on the bus.", |
|
416 NULL, |
|
417 G_PARAM_CONSTRUCT_ONLY | |
|
418 G_PARAM_READWRITE | |
|
419 G_PARAM_STATIC_NAME | |
|
420 G_PARAM_STATIC_BLURB); |
|
421 g_object_class_install_property (object_class, PROP_OBJECT_PATH, param_spec); |
|
422 |
|
423 param_spec = g_param_spec_enum ("mode", "Signalling mode", |
|
424 "Which signalling mode used to control the " |
|
425 "stream.", |
|
426 gabble_media_session_mode_get_type(), |
|
427 MODE_JINGLE, |
|
428 G_PARAM_CONSTRUCT_ONLY | |
|
429 G_PARAM_READWRITE | |
|
430 G_PARAM_STATIC_NAME | |
|
431 G_PARAM_STATIC_BLURB); |
|
432 g_object_class_install_property (object_class, PROP_MODE, param_spec); |
|
433 |
|
434 param_spec = g_param_spec_string ("name", "Stream name", |
|
435 "An opaque name for the stream used in the " |
|
436 "signalling.", |
|
437 NULL, |
|
438 G_PARAM_CONSTRUCT_ONLY | |
|
439 G_PARAM_READWRITE | |
|
440 G_PARAM_STATIC_NAME | |
|
441 G_PARAM_STATIC_BLURB); |
|
442 g_object_class_install_property (object_class, PROP_NAME, param_spec); |
|
443 |
|
444 param_spec = g_param_spec_uint ("id", "Stream ID", |
|
445 "A stream number for the stream used in the " |
|
446 "D-Bus API.", |
|
447 0, G_MAXUINT, 0, |
|
448 G_PARAM_CONSTRUCT_ONLY | |
|
449 G_PARAM_READWRITE | |
|
450 G_PARAM_STATIC_NAME | |
|
451 G_PARAM_STATIC_BLURB); |
|
452 g_object_class_install_property (object_class, PROP_ID, param_spec); |
|
453 |
|
454 param_spec = g_param_spec_uint ("initiator", "Stream initiator", |
|
455 "An enum signifying which end initiated " |
|
456 "the stream.", |
|
457 INITIATOR_LOCAL, |
|
458 INITIATOR_REMOTE, |
|
459 INITIATOR_LOCAL, |
|
460 G_PARAM_CONSTRUCT_ONLY | |
|
461 G_PARAM_READWRITE | |
|
462 G_PARAM_STATIC_NAME | |
|
463 G_PARAM_STATIC_BLURB); |
|
464 g_object_class_install_property (object_class, PROP_INITIATOR, param_spec); |
|
465 |
|
466 param_spec = g_param_spec_uint ("media-type", "Stream media type", |
|
467 "A constant indicating which media type the " |
|
468 "stream carries.", |
|
469 TP_MEDIA_STREAM_TYPE_AUDIO, |
|
470 TP_MEDIA_STREAM_TYPE_VIDEO, |
|
471 TP_MEDIA_STREAM_TYPE_AUDIO, |
|
472 G_PARAM_CONSTRUCT_ONLY | |
|
473 G_PARAM_READWRITE | |
|
474 G_PARAM_STATIC_NAME | |
|
475 G_PARAM_STATIC_BLURB); |
|
476 g_object_class_install_property (object_class, PROP_MEDIA_TYPE, param_spec); |
|
477 |
|
478 param_spec = g_param_spec_uint ("connection-state", "Stream connection state", |
|
479 "An integer indicating the state of the" |
|
480 "stream's connection.", |
|
481 TP_MEDIA_STREAM_STATE_DISCONNECTED, |
|
482 TP_MEDIA_STREAM_STATE_CONNECTED, |
|
483 TP_MEDIA_STREAM_STATE_DISCONNECTED, |
|
484 G_PARAM_CONSTRUCT | |
|
485 G_PARAM_READWRITE | |
|
486 G_PARAM_STATIC_NAME | |
|
487 G_PARAM_STATIC_BLURB); |
|
488 g_object_class_install_property (object_class, PROP_CONNECTION_STATE, param_spec); |
|
489 |
|
490 param_spec = g_param_spec_boolean ("ready", "Ready?", |
|
491 "A boolean signifying whether the user " |
|
492 "is ready to handle signals from this " |
|
493 "object.", |
|
494 FALSE, |
|
495 G_PARAM_CONSTRUCT | |
|
496 G_PARAM_READWRITE | |
|
497 G_PARAM_STATIC_NAME | |
|
498 G_PARAM_STATIC_BLURB); |
|
499 g_object_class_install_property (object_class, PROP_READY, param_spec); |
|
500 |
|
501 param_spec = g_param_spec_boolean ("got-local-codecs", "Got local codecs?", |
|
502 "A boolean signifying whether we've got " |
|
503 "the locally supported codecs from the user.", |
|
504 FALSE, |
|
505 G_PARAM_CONSTRUCT | |
|
506 G_PARAM_READWRITE | |
|
507 G_PARAM_STATIC_NAME | |
|
508 G_PARAM_STATIC_BLURB); |
|
509 g_object_class_install_property (object_class, PROP_GOT_LOCAL_CODECS, param_spec); |
|
510 |
|
511 param_spec = g_param_spec_uint ("signalling-state", "Signalling state", |
|
512 "Whether the stream is newly created, " |
|
513 "sent to the peer, or acknowledged.", |
|
514 STREAM_SIG_STATE_NEW, |
|
515 STREAM_SIG_STATE_REMOVING, |
|
516 STREAM_SIG_STATE_NEW, |
|
517 G_PARAM_CONSTRUCT | |
|
518 G_PARAM_READWRITE | |
|
519 G_PARAM_STATIC_NAME | |
|
520 G_PARAM_STATIC_BLURB); |
|
521 g_object_class_install_property (object_class, PROP_SIGNALLING_STATE, param_spec); |
|
522 |
|
523 param_spec = g_param_spec_boolean ("playing", "Set playing", |
|
524 "A boolean signifying whether the stream " |
|
525 "has been set playing yet.", |
|
526 FALSE, |
|
527 G_PARAM_CONSTRUCT | |
|
528 G_PARAM_READWRITE | |
|
529 G_PARAM_STATIC_NAME | |
|
530 G_PARAM_STATIC_BLURB); |
|
531 g_object_class_install_property (object_class, PROP_PLAYING, param_spec); |
|
532 |
|
533 param_spec = g_param_spec_uint ("combined-direction", |
|
534 "Combined direction", |
|
535 "An integer indicating the directions the stream currently sends in, " |
|
536 "and the peers who have been asked to send.", |
|
537 TP_MEDIA_STREAM_DIRECTION_NONE, |
|
538 MAKE_COMBINED_DIRECTION (TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL, |
|
539 TP_MEDIA_STREAM_PENDING_LOCAL_SEND | |
|
540 TP_MEDIA_STREAM_PENDING_REMOTE_SEND), |
|
541 TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL, |
|
542 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_NAME | |
|
543 G_PARAM_STATIC_BLURB); |
|
544 g_object_class_install_property (object_class, PROP_COMBINED_DIRECTION, |
|
545 param_spec); |
|
546 |
|
547 /* signals exported by D-Bus interface */ |
|
548 signals[DESTROY] = |
|
549 g_signal_new ("destroy", |
|
550 G_OBJECT_CLASS_TYPE (gabble_media_stream_class), |
|
551 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, |
|
552 0, |
|
553 NULL, NULL, |
|
554 g_cclosure_marshal_VOID__VOID, |
|
555 G_TYPE_NONE, 0); |
|
556 |
|
557 signals[ADD_REMOTE_CANDIDATE] = |
|
558 g_signal_new ("add-remote-candidate", |
|
559 G_OBJECT_CLASS_TYPE (gabble_media_stream_class), |
|
560 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, |
|
561 0, |
|
562 NULL, NULL, |
|
563 gabble_media_stream_marshal_VOID__STRING_BOXED, |
|
564 G_TYPE_NONE, 2, G_TYPE_STRING, TP_TYPE_TRANSPORT_LIST); |
|
565 |
|
566 signals[CLOSE] = |
|
567 g_signal_new ("close", |
|
568 G_OBJECT_CLASS_TYPE (gabble_media_stream_class), |
|
569 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, |
|
570 0, |
|
571 NULL, NULL, |
|
572 g_cclosure_marshal_VOID__VOID, |
|
573 G_TYPE_NONE, 0); |
|
574 |
|
575 signals[REMOVE_REMOTE_CANDIDATE] = |
|
576 g_signal_new ("remove-remote-candidate", |
|
577 G_OBJECT_CLASS_TYPE (gabble_media_stream_class), |
|
578 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, |
|
579 0, |
|
580 NULL, NULL, |
|
581 g_cclosure_marshal_VOID__STRING, |
|
582 G_TYPE_NONE, 1, G_TYPE_STRING); |
|
583 |
|
584 signals[SET_ACTIVE_CANDIDATE_PAIR] = |
|
585 g_signal_new ("set-active-candidate-pair", |
|
586 G_OBJECT_CLASS_TYPE (gabble_media_stream_class), |
|
587 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, |
|
588 0, |
|
589 NULL, NULL, |
|
590 gabble_media_stream_marshal_VOID__STRING_STRING, |
|
591 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING); |
|
592 |
|
593 signals[SET_REMOTE_CANDIDATE_LIST] = |
|
594 g_signal_new ("set-remote-candidate-list", |
|
595 G_OBJECT_CLASS_TYPE (gabble_media_stream_class), |
|
596 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, |
|
597 0, |
|
598 NULL, NULL, |
|
599 g_cclosure_marshal_VOID__BOXED, |
|
600 G_TYPE_NONE, 1, TP_TYPE_CANDIDATE_LIST); |
|
601 |
|
602 signals[SET_REMOTE_CODECS] = |
|
603 g_signal_new ("set-remote-codecs", |
|
604 G_OBJECT_CLASS_TYPE (gabble_media_stream_class), |
|
605 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, |
|
606 0, |
|
607 NULL, NULL, |
|
608 g_cclosure_marshal_VOID__BOXED, |
|
609 G_TYPE_NONE, 1, TP_TYPE_CODEC_LIST); |
|
610 |
|
611 /* signals not exported by D-Bus interface */ |
|
612 signals[NEW_ACTIVE_CANDIDATE_PAIR] = |
|
613 g_signal_new ("new-active-candidate-pair", |
|
614 G_OBJECT_CLASS_TYPE (gabble_media_stream_class), |
|
615 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, |
|
616 0, |
|
617 NULL, NULL, |
|
618 gabble_media_stream_marshal_VOID__STRING_STRING, |
|
619 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING); |
|
620 |
|
621 signals[NEW_NATIVE_CANDIDATE] = |
|
622 g_signal_new ("new-native-candidate", |
|
623 G_OBJECT_CLASS_TYPE (gabble_media_stream_class), |
|
624 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, |
|
625 0, |
|
626 NULL, NULL, |
|
627 gabble_media_stream_marshal_VOID__STRING_BOXED, |
|
628 G_TYPE_NONE, 2, G_TYPE_STRING, TP_TYPE_TRANSPORT_LIST); |
|
629 |
|
630 signals[SUPPORTED_CODECS] = |
|
631 g_signal_new ("supported-codecs", |
|
632 G_OBJECT_CLASS_TYPE (gabble_media_stream_class), |
|
633 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, |
|
634 0, |
|
635 NULL, NULL, |
|
636 g_cclosure_marshal_VOID__BOXED, |
|
637 G_TYPE_NONE, 1, TP_TYPE_CODEC_LIST); |
|
638 |
|
639 signals[SET_STREAM_PLAYING] = |
|
640 g_signal_new ("set-stream-playing", |
|
641 G_OBJECT_CLASS_TYPE (gabble_media_stream_class), |
|
642 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, |
|
643 0, |
|
644 NULL, NULL, |
|
645 g_cclosure_marshal_VOID__BOOLEAN, |
|
646 G_TYPE_NONE, 1, G_TYPE_BOOLEAN); |
|
647 |
|
648 signals[SET_STREAM_SENDING] = |
|
649 g_signal_new ("set-stream-sending", |
|
650 G_OBJECT_CLASS_TYPE (gabble_media_stream_class), |
|
651 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, |
|
652 0, |
|
653 NULL, NULL, |
|
654 g_cclosure_marshal_VOID__BOOLEAN, |
|
655 G_TYPE_NONE, 1, G_TYPE_BOOLEAN); |
|
656 |
|
657 signals[ERROR] = |
|
658 g_signal_new ("error", |
|
659 G_OBJECT_CLASS_TYPE (gabble_media_stream_class), |
|
660 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, |
|
661 0, |
|
662 NULL, NULL, |
|
663 gabble_media_stream_marshal_VOID__UINT_STRING, |
|
664 G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING); |
|
665 |
|
666 dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (gabble_media_stream_class), &dbus_glib_gabble_media_stream_object_info); |
|
667 } |
|
668 |
|
669 void |
|
670 gabble_media_stream_dispose (GObject *object) |
|
671 { |
|
672 GabbleMediaStream *self = GABBLE_MEDIA_STREAM (object); |
|
673 GabbleMediaStreamPrivate *priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (self); |
|
674 |
|
675 if (priv->dispose_has_run) |
|
676 return; |
|
677 |
|
678 _gabble_media_stream_close (self); |
|
679 |
|
680 g_signal_emit (self, signals[DESTROY], 0); |
|
681 |
|
682 priv->dispose_has_run = TRUE; |
|
683 |
|
684 if (G_OBJECT_CLASS (gabble_media_stream_parent_class)->dispose) |
|
685 G_OBJECT_CLASS (gabble_media_stream_parent_class)->dispose (object); |
|
686 } |
|
687 |
|
688 void |
|
689 gabble_media_stream_finalize (GObject *object) |
|
690 { |
|
691 GabbleMediaStream *self = GABBLE_MEDIA_STREAM (object); |
|
692 GabbleMediaStreamPrivate *priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (self); |
|
693 |
|
694 g_free (priv->object_path); |
|
695 |
|
696 g_value_unset (&priv->native_codecs); |
|
697 g_value_unset (&priv->native_candidates); |
|
698 |
|
699 g_value_unset (&priv->remote_codecs); |
|
700 g_value_unset (&priv->remote_candidates); |
|
701 |
|
702 G_OBJECT_CLASS (gabble_media_stream_parent_class)->finalize (object); |
|
703 } |
|
704 |
|
705 /** |
|
706 * gabble_media_stream_codec_choice |
|
707 * |
|
708 * Implements D-Bus method CodecChoice |
|
709 * on interface org.freedesktop.Telepathy.Media.StreamHandler |
|
710 * |
|
711 * @error: Used to return a pointer to a GError detailing any error |
|
712 * that occurred, D-Bus will throw the error only if this |
|
713 * function returns FALSE. |
|
714 * |
|
715 * Returns: TRUE if successful, FALSE if an error was thrown. |
|
716 */ |
|
717 gboolean |
|
718 gabble_media_stream_codec_choice (GabbleMediaStream *self, |
|
719 guint codec_id, |
|
720 GError **error) |
|
721 { |
|
722 GabbleMediaStreamPrivate *priv; |
|
723 |
|
724 g_assert (GABBLE_IS_MEDIA_STREAM (self)); |
|
725 |
|
726 priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (self); |
|
727 |
|
728 return TRUE; |
|
729 } |
|
730 |
|
731 |
|
732 /** |
|
733 * gabble_media_stream_error |
|
734 * |
|
735 * Implements D-Bus method Error |
|
736 * on interface org.freedesktop.Telepathy.Media.StreamHandler |
|
737 * |
|
738 * @error: Used to return a pointer to a GError detailing any error |
|
739 * that occurred, D-Bus will throw the error only if this |
|
740 * function returns FALSE. |
|
741 * |
|
742 * Returns: TRUE if successful, FALSE if an error was thrown. |
|
743 */ |
|
744 gboolean |
|
745 gabble_media_stream_error (GabbleMediaStream *self, |
|
746 guint errno, |
|
747 const gchar *message, |
|
748 GError **error) |
|
749 { |
|
750 GabbleMediaStreamPrivate *priv; |
|
751 |
|
752 g_assert (GABBLE_IS_MEDIA_STREAM (self)); |
|
753 |
|
754 priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (self); |
|
755 |
|
756 _gabble_media_session_debug (priv->session, DEBUG_MSG_WARNING, "Media.StreamHandler::Error called, error %u (%s) -- emitting signal", errno, message); |
|
757 |
|
758 g_signal_emit (self, signals[ERROR], 0, errno, message); |
|
759 |
|
760 return TRUE; |
|
761 } |
|
762 |
|
763 |
|
764 /** |
|
765 * gabble_media_stream_native_candidates_prepared |
|
766 * |
|
767 * Implements D-Bus method NativeCandidatesPrepared |
|
768 * on interface org.freedesktop.Telepathy.Media.StreamHandler |
|
769 * |
|
770 * @error: Used to return a pointer to a GError detailing any error |
|
771 * that occurred, D-Bus will throw the error only if this |
|
772 * function returns FALSE. |
|
773 * |
|
774 * Returns: TRUE if successful, FALSE if an error was thrown. |
|
775 */ |
|
776 gboolean |
|
777 gabble_media_stream_native_candidates_prepared (GabbleMediaStream *self, |
|
778 GError **error) |
|
779 { |
|
780 GabbleMediaStreamPrivate *priv; |
|
781 |
|
782 g_assert (GABBLE_IS_MEDIA_STREAM (self)); |
|
783 |
|
784 priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (self); |
|
785 |
|
786 return TRUE; |
|
787 } |
|
788 |
|
789 |
|
790 /** |
|
791 * gabble_media_stream_new_active_candidate_pair |
|
792 * |
|
793 * Implements D-Bus method NewActiveCandidatePair |
|
794 * on interface org.freedesktop.Telepathy.Media.StreamHandler |
|
795 * |
|
796 * @error: Used to return a pointer to a GError detailing any error |
|
797 * that occurred, D-Bus will throw the error only if this |
|
798 * function returns FALSE. |
|
799 * |
|
800 * Returns: TRUE if successful, FALSE if an error was thrown. |
|
801 */ |
|
802 gboolean |
|
803 gabble_media_stream_new_active_candidate_pair (GabbleMediaStream *self, |
|
804 const gchar *native_candidate_id, |
|
805 const gchar *remote_candidate_id, |
|
806 GError **error) |
|
807 { |
|
808 GabbleMediaStreamPrivate *priv; |
|
809 |
|
810 g_assert (GABBLE_IS_MEDIA_STREAM (self)); |
|
811 |
|
812 priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (self); |
|
813 |
|
814 g_signal_emit (self, signals[NEW_ACTIVE_CANDIDATE_PAIR], 0, |
|
815 native_candidate_id, remote_candidate_id); |
|
816 |
|
817 return TRUE; |
|
818 } |
|
819 |
|
820 |
|
821 /** |
|
822 * gabble_media_stream_new_native_candidate |
|
823 * |
|
824 * Implements D-Bus method NewNativeCandidate |
|
825 * on interface org.freedesktop.Telepathy.Media.StreamHandler |
|
826 * |
|
827 * @error: Used to return a pointer to a GError detailing any error |
|
828 * that occurred, D-Bus will throw the error only if this |
|
829 * function returns FALSE. |
|
830 * |
|
831 * Returns: TRUE if successful, FALSE if an error was thrown. |
|
832 */ |
|
833 gboolean |
|
834 gabble_media_stream_new_native_candidate (GabbleMediaStream *self, |
|
835 const gchar *candidate_id, |
|
836 const GPtrArray *transports, |
|
837 GError **error) |
|
838 { |
|
839 GabbleMediaStreamPrivate *priv; |
|
840 JingleSessionState state; |
|
841 GPtrArray *candidates; |
|
842 GValue candidate = { 0, }; |
|
843 GValueArray *transport; |
|
844 const gchar *addr; |
|
845 |
|
846 g_assert (GABBLE_IS_MEDIA_STREAM (self)); |
|
847 |
|
848 priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (self); |
|
849 |
|
850 g_object_get (priv->session, "state", &state, NULL); |
|
851 |
|
852 /* FIXME: maybe this should be an assertion in case the channel |
|
853 * isn't closed early enough right now? */ |
|
854 if (state > JS_STATE_ACTIVE) |
|
855 { |
|
856 gabble_debug (DEBUG_FLAG, "state > JS_STATE_ACTIVE, doing nothing"); |
|
857 return TRUE; |
|
858 } |
|
859 |
|
860 candidates = g_value_get_boxed (&priv->native_candidates); |
|
861 |
|
862 g_value_init (&candidate, TP_TYPE_CANDIDATE_STRUCT); |
|
863 g_value_take_boxed (&candidate, |
|
864 dbus_g_type_specialized_construct (TP_TYPE_CANDIDATE_STRUCT)); |
|
865 |
|
866 dbus_g_type_struct_set (&candidate, |
|
867 0, candidate_id, |
|
868 1, transports, |
|
869 G_MAXUINT); |
|
870 |
|
871 transport = g_ptr_array_index (transports, 0); |
|
872 addr = g_value_get_string (g_value_array_get_nth (transport, 1)); |
|
873 if (!strcmp (addr, "127.0.0.1")) |
|
874 { |
|
875 _gabble_media_session_debug (priv->session, DEBUG_MSG_WARNING, "%s: ignoring native localhost candidate", |
|
876 G_STRFUNC); |
|
877 return TRUE; |
|
878 } |
|
879 |
|
880 g_ptr_array_add (candidates, g_value_get_boxed (&candidate)); |
|
881 |
|
882 _gabble_media_session_debug (priv->session, DEBUG_MSG_INFO, DEBUG_MSG_INFO, "put 1 native candidate from stream-engine into cache"); |
|
883 |
|
884 push_native_candidates (self); |
|
885 |
|
886 g_signal_emit (self, signals[NEW_NATIVE_CANDIDATE], 0, |
|
887 candidate_id, transports); |
|
888 |
|
889 return TRUE; |
|
890 } |
|
891 |
|
892 |
|
893 /** |
|
894 * gabble_media_stream_ready |
|
895 * |
|
896 * Implements D-Bus method Ready |
|
897 * on interface org.freedesktop.Telepathy.Media.StreamHandler |
|
898 * |
|
899 * @error: Used to return a pointer to a GError detailing any error |
|
900 * that occurred, D-Bus will throw the error only if this |
|
901 * function returns FALSE. |
|
902 * |
|
903 * Returns: TRUE if successful, FALSE if an error was thrown. |
|
904 */ |
|
905 gboolean |
|
906 gabble_media_stream_ready (GabbleMediaStream *self, |
|
907 const GPtrArray *codecs, |
|
908 GError **error) |
|
909 { |
|
910 GabbleMediaStreamPrivate *priv; |
|
911 |
|
912 g_assert (GABBLE_IS_MEDIA_STREAM (self)); |
|
913 |
|
914 priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (self); |
|
915 |
|
916 _gabble_media_session_debug (priv->session, DEBUG_MSG_INFO, DEBUG_MSG_INFO, "ready called"); |
|
917 |
|
918 g_object_set (self, "ready", TRUE, NULL); |
|
919 |
|
920 push_remote_codecs (self); |
|
921 push_remote_candidates (self); |
|
922 push_playing (self); |
|
923 push_sending (self); |
|
924 |
|
925 return gabble_media_stream_set_local_codecs (self, codecs, error); |
|
926 } |
|
927 |
|
928 |
|
929 /** |
|
930 * gabble_media_stream_set_local_codecs |
|
931 * |
|
932 * Implements D-Bus method SetLocalCodecs |
|
933 * on interface org.freedesktop.Telepathy.Media.StreamHandler |
|
934 * |
|
935 * @error: Used to return a pointer to a GError detailing any error |
|
936 * that occurred, D-Bus will throw the error only if this |
|
937 * function returns FALSE. |
|
938 * |
|
939 * Returns: TRUE if successful, FALSE if an error was thrown. |
|
940 */ |
|
941 gboolean |
|
942 gabble_media_stream_set_local_codecs (GabbleMediaStream *self, |
|
943 const GPtrArray *codecs, |
|
944 GError **error) |
|
945 { |
|
946 GabbleMediaStreamPrivate *priv; |
|
947 |
|
948 g_assert (GABBLE_IS_MEDIA_STREAM (self)); |
|
949 |
|
950 priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (self); |
|
951 |
|
952 _gabble_media_session_debug (priv->session, DEBUG_MSG_INFO, DEBUG_MSG_INFO, "putting list of all %d locally supported " |
|
953 "codecs from stream-engine into cache", codecs->len); |
|
954 |
|
955 g_value_set_boxed (&priv->native_codecs, codecs); |
|
956 |
|
957 g_object_set (self, "got-local-codecs", TRUE, NULL); |
|
958 |
|
959 return TRUE; |
|
960 } |
|
961 |
|
962 |
|
963 /** |
|
964 * gabble_media_stream_stream_state |
|
965 * |
|
966 * Implements D-Bus method StreamState |
|
967 * on interface org.freedesktop.Telepathy.Media.StreamHandler |
|
968 * |
|
969 * @error: Used to return a pointer to a GError detailing any error |
|
970 * that occurred, D-Bus will throw the error only if this |
|
971 * function returns FALSE. |
|
972 * |
|
973 * Returns: TRUE if successful, FALSE if an error was thrown. |
|
974 */ |
|
975 gboolean |
|
976 gabble_media_stream_stream_state (GabbleMediaStream *self, |
|
977 guint connection_state, |
|
978 GError **error) |
|
979 { |
|
980 g_assert (GABBLE_IS_MEDIA_STREAM (self)); |
|
981 |
|
982 g_object_set (self, "connection-state", connection_state, NULL); |
|
983 |
|
984 return TRUE; |
|
985 } |
|
986 |
|
987 |
|
988 /** |
|
989 * gabble_media_stream_supported_codecs |
|
990 * |
|
991 * Implements D-Bus method SupportedCodecs |
|
992 * on interface org.freedesktop.Telepathy.Media.StreamHandler |
|
993 * |
|
994 * @error: Used to return a pointer to a GError detailing any error |
|
995 * that occurred, D-Bus will throw the error only if this |
|
996 * function returns FALSE. |
|
997 * |
|
998 * Returns: TRUE if successful, FALSE if an error was thrown. |
|
999 */ |
|
1000 gboolean |
|
1001 gabble_media_stream_supported_codecs (GabbleMediaStream *self, |
|
1002 const GPtrArray *codecs, |
|
1003 GError **error) |
|
1004 { |
|
1005 GabbleMediaStreamPrivate *priv; |
|
1006 |
|
1007 g_assert (GABBLE_IS_MEDIA_STREAM (self)); |
|
1008 |
|
1009 priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (self); |
|
1010 |
|
1011 _gabble_media_session_debug (priv->session, DEBUG_MSG_INFO, DEBUG_MSG_INFO, "got codec intersection containing %d " |
|
1012 "codecs from stream-engine", codecs->len); |
|
1013 |
|
1014 /* store the intersection for later on */ |
|
1015 g_value_set_boxed (&priv->native_codecs, codecs); |
|
1016 |
|
1017 g_signal_emit (self, signals[SUPPORTED_CODECS], 0, codecs); |
|
1018 |
|
1019 return TRUE; |
|
1020 } |
|
1021 |
|
1022 static LmHandlerResult |
|
1023 candidates_msg_reply_cb (GabbleConnection *conn, |
|
1024 LmMessage *sent_msg, |
|
1025 LmMessage *reply_msg, |
|
1026 GObject *object, |
|
1027 gpointer user_data) |
|
1028 { |
|
1029 GabbleMediaStream *stream = GABBLE_MEDIA_STREAM (object); |
|
1030 GabbleMediaStreamPrivate *priv; |
|
1031 |
|
1032 g_assert (GABBLE_IS_MEDIA_STREAM (stream)); |
|
1033 |
|
1034 priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream); |
|
1035 |
|
1036 MSG_REPLY_CB_END_SESSION_IF_NOT_SUCCESSFUL (priv->session, "candidates failed"); |
|
1037 |
|
1038 return LM_HANDLER_RESULT_REMOVE_MESSAGE; |
|
1039 } |
|
1040 |
|
1041 static void |
|
1042 _add_rtp_candidate_node (GabbleMediaSession *session, LmMessageNode *parent, |
|
1043 GValueArray *candidate) |
|
1044 { |
|
1045 gchar *addr; |
|
1046 gchar *user; |
|
1047 gchar *pass; |
|
1048 gchar *port_str; |
|
1049 gchar *pref_str; |
|
1050 gchar *xml; |
|
1051 const gchar *type_str; |
|
1052 const gchar *candidate_id; |
|
1053 guint port; |
|
1054 gdouble pref; |
|
1055 TpMediaStreamProto proto; |
|
1056 TpMediaStreamTransportType type; |
|
1057 const GPtrArray *transports; |
|
1058 GValue transport = { 0, }; |
|
1059 LmMessageNode *cand_node; |
|
1060 |
|
1061 candidate_id = g_value_get_string (g_value_array_get_nth (candidate, 0)); |
|
1062 transports = g_value_get_boxed (g_value_array_get_nth (candidate, 1)); |
|
1063 |
|
1064 /* jingle audio only supports the concept of one transport per candidate */ |
|
1065 g_assert (transports->len == 1); |
|
1066 |
|
1067 g_value_init (&transport, TP_TYPE_TRANSPORT_STRUCT); |
|
1068 g_value_set_static_boxed (&transport, g_ptr_array_index (transports, 0)); |
|
1069 |
|
1070 dbus_g_type_struct_get (&transport, |
|
1071 1, &addr, |
|
1072 2, &port, |
|
1073 3, &proto, |
|
1074 6, &pref, |
|
1075 7, &type, |
|
1076 8, &user, |
|
1077 9, &pass, |
|
1078 G_MAXUINT); |
|
1079 |
|
1080 port_str = g_strdup_printf ("%d", port); |
|
1081 pref_str = g_strdup_printf ("%f", pref); |
|
1082 |
|
1083 switch (type) { |
|
1084 case TP_MEDIA_STREAM_TRANSPORT_TYPE_LOCAL: |
|
1085 type_str = "local"; |
|
1086 break; |
|
1087 case TP_MEDIA_STREAM_TRANSPORT_TYPE_DERIVED: |
|
1088 type_str = "stun"; |
|
1089 break; |
|
1090 case TP_MEDIA_STREAM_TRANSPORT_TYPE_RELAY: |
|
1091 type_str = "relay"; |
|
1092 break; |
|
1093 default: |
|
1094 g_error ("%s: TpMediaStreamTransportType has an invalid value", |
|
1095 G_STRFUNC); |
|
1096 return; |
|
1097 } |
|
1098 |
|
1099 cand_node = lm_message_node_add_child (parent, "candidate", NULL); |
|
1100 lm_message_node_set_attributes (cand_node, |
|
1101 "name", "rtp", |
|
1102 "address", addr, |
|
1103 "port", port_str, |
|
1104 "username", user, |
|
1105 "password", pass, |
|
1106 "preference", pref_str, |
|
1107 "protocol", (proto == TP_MEDIA_STREAM_PROTO_UDP) ? "udp" : "tcp", |
|
1108 "type", type_str, |
|
1109 "network", "0", |
|
1110 "generation", "0", |
|
1111 NULL); |
|
1112 |
|
1113 xml = lm_message_node_to_string (cand_node); |
|
1114 _gabble_media_session_debug (session, DEBUG_MSG_DUMP, |
|
1115 " from Telepathy D-Bus struct: [%s\"%s\", %s[%s1, \"%s\", %d, %s, " |
|
1116 "\"%s\", \"%s\", %f, %s, \"%s\", \"%s\"%s]]", |
|
1117 ANSI_BOLD_OFF, candidate_id, ANSI_BOLD_ON, ANSI_BOLD_OFF, addr, port, |
|
1118 tp_protocols[proto], "RTP", "AVP", pref, tp_transports[type], user, pass, |
|
1119 ANSI_BOLD_ON); |
|
1120 _gabble_media_session_debug (session, DEBUG_MSG_DUMP, |
|
1121 " to Jingle XML: [%s%s%s]", ANSI_BOLD_OFF, xml, ANSI_BOLD_ON); |
|
1122 g_free (xml); |
|
1123 |
|
1124 g_free (addr); |
|
1125 g_free (user); |
|
1126 g_free (pass); |
|
1127 g_free (port_str); |
|
1128 g_free (pref_str); |
|
1129 } |
|
1130 |
|
1131 static LmMessage * |
|
1132 _gabble_media_stream_message_new (GabbleMediaStream *stream, |
|
1133 const gchar *action, |
|
1134 LmMessageNode **content_node) |
|
1135 { |
|
1136 GabbleMediaStreamPrivate *priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream); |
|
1137 LmMessage *msg; |
|
1138 LmMessageNode *session_node = NULL; |
|
1139 |
|
1140 /* construct a session message */ |
|
1141 msg = _gabble_media_session_message_new (priv->session, action, |
|
1142 &session_node); |
|
1143 |
|
1144 /* add our content node to it if necessary */ |
|
1145 *content_node = _gabble_media_stream_add_content_node (stream, session_node); |
|
1146 |
|
1147 return msg; |
|
1148 } |
|
1149 |
|
1150 |
|
1151 static void |
|
1152 push_candidate (GabbleMediaStream *stream, GValueArray *candidate) |
|
1153 { |
|
1154 GabbleMediaStreamPrivate *priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream); |
|
1155 LmMessage *msg; |
|
1156 LmMessageNode *content_node, *transport_node; |
|
1157 const gchar *action; |
|
1158 |
|
1159 if (priv->mode == MODE_GOOGLE) |
|
1160 action = "candidates"; |
|
1161 else |
|
1162 action = "transport-info"; |
|
1163 |
|
1164 /* construct a base message */ |
|
1165 msg = _gabble_media_stream_message_new (stream, action, &content_node); |
|
1166 |
|
1167 /* for jingle, add a transport */ |
|
1168 transport_node = _gabble_media_stream_content_node_add_transport (stream, |
|
1169 content_node); |
|
1170 |
|
1171 /* add transport info to it */ |
|
1172 _add_rtp_candidate_node (priv->session, transport_node, candidate); |
|
1173 |
|
1174 _gabble_media_session_debug (priv->session, DEBUG_MSG_INFO, DEBUG_MSG_INFO, "sending jingle session action \"%s\" to " |
|
1175 "peer", action); |
|
1176 |
|
1177 /* send it */ |
|
1178 _gabble_connection_send_with_reply (priv->conn, msg, candidates_msg_reply_cb, |
|
1179 G_OBJECT (stream), NULL, NULL); |
|
1180 |
|
1181 /* clean up */ |
|
1182 lm_message_unref (msg); |
|
1183 } |
|
1184 |
|
1185 static void |
|
1186 push_native_candidates (GabbleMediaStream *stream) |
|
1187 { |
|
1188 GabbleMediaStreamPrivate *priv; |
|
1189 GPtrArray *candidates; |
|
1190 guint i; |
|
1191 |
|
1192 g_assert (GABBLE_IS_MEDIA_STREAM (stream)); |
|
1193 |
|
1194 priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream); |
|
1195 |
|
1196 if (stream->signalling_state == STREAM_SIG_STATE_NEW || |
|
1197 stream->signalling_state == STREAM_SIG_STATE_REMOVING) |
|
1198 return; |
|
1199 |
|
1200 candidates = g_value_get_boxed (&priv->native_candidates); |
|
1201 |
|
1202 for (i = 0; i < candidates->len; i++) |
|
1203 push_candidate (stream, g_ptr_array_index (candidates, i)); |
|
1204 |
|
1205 g_value_take_boxed (&priv->native_candidates, |
|
1206 dbus_g_type_specialized_construct (TP_TYPE_CANDIDATE_LIST)); |
|
1207 } |
|
1208 |
|
1209 void |
|
1210 _gabble_media_stream_close (GabbleMediaStream *stream) |
|
1211 { |
|
1212 GabbleMediaStreamPrivate *priv; |
|
1213 |
|
1214 g_assert (GABBLE_IS_MEDIA_STREAM (stream)); |
|
1215 |
|
1216 priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream); |
|
1217 |
|
1218 if (!priv->closed) |
|
1219 { |
|
1220 priv->closed = TRUE; |
|
1221 g_signal_emit (stream, signals[CLOSE], 0); |
|
1222 } |
|
1223 } |
|
1224 |
|
1225 gboolean |
|
1226 _gabble_media_stream_post_remote_codecs (GabbleMediaStream *stream, |
|
1227 LmMessage *message, |
|
1228 LmMessageNode *desc_node, |
|
1229 GError **error) |
|
1230 { |
|
1231 GabbleMediaStreamPrivate *priv; |
|
1232 LmMessageNode *node; |
|
1233 GPtrArray *codecs; |
|
1234 |
|
1235 g_assert (GABBLE_IS_MEDIA_STREAM (stream)); |
|
1236 |
|
1237 priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream); |
|
1238 |
|
1239 codecs = g_value_get_boxed (&priv->remote_codecs); |
|
1240 |
|
1241 g_assert (codecs->len == 0); |
|
1242 |
|
1243 for (node = desc_node->children; node; node = node->next) |
|
1244 { |
|
1245 guchar id; |
|
1246 const gchar *name, *str; |
|
1247 guint clockrate, channels; |
|
1248 GHashTable *params; |
|
1249 GValue codec = { 0, }; |
|
1250 |
|
1251 if (g_strdiff (node->name, "payload-type")) |
|
1252 continue; |
|
1253 |
|
1254 /* id of codec */ |
|
1255 str = lm_message_node_get_attribute (node, "id"); |
|
1256 if (str == NULL) |
|
1257 { |
|
1258 g_set_error (error, GABBLE_XMPP_ERROR, XMPP_ERROR_BAD_REQUEST, |
|
1259 "description has no ID"); |
|
1260 return FALSE; |
|
1261 } |
|
1262 |
|
1263 id = atoi(str); |
|
1264 |
|
1265 /* codec name */ |
|
1266 name = lm_message_node_get_attribute (node, "name"); |
|
1267 if (name == NULL) |
|
1268 { |
|
1269 name = ""; |
|
1270 } |
|
1271 |
|
1272 /* clock rate: jingle and newer GTalk */ |
|
1273 str = lm_message_node_get_attribute (node, "clockrate"); /* google */ |
|
1274 if (str == NULL) |
|
1275 str = lm_message_node_get_attribute (node, "rate"); /* jingle */ |
|
1276 |
|
1277 if (str != NULL) |
|
1278 { |
|
1279 clockrate = atoi (str); |
|
1280 } |
|
1281 else |
|
1282 { |
|
1283 clockrate = 0; |
|
1284 } |
|
1285 |
|
1286 /* number of channels: jingle only */ |
|
1287 str = lm_message_node_get_attribute (node, "channels"); |
|
1288 if (str != NULL) |
|
1289 { |
|
1290 channels = atoi (str); |
|
1291 } |
|
1292 else |
|
1293 { |
|
1294 channels = 1; |
|
1295 } |
|
1296 |
|
1297 params = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free); |
|
1298 |
|
1299 /* bitrate: newer GTalk only */ |
|
1300 str = lm_message_node_get_attribute (node, "bitrate"); |
|
1301 if (str != NULL) |
|
1302 { |
|
1303 g_hash_table_insert (params, "bitrate", g_strdup (str)); |
|
1304 } |
|
1305 |
|
1306 g_value_init (&codec, TP_TYPE_CODEC_STRUCT); |
|
1307 g_value_take_boxed (&codec, |
|
1308 dbus_g_type_specialized_construct (TP_TYPE_CODEC_STRUCT)); |
|
1309 |
|
1310 dbus_g_type_struct_set (&codec, |
|
1311 0, id, |
|
1312 1, name, |
|
1313 2, TP_CODEC_MEDIA_TYPE_AUDIO, |
|
1314 3, clockrate, |
|
1315 4, channels, |
|
1316 5, params, |
|
1317 G_MAXUINT); |
|
1318 |
|
1319 g_ptr_array_add (codecs, g_value_get_boxed (&codec)); |
|
1320 } |
|
1321 |
|
1322 _gabble_media_session_debug (priv->session, DEBUG_MSG_INFO, DEBUG_MSG_INFO, "put %d remote codecs from peer into cache", |
|
1323 codecs->len); |
|
1324 |
|
1325 push_remote_codecs (stream); |
|
1326 |
|
1327 return TRUE; |
|
1328 } |
|
1329 |
|
1330 static void |
|
1331 push_remote_codecs (GabbleMediaStream *stream) |
|
1332 { |
|
1333 GabbleMediaStreamPrivate *priv; |
|
1334 GPtrArray *codecs; |
|
1335 |
|
1336 g_assert (GABBLE_IS_MEDIA_STREAM (stream)); |
|
1337 |
|
1338 priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream); |
|
1339 |
|
1340 if (!priv->ready) |
|
1341 return; |
|
1342 |
|
1343 codecs = g_value_get_boxed (&priv->remote_codecs); |
|
1344 if (codecs->len == 0) |
|
1345 return; |
|
1346 |
|
1347 _gabble_media_session_debug (priv->session, DEBUG_MSG_EVENT, "passing %d remote codecs to stream-engine", |
|
1348 codecs->len); |
|
1349 |
|
1350 g_signal_emit (stream, signals[SET_REMOTE_CODECS], 0, codecs); |
|
1351 |
|
1352 g_value_take_boxed (&priv->remote_codecs, |
|
1353 dbus_g_type_specialized_construct (TP_TYPE_CODEC_LIST)); |
|
1354 } |
|
1355 |
|
1356 gboolean |
|
1357 _gabble_media_stream_post_remote_candidates (GabbleMediaStream *stream, |
|
1358 LmMessage *message, |
|
1359 LmMessageNode *transport_node, |
|
1360 GError **error) |
|
1361 { |
|
1362 GabbleMediaStreamPrivate *priv; |
|
1363 LmMessageNode *node; |
|
1364 const gchar *str; |
|
1365 GPtrArray *candidates; |
|
1366 |
|
1367 g_assert (GABBLE_IS_MEDIA_STREAM (stream)); |
|
1368 |
|
1369 priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream); |
|
1370 |
|
1371 candidates = g_value_get_boxed (&priv->remote_candidates); |
|
1372 |
|
1373 for (node = transport_node->children; node; node = node->next) |
|
1374 { |
|
1375 gchar *candidate_id; |
|
1376 const gchar *name, *addr; |
|
1377 guint16 port; |
|
1378 TpMediaStreamProto proto; |
|
1379 gdouble pref; |
|
1380 TpMediaStreamTransportType type; |
|
1381 const gchar *user, *pass; |
|
1382 guchar net, gen; |
|
1383 GValue candidate = { 0, }; |
|
1384 GPtrArray *transports; |
|
1385 GValue transport = { 0, }; |
|
1386 gchar *xml; |
|
1387 |
|
1388 if (g_strdiff (node->name, "candidate")) |
|
1389 continue; |
|
1390 |
|
1391 /* |
|
1392 * Candidate |
|
1393 */ |
|
1394 |
|
1395 /* stream name */ |
|
1396 name = lm_message_node_get_attribute (node, "name"); |
|
1397 if (name == NULL || strcmp (name, "rtp") != 0) |
|
1398 goto FAILURE; |
|
1399 |
|
1400 |
|
1401 /* |
|
1402 * Transport |
|
1403 */ |
|
1404 |
|
1405 /* ip address */ |
|
1406 addr = lm_message_node_get_attribute (node, "address"); |
|
1407 if (addr == NULL) |
|
1408 goto FAILURE; |
|
1409 |
|
1410 /* port */ |
|
1411 str = lm_message_node_get_attribute (node, "port"); |
|
1412 if (str == NULL) |
|
1413 goto FAILURE; |
|
1414 port = atoi (str); |
|
1415 |
|
1416 /* protocol */ |
|
1417 str = lm_message_node_get_attribute (node, "protocol"); |
|
1418 if (str == NULL) |
|
1419 goto FAILURE; |
|
1420 |
|
1421 if (strcmp (str, "udp") == 0) |
|
1422 { |
|
1423 proto = TP_MEDIA_STREAM_PROTO_UDP; |
|
1424 } |
|
1425 else if (strcmp (str, "tcp") == 0) |
|
1426 { |
|
1427 proto = TP_MEDIA_STREAM_PROTO_TCP; |
|
1428 } |
|
1429 else if (strcmp (str, "ssltcp") == 0) |
|
1430 { |
|
1431 _gabble_media_session_debug (priv->session, DEBUG_MSG_WARNING, "%s: ssltcp candidates " |
|
1432 "not yet supported", G_STRFUNC); |
|
1433 continue; |
|
1434 } |
|
1435 else |
|
1436 goto FAILURE; |
|
1437 |
|
1438 /* protocol profile: hardcoded to "AVP" for now */ |
|
1439 |
|
1440 /* preference */ |
|
1441 str = lm_message_node_get_attribute (node, "preference"); |
|
1442 if (str == NULL) |
|
1443 goto FAILURE; |
|
1444 pref = g_ascii_strtod (str, NULL); |
|
1445 |
|
1446 /* type */ |
|
1447 str = lm_message_node_get_attribute (node, "type"); |
|
1448 if (str == NULL) |
|
1449 goto FAILURE; |
|
1450 |
|
1451 if (strcmp (str, "local") == 0) |
|
1452 { |
|
1453 type = TP_MEDIA_STREAM_TRANSPORT_TYPE_LOCAL; |
|
1454 } |
|
1455 else if (strcmp (str, "stun") == 0) |
|
1456 { |
|
1457 type = TP_MEDIA_STREAM_TRANSPORT_TYPE_DERIVED; |
|
1458 } |
|
1459 else if (strcmp (str, "relay") == 0) |
|
1460 { |
|
1461 type = TP_MEDIA_STREAM_TRANSPORT_TYPE_RELAY; |
|
1462 } |
|
1463 else |
|
1464 goto FAILURE; |
|
1465 |
|
1466 /* username */ |
|
1467 user = lm_message_node_get_attribute (node, "username"); |
|
1468 if (user == NULL) |
|
1469 goto FAILURE; |
|
1470 |
|
1471 /* password */ |
|
1472 pass = lm_message_node_get_attribute (node, "password"); |
|
1473 if (pass == NULL) |
|
1474 goto FAILURE; |
|
1475 |
|
1476 /* unknown */ |
|
1477 str = lm_message_node_get_attribute (node, "network"); |
|
1478 if (str == NULL) |
|
1479 goto FAILURE; |
|
1480 net = atoi (str); |
|
1481 |
|
1482 /* unknown */ |
|
1483 str = lm_message_node_get_attribute (node, "generation"); |
|
1484 if (str == NULL) |
|
1485 goto FAILURE; |
|
1486 gen = atoi (str); |
|
1487 |
|
1488 |
|
1489 g_value_init (&transport, TP_TYPE_TRANSPORT_STRUCT); |
|
1490 g_value_take_boxed (&transport, |
|
1491 dbus_g_type_specialized_construct (TP_TYPE_TRANSPORT_STRUCT)); |
|
1492 |
|
1493 dbus_g_type_struct_set (&transport, |
|
1494 0, 1, /* component number */ |
|
1495 1, addr, |
|
1496 2, port, |
|
1497 3, proto, |
|
1498 4, "RTP", |
|
1499 5, "AVP", |
|
1500 6, pref, |
|
1501 7, type, |
|
1502 8, user, |
|
1503 9, pass, |
|
1504 G_MAXUINT); |
|
1505 |
|
1506 transports = g_ptr_array_sized_new (1); |
|
1507 g_ptr_array_add (transports, g_value_get_boxed (&transport)); |
|
1508 |
|
1509 |
|
1510 g_value_init (&candidate, TP_TYPE_CANDIDATE_STRUCT); |
|
1511 g_value_take_boxed (&candidate, |
|
1512 dbus_g_type_specialized_construct (TP_TYPE_CANDIDATE_STRUCT)); |
|
1513 |
|
1514 /* FIXME: is this naming scheme sensible? */ |
|
1515 candidate_id = g_strdup_printf ("R%d", ++priv->remote_candidate_count); |
|
1516 |
|
1517 dbus_g_type_struct_set (&candidate, |
|
1518 0, candidate_id, |
|
1519 1, transports, |
|
1520 G_MAXUINT); |
|
1521 |
|
1522 g_ptr_array_add (candidates, g_value_get_boxed (&candidate)); |
|
1523 |
|
1524 xml = lm_message_node_to_string (node); |
|
1525 _gabble_media_session_debug (priv->session, DEBUG_MSG_INFO, DEBUG_MSG_INFO, "put 1 remote candidate from peer into cache"); |
|
1526 _gabble_media_session_debug (priv->session, DEBUG_MSG_DUMP, " from Jingle XML: [%s%s%s]", |
|
1527 ANSI_BOLD_OFF, xml, ANSI_BOLD_ON); |
|
1528 _gabble_media_session_debug (priv->session, DEBUG_MSG_DUMP, " to Telepathy D-Bus struct: [%s\"%s\", %s[%s1, \"%s\", %d, %s, \"%s\", \"%s\", %f, %s, \"%s\", \"%s\"%s]]", |
|
1529 ANSI_BOLD_OFF, candidate_id, ANSI_BOLD_ON, |
|
1530 ANSI_BOLD_OFF, addr, port, tp_protocols[proto], "RTP", "AVP", pref, tp_transports[type], user, pass, ANSI_BOLD_ON); |
|
1531 g_free (xml); |
|
1532 |
|
1533 g_free (candidate_id); |
|
1534 } |
|
1535 |
|
1536 /*SUCCESS:*/ |
|
1537 push_remote_candidates (stream); |
|
1538 |
|
1539 return TRUE; |
|
1540 |
|
1541 FAILURE: |
|
1542 g_set_error (error, GABBLE_XMPP_ERROR, XMPP_ERROR_BAD_REQUEST, |
|
1543 "unable to parse candidate"); |
|
1544 |
|
1545 return FALSE; |
|
1546 } |
|
1547 |
|
1548 static void |
|
1549 push_remote_candidates (GabbleMediaStream *stream) |
|
1550 { |
|
1551 GabbleMediaStreamPrivate *priv; |
|
1552 GPtrArray *candidates; |
|
1553 guint i; |
|
1554 |
|
1555 g_assert (GABBLE_IS_MEDIA_STREAM (stream)); |
|
1556 |
|
1557 priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream); |
|
1558 |
|
1559 candidates = g_value_get_boxed (&priv->remote_candidates); |
|
1560 |
|
1561 if (candidates->len == 0) |
|
1562 return; |
|
1563 |
|
1564 if (!priv->ready) |
|
1565 return; |
|
1566 |
|
1567 for (i = 0; i < candidates->len; i++) |
|
1568 { |
|
1569 GValueArray *candidate = g_ptr_array_index (candidates, i); |
|
1570 const gchar *candidate_id; |
|
1571 const GPtrArray *transports; |
|
1572 |
|
1573 candidate_id = g_value_get_string (g_value_array_get_nth (candidate, 0)); |
|
1574 transports = g_value_get_boxed (g_value_array_get_nth (candidate, 1)); |
|
1575 |
|
1576 _gabble_media_session_debug (priv->session, DEBUG_MSG_EVENT, "passing 1 remote candidate " |
|
1577 "to stream-engine"); |
|
1578 |
|
1579 g_signal_emit (stream, signals[ADD_REMOTE_CANDIDATE], 0, |
|
1580 candidate_id, transports); |
|
1581 } |
|
1582 |
|
1583 g_value_take_boxed (&priv->remote_candidates, |
|
1584 dbus_g_type_specialized_construct (TP_TYPE_CANDIDATE_LIST)); |
|
1585 } |
|
1586 |
|
1587 static void |
|
1588 push_playing (GabbleMediaStream *stream) |
|
1589 { |
|
1590 GabbleMediaStreamPrivate *priv; |
|
1591 |
|
1592 g_assert (GABBLE_IS_MEDIA_STREAM (stream)); |
|
1593 |
|
1594 priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream); |
|
1595 |
|
1596 if (!priv->ready) |
|
1597 return; |
|
1598 |
|
1599 _gabble_media_session_debug (priv->session, DEBUG_MSG_INFO, DEBUG_MSG_INFO, "stream %s emitting SetStreamPlaying(%s)", |
|
1600 stream->name, stream->playing ? "true" : "false"); |
|
1601 |
|
1602 g_signal_emit (stream, signals[SET_STREAM_PLAYING], 0, stream->playing); |
|
1603 } |
|
1604 |
|
1605 static void |
|
1606 push_sending (GabbleMediaStream *stream) |
|
1607 { |
|
1608 GabbleMediaStreamPrivate *priv; |
|
1609 |
|
1610 g_assert (GABBLE_IS_MEDIA_STREAM (stream)); |
|
1611 |
|
1612 priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream); |
|
1613 |
|
1614 if (!priv->ready) |
|
1615 return; |
|
1616 |
|
1617 _gabble_media_session_debug (priv->session, DEBUG_MSG_INFO, DEBUG_MSG_INFO, "stream %s emitting SetStreamSending(%s)", |
|
1618 stream->name, priv->sending ? "true" : "false"); |
|
1619 |
|
1620 g_signal_emit (stream, signals[SET_STREAM_SENDING], 0, priv->sending); |
|
1621 } |
|
1622 |
|
1623 /* |
|
1624 * oh sweet g_hash_table_foreach how beautiful thou be'st |
|
1625 * |
|
1626 * _\ / ^/ |
|
1627 * \/ \// 7_ __ |
|
1628 * ( 7 ) (__) (__) |
|
1629 * ^\\ |/__/___/ |
|
1630 * \\/_/ | <-- TP-cable kindly provided by Mika N. |
|
1631 * \ / O |
|
1632 * || /|\ |
|
1633 * || / \ |
|
1634 * || |
|
1635 * ____||_____________ |
|
1636 */ |
|
1637 |
|
1638 typedef struct { |
|
1639 GabbleMediaStreamPrivate *priv; |
|
1640 LmMessageNode *pt_node; |
|
1641 } CodecParamsFromTpContext; |
|
1642 |
|
1643 //#ifndef EMULATOR |
|
1644 static const gchar *video_codec_params[] = { |
|
1645 "x", "y", "width", "height", "layer", "transparent", |
|
1646 }; |
|
1647 //#endif |
|
1648 |
|
1649 static void |
|
1650 codec_params_from_tp_foreach (gpointer key, gpointer value, gpointer user_data) |
|
1651 { |
|
1652 CodecParamsFromTpContext *ctx = user_data; |
|
1653 GabbleMediaStreamPrivate *priv = ctx->priv; |
|
1654 const gchar *pname = key, *pvalue = value; |
|
1655 |
|
1656 if (priv->media_type == TP_CODEC_MEDIA_TYPE_AUDIO) |
|
1657 { |
|
1658 if (priv->mode == MODE_GOOGLE && strcmp (pname, "bitrate") == 0) |
|
1659 { |
|
1660 lm_message_node_set_attribute (ctx->pt_node, pname, pvalue); |
|
1661 return; |
|
1662 } |
|
1663 } |
|
1664 else if (priv->mode == MODE_JINGLE) |
|
1665 { |
|
1666 gint i; |
|
1667 |
|
1668 for (i = 0; video_codec_params[i] != NULL; i++) |
|
1669 { |
|
1670 if (strcmp (pname, video_codec_params[i]) == 0) |
|
1671 { |
|
1672 lm_message_node_set_attribute (ctx->pt_node, pname, pvalue); |
|
1673 return; |
|
1674 } |
|
1675 } |
|
1676 } |
|
1677 |
|
1678 gabble_debug (DEBUG_FLAG, "ignoring %s=%s for %s %s stream", pname, pvalue, |
|
1679 (priv->mode == MODE_JINGLE) ? "jingle" : "google", |
|
1680 (priv->media_type == TP_CODEC_MEDIA_TYPE_AUDIO) ? "audio" : "video"); |
|
1681 } |
|
1682 |
|
1683 LmMessageNode * |
|
1684 _gabble_media_stream_add_content_node (GabbleMediaStream *stream, |
|
1685 LmMessageNode *session_node) |
|
1686 { |
|
1687 GabbleMediaStreamPrivate *priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream); |
|
1688 LmMessageNode *node = session_node; |
|
1689 |
|
1690 /* add our content node to it if in jingle mode */ |
|
1691 if (priv->mode == MODE_JINGLE) |
|
1692 { |
|
1693 node = lm_message_node_add_child (session_node, "content", NULL); |
|
1694 lm_message_node_set_attribute (node, "name", stream->name); |
|
1695 |
|
1696 if (priv->session->initiator == stream->initiator) |
|
1697 lm_message_node_set_attribute (node, "creator", "initiator"); |
|
1698 else |
|
1699 lm_message_node_set_attribute (node, "creator", "responder"); |
|
1700 } |
|
1701 |
|
1702 return node; |
|
1703 } |
|
1704 |
|
1705 void |
|
1706 _gabble_media_stream_content_node_add_description (GabbleMediaStream *stream, |
|
1707 LmMessageNode *content_node) |
|
1708 { |
|
1709 GabbleMediaStreamPrivate *priv; |
|
1710 const GPtrArray *codecs; |
|
1711 LmMessageNode *desc_node; |
|
1712 guint i; |
|
1713 const gchar *xmlns; |
|
1714 |
|
1715 g_assert (GABBLE_IS_MEDIA_STREAM (stream)); |
|
1716 |
|
1717 priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream); |
|
1718 |
|
1719 codecs = g_value_get_boxed (&priv->native_codecs); |
|
1720 |
|
1721 desc_node = lm_message_node_add_child (content_node, "description", NULL); |
|
1722 |
|
1723 if (priv->mode == MODE_GOOGLE) |
|
1724 xmlns = NS_GOOGLE_SESSION_PHONE; |
|
1725 else if (priv->media_type == TP_CODEC_MEDIA_TYPE_VIDEO) |
|
1726 xmlns = NS_JINGLE_DESCRIPTION_VIDEO; |
|
1727 else |
|
1728 xmlns = NS_JINGLE_DESCRIPTION_AUDIO; |
|
1729 |
|
1730 lm_message_node_set_attribute (desc_node, "xmlns", xmlns); |
|
1731 |
|
1732 for (i = 0; i < codecs->len; i++) |
|
1733 { |
|
1734 GValue codec = { 0, }; |
|
1735 guint id, clock_rate, channels; |
|
1736 gchar *name, buf[16]; |
|
1737 GHashTable *params; |
|
1738 LmMessageNode *pt_node; |
|
1739 CodecParamsFromTpContext ctx; |
|
1740 |
|
1741 g_value_init (&codec, TP_TYPE_CODEC_STRUCT); |
|
1742 g_value_set_static_boxed (&codec, g_ptr_array_index (codecs, i)); |
|
1743 |
|
1744 dbus_g_type_struct_get (&codec, |
|
1745 0, &id, |
|
1746 1, &name, |
|
1747 3, &clock_rate, |
|
1748 4, &channels, |
|
1749 5, ¶ms, |
|
1750 G_MAXUINT); |
|
1751 |
|
1752 /* create a sub-node called "payload-type" and fill it */ |
|
1753 pt_node = lm_message_node_add_child (desc_node, "payload-type", NULL); |
|
1754 |
|
1755 /* id: required */ |
|
1756 sprintf (buf, "%u", id); |
|
1757 lm_message_node_set_attribute (pt_node, "id", buf); |
|
1758 |
|
1759 /* name: optional */ |
|
1760 if (*name != '\0') |
|
1761 { |
|
1762 lm_message_node_set_attribute (pt_node, "name", name); |
|
1763 } |
|
1764 |
|
1765 /* clock rate: optional */ |
|
1766 if (clock_rate != 0) |
|
1767 { |
|
1768 sprintf (buf, "%u", clock_rate); |
|
1769 lm_message_node_set_attribute (pt_node, |
|
1770 (priv->mode == MODE_GOOGLE) ? "clockrate" : "rate", buf); |
|
1771 } |
|
1772 |
|
1773 /* number of channels: optional, jingle only */ |
|
1774 /* FIXME: is it? */ |
|
1775 if (channels != 0 && priv->mode == MODE_JINGLE) |
|
1776 { |
|
1777 sprintf (buf, "%u", channels); |
|
1778 lm_message_node_set_attribute (pt_node, "channels", buf); |
|
1779 } |
|
1780 |
|
1781 /* parse the optional params */ |
|
1782 ctx.priv = priv; |
|
1783 ctx.pt_node = pt_node; |
|
1784 g_hash_table_foreach (params, codec_params_from_tp_foreach, &ctx); |
|
1785 |
|
1786 /* clean up */ |
|
1787 g_free (name); |
|
1788 g_hash_table_destroy (params); |
|
1789 } |
|
1790 } |
|
1791 |
|
1792 LmMessageNode * |
|
1793 _gabble_media_stream_content_node_add_transport (GabbleMediaStream *stream, |
|
1794 LmMessageNode *content_node) |
|
1795 { |
|
1796 GabbleMediaStreamPrivate *priv; |
|
1797 LmMessageNode *node; |
|
1798 |
|
1799 g_assert (GABBLE_IS_MEDIA_STREAM (stream)); |
|
1800 |
|
1801 priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream); |
|
1802 |
|
1803 if (priv->mode != MODE_JINGLE) |
|
1804 return content_node; |
|
1805 |
|
1806 node = lm_message_node_add_child (content_node, "transport", NULL); |
|
1807 |
|
1808 lm_message_node_set_attribute (node, "xmlns", NS_GOOGLE_TRANSPORT_P2P); |
|
1809 |
|
1810 return node; |
|
1811 } |
|
1812 |
|
1813 void |
|
1814 _gabble_media_stream_update_sending (GabbleMediaStream *stream, |
|
1815 gboolean start_sending) |
|
1816 { |
|
1817 GabbleMediaStreamPrivate *priv; |
|
1818 gboolean new_sending; |
|
1819 |
|
1820 g_assert (GABBLE_IS_MEDIA_STREAM (stream)); |
|
1821 |
|
1822 priv = GABBLE_MEDIA_STREAM_GET_PRIVATE (stream); |
|
1823 |
|
1824 new_sending = |
|
1825 ((stream->combined_direction & TP_MEDIA_STREAM_DIRECTION_SEND) != 0); |
|
1826 |
|
1827 if (priv->sending == new_sending) |
|
1828 return; |
|
1829 |
|
1830 if (new_sending && !start_sending) |
|
1831 return; |
|
1832 |
|
1833 priv->sending = new_sending; |
|
1834 push_sending (stream); |
|
1835 } |
|
1836 |