1 /*
2 * Farstream - Farstream libnice Stream Transmitter
3 *
4 * Copyright 2007 Collabora Ltd.
5 * @author: Olivier Crete <olivier.crete@collabora.co.uk>
6 * Copyright 2007 Nokia Corp.
7 *
8 * fs-nice-stream-transmitter.c - A Farstream libnice stream transmitter
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25
26 /**
27 * SECTION:fs-nice-stream-transmitter
28 * @short_description: A stream transmitter object for ICE using libnice
29 * @see_also: #FsRawUdpStreamTransmitter
30 *
31 */
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36
37 #include "fs-nice-stream-transmitter.h"
38 #include "fs-nice-transmitter.h"
39 #include "fs-nice-agent.h"
40
41 #include <farstream/fs-conference.h>
42
43 #include <gst/gst.h>
44
45 #include <string.h>
46 #include <sys/types.h>
47
48 #define GST_CAT_DEFAULT fs_nice_transmitter_debug
49
50 /* Signals */
51 enum
52 {
53 LAST_SIGNAL
54 };
55
56 /* props */
57 enum
58 {
59 PROP_0,
60 PROP_SENDING,
61 PROP_PREFERRED_LOCAL_CANDIDATES,
62 PROP_STUN_IP,
63 PROP_STUN_PORT,
64 PROP_CONTROLLING_MODE,
65 PROP_STREAM_ID,
66 PROP_COMPATIBILITY_MODE,
67 PROP_ASSOCIATE_ON_SOURCE,
68 PROP_RELAY_INFO,
69 PROP_MIN_PORT,
70 PROP_MAX_PORT,
71 PROP_ICE_TCP,
72 PROP_ICE_UDP,
73 PROP_RELIABLE,
74 PROP_DEBUG,
75 PROP_SEND_COMPONENT_MUX
76 };
77
78 struct _FsNiceStreamTransmitterPrivate
79 {
80 FsNiceTransmitter *transmitter;
81
82 FsNiceAgent *agent;
83
84 guint stream_id;
85
86 guint min_port;
87 guint max_port;
88
89 gchar *stun_ip;
90 guint stun_port;
91
92 gboolean controlling_mode;
93 gboolean ice_udp;
94 gboolean ice_tcp;
95 gboolean reliable;
96 gboolean send_component_mux;
97
98 guint compatibility_mode;
99
100 GMutex mutex;
101
102 GList *preferred_local_candidates;
103
104 gulong state_changed_handler_id;
105 gulong gathering_done_handler_id;
106 gulong new_selected_pair_handler_id;
107 gulong new_candidate_handler_id;
108
109 gulong tos_changed_handler_id;
110
111 GPtrArray *relay_info;
112
113 volatile gint associate_on_source;
114
115 gboolean *component_has_been_ready; /* only from NiceAgent main thread */
116
117 /* Everything below is protected by the mutex */
118
119 gboolean sending;
120
121 gboolean forced_candidates;
122 GList *remote_candidates;
123 GList *local_candidates;
124
125 /* These are fixed and must be identical in the latest draft */
126 gchar *username;
127 gchar *password;
128
129 gboolean gathered;
130
131 NiceGstStream *gststream;
132 };
133
134 #define FS_NICE_STREAM_TRANSMITTER_GET_PRIVATE(o) \
135 (G_TYPE_INSTANCE_GET_PRIVATE ((o), FS_TYPE_NICE_STREAM_TRANSMITTER, \
136 FsNiceStreamTransmitterPrivate))
137
138 #define FS_NICE_STREAM_TRANSMITTER_LOCK(o) g_mutex_lock (&(o)->priv->mutex)
139 #define FS_NICE_STREAM_TRANSMITTER_UNLOCK(o) g_mutex_unlock (&(o)->priv->mutex)
140
141
142 static void fs_nice_stream_transmitter_class_init (FsNiceStreamTransmitterClass *klass);
143 static void fs_nice_stream_transmitter_init (FsNiceStreamTransmitter *self);
144 static void fs_nice_stream_transmitter_dispose (GObject *object);
145 static void fs_nice_stream_transmitter_finalize (GObject *object);
146
147 static void fs_nice_stream_transmitter_get_property (GObject *object,
148 guint prop_id,
149 GValue *value,
150 GParamSpec *pspec);
151 static void fs_nice_stream_transmitter_set_property (GObject *object,
152 guint prop_id,
153 const GValue *value,
154 GParamSpec *pspec);
155
156 static gboolean fs_nice_stream_transmitter_add_remote_candidates (
157 FsStreamTransmitter *streamtransmitter, GList *candidates,
158 GError **error);
159 static gboolean fs_nice_stream_transmitter_force_remote_candidates (
160 FsStreamTransmitter *streamtransmitter,
161 GList *remote_candidates,
162 GError **error);
163 static gboolean fs_nice_stream_transmitter_gather_local_candidates (
164 FsStreamTransmitter *streamtransmitter,
165 GError **error);
166 static void fs_nice_stream_transmitter_stop (
167 FsStreamTransmitter *streamtransmitter);
168
169 static void agent_state_changed (NiceAgent *agent,
170 guint stream_id,
171 guint component_id,
172 guint state,
173 gpointer user_data);
174 static void agent_gathering_done (NiceAgent *agent, guint stream_id,
175 gpointer user_data);
176 static void agent_new_selected_pair (NiceAgent *agent,
177 guint stream_id,
178 guint component_id,
179 NiceCandidate *l_candidate,
180 NiceCandidate *r_candidate,
181 gpointer user_data);
182 static void agent_new_candidate (NiceAgent *agent,
183 NiceCandidate *candidate,
184 gpointer user_data);
185
186 static GstPadProbeReturn known_buffer_have_buffer_handler (GstPad *pad,
187 GstPadProbeInfo *info,
188 gpointer user_data);
189
190
191 static GObjectClass *parent_class = NULL;
192 // static guint signals[LAST_SIGNAL] = { 0 };
193
194 static GType type = 0;
195
196
197 GType
fs_nice_stream_transmitter_get_type(void)198 fs_nice_stream_transmitter_get_type (void)
199 {
200 return type;
201 }
202
203 GType
fs_nice_stream_transmitter_register_type(FsPlugin * module G_GNUC_UNUSED)204 fs_nice_stream_transmitter_register_type (FsPlugin *module G_GNUC_UNUSED)
205 {
206 static const GTypeInfo info = {
207 sizeof (FsNiceStreamTransmitterClass),
208 NULL,
209 NULL,
210 (GClassInitFunc) fs_nice_stream_transmitter_class_init,
211 NULL,
212 NULL,
213 sizeof (FsNiceStreamTransmitter),
214 0,
215 (GInstanceInitFunc) fs_nice_stream_transmitter_init
216 };
217
218 type = g_type_register_static (FS_TYPE_STREAM_TRANSMITTER,
219 "FsNiceStreamTransmitter", &info, 0);
220
221 return type;
222 }
223
224 static void
fs_nice_stream_transmitter_class_init(FsNiceStreamTransmitterClass * klass)225 fs_nice_stream_transmitter_class_init (FsNiceStreamTransmitterClass *klass)
226 {
227 GObjectClass *gobject_class = (GObjectClass *) klass;
228 FsStreamTransmitterClass *streamtransmitterclass =
229 FS_STREAM_TRANSMITTER_CLASS (klass);
230
231 parent_class = g_type_class_peek_parent (klass);
232
233 gobject_class->set_property = fs_nice_stream_transmitter_set_property;
234 gobject_class->get_property = fs_nice_stream_transmitter_get_property;
235 gobject_class->dispose = fs_nice_stream_transmitter_dispose;
236 gobject_class->finalize = fs_nice_stream_transmitter_finalize;
237
238 streamtransmitterclass->add_remote_candidates =
239 fs_nice_stream_transmitter_add_remote_candidates;
240 streamtransmitterclass->force_remote_candidates =
241 fs_nice_stream_transmitter_force_remote_candidates;
242 streamtransmitterclass->gather_local_candidates =
243 fs_nice_stream_transmitter_gather_local_candidates;
244 streamtransmitterclass->stop =
245 fs_nice_stream_transmitter_stop;
246
247 g_type_class_add_private (klass, sizeof (FsNiceStreamTransmitterPrivate));
248
249 g_object_class_override_property (gobject_class, PROP_SENDING, "sending");
250 g_object_class_override_property (gobject_class,
251 PROP_PREFERRED_LOCAL_CANDIDATES, "preferred-local-candidates");
252 g_object_class_override_property (gobject_class, PROP_ASSOCIATE_ON_SOURCE,
253 "associate-on-source");
254
255 g_object_class_install_property (gobject_class, PROP_STUN_IP,
256 g_param_spec_string (
257 "stun-ip",
258 "STUN server",
259 "The STUN server used to obtain server-reflexive candidates",
260 NULL,
261 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
262
263 g_object_class_install_property (gobject_class, PROP_STUN_PORT,
264 g_param_spec_uint (
265 "stun-port",
266 "STUN server port",
267 "The STUN server used to obtain server-reflexive candidates",
268 0, 65536,
269 3478,
270 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
271
272 g_object_class_install_property (gobject_class, PROP_CONTROLLING_MODE,
273 g_param_spec_boolean (
274 "controlling-mode",
275 "ICE controlling mode",
276 "Whether the agent is in controlling mode",
277 TRUE,
278 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
279
280 g_object_class_install_property (gobject_class, PROP_ICE_UDP,
281 g_param_spec_boolean (
282 "ice-udp",
283 "ICE UDP",
284 "Whether the agent gathers UDP candidates",
285 TRUE,
286 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
287
288 g_object_class_install_property (gobject_class, PROP_ICE_TCP,
289 g_param_spec_boolean (
290 "ice-tcp",
291 "ICE TCP",
292 "Whether the agent gathers TCP candidates",
293 TRUE,
294 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
295
296 g_object_class_install_property (gobject_class, PROP_RELIABLE,
297 g_param_spec_boolean (
298 "reliable",
299 "reliable mode",
300 "Whether the agent is reliable",
301 FALSE,
302 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
303
304 g_object_class_install_property (gobject_class, PROP_STREAM_ID,
305 g_param_spec_uint (
306 "stream-id",
307 "The id of the stream",
308 "The id of the stream according to libnice",
309 0, G_MAXINT,
310 0,
311 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
312
313 g_object_class_install_property (gobject_class, PROP_COMPATIBILITY_MODE,
314 g_param_spec_uint (
315 "compatibility-mode",
316 "The compability-mode",
317 "The id of the stream according to libnice",
318 NICE_COMPATIBILITY_DRAFT19, NICE_COMPATIBILITY_LAST,
319 NICE_COMPATIBILITY_DRAFT19,
320 G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
321
322 /**
323 * FsNiceStreamTransmitter:relay-info:
324 *
325 * This is a #GPtrArray containing one or more #GstStructure.
326 *
327 * The fields in the structure are:
328 * <informaltable>
329 * <tr><th colspan="2">Required</th></tr>
330 * <tr>
331 * <td nowrap="nowrap">(gchar*)</td>
332 * <td nowrap="nowrap">ip</td>
333 * <td>The IP address of the TURN server</td>
334 * </tr>
335 * <tr>
336 * <td nowrap="nowrap">(guint)</td>
337 * <td nowrap="nowrap">port</td>
338 * <td>The port of the TURN server</td>
339 * </tr>
340 * <tr>
341 * <td nowrap="nowrap">(gchar*)</td>
342 * <td nowrap="nowrap">username</td>
343 * </tr>
344 * <tr>
345 * <td nowrap="nowrap">(gchar*)</td>
346 * <td nowrap="nowrap">password</td>
347 * </tr>
348 * <tr><th colspan="2">Optional</th></tr>
349 * <tr>
350 * <td nowrap="nowrap">(gchar *)</td>
351 * <td nowrap="nowrap">relay-type</td>
352 * <td>The type of TURN server, can use "udp", "tcp" or "tls".
353 * Defaults to "udp" if not specified.</td>
354 * </tr>
355 * <tr>
356 * <td nowrap="nowrap">(guint)</td>
357 * <td nowrap="nowrap">component</td>
358 * <td>The component this TURN server and creditials will be used for.
359 * If no component is specified, it will be used for all components where
360 * no per-component details were specified.
361 * This is useful if you want to specify different short term creditial
362 * username/password combinations for Google and MSN compatibility modes.
363 * </td>
364 * </tr>
365 * </informaltable>
366 *
367 * Example:
368 * |[
369 GPtrArray *relay_info = g_ptr_array_new_full (1, (GDestroyNotify) gst_structure_free);
370 g_ptr_array_add (relay_info,
371 gst_structure_new ("aa",
372 "ip", G_TYPE_STRING, "127.0.0.1",
373 "port", G_TYPE_UINT, 7654,
374 "username", G_TYPE_STRING, "blah",
375 "password", G_TYPE_STRING, "blah2",
376 "relay-type", G_TYPE_STRING, "udp",
377 NULL));
378 |]
379 *
380 */
381
382 g_object_class_install_property (gobject_class, PROP_RELAY_INFO,
383 g_param_spec_boxed (
384 "relay-info",
385 "Information for the TURN server",
386 "ip/port/username/password/relay-type/component of the TURN servers"
387 " in a GPtrArray of GstStructures",
388 G_TYPE_PTR_ARRAY,
389 G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
390
391 g_object_class_install_property (gobject_class, PROP_DEBUG,
392 g_param_spec_boolean (
393 "debug",
394 "Enable debug messages",
395 "Whether the agent should enable libnice and stun debug messages",
396 FALSE,
397 G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
398
399 g_object_class_install_property (gobject_class, PROP_MIN_PORT,
400 g_param_spec_uint (
401 "min-port",
402 "Minimal listen port",
403 "Minimal port number for allocating host candidates."
404 " 0 means use any port",
405 0, 65535,
406 0,
407 G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
408
409 g_object_class_install_property (gobject_class, PROP_MAX_PORT,
410 g_param_spec_uint (
411 "max-port",
412 "Maximal listen port",
413 "Maximal port number for allocating host candidates."
414 " It should apply that min-port < max-port; otherwise, any port is"
415 " used, just as when the value is 0",
416 0, 65535,
417 0,
418 G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
419
420 g_object_class_install_property (gobject_class, PROP_SEND_COMPONENT_MUX,
421 g_param_spec_boolean (
422 "send-component-mux",
423 "Send component mux",
424 "Whether to mux all components on the same component as component 1",
425 FALSE,
426 G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
427
428 }
429
430 static void
fs_nice_stream_transmitter_init(FsNiceStreamTransmitter * self)431 fs_nice_stream_transmitter_init (FsNiceStreamTransmitter *self)
432 {
433 /* member init */
434 self->priv = FS_NICE_STREAM_TRANSMITTER_GET_PRIVATE (self);
435
436 self->priv->sending = TRUE;
437 g_mutex_init (&self->priv->mutex);
438
439 self->priv->controlling_mode = TRUE;
440 self->priv->ice_udp = TRUE;
441 self->priv->ice_tcp = TRUE;
442 self->priv->reliable = TRUE;
443 }
444
445 static void
fs_nice_stream_transmitter_dispose(GObject * object)446 fs_nice_stream_transmitter_dispose (GObject *object)
447 {
448 FsNiceStreamTransmitter *self = FS_NICE_STREAM_TRANSMITTER (object);
449
450 fs_nice_stream_transmitter_stop (FS_STREAM_TRANSMITTER_CAST (object));
451
452 FS_NICE_STREAM_TRANSMITTER_LOCK (self);
453 if (self->priv->state_changed_handler_id)
454 g_signal_handler_disconnect (self->priv->agent->agent,
455 self->priv->state_changed_handler_id);
456 self->priv->state_changed_handler_id = 0;
457
458 if (self->priv->gathering_done_handler_id)
459 g_signal_handler_disconnect (self->priv->agent->agent,
460 self->priv->gathering_done_handler_id);
461 self->priv->gathering_done_handler_id = 0;
462
463 if (self->priv->new_selected_pair_handler_id)
464 g_signal_handler_disconnect (self->priv->agent->agent,
465 self->priv->new_selected_pair_handler_id);
466 self->priv->new_selected_pair_handler_id = 0;
467
468 if (self->priv->new_candidate_handler_id)
469 g_signal_handler_disconnect (self->priv->agent->agent,
470 self->priv->new_candidate_handler_id);
471 self->priv->new_candidate_handler_id = 0;
472
473 if (self->priv->tos_changed_handler_id)
474 g_signal_handler_disconnect (self->priv->transmitter,
475 self->priv->tos_changed_handler_id);
476 self->priv->tos_changed_handler_id = 0;
477
478 if (self->priv->agent)
479 {
480 g_object_unref (self->priv->agent);
481 self->priv->agent = NULL;
482 }
483 FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
484
485 if (self->priv->transmitter)
486 {
487 g_object_unref (self->priv->transmitter);
488 self->priv->transmitter = NULL;
489 }
490
491 parent_class->dispose (object);
492 }
493
494 static void
fs_nice_stream_transmitter_stop(FsStreamTransmitter * streamtransmitter)495 fs_nice_stream_transmitter_stop (FsStreamTransmitter *streamtransmitter)
496 {
497 FsNiceStreamTransmitter *self =
498 FS_NICE_STREAM_TRANSMITTER (streamtransmitter);
499 NiceGstStream *gststream;
500 guint stream_id;
501
502
503 FS_NICE_STREAM_TRANSMITTER_LOCK (self);
504 gststream = self->priv->gststream;
505 self->priv->gststream = NULL;
506 stream_id = self->priv->stream_id;
507 /* We can't unset the stream id because it gets messy fast, just leave it as
508 * is, all calls should fail anyway
509 */
510 FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
511
512 if (gststream)
513 fs_nice_transmitter_free_gst_stream (self->priv->transmitter, gststream);
514 if (stream_id)
515 nice_agent_remove_stream (self->priv->agent->agent, stream_id);
516 }
517
518
519 static void
fs_nice_stream_transmitter_finalize(GObject * object)520 fs_nice_stream_transmitter_finalize (GObject *object)
521 {
522 FsNiceStreamTransmitter *self = FS_NICE_STREAM_TRANSMITTER (object);
523
524 fs_candidate_list_destroy (self->priv->preferred_local_candidates);
525
526 fs_candidate_list_destroy (self->priv->remote_candidates);
527 fs_candidate_list_destroy (self->priv->local_candidates);
528
529 if (self->priv->relay_info)
530 g_ptr_array_unref (self->priv->relay_info);
531
532 g_free (self->priv->stun_ip);
533
534 g_mutex_clear (&self->priv->mutex);
535
536 g_free (self->priv->username);
537 g_free (self->priv->password);
538
539 g_free (self->priv->component_has_been_ready);
540
541 parent_class->finalize (object);
542 }
543
544 static void
fs_nice_stream_transmitter_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)545 fs_nice_stream_transmitter_get_property (GObject *object,
546 guint prop_id,
547 GValue *value,
548 GParamSpec *pspec)
549 {
550 FsNiceStreamTransmitter *self = FS_NICE_STREAM_TRANSMITTER (object);
551
552 switch (prop_id)
553 {
554 case PROP_SENDING:
555 FS_NICE_STREAM_TRANSMITTER_LOCK (self);
556 g_value_set_boolean (value, self->priv->sending);
557 FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
558 break;
559 case PROP_PREFERRED_LOCAL_CANDIDATES:
560 g_value_set_boxed (value, self->priv->preferred_local_candidates);
561 break;
562 case PROP_STUN_IP:
563 if (self->priv->agent)
564 g_object_get_property (G_OBJECT (self->priv->agent->agent),
565 g_param_spec_get_name (pspec), value);
566 else
567 g_value_set_string (value, self->priv->stun_ip);
568 break;
569 case PROP_STUN_PORT:
570 if (self->priv->agent)
571 g_object_get_property (G_OBJECT (self->priv->agent->agent),
572 g_param_spec_get_name (pspec), value);
573 else
574 g_value_set_uint (value, self->priv->stun_port);
575 break;
576 case PROP_CONTROLLING_MODE:
577 if (self->priv->agent)
578 g_object_get_property (G_OBJECT (self->priv->agent->agent),
579 g_param_spec_get_name (pspec), value);
580 else
581 g_value_set_boolean (value, self->priv->controlling_mode);
582 break;
583 case PROP_ICE_UDP:
584 if (self->priv->agent)
585 g_object_get_property (G_OBJECT (self->priv->agent->agent),
586 g_param_spec_get_name (pspec), value);
587 else
588 g_value_set_boolean (value, self->priv->ice_udp);
589 break;
590 case PROP_ICE_TCP:
591 if (self->priv->agent)
592 g_object_get_property (G_OBJECT (self->priv->agent->agent),
593 g_param_spec_get_name (pspec), value);
594 else
595 g_value_set_boolean (value, self->priv->ice_tcp);
596 break;
597 case PROP_RELIABLE:
598 if (self->priv->agent)
599 g_object_get_property (G_OBJECT (self->priv->agent->agent),
600 g_param_spec_get_name (pspec), value);
601 else
602 g_value_set_boolean (value, self->priv->reliable);
603 break;
604 case PROP_STREAM_ID:
605 FS_NICE_STREAM_TRANSMITTER_LOCK (self);
606 g_value_set_uint (value, self->priv->stream_id);
607 FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
608 break;
609 case PROP_COMPATIBILITY_MODE:
610 g_value_set_uint (value, self->priv->compatibility_mode);
611 break;
612 case PROP_ASSOCIATE_ON_SOURCE:
613 g_value_set_boolean (value,
614 g_atomic_int_get (&self->priv->associate_on_source));
615 break;
616 case PROP_SEND_COMPONENT_MUX:
617 g_value_set_boolean (value, self->priv->send_component_mux);
618 break;
619 default:
620 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
621 break;
622 }
623 }
624
625 static void
fs_nice_stream_transmitter_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)626 fs_nice_stream_transmitter_set_property (GObject *object,
627 guint prop_id,
628 const GValue *value,
629 GParamSpec *pspec)
630 {
631 FsNiceStreamTransmitter *self = FS_NICE_STREAM_TRANSMITTER (object);
632
633 switch (prop_id)
634 {
635 case PROP_SENDING:
636 FS_NICE_STREAM_TRANSMITTER_LOCK (self);
637 self->priv->sending = g_value_get_boolean (value);
638 if (self->priv->gststream)
639 fs_nice_transmitter_set_sending (self->priv->transmitter,
640 self->priv->gststream, g_value_get_boolean (value));
641 FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
642 break;
643 case PROP_PREFERRED_LOCAL_CANDIDATES:
644 self->priv->preferred_local_candidates = g_value_dup_boxed (value);
645 break;
646 case PROP_STUN_IP:
647 self->priv->stun_ip = g_value_dup_string (value);
648 break;
649 case PROP_STUN_PORT:
650 self->priv->stun_port = g_value_get_uint (value);
651 break;
652 case PROP_CONTROLLING_MODE:
653 self->priv->controlling_mode = g_value_get_boolean (value);
654 if (self->priv->transmitter && self->priv->agent)
655 g_object_set_property (G_OBJECT (self->priv->agent->agent),
656 g_param_spec_get_name (pspec), value);
657 break;
658 case PROP_ICE_UDP:
659 self->priv->ice_udp = g_value_get_boolean (value);
660 if (self->priv->transmitter && self->priv->agent)
661 g_object_set_property (G_OBJECT (self->priv->agent->agent),
662 g_param_spec_get_name (pspec), value);
663 break;
664 case PROP_ICE_TCP:
665 self->priv->ice_tcp = g_value_get_boolean (value);
666 if (self->priv->transmitter && self->priv->agent)
667 g_object_set_property (G_OBJECT (self->priv->agent->agent),
668 g_param_spec_get_name (pspec), value);
669 break;
670 case PROP_RELIABLE:
671 self->priv->reliable = g_value_get_boolean (value);
672 break;
673 case PROP_COMPATIBILITY_MODE:
674 self->priv->compatibility_mode = g_value_get_uint (value);
675 break;
676 case PROP_ASSOCIATE_ON_SOURCE:
677 g_atomic_int_set (&self->priv->associate_on_source,
678 g_value_get_boolean (value));
679 break;
680 case PROP_RELAY_INFO:
681 self->priv->relay_info = g_value_dup_boxed (value);
682 break;
683 case PROP_MIN_PORT:
684 self->priv->min_port = g_value_get_uint (value);
685 break;
686 case PROP_MAX_PORT:
687 self->priv->max_port = g_value_get_uint (value);
688 break;
689 case PROP_DEBUG:
690 if (g_value_get_boolean (value)) {
691 nice_debug_enable (TRUE);
692 } else {
693 nice_debug_disable (TRUE);
694 }
695 break;
696 case PROP_SEND_COMPONENT_MUX:
697 self->priv->send_component_mux = g_value_get_boolean (value);
698 if (self->priv->gststream != NULL)
699 fs_nice_transmitter_set_send_component_mux (self->priv->transmitter,
700 self->priv->gststream, self->priv->send_component_mux);
701 break;
702
703 default:
704 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
705 break;
706 }
707 }
708
709
710 static NiceCandidateType
fs_candidate_type_to_nice_candidate_type(FsCandidateType type)711 fs_candidate_type_to_nice_candidate_type (FsCandidateType type)
712 {
713 switch (type)
714 {
715 case FS_CANDIDATE_TYPE_HOST:
716 return NICE_CANDIDATE_TYPE_HOST;
717 case FS_CANDIDATE_TYPE_SRFLX:
718 return NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE;
719 case FS_CANDIDATE_TYPE_PRFLX:
720 return NICE_CANDIDATE_TYPE_PEER_REFLEXIVE;
721 case FS_CANDIDATE_TYPE_RELAY:
722 return NICE_CANDIDATE_TYPE_RELAYED;
723 default:
724 GST_WARNING ("Invalid candidate type %d, defaulting to type host", type);
725 return NICE_CANDIDATE_TYPE_HOST;
726 }
727 }
728
729 static NiceCandidateTransport
fs_network_protocol_to_nice_candidate_protocol(FsNetworkProtocol proto)730 fs_network_protocol_to_nice_candidate_protocol (FsNetworkProtocol proto)
731 {
732 switch (proto)
733 {
734 case FS_NETWORK_PROTOCOL_UDP:
735 return NICE_CANDIDATE_TRANSPORT_UDP;
736 case FS_NETWORK_PROTOCOL_TCP_ACTIVE:
737 return NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE;
738 case FS_NETWORK_PROTOCOL_TCP_PASSIVE:
739 return NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE;
740 case FS_NETWORK_PROTOCOL_TCP_SO:
741 return NICE_CANDIDATE_TRANSPORT_TCP_SO;
742 default:
743 GST_WARNING ("Invalid Fs network protocol type %u", proto);
744 return NICE_CANDIDATE_TRANSPORT_UDP;
745 }
746 }
747
748 static NiceCandidate *
fs_candidate_to_nice_candidate(FsNiceStreamTransmitter * self,FsCandidate * candidate)749 fs_candidate_to_nice_candidate (FsNiceStreamTransmitter *self,
750 FsCandidate *candidate)
751 {
752 NiceCandidate *nc = nice_candidate_new (
753 fs_candidate_type_to_nice_candidate_type (candidate->type));
754
755 nc->transport =
756 fs_network_protocol_to_nice_candidate_protocol (candidate->proto);
757 nc->priority = candidate->priority;
758 nc->stream_id = self->priv->stream_id;
759 nc->component_id = candidate->component_id;
760 if (candidate->foundation != NULL)
761 strncpy (nc->foundation, candidate->foundation,
762 NICE_CANDIDATE_MAX_FOUNDATION - 1);
763
764 nc->username = g_strdup(candidate->username);
765 nc->password = g_strdup(candidate->password);
766
767
768 if (candidate->ip == NULL)
769 goto error;
770 if (!nice_address_set_from_string (&nc->addr, candidate->ip))
771 goto error;
772 nice_address_set_port (&nc->addr, candidate->port);
773
774 if (candidate->base_ip && candidate->base_port)
775 {
776 if (!nice_address_set_from_string (&nc->base_addr, candidate->base_ip))
777 goto error;
778 nice_address_set_port (&nc->base_addr, candidate->base_port);
779 }
780
781 return nc;
782
783 error:
784 nice_candidate_free (nc);
785 return NULL;
786 }
787
788
789 static gboolean
fs_nice_stream_transmitter_add_remote_candidates(FsStreamTransmitter * streamtransmitter,GList * candidates,GError ** error)790 fs_nice_stream_transmitter_add_remote_candidates (
791 FsStreamTransmitter *streamtransmitter,
792 GList *candidates,
793 GError **error)
794 {
795 FsNiceStreamTransmitter *self =
796 FS_NICE_STREAM_TRANSMITTER (streamtransmitter);
797 GList *item;
798 GSList *nice_candidates = NULL;
799 gint c;
800 const gchar *username;
801 const gchar *password;
802
803 if (!candidates)
804 {
805 GST_DEBUG ("NULL candidates passed, lets do an ICE restart");
806 FS_NICE_STREAM_TRANSMITTER_LOCK (self);
807 if (self->priv->remote_candidates)
808 fs_candidate_list_destroy (self->priv->remote_candidates);
809 self->priv->remote_candidates = NULL;
810 self->priv->forced_candidates = FALSE;
811 g_free (self->priv->username);
812 g_free (self->priv->password);
813 self->priv->username = NULL;
814 self->priv->password = NULL;
815 FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
816 nice_agent_restart (self->priv->agent->agent);
817 return TRUE;
818 }
819
820 FS_NICE_STREAM_TRANSMITTER_LOCK (self);
821
822 username = self->priv->username;
823 password = self->priv->password;
824
825 /* Validate candidates */
826 for (item = candidates;
827 item;
828 item = g_list_next (item))
829 {
830 FsCandidate *candidate = item->data;
831
832 if (!candidate->ip)
833 {
834 FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
835 g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
836 "Candidate MUST have an IP address");
837 return FALSE;
838 }
839
840 if (candidate->component_id == 0 ||
841 candidate->component_id > self->priv->transmitter->components)
842 {
843 FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
844 g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
845 "Candidate MUST have a component id between 1 and %d, %d is invalid",
846 self->priv->transmitter->components, candidate->component_id);
847 return FALSE;
848 }
849
850 if (candidate->type == FS_CANDIDATE_TYPE_MULTICAST)
851 {
852 FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
853 g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
854 "libnice transmitter does not accept multicast candidates");
855 return FALSE;
856 }
857
858 if (!candidate->username)
859 {
860 FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
861 g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
862 "Invalid remote candidates passed, does not have a username");
863 return FALSE;
864 }
865
866 if (self->priv->compatibility_mode != NICE_COMPATIBILITY_GOOGLE &&
867 !candidate->password)
868 {
869 FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
870 g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
871 "Invalid remote candidates passed, does not have a password");
872 return FALSE;
873 }
874
875 if (self->priv->compatibility_mode != NICE_COMPATIBILITY_GOOGLE &&
876 self->priv->compatibility_mode != NICE_COMPATIBILITY_MSN &&
877 self->priv->compatibility_mode != NICE_COMPATIBILITY_OC2007)
878 {
879 if (!username)
880 {
881 username = candidate->username;
882 }
883 else if (strcmp (username, candidate->username))
884 {
885 FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
886 g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
887 "Invalid remote candidates passed, does not have the right"
888 " username");
889 return FALSE;
890 }
891
892 if (!password)
893 {
894 password = candidate->password;
895 }
896 else if (strcmp (password, candidate->password))
897 {
898 FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
899 g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
900 "Invalid remote candidates passed, does not have the right"
901 " password");
902 return FALSE;
903 }
904 }
905 }
906
907 if (!self->priv->username)
908 self->priv->username = g_strdup (username);
909 if (!self->priv->password)
910 self->priv->password = g_strdup (password);
911
912 if (self->priv->forced_candidates)
913 {
914 FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
915 g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
916 "Candidates have been forced, can't set remote candidates");
917 return FALSE;
918 }
919
920 if (!self->priv->gathered)
921 {
922 self->priv->remote_candidates = g_list_concat (
923 self->priv->remote_candidates,
924 fs_candidate_list_copy (candidates));
925 FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
926 return TRUE;
927 }
928
929 if (self->priv->compatibility_mode != NICE_COMPATIBILITY_GOOGLE &&
930 self->priv->compatibility_mode != NICE_COMPATIBILITY_MSN &&
931 self->priv->compatibility_mode != NICE_COMPATIBILITY_OC2007)
932 {
933 username = g_strdup (username);
934 password = g_strdup (password);
935 FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
936
937 if (!nice_agent_set_remote_credentials (self->priv->agent->agent,
938 self->priv->stream_id, username, password))
939 {
940 g_free ((gchar*) username);
941 g_free ((gchar*) password);
942 g_set_error (error, FS_ERROR, FS_ERROR_INTERNAL,
943 "Could not set the security credentials");
944 return FALSE;
945 }
946 g_free ((gchar*) username);
947 g_free ((gchar*) password);
948 }
949 else
950 {
951 FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
952 }
953
954 for (c = 1; c <= self->priv->transmitter->components; c++)
955 {
956 for (item = candidates;
957 item;
958 item = g_list_next (item))
959 {
960 FsCandidate *candidate = item->data;
961
962 if (candidate->component_id == c)
963 {
964 NiceCandidate *nc = fs_candidate_to_nice_candidate (self, candidate);
965
966 if (!nc)
967 goto error;
968
969 nice_candidates = g_slist_append (nice_candidates, nc);
970 }
971 }
972
973 nice_agent_set_remote_candidates (self->priv->agent->agent,
974 self->priv->stream_id, c, nice_candidates);
975
976 g_slist_foreach (nice_candidates, (GFunc)nice_candidate_free, NULL);
977 g_slist_free (nice_candidates);
978 nice_candidates = NULL;
979 }
980
981 return TRUE;
982 error:
983
984 g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
985 "Invalid remote candidates passed");
986 g_slist_foreach (nice_candidates, (GFunc) nice_candidate_free, NULL);
987 g_slist_free (nice_candidates);
988
989 return FALSE;
990 }
991
992 static gboolean
fs_nice_stream_transmitter_force_remote_candidates_act(FsNiceStreamTransmitter * self,GList * remote_candidates)993 fs_nice_stream_transmitter_force_remote_candidates_act (
994 FsNiceStreamTransmitter *self,
995 GList *remote_candidates)
996 {
997 gboolean res = TRUE;
998 GList *item = NULL;
999
1000 for (item = remote_candidates;
1001 item && res;
1002 item = g_list_next (item))
1003 {
1004 FsCandidate *candidate = item->data;
1005 NiceCandidate *nc = fs_candidate_to_nice_candidate (self, candidate);
1006
1007 res &= nice_agent_set_selected_remote_candidate (self->priv->agent->agent,
1008 self->priv->stream_id, candidate->component_id, nc);
1009 nice_candidate_free (nc);
1010 }
1011
1012 return res;
1013 }
1014
1015 static gboolean
fs_nice_stream_transmitter_force_remote_candidates(FsStreamTransmitter * streamtransmitter,GList * remote_candidates,GError ** error)1016 fs_nice_stream_transmitter_force_remote_candidates (
1017 FsStreamTransmitter *streamtransmitter,
1018 GList *remote_candidates,
1019 GError **error)
1020 {
1021 FsNiceStreamTransmitter *self =
1022 FS_NICE_STREAM_TRANSMITTER (streamtransmitter);
1023 GList *item = NULL;
1024 gboolean res = TRUE;
1025 gboolean *done;
1026
1027 done = g_new0(gboolean, self->priv->transmitter->components);
1028
1029 memset (done, 0, self->priv->transmitter->components * sizeof (gboolean));
1030
1031 if (self->priv->stream_id == 0)
1032 {
1033 g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
1034 "Can not call this function before gathering local candidates");
1035 res = FALSE;
1036 goto out;
1037 }
1038
1039 /* First lets check that we have valid candidates */
1040
1041 for (item = remote_candidates; item; item = g_list_next (item))
1042 {
1043 FsCandidate *candidate = item->data;
1044
1045 if (candidate->component_id < 1 ||
1046 candidate->component_id > self->priv->transmitter->components)
1047 {
1048 g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
1049 "The component on this candidate is wrong");
1050 res = FALSE;
1051 goto out;
1052 }
1053
1054 if (done[candidate->component_id-1])
1055 {
1056 g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
1057 "You can set only one candidate per component");
1058 res = FALSE;
1059 goto out;
1060 }
1061 done[candidate->component_id-1] = TRUE;
1062 }
1063
1064 FS_NICE_STREAM_TRANSMITTER_LOCK (self);
1065 self->priv->forced_candidates = TRUE;
1066 if (self->priv->gathered)
1067 {
1068 FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
1069 res = fs_nice_stream_transmitter_force_remote_candidates_act (self,
1070 remote_candidates);
1071 }
1072 else
1073 {
1074 if (self->priv->remote_candidates)
1075 fs_candidate_list_destroy (self->priv->remote_candidates);
1076 self->priv->remote_candidates = fs_candidate_list_copy (remote_candidates);
1077 FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
1078 }
1079
1080 if (!res)
1081 g_set_error (error, FS_ERROR, FS_ERROR_INTERNAL,
1082 "Unknown error while selecting remote candidates");
1083
1084 out:
1085 g_free(done);
1086 return res;
1087 }
1088
1089 static FsCandidateType
nice_candidate_type_to_fs_candidate_type(NiceCandidateType type)1090 nice_candidate_type_to_fs_candidate_type (NiceCandidateType type)
1091 {
1092 switch (type)
1093 {
1094 case NICE_CANDIDATE_TYPE_HOST:
1095 return FS_CANDIDATE_TYPE_HOST;
1096 case NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE:
1097 return FS_CANDIDATE_TYPE_SRFLX;
1098 case NICE_CANDIDATE_TYPE_PEER_REFLEXIVE:
1099 return FS_CANDIDATE_TYPE_PRFLX;
1100 case NICE_CANDIDATE_TYPE_RELAYED:
1101 return FS_CANDIDATE_TYPE_RELAY;
1102 default:
1103 GST_WARNING ("Invalid candidate type %d, defaulting to type host", type);
1104 return FS_CANDIDATE_TYPE_HOST;
1105 }
1106 }
1107
1108 static FsNetworkProtocol
nice_candidate_transport_to_fs_network_protocol(NiceCandidateTransport trans)1109 nice_candidate_transport_to_fs_network_protocol (NiceCandidateTransport trans)
1110 {
1111 switch (trans)
1112 {
1113 case NICE_CANDIDATE_TRANSPORT_UDP:
1114 return FS_NETWORK_PROTOCOL_UDP;
1115 case NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE:
1116 return FS_NETWORK_PROTOCOL_TCP_PASSIVE;
1117 case NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE:
1118 return FS_NETWORK_PROTOCOL_TCP_ACTIVE;
1119 case NICE_CANDIDATE_TRANSPORT_TCP_SO:
1120 return FS_NETWORK_PROTOCOL_TCP_SO;
1121 default:
1122 GST_WARNING ("Invalid Nice network transport type %u", trans);
1123 return FS_NETWORK_PROTOCOL_UDP;
1124 }
1125 }
1126
1127 static FsCandidate *
nice_candidate_to_fs_candidate(NiceAgent * agent,NiceCandidate * nicecandidate,gboolean local)1128 nice_candidate_to_fs_candidate (NiceAgent *agent, NiceCandidate *nicecandidate,
1129 gboolean local)
1130 {
1131 FsCandidate *fscandidate;
1132 gchar *ipaddr = g_malloc (INET6_ADDRSTRLEN);
1133
1134 nice_address_to_string (&nicecandidate->addr, ipaddr);
1135
1136 fscandidate = fs_candidate_new (
1137 nicecandidate->foundation,
1138 nicecandidate->component_id,
1139 nice_candidate_type_to_fs_candidate_type (nicecandidate->type),
1140 nice_candidate_transport_to_fs_network_protocol (
1141 nicecandidate->transport),
1142 ipaddr,
1143 nice_address_get_port (&nicecandidate->addr));
1144
1145 if (nice_address_is_valid (&nicecandidate->base_addr) &&
1146 nicecandidate->type != NICE_CANDIDATE_TYPE_HOST)
1147 {
1148 nice_address_to_string (&nicecandidate->base_addr, ipaddr);
1149 fscandidate->base_ip = ipaddr;
1150 fscandidate->base_port = nice_address_get_port (&nicecandidate->base_addr);
1151 }
1152 else
1153 {
1154 g_free (ipaddr);
1155 ipaddr = NULL;
1156 }
1157
1158 fscandidate->username = g_strdup (nicecandidate->username);
1159 fscandidate->password = g_strdup (nicecandidate->password);
1160 fscandidate->priority = nicecandidate->priority;
1161
1162 if (local && fscandidate->username == NULL && fscandidate->password == NULL)
1163 {
1164 gchar *username = NULL, *password = NULL;
1165 nice_agent_get_local_credentials (agent, nicecandidate->stream_id,
1166 &username, &password);
1167 fscandidate->username = username;
1168 fscandidate->password = password;
1169
1170 if (username == NULL || password == NULL)
1171 {
1172 GST_WARNING ("The stream has no credentials??");
1173 }
1174 }
1175
1176
1177
1178 return fscandidate;
1179 }
1180
1181
1182 static gboolean
candidate_list_are_equal(GList * list1,GList * list2)1183 candidate_list_are_equal (GList *list1, GList *list2)
1184 {
1185 for (;
1186 list1 && list2;
1187 list1 = list1->next, list2 = list2->next)
1188 {
1189 FsCandidate *cand1 = list1->data;
1190 FsCandidate *cand2 = list2->data;
1191
1192 if (strcmp (cand1->ip, cand2->ip))
1193 return FALSE;
1194 }
1195
1196 return TRUE;
1197 }
1198
1199 static void
weak_agent_removed(gpointer user_data,GObject * where_the_object_was)1200 weak_agent_removed (gpointer user_data, GObject *where_the_object_was)
1201 {
1202 GList *agents = NULL;
1203 FsParticipant *participant = user_data;
1204
1205 FS_PARTICIPANT_DATA_LOCK (participant);
1206
1207 agents = g_object_get_data (G_OBJECT (participant), "nice-agents");
1208 agents = g_list_remove (agents, where_the_object_was);
1209 g_object_set_data (G_OBJECT (participant), "nice-agents", agents);
1210
1211 FS_PARTICIPANT_DATA_UNLOCK (participant);
1212
1213 g_object_unref (participant);
1214 }
1215
1216 static gboolean
fs_nice_stream_transmitter_set_relay_info(FsNiceStreamTransmitter * self,const GstStructure * s,guint component_id,GError ** error)1217 fs_nice_stream_transmitter_set_relay_info (FsNiceStreamTransmitter *self,
1218 const GstStructure *s, guint component_id, GError **error)
1219 {
1220 const gchar *username, *password, *ip;
1221 const gchar *relay_type_string;
1222 NiceRelayType relay_type = NICE_RELAY_TYPE_TURN_UDP;
1223 guint port;
1224 gboolean has_port;
1225
1226 ip = gst_structure_get_string (s, "ip");
1227 has_port = gst_structure_get_uint (s, "port", &port);
1228 username = gst_structure_get_string (s, "username");
1229 password = gst_structure_get_string (s, "password");
1230 relay_type_string = gst_structure_get_string (s, "relay-type");
1231
1232 if (!ip || !has_port || !username || !password || port > 65535)
1233 {
1234 g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
1235 "Need to pass an ip, port, username and password for a relay");
1236 return FALSE;
1237 }
1238
1239 if (relay_type_string)
1240 {
1241 if (!g_ascii_strcasecmp(relay_type_string, "tcp"))
1242 relay_type = NICE_RELAY_TYPE_TURN_TCP;
1243 else if (!g_ascii_strcasecmp(relay_type_string, "tls"))
1244 relay_type = NICE_RELAY_TYPE_TURN_TLS;
1245 }
1246
1247 nice_agent_set_relay_info(self->priv->agent->agent,
1248 self->priv->stream_id, component_id, ip, port, username, password,
1249 relay_type);
1250
1251 return TRUE;
1252 }
1253
1254
1255
1256 static void
tos_changed(GObject * transmitter,GParamSpec * param,FsNiceStreamTransmitter * self)1257 tos_changed (GObject *transmitter, GParamSpec *param,
1258 FsNiceStreamTransmitter *self)
1259 {
1260 guint tos;
1261
1262 g_object_get (transmitter, "tos", &tos, NULL);
1263 nice_agent_set_stream_tos (self->priv->agent->agent, self->priv->stream_id,
1264 tos);
1265 }
1266
1267 static gboolean
fs_nice_stream_transmitter_build(FsNiceStreamTransmitter * self,FsParticipant * participant,GError ** error)1268 fs_nice_stream_transmitter_build (FsNiceStreamTransmitter *self,
1269 FsParticipant *participant,
1270 GError **error)
1271 {
1272 GList *item;
1273 GList *agents = NULL;
1274 FsNiceAgent *agent = NULL;
1275 gint i;
1276
1277 /* Before going any further, check that the list of candidates are ok */
1278
1279 for (item = g_list_first (self->priv->preferred_local_candidates);
1280 item;
1281 item = g_list_next (item))
1282 {
1283 FsCandidate *cand = item->data;
1284
1285 if (cand->ip == NULL)
1286 {
1287 g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
1288 "You have to set an ip on your preferred candidate");
1289 return FALSE;
1290 }
1291
1292 if (cand->port || cand->component_id)
1293 {
1294 g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
1295 "You can not set a port or component id"
1296 " for the preferred nice candidate");
1297 return FALSE;
1298 }
1299
1300 if (cand->type != FS_CANDIDATE_TYPE_HOST)
1301 {
1302 g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
1303 "You can only set preferred candidates of type host");
1304 return FALSE;
1305 }
1306 }
1307
1308 /* Now if we have a relayinfo, lets verify that its ok */
1309
1310 if (self->priv->relay_info)
1311 {
1312 for (i = 0; i < self->priv->relay_info->len; i++)
1313 {
1314 const GstStructure *s = g_ptr_array_index (self->priv->relay_info, i);
1315
1316 if (!s)
1317 {
1318 g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
1319 "Element %d of the relay-info GPtrArray is NULL",
1320 i);
1321 return FALSE;
1322 }
1323
1324 if (!gst_structure_has_field_typed (s, "ip", G_TYPE_STRING))
1325 {
1326 g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
1327 "Element %d of the relay-info does not have an ip as a string", i);
1328 return FALSE;
1329 }
1330
1331 if (!gst_structure_has_field_typed (s, "port", G_TYPE_UINT))
1332 {
1333 g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
1334 "Element %d of the relay-info does not have a port as a guint", i);
1335 return FALSE;
1336 }
1337
1338 if (gst_structure_has_field (s, "username") &&
1339 !gst_structure_has_field_typed (s, "username", G_TYPE_STRING))
1340 {
1341 g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
1342 "Element %d of the relay-info has a username that is not a string",
1343 i);
1344 return FALSE;
1345 }
1346
1347 if (gst_structure_has_field (s, "password") &&
1348 !gst_structure_has_field_typed (s, "password", G_TYPE_STRING))
1349 {
1350 g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
1351 "Element %d of the relay-info has a password that is not a string",
1352 i);
1353 return FALSE;
1354 }
1355
1356 if (gst_structure_has_field (s, "relay-type") &&
1357 !gst_structure_has_field_typed (s, "relay-type",
1358 G_TYPE_STRING))
1359 {
1360 g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
1361 "Element %d of the relay-info a relay-type"
1362 " that is not a string", i);
1363 return FALSE;
1364 }
1365
1366 if (gst_structure_has_field (s, "component") &&
1367 !gst_structure_has_field_typed (s, "component",
1368 G_TYPE_UINT))
1369 {
1370 g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
1371 "Element %d of the relay-info has a component that is not a uint",
1372 i);
1373 return FALSE;
1374 }
1375 }
1376 }
1377
1378
1379 /* First find if there is already a matching agent */
1380
1381 FS_PARTICIPANT_DATA_LOCK (participant);
1382
1383 agents = g_object_get_data (G_OBJECT (participant), "nice-agents");
1384
1385 for (item = g_list_first (agents);
1386 item;
1387 item = g_list_next (item))
1388 {
1389 guint stun_port;
1390 gchar *stun_server;
1391 guint compatibility;
1392
1393 agent = item->data;
1394
1395 g_object_get (agent->agent,
1396 "stun-server", &stun_server,
1397 "stun-server-port", &stun_port,
1398 "compatibility", &compatibility,
1399 NULL);
1400
1401 /*
1402 * Check if the agent matches our requested criteria
1403 */
1404 if (compatibility == self->priv->compatibility_mode &&
1405 stun_port == self->priv->stun_port &&
1406 (stun_server == self->priv->stun_ip ||
1407 (stun_server && self->priv->stun_ip &&
1408 !strcmp (stun_server, self->priv->stun_ip))))
1409 {
1410 GList *prefs = NULL;
1411
1412 g_object_get (G_OBJECT (agent),
1413 "preferred-local-candidates", &prefs,
1414 NULL);
1415
1416 if (candidate_list_are_equal (prefs,
1417 self->priv->preferred_local_candidates))
1418 {
1419 fs_candidate_list_destroy (prefs);
1420 g_free (stun_server);
1421 break;
1422 }
1423 fs_candidate_list_destroy (prefs);
1424 }
1425 g_free (stun_server);
1426 }
1427
1428
1429 /* In this case we need to build a new agent */
1430 if (item == NULL)
1431 {
1432 agent = fs_nice_agent_new (self->priv->compatibility_mode,
1433 self->priv->preferred_local_candidates, self->priv->reliable,
1434 error);
1435
1436 if (!agent)
1437 return FALSE;
1438
1439 if (self->priv->stun_ip && self->priv->stun_port)
1440 g_object_set (agent->agent,
1441 "stun-server", self->priv->stun_ip,
1442 "stun-server-port", self->priv->stun_port,
1443 NULL);
1444
1445 g_object_set (agent->agent,
1446 "controlling-mode", self->priv->controlling_mode,
1447 "ice-udp", self->priv->ice_udp,
1448 "ice-tcp", self->priv->ice_tcp,
1449 NULL);
1450
1451 agents = g_list_prepend (agents, agent);
1452 g_object_set_data (G_OBJECT (participant), "nice-agents", agents);
1453 g_object_weak_ref (G_OBJECT (agent), weak_agent_removed, participant);
1454 g_object_ref (participant);
1455
1456 self->priv->agent = agent;
1457 } else {
1458 self->priv->agent = g_object_ref (agent);
1459 }
1460
1461 FS_PARTICIPANT_DATA_UNLOCK (participant);
1462
1463 self->priv->component_has_been_ready = g_new0 (gboolean,
1464 self->priv->transmitter->components);
1465
1466 self->priv->stream_id = nice_agent_add_stream (
1467 self->priv->agent->agent,
1468 self->priv->transmitter->components);
1469
1470 if (self->priv->stream_id == 0)
1471 {
1472 g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
1473 "Could not create libnice stream");
1474 return FALSE;
1475 }
1476
1477 /* if we have a relay- info, lets set it */
1478 if (self->priv->relay_info)
1479 {
1480 gint c;
1481 for (c = 1; c <= self->priv->transmitter->components; c++)
1482 {
1483 gboolean relay_info_set = FALSE;
1484
1485 for (i = 0; i < self->priv->relay_info->len; i++)
1486 {
1487 const GstStructure *s = g_ptr_array_index (self->priv->relay_info, i);
1488 guint component_id;
1489
1490 if (gst_structure_get_uint (s, "component", &component_id) &&
1491 component_id == c)
1492 {
1493 if (!fs_nice_stream_transmitter_set_relay_info (self, s, c, error))
1494 return FALSE;
1495 relay_info_set = TRUE;
1496 }
1497 }
1498
1499 if (!relay_info_set)
1500 {
1501 for (i = 0; i < self->priv->relay_info->len; i++)
1502 {
1503 const GstStructure *s = g_ptr_array_index (self->priv->relay_info, i);
1504
1505 if (!gst_structure_has_field (s, "component"))
1506 if (!fs_nice_stream_transmitter_set_relay_info (self, s, c, error))
1507 return FALSE;
1508 }
1509 }
1510 }
1511 }
1512
1513 /* Set a port range if it has been specified. */
1514 if (self->priv->min_port && (self->priv->min_port < self->priv->max_port))
1515 {
1516 gint c;
1517 for (c = 1; c <= self->priv->transmitter->components; c++)
1518 {
1519 nice_agent_set_port_range (self->priv->agent->agent,
1520 self->priv->stream_id, c, self->priv->min_port, self->priv->max_port);
1521 }
1522 }
1523
1524 self->priv->state_changed_handler_id = g_signal_connect_object (agent->agent,
1525 "component-state-changed", G_CALLBACK (agent_state_changed), self, 0);
1526 self->priv->gathering_done_handler_id = g_signal_connect_object (agent->agent,
1527 "candidate-gathering-done", G_CALLBACK (agent_gathering_done), self, 0);
1528 self->priv->new_selected_pair_handler_id = g_signal_connect_object (
1529 agent->agent, "new-selected-pair-full",
1530 G_CALLBACK (agent_new_selected_pair),
1531 self, 0);
1532 self->priv->new_candidate_handler_id = g_signal_connect_object (agent->agent,
1533 "new-candidate-full", G_CALLBACK (agent_new_candidate), self, 0);
1534 self->priv->tos_changed_handler_id = g_signal_connect_object (
1535 self->priv->transmitter, "notify::tos", G_CALLBACK (tos_changed), self,
1536 0);
1537
1538 tos_changed (G_OBJECT (self->priv->transmitter), NULL, self);
1539
1540 self->priv->gststream = fs_nice_transmitter_add_gst_stream (
1541 self->priv->transmitter,
1542 self->priv->agent->agent,
1543 self->priv->stream_id,
1544 known_buffer_have_buffer_handler, self,
1545 error);
1546 if (self->priv->gststream == NULL)
1547 return FALSE;
1548
1549 fs_nice_transmitter_set_send_component_mux (self->priv->transmitter,
1550 self->priv->gststream, self->priv->send_component_mux);
1551
1552 GST_DEBUG ("Created a stream with %u components",
1553 self->priv->transmitter->components);
1554
1555 return TRUE;
1556 }
1557
1558 static gboolean
fs_nice_stream_transmitter_gather_local_candidates(FsStreamTransmitter * streamtransmitter,GError ** error)1559 fs_nice_stream_transmitter_gather_local_candidates (
1560 FsStreamTransmitter *streamtransmitter,
1561 GError **error)
1562 {
1563 FsNiceStreamTransmitter *self =
1564 FS_NICE_STREAM_TRANSMITTER (streamtransmitter);
1565
1566 GST_DEBUG ("Stream %u started", self->priv->stream_id);
1567
1568 nice_agent_gather_candidates (self->priv->agent->agent,
1569 self->priv->stream_id);
1570
1571 return TRUE;
1572 }
1573
1574 static FsStreamState
nice_component_state_to_fs_stream_state(NiceComponentState state)1575 nice_component_state_to_fs_stream_state (NiceComponentState state)
1576 {
1577 switch (state)
1578 {
1579 case NICE_COMPONENT_STATE_DISCONNECTED:
1580 return FS_STREAM_STATE_DISCONNECTED;
1581 case NICE_COMPONENT_STATE_GATHERING:
1582 return FS_STREAM_STATE_GATHERING;
1583 case NICE_COMPONENT_STATE_CONNECTING:
1584 return FS_STREAM_STATE_CONNECTING;
1585 case NICE_COMPONENT_STATE_CONNECTED:
1586 return FS_STREAM_STATE_CONNECTED;
1587 case NICE_COMPONENT_STATE_READY:
1588 return FS_STREAM_STATE_READY;
1589 case NICE_COMPONENT_STATE_FAILED:
1590 return FS_STREAM_STATE_FAILED;
1591 default:
1592 GST_ERROR ("Invalid state %u", state);
1593 return FS_STREAM_STATE_FAILED;
1594 }
1595 }
1596
1597 struct state_changed_signal_data
1598 {
1599 FsNiceStreamTransmitter *self;
1600 guint component_id;
1601 FsStreamState fs_state;
1602 };
1603
1604 static void
free_state_changed_signal_data(gpointer user_data)1605 free_state_changed_signal_data (gpointer user_data)
1606 {
1607 struct state_changed_signal_data *data = user_data;
1608 g_object_unref (data->self);
1609 g_slice_free (struct state_changed_signal_data, data);
1610 }
1611
1612 static gboolean
state_changed_signal_idle(gpointer userdata)1613 state_changed_signal_idle (gpointer userdata)
1614 {
1615 struct state_changed_signal_data *data = userdata;
1616
1617 g_signal_emit_by_name (data->self, "state-changed", data->component_id,
1618 data->fs_state);
1619 return FALSE;
1620 }
1621
1622 static void
agent_state_changed(NiceAgent * agent,guint stream_id,guint component_id,guint state,gpointer user_data)1623 agent_state_changed (NiceAgent *agent,
1624 guint stream_id,
1625 guint component_id,
1626 guint state,
1627 gpointer user_data)
1628 {
1629 FsNiceStreamTransmitter *self = FS_NICE_STREAM_TRANSMITTER (user_data);
1630 FsStreamState fs_state;
1631 struct state_changed_signal_data *data;
1632
1633 if (stream_id != self->priv->stream_id)
1634 return;
1635
1636 g_return_if_fail (component_id > 0 &&
1637 component_id <= self->priv->transmitter->components);
1638
1639 /* Ignore failed until we've connected, never time out because
1640 * of the dribbling case, more candidates could come later
1641 */
1642 if (state == NICE_COMPONENT_STATE_FAILED &&
1643 !self->priv->component_has_been_ready[component_id - 1])
1644 return;
1645 else if (state == NICE_COMPONENT_STATE_READY)
1646 self->priv->component_has_been_ready[component_id - 1] = TRUE;
1647
1648 fs_state = nice_component_state_to_fs_stream_state (state);
1649 data = g_slice_new (struct state_changed_signal_data);
1650
1651 GST_DEBUG ("Stream: %u Component %u has state %u",
1652 self->priv->stream_id, component_id, state);
1653
1654 data->self = g_object_ref (self);
1655 data->component_id = component_id;
1656 data->fs_state = fs_state;
1657 fs_nice_agent_add_idle (self->priv->agent, state_changed_signal_idle,
1658 data, free_state_changed_signal_data);
1659
1660 if (fs_state >= FS_STREAM_STATE_CONNECTED)
1661 {
1662 FS_NICE_STREAM_TRANSMITTER_LOCK (self);
1663 if (self->priv->gststream)
1664 fs_nice_transmitter_request_keyunit (self->priv->transmitter,
1665 self->priv->gststream, component_id);
1666 FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
1667 }
1668 }
1669
1670
1671 struct candidate_signal_data
1672 {
1673 FsNiceStreamTransmitter *self;
1674 const gchar *signal_name;
1675 FsCandidate *candidate1;
1676 FsCandidate *candidate2;
1677 };
1678
1679 static void
free_candidate_signal_data(gpointer user_data)1680 free_candidate_signal_data (gpointer user_data)
1681 {
1682 struct candidate_signal_data *data = user_data;
1683 fs_candidate_destroy (data->candidate1);
1684 if (data->candidate2)
1685 fs_candidate_destroy (data->candidate2);
1686 g_object_unref (data->self);
1687 g_slice_free (struct candidate_signal_data, data);
1688 }
1689
1690 static gboolean
agent_candidate_signal_idle(gpointer userdata)1691 agent_candidate_signal_idle (gpointer userdata)
1692 {
1693 struct candidate_signal_data *data = userdata;
1694
1695 g_signal_emit_by_name (data->self, data->signal_name, data->candidate1,
1696 data->candidate2);
1697 return FALSE;
1698 }
1699
1700
1701 static void
agent_new_selected_pair(NiceAgent * agent,guint stream_id,guint component_id,NiceCandidate * l_candidate,NiceCandidate * r_candidate,gpointer user_data)1702 agent_new_selected_pair (NiceAgent *agent,
1703 guint stream_id,
1704 guint component_id,
1705 NiceCandidate *l_candidate,
1706 NiceCandidate *r_candidate,
1707 gpointer user_data)
1708 {
1709 FsNiceStreamTransmitter *self = FS_NICE_STREAM_TRANSMITTER (user_data);
1710 FsCandidate *local = NULL;
1711 FsCandidate *remote = NULL;
1712 struct candidate_signal_data *data;
1713
1714 if (stream_id != self->priv->stream_id)
1715 return;
1716
1717 local = nice_candidate_to_fs_candidate (agent, l_candidate, TRUE);
1718 remote = nice_candidate_to_fs_candidate (agent, r_candidate, FALSE);
1719
1720 data = g_slice_new (struct candidate_signal_data);
1721 data->self = g_object_ref (self);
1722 data->signal_name = "new-active-candidate-pair";
1723 data->candidate1 = local;
1724 data->candidate2 = remote;
1725 fs_nice_agent_add_idle (self->priv->agent, agent_candidate_signal_idle,
1726 data, free_candidate_signal_data);
1727 }
1728
1729 static void
agent_new_candidate(NiceAgent * agent,NiceCandidate * candidate,gpointer user_data)1730 agent_new_candidate (NiceAgent *agent,
1731 NiceCandidate *candidate,
1732 gpointer user_data)
1733 {
1734 FsNiceStreamTransmitter *self = FS_NICE_STREAM_TRANSMITTER (user_data);
1735 FsCandidate *fscandidate = NULL;
1736
1737 if (candidate->stream_id != self->priv->stream_id)
1738 return;
1739
1740 GST_DEBUG ("New candidate found");
1741
1742 fscandidate = nice_candidate_to_fs_candidate (agent, candidate, TRUE);
1743
1744 FS_NICE_STREAM_TRANSMITTER_LOCK (self);
1745 if (!self->priv->gathered)
1746 {
1747 /* Nice doesn't do connchecks while gathering, so don't tell the upper
1748 * layers about the candidates untill gathering is finished.
1749 * Also older versions of farstream would fail the connection right away
1750 * when the first candidate given failed immediately (e.g. ipv6 on a
1751 * non-ipv6 capable host, so we order ipv6 candidates after ipv4 ones */
1752
1753 if (strchr (fscandidate->ip, ':'))
1754 self->priv->local_candidates = g_list_append
1755 (self->priv->local_candidates, fscandidate);
1756 else
1757 self->priv->local_candidates = g_list_prepend
1758 (self->priv->local_candidates, fscandidate);
1759 FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
1760 }
1761 else
1762 {
1763 struct candidate_signal_data *data =
1764 g_slice_new (struct candidate_signal_data);
1765
1766 FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
1767
1768 data->self = g_object_ref (self);
1769 data->signal_name = "new-local-candidate";
1770 data->candidate1 = fscandidate;
1771 data->candidate2 = NULL;
1772 fs_nice_agent_add_idle (self->priv->agent, agent_candidate_signal_idle,
1773 data, free_candidate_signal_data);
1774 }
1775 }
1776
1777
1778 static gboolean
agent_gathering_done_idle(gpointer data)1779 agent_gathering_done_idle (gpointer data)
1780 {
1781 FsNiceStreamTransmitter *self = data;
1782 GList *remote_candidates = NULL;
1783 GList *local_candidates = NULL;
1784 gboolean forced_candidates;
1785
1786 FS_NICE_STREAM_TRANSMITTER_LOCK (self);
1787 if (self->priv->gathered)
1788 {
1789 FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
1790 return FALSE;
1791 }
1792
1793 self->priv->gathered = TRUE;
1794 remote_candidates = self->priv->remote_candidates;
1795 self->priv->remote_candidates = NULL;
1796 local_candidates = self->priv->local_candidates;
1797 self->priv->local_candidates = NULL;
1798 forced_candidates = self->priv->forced_candidates;
1799 FS_NICE_STREAM_TRANSMITTER_UNLOCK (self);
1800
1801 GST_DEBUG ("Candidates gathered for stream %u", self->priv->stream_id);
1802
1803 if (local_candidates)
1804 {
1805 GList *l;
1806
1807 for (l = local_candidates ; l != NULL; l = g_list_next (l))
1808 g_signal_emit_by_name (self, "new-local-candidate", l->data);
1809 fs_candidate_list_destroy (local_candidates);
1810 }
1811
1812 g_signal_emit_by_name (self, "local-candidates-prepared");
1813
1814 if (remote_candidates)
1815 {
1816 if (forced_candidates)
1817 {
1818 if (!fs_nice_stream_transmitter_force_remote_candidates_act (self,
1819 remote_candidates))
1820 {
1821 fs_stream_transmitter_emit_error (FS_STREAM_TRANSMITTER (self),
1822 FS_ERROR_INTERNAL,
1823 "Error setting delayed forced remote candidates");
1824 }
1825 }
1826 else
1827 {
1828 GError *error = NULL;
1829
1830 if (self->priv->compatibility_mode != NICE_COMPATIBILITY_GOOGLE &&
1831 self->priv->compatibility_mode != NICE_COMPATIBILITY_MSN &&
1832 self->priv->compatibility_mode != NICE_COMPATIBILITY_OC2007)
1833 {
1834 if (!nice_agent_set_remote_credentials (self->priv->agent->agent,
1835 self->priv->stream_id, self->priv->username,
1836 self->priv->password))
1837 {
1838 fs_stream_transmitter_emit_error (FS_STREAM_TRANSMITTER (self),
1839 FS_ERROR_INTERNAL,
1840 "Could not set the security credentials");
1841 fs_candidate_list_destroy (remote_candidates);
1842 return FALSE;
1843 }
1844 }
1845
1846
1847 if (!fs_nice_stream_transmitter_add_remote_candidates (
1848 FS_STREAM_TRANSMITTER_CAST (self),
1849 remote_candidates, &error))
1850 {
1851 fs_stream_transmitter_emit_error (FS_STREAM_TRANSMITTER (self),
1852 error->code, error->message);
1853 }
1854 g_clear_error (&error);
1855 }
1856
1857 fs_candidate_list_destroy (remote_candidates);
1858 }
1859
1860 return FALSE;
1861 }
1862
1863
1864 static void
agent_gathering_done(NiceAgent * agent,guint stream_id,gpointer user_data)1865 agent_gathering_done (NiceAgent *agent, guint stream_id, gpointer user_data)
1866 {
1867 FsNiceStreamTransmitter *self = FS_NICE_STREAM_TRANSMITTER (user_data);
1868
1869 if (stream_id != self->priv->stream_id)
1870 return;
1871
1872 fs_nice_agent_add_idle (self->priv->agent, agent_gathering_done_idle,
1873 g_object_ref (self), g_object_unref);
1874 }
1875
1876
1877 FsNiceStreamTransmitter *
fs_nice_stream_transmitter_newv(FsNiceTransmitter * transmitter,FsParticipant * participant,guint n_parameters,GParameter * parameters,GError ** error)1878 fs_nice_stream_transmitter_newv (FsNiceTransmitter *transmitter,
1879 FsParticipant *participant,
1880 guint n_parameters,
1881 GParameter *parameters,
1882 GError **error)
1883 {
1884 FsNiceStreamTransmitter *streamtransmitter = NULL;
1885
1886 if (!participant || !FS_IS_PARTICIPANT (participant))
1887 {
1888 g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS,
1889 "You need a valid participant");
1890 return NULL;
1891 }
1892
1893 streamtransmitter = g_object_newv (FS_TYPE_NICE_STREAM_TRANSMITTER,
1894 n_parameters, parameters);
1895
1896 if (!streamtransmitter)
1897 {
1898 g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
1899 "Could not build the stream transmitter");
1900 return NULL;
1901 }
1902
1903 streamtransmitter->priv->transmitter = g_object_ref (transmitter);
1904
1905 if (!fs_nice_stream_transmitter_build (streamtransmitter, participant, error))
1906 {
1907 g_object_unref (streamtransmitter);
1908 return NULL;
1909 }
1910
1911 return streamtransmitter;
1912 }
1913
1914
1915 static GstPadProbeReturn
known_buffer_have_buffer_handler(GstPad * pad,GstPadProbeInfo * info,gpointer user_data)1916 known_buffer_have_buffer_handler (GstPad *pad, GstPadProbeInfo *info,
1917 gpointer user_data)
1918 {
1919 FsNiceStreamTransmitter *self = FS_NICE_STREAM_TRANSMITTER (user_data);
1920 guint component_id;
1921 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER (info);
1922
1923 if (!g_atomic_int_get (&self->priv->associate_on_source))
1924 return GST_PAD_PROBE_OK;
1925
1926 component_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (pad),
1927 "component-id"));
1928
1929 g_signal_emit_by_name (self, "known-source-packet-received", component_id,
1930 buffer);
1931
1932 return GST_PAD_PROBE_OK;
1933 }
1934