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