webrtcbin: Take PC_LOCK when requesting new pad
[platform/upstream/gstreamer.git] / ext / webrtc / gstwebrtcbin.c
1 /* GStreamer
2  * Copyright (C) 2017 Matthew Waters <matthew@centricular.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23
24 #include "gstwebrtcbin.h"
25 #include "gstwebrtcstats.h"
26 #include "transportstream.h"
27 #include "transportreceivebin.h"
28 #include "utils.h"
29 #include "webrtcsdp.h"
30 #include "webrtctransceiver.h"
31 #include "webrtcdatachannel.h"
32 #include "sctptransport.h"
33
34 #include <gst/rtp/rtp.h>
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39
40 #define RANDOM_SESSION_ID \
41     ((((((guint64) g_random_int()) << 32) | \
42        (guint64) g_random_int ())) & \
43     G_GUINT64_CONSTANT (0x7fffffffffffffff))
44
45 #define PC_GET_LOCK(w) (&w->priv->pc_lock)
46 #define PC_LOCK(w) (g_mutex_lock (PC_GET_LOCK(w)))
47 #define PC_UNLOCK(w) (g_mutex_unlock (PC_GET_LOCK(w)))
48
49 #define PC_GET_COND(w) (&w->priv->pc_cond)
50 #define PC_COND_WAIT(w) (g_cond_wait(PC_GET_COND(w), PC_GET_LOCK(w)))
51 #define PC_COND_BROADCAST(w) (g_cond_broadcast(PC_GET_COND(w)))
52 #define PC_COND_SIGNAL(w) (g_cond_signal(PC_GET_COND(w)))
53
54 #define ICE_GET_LOCK(w) (&w->priv->ice_lock)
55 #define ICE_LOCK(w) (g_mutex_lock (ICE_GET_LOCK(w)))
56 #define ICE_UNLOCK(w) (g_mutex_unlock (ICE_GET_LOCK(w)))
57
58
59 /* The extra time for the rtpstorage compared to the RTP jitterbuffer (in ms) */
60 #define RTPSTORAGE_EXTRA_TIME (50)
61
62 /**
63  * SECTION: element-webrtcbin
64  * title: webrtcbin
65  *
66  * This webrtcbin implements the majority of the W3's peerconnection API and
67  * implementation guide where possible. Generating offers, answers and setting
68  * local and remote SDP's are all supported.  Both media descriptions and
69  * descriptions involving data channels are supported.
70  *
71  * Each input/output pad is equivalent to a Track in W3 parlance which are
72  * added/removed from the bin.  The number of requested sink pads is the number
73  * of streams that will be sent to the receiver and will be associated with a
74  * GstWebRTCRTPTransceiver (very similar to W3 RTPTransceiver's).
75  *
76  * On the receiving side, RTPTransceiver's are created in response to setting
77  * a remote description.  Output pads for the receiving streams in the set
78  * description are also created when data is received.
79  *
80  * A TransportStream is created when needed in order to transport the data over
81  * the necessary DTLS/ICE channel to the peer.  The exact configuration depends
82  * on the negotiated SDP's between the peers based on the bundle and rtcp
83  * configuration.  Some cases are outlined below for a simple single
84  * audio/video/data session:
85  *
86  * - max-bundle uses a single transport for all
87  *   media/data transported.  Renegotiation involves adding/removing the
88  *   necessary streams to the existing transports.
89  * - max-compat involves two TransportStream per media stream
90  *   to transport the rtp and the rtcp packets and a single TransportStream for
91  *   all data channels.  Each stream change involves modifying the associated
92  *   TransportStream/s as necessary.
93  */
94
95 /*
96  * TODO:
97  * assert sending payload type matches the stream
98  * reconfiguration (of anything)
99  * LS groups
100  * balanced bundle policy
101  * setting custom DTLS certificates
102  *
103  * separate session id's from mlineindex properly
104  * how to deal with replacing a input/output track/stream
105  */
106
107 static void _update_need_negotiation (GstWebRTCBin * webrtc);
108
109 #define GST_CAT_DEFAULT gst_webrtc_bin_debug
110 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
111
112 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink_%u",
113     GST_PAD_SINK,
114     GST_PAD_REQUEST,
115     GST_STATIC_CAPS ("application/x-rtp"));
116
117 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src_%u",
118     GST_PAD_SRC,
119     GST_PAD_SOMETIMES,
120     GST_STATIC_CAPS ("application/x-rtp"));
121
122 enum
123 {
124   PROP_PAD_TRANSCEIVER = 1,
125 };
126
127 static gboolean
128 _have_nice_elements (GstWebRTCBin * webrtc)
129 {
130   GstPluginFeature *feature;
131
132   feature = gst_registry_lookup_feature (gst_registry_get (), "nicesrc");
133   if (feature) {
134     gst_object_unref (feature);
135   } else {
136     GST_ELEMENT_ERROR (webrtc, CORE, MISSING_PLUGIN, NULL,
137         ("%s", "libnice elements are not available"));
138     return FALSE;
139   }
140
141   feature = gst_registry_lookup_feature (gst_registry_get (), "nicesink");
142   if (feature) {
143     gst_object_unref (feature);
144   } else {
145     GST_ELEMENT_ERROR (webrtc, CORE, MISSING_PLUGIN, NULL,
146         ("%s", "libnice elements are not available"));
147     return FALSE;
148   }
149
150   return TRUE;
151 }
152
153 static gboolean
154 _have_sctp_elements (GstWebRTCBin * webrtc)
155 {
156   GstPluginFeature *feature;
157
158   feature = gst_registry_lookup_feature (gst_registry_get (), "sctpdec");
159   if (feature) {
160     gst_object_unref (feature);
161   } else {
162     GST_ELEMENT_ERROR (webrtc, CORE, MISSING_PLUGIN, NULL,
163         ("%s", "sctp elements are not available"));
164     return FALSE;
165   }
166
167   feature = gst_registry_lookup_feature (gst_registry_get (), "sctpenc");
168   if (feature) {
169     gst_object_unref (feature);
170   } else {
171     GST_ELEMENT_ERROR (webrtc, CORE, MISSING_PLUGIN, NULL,
172         ("%s", "sctp elements are not available"));
173     return FALSE;
174   }
175
176   return TRUE;
177 }
178
179 static gboolean
180 _have_dtls_elements (GstWebRTCBin * webrtc)
181 {
182   GstPluginFeature *feature;
183
184   feature = gst_registry_lookup_feature (gst_registry_get (), "dtlsdec");
185   if (feature) {
186     gst_object_unref (feature);
187   } else {
188     GST_ELEMENT_ERROR (webrtc, CORE, MISSING_PLUGIN, NULL,
189         ("%s", "dtls elements are not available"));
190     return FALSE;
191   }
192
193   feature = gst_registry_lookup_feature (gst_registry_get (), "dtlsenc");
194   if (feature) {
195     gst_object_unref (feature);
196   } else {
197     GST_ELEMENT_ERROR (webrtc, CORE, MISSING_PLUGIN, NULL,
198         ("%s", "dtls elements are not available"));
199     return FALSE;
200   }
201
202   return TRUE;
203 }
204
205 G_DEFINE_TYPE (GstWebRTCBinPad, gst_webrtc_bin_pad, GST_TYPE_GHOST_PAD);
206
207 static void
208 gst_webrtc_bin_pad_get_property (GObject * object, guint prop_id,
209     GValue * value, GParamSpec * pspec)
210 {
211   GstWebRTCBinPad *pad = GST_WEBRTC_BIN_PAD (object);
212
213   switch (prop_id) {
214     case PROP_PAD_TRANSCEIVER:
215       g_value_set_object (value, pad->trans);
216       break;
217     default:
218       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
219       break;
220   }
221 }
222
223 static void
224 gst_webrtc_bin_pad_finalize (GObject * object)
225 {
226   GstWebRTCBinPad *pad = GST_WEBRTC_BIN_PAD (object);
227
228   if (pad->trans)
229     gst_object_unref (pad->trans);
230   pad->trans = NULL;
231
232   if (pad->received_caps)
233     gst_caps_unref (pad->received_caps);
234   pad->received_caps = NULL;
235
236   G_OBJECT_CLASS (gst_webrtc_bin_pad_parent_class)->finalize (object);
237 }
238
239 static void
240 gst_webrtc_bin_pad_class_init (GstWebRTCBinPadClass * klass)
241 {
242   GObjectClass *gobject_class = (GObjectClass *) klass;
243
244   gobject_class->get_property = gst_webrtc_bin_pad_get_property;
245   gobject_class->finalize = gst_webrtc_bin_pad_finalize;
246
247   g_object_class_install_property (gobject_class,
248       PROP_PAD_TRANSCEIVER,
249       g_param_spec_object ("transceiver", "Transceiver",
250           "Transceiver associated with this pad",
251           GST_TYPE_WEBRTC_RTP_TRANSCEIVER,
252           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
253 }
254
255 static void
256 gst_webrtc_bin_pad_update_ssrc_event (GstWebRTCBinPad * wpad)
257 {
258   if (wpad->received_caps) {
259     WebRTCTransceiver *trans = (WebRTCTransceiver *) wpad->trans;
260     GstPad *pad = GST_PAD (wpad);
261
262     trans->ssrc_event =
263         gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_STICKY,
264         gst_structure_new ("GstWebRtcBinUpdateTos", "ssrc", G_TYPE_UINT,
265             trans->current_ssrc, NULL));
266     gst_pad_send_event (pad, gst_event_ref (trans->ssrc_event));
267   }
268 }
269
270 static gboolean
271 gst_webrtcbin_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
272 {
273   GstWebRTCBinPad *wpad = GST_WEBRTC_BIN_PAD (pad);
274   GstWebRTCBin *webrtc = GST_WEBRTC_BIN (parent);
275   gboolean check_negotiation = FALSE;
276
277   if (GST_EVENT_TYPE (event) == GST_EVENT_CAPS) {
278     GstCaps *caps;
279
280     gst_event_parse_caps (event, &caps);
281     check_negotiation = (!wpad->received_caps
282         || gst_caps_is_equal (wpad->received_caps, caps));
283     gst_caps_replace (&wpad->received_caps, caps);
284
285     GST_DEBUG_OBJECT (parent,
286         "On %" GST_PTR_FORMAT " checking negotiation? %u, caps %"
287         GST_PTR_FORMAT, pad, check_negotiation, caps);
288
289     if (check_negotiation) {
290       WebRTCTransceiver *trans = WEBRTC_TRANSCEIVER (wpad->trans);
291       const GstStructure *s;
292
293       s = gst_caps_get_structure (caps, 0);
294       gst_structure_get_uint (s, "ssrc", &trans->current_ssrc);
295       gst_webrtc_bin_pad_update_ssrc_event (wpad);
296     }
297   } else if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
298     check_negotiation = TRUE;
299   }
300
301   if (check_negotiation) {
302     PC_LOCK (webrtc);
303     _update_need_negotiation (webrtc);
304     PC_UNLOCK (webrtc);
305   }
306
307   return gst_pad_event_default (pad, parent, event);
308 }
309
310 static void
311 gst_webrtc_bin_pad_init (GstWebRTCBinPad * pad)
312 {
313 }
314
315 static GstWebRTCBinPad *
316 gst_webrtc_bin_pad_new (const gchar * name, GstPadDirection direction)
317 {
318   GstWebRTCBinPad *pad;
319   GstPadTemplate *template;
320
321   if (direction == GST_PAD_SINK)
322     template = gst_static_pad_template_get (&sink_template);
323   else if (direction == GST_PAD_SRC)
324     template = gst_static_pad_template_get (&src_template);
325   else
326     g_assert_not_reached ();
327
328   pad =
329       g_object_new (gst_webrtc_bin_pad_get_type (), "name", name, "direction",
330       direction, "template", template, NULL);
331   gst_object_unref (template);
332
333   gst_pad_set_event_function (GST_PAD (pad), gst_webrtcbin_sink_event);
334
335   GST_DEBUG_OBJECT (pad, "new visible pad with direction %s",
336       direction == GST_PAD_SRC ? "src" : "sink");
337   return pad;
338 }
339
340 #define gst_webrtc_bin_parent_class parent_class
341 G_DEFINE_TYPE_WITH_CODE (GstWebRTCBin, gst_webrtc_bin, GST_TYPE_BIN,
342     G_ADD_PRIVATE (GstWebRTCBin)
343     GST_DEBUG_CATEGORY_INIT (gst_webrtc_bin_debug, "webrtcbin", 0,
344         "webrtcbin element"););
345
346 static GstPad *_connect_input_stream (GstWebRTCBin * webrtc,
347     GstWebRTCBinPad * pad);
348
349 enum
350 {
351   SIGNAL_0,
352   CREATE_OFFER_SIGNAL,
353   CREATE_ANSWER_SIGNAL,
354   SET_LOCAL_DESCRIPTION_SIGNAL,
355   SET_REMOTE_DESCRIPTION_SIGNAL,
356   ADD_ICE_CANDIDATE_SIGNAL,
357   ON_NEGOTIATION_NEEDED_SIGNAL,
358   ON_ICE_CANDIDATE_SIGNAL,
359   ON_NEW_TRANSCEIVER_SIGNAL,
360   GET_STATS_SIGNAL,
361   ADD_TRANSCEIVER_SIGNAL,
362   GET_TRANSCEIVER_SIGNAL,
363   GET_TRANSCEIVERS_SIGNAL,
364   ADD_TURN_SERVER_SIGNAL,
365   CREATE_DATA_CHANNEL_SIGNAL,
366   ON_DATA_CHANNEL_SIGNAL,
367   LAST_SIGNAL,
368 };
369
370 enum
371 {
372   PROP_0,
373   PROP_CONNECTION_STATE,
374   PROP_SIGNALING_STATE,
375   PROP_ICE_GATHERING_STATE,
376   PROP_ICE_CONNECTION_STATE,
377   PROP_LOCAL_DESCRIPTION,
378   PROP_CURRENT_LOCAL_DESCRIPTION,
379   PROP_PENDING_LOCAL_DESCRIPTION,
380   PROP_REMOTE_DESCRIPTION,
381   PROP_CURRENT_REMOTE_DESCRIPTION,
382   PROP_PENDING_REMOTE_DESCRIPTION,
383   PROP_STUN_SERVER,
384   PROP_TURN_SERVER,
385   PROP_BUNDLE_POLICY,
386   PROP_ICE_TRANSPORT_POLICY,
387   PROP_ICE_AGENT,
388   PROP_LATENCY
389 };
390
391 static guint gst_webrtc_bin_signals[LAST_SIGNAL] = { 0 };
392
393 typedef struct
394 {
395   guint session_id;
396   GstWebRTCICEStream *stream;
397 } IceStreamItem;
398
399 /* FIXME: locking? */
400 GstWebRTCICEStream *
401 _find_ice_stream_for_session (GstWebRTCBin * webrtc, guint session_id)
402 {
403   int i;
404
405   for (i = 0; i < webrtc->priv->ice_stream_map->len; i++) {
406     IceStreamItem *item =
407         &g_array_index (webrtc->priv->ice_stream_map, IceStreamItem, i);
408
409     if (item->session_id == session_id) {
410       GST_TRACE_OBJECT (webrtc, "Found ice stream id %" GST_PTR_FORMAT " for "
411           "session %u", item->stream, session_id);
412       return item->stream;
413     }
414   }
415
416   GST_TRACE_OBJECT (webrtc, "No ice stream available for session %u",
417       session_id);
418   return NULL;
419 }
420
421 void
422 _add_ice_stream_item (GstWebRTCBin * webrtc, guint session_id,
423     GstWebRTCICEStream * stream)
424 {
425   IceStreamItem item = { session_id, stream };
426
427   GST_TRACE_OBJECT (webrtc, "adding ice stream %" GST_PTR_FORMAT " for "
428       "session %u", stream, session_id);
429   g_array_append_val (webrtc->priv->ice_stream_map, item);
430 }
431
432 typedef gboolean (*FindTransceiverFunc) (GstWebRTCRTPTransceiver * p1,
433     gconstpointer data);
434
435 static GstWebRTCRTPTransceiver *
436 _find_transceiver (GstWebRTCBin * webrtc, gconstpointer data,
437     FindTransceiverFunc func)
438 {
439   int i;
440
441   for (i = 0; i < webrtc->priv->transceivers->len; i++) {
442     GstWebRTCRTPTransceiver *transceiver =
443         g_ptr_array_index (webrtc->priv->transceivers, i);
444
445     if (func (transceiver, data))
446       return transceiver;
447   }
448
449   return NULL;
450 }
451
452 static gboolean
453 match_for_mid (GstWebRTCRTPTransceiver * trans, const gchar * mid)
454 {
455   return g_strcmp0 (trans->mid, mid) == 0;
456 }
457
458 static gboolean
459 transceiver_match_for_mline (GstWebRTCRTPTransceiver * trans, guint * mline)
460 {
461   if (trans->stopped)
462     return FALSE;
463
464   return trans->mline == *mline;
465 }
466
467 static GstWebRTCRTPTransceiver *
468 _find_transceiver_for_mline (GstWebRTCBin * webrtc, guint mlineindex)
469 {
470   GstWebRTCRTPTransceiver *trans;
471
472   trans = _find_transceiver (webrtc, &mlineindex,
473       (FindTransceiverFunc) transceiver_match_for_mline);
474
475   GST_TRACE_OBJECT (webrtc,
476       "Found transceiver %" GST_PTR_FORMAT " for mlineindex %u", trans,
477       mlineindex);
478
479   return trans;
480 }
481
482 typedef gboolean (*FindTransportFunc) (TransportStream * p1,
483     gconstpointer data);
484
485 static TransportStream *
486 _find_transport (GstWebRTCBin * webrtc, gconstpointer data,
487     FindTransportFunc func)
488 {
489   int i;
490
491   for (i = 0; i < webrtc->priv->transports->len; i++) {
492     TransportStream *stream = g_ptr_array_index (webrtc->priv->transports, i);
493
494     if (func (stream, data))
495       return stream;
496   }
497
498   return NULL;
499 }
500
501 static gboolean
502 match_stream_for_session (TransportStream * trans, guint * session)
503 {
504   return trans->session_id == *session;
505 }
506
507 static TransportStream *
508 _find_transport_for_session (GstWebRTCBin * webrtc, guint session_id)
509 {
510   TransportStream *stream;
511
512   stream = _find_transport (webrtc, &session_id,
513       (FindTransportFunc) match_stream_for_session);
514
515   GST_TRACE_OBJECT (webrtc,
516       "Found transport %" GST_PTR_FORMAT " for session %u", stream, session_id);
517
518   return stream;
519 }
520
521 typedef gboolean (*FindPadFunc) (GstWebRTCBinPad * p1, gconstpointer data);
522
523 static GstWebRTCBinPad *
524 _find_pad (GstWebRTCBin * webrtc, gconstpointer data, FindPadFunc func)
525 {
526   GstElement *element = GST_ELEMENT (webrtc);
527   GList *l;
528
529   GST_OBJECT_LOCK (webrtc);
530   l = element->pads;
531   for (; l; l = g_list_next (l)) {
532     if (!GST_IS_WEBRTC_BIN_PAD (l->data))
533       continue;
534     if (func (l->data, data)) {
535       gst_object_ref (l->data);
536       GST_OBJECT_UNLOCK (webrtc);
537       return l->data;
538     }
539   }
540
541   l = webrtc->priv->pending_pads;
542   for (; l; l = g_list_next (l)) {
543     if (!GST_IS_WEBRTC_BIN_PAD (l->data))
544       continue;
545     if (func (l->data, data)) {
546       gst_object_ref (l->data);
547       GST_OBJECT_UNLOCK (webrtc);
548       return l->data;
549     }
550   }
551   GST_OBJECT_UNLOCK (webrtc);
552
553   return NULL;
554 }
555
556 typedef gboolean (*FindDataChannelFunc) (WebRTCDataChannel * p1,
557     gconstpointer data);
558
559 static WebRTCDataChannel *
560 _find_data_channel (GstWebRTCBin * webrtc, gconstpointer data,
561     FindDataChannelFunc func)
562 {
563   int i;
564
565   for (i = 0; i < webrtc->priv->data_channels->len; i++) {
566     WebRTCDataChannel *channel =
567         g_ptr_array_index (webrtc->priv->data_channels, i);
568
569     if (func (channel, data))
570       return channel;
571   }
572
573   return NULL;
574 }
575
576 static gboolean
577 data_channel_match_for_id (WebRTCDataChannel * channel, gint * id)
578 {
579   return channel->parent.id == *id;
580 }
581
582 static WebRTCDataChannel *
583 _find_data_channel_for_id (GstWebRTCBin * webrtc, gint id)
584 {
585   WebRTCDataChannel *channel;
586
587   channel = _find_data_channel (webrtc, &id,
588       (FindDataChannelFunc) data_channel_match_for_id);
589
590   GST_TRACE_OBJECT (webrtc,
591       "Found data channel %" GST_PTR_FORMAT " for id %i", channel, id);
592
593   return channel;
594 }
595
596 static void
597 _add_pad_to_list (GstWebRTCBin * webrtc, GstWebRTCBinPad * pad)
598 {
599   GST_OBJECT_LOCK (webrtc);
600   webrtc->priv->pending_pads = g_list_prepend (webrtc->priv->pending_pads, pad);
601   GST_OBJECT_UNLOCK (webrtc);
602 }
603
604 static void
605 _remove_pending_pad (GstWebRTCBin * webrtc, GstWebRTCBinPad * pad)
606 {
607   GST_OBJECT_LOCK (webrtc);
608   webrtc->priv->pending_pads = g_list_remove (webrtc->priv->pending_pads, pad);
609   GST_OBJECT_UNLOCK (webrtc);
610 }
611
612 static void
613 _add_pad (GstWebRTCBin * webrtc, GstWebRTCBinPad * pad)
614 {
615   _remove_pending_pad (webrtc, pad);
616
617   if (webrtc->priv->running)
618     gst_pad_set_active (GST_PAD (pad), TRUE);
619   gst_element_add_pad (GST_ELEMENT (webrtc), GST_PAD (pad));
620 }
621
622 static void
623 _remove_pad (GstWebRTCBin * webrtc, GstWebRTCBinPad * pad)
624 {
625   _remove_pending_pad (webrtc, pad);
626
627   gst_element_remove_pad (GST_ELEMENT (webrtc), GST_PAD (pad));
628 }
629
630 typedef struct
631 {
632   GstPadDirection direction;
633   guint mline;
634 } MLineMatch;
635
636 static gboolean
637 pad_match_for_mline (GstWebRTCBinPad * pad, const MLineMatch * match)
638 {
639   return GST_PAD_DIRECTION (pad) == match->direction
640       && pad->trans->mline == match->mline;
641 }
642
643 static GstWebRTCBinPad *
644 _find_pad_for_mline (GstWebRTCBin * webrtc, GstPadDirection direction,
645     guint mline)
646 {
647   MLineMatch m = { direction, mline };
648
649   return _find_pad (webrtc, &m, (FindPadFunc) pad_match_for_mline);
650 }
651
652 typedef struct
653 {
654   GstPadDirection direction;
655   GstWebRTCRTPTransceiver *trans;
656 } TransMatch;
657
658 static gboolean
659 pad_match_for_transceiver (GstWebRTCBinPad * pad, TransMatch * m)
660 {
661   return GST_PAD_DIRECTION (pad) == m->direction && pad->trans == m->trans;
662 }
663
664 static GstWebRTCBinPad *
665 _find_pad_for_transceiver (GstWebRTCBin * webrtc, GstPadDirection direction,
666     GstWebRTCRTPTransceiver * trans)
667 {
668   TransMatch m = { direction, trans };
669
670   return _find_pad (webrtc, &m, (FindPadFunc) pad_match_for_transceiver);
671 }
672
673 #if 0
674 static gboolean
675 match_for_ssrc (GstWebRTCBinPad * pad, guint * ssrc)
676 {
677   return pad->ssrc == *ssrc;
678 }
679
680 static gboolean
681 match_for_pad (GstWebRTCBinPad * pad, GstWebRTCBinPad * other)
682 {
683   return pad == other;
684 }
685 #endif
686
687 static gboolean
688 _unlock_pc_thread (GMutex * lock)
689 {
690   g_mutex_unlock (lock);
691   return G_SOURCE_REMOVE;
692 }
693
694 static gpointer
695 _gst_pc_thread (GstWebRTCBin * webrtc)
696 {
697   PC_LOCK (webrtc);
698   webrtc->priv->main_context = g_main_context_new ();
699   webrtc->priv->loop = g_main_loop_new (webrtc->priv->main_context, FALSE);
700
701   PC_COND_BROADCAST (webrtc);
702   g_main_context_invoke (webrtc->priv->main_context,
703       (GSourceFunc) _unlock_pc_thread, PC_GET_LOCK (webrtc));
704
705   /* Having the thread be the thread default GMainContext will break the
706    * required queue-like ordering (from W3's peerconnection spec) of re-entrant
707    * tasks */
708   g_main_loop_run (webrtc->priv->loop);
709
710   GST_OBJECT_LOCK (webrtc);
711   g_main_context_unref (webrtc->priv->main_context);
712   webrtc->priv->main_context = NULL;
713   GST_OBJECT_UNLOCK (webrtc);
714
715   PC_LOCK (webrtc);
716   g_main_loop_unref (webrtc->priv->loop);
717   webrtc->priv->loop = NULL;
718   PC_COND_BROADCAST (webrtc);
719   PC_UNLOCK (webrtc);
720
721   return NULL;
722 }
723
724 static void
725 _start_thread (GstWebRTCBin * webrtc)
726 {
727   gchar *name;
728
729   PC_LOCK (webrtc);
730   name = g_strdup_printf ("%s:pc", GST_OBJECT_NAME (webrtc));
731   webrtc->priv->thread = g_thread_new (name, (GThreadFunc) _gst_pc_thread,
732       webrtc);
733   g_free (name);
734
735   while (!webrtc->priv->loop)
736     PC_COND_WAIT (webrtc);
737   webrtc->priv->is_closed = FALSE;
738   PC_UNLOCK (webrtc);
739 }
740
741 static void
742 _stop_thread (GstWebRTCBin * webrtc)
743 {
744   GST_OBJECT_LOCK (webrtc);
745   webrtc->priv->is_closed = TRUE;
746   GST_OBJECT_UNLOCK (webrtc);
747
748   PC_LOCK (webrtc);
749   g_main_loop_quit (webrtc->priv->loop);
750   while (webrtc->priv->loop)
751     PC_COND_WAIT (webrtc);
752   PC_UNLOCK (webrtc);
753
754   g_thread_unref (webrtc->priv->thread);
755 }
756
757 static gboolean
758 _execute_op (GstWebRTCBinTask * op)
759 {
760   PC_LOCK (op->webrtc);
761   if (op->webrtc->priv->is_closed) {
762     if (op->promise) {
763       GError *error =
764           g_error_new (GST_WEBRTC_BIN_ERROR, GST_WEBRTC_BIN_ERROR_CLOSED,
765           "webrtcbin is closed. aborting execution.");
766       GstStructure *s =
767           gst_structure_new ("application/x-gstwebrtcbin-promise-error",
768           "error", G_TYPE_ERROR, error, NULL);
769
770       gst_promise_reply (op->promise, s);
771
772       g_clear_error (&error);
773     }
774     GST_DEBUG_OBJECT (op->webrtc,
775         "Peerconnection is closed, aborting execution");
776     goto out;
777   }
778
779   op->op (op->webrtc, op->data);
780
781 out:
782   PC_UNLOCK (op->webrtc);
783   return G_SOURCE_REMOVE;
784 }
785
786 static void
787 _free_op (GstWebRTCBinTask * op)
788 {
789   if (op->notify)
790     op->notify (op->data);
791   if (op->promise)
792     gst_promise_unref (op->promise);
793   g_free (op);
794 }
795
796 /*
797  * @promise is for correctly signalling the failure case to the caller when
798  * the user supplies it.  Without passing it in, the promise would never
799  * be replied to in the case that @webrtc becomes closed between the idle
800  * source addition and the the execution of the idle source.
801  */
802 gboolean
803 gst_webrtc_bin_enqueue_task (GstWebRTCBin * webrtc, GstWebRTCBinFunc func,
804     gpointer data, GDestroyNotify notify, GstPromise * promise)
805 {
806   GstWebRTCBinTask *op;
807   GMainContext *ctx;
808   GSource *source;
809
810   g_return_val_if_fail (GST_IS_WEBRTC_BIN (webrtc), FALSE);
811
812   GST_OBJECT_LOCK (webrtc);
813   if (webrtc->priv->is_closed) {
814     GST_OBJECT_UNLOCK (webrtc);
815     GST_DEBUG_OBJECT (webrtc, "Peerconnection is closed, aborting execution");
816     if (notify)
817       notify (data);
818     return FALSE;
819   }
820   ctx = g_main_context_ref (webrtc->priv->main_context);
821   GST_OBJECT_UNLOCK (webrtc);
822
823   op = g_new0 (GstWebRTCBinTask, 1);
824   op->webrtc = webrtc;
825   op->op = func;
826   op->data = data;
827   op->notify = notify;
828   if (promise)
829     op->promise = gst_promise_ref (promise);
830
831   source = g_idle_source_new ();
832   g_source_set_priority (source, G_PRIORITY_DEFAULT);
833   g_source_set_callback (source, (GSourceFunc) _execute_op, op,
834       (GDestroyNotify) _free_op);
835   g_source_attach (source, ctx);
836   g_source_unref (source);
837   g_main_context_unref (ctx);
838
839   return TRUE;
840 }
841
842 /* https://www.w3.org/TR/webrtc/#dom-rtciceconnectionstate */
843 static GstWebRTCICEConnectionState
844 _collate_ice_connection_states (GstWebRTCBin * webrtc)
845 {
846 #define STATE(val) GST_WEBRTC_ICE_CONNECTION_STATE_ ## val
847   GstWebRTCICEConnectionState any_state = 0;
848   gboolean all_new_or_closed = TRUE;
849   gboolean all_completed_or_closed = TRUE;
850   gboolean all_connected_completed_or_closed = TRUE;
851   int i;
852
853   for (i = 0; i < webrtc->priv->transceivers->len; i++) {
854     GstWebRTCRTPTransceiver *rtp_trans =
855         g_ptr_array_index (webrtc->priv->transceivers, i);
856     GstWebRTCICETransport *transport;
857     GstWebRTCICEConnectionState ice_state;
858
859     if (rtp_trans->stopped) {
860       GST_TRACE_OBJECT (webrtc, "transceiver %p stopped", rtp_trans);
861       continue;
862     }
863
864     if (!rtp_trans->mid) {
865       GST_TRACE_OBJECT (webrtc, "transceiver %p has no mid", rtp_trans);
866       continue;
867     }
868
869     transport = webrtc_transceiver_get_dtls_transport (rtp_trans)->transport;
870
871     /* get transport state */
872     g_object_get (transport, "state", &ice_state, NULL);
873     GST_TRACE_OBJECT (webrtc, "transceiver %p state 0x%x", rtp_trans,
874         ice_state);
875     any_state |= (1 << ice_state);
876
877     if (ice_state != STATE (NEW) && ice_state != STATE (CLOSED))
878       all_new_or_closed = FALSE;
879     if (ice_state != STATE (COMPLETED) && ice_state != STATE (CLOSED))
880       all_completed_or_closed = FALSE;
881     if (ice_state != STATE (CONNECTED) && ice_state != STATE (COMPLETED)
882         && ice_state != STATE (CLOSED))
883       all_connected_completed_or_closed = FALSE;
884   }
885
886   GST_TRACE_OBJECT (webrtc, "ICE connection state: 0x%x", any_state);
887
888   if (webrtc->priv->is_closed) {
889     GST_TRACE_OBJECT (webrtc, "returning closed");
890     return STATE (CLOSED);
891   }
892   /* Any of the RTCIceTransports are in the failed state. */
893   if (any_state & (1 << STATE (FAILED))) {
894     GST_TRACE_OBJECT (webrtc, "returning failed");
895     return STATE (FAILED);
896   }
897   /* Any of the RTCIceTransports are in the disconnected state. */
898   if (any_state & (1 << STATE (DISCONNECTED))) {
899     GST_TRACE_OBJECT (webrtc, "returning disconnected");
900     return STATE (DISCONNECTED);
901   }
902   /* All of the RTCIceTransports are in the new or closed state, or there are
903    * no transports. */
904   if (all_new_or_closed || webrtc->priv->transceivers->len == 0) {
905     GST_TRACE_OBJECT (webrtc, "returning new");
906     return STATE (NEW);
907   }
908   /* Any of the RTCIceTransports are in the checking or new state. */
909   if ((any_state & (1 << STATE (CHECKING))) || (any_state & (1 << STATE (NEW)))) {
910     GST_TRACE_OBJECT (webrtc, "returning checking");
911     return STATE (CHECKING);
912   }
913   /* All RTCIceTransports are in the completed or closed state. */
914   if (all_completed_or_closed) {
915     GST_TRACE_OBJECT (webrtc, "returning completed");
916     return STATE (COMPLETED);
917   }
918   /* All RTCIceTransports are in the connected, completed or closed state. */
919   if (all_connected_completed_or_closed) {
920     GST_TRACE_OBJECT (webrtc, "returning connected");
921     return STATE (CONNECTED);
922   }
923
924   GST_FIXME ("unspecified situation, returning old state");
925   return webrtc->ice_connection_state;
926 #undef STATE
927 }
928
929 /* https://www.w3.org/TR/webrtc/#dom-rtcicegatheringstate */
930 static GstWebRTCICEGatheringState
931 _collate_ice_gathering_states (GstWebRTCBin * webrtc)
932 {
933 #define STATE(val) GST_WEBRTC_ICE_GATHERING_STATE_ ## val
934   GstWebRTCICEGatheringState any_state = 0;
935   gboolean all_completed = webrtc->priv->transceivers->len > 0;
936   int i;
937
938   for (i = 0; i < webrtc->priv->transceivers->len; i++) {
939     GstWebRTCRTPTransceiver *rtp_trans =
940         g_ptr_array_index (webrtc->priv->transceivers, i);
941     WebRTCTransceiver *trans = WEBRTC_TRANSCEIVER (rtp_trans);
942     TransportStream *stream = trans->stream;
943     GstWebRTCDTLSTransport *dtls_transport;
944     GstWebRTCICETransport *transport;
945     GstWebRTCICEGatheringState ice_state;
946
947     if (rtp_trans->stopped || stream == NULL) {
948       GST_TRACE_OBJECT (webrtc, "transceiver %p stopped or unassociated",
949           rtp_trans);
950       continue;
951     }
952
953     /* We only have a mid in the transceiver after we got the SDP answer,
954      * which is usually long after gathering has finished */
955     if (!rtp_trans->mid) {
956       GST_TRACE_OBJECT (webrtc, "transceiver %p has no mid", rtp_trans);
957     }
958
959     dtls_transport = webrtc_transceiver_get_dtls_transport (rtp_trans);
960     if (dtls_transport == NULL) {
961       GST_WARNING ("Transceiver %p has no DTLS transport", rtp_trans);
962       continue;
963     }
964
965     transport = dtls_transport->transport;
966
967     /* get gathering state */
968     g_object_get (transport, "gathering-state", &ice_state, NULL);
969     GST_TRACE_OBJECT (webrtc, "transceiver %p gathering state: 0x%x", rtp_trans,
970         ice_state);
971     any_state |= (1 << ice_state);
972     if (ice_state != STATE (COMPLETE))
973       all_completed = FALSE;
974   }
975
976   GST_TRACE_OBJECT (webrtc, "ICE gathering state: 0x%x", any_state);
977
978   /* Any of the RTCIceTransport s are in the gathering state. */
979   if (any_state & (1 << STATE (GATHERING))) {
980     GST_TRACE_OBJECT (webrtc, "returning gathering");
981     return STATE (GATHERING);
982   }
983   /* At least one RTCIceTransport exists, and all RTCIceTransport s are in
984    * the completed gathering state. */
985   if (all_completed) {
986     GST_TRACE_OBJECT (webrtc, "returning complete");
987     return STATE (COMPLETE);
988   }
989
990   /* Any of the RTCIceTransport s are in the new gathering state and none
991    * of the transports are in the gathering state, or there are no transports. */
992   GST_TRACE_OBJECT (webrtc, "returning new");
993   return STATE (NEW);
994 #undef STATE
995 }
996
997 /* https://www.w3.org/TR/webrtc/#rtcpeerconnectionstate-enum */
998 static GstWebRTCPeerConnectionState
999 _collate_peer_connection_states (GstWebRTCBin * webrtc)
1000 {
1001 #define STATE(v) GST_WEBRTC_PEER_CONNECTION_STATE_ ## v
1002 #define ICE_STATE(v) GST_WEBRTC_ICE_CONNECTION_STATE_ ## v
1003 #define DTLS_STATE(v) GST_WEBRTC_DTLS_TRANSPORT_STATE_ ## v
1004   GstWebRTCICEConnectionState any_ice_state = 0;
1005   GstWebRTCDTLSTransportState any_dtls_state = 0;
1006   gboolean ice_all_new_or_closed = TRUE;
1007   gboolean dtls_all_new_or_closed = TRUE;
1008   gboolean ice_all_new_connecting_or_checking = TRUE;
1009   gboolean dtls_all_new_connecting_or_checking = TRUE;
1010   gboolean ice_all_connected_completed_or_closed = TRUE;
1011   gboolean dtls_all_connected_completed_or_closed = TRUE;
1012   int i;
1013
1014   for (i = 0; i < webrtc->priv->transceivers->len; i++) {
1015     GstWebRTCRTPTransceiver *rtp_trans =
1016         g_ptr_array_index (webrtc->priv->transceivers, i);
1017     GstWebRTCDTLSTransport *transport;
1018     GstWebRTCICEConnectionState ice_state;
1019     GstWebRTCDTLSTransportState dtls_state;
1020
1021     if (rtp_trans->stopped) {
1022       GST_TRACE_OBJECT (webrtc, "transceiver %p stopped", rtp_trans);
1023       continue;
1024     }
1025     if (!rtp_trans->mid) {
1026       GST_TRACE_OBJECT (webrtc, "transceiver %p has no mid", rtp_trans);
1027       continue;
1028     }
1029
1030     transport = webrtc_transceiver_get_dtls_transport (rtp_trans);
1031
1032     /* get transport state */
1033     g_object_get (transport, "state", &dtls_state, NULL);
1034     GST_TRACE_OBJECT (webrtc, "transceiver %p DTLS state: 0x%x", rtp_trans,
1035         dtls_state);
1036     any_dtls_state |= (1 << dtls_state);
1037
1038     if (dtls_state != DTLS_STATE (NEW) && dtls_state != DTLS_STATE (CLOSED))
1039       dtls_all_new_or_closed = FALSE;
1040     if (dtls_state != DTLS_STATE (NEW) && dtls_state != DTLS_STATE (CONNECTING))
1041       dtls_all_new_connecting_or_checking = FALSE;
1042     if (dtls_state != DTLS_STATE (CONNECTED)
1043         && dtls_state != DTLS_STATE (CLOSED))
1044       dtls_all_connected_completed_or_closed = FALSE;
1045
1046     g_object_get (transport->transport, "state", &ice_state, NULL);
1047     GST_TRACE_OBJECT (webrtc, "transceiver %p ICE state: 0x%x", rtp_trans,
1048         ice_state);
1049     any_ice_state |= (1 << ice_state);
1050
1051     if (ice_state != ICE_STATE (NEW) && ice_state != ICE_STATE (CLOSED))
1052       ice_all_new_or_closed = FALSE;
1053     if (ice_state != ICE_STATE (NEW) && ice_state != ICE_STATE (CHECKING))
1054       ice_all_new_connecting_or_checking = FALSE;
1055     if (ice_state != ICE_STATE (CONNECTED) && ice_state != ICE_STATE (COMPLETED)
1056         && ice_state != ICE_STATE (CLOSED))
1057       ice_all_connected_completed_or_closed = FALSE;
1058   }
1059
1060   GST_TRACE_OBJECT (webrtc, "ICE connection state: 0x%x. DTLS connection "
1061       "state: 0x%x", any_ice_state, any_dtls_state);
1062
1063   /* The RTCPeerConnection object's [[ isClosed]] slot is true.  */
1064   if (webrtc->priv->is_closed) {
1065     GST_TRACE_OBJECT (webrtc, "returning closed");
1066     return STATE (CLOSED);
1067   }
1068
1069   /* Any of the RTCIceTransport s or RTCDtlsTransport s are in a failed state. */
1070   if (any_ice_state & (1 << ICE_STATE (FAILED))) {
1071     GST_TRACE_OBJECT (webrtc, "returning failed");
1072     return STATE (FAILED);
1073   }
1074   if (any_dtls_state & (1 << DTLS_STATE (FAILED))) {
1075     GST_TRACE_OBJECT (webrtc, "returning failed");
1076     return STATE (FAILED);
1077   }
1078
1079   /* Any of the RTCIceTransport's or RTCDtlsTransport's are in the disconnected
1080    * state. */
1081   if (any_ice_state & (1 << ICE_STATE (DISCONNECTED))) {
1082     GST_TRACE_OBJECT (webrtc, "returning disconnected");
1083     return STATE (DISCONNECTED);
1084   }
1085
1086   /* All RTCIceTransports and RTCDtlsTransports are in the new or closed
1087    * state, or there are no transports. */
1088   if ((dtls_all_new_or_closed && ice_all_new_or_closed)
1089       || webrtc->priv->transceivers->len == 0) {
1090     GST_TRACE_OBJECT (webrtc, "returning new");
1091     return STATE (NEW);
1092   }
1093
1094   /* All RTCIceTransports and RTCDtlsTransports are in the new, connecting
1095    * or checking state. */
1096   if (dtls_all_new_connecting_or_checking && ice_all_new_connecting_or_checking) {
1097     GST_TRACE_OBJECT (webrtc, "returning connecting");
1098     return STATE (CONNECTING);
1099   }
1100
1101   /* All RTCIceTransports and RTCDtlsTransports are in the connected,
1102    * completed or closed state. */
1103   if (dtls_all_connected_completed_or_closed
1104       && ice_all_connected_completed_or_closed) {
1105     GST_TRACE_OBJECT (webrtc, "returning connected");
1106     return STATE (CONNECTED);
1107   }
1108
1109   /* FIXME: Unspecified state that happens for us */
1110   if ((dtls_all_new_connecting_or_checking
1111           || dtls_all_connected_completed_or_closed)
1112       && (ice_all_new_connecting_or_checking
1113           || ice_all_connected_completed_or_closed)) {
1114     GST_TRACE_OBJECT (webrtc, "returning connecting");
1115     return STATE (CONNECTING);
1116   }
1117
1118   GST_FIXME_OBJECT (webrtc,
1119       "Undefined situation detected, returning old state");
1120   return webrtc->peer_connection_state;
1121 #undef DTLS_STATE
1122 #undef ICE_STATE
1123 #undef STATE
1124 }
1125
1126 static void
1127 _update_ice_gathering_state_task (GstWebRTCBin * webrtc, gpointer data)
1128 {
1129   GstWebRTCICEGatheringState old_state = webrtc->ice_gathering_state;
1130   GstWebRTCICEGatheringState new_state;
1131
1132   new_state = _collate_ice_gathering_states (webrtc);
1133
1134   /* If the new state is complete, before we update the public state,
1135    * check if anyone published more ICE candidates while we were collating
1136    * and stop if so, because it means there's a new later
1137    * ice_gathering_state_task queued */
1138   if (new_state == GST_WEBRTC_ICE_GATHERING_STATE_COMPLETE) {
1139     ICE_LOCK (webrtc);
1140     if (webrtc->priv->pending_local_ice_candidates->len != 0) {
1141       /* ICE candidates queued for emissiong -> we're gathering, not complete */
1142       new_state = GST_WEBRTC_ICE_GATHERING_STATE_GATHERING;
1143     }
1144     ICE_UNLOCK (webrtc);
1145   }
1146
1147   if (new_state != webrtc->ice_gathering_state) {
1148     gchar *old_s, *new_s;
1149
1150     old_s = _enum_value_to_string (GST_TYPE_WEBRTC_ICE_GATHERING_STATE,
1151         old_state);
1152     new_s = _enum_value_to_string (GST_TYPE_WEBRTC_ICE_GATHERING_STATE,
1153         new_state);
1154     GST_INFO_OBJECT (webrtc, "ICE gathering state change from %s(%u) to %s(%u)",
1155         old_s, old_state, new_s, new_state);
1156     g_free (old_s);
1157     g_free (new_s);
1158
1159     webrtc->ice_gathering_state = new_state;
1160     PC_UNLOCK (webrtc);
1161     g_object_notify (G_OBJECT (webrtc), "ice-gathering-state");
1162     PC_LOCK (webrtc);
1163   }
1164 }
1165
1166 static void
1167 _update_ice_gathering_state (GstWebRTCBin * webrtc)
1168 {
1169   gst_webrtc_bin_enqueue_task (webrtc, _update_ice_gathering_state_task, NULL,
1170       NULL, NULL);
1171 }
1172
1173 static void
1174 _update_ice_connection_state_task (GstWebRTCBin * webrtc, gpointer data)
1175 {
1176   GstWebRTCICEConnectionState old_state = webrtc->ice_connection_state;
1177   GstWebRTCICEConnectionState new_state;
1178
1179   new_state = _collate_ice_connection_states (webrtc);
1180
1181   if (new_state != old_state) {
1182     gchar *old_s, *new_s;
1183
1184     old_s = _enum_value_to_string (GST_TYPE_WEBRTC_ICE_CONNECTION_STATE,
1185         old_state);
1186     new_s = _enum_value_to_string (GST_TYPE_WEBRTC_ICE_CONNECTION_STATE,
1187         new_state);
1188     GST_INFO_OBJECT (webrtc,
1189         "ICE connection state change from %s(%u) to %s(%u)", old_s, old_state,
1190         new_s, new_state);
1191     g_free (old_s);
1192     g_free (new_s);
1193
1194     webrtc->ice_connection_state = new_state;
1195     PC_UNLOCK (webrtc);
1196     g_object_notify (G_OBJECT (webrtc), "ice-connection-state");
1197     PC_LOCK (webrtc);
1198   }
1199 }
1200
1201 static void
1202 _update_ice_connection_state (GstWebRTCBin * webrtc)
1203 {
1204   gst_webrtc_bin_enqueue_task (webrtc, _update_ice_connection_state_task, NULL,
1205       NULL, NULL);
1206 }
1207
1208 static void
1209 _update_peer_connection_state_task (GstWebRTCBin * webrtc, gpointer data)
1210 {
1211   GstWebRTCPeerConnectionState old_state = webrtc->peer_connection_state;
1212   GstWebRTCPeerConnectionState new_state;
1213
1214   new_state = _collate_peer_connection_states (webrtc);
1215
1216   if (new_state != old_state) {
1217     gchar *old_s, *new_s;
1218
1219     old_s = _enum_value_to_string (GST_TYPE_WEBRTC_PEER_CONNECTION_STATE,
1220         old_state);
1221     new_s = _enum_value_to_string (GST_TYPE_WEBRTC_PEER_CONNECTION_STATE,
1222         new_state);
1223     GST_INFO_OBJECT (webrtc,
1224         "Peer connection state change from %s(%u) to %s(%u)", old_s, old_state,
1225         new_s, new_state);
1226     g_free (old_s);
1227     g_free (new_s);
1228
1229     webrtc->peer_connection_state = new_state;
1230     PC_UNLOCK (webrtc);
1231     g_object_notify (G_OBJECT (webrtc), "connection-state");
1232     PC_LOCK (webrtc);
1233   }
1234 }
1235
1236 static void
1237 _update_peer_connection_state (GstWebRTCBin * webrtc)
1238 {
1239   gst_webrtc_bin_enqueue_task (webrtc, _update_peer_connection_state_task,
1240       NULL, NULL, NULL);
1241 }
1242
1243 static gboolean
1244 _all_sinks_have_caps (GstWebRTCBin * webrtc)
1245 {
1246   GList *l;
1247   gboolean res = FALSE;
1248
1249   GST_OBJECT_LOCK (webrtc);
1250   l = GST_ELEMENT (webrtc)->pads;
1251   for (; l; l = g_list_next (l)) {
1252     GstWebRTCBinPad *wpad;
1253
1254     if (!GST_IS_WEBRTC_BIN_PAD (l->data))
1255       continue;
1256
1257     wpad = GST_WEBRTC_BIN_PAD (l->data);
1258     if (GST_PAD_DIRECTION (l->data) == GST_PAD_SINK && !wpad->received_caps
1259         && (!wpad->trans || !wpad->trans->stopped)) {
1260       goto done;
1261     }
1262   }
1263
1264   l = webrtc->priv->pending_pads;
1265   for (; l; l = g_list_next (l)) {
1266     if (!GST_IS_WEBRTC_BIN_PAD (l->data)) {
1267       goto done;
1268     }
1269   }
1270
1271   res = TRUE;
1272
1273 done:
1274   GST_OBJECT_UNLOCK (webrtc);
1275   return res;
1276 }
1277
1278 /* http://w3c.github.io/webrtc-pc/#dfn-check-if-negotiation-is-needed */
1279 static gboolean
1280 _check_if_negotiation_is_needed (GstWebRTCBin * webrtc)
1281 {
1282   int i;
1283
1284   GST_LOG_OBJECT (webrtc, "checking if negotiation is needed");
1285
1286   /* We can't negotiate until we have received caps on all our sink pads,
1287    * as we will need the ssrcs in our offer / answer */
1288   if (!_all_sinks_have_caps (webrtc)) {
1289     GST_LOG_OBJECT (webrtc,
1290         "no negotiation possible until caps have been received on all sink pads");
1291     return FALSE;
1292   }
1293
1294   /* If any implementation-specific negotiation is required, as described at
1295    * the start of this section, return "true".
1296    * FIXME */
1297   /* FIXME: emit when input caps/format changes? */
1298
1299   if (!webrtc->current_local_description) {
1300     GST_LOG_OBJECT (webrtc, "no local description set");
1301     return TRUE;
1302   }
1303
1304   if (!webrtc->current_remote_description) {
1305     GST_LOG_OBJECT (webrtc, "no remote description set");
1306     return TRUE;
1307   }
1308
1309   /* If connection has created any RTCDataChannel's, and no m= section has
1310    * been negotiated yet for data, return "true". */
1311   if (webrtc->priv->data_channels->len > 0) {
1312     if (_message_get_datachannel_index (webrtc->current_local_description->
1313             sdp) >= G_MAXUINT) {
1314       GST_LOG_OBJECT (webrtc,
1315           "no data channel media section and have %u " "transports",
1316           webrtc->priv->data_channels->len);
1317       return TRUE;
1318     }
1319   }
1320
1321   for (i = 0; i < webrtc->priv->transceivers->len; i++) {
1322     GstWebRTCRTPTransceiver *trans;
1323
1324     trans = g_ptr_array_index (webrtc->priv->transceivers, i);
1325
1326     if (trans->stopped) {
1327       /* FIXME: If t is stopped and is associated with an m= section according to
1328        * [JSEP] (section 3.4.1.), but the associated m= section is not yet
1329        * rejected in connection's currentLocalDescription or
1330        * currentRemoteDescription , return "true". */
1331       GST_FIXME_OBJECT (webrtc,
1332           "check if the transceiver is rejected in descriptions");
1333     } else {
1334       const GstSDPMedia *media;
1335       GstWebRTCRTPTransceiverDirection local_dir, remote_dir;
1336
1337       if (trans->mline == -1 || trans->mid == NULL) {
1338         GST_LOG_OBJECT (webrtc, "unassociated transceiver %i %" GST_PTR_FORMAT
1339             " mid %s", i, trans, trans->mid);
1340         return TRUE;
1341       }
1342       /* internal inconsistency */
1343       g_assert (trans->mline <
1344           gst_sdp_message_medias_len (webrtc->current_local_description->sdp));
1345       g_assert (trans->mline <
1346           gst_sdp_message_medias_len (webrtc->current_remote_description->sdp));
1347
1348       /* FIXME: msid handling
1349        * If t's direction is "sendrecv" or "sendonly", and the associated m=
1350        * section in connection's currentLocalDescription doesn't contain an
1351        * "a=msid" line, return "true". */
1352
1353       media =
1354           gst_sdp_message_get_media (webrtc->current_local_description->sdp,
1355           trans->mline);
1356       local_dir = _get_direction_from_media (media);
1357
1358       media =
1359           gst_sdp_message_get_media (webrtc->current_remote_description->sdp,
1360           trans->mline);
1361       remote_dir = _get_direction_from_media (media);
1362
1363       if (webrtc->current_local_description->type == GST_WEBRTC_SDP_TYPE_OFFER) {
1364         /* If connection's currentLocalDescription if of type "offer", and
1365          * the direction of the associated m= section in neither the offer
1366          * nor answer matches t's direction, return "true". */
1367
1368         if (local_dir != trans->direction && remote_dir != trans->direction) {
1369           gchar *local_str, *remote_str, *dir_str;
1370
1371           local_str =
1372               _enum_value_to_string (GST_TYPE_WEBRTC_RTP_TRANSCEIVER_DIRECTION,
1373               local_dir);
1374           remote_str =
1375               _enum_value_to_string (GST_TYPE_WEBRTC_RTP_TRANSCEIVER_DIRECTION,
1376               remote_dir);
1377           dir_str =
1378               _enum_value_to_string (GST_TYPE_WEBRTC_RTP_TRANSCEIVER_DIRECTION,
1379               trans->direction);
1380
1381           GST_LOG_OBJECT (webrtc, "transceiver direction (%s) doesn't match "
1382               "description (local %s remote %s)", dir_str, local_str,
1383               remote_str);
1384
1385           g_free (dir_str);
1386           g_free (local_str);
1387           g_free (remote_str);
1388
1389           return TRUE;
1390         }
1391       } else if (webrtc->current_local_description->type ==
1392           GST_WEBRTC_SDP_TYPE_ANSWER) {
1393         GstWebRTCRTPTransceiverDirection intersect_dir;
1394
1395         /* If connection's currentLocalDescription if of type "answer", and
1396          * the direction of the associated m= section in the answer does not
1397          * match t's direction intersected with the offered direction (as
1398          * described in [JSEP] (section 5.3.1.)), return "true". */
1399
1400         /* remote is the offer, local is the answer */
1401         intersect_dir = _intersect_answer_directions (remote_dir, local_dir);
1402
1403         if (intersect_dir != trans->direction) {
1404           gchar *local_str, *remote_str, *inter_str, *dir_str;
1405
1406           local_str =
1407               _enum_value_to_string (GST_TYPE_WEBRTC_RTP_TRANSCEIVER_DIRECTION,
1408               local_dir);
1409           remote_str =
1410               _enum_value_to_string (GST_TYPE_WEBRTC_RTP_TRANSCEIVER_DIRECTION,
1411               remote_dir);
1412           dir_str =
1413               _enum_value_to_string (GST_TYPE_WEBRTC_RTP_TRANSCEIVER_DIRECTION,
1414               trans->direction);
1415           inter_str =
1416               _enum_value_to_string (GST_TYPE_WEBRTC_RTP_TRANSCEIVER_DIRECTION,
1417               intersect_dir);
1418
1419           GST_LOG_OBJECT (webrtc, "transceiver direction (%s) doesn't match "
1420               "description intersected direction %s (local %s remote %s)",
1421               dir_str, local_str, inter_str, remote_str);
1422
1423           g_free (dir_str);
1424           g_free (local_str);
1425           g_free (remote_str);
1426           g_free (inter_str);
1427
1428           return TRUE;
1429         }
1430       }
1431     }
1432   }
1433
1434   GST_LOG_OBJECT (webrtc, "no negotiation needed");
1435   return FALSE;
1436 }
1437
1438 static void
1439 _check_need_negotiation_task (GstWebRTCBin * webrtc, gpointer unused)
1440 {
1441   if (webrtc->priv->need_negotiation) {
1442     GST_TRACE_OBJECT (webrtc, "emitting on-negotiation-needed");
1443     PC_UNLOCK (webrtc);
1444     g_signal_emit (webrtc, gst_webrtc_bin_signals[ON_NEGOTIATION_NEEDED_SIGNAL],
1445         0);
1446     PC_LOCK (webrtc);
1447   }
1448 }
1449
1450 /* http://w3c.github.io/webrtc-pc/#dfn-update-the-negotiation-needed-flag */
1451 static void
1452 _update_need_negotiation (GstWebRTCBin * webrtc)
1453 {
1454   /* If connection's [[isClosed]] slot is true, abort these steps. */
1455   if (webrtc->priv->is_closed)
1456     return;
1457   /* If connection's signaling state is not "stable", abort these steps. */
1458   if (webrtc->signaling_state != GST_WEBRTC_SIGNALING_STATE_STABLE)
1459     return;
1460
1461   /* If the result of checking if negotiation is needed is "false", clear the
1462    * negotiation-needed flag by setting connection's [[ needNegotiation]] slot
1463    * to false, and abort these steps. */
1464   if (!_check_if_negotiation_is_needed (webrtc)) {
1465     webrtc->priv->need_negotiation = FALSE;
1466     return;
1467   }
1468   /* If connection's [[needNegotiation]] slot is already true, abort these steps. */
1469   if (webrtc->priv->need_negotiation)
1470     return;
1471   /* Set connection's [[needNegotiation]] slot to true. */
1472   webrtc->priv->need_negotiation = TRUE;
1473   /* Queue a task to check connection's [[ needNegotiation]] slot and, if still
1474    * true, fire a simple event named negotiationneeded at connection. */
1475   gst_webrtc_bin_enqueue_task (webrtc, _check_need_negotiation_task, NULL,
1476       NULL, NULL);
1477 }
1478
1479 static GstCaps *
1480 _find_codec_preferences (GstWebRTCBin * webrtc,
1481     GstWebRTCRTPTransceiver * rtp_trans, GstPadDirection direction,
1482     guint media_idx)
1483 {
1484   WebRTCTransceiver *trans = (WebRTCTransceiver *) rtp_trans;
1485   GstCaps *ret = NULL;
1486
1487   GST_LOG_OBJECT (webrtc, "retrieving codec preferences from %" GST_PTR_FORMAT,
1488       trans);
1489
1490   if (rtp_trans && rtp_trans->codec_preferences) {
1491     GST_LOG_OBJECT (webrtc, "Using codec preferences: %" GST_PTR_FORMAT,
1492         rtp_trans->codec_preferences);
1493     ret = gst_caps_ref (rtp_trans->codec_preferences);
1494   } else {
1495     GstWebRTCBinPad *pad = NULL;
1496
1497     /* try to find a pad */
1498     if (!trans
1499         || !(pad = _find_pad_for_transceiver (webrtc, direction, rtp_trans)))
1500       pad = _find_pad_for_mline (webrtc, direction, media_idx);
1501
1502     if (!pad) {
1503       if (trans && trans->last_configured_caps)
1504         ret = gst_caps_ref (trans->last_configured_caps);
1505     } else {
1506       GstCaps *caps = NULL;
1507
1508       if (pad->received_caps) {
1509         caps = gst_caps_ref (pad->received_caps);
1510       } else if ((caps = gst_pad_get_current_caps (GST_PAD (pad)))) {
1511         GST_LOG_OBJECT (webrtc, "Using current pad caps: %" GST_PTR_FORMAT,
1512             caps);
1513       } else {
1514         static GstStaticCaps static_filter =
1515             GST_STATIC_CAPS ("application/x-rtp, "
1516             "media = (string) { audio, video }, payload = (int) [ 0, 127 ]");
1517         GstCaps *filter = gst_static_caps_get (&static_filter);
1518
1519         filter = gst_caps_make_writable (filter);
1520
1521         if (rtp_trans->kind == GST_WEBRTC_KIND_AUDIO)
1522           gst_caps_set_simple (filter, "media", G_TYPE_STRING, "audio", NULL);
1523         else if (rtp_trans->kind == GST_WEBRTC_KIND_VIDEO)
1524           gst_caps_set_simple (filter, "media", G_TYPE_STRING, "video", NULL);
1525
1526         caps = gst_pad_peer_query_caps (GST_PAD (pad), filter);
1527         GST_LOG_OBJECT (webrtc, "Using peer query caps: %" GST_PTR_FORMAT,
1528             caps);
1529
1530         if (!gst_caps_is_fixed (caps) || gst_caps_is_equal_fixed (caps, filter)
1531             || gst_caps_is_empty (caps) || gst_caps_is_any (caps)) {
1532           gst_caps_unref (caps);
1533           caps = NULL;
1534         }
1535         gst_caps_unref (filter);
1536       }
1537       if (caps) {
1538         if (trans)
1539           gst_caps_replace (&trans->last_configured_caps, caps);
1540
1541         ret = caps;
1542       }
1543
1544       gst_object_unref (pad);
1545     }
1546   }
1547
1548   if (!ret)
1549     GST_DEBUG_OBJECT (trans, "Could not find caps for mline %u", media_idx);
1550
1551   return ret;
1552 }
1553
1554 static GstCaps *
1555 _add_supported_attributes_to_caps (GstWebRTCBin * webrtc,
1556     WebRTCTransceiver * trans, const GstCaps * caps)
1557 {
1558   GstCaps *ret;
1559   guint i;
1560
1561   if (caps == NULL)
1562     return NULL;
1563
1564   ret = gst_caps_make_writable (caps);
1565
1566   for (i = 0; i < gst_caps_get_size (ret); i++) {
1567     GstStructure *s = gst_caps_get_structure (ret, i);
1568
1569     if (trans->do_nack)
1570       if (!gst_structure_has_field (s, "rtcp-fb-nack"))
1571         gst_structure_set (s, "rtcp-fb-nack", G_TYPE_BOOLEAN, TRUE, NULL);
1572
1573     if (!gst_structure_has_field (s, "rtcp-fb-nack-pli"))
1574       gst_structure_set (s, "rtcp-fb-nack-pli", G_TYPE_BOOLEAN, TRUE, NULL);
1575     /* FIXME: is this needed? */
1576     /*if (!gst_structure_has_field (s, "rtcp-fb-transport-cc"))
1577        gst_structure_set (s, "rtcp-fb-nack-pli", G_TYPE_BOOLEAN, TRUE, NULL); */
1578
1579     /* FIXME: codec-specific parameters? */
1580   }
1581
1582   return ret;
1583 }
1584
1585 static void
1586 _on_ice_transport_notify_state (GstWebRTCICETransport * transport,
1587     GParamSpec * pspec, GstWebRTCBin * webrtc)
1588 {
1589   _update_ice_connection_state (webrtc);
1590   _update_peer_connection_state (webrtc);
1591 }
1592
1593 static void
1594 _on_ice_transport_notify_gathering_state (GstWebRTCICETransport * transport,
1595     GParamSpec * pspec, GstWebRTCBin * webrtc)
1596 {
1597   _update_ice_gathering_state (webrtc);
1598 }
1599
1600 static void
1601 _on_dtls_transport_notify_state (GstWebRTCDTLSTransport * transport,
1602     GParamSpec * pspec, GstWebRTCBin * webrtc)
1603 {
1604   _update_peer_connection_state (webrtc);
1605 }
1606
1607 static gboolean
1608 match_ssrc (GstWebRTCRTPTransceiver * rtp_trans, gconstpointer data)
1609 {
1610   WebRTCTransceiver *trans = (WebRTCTransceiver *) rtp_trans;
1611
1612   return (trans->current_ssrc == GPOINTER_TO_UINT (data));
1613 }
1614
1615 static gboolean
1616 _on_sending_rtcp (GObject * internal_session, GstBuffer * buffer,
1617     gboolean early, gpointer user_data)
1618 {
1619   GstWebRTCBin *webrtc = user_data;
1620   GstRTCPBuffer rtcp = GST_RTCP_BUFFER_INIT;
1621   GstRTCPPacket packet;
1622
1623   if (!gst_rtcp_buffer_map (buffer, GST_MAP_READ, &rtcp))
1624     goto done;
1625
1626   if (gst_rtcp_buffer_get_first_packet (&rtcp, &packet)) {
1627     if (gst_rtcp_packet_get_type (&packet) == GST_RTCP_TYPE_SR) {
1628       guint32 ssrc;
1629       GstWebRTCRTPTransceiver *rtp_trans;
1630       WebRTCTransceiver *trans;
1631
1632       gst_rtcp_packet_sr_get_sender_info (&packet, &ssrc, NULL, NULL, NULL,
1633           NULL);
1634
1635       rtp_trans = _find_transceiver (webrtc, GUINT_TO_POINTER (ssrc),
1636           match_ssrc);
1637       trans = (WebRTCTransceiver *) rtp_trans;
1638
1639       if (rtp_trans && rtp_trans->sender && trans->ssrc_event) {
1640         GstPad *pad;
1641         gchar *pad_name = NULL;
1642
1643         pad_name =
1644             g_strdup_printf ("send_rtcp_src_%u",
1645             rtp_trans->sender->transport->session_id);
1646         pad = gst_element_get_static_pad (webrtc->rtpbin, pad_name);
1647         g_free (pad_name);
1648         if (pad) {
1649           gst_pad_push_event (pad, gst_event_ref (trans->ssrc_event));
1650           gst_object_unref (pad);
1651         }
1652       }
1653     }
1654   }
1655
1656   gst_rtcp_buffer_unmap (&rtcp);
1657
1658 done:
1659   /* False means we don't care about suppression */
1660   return FALSE;
1661 }
1662
1663 static void
1664 gst_webrtc_bin_attach_tos_to_session (GstWebRTCBin * webrtc, guint session_id)
1665 {
1666   GObject *internal_session = NULL;
1667
1668   g_signal_emit_by_name (webrtc->rtpbin, "get-internal-session",
1669       session_id, &internal_session);
1670
1671   if (internal_session) {
1672     g_signal_connect (internal_session, "on-sending-rtcp",
1673         G_CALLBACK (_on_sending_rtcp), webrtc);
1674     g_object_unref (internal_session);
1675   }
1676 }
1677
1678 static GstPadProbeReturn
1679 _nicesink_pad_probe (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
1680 {
1681   GstWebRTCBin *webrtc = user_data;
1682
1683   if (GST_EVENT_TYPE (GST_PAD_PROBE_INFO_EVENT (info))
1684       == GST_EVENT_CUSTOM_DOWNSTREAM_STICKY) {
1685     const GstStructure *s =
1686         gst_event_get_structure (GST_PAD_PROBE_INFO_EVENT (info));
1687
1688     if (gst_structure_has_name (s, "GstWebRtcBinUpdateTos")) {
1689       guint ssrc;
1690       gint priority;
1691
1692       if (gst_structure_get_uint (s, "ssrc", &ssrc)) {
1693         GstWebRTCRTPTransceiver *rtp_trans;
1694
1695         rtp_trans = _find_transceiver (webrtc, GUINT_TO_POINTER (ssrc),
1696             match_ssrc);
1697         if (rtp_trans) {
1698           WebRTCTransceiver *trans = WEBRTC_TRANSCEIVER (rtp_trans);
1699           GstWebRTCICEStream *stream = _find_ice_stream_for_session (webrtc,
1700               trans->stream->session_id);
1701           guint8 dscp = 0;
1702
1703           /* Set DSCP field based on
1704            * https://tools.ietf.org/html/draft-ietf-tsvwg-rtcweb-qos-18#section-5
1705            */
1706           switch (rtp_trans->sender->priority) {
1707             case GST_WEBRTC_PRIORITY_TYPE_VERY_LOW:
1708               dscp = 8;         /* CS1 */
1709               break;
1710             case GST_WEBRTC_PRIORITY_TYPE_LOW:
1711               dscp = 0;         /* DF */
1712               break;
1713             case GST_WEBRTC_PRIORITY_TYPE_MEDIUM:
1714               switch (rtp_trans->kind) {
1715                 case GST_WEBRTC_KIND_AUDIO:
1716                   dscp = 46;    /* EF */
1717                   break;
1718                 case GST_WEBRTC_KIND_VIDEO:
1719                   dscp = 38;    /* AF43 *//* TODO: differentiate non-interactive */
1720                   break;
1721                 case GST_WEBRTC_KIND_UNKNOWN:
1722                   dscp = 0;
1723                   break;
1724               }
1725               break;
1726             case GST_WEBRTC_PRIORITY_TYPE_HIGH:
1727               switch (rtp_trans->kind) {
1728                 case GST_WEBRTC_KIND_AUDIO:
1729                   dscp = 46;    /* EF */
1730                   break;
1731                 case GST_WEBRTC_KIND_VIDEO:
1732                   dscp = 36;    /* AF42 *//* TODO: differentiate non-interactive */
1733                   break;
1734                 case GST_WEBRTC_KIND_UNKNOWN:
1735                   dscp = 0;
1736                   break;
1737               }
1738               break;
1739           }
1740
1741           gst_webrtc_ice_set_tos (webrtc->priv->ice, stream, dscp << 2);
1742         }
1743       } else if (gst_structure_get_enum (s, "sctp-priority",
1744               GST_TYPE_WEBRTC_PRIORITY_TYPE, &priority)) {
1745         guint8 dscp = 0;
1746
1747         /* Set DSCP field based on
1748          * https://tools.ietf.org/html/draft-ietf-tsvwg-rtcweb-qos-18#section-5
1749          */
1750         switch (priority) {
1751           case GST_WEBRTC_PRIORITY_TYPE_VERY_LOW:
1752             dscp = 8;           /* CS1 */
1753             break;
1754           case GST_WEBRTC_PRIORITY_TYPE_LOW:
1755             dscp = 0;           /* DF */
1756             break;
1757           case GST_WEBRTC_PRIORITY_TYPE_MEDIUM:
1758             dscp = 10;          /* AF11 */
1759             break;
1760           case GST_WEBRTC_PRIORITY_TYPE_HIGH:
1761             dscp = 18;          /* AF21 */
1762             break;
1763         }
1764         if (webrtc->priv->data_channel_transport)
1765           gst_webrtc_ice_set_tos (webrtc->priv->ice,
1766               webrtc->priv->data_channel_transport->stream, dscp << 2);
1767       }
1768     }
1769   }
1770   return GST_PAD_PROBE_OK;
1771 }
1772
1773 static void gst_webrtc_bin_attach_tos (GstWebRTCBin * webrtc);
1774
1775 static void
1776 gst_webrtc_bin_update_sctp_priority (GstWebRTCBin * webrtc)
1777 {
1778   GstWebRTCPriorityType sctp_priority = 0;
1779   guint i;
1780
1781   if (!webrtc->priv->sctp_transport)
1782     return;
1783
1784   for (i = 0; i < webrtc->priv->data_channels->len; i++) {
1785     GstWebRTCDataChannel *channel
1786         = g_ptr_array_index (webrtc->priv->data_channels, i);
1787
1788     sctp_priority = MAX (sctp_priority, channel->priority);
1789   }
1790
1791   /* Default priority is low means DSCP field is left as 0 */
1792   if (sctp_priority == 0)
1793     sctp_priority = GST_WEBRTC_PRIORITY_TYPE_LOW;
1794
1795   /* Nobody asks for DSCP, leave it as-is */
1796   if (sctp_priority == GST_WEBRTC_PRIORITY_TYPE_LOW &&
1797       !webrtc->priv->tos_attached)
1798     return;
1799
1800   /* If one stream has a non-default priority, then everyone else does too */
1801   gst_webrtc_bin_attach_tos (webrtc);
1802
1803   gst_webrtc_sctp_transport_set_priority (webrtc->priv->sctp_transport,
1804       sctp_priority);
1805 }
1806
1807 static void
1808 gst_webrtc_bin_attach_probe_to_ice_sink (GstWebRTCBin * webrtc,
1809     GstWebRTCICETransport * transport)
1810 {
1811   GstPad *pad;
1812
1813   pad = gst_element_get_static_pad (transport->sink, "sink");
1814   gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
1815       _nicesink_pad_probe, g_object_ref (webrtc),
1816       (GDestroyNotify) gst_object_unref);
1817   gst_object_unref (pad);
1818 }
1819
1820 static void
1821 gst_webrtc_bin_attach_tos (GstWebRTCBin * webrtc)
1822 {
1823   guint i;
1824
1825   if (webrtc->priv->tos_attached)
1826     return;
1827   webrtc->priv->tos_attached = TRUE;
1828
1829   for (i = 0; i < webrtc->priv->transports->len; i++) {
1830     TransportStream *stream = g_ptr_array_index (webrtc->priv->transports, i);
1831
1832     gst_webrtc_bin_attach_tos_to_session (webrtc, stream->session_id);
1833
1834     gst_webrtc_bin_attach_probe_to_ice_sink (webrtc,
1835         stream->transport->transport);
1836   }
1837
1838   gst_webrtc_bin_update_sctp_priority (webrtc);
1839 }
1840
1841 static WebRTCTransceiver *
1842 _create_webrtc_transceiver (GstWebRTCBin * webrtc,
1843     GstWebRTCRTPTransceiverDirection direction, guint mline)
1844 {
1845   WebRTCTransceiver *trans;
1846   GstWebRTCRTPTransceiver *rtp_trans;
1847   GstWebRTCRTPSender *sender;
1848   GstWebRTCRTPReceiver *receiver;
1849
1850   sender = gst_webrtc_rtp_sender_new ();
1851   receiver = gst_webrtc_rtp_receiver_new ();
1852   trans = webrtc_transceiver_new (webrtc, sender, receiver);
1853   rtp_trans = GST_WEBRTC_RTP_TRANSCEIVER (trans);
1854   rtp_trans->direction = direction;
1855   rtp_trans->mline = mline;
1856   /* FIXME: We don't support stopping transceiver yet so they're always not stopped */
1857   rtp_trans->stopped = FALSE;
1858
1859   g_signal_connect_object (sender, "notify::priority",
1860       G_CALLBACK (gst_webrtc_bin_attach_tos), webrtc, G_CONNECT_SWAPPED);
1861
1862   g_ptr_array_add (webrtc->priv->transceivers, trans);
1863
1864   gst_object_unref (sender);
1865   gst_object_unref (receiver);
1866
1867   g_signal_emit (webrtc, gst_webrtc_bin_signals[ON_NEW_TRANSCEIVER_SIGNAL],
1868       0, trans);
1869
1870   return trans;
1871 }
1872
1873 static TransportStream *
1874 _create_transport_channel (GstWebRTCBin * webrtc, guint session_id)
1875 {
1876   GstWebRTCDTLSTransport *transport;
1877   TransportStream *ret;
1878
1879   /* FIXME: how to parametrize the sender and the receiver */
1880   ret = transport_stream_new (webrtc, session_id);
1881   transport = ret->transport;
1882
1883   g_signal_connect (G_OBJECT (transport->transport), "notify::state",
1884       G_CALLBACK (_on_ice_transport_notify_state), webrtc);
1885   g_signal_connect (G_OBJECT (transport->transport),
1886       "notify::gathering-state",
1887       G_CALLBACK (_on_ice_transport_notify_gathering_state), webrtc);
1888   g_signal_connect (G_OBJECT (transport), "notify::state",
1889       G_CALLBACK (_on_dtls_transport_notify_state), webrtc);
1890   if (webrtc->priv->tos_attached)
1891     gst_webrtc_bin_attach_probe_to_ice_sink (webrtc, transport->transport);
1892
1893   GST_TRACE_OBJECT (webrtc,
1894       "Create transport %" GST_PTR_FORMAT " for session %u", ret, session_id);
1895
1896   return ret;
1897 }
1898
1899 static TransportStream *
1900 _get_or_create_rtp_transport_channel (GstWebRTCBin * webrtc, guint session_id)
1901 {
1902   TransportStream *ret;
1903   gchar *pad_name;
1904
1905   ret = _find_transport_for_session (webrtc, session_id);
1906
1907   if (!ret) {
1908     ret = _create_transport_channel (webrtc, session_id);
1909     gst_bin_add (GST_BIN (webrtc), GST_ELEMENT (ret->send_bin));
1910     gst_bin_add (GST_BIN (webrtc), GST_ELEMENT (ret->receive_bin));
1911     g_ptr_array_add (webrtc->priv->transports, ret);
1912
1913     pad_name = g_strdup_printf ("recv_rtcp_sink_%u", ret->session_id);
1914     if (!gst_element_link_pads (GST_ELEMENT (ret->receive_bin), "rtcp_src",
1915             GST_ELEMENT (webrtc->rtpbin), pad_name))
1916       g_warn_if_reached ();
1917     g_free (pad_name);
1918
1919     pad_name = g_strdup_printf ("send_rtcp_src_%u", ret->session_id);
1920     if (!gst_element_link_pads (GST_ELEMENT (webrtc->rtpbin), pad_name,
1921             GST_ELEMENT (ret->send_bin), "rtcp_sink"))
1922       g_warn_if_reached ();
1923     if (webrtc->priv->tos_attached)
1924       gst_webrtc_bin_attach_tos_to_session (webrtc, ret->session_id);
1925     g_free (pad_name);
1926   }
1927
1928   gst_element_sync_state_with_parent (GST_ELEMENT (ret->send_bin));
1929   gst_element_sync_state_with_parent (GST_ELEMENT (ret->receive_bin));
1930
1931   return ret;
1932 }
1933
1934 /* this is called from the webrtc thread with the pc lock held */
1935 static void
1936 _on_data_channel_ready_state (WebRTCDataChannel * channel,
1937     GParamSpec * pspec, GstWebRTCBin * webrtc)
1938 {
1939   GstWebRTCDataChannelState ready_state;
1940   guint i;
1941
1942   g_object_get (channel, "ready-state", &ready_state, NULL);
1943
1944   if (ready_state == GST_WEBRTC_DATA_CHANNEL_STATE_OPEN) {
1945     gboolean found = FALSE;
1946
1947     for (i = 0; i < webrtc->priv->pending_data_channels->len; i++) {
1948       WebRTCDataChannel *c;
1949
1950       c = g_ptr_array_index (webrtc->priv->pending_data_channels, i);
1951       if (c == channel) {
1952         found = TRUE;
1953         g_ptr_array_remove_index (webrtc->priv->pending_data_channels, i);
1954         break;
1955       }
1956     }
1957     if (found == FALSE) {
1958       GST_FIXME_OBJECT (webrtc, "Received open for unknown data channel");
1959       return;
1960     }
1961
1962     g_ptr_array_add (webrtc->priv->data_channels, channel);
1963
1964     gst_webrtc_bin_update_sctp_priority (webrtc);
1965
1966     g_signal_emit (webrtc, gst_webrtc_bin_signals[ON_DATA_CHANNEL_SIGNAL], 0,
1967         gst_object_ref (channel));
1968   }
1969 }
1970
1971 static void
1972 _on_sctpdec_pad_added (GstElement * sctpdec, GstPad * pad,
1973     GstWebRTCBin * webrtc)
1974 {
1975   WebRTCDataChannel *channel;
1976   guint stream_id;
1977   GstPad *sink_pad;
1978
1979   if (sscanf (GST_PAD_NAME (pad), "src_%u", &stream_id) != 1)
1980     return;
1981
1982   PC_LOCK (webrtc);
1983   channel = _find_data_channel_for_id (webrtc, stream_id);
1984   if (!channel) {
1985     channel = g_object_new (WEBRTC_TYPE_DATA_CHANNEL, NULL);
1986     channel->parent.id = stream_id;
1987     channel->webrtcbin = webrtc;
1988
1989     gst_bin_add (GST_BIN (webrtc), channel->appsrc);
1990     gst_bin_add (GST_BIN (webrtc), channel->appsink);
1991
1992     gst_element_sync_state_with_parent (channel->appsrc);
1993     gst_element_sync_state_with_parent (channel->appsink);
1994
1995     webrtc_data_channel_link_to_sctp (channel, webrtc->priv->sctp_transport);
1996
1997     g_ptr_array_add (webrtc->priv->pending_data_channels, channel);
1998   }
1999
2000   g_signal_connect (channel, "notify::ready-state",
2001       G_CALLBACK (_on_data_channel_ready_state), webrtc);
2002
2003   sink_pad = gst_element_get_static_pad (channel->appsink, "sink");
2004   if (gst_pad_link (pad, sink_pad) != GST_PAD_LINK_OK)
2005     GST_WARNING_OBJECT (channel, "Failed to link sctp pad %s with channel %"
2006         GST_PTR_FORMAT, GST_PAD_NAME (pad), channel);
2007   gst_object_unref (sink_pad);
2008   PC_UNLOCK (webrtc);
2009 }
2010
2011 static void
2012 _on_sctp_state_notify (GstWebRTCSCTPTransport * sctp, GParamSpec * pspec,
2013     GstWebRTCBin * webrtc)
2014 {
2015   GstWebRTCSCTPTransportState state;
2016
2017   g_object_get (sctp, "state", &state, NULL);
2018
2019   if (state == GST_WEBRTC_SCTP_TRANSPORT_STATE_CONNECTED) {
2020     int i;
2021
2022     PC_LOCK (webrtc);
2023     GST_DEBUG_OBJECT (webrtc, "SCTP association established");
2024
2025     for (i = 0; i < webrtc->priv->data_channels->len; i++) {
2026       WebRTCDataChannel *channel;
2027
2028       channel = g_ptr_array_index (webrtc->priv->data_channels, i);
2029
2030       webrtc_data_channel_link_to_sctp (channel, webrtc->priv->sctp_transport);
2031
2032       if (!channel->parent.negotiated && !channel->opened)
2033         webrtc_data_channel_start_negotiation (channel);
2034     }
2035     PC_UNLOCK (webrtc);
2036   }
2037 }
2038
2039 /* Forward declaration so we can easily disconnect the signal handler */
2040 static void _on_sctp_notify_dtls_state (GstWebRTCDTLSTransport * transport,
2041     GParamSpec * pspec, GstWebRTCBin * webrtc);
2042
2043 static void
2044 _sctp_check_dtls_state_task (GstWebRTCBin * webrtc, gpointer unused)
2045 {
2046   TransportStream *stream;
2047   GstWebRTCDTLSTransport *transport;
2048   GstWebRTCDTLSTransportState dtls_state;
2049   GstWebRTCSCTPTransport *sctp_transport;
2050
2051   stream = webrtc->priv->data_channel_transport;
2052   transport = stream->transport;
2053
2054   g_object_get (transport, "state", &dtls_state, NULL);
2055   /* Not connected yet so just return */
2056   if (dtls_state != GST_WEBRTC_DTLS_TRANSPORT_STATE_CONNECTED) {
2057     GST_DEBUG_OBJECT (webrtc,
2058         "Data channel DTLS connection is not ready yet: %d", dtls_state);
2059     return;
2060   }
2061
2062   GST_DEBUG_OBJECT (webrtc, "Data channel DTLS connection is now ready");
2063   sctp_transport = webrtc->priv->sctp_transport;
2064
2065   /* Not locked state anymore so this was already taken care of before */
2066   if (!gst_element_is_locked_state (sctp_transport->sctpdec))
2067     return;
2068
2069   /* Start up the SCTP elements now that the DTLS connection is established */
2070   gst_element_set_locked_state (sctp_transport->sctpdec, FALSE);
2071   gst_element_set_locked_state (sctp_transport->sctpenc, FALSE);
2072
2073   gst_element_sync_state_with_parent (GST_ELEMENT (sctp_transport->sctpdec));
2074   gst_element_sync_state_with_parent (GST_ELEMENT (sctp_transport->sctpenc));
2075
2076   if (sctp_transport->sctpdec_block_id) {
2077     GstPad *receive_srcpad;
2078
2079     receive_srcpad =
2080         gst_element_get_static_pad (GST_ELEMENT (stream->receive_bin),
2081         "data_src");
2082     gst_pad_remove_probe (receive_srcpad, sctp_transport->sctpdec_block_id);
2083
2084     sctp_transport->sctpdec_block_id = 0;
2085     gst_object_unref (receive_srcpad);
2086   }
2087
2088   g_signal_handlers_disconnect_by_func (transport, _on_sctp_notify_dtls_state,
2089       webrtc);
2090 }
2091
2092 static void
2093 _on_sctp_notify_dtls_state (GstWebRTCDTLSTransport * transport,
2094     GParamSpec * pspec, GstWebRTCBin * webrtc)
2095 {
2096   GstWebRTCDTLSTransportState dtls_state;
2097
2098   g_object_get (transport, "state", &dtls_state, NULL);
2099
2100   GST_TRACE_OBJECT (webrtc, "Data channel DTLS state changed to %d",
2101       dtls_state);
2102
2103   /* Connected now, so schedule a task to update the state of the SCTP
2104    * elements */
2105   if (dtls_state == GST_WEBRTC_DTLS_TRANSPORT_STATE_CONNECTED) {
2106     gst_webrtc_bin_enqueue_task (webrtc,
2107         (GstWebRTCBinFunc) _sctp_check_dtls_state_task, NULL, NULL, NULL);
2108   }
2109 }
2110
2111 static GstPadProbeReturn
2112 sctp_pad_block (GstPad * pad, GstPadProbeInfo * info, gpointer unused)
2113 {
2114   /* Drop all events: we don't care about them and don't want to block on
2115    * them. Sticky events would be forwarded again later once we unblock
2116    * and we don't want to forward them here already because that might
2117    * cause a spurious GST_FLOW_FLUSHING */
2118   if (GST_IS_EVENT (info->data))
2119     return GST_PAD_PROBE_DROP;
2120
2121   /* But block on any actual data-flow so we don't accidentally send that
2122    * to a pad that is not ready yet, causing GST_FLOW_FLUSHING and everything
2123    * to silently stop.
2124    */
2125   GST_LOG_OBJECT (pad, "blocking pad with data %" GST_PTR_FORMAT, info->data);
2126
2127   return GST_PAD_PROBE_OK;
2128 }
2129
2130 static TransportStream *
2131 _get_or_create_data_channel_transports (GstWebRTCBin * webrtc, guint session_id)
2132 {
2133   if (!webrtc->priv->data_channel_transport) {
2134     TransportStream *stream;
2135     GstWebRTCSCTPTransport *sctp_transport;
2136     int i;
2137
2138     stream = _find_transport_for_session (webrtc, session_id);
2139
2140     if (!stream) {
2141       stream = _create_transport_channel (webrtc, session_id);
2142       gst_bin_add (GST_BIN (webrtc), GST_ELEMENT (stream->send_bin));
2143       gst_bin_add (GST_BIN (webrtc), GST_ELEMENT (stream->receive_bin));
2144       g_ptr_array_add (webrtc->priv->transports, stream);
2145     }
2146
2147     webrtc->priv->data_channel_transport = stream;
2148
2149     if (!(sctp_transport = webrtc->priv->sctp_transport)) {
2150       sctp_transport = gst_webrtc_sctp_transport_new ();
2151       sctp_transport->transport =
2152           g_object_ref (webrtc->priv->data_channel_transport->transport);
2153       sctp_transport->webrtcbin = webrtc;
2154
2155       /* Don't automatically start SCTP elements as part of webrtcbin. We
2156        * need to delay this until the DTLS transport is fully connected! */
2157       gst_element_set_locked_state (sctp_transport->sctpdec, TRUE);
2158       gst_element_set_locked_state (sctp_transport->sctpenc, TRUE);
2159
2160       gst_bin_add (GST_BIN (webrtc), sctp_transport->sctpdec);
2161       gst_bin_add (GST_BIN (webrtc), sctp_transport->sctpenc);
2162     }
2163
2164     g_signal_connect (sctp_transport->sctpdec, "pad-added",
2165         G_CALLBACK (_on_sctpdec_pad_added), webrtc);
2166     g_signal_connect (sctp_transport, "notify::state",
2167         G_CALLBACK (_on_sctp_state_notify), webrtc);
2168
2169     if (sctp_transport->sctpdec_block_id == 0) {
2170       GstPad *receive_srcpad;
2171       receive_srcpad =
2172           gst_element_get_static_pad (GST_ELEMENT (stream->receive_bin),
2173           "data_src");
2174       sctp_transport->sctpdec_block_id =
2175           gst_pad_add_probe (receive_srcpad,
2176           GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,
2177           (GstPadProbeCallback) sctp_pad_block, NULL, NULL);
2178       gst_object_unref (receive_srcpad);
2179     }
2180
2181     if (!gst_element_link_pads (GST_ELEMENT (stream->receive_bin), "data_src",
2182             GST_ELEMENT (sctp_transport->sctpdec), "sink"))
2183       g_warn_if_reached ();
2184
2185     if (!gst_element_link_pads (GST_ELEMENT (sctp_transport->sctpenc), "src",
2186             GST_ELEMENT (stream->send_bin), "data_sink"))
2187       g_warn_if_reached ();
2188
2189     for (i = 0; i < webrtc->priv->data_channels->len; i++) {
2190       WebRTCDataChannel *channel;
2191
2192       channel = g_ptr_array_index (webrtc->priv->data_channels, i);
2193
2194       webrtc_data_channel_link_to_sctp (channel, webrtc->priv->sctp_transport);
2195     }
2196
2197     gst_element_sync_state_with_parent (GST_ELEMENT (stream->send_bin));
2198     gst_element_sync_state_with_parent (GST_ELEMENT (stream->receive_bin));
2199
2200     if (!webrtc->priv->sctp_transport) {
2201       /* Connect to the notify::state signal to get notified when the DTLS
2202        * connection is established. Only then can we start the SCTP elements */
2203       g_signal_connect (stream->transport, "notify::state",
2204           G_CALLBACK (_on_sctp_notify_dtls_state), webrtc);
2205
2206       /* As this would be racy otherwise, also schedule a task that checks the
2207        * current state of the connection already without getting the signal
2208        * called */
2209       gst_webrtc_bin_enqueue_task (webrtc,
2210           (GstWebRTCBinFunc) _sctp_check_dtls_state_task, NULL, NULL, NULL);
2211     }
2212
2213     webrtc->priv->sctp_transport = sctp_transport;
2214     gst_webrtc_bin_update_sctp_priority (webrtc);
2215   }
2216
2217   return webrtc->priv->data_channel_transport;
2218 }
2219
2220 static TransportStream *
2221 _get_or_create_transport_stream (GstWebRTCBin * webrtc, guint session_id,
2222     gboolean is_datachannel)
2223 {
2224   if (is_datachannel)
2225     return _get_or_create_data_channel_transports (webrtc, session_id);
2226   else
2227     return _get_or_create_rtp_transport_channel (webrtc, session_id);
2228 }
2229
2230 static guint
2231 g_array_find_uint (GArray * array, guint val)
2232 {
2233   guint i;
2234
2235   for (i = 0; i < array->len; i++) {
2236     if (g_array_index (array, guint, i) == val)
2237       return i;
2238   }
2239
2240   return G_MAXUINT;
2241 }
2242
2243 static gboolean
2244 _pick_available_pt (GArray * reserved_pts, guint * i)
2245 {
2246   gboolean ret = FALSE;
2247
2248   for (*i = 96; *i <= 127; (*i)++) {
2249     if (g_array_find_uint (reserved_pts, *i) == G_MAXUINT) {
2250       g_array_append_val (reserved_pts, *i);
2251       ret = TRUE;
2252       break;
2253     }
2254   }
2255
2256   return ret;
2257 }
2258
2259 static gboolean
2260 _pick_fec_payload_types (GstWebRTCBin * webrtc, WebRTCTransceiver * trans,
2261     GArray * reserved_pts, gint clockrate, gint * rtx_target_pt,
2262     GstSDPMedia * media)
2263 {
2264   gboolean ret = TRUE;
2265
2266   if (trans->fec_type == GST_WEBRTC_FEC_TYPE_NONE)
2267     goto done;
2268
2269   if (trans->fec_type == GST_WEBRTC_FEC_TYPE_ULP_RED && clockrate != -1) {
2270     guint pt;
2271     gchar *str;
2272
2273     if (!(ret = _pick_available_pt (reserved_pts, &pt)))
2274       goto done;
2275
2276     /* https://tools.ietf.org/html/rfc5109#section-14.1 */
2277
2278     str = g_strdup_printf ("%u", pt);
2279     gst_sdp_media_add_format (media, str);
2280     g_free (str);
2281     str = g_strdup_printf ("%u red/%d", pt, clockrate);
2282     gst_sdp_media_add_attribute (media, "rtpmap", str);
2283     g_free (str);
2284
2285     *rtx_target_pt = pt;
2286
2287     if (!(ret = _pick_available_pt (reserved_pts, &pt)))
2288       goto done;
2289
2290     str = g_strdup_printf ("%u", pt);
2291     gst_sdp_media_add_format (media, str);
2292     g_free (str);
2293     str = g_strdup_printf ("%u ulpfec/%d", pt, clockrate);
2294     gst_sdp_media_add_attribute (media, "rtpmap", str);
2295     g_free (str);
2296   }
2297
2298 done:
2299   return ret;
2300 }
2301
2302 static gboolean
2303 _pick_rtx_payload_types (GstWebRTCBin * webrtc, WebRTCTransceiver * trans,
2304     GArray * reserved_pts, gint clockrate, gint target_pt, guint target_ssrc,
2305     GstSDPMedia * media)
2306 {
2307   gboolean ret = TRUE;
2308
2309   if (trans->local_rtx_ssrc_map)
2310     gst_structure_free (trans->local_rtx_ssrc_map);
2311
2312   trans->local_rtx_ssrc_map =
2313       gst_structure_new_empty ("application/x-rtp-ssrc-map");
2314
2315   if (trans->do_nack) {
2316     guint pt;
2317     gchar *str;
2318
2319     if (!(ret = _pick_available_pt (reserved_pts, &pt)))
2320       goto done;
2321
2322     /* https://tools.ietf.org/html/rfc4588#section-8.6 */
2323
2324     str = g_strdup_printf ("%u", target_ssrc);
2325     gst_structure_set (trans->local_rtx_ssrc_map, str, G_TYPE_UINT,
2326         g_random_int (), NULL);
2327     g_free (str);
2328
2329     str = g_strdup_printf ("%u", pt);
2330     gst_sdp_media_add_format (media, str);
2331     g_free (str);
2332
2333     str = g_strdup_printf ("%u rtx/%d", pt, clockrate);
2334     gst_sdp_media_add_attribute (media, "rtpmap", str);
2335     g_free (str);
2336
2337     str = g_strdup_printf ("%u apt=%d", pt, target_pt);
2338     gst_sdp_media_add_attribute (media, "fmtp", str);
2339     g_free (str);
2340   }
2341
2342 done:
2343   return ret;
2344 }
2345
2346 /* https://tools.ietf.org/html/rfc5576#section-4.2 */
2347 static gboolean
2348 _media_add_rtx_ssrc_group (GQuark field_id, const GValue * value,
2349     GstSDPMedia * media)
2350 {
2351   gchar *str;
2352
2353   str =
2354       g_strdup_printf ("FID %s %u", g_quark_to_string (field_id),
2355       g_value_get_uint (value));
2356   gst_sdp_media_add_attribute (media, "ssrc-group", str);
2357
2358   g_free (str);
2359
2360   return TRUE;
2361 }
2362
2363 typedef struct
2364 {
2365   GstSDPMedia *media;
2366   GstWebRTCBin *webrtc;
2367   WebRTCTransceiver *trans;
2368 } RtxSsrcData;
2369
2370 static gboolean
2371 _media_add_rtx_ssrc (GQuark field_id, const GValue * value, RtxSsrcData * data)
2372 {
2373   gchar *str;
2374   GstStructure *sdes;
2375   const gchar *cname;
2376
2377   g_object_get (data->webrtc->rtpbin, "sdes", &sdes, NULL);
2378   /* http://www.freesoft.org/CIE/RFC/1889/24.htm */
2379   cname = gst_structure_get_string (sdes, "cname");
2380
2381   /* https://tools.ietf.org/html/draft-ietf-mmusic-msid-16 */
2382   str =
2383       g_strdup_printf ("%u msid:%s %s", g_value_get_uint (value),
2384       cname, GST_OBJECT_NAME (data->trans));
2385   gst_sdp_media_add_attribute (data->media, "ssrc", str);
2386   g_free (str);
2387
2388   str = g_strdup_printf ("%u cname:%s", g_value_get_uint (value), cname);
2389   gst_sdp_media_add_attribute (data->media, "ssrc", str);
2390   g_free (str);
2391
2392   gst_structure_free (sdes);
2393
2394   return TRUE;
2395 }
2396
2397 static void
2398 _media_add_ssrcs (GstSDPMedia * media, GstCaps * caps, GstWebRTCBin * webrtc,
2399     WebRTCTransceiver * trans)
2400 {
2401   guint i;
2402   RtxSsrcData data = { media, webrtc, trans };
2403   const gchar *cname;
2404   GstStructure *sdes;
2405
2406   g_object_get (webrtc->rtpbin, "sdes", &sdes, NULL);
2407   /* http://www.freesoft.org/CIE/RFC/1889/24.htm */
2408   cname = gst_structure_get_string (sdes, "cname");
2409
2410   if (trans->local_rtx_ssrc_map)
2411     gst_structure_foreach (trans->local_rtx_ssrc_map,
2412         (GstStructureForeachFunc) _media_add_rtx_ssrc_group, media);
2413
2414   for (i = 0; i < gst_caps_get_size (caps); i++) {
2415     const GstStructure *s = gst_caps_get_structure (caps, i);
2416     guint ssrc;
2417
2418     if (gst_structure_get_uint (s, "ssrc", &ssrc)) {
2419       gchar *str;
2420
2421       /* https://tools.ietf.org/html/draft-ietf-mmusic-msid-16 */
2422       str =
2423           g_strdup_printf ("%u msid:%s %s", ssrc, cname,
2424           GST_OBJECT_NAME (trans));
2425       gst_sdp_media_add_attribute (media, "ssrc", str);
2426       g_free (str);
2427
2428       str = g_strdup_printf ("%u cname:%s", ssrc, cname);
2429       gst_sdp_media_add_attribute (media, "ssrc", str);
2430       g_free (str);
2431     }
2432   }
2433
2434   gst_structure_free (sdes);
2435
2436   if (trans->local_rtx_ssrc_map)
2437     gst_structure_foreach (trans->local_rtx_ssrc_map,
2438         (GstStructureForeachFunc) _media_add_rtx_ssrc, &data);
2439 }
2440
2441 static void
2442 _add_fingerprint_to_media (GstWebRTCDTLSTransport * transport,
2443     GstSDPMedia * media)
2444 {
2445   gchar *cert, *fingerprint, *val;
2446
2447   g_object_get (transport, "certificate", &cert, NULL);
2448
2449   fingerprint =
2450       _generate_fingerprint_from_certificate (cert, G_CHECKSUM_SHA256);
2451   g_free (cert);
2452   val =
2453       g_strdup_printf ("%s %s",
2454       _g_checksum_to_webrtc_string (G_CHECKSUM_SHA256), fingerprint);
2455   g_free (fingerprint);
2456
2457   gst_sdp_media_add_attribute (media, "fingerprint", val);
2458   g_free (val);
2459 }
2460
2461 /* based off https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-18#section-5.2.1 */
2462 static gboolean
2463 sdp_media_from_transceiver (GstWebRTCBin * webrtc, GstSDPMedia * media,
2464     GstWebRTCRTPTransceiver * trans, GstWebRTCSDPType type, guint media_idx,
2465     GString * bundled_mids, guint bundle_idx, gchar * bundle_ufrag,
2466     gchar * bundle_pwd, GArray * reserved_pts, GHashTable * all_mids)
2467 {
2468   /* TODO:
2469    * rtp header extensions
2470    * ice attributes
2471    * rtx
2472    * fec
2473    * msid-semantics
2474    * msid
2475    * dtls fingerprints
2476    * multiple dtls fingerprints https://tools.ietf.org/html/draft-ietf-mmusic-4572-update-05
2477    */
2478   GstSDPMessage *last_offer = _get_latest_self_generated_sdp (webrtc);
2479   gchar *direction, *sdp_mid, *ufrag, *pwd;
2480   gboolean bundle_only;
2481   GstCaps *caps;
2482   int i;
2483
2484   if (trans->direction == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_NONE
2485       || trans->direction == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_INACTIVE)
2486     return FALSE;
2487
2488   g_assert (trans->mline == -1 || trans->mline == media_idx);
2489
2490   bundle_only = bundled_mids && bundle_idx != media_idx
2491       && webrtc->bundle_policy == GST_WEBRTC_BUNDLE_POLICY_MAX_BUNDLE;
2492
2493   /* mandated by JSEP */
2494   gst_sdp_media_add_attribute (media, "setup", "actpass");
2495
2496   /* FIXME: deal with ICE restarts */
2497   if (last_offer && trans->mline != -1 && trans->mid) {
2498     ufrag = g_strdup (_media_get_ice_ufrag (last_offer, trans->mline));
2499     pwd = g_strdup (_media_get_ice_pwd (last_offer, trans->mline));
2500     GST_DEBUG_OBJECT (trans, "%u Using previous ice parameters", media_idx);
2501   } else {
2502     GST_DEBUG_OBJECT (trans,
2503         "%u Generating new ice parameters mline %i, mid %s", media_idx,
2504         trans->mline, trans->mid);
2505     if (webrtc->bundle_policy == GST_WEBRTC_BUNDLE_POLICY_NONE) {
2506       _generate_ice_credentials (&ufrag, &pwd);
2507     } else {
2508       g_assert (bundle_ufrag && bundle_pwd);
2509       ufrag = g_strdup (bundle_ufrag);
2510       pwd = g_strdup (bundle_pwd);
2511     }
2512   }
2513
2514   gst_sdp_media_add_attribute (media, "ice-ufrag", ufrag);
2515   gst_sdp_media_add_attribute (media, "ice-pwd", pwd);
2516   g_free (ufrag);
2517   g_free (pwd);
2518
2519   gst_sdp_media_set_port_info (media, bundle_only || trans->stopped ? 0 : 9, 0);
2520   gst_sdp_media_set_proto (media, "UDP/TLS/RTP/SAVPF");
2521   gst_sdp_media_add_connection (media, "IN", "IP4", "0.0.0.0", 0, 0);
2522
2523   if (bundle_only) {
2524     gst_sdp_media_add_attribute (media, "bundle-only", NULL);
2525   }
2526
2527   /* FIXME: negotiate this */
2528   /* FIXME: when bundle_only, these should not be added:
2529    * https://tools.ietf.org/html/draft-ietf-mmusic-sdp-bundle-negotiation-52#section-7.1.3
2530    * However, this causes incompatibilities with current versions
2531    * of the major browsers */
2532   gst_sdp_media_add_attribute (media, "rtcp-mux", "");
2533   gst_sdp_media_add_attribute (media, "rtcp-rsize", NULL);
2534
2535   direction =
2536       _enum_value_to_string (GST_TYPE_WEBRTC_RTP_TRANSCEIVER_DIRECTION,
2537       trans->direction);
2538   gst_sdp_media_add_attribute (media, direction, "");
2539   g_free (direction);
2540
2541   if (type == GST_WEBRTC_SDP_TYPE_OFFER) {
2542     caps = _find_codec_preferences (webrtc, trans, GST_PAD_SINK, media_idx);
2543     caps =
2544         _add_supported_attributes_to_caps (webrtc, WEBRTC_TRANSCEIVER (trans),
2545         caps);
2546   } else {
2547     g_assert_not_reached ();
2548   }
2549
2550   if (!caps || gst_caps_is_empty (caps) || gst_caps_is_any (caps)) {
2551     GST_WARNING_OBJECT (webrtc, "no caps available for transceiver, skipping");
2552     if (caps)
2553       gst_caps_unref (caps);
2554     return FALSE;
2555   }
2556
2557   for (i = 0; i < gst_caps_get_size (caps); i++) {
2558     GstCaps *format = gst_caps_new_empty ();
2559     const GstStructure *s = gst_caps_get_structure (caps, i);
2560
2561     gst_caps_append_structure (format, gst_structure_copy (s));
2562
2563     GST_DEBUG_OBJECT (webrtc, "Adding %u-th caps %" GST_PTR_FORMAT
2564         " to %u-th media", i, format, media_idx);
2565
2566     /* this only looks at the first structure so we loop over the given caps
2567      * and add each structure inside it piecemeal */
2568     gst_sdp_media_set_media_from_caps (format, media);
2569
2570     gst_caps_unref (format);
2571   }
2572
2573   if (type == GST_WEBRTC_SDP_TYPE_OFFER) {
2574     const GstStructure *s = gst_caps_get_structure (caps, 0);
2575     gint clockrate = -1;
2576     gint rtx_target_pt;
2577     gint original_rtx_target_pt;        /* Workaround chrome bug: https://bugs.chromium.org/p/webrtc/issues/detail?id=6196 */
2578     guint rtx_target_ssrc = -1;
2579
2580     if (gst_structure_get_int (s, "payload", &rtx_target_pt) &&
2581         webrtc->bundle_policy == GST_WEBRTC_BUNDLE_POLICY_NONE)
2582       g_array_append_val (reserved_pts, rtx_target_pt);
2583
2584     original_rtx_target_pt = rtx_target_pt;
2585
2586     if (!gst_structure_get_int (s, "clock-rate", &clockrate))
2587       GST_WARNING_OBJECT (webrtc,
2588           "Caps %" GST_PTR_FORMAT " are missing clock-rate", caps);
2589     if (!gst_structure_get_uint (s, "ssrc", &rtx_target_ssrc))
2590       GST_WARNING_OBJECT (webrtc, "Caps %" GST_PTR_FORMAT " are missing ssrc",
2591           caps);
2592
2593     _pick_fec_payload_types (webrtc, WEBRTC_TRANSCEIVER (trans), reserved_pts,
2594         clockrate, &rtx_target_pt, media);
2595     _pick_rtx_payload_types (webrtc, WEBRTC_TRANSCEIVER (trans), reserved_pts,
2596         clockrate, rtx_target_pt, rtx_target_ssrc, media);
2597     if (original_rtx_target_pt != rtx_target_pt)
2598       _pick_rtx_payload_types (webrtc, WEBRTC_TRANSCEIVER (trans), reserved_pts,
2599           clockrate, original_rtx_target_pt, rtx_target_ssrc, media);
2600   }
2601
2602   _media_add_ssrcs (media, caps, webrtc, WEBRTC_TRANSCEIVER (trans));
2603
2604   /* Some identifier; we also add the media name to it so it's identifiable */
2605   if (trans->mid) {
2606     gst_sdp_media_add_attribute (media, "mid", trans->mid);
2607   } else {
2608     /* Make sure to avoid mid collisions */
2609     while (TRUE) {
2610       sdp_mid = g_strdup_printf ("%s%u", gst_sdp_media_get_media (media),
2611           webrtc->priv->media_counter++);
2612       if (g_hash_table_contains (all_mids, (gpointer) sdp_mid)) {
2613         g_free (sdp_mid);
2614       } else {
2615         gst_sdp_media_add_attribute (media, "mid", sdp_mid);
2616         g_hash_table_insert (all_mids, sdp_mid, NULL);
2617         break;
2618       }
2619     }
2620   }
2621
2622   /* TODO:
2623    * - add a=candidate lines for gathered candidates
2624    */
2625
2626   if (trans->sender) {
2627     if (!trans->sender->transport) {
2628       TransportStream *item;
2629
2630       item =
2631           _get_or_create_transport_stream (webrtc,
2632           bundled_mids ? bundle_idx : media_idx, FALSE);
2633
2634       webrtc_transceiver_set_transport (WEBRTC_TRANSCEIVER (trans), item);
2635     }
2636
2637     _add_fingerprint_to_media (trans->sender->transport, media);
2638   }
2639
2640   if (bundled_mids) {
2641     const gchar *mid = gst_sdp_media_get_attribute_val (media, "mid");
2642
2643     g_assert (mid);
2644     g_string_append_printf (bundled_mids, " %s", mid);
2645   }
2646
2647   gst_caps_unref (caps);
2648
2649   return TRUE;
2650 }
2651
2652 static void
2653 gather_pad_pt (GstWebRTCBinPad * pad, GArray * reserved_pts)
2654 {
2655   if (pad->received_caps) {
2656     GstStructure *s = gst_caps_get_structure (pad->received_caps, 0);
2657     gint pt;
2658
2659     if (gst_structure_get_int (s, "payload", &pt)) {
2660       GST_TRACE_OBJECT (pad, "have reserved pt %u from received caps", pt);
2661       g_array_append_val (reserved_pts, pt);
2662     }
2663   }
2664 }
2665
2666 static GArray *
2667 gather_reserved_pts (GstWebRTCBin * webrtc)
2668 {
2669   GstElement *element = GST_ELEMENT (webrtc);
2670   GArray *reserved_pts = g_array_new (FALSE, FALSE, sizeof (guint));
2671   guint i;
2672
2673   GST_OBJECT_LOCK (webrtc);
2674   g_list_foreach (element->sinkpads, (GFunc) gather_pad_pt, reserved_pts);
2675   g_list_foreach (webrtc->priv->pending_pads, (GFunc) gather_pad_pt,
2676       reserved_pts);
2677
2678   for (i = 0; i < webrtc->priv->transceivers->len; i++) {
2679     GstWebRTCRTPTransceiver *trans;
2680
2681     trans = g_ptr_array_index (webrtc->priv->transceivers, i);
2682     if (trans->codec_preferences) {
2683       guint j, n;
2684       gint pt;
2685
2686       n = gst_caps_get_size (trans->codec_preferences);
2687       for (j = 0; j < n; j++) {
2688         GstStructure *s = gst_caps_get_structure (trans->codec_preferences, j);
2689         if (gst_structure_get_int (s, "payload", &pt)) {
2690           GST_TRACE_OBJECT (trans, "have reserved pt %u from codec preferences",
2691               pt);
2692           g_array_append_val (reserved_pts, pt);
2693         }
2694       }
2695     }
2696   }
2697   GST_OBJECT_UNLOCK (webrtc);
2698
2699   return reserved_pts;
2700 }
2701
2702 static gboolean
2703 _add_data_channel_offer (GstWebRTCBin * webrtc, GstSDPMessage * msg,
2704     GstSDPMedia * media, GString * bundled_mids, guint bundle_idx,
2705     gchar * bundle_ufrag, gchar * bundle_pwd, GHashTable * all_mids)
2706 {
2707   GstSDPMessage *last_offer = _get_latest_self_generated_sdp (webrtc);
2708   gchar *ufrag, *pwd, *sdp_mid;
2709   gboolean bundle_only = bundled_mids
2710       && webrtc->bundle_policy == GST_WEBRTC_BUNDLE_POLICY_MAX_BUNDLE
2711       && gst_sdp_message_medias_len (msg) != bundle_idx;
2712   guint last_data_index = G_MAXUINT;
2713
2714   /* add data channel support */
2715   if (webrtc->priv->data_channels->len == 0)
2716     return FALSE;
2717
2718   if (last_offer) {
2719     last_data_index = _message_get_datachannel_index (last_offer);
2720     if (last_data_index < G_MAXUINT) {
2721       g_assert (last_data_index < gst_sdp_message_medias_len (last_offer));
2722       /* XXX: is this always true when recycling transceivers?
2723        * i.e. do we always put the data channel in the same mline */
2724       g_assert (last_data_index == gst_sdp_message_medias_len (msg));
2725     }
2726   }
2727
2728   /* mandated by JSEP */
2729   gst_sdp_media_add_attribute (media, "setup", "actpass");
2730
2731   /* FIXME: only needed when restarting ICE */
2732   if (last_offer && last_data_index < G_MAXUINT) {
2733     ufrag = g_strdup (_media_get_ice_ufrag (last_offer, last_data_index));
2734     pwd = g_strdup (_media_get_ice_pwd (last_offer, last_data_index));
2735   } else {
2736     if (webrtc->bundle_policy == GST_WEBRTC_BUNDLE_POLICY_NONE) {
2737       _generate_ice_credentials (&ufrag, &pwd);
2738     } else {
2739       ufrag = g_strdup (bundle_ufrag);
2740       pwd = g_strdup (bundle_pwd);
2741     }
2742   }
2743   gst_sdp_media_add_attribute (media, "ice-ufrag", ufrag);
2744   gst_sdp_media_add_attribute (media, "ice-pwd", pwd);
2745   g_free (ufrag);
2746   g_free (pwd);
2747
2748   gst_sdp_media_set_media (media, "application");
2749   gst_sdp_media_set_port_info (media, bundle_only ? 0 : 9, 0);
2750   gst_sdp_media_set_proto (media, "UDP/DTLS/SCTP");
2751   gst_sdp_media_add_connection (media, "IN", "IP4", "0.0.0.0", 0, 0);
2752   gst_sdp_media_add_format (media, "webrtc-datachannel");
2753
2754   if (bundle_idx != gst_sdp_message_medias_len (msg))
2755     gst_sdp_media_add_attribute (media, "bundle-only", NULL);
2756
2757   if (last_offer && last_data_index < G_MAXUINT) {
2758     const GstSDPMedia *last_data_media;
2759     const gchar *mid;
2760
2761     last_data_media = gst_sdp_message_get_media (last_offer, last_data_index);
2762     mid = gst_sdp_media_get_attribute_val (last_data_media, "mid");
2763
2764     gst_sdp_media_add_attribute (media, "mid", mid);
2765   } else {
2766     /* Make sure to avoid mid collisions */
2767     while (TRUE) {
2768       sdp_mid = g_strdup_printf ("%s%u", gst_sdp_media_get_media (media),
2769           webrtc->priv->media_counter++);
2770       if (g_hash_table_contains (all_mids, (gpointer) sdp_mid)) {
2771         g_free (sdp_mid);
2772       } else {
2773         gst_sdp_media_add_attribute (media, "mid", sdp_mid);
2774         g_hash_table_insert (all_mids, sdp_mid, NULL);
2775         break;
2776       }
2777     }
2778   }
2779
2780   if (bundled_mids) {
2781     const gchar *mid = gst_sdp_media_get_attribute_val (media, "mid");
2782
2783     g_assert (mid);
2784     g_string_append_printf (bundled_mids, " %s", mid);
2785   }
2786
2787   /* FIXME: negotiate this properly */
2788   gst_sdp_media_add_attribute (media, "sctp-port", "5000");
2789
2790   _get_or_create_data_channel_transports (webrtc,
2791       bundled_mids ? 0 : webrtc->priv->transceivers->len);
2792   _add_fingerprint_to_media (webrtc->priv->sctp_transport->transport, media);
2793
2794   return TRUE;
2795 }
2796
2797 /* TODO: use the options argument */
2798 static GstSDPMessage *
2799 _create_offer_task (GstWebRTCBin * webrtc, const GstStructure * options,
2800     GError ** error)
2801 {
2802   GstSDPMessage *ret = NULL;
2803   GString *bundled_mids = NULL;
2804   gchar *bundle_ufrag = NULL;
2805   gchar *bundle_pwd = NULL;
2806   GArray *reserved_pts = NULL;
2807   GHashTable *all_mids =
2808       g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
2809
2810   GstSDPMessage *last_offer = _get_latest_self_generated_sdp (webrtc);
2811   GList *seen_transceivers = NULL;
2812   guint media_idx = 0;
2813   int i;
2814
2815   gst_sdp_message_new (&ret);
2816
2817   gst_sdp_message_set_version (ret, "0");
2818   {
2819     gchar *v, *sess_id;
2820     v = g_strdup_printf ("%u", webrtc->priv->offer_count++);
2821     if (last_offer) {
2822       const GstSDPOrigin *origin = gst_sdp_message_get_origin (last_offer);
2823       sess_id = g_strdup (origin->sess_id);
2824     } else {
2825       sess_id = g_strdup_printf ("%" G_GUINT64_FORMAT, RANDOM_SESSION_ID);
2826     }
2827     gst_sdp_message_set_origin (ret, "-", sess_id, v, "IN", "IP4", "0.0.0.0");
2828     g_free (sess_id);
2829     g_free (v);
2830   }
2831   gst_sdp_message_set_session_name (ret, "-");
2832   gst_sdp_message_add_time (ret, "0", "0", NULL);
2833   gst_sdp_message_add_attribute (ret, "ice-options", "trickle");
2834
2835   if (webrtc->bundle_policy == GST_WEBRTC_BUNDLE_POLICY_MAX_BUNDLE) {
2836     bundled_mids = g_string_new ("BUNDLE");
2837   } else if (webrtc->bundle_policy == GST_WEBRTC_BUNDLE_POLICY_MAX_COMPAT) {
2838     bundled_mids = g_string_new ("BUNDLE");
2839   }
2840
2841   if (webrtc->bundle_policy != GST_WEBRTC_BUNDLE_POLICY_NONE) {
2842     GStrv last_bundle = NULL;
2843     guint bundle_media_index;
2844
2845     reserved_pts = gather_reserved_pts (webrtc);
2846     if (last_offer && _parse_bundle (last_offer, &last_bundle, NULL)
2847         && last_bundle && last_bundle && last_bundle[0]
2848         && _get_bundle_index (last_offer, last_bundle, &bundle_media_index)) {
2849       bundle_ufrag =
2850           g_strdup (_media_get_ice_ufrag (last_offer, bundle_media_index));
2851       bundle_pwd =
2852           g_strdup (_media_get_ice_pwd (last_offer, bundle_media_index));
2853     } else {
2854       _generate_ice_credentials (&bundle_ufrag, &bundle_pwd);
2855     }
2856
2857     g_strfreev (last_bundle);
2858   }
2859
2860   /* FIXME: recycle transceivers */
2861
2862   /* Fill up the renegotiated streams first */
2863   if (last_offer) {
2864     for (i = 0; i < gst_sdp_message_medias_len (last_offer); i++) {
2865       GstWebRTCRTPTransceiver *trans = NULL;
2866       const GstSDPMedia *last_media;
2867
2868       last_media = gst_sdp_message_get_media (last_offer, i);
2869
2870       if (g_strcmp0 (gst_sdp_media_get_media (last_media), "audio") == 0
2871           || g_strcmp0 (gst_sdp_media_get_media (last_media), "video") == 0) {
2872         const gchar *last_mid;
2873         int j;
2874         last_mid = gst_sdp_media_get_attribute_val (last_media, "mid");
2875
2876         for (j = 0; j < webrtc->priv->transceivers->len; j++) {
2877           trans = g_ptr_array_index (webrtc->priv->transceivers, j);
2878
2879           if (trans->mid && g_strcmp0 (trans->mid, last_mid) == 0) {
2880             GstSDPMedia *media;
2881             const gchar *mid;
2882             WebRTCTransceiver *wtrans = WEBRTC_TRANSCEIVER (trans);
2883
2884             g_assert (!g_list_find (seen_transceivers, trans));
2885
2886             if (wtrans->mline_locked && trans->mline != media_idx) {
2887               g_set_error (error, GST_WEBRTC_BIN_ERROR,
2888                   GST_WEBRTC_BIN_ERROR_IMPOSSIBLE_MLINE_RESTRICTION,
2889                   "Previous negotiatied transceiver %"
2890                   GST_PTR_FORMAT " with mid %s was in mline %d but transceiver"
2891                   " has locked mline %u", trans, trans->mid, media_idx,
2892                   trans->mline);
2893               goto cancel_offer;
2894             }
2895
2896             GST_LOG_OBJECT (webrtc, "using previous negotiatied transceiver %"
2897                 GST_PTR_FORMAT " with mid %s into media index %u", trans,
2898                 trans->mid, media_idx);
2899
2900             /* FIXME: deal with format changes */
2901             gst_sdp_media_copy (last_media, &media);
2902             _media_replace_direction (media, trans->direction);
2903
2904             mid = gst_sdp_media_get_attribute_val (media, "mid");
2905             g_assert (mid);
2906
2907             if (g_hash_table_contains (all_mids, mid)) {
2908               gst_sdp_media_free (media);
2909               g_set_error (error, GST_WEBRTC_BIN_ERROR,
2910                   GST_WEBRTC_BIN_ERROR_FAILED,
2911                   "Duplicate mid %s when creating offer", mid);
2912               goto cancel_offer;
2913             }
2914
2915             g_hash_table_insert (all_mids, g_strdup (mid), NULL);
2916
2917             if (bundled_mids)
2918               g_string_append_printf (bundled_mids, " %s", mid);
2919
2920             gst_sdp_message_add_media (ret, media);
2921             media_idx++;
2922
2923             gst_sdp_media_free (media);
2924             seen_transceivers = g_list_prepend (seen_transceivers, trans);
2925             break;
2926           }
2927         }
2928       } else if (g_strcmp0 (gst_sdp_media_get_media (last_media),
2929               "application") == 0) {
2930         GstSDPMedia media = { 0, };
2931         gst_sdp_media_init (&media);
2932         if (_add_data_channel_offer (webrtc, ret, &media, bundled_mids, 0,
2933                 bundle_ufrag, bundle_pwd, all_mids)) {
2934           gst_sdp_message_add_media (ret, &media);
2935           media_idx++;
2936         } else {
2937           gst_sdp_media_uninit (&media);
2938         }
2939       }
2940     }
2941   }
2942
2943   /* First, go over all transceivers and gather existing mids */
2944   for (i = 0; i < webrtc->priv->transceivers->len; i++) {
2945     GstWebRTCRTPTransceiver *trans;
2946
2947     trans = g_ptr_array_index (webrtc->priv->transceivers, i);
2948
2949     if (g_list_find (seen_transceivers, trans))
2950       continue;
2951
2952     if (trans->mid) {
2953       if (g_hash_table_contains (all_mids, trans->mid)) {
2954         g_set_error (error, GST_WEBRTC_BIN_ERROR, GST_WEBRTC_BIN_ERROR_FAILED,
2955             "Duplicate mid %s when creating offer", trans->mid);
2956         goto cancel_offer;
2957       }
2958
2959       g_hash_table_insert (all_mids, g_strdup (trans->mid), NULL);
2960     }
2961   }
2962
2963
2964   /* add any extra streams */
2965   for (;;) {
2966     GstWebRTCRTPTransceiver *trans = NULL;
2967     GstSDPMedia media = { 0, };
2968
2969     /* First find a transceiver requesting this m-line */
2970     trans = _find_transceiver_for_mline (webrtc, media_idx);
2971
2972     if (trans) {
2973       /* We can't have seen it already, because it is locked to this line */
2974       g_assert (!g_list_find (seen_transceivers, trans));
2975       seen_transceivers = g_list_prepend (seen_transceivers, trans);
2976     } else {
2977       /* Otherwise find a free transceiver */
2978       for (i = 0; i < webrtc->priv->transceivers->len; i++) {
2979         WebRTCTransceiver *wtrans;
2980
2981         trans = g_ptr_array_index (webrtc->priv->transceivers, i);
2982         wtrans = WEBRTC_TRANSCEIVER (trans);
2983
2984         /* don't add transceivers twice */
2985         if (g_list_find (seen_transceivers, trans))
2986           continue;
2987
2988         /* Ignore transceivers with a locked mline, as they would have been
2989          * found above or will be used later */
2990         if (wtrans->mline_locked)
2991           continue;
2992
2993         seen_transceivers = g_list_prepend (seen_transceivers, trans);
2994         /* don't add stopped transceivers */
2995         if (trans->stopped) {
2996           continue;
2997         }
2998
2999         /* Otherwise take it */
3000         break;
3001       }
3002
3003       /* Stop if we got all transceivers */
3004       if (i == webrtc->priv->transceivers->len) {
3005
3006         /* But try to add a data channel first, we do it here, because
3007          * it can allow a locked m-line to be put after, so we need to
3008          * do another iteration after.
3009          */
3010         if (_message_get_datachannel_index (ret) == G_MAXUINT) {
3011           GstSDPMedia media = { 0, };
3012           gst_sdp_media_init (&media);
3013           if (_add_data_channel_offer (webrtc, ret, &media, bundled_mids, 0,
3014                   bundle_ufrag, bundle_pwd, all_mids)) {
3015             gst_sdp_message_add_media (ret, &media);
3016             media_idx++;
3017             continue;
3018           } else {
3019             gst_sdp_media_uninit (&media);
3020           }
3021         }
3022
3023         /* Verify that we didn't ignore any locked m-line transceivers */
3024         for (i = 0; i < webrtc->priv->transceivers->len; i++) {
3025           WebRTCTransceiver *wtrans;
3026
3027           trans = g_ptr_array_index (webrtc->priv->transceivers, i);
3028           wtrans = WEBRTC_TRANSCEIVER (trans);
3029           /* don't add transceivers twice */
3030           if (g_list_find (seen_transceivers, trans))
3031             continue;
3032           g_assert (wtrans->mline_locked);
3033
3034           g_set_error (error, GST_WEBRTC_BIN_ERROR,
3035               GST_WEBRTC_BIN_ERROR_IMPOSSIBLE_MLINE_RESTRICTION,
3036               "Tranceiver %" GST_PTR_FORMAT " with mid %s has locked mline %d"
3037               " but the whole offer only has %u sections", trans, trans->mid,
3038               trans->mline, media_idx);
3039           goto cancel_offer;
3040         }
3041         break;
3042       }
3043     }
3044
3045     gst_sdp_media_init (&media);
3046
3047     if (webrtc->bundle_policy == GST_WEBRTC_BUNDLE_POLICY_NONE) {
3048       reserved_pts = g_array_new (FALSE, FALSE, sizeof (guint));
3049     }
3050
3051     GST_LOG_OBJECT (webrtc, "adding transceiver %" GST_PTR_FORMAT " at media "
3052         "index %u", trans, media_idx);
3053
3054     if (sdp_media_from_transceiver (webrtc, &media, trans,
3055             GST_WEBRTC_SDP_TYPE_OFFER, media_idx, bundled_mids, 0, bundle_ufrag,
3056             bundle_pwd, reserved_pts, all_mids)) {
3057       gst_sdp_message_add_media (ret, &media);
3058       media_idx++;
3059     } else {
3060       gst_sdp_media_uninit (&media);
3061     }
3062
3063     if (webrtc->bundle_policy == GST_WEBRTC_BUNDLE_POLICY_NONE) {
3064       g_array_free (reserved_pts, TRUE);
3065       reserved_pts = NULL;
3066     }
3067   }
3068
3069   if (webrtc->bundle_policy != GST_WEBRTC_BUNDLE_POLICY_NONE) {
3070     g_array_free (reserved_pts, TRUE);
3071     reserved_pts = NULL;
3072   }
3073
3074   webrtc->priv->max_sink_pad_serial = MAX (webrtc->priv->max_sink_pad_serial,
3075       media_idx);
3076
3077   g_assert (media_idx == gst_sdp_message_medias_len (ret));
3078
3079   if (bundled_mids) {
3080     gchar *mids = g_string_free (bundled_mids, FALSE);
3081
3082     gst_sdp_message_add_attribute (ret, "group", mids);
3083     g_free (mids);
3084     bundled_mids = NULL;
3085   }
3086
3087   /* FIXME: pre-emptively setup receiving elements when needed */
3088
3089   if (webrtc->priv->last_generated_answer)
3090     gst_webrtc_session_description_free (webrtc->priv->last_generated_answer);
3091   webrtc->priv->last_generated_answer = NULL;
3092   if (webrtc->priv->last_generated_offer)
3093     gst_webrtc_session_description_free (webrtc->priv->last_generated_offer);
3094   {
3095     GstSDPMessage *copy;
3096     gst_sdp_message_copy (ret, &copy);
3097     webrtc->priv->last_generated_offer =
3098         gst_webrtc_session_description_new (GST_WEBRTC_SDP_TYPE_OFFER, copy);
3099   }
3100
3101 out:
3102   if (reserved_pts)
3103     g_array_free (reserved_pts, TRUE);
3104
3105   g_hash_table_unref (all_mids);
3106
3107   g_list_free (seen_transceivers);
3108
3109   if (bundle_ufrag)
3110     g_free (bundle_ufrag);
3111
3112   if (bundle_pwd)
3113     g_free (bundle_pwd);
3114
3115   if (bundled_mids)
3116     g_string_free (bundled_mids, TRUE);
3117
3118   return ret;
3119
3120 cancel_offer:
3121   gst_sdp_message_uninit (ret);
3122   ret = NULL;
3123   goto out;
3124 }
3125
3126 static void
3127 _media_add_fec (GstSDPMedia * media, WebRTCTransceiver * trans, GstCaps * caps,
3128     gint * rtx_target_pt)
3129 {
3130   guint i;
3131
3132   if (trans->fec_type == GST_WEBRTC_FEC_TYPE_NONE)
3133     return;
3134
3135   for (i = 0; i < gst_caps_get_size (caps); i++) {
3136     const GstStructure *s = gst_caps_get_structure (caps, i);
3137
3138     if (gst_structure_has_name (s, "application/x-rtp")) {
3139       const gchar *encoding_name =
3140           gst_structure_get_string (s, "encoding-name");
3141       gint clock_rate;
3142       gint pt;
3143
3144       if (gst_structure_get_int (s, "clock-rate", &clock_rate) &&
3145           gst_structure_get_int (s, "payload", &pt)) {
3146         if (!g_strcmp0 (encoding_name, "RED")) {
3147           gchar *str;
3148
3149           str = g_strdup_printf ("%u", pt);
3150           gst_sdp_media_add_format (media, str);
3151           g_free (str);
3152           str = g_strdup_printf ("%u red/%d", pt, clock_rate);
3153           *rtx_target_pt = pt;
3154           gst_sdp_media_add_attribute (media, "rtpmap", str);
3155           g_free (str);
3156         } else if (!g_strcmp0 (encoding_name, "ULPFEC")) {
3157           gchar *str;
3158
3159           str = g_strdup_printf ("%u", pt);
3160           gst_sdp_media_add_format (media, str);
3161           g_free (str);
3162           str = g_strdup_printf ("%u ulpfec/%d", pt, clock_rate);
3163           gst_sdp_media_add_attribute (media, "rtpmap", str);
3164           g_free (str);
3165         }
3166       }
3167     }
3168   }
3169 }
3170
3171 static void
3172 _media_add_rtx (GstSDPMedia * media, WebRTCTransceiver * trans,
3173     GstCaps * offer_caps, gint target_pt, guint target_ssrc)
3174 {
3175   guint i;
3176   const GstStructure *s;
3177
3178   if (trans->local_rtx_ssrc_map)
3179     gst_structure_free (trans->local_rtx_ssrc_map);
3180
3181   trans->local_rtx_ssrc_map =
3182       gst_structure_new_empty ("application/x-rtp-ssrc-map");
3183
3184   for (i = 0; i < gst_caps_get_size (offer_caps); i++) {
3185     s = gst_caps_get_structure (offer_caps, i);
3186
3187     if (gst_structure_has_name (s, "application/x-rtp")) {
3188       const gchar *encoding_name =
3189           gst_structure_get_string (s, "encoding-name");
3190       const gchar *apt_str = gst_structure_get_string (s, "apt");
3191       gint apt;
3192       gint clock_rate;
3193       gint pt;
3194
3195       if (!apt_str)
3196         continue;
3197
3198       apt = atoi (apt_str);
3199
3200       if (gst_structure_get_int (s, "clock-rate", &clock_rate) &&
3201           gst_structure_get_int (s, "payload", &pt) && apt == target_pt) {
3202         if (!g_strcmp0 (encoding_name, "RTX")) {
3203           gchar *str;
3204
3205           str = g_strdup_printf ("%u", pt);
3206           gst_sdp_media_add_format (media, str);
3207           g_free (str);
3208           str = g_strdup_printf ("%u rtx/%d", pt, clock_rate);
3209           gst_sdp_media_add_attribute (media, "rtpmap", str);
3210           g_free (str);
3211
3212           str = g_strdup_printf ("%d apt=%d", pt, apt);
3213           gst_sdp_media_add_attribute (media, "fmtp", str);
3214           g_free (str);
3215
3216           str = g_strdup_printf ("%u", target_ssrc);
3217           gst_structure_set (trans->local_rtx_ssrc_map, str, G_TYPE_UINT,
3218               g_random_int (), NULL);
3219         }
3220       }
3221     }
3222   }
3223 }
3224
3225 static GstWebRTCKind
3226 _kind_from_caps (const GstCaps * caps)
3227 {
3228   GstStructure *s;
3229   const gchar *media;
3230
3231   if (gst_caps_get_size (caps) == 0)
3232     return GST_WEBRTC_KIND_UNKNOWN;
3233
3234   s = gst_caps_get_structure (caps, 0);
3235
3236   media = gst_structure_get_string (s, "media");
3237   if (media == NULL)
3238     return GST_WEBRTC_KIND_UNKNOWN;
3239
3240   if (!g_strcmp0 (media, "audio"))
3241     return GST_WEBRTC_KIND_AUDIO;
3242
3243   if (!g_strcmp0 (media, "video"))
3244     return GST_WEBRTC_KIND_VIDEO;
3245
3246   return GST_WEBRTC_KIND_UNKNOWN;
3247 }
3248
3249 static gboolean
3250 _update_transceiver_kind_from_caps (GstWebRTCRTPTransceiver * trans,
3251     const GstCaps * caps)
3252 {
3253   GstWebRTCKind kind = _kind_from_caps (caps);
3254
3255   if (trans->kind == kind)
3256     return TRUE;
3257
3258   if (trans->kind == GST_WEBRTC_KIND_UNKNOWN) {
3259     trans->kind = kind;
3260     return TRUE;
3261   } else {
3262     return FALSE;
3263   }
3264 }
3265
3266 static void
3267 _get_rtx_target_pt_and_ssrc_from_caps (GstCaps * answer_caps, gint * target_pt,
3268     guint * target_ssrc)
3269 {
3270   const GstStructure *s = gst_caps_get_structure (answer_caps, 0);
3271
3272   gst_structure_get_int (s, "payload", target_pt);
3273   gst_structure_get_uint (s, "ssrc", target_ssrc);
3274 }
3275
3276 /* TODO: use the options argument */
3277 static GstSDPMessage *
3278 _create_answer_task (GstWebRTCBin * webrtc, const GstStructure * options,
3279     GError ** error)
3280 {
3281   GstSDPMessage *ret = NULL;
3282   const GstWebRTCSessionDescription *pending_remote =
3283       webrtc->pending_remote_description;
3284   guint i;
3285   GStrv bundled = NULL;
3286   guint bundle_idx = 0;
3287   GString *bundled_mids = NULL;
3288   gchar *bundle_ufrag = NULL;
3289   gchar *bundle_pwd = NULL;
3290   GList *seen_transceivers = NULL;
3291   GstSDPMessage *last_answer = _get_latest_self_generated_sdp (webrtc);
3292
3293   if (!webrtc->pending_remote_description) {
3294     g_set_error_literal (error, GST_WEBRTC_BIN_ERROR,
3295         GST_WEBRTC_BIN_ERROR_INVALID_STATE,
3296         "Asked to create an answer without a remote description");
3297     return NULL;
3298   }
3299
3300   if (!_parse_bundle (pending_remote->sdp, &bundled, error))
3301     goto out;
3302
3303   if (bundled) {
3304     GStrv last_bundle = NULL;
3305     guint bundle_media_index;
3306
3307     if (!_get_bundle_index (pending_remote->sdp, bundled, &bundle_idx)) {
3308       g_set_error (error, GST_WEBRTC_BIN_ERROR, GST_WEBRTC_BIN_ERROR_BAD_SDP,
3309           "Bundle tag is %s but no media found matching", bundled[0]);
3310       goto out;
3311     }
3312
3313     if (webrtc->bundle_policy != GST_WEBRTC_BUNDLE_POLICY_NONE) {
3314       bundled_mids = g_string_new ("BUNDLE");
3315     }
3316
3317     if (last_answer && _parse_bundle (last_answer, &last_bundle, NULL)
3318         && last_bundle && last_bundle[0]
3319         && _get_bundle_index (last_answer, last_bundle, &bundle_media_index)) {
3320       bundle_ufrag =
3321           g_strdup (_media_get_ice_ufrag (last_answer, bundle_media_index));
3322       bundle_pwd =
3323           g_strdup (_media_get_ice_pwd (last_answer, bundle_media_index));
3324     } else {
3325       _generate_ice_credentials (&bundle_ufrag, &bundle_pwd);
3326     }
3327
3328     g_strfreev (last_bundle);
3329   }
3330
3331   gst_sdp_message_new (&ret);
3332
3333   gst_sdp_message_set_version (ret, "0");
3334   {
3335     const GstSDPOrigin *offer_origin =
3336         gst_sdp_message_get_origin (pending_remote->sdp);
3337     gst_sdp_message_set_origin (ret, "-", offer_origin->sess_id,
3338         offer_origin->sess_version, "IN", "IP4", "0.0.0.0");
3339   }
3340   gst_sdp_message_set_session_name (ret, "-");
3341
3342   for (i = 0; i < gst_sdp_message_attributes_len (pending_remote->sdp); i++) {
3343     const GstSDPAttribute *attr =
3344         gst_sdp_message_get_attribute (pending_remote->sdp, i);
3345
3346     if (g_strcmp0 (attr->key, "ice-options") == 0) {
3347       gst_sdp_message_add_attribute (ret, attr->key, attr->value);
3348     }
3349   }
3350
3351   for (i = 0; i < gst_sdp_message_medias_len (pending_remote->sdp); i++) {
3352     GstSDPMedia *media = NULL;
3353     GstSDPMedia *offer_media;
3354     GstWebRTCDTLSSetup offer_setup, answer_setup;
3355     guint j, k;
3356     gboolean bundle_only;
3357     const gchar *mid;
3358
3359     offer_media =
3360         (GstSDPMedia *) gst_sdp_message_get_media (pending_remote->sdp, i);
3361     bundle_only = _media_has_attribute_key (offer_media, "bundle-only");
3362
3363     gst_sdp_media_new (&media);
3364     if (bundle_only && webrtc->bundle_policy == GST_WEBRTC_BUNDLE_POLICY_NONE)
3365       gst_sdp_media_set_port_info (media, 0, 0);
3366     else
3367       gst_sdp_media_set_port_info (media, 9, 0);
3368     gst_sdp_media_add_connection (media, "IN", "IP4", "0.0.0.0", 0, 0);
3369
3370     {
3371       gchar *ufrag, *pwd;
3372
3373       /* FIXME: deal with ICE restarts */
3374       if (last_answer && i < gst_sdp_message_medias_len (last_answer)) {
3375         ufrag = g_strdup (_media_get_ice_ufrag (last_answer, i));
3376         pwd = g_strdup (_media_get_ice_pwd (last_answer, i));
3377       } else {
3378         if (!bundled) {
3379           _generate_ice_credentials (&ufrag, &pwd);
3380         } else {
3381           ufrag = g_strdup (bundle_ufrag);
3382           pwd = g_strdup (bundle_pwd);
3383         }
3384       }
3385       gst_sdp_media_add_attribute (media, "ice-ufrag", ufrag);
3386       gst_sdp_media_add_attribute (media, "ice-pwd", pwd);
3387       g_free (ufrag);
3388       g_free (pwd);
3389     }
3390
3391     for (j = 0; j < gst_sdp_media_attributes_len (offer_media); j++) {
3392       const GstSDPAttribute *attr =
3393           gst_sdp_media_get_attribute (offer_media, j);
3394
3395       if (g_strcmp0 (attr->key, "mid") == 0
3396           || g_strcmp0 (attr->key, "rtcp-mux") == 0) {
3397         gst_sdp_media_add_attribute (media, attr->key, attr->value);
3398         /* FIXME: handle anything we want to keep */
3399       }
3400     }
3401
3402     mid = gst_sdp_media_get_attribute_val (media, "mid");
3403     /* XXX: not strictly required but a lot of functionality requires a mid */
3404     g_assert (mid);
3405
3406     /* set the a=setup: attribute */
3407     offer_setup = _get_dtls_setup_from_media (offer_media);
3408     answer_setup = _intersect_dtls_setup (offer_setup);
3409     if (answer_setup == GST_WEBRTC_DTLS_SETUP_NONE) {
3410       GST_WARNING_OBJECT (webrtc, "Could not intersect offer setup with "
3411           "transceiver direction");
3412       goto rejected;
3413     }
3414     _media_replace_setup (media, answer_setup);
3415
3416     if (g_strcmp0 (gst_sdp_media_get_media (offer_media), "application") == 0) {
3417       int sctp_port;
3418
3419       if (gst_sdp_media_formats_len (offer_media) != 1) {
3420         GST_WARNING_OBJECT (webrtc, "Could not find a format in the m= line "
3421             "for webrtc-datachannel");
3422         goto rejected;
3423       }
3424       sctp_port = _get_sctp_port_from_media (offer_media);
3425       if (sctp_port == -1) {
3426         GST_WARNING_OBJECT (webrtc, "media does not contain a sctp port");
3427         goto rejected;
3428       }
3429
3430       /* XXX: older browsers will produce a different SDP format for data
3431        * channel that is currently not parsed correctly */
3432       gst_sdp_media_set_proto (media, "UDP/DTLS/SCTP");
3433
3434       gst_sdp_media_set_media (media, "application");
3435       gst_sdp_media_set_port_info (media, 9, 0);
3436       gst_sdp_media_add_format (media, "webrtc-datachannel");
3437
3438       /* FIXME: negotiate this properly on renegotiation */
3439       gst_sdp_media_add_attribute (media, "sctp-port", "5000");
3440
3441       _get_or_create_data_channel_transports (webrtc,
3442           bundled_mids ? bundle_idx : i);
3443
3444       if (bundled_mids) {
3445         g_assert (mid);
3446         g_string_append_printf (bundled_mids, " %s", mid);
3447       }
3448
3449       _add_fingerprint_to_media (webrtc->priv->sctp_transport->transport,
3450           media);
3451     } else if (g_strcmp0 (gst_sdp_media_get_media (offer_media), "audio") == 0
3452         || g_strcmp0 (gst_sdp_media_get_media (offer_media), "video") == 0) {
3453       GstCaps *offer_caps, *answer_caps = NULL;
3454       GstWebRTCRTPTransceiver *rtp_trans = NULL;
3455       WebRTCTransceiver *trans = NULL;
3456       GstWebRTCRTPTransceiverDirection offer_dir, answer_dir;
3457       gint target_pt = -1;
3458       gint original_target_pt = -1;
3459       guint target_ssrc = 0;
3460
3461       gst_sdp_media_set_proto (media, "UDP/TLS/RTP/SAVPF");
3462       offer_caps = _rtp_caps_from_media (offer_media);
3463
3464       if (last_answer && i < gst_sdp_message_medias_len (last_answer)
3465           && (rtp_trans =
3466               _find_transceiver (webrtc, mid,
3467                   (FindTransceiverFunc) match_for_mid))) {
3468         const GstSDPMedia *last_media =
3469             gst_sdp_message_get_media (last_answer, i);
3470         const gchar *last_mid =
3471             gst_sdp_media_get_attribute_val (last_media, "mid");
3472
3473         /* FIXME: assumes no shenanigans with recycling transceivers */
3474         g_assert (g_strcmp0 (mid, last_mid) == 0);
3475
3476         if (!answer_caps
3477             && (rtp_trans->direction ==
3478                 GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV
3479                 || rtp_trans->direction ==
3480                 GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY))
3481           answer_caps =
3482               _find_codec_preferences (webrtc, rtp_trans, GST_PAD_SINK, i);
3483         if (!answer_caps
3484             && (rtp_trans->direction ==
3485                 GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV
3486                 || rtp_trans->direction ==
3487                 GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY))
3488           answer_caps =
3489               _find_codec_preferences (webrtc, rtp_trans, GST_PAD_SRC, i);
3490         if (!answer_caps)
3491           answer_caps = _rtp_caps_from_media (last_media);
3492
3493         /* XXX: In theory we're meant to use the sendrecv formats for the
3494          * inactive direction however we don't know what that may be and would
3495          * require asking outside what it expects to possibly send later */
3496
3497         GST_LOG_OBJECT (webrtc, "Found existing previously negotiated "
3498             "transceiver %" GST_PTR_FORMAT " from mid %s for mline %u "
3499             "using caps %" GST_PTR_FORMAT, rtp_trans, mid, i, answer_caps);
3500       } else {
3501         for (j = 0; j < webrtc->priv->transceivers->len; j++) {
3502           GstCaps *trans_caps;
3503
3504           rtp_trans = g_ptr_array_index (webrtc->priv->transceivers, j);
3505
3506           if (g_list_find (seen_transceivers, rtp_trans)) {
3507             /* Don't double allocate a transceiver to multiple mlines */
3508             rtp_trans = NULL;
3509             continue;
3510           }
3511
3512           trans_caps =
3513               _find_codec_preferences (webrtc, rtp_trans, GST_PAD_SINK, j);
3514
3515           GST_TRACE_OBJECT (webrtc, "trying to compare %" GST_PTR_FORMAT
3516               " and %" GST_PTR_FORMAT, offer_caps, trans_caps);
3517
3518           /* FIXME: technically this is a little overreaching as some fields we
3519            * we can deal with not having and/or we may have unrecognized fields
3520            * that we cannot actually support */
3521           if (trans_caps) {
3522             answer_caps = gst_caps_intersect (offer_caps, trans_caps);
3523             if (answer_caps && !gst_caps_is_empty (answer_caps)) {
3524               GST_LOG_OBJECT (webrtc,
3525                   "found compatible transceiver %" GST_PTR_FORMAT
3526                   " for offer media %u", rtp_trans, i);
3527               if (trans_caps)
3528                 gst_caps_unref (trans_caps);
3529               break;
3530             } else {
3531               if (answer_caps) {
3532                 gst_caps_unref (answer_caps);
3533                 answer_caps = NULL;
3534               }
3535               if (trans_caps)
3536                 gst_caps_unref (trans_caps);
3537               rtp_trans = NULL;
3538             }
3539           } else {
3540             rtp_trans = NULL;
3541           }
3542         }
3543       }
3544
3545       if (rtp_trans) {
3546         answer_dir = rtp_trans->direction;
3547         g_assert (answer_caps != NULL);
3548       } else {
3549         /* if no transceiver, then we only receive that stream and respond with
3550          * the exact same caps */
3551         /* FIXME: how to validate that subsequent elements can actually receive
3552          * this payload/format */
3553         answer_dir = GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY;
3554         answer_caps = gst_caps_ref (offer_caps);
3555       }
3556
3557       if (gst_caps_is_empty (answer_caps)) {
3558         GST_WARNING_OBJECT (webrtc, "Could not create caps for media");
3559         if (rtp_trans)
3560           gst_object_unref (rtp_trans);
3561         gst_caps_unref (answer_caps);
3562         goto rejected;
3563       }
3564
3565       seen_transceivers = g_list_prepend (seen_transceivers, rtp_trans);
3566
3567       if (!rtp_trans) {
3568         trans = _create_webrtc_transceiver (webrtc, answer_dir, i);
3569         rtp_trans = GST_WEBRTC_RTP_TRANSCEIVER (trans);
3570
3571         GST_LOG_OBJECT (webrtc, "Created new transceiver %" GST_PTR_FORMAT
3572             " for mline %u", trans, i);
3573       } else {
3574         trans = WEBRTC_TRANSCEIVER (rtp_trans);
3575       }
3576       if (!_update_transceiver_kind_from_caps (rtp_trans, answer_caps))
3577         GST_WARNING_OBJECT (webrtc,
3578             "Trying to change transceiver %d kind from %d to %d",
3579             rtp_trans->mline, rtp_trans->kind, _kind_from_caps (answer_caps));
3580
3581       if (!trans->do_nack) {
3582         answer_caps = gst_caps_make_writable (answer_caps);
3583         for (k = 0; k < gst_caps_get_size (answer_caps); k++) {
3584           GstStructure *s = gst_caps_get_structure (answer_caps, k);
3585           gst_structure_remove_fields (s, "rtcp-fb-nack", NULL);
3586         }
3587       }
3588
3589       gst_sdp_media_set_media_from_caps (answer_caps, media);
3590
3591       _get_rtx_target_pt_and_ssrc_from_caps (answer_caps, &target_pt,
3592           &target_ssrc);
3593
3594       original_target_pt = target_pt;
3595
3596       _media_add_fec (media, trans, offer_caps, &target_pt);
3597       if (trans->do_nack) {
3598         _media_add_rtx (media, trans, offer_caps, target_pt, target_ssrc);
3599         if (target_pt != original_target_pt)
3600           _media_add_rtx (media, trans, offer_caps, original_target_pt,
3601               target_ssrc);
3602       }
3603
3604       if (answer_dir != GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY)
3605         _media_add_ssrcs (media, answer_caps, webrtc,
3606             WEBRTC_TRANSCEIVER (rtp_trans));
3607
3608       gst_caps_unref (answer_caps);
3609       answer_caps = NULL;
3610
3611       /* set the new media direction */
3612       offer_dir = _get_direction_from_media (offer_media);
3613       answer_dir = _intersect_answer_directions (offer_dir, answer_dir);
3614       if (answer_dir == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_NONE) {
3615         GST_WARNING_OBJECT (webrtc, "Could not intersect offer direction with "
3616             "transceiver direction");
3617         goto rejected;
3618       }
3619       _media_replace_direction (media, answer_dir);
3620
3621       if (!trans->stream) {
3622         TransportStream *item;
3623
3624         item =
3625             _get_or_create_transport_stream (webrtc,
3626             bundled_mids ? bundle_idx : i, FALSE);
3627         webrtc_transceiver_set_transport (trans, item);
3628       }
3629
3630       if (bundled_mids) {
3631         const gchar *mid = gst_sdp_media_get_attribute_val (media, "mid");
3632
3633         g_assert (mid);
3634         g_string_append_printf (bundled_mids, " %s", mid);
3635       }
3636
3637       /* set the a=fingerprint: for this transport */
3638       _add_fingerprint_to_media (trans->stream->transport, media);
3639
3640       gst_caps_unref (offer_caps);
3641     } else {
3642       GST_WARNING_OBJECT (webrtc, "unknown m= line media name");
3643       goto rejected;
3644     }
3645
3646     if (0) {
3647     rejected:
3648       GST_INFO_OBJECT (webrtc, "media %u rejected", i);
3649       gst_sdp_media_free (media);
3650       gst_sdp_media_copy (offer_media, &media);
3651       gst_sdp_media_set_port_info (media, 0, 0);
3652     }
3653     gst_sdp_message_add_media (ret, media);
3654     gst_sdp_media_free (media);
3655   }
3656
3657   if (bundled_mids) {
3658     gchar *mids = g_string_free (bundled_mids, FALSE);
3659
3660     gst_sdp_message_add_attribute (ret, "group", mids);
3661     g_free (mids);
3662   }
3663
3664   if (bundle_ufrag)
3665     g_free (bundle_ufrag);
3666
3667   if (bundle_pwd)
3668     g_free (bundle_pwd);
3669
3670   /* FIXME: can we add not matched transceivers? */
3671
3672   /* XXX: only true for the initial offerer */
3673   gst_webrtc_ice_set_is_controller (webrtc->priv->ice, FALSE);
3674
3675 out:
3676   g_strfreev (bundled);
3677
3678   g_list_free (seen_transceivers);
3679
3680   if (webrtc->priv->last_generated_offer)
3681     gst_webrtc_session_description_free (webrtc->priv->last_generated_offer);
3682   webrtc->priv->last_generated_offer = NULL;
3683   if (webrtc->priv->last_generated_answer)
3684     gst_webrtc_session_description_free (webrtc->priv->last_generated_answer);
3685   {
3686     GstSDPMessage *copy;
3687     gst_sdp_message_copy (ret, &copy);
3688     webrtc->priv->last_generated_answer =
3689         gst_webrtc_session_description_new (GST_WEBRTC_SDP_TYPE_ANSWER, copy);
3690   }
3691
3692   return ret;
3693 }
3694
3695 struct create_sdp
3696 {
3697   GstStructure *options;
3698   GstPromise *promise;
3699   GstWebRTCSDPType type;
3700 };
3701
3702 static void
3703 _create_sdp_task (GstWebRTCBin * webrtc, struct create_sdp *data)
3704 {
3705   GstWebRTCSessionDescription *desc = NULL;
3706   GstSDPMessage *sdp = NULL;
3707   GstStructure *s = NULL;
3708   GError *error = NULL;
3709
3710   GST_INFO_OBJECT (webrtc, "creating %s sdp with options %" GST_PTR_FORMAT,
3711       gst_webrtc_sdp_type_to_string (data->type), data->options);
3712
3713   if (data->type == GST_WEBRTC_SDP_TYPE_OFFER)
3714     sdp = _create_offer_task (webrtc, data->options, &error);
3715   else if (data->type == GST_WEBRTC_SDP_TYPE_ANSWER)
3716     sdp = _create_answer_task (webrtc, data->options, &error);
3717   else {
3718     g_assert_not_reached ();
3719     goto out;
3720   }
3721
3722   if (sdp) {
3723     desc = gst_webrtc_session_description_new (data->type, sdp);
3724     s = gst_structure_new ("application/x-gst-promise",
3725         gst_webrtc_sdp_type_to_string (data->type),
3726         GST_TYPE_WEBRTC_SESSION_DESCRIPTION, desc, NULL);
3727   } else {
3728     g_warn_if_fail (error != NULL);
3729     GST_WARNING_OBJECT (webrtc, "returning error: %s",
3730         error ? error->message : "Unknown");
3731     s = gst_structure_new ("application/x-gstwebrtcbin-error",
3732         "error", G_TYPE_ERROR, error, NULL);
3733     g_clear_error (&error);
3734   }
3735
3736 out:
3737   PC_UNLOCK (webrtc);
3738   gst_promise_reply (data->promise, s);
3739   PC_LOCK (webrtc);
3740
3741   if (desc)
3742     gst_webrtc_session_description_free (desc);
3743 }
3744
3745 static void
3746 _free_create_sdp_data (struct create_sdp *data)
3747 {
3748   if (data->options)
3749     gst_structure_free (data->options);
3750   gst_promise_unref (data->promise);
3751   g_free (data);
3752 }
3753
3754 static void
3755 gst_webrtc_bin_create_offer (GstWebRTCBin * webrtc,
3756     const GstStructure * options, GstPromise * promise)
3757 {
3758   struct create_sdp *data = g_new0 (struct create_sdp, 1);
3759
3760   if (options)
3761     data->options = gst_structure_copy (options);
3762   data->promise = gst_promise_ref (promise);
3763   data->type = GST_WEBRTC_SDP_TYPE_OFFER;
3764
3765   if (!gst_webrtc_bin_enqueue_task (webrtc, (GstWebRTCBinFunc) _create_sdp_task,
3766           data, (GDestroyNotify) _free_create_sdp_data, promise)) {
3767     GError *error =
3768         g_error_new (GST_WEBRTC_BIN_ERROR, GST_WEBRTC_BIN_ERROR_CLOSED,
3769         "Could not create offer. webrtcbin is closed");
3770     GstStructure *s =
3771         gst_structure_new ("application/x-gstwebrtcbin-promise-error",
3772         "error", G_TYPE_ERROR, error, NULL);
3773
3774     gst_promise_reply (promise, s);
3775
3776     g_clear_error (&error);
3777   }
3778 }
3779
3780 static void
3781 gst_webrtc_bin_create_answer (GstWebRTCBin * webrtc,
3782     const GstStructure * options, GstPromise * promise)
3783 {
3784   struct create_sdp *data = g_new0 (struct create_sdp, 1);
3785
3786   if (options)
3787     data->options = gst_structure_copy (options);
3788   data->promise = gst_promise_ref (promise);
3789   data->type = GST_WEBRTC_SDP_TYPE_ANSWER;
3790
3791   if (!gst_webrtc_bin_enqueue_task (webrtc, (GstWebRTCBinFunc) _create_sdp_task,
3792           data, (GDestroyNotify) _free_create_sdp_data, promise)) {
3793     GError *error =
3794         g_error_new (GST_WEBRTC_BIN_ERROR, GST_WEBRTC_BIN_ERROR_CLOSED,
3795         "Could not create answer. webrtcbin is closed.");
3796     GstStructure *s =
3797         gst_structure_new ("application/x-gstwebrtcbin-promise-error",
3798         "error", G_TYPE_ERROR, error, NULL);
3799
3800     gst_promise_reply (promise, s);
3801
3802     g_clear_error (&error);
3803   }
3804 }
3805
3806 static GstWebRTCBinPad *
3807 _create_pad_for_sdp_media (GstWebRTCBin * webrtc, GstPadDirection direction,
3808     GstWebRTCRTPTransceiver * trans, guint serial)
3809 {
3810   GstWebRTCBinPad *pad;
3811   gchar *pad_name;
3812
3813   if (direction == GST_PAD_SINK) {
3814     if (serial == G_MAXUINT)
3815       serial = webrtc->priv->max_sink_pad_serial++;
3816   } else {
3817     serial = trans->mline;
3818   }
3819
3820   pad_name =
3821       g_strdup_printf ("%s_%u", direction == GST_PAD_SRC ? "src" : "sink",
3822       serial);
3823   pad = gst_webrtc_bin_pad_new (pad_name, direction);
3824   g_free (pad_name);
3825
3826   pad->trans = gst_object_ref (trans);
3827
3828   return pad;
3829 }
3830
3831 static GstWebRTCRTPTransceiver *
3832 _find_transceiver_for_sdp_media (GstWebRTCBin * webrtc,
3833     const GstSDPMessage * sdp, guint media_idx)
3834 {
3835   const GstSDPMedia *media = gst_sdp_message_get_media (sdp, media_idx);
3836   GstWebRTCRTPTransceiver *ret = NULL;
3837   int i;
3838
3839   for (i = 0; i < gst_sdp_media_attributes_len (media); i++) {
3840     const GstSDPAttribute *attr = gst_sdp_media_get_attribute (media, i);
3841
3842     if (g_strcmp0 (attr->key, "mid") == 0) {
3843       if ((ret =
3844               _find_transceiver (webrtc, attr->value,
3845                   (FindTransceiverFunc) match_for_mid)))
3846         goto out;
3847     }
3848   }
3849
3850   ret = _find_transceiver (webrtc, &media_idx,
3851       (FindTransceiverFunc) transceiver_match_for_mline);
3852
3853 out:
3854   GST_TRACE_OBJECT (webrtc, "Found transceiver %" GST_PTR_FORMAT, ret);
3855   return ret;
3856 }
3857
3858 static GstPad *
3859 _connect_input_stream (GstWebRTCBin * webrtc, GstWebRTCBinPad * pad)
3860 {
3861 /*
3862  * Not-bundle case:
3863  *
3864  * ,-------------------------webrtcbin-------------------------,
3865  * ;                                                           ;
3866  * ;          ,-------rtpbin-------,   ,--transport_send_%u--, ;
3867  * ;          ;    send_rtp_src_%u o---o rtp_sink            ; ;
3868  * ;          ;                    ;   ;                     ; ;
3869  * ;          ;   send_rtcp_src_%u o---o rtcp_sink           ; ;
3870  * ; sink_%u  ;                    ;   '---------------------' ;
3871  * o----------o send_rtp_sink_%u   ;                           ;
3872  * ;          '--------------------'                           ;
3873  * '--------------------- -------------------------------------'
3874  */
3875
3876 /*
3877  * Bundle case:
3878  * ,--------------------------------webrtcbin--------------------------------,
3879  * ;                                                                         ;
3880  * ;                        ,-------rtpbin-------,   ,--transport_send_%u--, ;
3881  * ;                        ;    send_rtp_src_%u o---o rtp_sink            ; ;
3882  * ;                        ;                    ;   ;                     ; ;
3883  * ;                        ;   send_rtcp_src_%u o---o rtcp_sink           ; ;
3884  * ; sink_%u ,---funnel---, ;                    ;   '---------------------' ;
3885  * o---------o sink_%u    ; ;                    ;                           ;
3886  * ; sink_%u ;        src o-o send_rtp_sink_%u   ;                           ;
3887  * o---------o sink_%u    ; ;                    ;                           ;
3888  * ;         '------------' '--------------------'                           ;
3889  * '-------------------------------------------------------------------------'
3890  */
3891   GstPadTemplate *rtp_templ;
3892   GstPad *rtp_sink;
3893   gchar *pad_name;
3894   WebRTCTransceiver *trans;
3895
3896   g_return_val_if_fail (pad->trans != NULL, NULL);
3897
3898   trans = WEBRTC_TRANSCEIVER (pad->trans);
3899
3900   GST_INFO_OBJECT (pad, "linking input stream %u", pad->trans->mline);
3901
3902   g_assert (trans->stream);
3903
3904   if (!webrtc->rtpfunnel) {
3905     rtp_templ =
3906         _find_pad_template (webrtc->rtpbin, GST_PAD_SINK, GST_PAD_REQUEST,
3907         "send_rtp_sink_%u");
3908     g_assert (rtp_templ);
3909
3910     pad_name = g_strdup_printf ("send_rtp_sink_%u", pad->trans->mline);
3911     rtp_sink =
3912         gst_element_request_pad (webrtc->rtpbin, rtp_templ, pad_name, NULL);
3913     g_free (pad_name);
3914     gst_ghost_pad_set_target (GST_GHOST_PAD (pad), rtp_sink);
3915     gst_object_unref (rtp_sink);
3916
3917     pad_name = g_strdup_printf ("send_rtp_src_%u", pad->trans->mline);
3918     if (!gst_element_link_pads (GST_ELEMENT (webrtc->rtpbin), pad_name,
3919             GST_ELEMENT (trans->stream->send_bin), "rtp_sink"))
3920       g_warn_if_reached ();
3921     g_free (pad_name);
3922   } else {
3923     gchar *pad_name = g_strdup_printf ("sink_%u", pad->trans->mline);
3924     GstPad *funnel_sinkpad =
3925         gst_element_get_request_pad (webrtc->rtpfunnel, pad_name);
3926
3927     gst_ghost_pad_set_target (GST_GHOST_PAD (pad), funnel_sinkpad);
3928
3929     g_free (pad_name);
3930     gst_object_unref (funnel_sinkpad);
3931   }
3932
3933   gst_element_sync_state_with_parent (GST_ELEMENT (trans->stream->send_bin));
3934
3935   return GST_PAD (pad);
3936 }
3937
3938 /* output pads are receiving elements */
3939 static void
3940 _connect_output_stream (GstWebRTCBin * webrtc,
3941     TransportStream * stream, guint session_id)
3942 {
3943 /*
3944  * ,------------------------webrtcbin------------------------,
3945  * ;                             ,---------rtpbin---------,  ;
3946  * ; ,-transport_receive_%u--,   ;                        ;  ;
3947  * ; ;               rtp_src o---o recv_rtp_sink_%u       ;  ;
3948  * ; ;                       ;   ;                        ;  ;
3949  * ; ;              rtcp_src o---o recv_rtcp_sink_%u      ;  ;
3950  * ; '-----------------------'   ;                        ;  ; src_%u
3951  * ;                             ;  recv_rtp_src_%u_%u_%u o--o
3952  * ;                             '------------------------'  ;
3953  * '---------------------------------------------------------'
3954  */
3955   gchar *pad_name;
3956
3957   if (stream->output_connected) {
3958     GST_DEBUG_OBJECT (webrtc, "stream %" GST_PTR_FORMAT " is already "
3959         "connected to rtpbin.  Not connecting", stream);
3960     return;
3961   }
3962
3963   GST_INFO_OBJECT (webrtc, "linking output stream %u %" GST_PTR_FORMAT,
3964       session_id, stream);
3965
3966   pad_name = g_strdup_printf ("recv_rtp_sink_%u", session_id);
3967   if (!gst_element_link_pads (GST_ELEMENT (stream->receive_bin),
3968           "rtp_src", GST_ELEMENT (webrtc->rtpbin), pad_name))
3969     g_warn_if_reached ();
3970   g_free (pad_name);
3971
3972   gst_element_sync_state_with_parent (GST_ELEMENT (stream->receive_bin));
3973
3974   /* The webrtcbin src_%u output pads will be created when rtpbin receives
3975    * data on that stream in on_rtpbin_pad_added() */
3976
3977   stream->output_connected = TRUE;
3978 }
3979
3980 typedef struct
3981 {
3982   guint mlineindex;
3983   gchar *candidate;
3984 } IceCandidateItem;
3985
3986 static void
3987 _clear_ice_candidate_item (IceCandidateItem * item)
3988 {
3989   g_free (item->candidate);
3990 }
3991
3992 static void
3993 _add_ice_candidate (GstWebRTCBin * webrtc, IceCandidateItem * item,
3994     gboolean drop_invalid)
3995 {
3996   GstWebRTCICEStream *stream;
3997
3998   stream = _find_ice_stream_for_session (webrtc, item->mlineindex);
3999   if (stream == NULL) {
4000     if (drop_invalid) {
4001       GST_WARNING_OBJECT (webrtc, "Unknown mline %u, dropping",
4002           item->mlineindex);
4003     } else {
4004       IceCandidateItem new;
4005       new.mlineindex = item->mlineindex;
4006       new.candidate = g_strdup (item->candidate);
4007       GST_INFO_OBJECT (webrtc, "Unknown mline %u, deferring", item->mlineindex);
4008
4009       ICE_LOCK (webrtc);
4010       g_array_append_val (webrtc->priv->pending_remote_ice_candidates, new);
4011       ICE_UNLOCK (webrtc);
4012     }
4013     return;
4014   }
4015
4016   GST_LOG_OBJECT (webrtc, "adding ICE candidate with mline:%u, %s",
4017       item->mlineindex, item->candidate);
4018
4019   gst_webrtc_ice_add_candidate (webrtc->priv->ice, stream, item->candidate);
4020 }
4021
4022 static void
4023 _add_ice_candidates_from_sdp (GstWebRTCBin * webrtc, gint mlineindex,
4024     const GstSDPMedia * media)
4025 {
4026   gint a;
4027   GstWebRTCICEStream *stream = NULL;
4028
4029   for (a = 0; a < gst_sdp_media_attributes_len (media); a++) {
4030     const GstSDPAttribute *attr = gst_sdp_media_get_attribute (media, a);
4031     if (g_strcmp0 (attr->key, "candidate") == 0) {
4032       gchar *candidate;
4033
4034       if (stream == NULL)
4035         stream = _find_ice_stream_for_session (webrtc, mlineindex);
4036       if (stream == NULL) {
4037         GST_WARNING_OBJECT (webrtc,
4038             "Unknown mline %u, dropping ICE candidates from SDP", mlineindex);
4039         return;
4040       }
4041
4042       candidate = g_strdup_printf ("a=candidate:%s", attr->value);
4043       GST_LOG_OBJECT (webrtc, "adding ICE candidate with mline:%u, %s",
4044           mlineindex, candidate);
4045       gst_webrtc_ice_add_candidate (webrtc->priv->ice, stream, candidate);
4046       g_free (candidate);
4047     }
4048   }
4049 }
4050
4051 static void
4052 _add_ice_candidate_to_sdp (GstWebRTCBin * webrtc,
4053     GstSDPMessage * sdp, gint mline_index, const gchar * candidate)
4054 {
4055   GstSDPMedia *media = NULL;
4056
4057   if (mline_index < sdp->medias->len) {
4058     media = &g_array_index (sdp->medias, GstSDPMedia, mline_index);
4059   }
4060
4061   if (media == NULL) {
4062     GST_WARNING_OBJECT (webrtc, "Couldn't find mline %d to merge ICE candidate",
4063         mline_index);
4064     return;
4065   }
4066   // Add the candidate as an attribute, first stripping off the existing
4067   // candidate: key from the string description
4068   if (strlen (candidate) < 10) {
4069     GST_WARNING_OBJECT (webrtc,
4070         "Dropping invalid ICE candidate for mline %d: %s", mline_index,
4071         candidate);
4072     return;
4073   }
4074   gst_sdp_media_add_attribute (media, "candidate", candidate + 10);
4075 }
4076
4077 static gboolean
4078 _filter_sdp_fields (GQuark field_id, const GValue * value,
4079     GstStructure * new_structure)
4080 {
4081   if (!g_str_has_prefix (g_quark_to_string (field_id), "a-")) {
4082     gst_structure_id_set_value (new_structure, field_id, value);
4083   }
4084   return TRUE;
4085 }
4086
4087 static void
4088 _set_rtx_ptmap_from_stream (GstWebRTCBin * webrtc, TransportStream * stream)
4089 {
4090   gint *rtx_pt;
4091   gsize rtx_count;
4092
4093   rtx_pt = transport_stream_get_all_pt (stream, "RTX", &rtx_count);
4094   GST_LOG_OBJECT (stream, "have %" G_GSIZE_FORMAT " rtx payloads", rtx_count);
4095   if (rtx_pt) {
4096     GstStructure *pt_map = gst_structure_new_empty ("application/x-rtp-pt-map");
4097     gsize i;
4098
4099     for (i = 0; i < rtx_count; i++) {
4100       GstCaps *rtx_caps = transport_stream_get_caps_for_pt (stream, rtx_pt[i]);
4101       const GstStructure *s = gst_caps_get_structure (rtx_caps, 0);
4102       const gchar *apt = gst_structure_get_string (s, "apt");
4103
4104       GST_LOG_OBJECT (stream, "setting rtx mapping: %s -> %u", apt, rtx_pt[i]);
4105       gst_structure_set (pt_map, apt, G_TYPE_UINT, rtx_pt[i], NULL);
4106     }
4107
4108     GST_DEBUG_OBJECT (stream, "setting payload map on %" GST_PTR_FORMAT " : %"
4109         GST_PTR_FORMAT " and %" GST_PTR_FORMAT, stream->rtxreceive,
4110         stream->rtxsend, pt_map);
4111
4112     if (stream->rtxreceive)
4113       g_object_set (stream->rtxreceive, "payload-type-map", pt_map, NULL);
4114     if (stream->rtxsend)
4115       g_object_set (stream->rtxsend, "payload-type-map", pt_map, NULL);
4116
4117     gst_structure_free (pt_map);
4118   }
4119 }
4120
4121 static void
4122 _update_transport_ptmap_from_media (GstWebRTCBin * webrtc,
4123     TransportStream * stream, const GstSDPMessage * sdp, guint media_idx)
4124 {
4125   guint i, len;
4126   const gchar *proto;
4127   const GstSDPMedia *media = gst_sdp_message_get_media (sdp, media_idx);
4128
4129   /* get proto */
4130   proto = gst_sdp_media_get_proto (media);
4131   if (proto != NULL) {
4132     /* Parse global SDP attributes once */
4133     GstCaps *global_caps = gst_caps_new_empty_simple ("application/x-unknown");
4134     GST_DEBUG_OBJECT (webrtc, "mapping sdp session level attributes to caps");
4135     gst_sdp_message_attributes_to_caps (sdp, global_caps);
4136     GST_DEBUG_OBJECT (webrtc, "mapping sdp media level attributes to caps");
4137     gst_sdp_media_attributes_to_caps (media, global_caps);
4138
4139     len = gst_sdp_media_formats_len (media);
4140     for (i = 0; i < len; i++) {
4141       GstCaps *caps, *outcaps;
4142       GstStructure *s;
4143       PtMapItem item;
4144       gint pt;
4145       guint j;
4146
4147       pt = atoi (gst_sdp_media_get_format (media, i));
4148
4149       GST_DEBUG_OBJECT (webrtc, " looking at %d pt: %d", i, pt);
4150
4151       /* convert caps */
4152       caps = gst_sdp_media_get_caps_from_media (media, pt);
4153       if (caps == NULL) {
4154         GST_WARNING_OBJECT (webrtc, " skipping pt %d without caps", pt);
4155         continue;
4156       }
4157
4158       /* Merge in global caps */
4159       /* Intersect will merge in missing fields to the current caps */
4160       outcaps = gst_caps_intersect (caps, global_caps);
4161       gst_caps_unref (caps);
4162
4163       s = gst_caps_get_structure (outcaps, 0);
4164       gst_structure_set_name (s, "application/x-rtp");
4165       if (!g_strcmp0 (gst_structure_get_string (s, "encoding-name"), "ULPFEC"))
4166         gst_structure_set (s, "is-fec", G_TYPE_BOOLEAN, TRUE, NULL);
4167
4168       item.caps = gst_caps_new_empty ();
4169
4170       for (j = 0; j < gst_caps_get_size (outcaps); j++) {
4171         GstStructure *s = gst_caps_get_structure (outcaps, j);
4172         GstStructure *filtered =
4173             gst_structure_new_empty (gst_structure_get_name (s));
4174
4175         gst_structure_foreach (s,
4176             (GstStructureForeachFunc) _filter_sdp_fields, filtered);
4177         gst_caps_append_structure (item.caps, filtered);
4178       }
4179
4180       item.pt = pt;
4181       gst_caps_unref (outcaps);
4182
4183       g_array_append_val (stream->ptmap, item);
4184     }
4185
4186     gst_caps_unref (global_caps);
4187   }
4188 }
4189
4190 static void
4191 _update_transceiver_from_sdp_media (GstWebRTCBin * webrtc,
4192     const GstSDPMessage * sdp, guint media_idx,
4193     TransportStream * stream, GstWebRTCRTPTransceiver * rtp_trans,
4194     GStrv bundled, guint bundle_idx, GError ** error)
4195 {
4196   WebRTCTransceiver *trans = WEBRTC_TRANSCEIVER (rtp_trans);
4197   GstWebRTCRTPTransceiverDirection prev_dir = rtp_trans->current_direction;
4198   GstWebRTCRTPTransceiverDirection new_dir;
4199   const GstSDPMedia *media = gst_sdp_message_get_media (sdp, media_idx);
4200   GstWebRTCDTLSSetup new_setup;
4201   gboolean new_rtcp_rsize;
4202   ReceiveState receive_state = RECEIVE_STATE_UNSET;
4203   int i;
4204
4205   rtp_trans->mline = media_idx;
4206
4207   if (!g_strcmp0 (gst_sdp_media_get_media (media), "audio")) {
4208     if (rtp_trans->kind == GST_WEBRTC_KIND_VIDEO)
4209       GST_FIXME_OBJECT (webrtc,
4210           "Updating video transceiver to audio, which isn't fully supported.");
4211     rtp_trans->kind = GST_WEBRTC_KIND_AUDIO;
4212   }
4213
4214   if (!g_strcmp0 (gst_sdp_media_get_media (media), "video")) {
4215     if (rtp_trans->kind == GST_WEBRTC_KIND_AUDIO)
4216       GST_FIXME_OBJECT (webrtc,
4217           "Updating audio transceiver to video, which isn't fully supported.");
4218     rtp_trans->kind = GST_WEBRTC_KIND_VIDEO;
4219   }
4220
4221   for (i = 0; i < gst_sdp_media_attributes_len (media); i++) {
4222     const GstSDPAttribute *attr = gst_sdp_media_get_attribute (media, i);
4223
4224     if (g_strcmp0 (attr->key, "mid") == 0) {
4225       g_free (rtp_trans->mid);
4226       rtp_trans->mid = g_strdup (attr->value);
4227     }
4228   }
4229
4230   {
4231     const GstSDPMedia *local_media, *remote_media;
4232     GstWebRTCRTPTransceiverDirection local_dir, remote_dir;
4233     GstWebRTCDTLSSetup local_setup, remote_setup;
4234
4235     local_media =
4236         gst_sdp_message_get_media (webrtc->current_local_description->sdp,
4237         media_idx);
4238     remote_media =
4239         gst_sdp_message_get_media (webrtc->current_remote_description->sdp,
4240         media_idx);
4241
4242     local_setup = _get_dtls_setup_from_media (local_media);
4243     remote_setup = _get_dtls_setup_from_media (remote_media);
4244     new_setup = _get_final_setup (local_setup, remote_setup);
4245     if (new_setup == GST_WEBRTC_DTLS_SETUP_NONE) {
4246       g_set_error (error, GST_WEBRTC_BIN_ERROR, GST_WEBRTC_BIN_ERROR_BAD_SDP,
4247           "Cannot intersect direction attributes for media %u", media_idx);
4248       return;
4249     }
4250
4251     local_dir = _get_direction_from_media (local_media);
4252     remote_dir = _get_direction_from_media (remote_media);
4253     new_dir = _get_final_direction (local_dir, remote_dir);
4254     if (new_dir == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_NONE) {
4255       g_set_error (error, GST_WEBRTC_BIN_ERROR, GST_WEBRTC_BIN_ERROR_BAD_SDP,
4256           "Cannot intersect dtls setup attributes for media %u", media_idx);
4257       return;
4258     }
4259
4260     if (prev_dir != GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_NONE
4261         && new_dir != GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_INACTIVE
4262         && prev_dir != new_dir) {
4263       g_set_error (error, GST_WEBRTC_BIN_ERROR,
4264           GST_WEBRTC_BIN_ERROR_NOT_IMPLEMENTED,
4265           "transceiver direction changes are not implemented. Media %u",
4266           media_idx);
4267       return;
4268     }
4269
4270     if (!bundled || bundle_idx == media_idx) {
4271       new_rtcp_rsize = _media_has_attribute_key (local_media, "rtcp-rsize")
4272           && _media_has_attribute_key (remote_media, "rtcp-rsize");
4273
4274       {
4275         GObject *session;
4276         g_signal_emit_by_name (webrtc->rtpbin, "get-internal-session",
4277             media_idx, &session);
4278         if (session) {
4279           g_object_set (session, "rtcp-reduced-size", new_rtcp_rsize, NULL);
4280           g_object_unref (session);
4281         }
4282       }
4283     }
4284   }
4285
4286   if (new_dir == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_INACTIVE) {
4287     if (!bundled) {
4288       /* Not a bundled stream means this entire transport is inactive,
4289        * so set the receive state to BLOCK below */
4290       stream->active = FALSE;
4291       receive_state = RECEIVE_STATE_BLOCK;
4292     }
4293   } else {
4294     /* If this transceiver is active for sending or receiving,
4295      * we still need receive at least RTCP, so need to unblock
4296      * the receive bin below. */
4297     GST_LOG_OBJECT (webrtc, "marking stream %p as active", stream);
4298     receive_state = RECEIVE_STATE_PASS;
4299     stream->active = TRUE;
4300   }
4301
4302   if (new_dir != prev_dir) {
4303     gchar *prev_dir_s, *new_dir_s;
4304
4305     prev_dir_s =
4306         _enum_value_to_string (GST_TYPE_WEBRTC_RTP_TRANSCEIVER_DIRECTION,
4307         prev_dir);
4308     new_dir_s =
4309         _enum_value_to_string (GST_TYPE_WEBRTC_RTP_TRANSCEIVER_DIRECTION,
4310         new_dir);
4311
4312     GST_DEBUG_OBJECT (webrtc, "transceiver %" GST_PTR_FORMAT
4313         " direction change from %s to %s", rtp_trans, prev_dir_s, new_dir_s);
4314
4315     g_free (prev_dir_s);
4316     prev_dir_s = NULL;
4317     g_free (new_dir_s);
4318     new_dir_s = NULL;
4319
4320     if (new_dir == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_INACTIVE) {
4321       GstWebRTCBinPad *pad;
4322
4323       pad = _find_pad_for_mline (webrtc, GST_PAD_SRC, media_idx);
4324       if (pad) {
4325         GstPad *target = gst_ghost_pad_get_target (GST_GHOST_PAD (pad));
4326         if (target) {
4327           GstPad *peer = gst_pad_get_peer (target);
4328           if (peer) {
4329             gst_pad_send_event (peer, gst_event_new_eos ());
4330             gst_object_unref (peer);
4331           }
4332           gst_object_unref (target);
4333         }
4334         gst_object_unref (pad);
4335       }
4336
4337       /* XXX: send eos event up the sink pad as well? */
4338     }
4339
4340     if (new_dir == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY ||
4341         new_dir == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV) {
4342       GstWebRTCBinPad *pad =
4343           _find_pad_for_transceiver (webrtc, GST_PAD_SINK, rtp_trans);
4344       if (pad) {
4345         GST_DEBUG_OBJECT (webrtc, "found existing send pad %" GST_PTR_FORMAT
4346             " for transceiver %" GST_PTR_FORMAT, pad, trans);
4347         gst_object_unref (pad);
4348       } else {
4349         GST_DEBUG_OBJECT (webrtc,
4350             "creating new send pad for transceiver %" GST_PTR_FORMAT, trans);
4351         pad = _create_pad_for_sdp_media (webrtc, GST_PAD_SINK, rtp_trans,
4352             G_MAXUINT);
4353         _connect_input_stream (webrtc, pad);
4354         _add_pad (webrtc, pad);
4355       }
4356     }
4357     if (new_dir == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY ||
4358         new_dir == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV) {
4359       GstWebRTCBinPad *pad =
4360           _find_pad_for_transceiver (webrtc, GST_PAD_SRC, rtp_trans);
4361       if (pad) {
4362         GST_DEBUG_OBJECT (webrtc, "found existing receive pad %" GST_PTR_FORMAT
4363             " for transceiver %" GST_PTR_FORMAT, pad, trans);
4364         gst_object_unref (pad);
4365       } else {
4366         GST_DEBUG_OBJECT (webrtc,
4367             "creating new receive pad for transceiver %" GST_PTR_FORMAT, trans);
4368         pad = _create_pad_for_sdp_media (webrtc, GST_PAD_SRC, rtp_trans,
4369             G_MAXUINT);
4370
4371         if (!trans->stream) {
4372           TransportStream *item;
4373
4374           item =
4375               _get_or_create_transport_stream (webrtc,
4376               bundled ? bundle_idx : media_idx, FALSE);
4377           webrtc_transceiver_set_transport (trans, item);
4378         }
4379
4380         _connect_output_stream (webrtc, trans->stream,
4381             bundled ? bundle_idx : media_idx);
4382         /* delay adding the pad until rtpbin creates the recv output pad
4383          * to ghost to so queries/events travel through the pipeline correctly
4384          * as soon as the pad is added */
4385         _add_pad_to_list (webrtc, pad);
4386       }
4387
4388     }
4389
4390     rtp_trans->mline = media_idx;
4391     rtp_trans->current_direction = new_dir;
4392   }
4393
4394   if (!bundled || bundle_idx == media_idx) {
4395     if (stream->rtxsend || stream->rtxreceive) {
4396       _set_rtx_ptmap_from_stream (webrtc, stream);
4397     }
4398
4399     g_object_set (stream, "dtls-client",
4400         new_setup == GST_WEBRTC_DTLS_SETUP_ACTIVE, NULL);
4401   }
4402
4403   /* Must be after setting the "dtls-client" so that data is not pushed into
4404    * the dtlssrtp elements before the ssl direction has been set which will
4405    * throw SSL errors */
4406   if (receive_state != RECEIVE_STATE_UNSET)
4407     transport_receive_bin_set_receive_state (stream->receive_bin,
4408         receive_state);
4409 }
4410
4411 /* must be called with the pc lock held */
4412 static gint
4413 _generate_data_channel_id (GstWebRTCBin * webrtc)
4414 {
4415   gboolean is_client;
4416   gint new_id = -1, max_channels = 0;
4417
4418   if (webrtc->priv->sctp_transport) {
4419     g_object_get (webrtc->priv->sctp_transport, "max-channels", &max_channels,
4420         NULL);
4421   }
4422   if (max_channels <= 0) {
4423     max_channels = 65534;
4424   }
4425
4426   g_object_get (webrtc->priv->sctp_transport->transport, "client", &is_client,
4427       NULL);
4428
4429   /* TODO: a better search algorithm */
4430   do {
4431     WebRTCDataChannel *channel;
4432
4433     new_id++;
4434
4435     if (new_id < 0 || new_id >= max_channels) {
4436       /* exhausted id space */
4437       GST_WARNING_OBJECT (webrtc, "Could not find a suitable "
4438           "data channel id (max %i)", max_channels);
4439       return -1;
4440     }
4441
4442     /* client must generate even ids, server must generate odd ids */
4443     if (new_id % 2 == ! !is_client)
4444       continue;
4445
4446     channel = _find_data_channel_for_id (webrtc, new_id);
4447     if (!channel)
4448       break;
4449   } while (TRUE);
4450
4451   return new_id;
4452 }
4453
4454 static void
4455 _update_data_channel_from_sdp_media (GstWebRTCBin * webrtc,
4456     const GstSDPMessage * sdp, guint media_idx, TransportStream * stream,
4457     GError ** error)
4458 {
4459   const GstSDPMedia *local_media, *remote_media;
4460   GstWebRTCDTLSSetup local_setup, remote_setup, new_setup;
4461   TransportReceiveBin *receive;
4462   int local_port, remote_port;
4463   guint64 local_max_size, remote_max_size, max_size;
4464   int i;
4465
4466   local_media =
4467       gst_sdp_message_get_media (webrtc->current_local_description->sdp,
4468       media_idx);
4469   remote_media =
4470       gst_sdp_message_get_media (webrtc->current_remote_description->sdp,
4471       media_idx);
4472
4473   local_setup = _get_dtls_setup_from_media (local_media);
4474   remote_setup = _get_dtls_setup_from_media (remote_media);
4475   new_setup = _get_final_setup (local_setup, remote_setup);
4476   if (new_setup == GST_WEBRTC_DTLS_SETUP_NONE) {
4477     g_set_error (error, GST_WEBRTC_BIN_ERROR, GST_WEBRTC_BIN_ERROR_BAD_SDP,
4478         "Cannot intersect dtls setup for media %u", media_idx);
4479     return;
4480   }
4481
4482   /* data channel is always rtcp-muxed to avoid generating ICE candidates
4483    * for RTCP */
4484   g_object_set (stream, "dtls-client",
4485       new_setup == GST_WEBRTC_DTLS_SETUP_ACTIVE, NULL);
4486
4487   local_port = _get_sctp_port_from_media (local_media);
4488   remote_port = _get_sctp_port_from_media (local_media);
4489   if (local_port == -1 || remote_port == -1) {
4490     g_set_error (error, GST_WEBRTC_BIN_ERROR, GST_WEBRTC_BIN_ERROR_BAD_SDP,
4491         "Could not find sctp port for media %u (local %i, remote %i)",
4492         media_idx, local_port, remote_port);
4493     return;
4494   }
4495
4496   if (0 == (local_max_size =
4497           _get_sctp_max_message_size_from_media (local_media)))
4498     local_max_size = G_MAXUINT64;
4499   if (0 == (remote_max_size =
4500           _get_sctp_max_message_size_from_media (remote_media)))
4501     remote_max_size = G_MAXUINT64;
4502   max_size = MIN (local_max_size, remote_max_size);
4503
4504   webrtc->priv->sctp_transport->max_message_size = max_size;
4505
4506   {
4507     guint orig_local_port, orig_remote_port;
4508
4509     /* XXX: sctpassociation warns if we are in the wrong state */
4510     g_object_get (webrtc->priv->sctp_transport->sctpdec, "local-sctp-port",
4511         &orig_local_port, NULL);
4512
4513     if (orig_local_port != local_port)
4514       g_object_set (webrtc->priv->sctp_transport->sctpdec, "local-sctp-port",
4515           local_port, NULL);
4516
4517     g_object_get (webrtc->priv->sctp_transport->sctpenc, "remote-sctp-port",
4518         &orig_remote_port, NULL);
4519     if (orig_remote_port != remote_port)
4520       g_object_set (webrtc->priv->sctp_transport->sctpenc, "remote-sctp-port",
4521           remote_port, NULL);
4522   }
4523
4524   for (i = 0; i < webrtc->priv->data_channels->len; i++) {
4525     WebRTCDataChannel *channel;
4526
4527     channel = g_ptr_array_index (webrtc->priv->data_channels, i);
4528
4529     if (channel->parent.id == -1)
4530       channel->parent.id = _generate_data_channel_id (webrtc);
4531     if (channel->parent.id == -1)
4532       GST_ELEMENT_WARNING (webrtc, RESOURCE, NOT_FOUND,
4533           ("%s", "Failed to generate an identifier for a data channel"), NULL);
4534
4535     if (webrtc->priv->sctp_transport->association_established
4536         && !channel->parent.negotiated && !channel->opened) {
4537       webrtc_data_channel_link_to_sctp (channel, webrtc->priv->sctp_transport);
4538       webrtc_data_channel_start_negotiation (channel);
4539     }
4540   }
4541
4542   stream->active = TRUE;
4543
4544   receive = TRANSPORT_RECEIVE_BIN (stream->receive_bin);
4545   transport_receive_bin_set_receive_state (receive, RECEIVE_STATE_PASS);
4546 }
4547
4548 static gboolean
4549 _find_compatible_unassociated_transceiver (GstWebRTCRTPTransceiver * p1,
4550     gconstpointer data)
4551 {
4552   GstWebRTCKind kind = GPOINTER_TO_INT (data);
4553
4554   if (p1->mid)
4555     return FALSE;
4556   if (p1->mline != -1)
4557     return FALSE;
4558   if (p1->stopped)
4559     return FALSE;
4560   if (p1->kind != GST_WEBRTC_KIND_UNKNOWN && p1->kind != kind)
4561     return FALSE;
4562
4563   return TRUE;
4564 }
4565
4566 static void
4567 _connect_rtpfunnel (GstWebRTCBin * webrtc, guint session_id)
4568 {
4569   gchar *pad_name;
4570   GstPad *queue_srcpad;
4571   GstPad *rtp_sink;
4572   TransportStream *stream = _find_transport_for_session (webrtc, session_id);
4573   GstElement *queue;
4574
4575   g_assert (stream);
4576
4577   if (webrtc->rtpfunnel)
4578     goto done;
4579
4580   webrtc->rtpfunnel = gst_element_factory_make ("rtpfunnel", NULL);
4581   gst_bin_add (GST_BIN (webrtc), webrtc->rtpfunnel);
4582   gst_element_sync_state_with_parent (webrtc->rtpfunnel);
4583
4584   queue = gst_element_factory_make ("queue", NULL);
4585   gst_bin_add (GST_BIN (webrtc), queue);
4586   gst_element_sync_state_with_parent (queue);
4587
4588   gst_element_link (webrtc->rtpfunnel, queue);
4589
4590   queue_srcpad = gst_element_get_static_pad (queue, "src");
4591
4592   pad_name = g_strdup_printf ("send_rtp_sink_%d", session_id);
4593   rtp_sink = gst_element_get_request_pad (webrtc->rtpbin, pad_name);
4594   g_free (pad_name);
4595   gst_pad_link (queue_srcpad, rtp_sink);
4596   gst_object_unref (queue_srcpad);
4597   gst_object_unref (rtp_sink);
4598
4599   pad_name = g_strdup_printf ("send_rtp_src_%d", session_id);
4600   if (!gst_element_link_pads (GST_ELEMENT (webrtc->rtpbin), pad_name,
4601           GST_ELEMENT (stream->send_bin), "rtp_sink"))
4602     g_warn_if_reached ();
4603   g_free (pad_name);
4604
4605 done:
4606   return;
4607 }
4608
4609 static gboolean
4610 _update_transceivers_from_sdp (GstWebRTCBin * webrtc, SDPSource source,
4611     GstWebRTCSessionDescription * sdp, GError ** error)
4612 {
4613   int i;
4614   gboolean ret = FALSE;
4615   GStrv bundled = NULL;
4616   guint bundle_idx = 0;
4617   TransportStream *bundle_stream = NULL;
4618
4619   /* FIXME: With some peers, it's possible we could have
4620    * multiple bundles to deal with, although I've never seen one yet */
4621   if (webrtc->bundle_policy != GST_WEBRTC_BUNDLE_POLICY_NONE)
4622     if (!_parse_bundle (sdp->sdp, &bundled, error))
4623       goto done;
4624
4625   if (bundled) {
4626
4627     if (!_get_bundle_index (sdp->sdp, bundled, &bundle_idx)) {
4628       g_set_error (error, GST_WEBRTC_BIN_ERROR, GST_WEBRTC_BIN_ERROR_BAD_SDP,
4629           "Bundle tag is %s but no media found matching", bundled[0]);
4630       goto done;
4631     }
4632
4633     bundle_stream = _get_or_create_transport_stream (webrtc, bundle_idx,
4634         _message_media_is_datachannel (sdp->sdp, bundle_idx));
4635     /* Mark the bundle stream as inactive to start. It will be set to TRUE
4636      * by any bundled mline that is active, and at the end we set the
4637      * receivebin to BLOCK if all mlines were inactive. */
4638     bundle_stream->active = FALSE;
4639
4640     g_array_set_size (bundle_stream->ptmap, 0);
4641     for (i = 0; i < gst_sdp_message_medias_len (sdp->sdp); i++) {
4642       /* When bundling, we need to do this up front, or else RTX
4643        * parameters aren't set up properly for the bundled streams */
4644       _update_transport_ptmap_from_media (webrtc, bundle_stream, sdp->sdp, i);
4645     }
4646
4647     _connect_rtpfunnel (webrtc, bundle_idx);
4648   }
4649
4650   for (i = 0; i < gst_sdp_message_medias_len (sdp->sdp); i++) {
4651     const GstSDPMedia *media = gst_sdp_message_get_media (sdp->sdp, i);
4652     TransportStream *stream;
4653     GstWebRTCRTPTransceiver *trans;
4654     guint transport_idx;
4655
4656     /* skip rejected media */
4657     if (gst_sdp_media_get_port (media) == 0)
4658       continue;
4659
4660     if (bundled)
4661       transport_idx = bundle_idx;
4662     else
4663       transport_idx = i;
4664
4665     trans = _find_transceiver_for_sdp_media (webrtc, sdp->sdp, i);
4666
4667     stream = _get_or_create_transport_stream (webrtc, transport_idx,
4668         _message_media_is_datachannel (sdp->sdp, transport_idx));
4669     if (!bundled) {
4670       /* When bundling, these were all set up above, but when not
4671        * bundling we need to do it now */
4672       g_array_set_size (stream->ptmap, 0);
4673       _update_transport_ptmap_from_media (webrtc, stream, sdp->sdp, i);
4674     }
4675
4676     if (trans)
4677       webrtc_transceiver_set_transport ((WebRTCTransceiver *) trans, stream);
4678
4679     if (source == SDP_LOCAL && sdp->type == GST_WEBRTC_SDP_TYPE_OFFER && !trans) {
4680       g_set_error (error, GST_WEBRTC_BIN_ERROR, GST_WEBRTC_BIN_ERROR_BAD_SDP,
4681           "State mismatch.  Could not find local transceiver by mline %u", i);
4682       goto done;
4683     } else {
4684       if (g_strcmp0 (gst_sdp_media_get_media (media), "audio") == 0 ||
4685           g_strcmp0 (gst_sdp_media_get_media (media), "video") == 0) {
4686         /* No existing transceiver, find an unused one */
4687         if (!trans) {
4688           GstWebRTCKind kind;
4689
4690           if (g_strcmp0 (gst_sdp_media_get_media (media), "audio") == 0)
4691             kind = GST_WEBRTC_KIND_AUDIO;
4692           else
4693             kind = GST_WEBRTC_KIND_VIDEO;
4694
4695           trans = _find_transceiver (webrtc, GINT_TO_POINTER (kind),
4696               (FindTransceiverFunc) _find_compatible_unassociated_transceiver);
4697         }
4698
4699         /* Still no transceiver? Create one */
4700         /* XXX: default to the advertised direction in the sdp for new
4701          * transceivers.  The spec doesn't actually say what happens here, only
4702          * that calls to setDirection will change the value.  Nothing about
4703          * a default value when the transceiver is created internally */
4704         if (!trans) {
4705           WebRTCTransceiver *t = _create_webrtc_transceiver (webrtc,
4706               _get_direction_from_media (media), i);
4707           webrtc_transceiver_set_transport (t, stream);
4708           trans = GST_WEBRTC_RTP_TRANSCEIVER (t);
4709         }
4710
4711         _update_transceiver_from_sdp_media (webrtc, sdp->sdp, i, stream,
4712             trans, bundled, bundle_idx, error);
4713       } else if (_message_media_is_datachannel (sdp->sdp, i)) {
4714         _update_data_channel_from_sdp_media (webrtc, sdp->sdp, i, stream,
4715             error);
4716       } else {
4717         GST_ERROR_OBJECT (webrtc, "Unknown media type in SDP at index %u", i);
4718       }
4719     }
4720   }
4721
4722   if (bundle_stream && bundle_stream->active == FALSE) {
4723     /* No bundled mline marked the bundle as active, so block the receive bin, as
4724      * this bundle is completely inactive */
4725     GST_LOG_OBJECT (webrtc,
4726         "All mlines in bundle %u are inactive. Blocking receiver", bundle_idx);
4727     transport_receive_bin_set_receive_state (bundle_stream->receive_bin,
4728         RECEIVE_STATE_BLOCK);
4729   }
4730
4731   ret = TRUE;
4732
4733 done:
4734   g_strfreev (bundled);
4735
4736   return ret;
4737 }
4738
4739 static gboolean
4740 check_transceivers_not_removed (GstWebRTCBin * webrtc,
4741     GstWebRTCSessionDescription * previous, GstWebRTCSessionDescription * new)
4742 {
4743   if (!previous)
4744     return TRUE;
4745
4746   if (gst_sdp_message_medias_len (previous->sdp) >
4747       gst_sdp_message_medias_len (new->sdp))
4748     return FALSE;
4749
4750   return TRUE;
4751 }
4752
4753 static gboolean
4754 check_locked_mlines (GstWebRTCBin * webrtc, GstWebRTCSessionDescription * sdp,
4755     GError ** error)
4756 {
4757   guint i;
4758
4759   for (i = 0; i < gst_sdp_message_medias_len (sdp->sdp); i++) {
4760     const GstSDPMedia *media = gst_sdp_message_get_media (sdp->sdp, i);
4761     GstWebRTCRTPTransceiver *rtp_trans;
4762     WebRTCTransceiver *trans;
4763
4764     rtp_trans = _find_transceiver_for_sdp_media (webrtc, sdp->sdp, i);
4765     /* only look for matching mid */
4766     if (rtp_trans == NULL)
4767       continue;
4768
4769     trans = WEBRTC_TRANSCEIVER (rtp_trans);
4770
4771     /* We only validate the locked mlines for now */
4772     if (!trans->mline_locked)
4773       continue;
4774
4775     if (rtp_trans->mline != i) {
4776       g_set_error (error, GST_WEBRTC_BIN_ERROR,
4777           GST_WEBRTC_BIN_ERROR_IMPOSSIBLE_MLINE_RESTRICTION,
4778           "m-line with mid %s is at position %d, but was locked to %d, "
4779           "rejecting", rtp_trans->mid, i, rtp_trans->mline);
4780       return FALSE;
4781     }
4782
4783     if (rtp_trans->kind != GST_WEBRTC_KIND_UNKNOWN) {
4784       if (!g_strcmp0 (gst_sdp_media_get_media (media), "audio") &&
4785           rtp_trans->kind != GST_WEBRTC_KIND_AUDIO) {
4786         g_set_error (error, GST_WEBRTC_BIN_ERROR,
4787             GST_WEBRTC_BIN_ERROR_IMPOSSIBLE_MLINE_RESTRICTION,
4788             "m-line %d was locked to audio, but SDP has %s media", i,
4789             gst_sdp_media_get_media (media));
4790         return FALSE;
4791       }
4792
4793       if (!g_strcmp0 (gst_sdp_media_get_media (media), "video") &&
4794           rtp_trans->kind != GST_WEBRTC_KIND_VIDEO) {
4795         g_set_error (error, GST_WEBRTC_BIN_ERROR,
4796             GST_WEBRTC_BIN_ERROR_IMPOSSIBLE_MLINE_RESTRICTION,
4797             "m-line %d was locked to video, but SDP has %s media", i,
4798             gst_sdp_media_get_media (media));
4799         return FALSE;
4800       }
4801     }
4802   }
4803
4804   return TRUE;
4805 }
4806
4807
4808 struct set_description
4809 {
4810   GstPromise *promise;
4811   SDPSource source;
4812   GstWebRTCSessionDescription *sdp;
4813 };
4814
4815 static GstWebRTCSessionDescription *
4816 get_previous_description (GstWebRTCBin * webrtc, SDPSource source,
4817     GstWebRTCSDPType type)
4818 {
4819   switch (type) {
4820     case GST_WEBRTC_SDP_TYPE_OFFER:
4821     case GST_WEBRTC_SDP_TYPE_PRANSWER:
4822     case GST_WEBRTC_SDP_TYPE_ANSWER:
4823       if (source == SDP_LOCAL) {
4824         return webrtc->current_local_description;
4825       } else {
4826         return webrtc->current_remote_description;
4827       }
4828     case GST_WEBRTC_SDP_TYPE_ROLLBACK:
4829       return NULL;
4830     default:
4831       /* other values mean memory corruption/uninitialized! */
4832       g_assert_not_reached ();
4833       break;
4834   }
4835
4836   return NULL;
4837 }
4838
4839 /* http://w3c.github.io/webrtc-pc/#set-description */
4840 static void
4841 _set_description_task (GstWebRTCBin * webrtc, struct set_description *sd)
4842 {
4843   GstWebRTCSignalingState new_signaling_state = webrtc->signaling_state;
4844   gboolean signalling_state_changed = FALSE;
4845   GError *error = NULL;
4846   GStrv bundled = NULL;
4847   guint bundle_idx = 0;
4848   guint i;
4849
4850   {
4851     gchar *state = _enum_value_to_string (GST_TYPE_WEBRTC_SIGNALING_STATE,
4852         webrtc->signaling_state);
4853     gchar *type_str =
4854         _enum_value_to_string (GST_TYPE_WEBRTC_SDP_TYPE, sd->sdp->type);
4855     gchar *sdp_text = gst_sdp_message_as_text (sd->sdp->sdp);
4856     GST_INFO_OBJECT (webrtc, "Attempting to set %s %s in the %s state",
4857         _sdp_source_to_string (sd->source), type_str, state);
4858     GST_TRACE_OBJECT (webrtc, "SDP contents\n%s", sdp_text);
4859     g_free (sdp_text);
4860     g_free (state);
4861     g_free (type_str);
4862   }
4863
4864   if (!validate_sdp (webrtc->signaling_state, sd->source, sd->sdp, &error))
4865     goto out;
4866
4867   if (webrtc->bundle_policy != GST_WEBRTC_BUNDLE_POLICY_NONE)
4868     if (!_parse_bundle (sd->sdp->sdp, &bundled, &error))
4869       goto out;
4870
4871   if (bundled) {
4872     if (!_get_bundle_index (sd->sdp->sdp, bundled, &bundle_idx)) {
4873       g_set_error (&error, GST_WEBRTC_BIN_ERROR, GST_WEBRTC_BIN_ERROR_BAD_SDP,
4874           "Bundle tag is %s but no matching media found", bundled[0]);
4875       goto out;
4876     }
4877   }
4878
4879   if (!check_transceivers_not_removed (webrtc,
4880           get_previous_description (webrtc, sd->source, sd->sdp->type),
4881           sd->sdp)) {
4882     g_set_error_literal (&error, GST_WEBRTC_BIN_ERROR,
4883         GST_WEBRTC_BIN_ERROR_BAD_SDP,
4884         "m=lines removed from the SDP. Processing a completely new connection "
4885         "is not currently supported.");
4886     goto out;
4887   }
4888
4889   if (!check_locked_mlines (webrtc, sd->sdp, &error))
4890     goto out;
4891
4892   switch (sd->sdp->type) {
4893     case GST_WEBRTC_SDP_TYPE_OFFER:{
4894       if (sd->source == SDP_LOCAL) {
4895         if (webrtc->pending_local_description)
4896           gst_webrtc_session_description_free
4897               (webrtc->pending_local_description);
4898         webrtc->pending_local_description =
4899             gst_webrtc_session_description_copy (sd->sdp);
4900         new_signaling_state = GST_WEBRTC_SIGNALING_STATE_HAVE_LOCAL_OFFER;
4901       } else {
4902         if (webrtc->pending_remote_description)
4903           gst_webrtc_session_description_free
4904               (webrtc->pending_remote_description);
4905         webrtc->pending_remote_description =
4906             gst_webrtc_session_description_copy (sd->sdp);
4907         new_signaling_state = GST_WEBRTC_SIGNALING_STATE_HAVE_REMOTE_OFFER;
4908       }
4909       break;
4910     }
4911     case GST_WEBRTC_SDP_TYPE_ANSWER:{
4912       if (sd->source == SDP_LOCAL) {
4913         if (webrtc->current_local_description)
4914           gst_webrtc_session_description_free
4915               (webrtc->current_local_description);
4916         webrtc->current_local_description =
4917             gst_webrtc_session_description_copy (sd->sdp);
4918
4919         if (webrtc->current_remote_description)
4920           gst_webrtc_session_description_free
4921               (webrtc->current_remote_description);
4922         webrtc->current_remote_description = webrtc->pending_remote_description;
4923         webrtc->pending_remote_description = NULL;
4924       } else {
4925         if (webrtc->current_remote_description)
4926           gst_webrtc_session_description_free
4927               (webrtc->current_remote_description);
4928         webrtc->current_remote_description =
4929             gst_webrtc_session_description_copy (sd->sdp);
4930
4931         if (webrtc->current_local_description)
4932           gst_webrtc_session_description_free
4933               (webrtc->current_local_description);
4934         webrtc->current_local_description = webrtc->pending_local_description;
4935         webrtc->pending_local_description = NULL;
4936       }
4937
4938       if (webrtc->pending_local_description)
4939         gst_webrtc_session_description_free (webrtc->pending_local_description);
4940       webrtc->pending_local_description = NULL;
4941
4942       if (webrtc->pending_remote_description)
4943         gst_webrtc_session_description_free
4944             (webrtc->pending_remote_description);
4945       webrtc->pending_remote_description = NULL;
4946
4947       new_signaling_state = GST_WEBRTC_SIGNALING_STATE_STABLE;
4948       break;
4949     }
4950     case GST_WEBRTC_SDP_TYPE_ROLLBACK:{
4951       GST_FIXME_OBJECT (webrtc, "rollbacks are completely untested");
4952       if (sd->source == SDP_LOCAL) {
4953         if (webrtc->pending_local_description)
4954           gst_webrtc_session_description_free
4955               (webrtc->pending_local_description);
4956         webrtc->pending_local_description = NULL;
4957       } else {
4958         if (webrtc->pending_remote_description)
4959           gst_webrtc_session_description_free
4960               (webrtc->pending_remote_description);
4961         webrtc->pending_remote_description = NULL;
4962       }
4963
4964       new_signaling_state = GST_WEBRTC_SIGNALING_STATE_STABLE;
4965       break;
4966     }
4967     case GST_WEBRTC_SDP_TYPE_PRANSWER:{
4968       GST_FIXME_OBJECT (webrtc, "pranswers are completely untested");
4969       if (sd->source == SDP_LOCAL) {
4970         if (webrtc->pending_local_description)
4971           gst_webrtc_session_description_free
4972               (webrtc->pending_local_description);
4973         webrtc->pending_local_description =
4974             gst_webrtc_session_description_copy (sd->sdp);
4975
4976         new_signaling_state = GST_WEBRTC_SIGNALING_STATE_HAVE_LOCAL_PRANSWER;
4977       } else {
4978         if (webrtc->pending_remote_description)
4979           gst_webrtc_session_description_free
4980               (webrtc->pending_remote_description);
4981         webrtc->pending_remote_description =
4982             gst_webrtc_session_description_copy (sd->sdp);
4983
4984         new_signaling_state = GST_WEBRTC_SIGNALING_STATE_HAVE_REMOTE_PRANSWER;
4985       }
4986       break;
4987     }
4988   }
4989
4990   if (sd->sdp->type == GST_WEBRTC_SDP_TYPE_ROLLBACK) {
4991     /* FIXME:
4992      * If the mid value of an RTCRtpTransceiver was set to a non-null value
4993      * by the RTCSessionDescription that is being rolled back, set the mid
4994      * value of that transceiver to null, as described by [JSEP]
4995      * (section 4.1.7.2.).
4996      * If an RTCRtpTransceiver was created by applying the
4997      * RTCSessionDescription that is being rolled back, and a track has not
4998      * been attached to it via addTrack, remove that transceiver from
4999      * connection's set of transceivers, as described by [JSEP]
5000      * (section 4.1.7.2.).
5001      * Restore the value of connection's [[ sctpTransport]] internal slot
5002      * to its value at the last stable signaling state.
5003      */
5004   }
5005
5006   if (webrtc->signaling_state != new_signaling_state) {
5007     webrtc->signaling_state = new_signaling_state;
5008     signalling_state_changed = TRUE;
5009   }
5010
5011   {
5012     gboolean ice_controller = FALSE;
5013
5014     /* get the current value so we don't change ice controller from TRUE to
5015      * FALSE on renegotiation or once set to TRUE for the initial local offer */
5016     ice_controller = gst_webrtc_ice_get_is_controller (webrtc->priv->ice);
5017
5018     /* we control ice negotiation if we send the initial offer */
5019     ice_controller |=
5020         new_signaling_state == GST_WEBRTC_SIGNALING_STATE_HAVE_LOCAL_OFFER
5021         && webrtc->current_remote_description == NULL;
5022     /* or, if the remote is an ice-lite peer */
5023     ice_controller |= new_signaling_state == GST_WEBRTC_SIGNALING_STATE_STABLE
5024         && webrtc->current_remote_description
5025         && _message_has_attribute_key (webrtc->current_remote_description->sdp,
5026         "ice-lite");
5027
5028     GST_DEBUG_OBJECT (webrtc, "we are in ice controlling mode: %s",
5029         ice_controller ? "true" : "false");
5030     gst_webrtc_ice_set_is_controller (webrtc->priv->ice, ice_controller);
5031   }
5032
5033   if (new_signaling_state == GST_WEBRTC_SIGNALING_STATE_STABLE) {
5034     GList *tmp;
5035
5036     /* media modifications */
5037     if (!_update_transceivers_from_sdp (webrtc, sd->source, sd->sdp, &error))
5038       goto out;
5039
5040     for (tmp = webrtc->priv->pending_sink_transceivers; tmp;) {
5041       GstWebRTCBinPad *pad = GST_WEBRTC_BIN_PAD (tmp->data);
5042       GstWebRTCRTPTransceiverDirection new_dir;
5043       GList *old = tmp;
5044       const GstSDPMedia *media;
5045
5046       if (!pad->received_caps) {
5047         GST_LOG_OBJECT (pad, "has not received any caps yet. Skipping.");
5048         tmp = tmp->next;
5049         continue;
5050       }
5051
5052       if (pad->trans->mline >= gst_sdp_message_medias_len (sd->sdp->sdp)) {
5053         GST_DEBUG_OBJECT (pad, "not mentioned in this description. Skipping");
5054         tmp = tmp->next;
5055         continue;
5056       }
5057
5058       media = gst_sdp_message_get_media (sd->sdp->sdp, pad->trans->mline);
5059       /* skip rejected media */
5060       if (gst_sdp_media_get_port (media) == 0) {
5061         /* FIXME: arrange for an appropriate flow return */
5062         GST_FIXME_OBJECT (pad, "Media has been rejected.  Need to arrange for "
5063             "a more correct flow return.");
5064         tmp = tmp->next;
5065         continue;
5066       }
5067
5068       if (!pad->trans) {
5069         GST_LOG_OBJECT (pad, "doesn't have a transceiver");
5070         tmp = tmp->next;
5071         continue;
5072       }
5073
5074       new_dir = pad->trans->direction;
5075       if (new_dir != GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY &&
5076           new_dir != GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV) {
5077         GST_LOG_OBJECT (pad, "transceiver %" GST_PTR_FORMAT " is not sending "
5078             "data at the moment. Not connecting input stream yet", pad->trans);
5079         tmp = tmp->next;
5080         continue;
5081       }
5082
5083       GST_LOG_OBJECT (pad, "Connecting input stream to rtpbin with "
5084           "transceiver %" GST_PTR_FORMAT " and caps %" GST_PTR_FORMAT,
5085           pad->trans, pad->received_caps);
5086       _connect_input_stream (webrtc, pad);
5087       gst_pad_remove_probe (GST_PAD (pad), pad->block_id);
5088       pad->block_id = 0;
5089
5090       tmp = tmp->next;
5091       gst_object_unref (old->data);
5092       webrtc->priv->pending_sink_transceivers =
5093           g_list_delete_link (webrtc->priv->pending_sink_transceivers, old);
5094     }
5095   }
5096
5097   for (i = 0; i < gst_sdp_message_medias_len (sd->sdp->sdp); i++) {
5098     const GstSDPMedia *media = gst_sdp_message_get_media (sd->sdp->sdp, i);
5099     gchar *ufrag, *pwd;
5100     TransportStream *item;
5101
5102     item =
5103         _get_or_create_transport_stream (webrtc, bundled ? bundle_idx : i,
5104         _message_media_is_datachannel (sd->sdp->sdp, bundled ? bundle_idx : i));
5105
5106     if (sd->source == SDP_REMOTE) {
5107       guint j;
5108
5109       for (j = 0; j < gst_sdp_media_attributes_len (media); j++) {
5110         const GstSDPAttribute *attr = gst_sdp_media_get_attribute (media, j);
5111
5112         if (g_strcmp0 (attr->key, "ssrc") == 0) {
5113           GStrv split = g_strsplit (attr->value, " ", 0);
5114           guint32 ssrc;
5115
5116           if (split[0] && sscanf (split[0], "%u", &ssrc) && split[1]
5117               && g_str_has_prefix (split[1], "cname:")) {
5118             g_ptr_array_add (item->remote_ssrcmap, ssrcmap_item_new (ssrc, i));
5119           }
5120           g_strfreev (split);
5121         }
5122       }
5123     }
5124
5125     if (sd->source == SDP_LOCAL && (!bundled || bundle_idx == i)) {
5126       _get_ice_credentials_from_sdp_media (sd->sdp->sdp, i, &ufrag, &pwd);
5127
5128       gst_webrtc_ice_set_local_credentials (webrtc->priv->ice,
5129           item->stream, ufrag, pwd);
5130       g_free (ufrag);
5131       g_free (pwd);
5132     } else if (sd->source == SDP_REMOTE && !_media_is_bundle_only (media)) {
5133       _get_ice_credentials_from_sdp_media (sd->sdp->sdp, i, &ufrag, &pwd);
5134
5135       gst_webrtc_ice_set_remote_credentials (webrtc->priv->ice,
5136           item->stream, ufrag, pwd);
5137       g_free (ufrag);
5138       g_free (pwd);
5139     }
5140   }
5141
5142   if (sd->source == SDP_LOCAL) {
5143     for (i = 0; i < webrtc->priv->ice_stream_map->len; i++) {
5144       IceStreamItem *item =
5145           &g_array_index (webrtc->priv->ice_stream_map, IceStreamItem, i);
5146
5147       gst_webrtc_ice_gather_candidates (webrtc->priv->ice, item->stream);
5148     }
5149   }
5150
5151   /* Add any pending trickle ICE candidates if we have both offer and answer */
5152   if (webrtc->current_local_description && webrtc->current_remote_description) {
5153     int i;
5154
5155     GstWebRTCSessionDescription *remote_sdp =
5156         webrtc->current_remote_description;
5157
5158     /* Add any remote ICE candidates from the remote description to
5159      * support non-trickle peers first */
5160     for (i = 0; i < gst_sdp_message_medias_len (remote_sdp->sdp); i++) {
5161       const GstSDPMedia *media = gst_sdp_message_get_media (remote_sdp->sdp, i);
5162       _add_ice_candidates_from_sdp (webrtc, i, media);
5163     }
5164
5165     ICE_LOCK (webrtc);
5166     for (i = 0; i < webrtc->priv->pending_remote_ice_candidates->len; i++) {
5167       IceCandidateItem *item =
5168           &g_array_index (webrtc->priv->pending_remote_ice_candidates,
5169           IceCandidateItem, i);
5170
5171       _add_ice_candidate (webrtc, item, TRUE);
5172     }
5173     g_array_set_size (webrtc->priv->pending_remote_ice_candidates, 0);
5174     ICE_UNLOCK (webrtc);
5175   }
5176
5177   /*
5178    * If connection's signaling state changed above, fire an event named
5179    * signalingstatechange at connection.
5180    */
5181   if (signalling_state_changed) {
5182     gchar *from = _enum_value_to_string (GST_TYPE_WEBRTC_SIGNALING_STATE,
5183         webrtc->signaling_state);
5184     gchar *to = _enum_value_to_string (GST_TYPE_WEBRTC_SIGNALING_STATE,
5185         new_signaling_state);
5186     GST_TRACE_OBJECT (webrtc, "notify signaling-state from %s "
5187         "to %s", from, to);
5188     PC_UNLOCK (webrtc);
5189     g_object_notify (G_OBJECT (webrtc), "signaling-state");
5190     PC_LOCK (webrtc);
5191
5192     g_free (from);
5193     g_free (to);
5194   }
5195
5196   if (webrtc->signaling_state == GST_WEBRTC_SIGNALING_STATE_STABLE) {
5197     gboolean prev_need_negotiation = webrtc->priv->need_negotiation;
5198
5199     /* If connection's signaling state is now stable, update the
5200      * negotiation-needed flag. If connection's [[ needNegotiation]] slot
5201      * was true both before and after this update, queue a task to check
5202      * connection's [[needNegotiation]] slot and, if still true, fire a
5203      * simple event named negotiationneeded at connection.*/
5204     _update_need_negotiation (webrtc);
5205     if (prev_need_negotiation && webrtc->priv->need_negotiation) {
5206       _check_need_negotiation_task (webrtc, NULL);
5207     }
5208   }
5209
5210 out:
5211   g_strfreev (bundled);
5212
5213   PC_UNLOCK (webrtc);
5214   if (error) {
5215     GST_WARNING_OBJECT (webrtc, "returning error: %s", error->message);
5216     gst_promise_reply (sd->promise,
5217         gst_structure_new ("application/x-gstwebrtcbin-error", "error",
5218             G_TYPE_ERROR, error, NULL));
5219     g_clear_error (&error);
5220   } else {
5221     gst_promise_reply (sd->promise, NULL);
5222   }
5223   PC_LOCK (webrtc);
5224 }
5225
5226 static void
5227 _free_set_description_data (struct set_description *sd)
5228 {
5229   if (sd->promise)
5230     gst_promise_unref (sd->promise);
5231   if (sd->sdp)
5232     gst_webrtc_session_description_free (sd->sdp);
5233   g_free (sd);
5234 }
5235
5236 static void
5237 gst_webrtc_bin_set_remote_description (GstWebRTCBin * webrtc,
5238     GstWebRTCSessionDescription * remote_sdp, GstPromise * promise)
5239 {
5240   struct set_description *sd;
5241
5242   if (remote_sdp == NULL)
5243     goto bad_input;
5244   if (remote_sdp->sdp == NULL)
5245     goto bad_input;
5246
5247   sd = g_new0 (struct set_description, 1);
5248   if (promise != NULL)
5249     sd->promise = gst_promise_ref (promise);
5250   sd->source = SDP_REMOTE;
5251   sd->sdp = gst_webrtc_session_description_copy (remote_sdp);
5252
5253   if (!gst_webrtc_bin_enqueue_task (webrtc,
5254           (GstWebRTCBinFunc) _set_description_task, sd,
5255           (GDestroyNotify) _free_set_description_data, promise)) {
5256     GError *error =
5257         g_error_new (GST_WEBRTC_BIN_ERROR, GST_WEBRTC_BIN_ERROR_CLOSED,
5258         "Could not set remote description. webrtcbin is closed.");
5259     GstStructure *s =
5260         gst_structure_new ("application/x-gstwebrtcbin-promise-error",
5261         "error", G_TYPE_ERROR, error, NULL);
5262
5263     gst_promise_reply (promise, s);
5264
5265     g_clear_error (&error);
5266   }
5267
5268   return;
5269
5270 bad_input:
5271   {
5272     gst_promise_reply (promise, NULL);
5273     g_return_if_reached ();
5274   }
5275 }
5276
5277 static void
5278 gst_webrtc_bin_set_local_description (GstWebRTCBin * webrtc,
5279     GstWebRTCSessionDescription * local_sdp, GstPromise * promise)
5280 {
5281   struct set_description *sd;
5282
5283   if (local_sdp == NULL)
5284     goto bad_input;
5285   if (local_sdp->sdp == NULL)
5286     goto bad_input;
5287
5288   sd = g_new0 (struct set_description, 1);
5289   if (promise != NULL)
5290     sd->promise = gst_promise_ref (promise);
5291   sd->source = SDP_LOCAL;
5292   sd->sdp = gst_webrtc_session_description_copy (local_sdp);
5293
5294   if (!gst_webrtc_bin_enqueue_task (webrtc,
5295           (GstWebRTCBinFunc) _set_description_task, sd,
5296           (GDestroyNotify) _free_set_description_data, promise)) {
5297     GError *error =
5298         g_error_new (GST_WEBRTC_BIN_ERROR, GST_WEBRTC_BIN_ERROR_CLOSED,
5299         "Could not set remote description. webrtcbin is closed");
5300     GstStructure *s =
5301         gst_structure_new ("application/x-gstwebrtcbin-promise-error",
5302         "error", G_TYPE_ERROR, error, NULL);
5303
5304     gst_promise_reply (promise, s);
5305
5306     g_clear_error (&error);
5307   }
5308
5309   return;
5310
5311 bad_input:
5312   {
5313     gst_promise_reply (promise, NULL);
5314     g_return_if_reached ();
5315   }
5316 }
5317
5318 static void
5319 _add_ice_candidate_task (GstWebRTCBin * webrtc, IceCandidateItem * item)
5320 {
5321   if (!webrtc->current_local_description || !webrtc->current_remote_description) {
5322     IceCandidateItem new;
5323     new.mlineindex = item->mlineindex;
5324     new.candidate = g_steal_pointer (&item->candidate);
5325
5326     ICE_LOCK (webrtc);
5327     g_array_append_val (webrtc->priv->pending_remote_ice_candidates, new);
5328     ICE_UNLOCK (webrtc);
5329   } else {
5330     _add_ice_candidate (webrtc, item, FALSE);
5331   }
5332 }
5333
5334 static void
5335 _free_ice_candidate_item (IceCandidateItem * item)
5336 {
5337   _clear_ice_candidate_item (item);
5338   g_free (item);
5339 }
5340
5341 static void
5342 gst_webrtc_bin_add_ice_candidate (GstWebRTCBin * webrtc, guint mline,
5343     const gchar * attr)
5344 {
5345   IceCandidateItem *item;
5346
5347   item = g_new0 (IceCandidateItem, 1);
5348   item->mlineindex = mline;
5349   if (attr && attr[0] != 0) {
5350     if (!g_ascii_strncasecmp (attr, "a=candidate:", 12))
5351       item->candidate = g_strdup (attr);
5352     else if (!g_ascii_strncasecmp (attr, "candidate:", 10))
5353       item->candidate = g_strdup_printf ("a=%s", attr);
5354   }
5355   gst_webrtc_bin_enqueue_task (webrtc,
5356       (GstWebRTCBinFunc) _add_ice_candidate_task, item,
5357       (GDestroyNotify) _free_ice_candidate_item, NULL);
5358 }
5359
5360 static void
5361 _on_local_ice_candidate_task (GstWebRTCBin * webrtc)
5362 {
5363   gsize i;
5364   GArray *items;
5365
5366   ICE_LOCK (webrtc);
5367   if (webrtc->priv->pending_local_ice_candidates->len == 0) {
5368     ICE_UNLOCK (webrtc);
5369     GST_LOG_OBJECT (webrtc, "No ICE candidates to process right now");
5370     return;                     /* Nothing to process */
5371   }
5372   /* Take the array so we can process it all and free it later
5373    * without holding the lock
5374    * FIXME: When we depend on GLib 2.64, we can use g_array_steal()
5375    * here */
5376   items = webrtc->priv->pending_local_ice_candidates;
5377   /* Replace with a new array */
5378   webrtc->priv->pending_local_ice_candidates =
5379       g_array_new (FALSE, TRUE, sizeof (IceCandidateItem));
5380   g_array_set_clear_func (webrtc->priv->pending_local_ice_candidates,
5381       (GDestroyNotify) _clear_ice_candidate_item);
5382   ICE_UNLOCK (webrtc);
5383
5384   for (i = 0; i < items->len; i++) {
5385     IceCandidateItem *item = &g_array_index (items, IceCandidateItem, i);
5386     const gchar *cand = item->candidate;
5387
5388     if (!g_ascii_strncasecmp (cand, "a=candidate:", 12)) {
5389       /* stripping away "a=" */
5390       cand += 2;
5391     }
5392
5393     GST_TRACE_OBJECT (webrtc, "produced ICE candidate for mline:%u and %s",
5394         item->mlineindex, cand);
5395
5396     /* First, merge this ice candidate into the appropriate mline
5397      * in the local-description SDP.
5398      * Second, emit the on-ice-candidate signal for the app.
5399      *
5400      * FIXME: This ICE candidate should be stored somewhere with
5401      * the associated mid and also merged back into any subsequent
5402      * local descriptions on renegotiation */
5403     if (webrtc->current_local_description)
5404       _add_ice_candidate_to_sdp (webrtc, webrtc->current_local_description->sdp,
5405           item->mlineindex, cand);
5406     if (webrtc->pending_local_description)
5407       _add_ice_candidate_to_sdp (webrtc, webrtc->pending_local_description->sdp,
5408           item->mlineindex, cand);
5409
5410     PC_UNLOCK (webrtc);
5411     g_signal_emit (webrtc, gst_webrtc_bin_signals[ON_ICE_CANDIDATE_SIGNAL],
5412         0, item->mlineindex, cand);
5413     PC_LOCK (webrtc);
5414
5415   }
5416   g_array_free (items, TRUE);
5417 }
5418
5419 static void
5420 _on_local_ice_candidate_cb (GstWebRTCICE * ice, guint session_id,
5421     gchar * candidate, GstWebRTCBin * webrtc)
5422 {
5423   IceCandidateItem item;
5424   gboolean queue_task = FALSE;
5425
5426   item.mlineindex = session_id;
5427   item.candidate = g_strdup (candidate);
5428
5429   ICE_LOCK (webrtc);
5430   g_array_append_val (webrtc->priv->pending_local_ice_candidates, item);
5431
5432   /* Let the first pending candidate queue a task each time, which will
5433    * handle any that arrive between now and when the task runs */
5434   if (webrtc->priv->pending_local_ice_candidates->len == 1)
5435     queue_task = TRUE;
5436   ICE_UNLOCK (webrtc);
5437
5438   if (queue_task) {
5439     GST_TRACE_OBJECT (webrtc, "Queueing on_ice_candidate_task");
5440     gst_webrtc_bin_enqueue_task (webrtc,
5441         (GstWebRTCBinFunc) _on_local_ice_candidate_task, NULL, NULL, NULL);
5442   }
5443 }
5444
5445 struct get_stats
5446 {
5447   GstPad *pad;
5448   GstPromise *promise;
5449 };
5450
5451 static void
5452 _free_get_stats (struct get_stats *stats)
5453 {
5454   if (stats->pad)
5455     gst_object_unref (stats->pad);
5456   if (stats->promise)
5457     gst_promise_unref (stats->promise);
5458   g_free (stats);
5459 }
5460
5461 /* https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-getstats() */
5462 static void
5463 _get_stats_task (GstWebRTCBin * webrtc, struct get_stats *stats)
5464 {
5465   /* Our selector is the pad,
5466    * https://www.w3.org/TR/webrtc/#dfn-stats-selection-algorithm
5467    */
5468   gst_promise_reply (stats->promise, gst_webrtc_bin_create_stats (webrtc,
5469           stats->pad));
5470 }
5471
5472 static void
5473 gst_webrtc_bin_get_stats (GstWebRTCBin * webrtc, GstPad * pad,
5474     GstPromise * promise)
5475 {
5476   struct get_stats *stats;
5477
5478   g_return_if_fail (promise != NULL);
5479   g_return_if_fail (pad == NULL || GST_IS_WEBRTC_BIN_PAD (pad));
5480
5481   stats = g_new0 (struct get_stats, 1);
5482   stats->promise = gst_promise_ref (promise);
5483   /* FIXME: check that pad exists in element */
5484   if (pad)
5485     stats->pad = gst_object_ref (pad);
5486
5487   if (!gst_webrtc_bin_enqueue_task (webrtc, (GstWebRTCBinFunc) _get_stats_task,
5488           stats, (GDestroyNotify) _free_get_stats, promise)) {
5489     GError *error =
5490         g_error_new (GST_WEBRTC_BIN_ERROR, GST_WEBRTC_BIN_ERROR_CLOSED,
5491         "Could not retrieve statistics. webrtcbin is closed.");
5492     GstStructure *s = gst_structure_new ("application/x-gst-promise-error",
5493         "error", G_TYPE_ERROR, error, NULL);
5494
5495     gst_promise_reply (promise, s);
5496
5497     g_clear_error (&error);
5498   }
5499 }
5500
5501 static GstWebRTCRTPTransceiver *
5502 gst_webrtc_bin_add_transceiver (GstWebRTCBin * webrtc,
5503     GstWebRTCRTPTransceiverDirection direction, GstCaps * caps)
5504 {
5505   WebRTCTransceiver *trans;
5506   GstWebRTCRTPTransceiver *rtp_trans;
5507
5508   g_return_val_if_fail (direction != GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_NONE,
5509       NULL);
5510
5511   trans = _create_webrtc_transceiver (webrtc, direction, -1);
5512   GST_LOG_OBJECT (webrtc,
5513       "Created new unassociated transceiver %" GST_PTR_FORMAT, trans);
5514
5515   rtp_trans = GST_WEBRTC_RTP_TRANSCEIVER (trans);
5516   if (caps) {
5517     rtp_trans->codec_preferences = gst_caps_ref (caps);
5518     _update_transceiver_kind_from_caps (rtp_trans, caps);
5519   }
5520
5521   return gst_object_ref (trans);
5522 }
5523
5524 static void
5525 _deref_and_unref (GstObject ** object)
5526 {
5527   gst_clear_object (object);
5528 }
5529
5530 static GArray *
5531 gst_webrtc_bin_get_transceivers (GstWebRTCBin * webrtc)
5532 {
5533   GArray *arr = g_array_new (FALSE, TRUE, sizeof (GstWebRTCRTPTransceiver *));
5534   int i;
5535
5536   g_array_set_clear_func (arr, (GDestroyNotify) _deref_and_unref);
5537
5538   for (i = 0; i < webrtc->priv->transceivers->len; i++) {
5539     GstWebRTCRTPTransceiver *trans =
5540         g_ptr_array_index (webrtc->priv->transceivers, i);
5541     gst_object_ref (trans);
5542     g_array_append_val (arr, trans);
5543   }
5544
5545   return arr;
5546 }
5547
5548 static GstWebRTCRTPTransceiver *
5549 gst_webrtc_bin_get_transceiver (GstWebRTCBin * webrtc, guint idx)
5550 {
5551   GstWebRTCRTPTransceiver *trans = NULL;
5552
5553   if (idx >= webrtc->priv->transceivers->len) {
5554     GST_ERROR_OBJECT (webrtc, "No transceiver for idx %d", idx);
5555     goto done;
5556   }
5557
5558   trans = g_ptr_array_index (webrtc->priv->transceivers, idx);
5559   gst_object_ref (trans);
5560
5561 done:
5562   return trans;
5563 }
5564
5565 static gboolean
5566 gst_webrtc_bin_add_turn_server (GstWebRTCBin * webrtc, const gchar * uri)
5567 {
5568   g_return_val_if_fail (GST_IS_WEBRTC_BIN (webrtc), FALSE);
5569   g_return_val_if_fail (uri != NULL, FALSE);
5570
5571   GST_DEBUG_OBJECT (webrtc, "Adding turn server: %s", uri);
5572
5573   return gst_webrtc_ice_add_turn_server (webrtc->priv->ice, uri);
5574 }
5575
5576 static gboolean
5577 copy_sticky_events (GstPad * pad, GstEvent ** event, gpointer user_data)
5578 {
5579   GstPad *gpad = GST_PAD_CAST (user_data);
5580
5581   GST_DEBUG_OBJECT (gpad, "store sticky event %" GST_PTR_FORMAT, *event);
5582   gst_pad_store_sticky_event (gpad, *event);
5583
5584   return TRUE;
5585 }
5586
5587 static WebRTCDataChannel *
5588 gst_webrtc_bin_create_data_channel (GstWebRTCBin * webrtc, const gchar * label,
5589     GstStructure * init_params)
5590 {
5591   gboolean ordered;
5592   gint max_packet_lifetime;
5593   gint max_retransmits;
5594   const gchar *protocol;
5595   gboolean negotiated;
5596   gint id;
5597   GstWebRTCPriorityType priority;
5598   WebRTCDataChannel *ret;
5599   gint max_channels = 65534;
5600
5601   g_return_val_if_fail (GST_IS_WEBRTC_BIN (webrtc), NULL);
5602   g_return_val_if_fail (label != NULL, NULL);
5603   g_return_val_if_fail (strlen (label) <= 65535, NULL);
5604   g_return_val_if_fail (webrtc->priv->is_closed != TRUE, NULL);
5605
5606   if (!init_params
5607       || !gst_structure_get_boolean (init_params, "ordered", &ordered))
5608     ordered = TRUE;
5609   if (!init_params
5610       || !gst_structure_get_int (init_params, "max-packet-lifetime",
5611           &max_packet_lifetime))
5612     max_packet_lifetime = -1;
5613   if (!init_params
5614       || !gst_structure_get_int (init_params, "max-retransmits",
5615           &max_retransmits))
5616     max_retransmits = -1;
5617   /* both retransmits and lifetime cannot be set */
5618   g_return_val_if_fail ((max_packet_lifetime == -1)
5619       || (max_retransmits == -1), NULL);
5620
5621   if (!init_params
5622       || !(protocol = gst_structure_get_string (init_params, "protocol")))
5623     protocol = "";
5624   g_return_val_if_fail (strlen (protocol) <= 65535, NULL);
5625
5626   if (!init_params
5627       || !gst_structure_get_boolean (init_params, "negotiated", &negotiated))
5628     negotiated = FALSE;
5629   if (!negotiated || !init_params
5630       || !gst_structure_get_int (init_params, "id", &id))
5631     id = -1;
5632   if (negotiated)
5633     g_return_val_if_fail (id != -1, NULL);
5634   g_return_val_if_fail (id < 65535, NULL);
5635
5636   if (!init_params
5637       || !gst_structure_get_enum (init_params, "priority",
5638           GST_TYPE_WEBRTC_PRIORITY_TYPE, (gint *) & priority))
5639     priority = GST_WEBRTC_PRIORITY_TYPE_LOW;
5640
5641   /* FIXME: clamp max-retransmits and max-packet-lifetime */
5642
5643   if (webrtc->priv->sctp_transport) {
5644     /* Let transport be the connection's [[SctpTransport]] slot.
5645      *
5646      * If the [[DataChannelId]] slot is not null, transport is in 
5647      * connected state and [[DataChannelId]] is greater or equal to the
5648      * transport's [[MaxChannels]] slot, throw an OperationError.
5649      */
5650     g_object_get (webrtc->priv->sctp_transport, "max-channels", &max_channels,
5651         NULL);
5652
5653     g_return_val_if_fail (id <= max_channels, NULL);
5654   }
5655
5656   if (!_have_nice_elements (webrtc) || !_have_dtls_elements (webrtc) ||
5657       !_have_sctp_elements (webrtc))
5658     return NULL;
5659
5660   PC_LOCK (webrtc);
5661   /* check if the id has been used already */
5662   if (id != -1) {
5663     WebRTCDataChannel *channel = _find_data_channel_for_id (webrtc, id);
5664     if (channel) {
5665       GST_ELEMENT_WARNING (webrtc, LIBRARY, SETTINGS,
5666           ("Attempting to add a data channel with a duplicate ID: %i", id),
5667           NULL);
5668       PC_UNLOCK (webrtc);
5669       return NULL;
5670     }
5671   } else if (webrtc->current_local_description
5672       && webrtc->current_remote_description && webrtc->priv->sctp_transport
5673       && webrtc->priv->sctp_transport->transport) {
5674     /* else we can only generate an id if we're configured already.  The other
5675      * case for generating an id is on sdp setting */
5676     id = _generate_data_channel_id (webrtc);
5677     if (id == -1) {
5678       GST_ELEMENT_WARNING (webrtc, RESOURCE, NOT_FOUND,
5679           ("%s", "Failed to generate an identifier for a data channel"), NULL);
5680       PC_UNLOCK (webrtc);
5681       return NULL;
5682     }
5683   }
5684
5685   ret = g_object_new (WEBRTC_TYPE_DATA_CHANNEL, "label", label,
5686       "ordered", ordered, "max-packet-lifetime", max_packet_lifetime,
5687       "max-retransmits", max_retransmits, "protocol", protocol,
5688       "negotiated", negotiated, "id", id, "priority", priority, NULL);
5689
5690   if (ret) {
5691     gst_bin_add (GST_BIN (webrtc), ret->appsrc);
5692     gst_bin_add (GST_BIN (webrtc), ret->appsink);
5693
5694     gst_element_sync_state_with_parent (ret->appsrc);
5695     gst_element_sync_state_with_parent (ret->appsink);
5696
5697     ret = gst_object_ref (ret);
5698     ret->webrtcbin = webrtc;
5699     g_ptr_array_add (webrtc->priv->data_channels, ret);
5700     gst_webrtc_bin_update_sctp_priority (webrtc);
5701     webrtc_data_channel_link_to_sctp (ret, webrtc->priv->sctp_transport);
5702     if (webrtc->priv->sctp_transport &&
5703         webrtc->priv->sctp_transport->association_established
5704         && !ret->parent.negotiated) {
5705       webrtc_data_channel_start_negotiation (ret);
5706     } else {
5707       _update_need_negotiation (webrtc);
5708     }
5709   }
5710
5711   PC_UNLOCK (webrtc);
5712   return ret;
5713 }
5714
5715 /* === rtpbin signal implementations === */
5716
5717 static void
5718 on_rtpbin_pad_added (GstElement * rtpbin, GstPad * new_pad,
5719     GstWebRTCBin * webrtc)
5720 {
5721   gchar *new_pad_name = NULL;
5722
5723   new_pad_name = gst_pad_get_name (new_pad);
5724   GST_TRACE_OBJECT (webrtc, "new rtpbin pad %s", new_pad_name);
5725   if (g_str_has_prefix (new_pad_name, "recv_rtp_src_")) {
5726     guint32 session_id = 0, ssrc = 0, pt = 0;
5727     GstWebRTCRTPTransceiver *rtp_trans;
5728     WebRTCTransceiver *trans;
5729     TransportStream *stream;
5730     GstWebRTCBinPad *pad;
5731     guint media_idx = 0;
5732     gboolean found_ssrc = FALSE;
5733     guint i;
5734
5735     if (sscanf (new_pad_name, "recv_rtp_src_%u_%u_%u", &session_id, &ssrc,
5736             &pt) != 3) {
5737       g_critical ("Invalid rtpbin pad name \'%s\'", new_pad_name);
5738       return;
5739     }
5740
5741     stream = _find_transport_for_session (webrtc, session_id);
5742     if (!stream)
5743       g_warn_if_reached ();
5744
5745     media_idx = session_id;
5746
5747     for (i = 0; i < stream->remote_ssrcmap->len; i++) {
5748       SsrcMapItem *item = g_ptr_array_index (stream->remote_ssrcmap, i);
5749       if (item->ssrc == ssrc) {
5750         media_idx = item->media_idx;
5751         found_ssrc = TRUE;
5752         break;
5753       }
5754     }
5755
5756     if (!found_ssrc) {
5757       GST_WARNING_OBJECT (webrtc, "Could not find ssrc %u", ssrc);
5758     }
5759
5760     rtp_trans = _find_transceiver_for_mline (webrtc, media_idx);
5761     if (!rtp_trans)
5762       g_warn_if_reached ();
5763     trans = WEBRTC_TRANSCEIVER (rtp_trans);
5764     g_assert (trans->stream == stream);
5765
5766     pad = _find_pad_for_transceiver (webrtc, GST_PAD_SRC, rtp_trans);
5767
5768     GST_TRACE_OBJECT (webrtc, "found pad %" GST_PTR_FORMAT
5769         " for rtpbin pad name %s", pad, new_pad_name);
5770     if (!pad)
5771       g_warn_if_reached ();
5772     gst_ghost_pad_set_target (GST_GHOST_PAD (pad), GST_PAD (new_pad));
5773
5774     if (webrtc->priv->running)
5775       gst_pad_set_active (GST_PAD (pad), TRUE);
5776     gst_pad_sticky_events_foreach (new_pad, copy_sticky_events, pad);
5777     gst_element_add_pad (GST_ELEMENT (webrtc), GST_PAD (pad));
5778     _remove_pending_pad (webrtc, pad);
5779
5780     gst_object_unref (pad);
5781   }
5782   g_free (new_pad_name);
5783 }
5784
5785 /* only used for the receiving streams */
5786 static GstCaps *
5787 on_rtpbin_request_pt_map (GstElement * rtpbin, guint session_id, guint pt,
5788     GstWebRTCBin * webrtc)
5789 {
5790   TransportStream *stream;
5791   GstCaps *ret;
5792
5793   GST_DEBUG_OBJECT (webrtc, "getting pt map for pt %d in session %d", pt,
5794       session_id);
5795
5796   stream = _find_transport_for_session (webrtc, session_id);
5797   if (!stream)
5798     goto unknown_session;
5799
5800   if ((ret = transport_stream_get_caps_for_pt (stream, pt)))
5801     gst_caps_ref (ret);
5802
5803   GST_TRACE_OBJECT (webrtc, "Found caps %" GST_PTR_FORMAT " for pt %d in "
5804       "session %d", ret, pt, session_id);
5805
5806   return ret;
5807
5808 unknown_session:
5809   {
5810     GST_DEBUG_OBJECT (webrtc, "unknown session %d", session_id);
5811     return NULL;
5812   }
5813 }
5814
5815 static gboolean
5816 _merge_structure (GQuark field_id, const GValue * value, gpointer user_data)
5817 {
5818   GstStructure *s = user_data;
5819
5820   gst_structure_id_set_value (s, field_id, value);
5821
5822   return TRUE;
5823 }
5824
5825 static GstElement *
5826 on_rtpbin_request_aux_sender (GstElement * rtpbin, guint session_id,
5827     GstWebRTCBin * webrtc)
5828 {
5829   TransportStream *stream;
5830   gboolean have_rtx = FALSE;
5831   GstStructure *pt_map = NULL;
5832   GstElement *ret = NULL;
5833
5834   stream = _find_transport_for_session (webrtc, session_id);
5835
5836   if (stream)
5837     have_rtx = transport_stream_get_pt (stream, "RTX") != 0;
5838
5839   GST_LOG_OBJECT (webrtc, "requesting aux sender for stream %" GST_PTR_FORMAT
5840       " with pt map %" GST_PTR_FORMAT, stream, pt_map);
5841
5842   if (have_rtx) {
5843     GstElement *rtx;
5844     GstPad *pad;
5845     gchar *name;
5846     GstStructure *merged_local_rtx_ssrc_map =
5847         gst_structure_new_empty ("application/x-rtp-ssrc-map");
5848     guint i;
5849
5850     if (stream->rtxsend) {
5851       GST_WARNING_OBJECT (webrtc, "rtprtxsend already created! rtpbin bug?!");
5852       goto out;
5853     }
5854
5855     GST_INFO ("creating AUX sender");
5856     ret = gst_bin_new (NULL);
5857     rtx = gst_element_factory_make ("rtprtxsend", NULL);
5858     g_object_set (rtx, "max-size-packets", 500, NULL);
5859     _set_rtx_ptmap_from_stream (webrtc, stream);
5860
5861     for (i = 0; i < webrtc->priv->transceivers->len; i++) {
5862       WebRTCTransceiver *trans =
5863           WEBRTC_TRANSCEIVER (g_ptr_array_index (webrtc->priv->transceivers,
5864               i));
5865
5866       if (trans->stream == stream && trans->local_rtx_ssrc_map)
5867         gst_structure_foreach (trans->local_rtx_ssrc_map,
5868             _merge_structure, merged_local_rtx_ssrc_map);
5869     }
5870
5871     g_object_set (rtx, "ssrc-map", merged_local_rtx_ssrc_map, NULL);
5872     gst_structure_free (merged_local_rtx_ssrc_map);
5873
5874     gst_bin_add (GST_BIN (ret), rtx);
5875
5876     pad = gst_element_get_static_pad (rtx, "src");
5877     name = g_strdup_printf ("src_%u", session_id);
5878     gst_element_add_pad (ret, gst_ghost_pad_new (name, pad));
5879     g_free (name);
5880     gst_object_unref (pad);
5881
5882     pad = gst_element_get_static_pad (rtx, "sink");
5883     name = g_strdup_printf ("sink_%u", session_id);
5884     gst_element_add_pad (ret, gst_ghost_pad_new (name, pad));
5885     g_free (name);
5886     gst_object_unref (pad);
5887
5888     stream->rtxsend = gst_object_ref (rtx);
5889   }
5890
5891 out:
5892   if (pt_map)
5893     gst_structure_free (pt_map);
5894
5895   return ret;
5896 }
5897
5898 static GstElement *
5899 on_rtpbin_request_aux_receiver (GstElement * rtpbin, guint session_id,
5900     GstWebRTCBin * webrtc)
5901 {
5902   GstElement *ret = NULL;
5903   GstElement *prev = NULL;
5904   GstPad *sinkpad = NULL;
5905   TransportStream *stream;
5906   gint red_pt = 0;
5907   gint rtx_pt = 0;
5908
5909   stream = _find_transport_for_session (webrtc, session_id);
5910
5911   if (stream) {
5912     red_pt = transport_stream_get_pt (stream, "RED");
5913     rtx_pt = transport_stream_get_pt (stream, "RTX");
5914   }
5915
5916   GST_LOG_OBJECT (webrtc, "requesting aux receiver for stream %" GST_PTR_FORMAT,
5917       stream);
5918
5919   if (red_pt || rtx_pt)
5920     ret = gst_bin_new (NULL);
5921
5922   if (rtx_pt) {
5923     if (stream->rtxreceive) {
5924       GST_WARNING_OBJECT (webrtc,
5925           "rtprtxreceive already created! rtpbin bug?!");
5926       goto error;
5927     }
5928
5929     stream->rtxreceive = gst_element_factory_make ("rtprtxreceive", NULL);
5930     _set_rtx_ptmap_from_stream (webrtc, stream);
5931
5932     gst_bin_add (GST_BIN (ret), stream->rtxreceive);
5933
5934     sinkpad = gst_element_get_static_pad (stream->rtxreceive, "sink");
5935
5936     prev = gst_object_ref (stream->rtxreceive);
5937   }
5938
5939   if (red_pt) {
5940     GstElement *rtpreddec = gst_element_factory_make ("rtpreddec", NULL);
5941
5942     GST_DEBUG_OBJECT (webrtc, "Creating RED decoder for pt %d in session %u",
5943         red_pt, session_id);
5944
5945     gst_bin_add (GST_BIN (ret), rtpreddec);
5946
5947     g_object_set (rtpreddec, "pt", red_pt, NULL);
5948
5949     if (prev)
5950       gst_element_link (prev, rtpreddec);
5951     else
5952       sinkpad = gst_element_get_static_pad (rtpreddec, "sink");
5953
5954     prev = rtpreddec;
5955   }
5956
5957   if (sinkpad) {
5958     gchar *name = g_strdup_printf ("sink_%u", session_id);
5959     GstPad *ghost = gst_ghost_pad_new (name, sinkpad);
5960     g_free (name);
5961     gst_object_unref (sinkpad);
5962     gst_element_add_pad (ret, ghost);
5963   }
5964
5965   if (prev) {
5966     gchar *name = g_strdup_printf ("src_%u", session_id);
5967     GstPad *srcpad = gst_element_get_static_pad (prev, "src");
5968     GstPad *ghost = gst_ghost_pad_new (name, srcpad);
5969     g_free (name);
5970     gst_object_unref (srcpad);
5971     gst_element_add_pad (ret, ghost);
5972   }
5973
5974 out:
5975   return ret;
5976
5977 error:
5978   if (ret)
5979     gst_object_unref (ret);
5980   goto out;
5981 }
5982
5983 static GstElement *
5984 on_rtpbin_request_fec_decoder (GstElement * rtpbin, guint session_id,
5985     GstWebRTCBin * webrtc)
5986 {
5987   TransportStream *stream;
5988   GstElement *ret = NULL;
5989   gint pt = 0;
5990   GObject *internal_storage;
5991
5992   stream = _find_transport_for_session (webrtc, session_id);
5993
5994   /* TODO: for now, we only support ulpfec, but once we support
5995    * more algorithms, if the remote may use more than one algorithm,
5996    * we will want to do the following:
5997    *
5998    * + Return a bin here, with the relevant FEC decoders plugged in
5999    *   and their payload type set to 0
6000    * + Enable the decoders by setting the payload type only when
6001    *   we detect it (by connecting to ptdemux:new-payload-type for
6002    *   example)
6003    */
6004   if (stream)
6005     pt = transport_stream_get_pt (stream, "ULPFEC");
6006
6007   if (pt) {
6008     GST_DEBUG_OBJECT (webrtc, "Creating ULPFEC decoder for pt %d in session %u",
6009         pt, session_id);
6010     ret = gst_element_factory_make ("rtpulpfecdec", NULL);
6011     g_signal_emit_by_name (webrtc->rtpbin, "get-internal-storage", session_id,
6012         &internal_storage);
6013
6014     g_object_set (ret, "pt", pt, "storage", internal_storage, NULL);
6015     g_object_unref (internal_storage);
6016   }
6017
6018   return ret;
6019 }
6020
6021 static GstElement *
6022 on_rtpbin_request_fec_encoder (GstElement * rtpbin, guint session_id,
6023     GstWebRTCBin * webrtc)
6024 {
6025   GstElement *ret = NULL;
6026   GstElement *prev = NULL;
6027   TransportStream *stream;
6028   guint ulpfec_pt = 0;
6029   guint red_pt = 0;
6030   GstPad *sinkpad = NULL;
6031   GstWebRTCRTPTransceiver *trans;
6032
6033   stream = _find_transport_for_session (webrtc, session_id);
6034   trans = _find_transceiver (webrtc, &session_id,
6035       (FindTransceiverFunc) transceiver_match_for_mline);
6036
6037   if (stream) {
6038     ulpfec_pt = transport_stream_get_pt (stream, "ULPFEC");
6039     red_pt = transport_stream_get_pt (stream, "RED");
6040   }
6041
6042   if (ulpfec_pt || red_pt)
6043     ret = gst_bin_new (NULL);
6044
6045   if (ulpfec_pt) {
6046     GstElement *fecenc = gst_element_factory_make ("rtpulpfecenc", NULL);
6047     GstCaps *caps = transport_stream_get_caps_for_pt (stream, ulpfec_pt);
6048
6049     GST_DEBUG_OBJECT (webrtc,
6050         "Creating ULPFEC encoder for session %d with pt %d", session_id,
6051         ulpfec_pt);
6052
6053     gst_bin_add (GST_BIN (ret), fecenc);
6054     sinkpad = gst_element_get_static_pad (fecenc, "sink");
6055     g_object_set (fecenc, "pt", ulpfec_pt, "percentage",
6056         WEBRTC_TRANSCEIVER (trans)->fec_percentage, NULL);
6057
6058
6059     if (caps && !gst_caps_is_empty (caps)) {
6060       const GstStructure *s = gst_caps_get_structure (caps, 0);
6061       const gchar *media = gst_structure_get_string (s, "media");
6062
6063       if (!g_strcmp0 (media, "video"))
6064         g_object_set (fecenc, "multipacket", TRUE, NULL);
6065     }
6066
6067     prev = fecenc;
6068   }
6069
6070   if (red_pt) {
6071     GstElement *redenc = gst_element_factory_make ("rtpredenc", NULL);
6072
6073     GST_DEBUG_OBJECT (webrtc, "Creating RED encoder for session %d with pt %d",
6074         session_id, red_pt);
6075
6076     gst_bin_add (GST_BIN (ret), redenc);
6077     if (prev)
6078       gst_element_link (prev, redenc);
6079     else
6080       sinkpad = gst_element_get_static_pad (redenc, "sink");
6081
6082     g_object_set (redenc, "pt", red_pt, "allow-no-red-blocks", TRUE, NULL);
6083
6084     prev = redenc;
6085   }
6086
6087   if (sinkpad) {
6088     GstPad *ghost = gst_ghost_pad_new ("sink", sinkpad);
6089     gst_object_unref (sinkpad);
6090     gst_element_add_pad (ret, ghost);
6091   }
6092
6093   if (prev) {
6094     GstPad *srcpad = gst_element_get_static_pad (prev, "src");
6095     GstPad *ghost = gst_ghost_pad_new ("src", srcpad);
6096     gst_object_unref (srcpad);
6097     gst_element_add_pad (ret, ghost);
6098   }
6099
6100   return ret;
6101 }
6102
6103 static void
6104 on_rtpbin_bye_ssrc (GstElement * rtpbin, guint session_id, guint ssrc,
6105     GstWebRTCBin * webrtc)
6106 {
6107   GST_INFO_OBJECT (webrtc, "session %u ssrc %u received bye", session_id, ssrc);
6108 }
6109
6110 static void
6111 on_rtpbin_bye_timeout (GstElement * rtpbin, guint session_id, guint ssrc,
6112     GstWebRTCBin * webrtc)
6113 {
6114   GST_INFO_OBJECT (webrtc, "session %u ssrc %u bye timeout", session_id, ssrc);
6115 }
6116
6117 static void
6118 on_rtpbin_sender_timeout (GstElement * rtpbin, guint session_id, guint ssrc,
6119     GstWebRTCBin * webrtc)
6120 {
6121   GST_INFO_OBJECT (webrtc, "session %u ssrc %u sender timeout", session_id,
6122       ssrc);
6123 }
6124
6125 static void
6126 on_rtpbin_new_ssrc (GstElement * rtpbin, guint session_id, guint ssrc,
6127     GstWebRTCBin * webrtc)
6128 {
6129   GST_INFO_OBJECT (webrtc, "session %u ssrc %u new ssrc", session_id, ssrc);
6130 }
6131
6132 static void
6133 on_rtpbin_ssrc_active (GstElement * rtpbin, guint session_id, guint ssrc,
6134     GstWebRTCBin * webrtc)
6135 {
6136   GST_INFO_OBJECT (webrtc, "session %u ssrc %u active", session_id, ssrc);
6137 }
6138
6139 static void
6140 on_rtpbin_ssrc_collision (GstElement * rtpbin, guint session_id, guint ssrc,
6141     GstWebRTCBin * webrtc)
6142 {
6143   GST_INFO_OBJECT (webrtc, "session %u ssrc %u collision", session_id, ssrc);
6144 }
6145
6146 static void
6147 on_rtpbin_ssrc_sdes (GstElement * rtpbin, guint session_id, guint ssrc,
6148     GstWebRTCBin * webrtc)
6149 {
6150   GST_INFO_OBJECT (webrtc, "session %u ssrc %u sdes", session_id, ssrc);
6151 }
6152
6153 static void
6154 on_rtpbin_ssrc_validated (GstElement * rtpbin, guint session_id, guint ssrc,
6155     GstWebRTCBin * webrtc)
6156 {
6157   GST_INFO_OBJECT (webrtc, "session %u ssrc %u validated", session_id, ssrc);
6158 }
6159
6160 static void
6161 on_rtpbin_timeout (GstElement * rtpbin, guint session_id, guint ssrc,
6162     GstWebRTCBin * webrtc)
6163 {
6164   GST_INFO_OBJECT (webrtc, "session %u ssrc %u timeout", session_id, ssrc);
6165 }
6166
6167 static void
6168 on_rtpbin_new_sender_ssrc (GstElement * rtpbin, guint session_id, guint ssrc,
6169     GstWebRTCBin * webrtc)
6170 {
6171   GST_INFO_OBJECT (webrtc, "session %u ssrc %u new sender ssrc", session_id,
6172       ssrc);
6173 }
6174
6175 static void
6176 on_rtpbin_sender_ssrc_active (GstElement * rtpbin, guint session_id, guint ssrc,
6177     GstWebRTCBin * webrtc)
6178 {
6179   GST_INFO_OBJECT (webrtc, "session %u ssrc %u sender ssrc active", session_id,
6180       ssrc);
6181 }
6182
6183 static void
6184 on_rtpbin_new_jitterbuffer (GstElement * rtpbin, GstElement * jitterbuffer,
6185     guint session_id, guint ssrc, GstWebRTCBin * webrtc)
6186 {
6187   WebRTCTransceiver *trans;
6188   guint i;
6189
6190   trans = (WebRTCTransceiver *) _find_transceiver (webrtc, &session_id,
6191       (FindTransceiverFunc) transceiver_match_for_mline);
6192
6193   if (trans) {
6194     /* We don't set do-retransmission on rtpbin as we want per-session control */
6195     g_object_set (jitterbuffer, "do-retransmission",
6196         WEBRTC_TRANSCEIVER (trans)->do_nack, NULL);
6197
6198     for (i = 0; i < trans->stream->remote_ssrcmap->len; i++) {
6199       SsrcMapItem *item = g_ptr_array_index (trans->stream->remote_ssrcmap, i);
6200
6201       if (item->ssrc == ssrc) {
6202         g_weak_ref_set (&item->rtpjitterbuffer, jitterbuffer);
6203         break;
6204       }
6205     }
6206   } else {
6207     g_assert_not_reached ();
6208   }
6209 }
6210
6211 static void
6212 on_rtpbin_new_storage (GstElement * rtpbin, GstElement * storage,
6213     guint session_id, GstWebRTCBin * webrtc)
6214 {
6215   guint64 latency = webrtc->priv->jb_latency;
6216
6217   /* Add an extra 50 ms for safey */
6218   latency += RTPSTORAGE_EXTRA_TIME;
6219   latency *= GST_MSECOND;
6220
6221   g_object_set (storage, "size-time", latency, NULL);
6222 }
6223
6224 static GstElement *
6225 _create_rtpbin (GstWebRTCBin * webrtc)
6226 {
6227   GstElement *rtpbin;
6228
6229   if (!(rtpbin = gst_element_factory_make ("rtpbin", "rtpbin")))
6230     return NULL;
6231
6232   /* mandated by WebRTC */
6233   gst_util_set_object_arg (G_OBJECT (rtpbin), "rtp-profile", "savpf");
6234
6235   g_object_set (rtpbin, "do-lost", TRUE, NULL);
6236
6237   g_signal_connect (rtpbin, "pad-added", G_CALLBACK (on_rtpbin_pad_added),
6238       webrtc);
6239   g_signal_connect (rtpbin, "request-pt-map",
6240       G_CALLBACK (on_rtpbin_request_pt_map), webrtc);
6241   g_signal_connect (rtpbin, "request-aux-sender",
6242       G_CALLBACK (on_rtpbin_request_aux_sender), webrtc);
6243   g_signal_connect (rtpbin, "request-aux-receiver",
6244       G_CALLBACK (on_rtpbin_request_aux_receiver), webrtc);
6245   g_signal_connect (rtpbin, "new-storage",
6246       G_CALLBACK (on_rtpbin_new_storage), webrtc);
6247   g_signal_connect (rtpbin, "request-fec-decoder",
6248       G_CALLBACK (on_rtpbin_request_fec_decoder), webrtc);
6249   g_signal_connect (rtpbin, "request-fec-encoder",
6250       G_CALLBACK (on_rtpbin_request_fec_encoder), webrtc);
6251   g_signal_connect (rtpbin, "on-bye-ssrc",
6252       G_CALLBACK (on_rtpbin_bye_ssrc), webrtc);
6253   g_signal_connect (rtpbin, "on-bye-timeout",
6254       G_CALLBACK (on_rtpbin_bye_timeout), webrtc);
6255   g_signal_connect (rtpbin, "on-new-ssrc",
6256       G_CALLBACK (on_rtpbin_new_ssrc), webrtc);
6257   g_signal_connect (rtpbin, "on-new-sender-ssrc",
6258       G_CALLBACK (on_rtpbin_new_sender_ssrc), webrtc);
6259   g_signal_connect (rtpbin, "on-sender-ssrc-active",
6260       G_CALLBACK (on_rtpbin_sender_ssrc_active), webrtc);
6261   g_signal_connect (rtpbin, "on-sender-timeout",
6262       G_CALLBACK (on_rtpbin_sender_timeout), webrtc);
6263   g_signal_connect (rtpbin, "on-ssrc-active",
6264       G_CALLBACK (on_rtpbin_ssrc_active), webrtc);
6265   g_signal_connect (rtpbin, "on-ssrc-collision",
6266       G_CALLBACK (on_rtpbin_ssrc_collision), webrtc);
6267   g_signal_connect (rtpbin, "on-ssrc-sdes",
6268       G_CALLBACK (on_rtpbin_ssrc_sdes), webrtc);
6269   g_signal_connect (rtpbin, "on-ssrc-validated",
6270       G_CALLBACK (on_rtpbin_ssrc_validated), webrtc);
6271   g_signal_connect (rtpbin, "on-timeout",
6272       G_CALLBACK (on_rtpbin_timeout), webrtc);
6273   g_signal_connect (rtpbin, "new-jitterbuffer",
6274       G_CALLBACK (on_rtpbin_new_jitterbuffer), webrtc);
6275
6276   return rtpbin;
6277 }
6278
6279 static GstStateChangeReturn
6280 gst_webrtc_bin_change_state (GstElement * element, GstStateChange transition)
6281 {
6282   GstWebRTCBin *webrtc = GST_WEBRTC_BIN (element);
6283   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
6284
6285   GST_DEBUG ("changing state: %s => %s",
6286       gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
6287       gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
6288
6289   switch (transition) {
6290     case GST_STATE_CHANGE_NULL_TO_READY:{
6291       if (!_have_nice_elements (webrtc) || !_have_dtls_elements (webrtc))
6292         return GST_STATE_CHANGE_FAILURE;
6293       _start_thread (webrtc);
6294       PC_LOCK (webrtc);
6295       _update_need_negotiation (webrtc);
6296       PC_UNLOCK (webrtc);
6297       break;
6298     }
6299     case GST_STATE_CHANGE_READY_TO_PAUSED:
6300       webrtc->priv->running = TRUE;
6301       break;
6302     default:
6303       break;
6304   }
6305
6306   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
6307   if (ret == GST_STATE_CHANGE_FAILURE)
6308     return ret;
6309
6310   switch (transition) {
6311     case GST_STATE_CHANGE_READY_TO_PAUSED:
6312       /* Mangle the return value to NO_PREROLL as that's what really is
6313        * occurring here however cannot be propagated correctly due to nicesrc
6314        * requiring that it be in PLAYING already in order to send/receive
6315        * correctly :/ */
6316       ret = GST_STATE_CHANGE_NO_PREROLL;
6317       break;
6318     case GST_STATE_CHANGE_PAUSED_TO_READY:
6319       webrtc->priv->running = FALSE;
6320       break;
6321     case GST_STATE_CHANGE_READY_TO_NULL:
6322       _stop_thread (webrtc);
6323       break;
6324     default:
6325       break;
6326   }
6327
6328   return ret;
6329 }
6330
6331 static GstPadProbeReturn
6332 sink_pad_block (GstPad * pad, GstPadProbeInfo * info, gpointer unused)
6333 {
6334   GST_LOG_OBJECT (pad, "blocking pad with data %" GST_PTR_FORMAT, info->data);
6335
6336   return GST_PAD_PROBE_OK;
6337 }
6338
6339
6340 static GstPad *
6341 gst_webrtc_bin_request_new_pad (GstElement * element, GstPadTemplate * templ,
6342     const gchar * name, const GstCaps * caps)
6343 {
6344   GstWebRTCBin *webrtc = GST_WEBRTC_BIN (element);
6345   GstWebRTCRTPTransceiver *trans = NULL;
6346   GstWebRTCBinPad *pad = NULL;
6347   guint serial;
6348   gboolean lock_mline = FALSE;
6349
6350   if (!_have_nice_elements (webrtc) || !_have_dtls_elements (webrtc))
6351     return NULL;
6352
6353   if (templ->direction != GST_PAD_SINK ||
6354       g_strcmp0 (templ->name_template, "sink_%u") != 0) {
6355     GST_ERROR_OBJECT (element, "Requested pad that shouldn't be requestable");
6356     return NULL;
6357   }
6358
6359   PC_LOCK (webrtc);
6360
6361   if (name == NULL || strlen (name) < 6 || !g_str_has_prefix (name, "sink_")) {
6362     /* no name given when requesting the pad, use next available int */
6363     serial = webrtc->priv->max_sink_pad_serial++;
6364   } else {
6365     /* parse serial number from requested padname */
6366     serial = g_ascii_strtoull (&name[5], NULL, 10);
6367     lock_mline = TRUE;
6368   }
6369
6370   if (lock_mline) {
6371     GstWebRTCBinPad *pad2;
6372
6373     trans = _find_transceiver_for_mline (webrtc, serial);
6374
6375     if (trans) {
6376       /* Reject transceivers that are only for receiving ... */
6377       if (trans->direction == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY ||
6378           trans->direction == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_INACTIVE) {
6379         gchar *direction =
6380             g_enum_to_string (GST_TYPE_WEBRTC_RTP_TRANSCEIVER_DIRECTION,
6381             trans->direction);
6382         GST_ERROR_OBJECT (element, "Tried to request a new sink pad %s for"
6383             " existing m-line %d, but the transceiver's direction is %s",
6384             name, serial, direction);
6385         g_free (direction);
6386         goto error_out;
6387       }
6388
6389       /* Reject transceivers that already have a pad allocated */
6390       pad2 = _find_pad_for_transceiver (webrtc, GST_PAD_SINK, trans);
6391       if (pad2) {
6392         GST_ERROR_OBJECT (element, "Trying to request pad %s for m-line %d, "
6393             " but the transceiver associated with this m-line already has pad"
6394             " %s", name, serial, GST_PAD_NAME (pad2));
6395         gst_object_unref (pad2);
6396         goto error_out;
6397       }
6398
6399       if (caps) {
6400         if (trans->codec_preferences &&
6401             !gst_caps_can_intersect (caps, trans->codec_preferences)) {
6402           GST_ERROR_OBJECT (element, "Tried to request a new sink pad %s for"
6403               " existing m-line %d, but requested caps %" GST_PTR_FORMAT
6404               " don't match existing codec preferences %" GST_PTR_FORMAT,
6405               name, serial, caps, trans->codec_preferences);
6406           goto error_out;
6407         }
6408
6409         if (trans->kind != GST_WEBRTC_KIND_UNKNOWN) {
6410           GstWebRTCKind kind = _kind_from_caps (caps);
6411
6412           if (trans->kind != kind) {
6413             GST_ERROR_OBJECT (element, "Tried to request a new sink pad %s for"
6414                 " existing m-line %d, but requested caps %" GST_PTR_FORMAT
6415                 " don't match transceiver kind %d",
6416                 name, serial, caps, trans->kind);
6417             goto error_out;
6418           }
6419         }
6420       }
6421     }
6422   }
6423
6424   /* Let's try to find a free transceiver that matches */
6425   if (!trans) {
6426     GstWebRTCKind kind = GST_WEBRTC_KIND_UNKNOWN;
6427     guint i;
6428
6429     if (caps)
6430       kind = _kind_from_caps (caps);
6431
6432     for (i = 0; i < webrtc->priv->transceivers->len; i++) {
6433       GstWebRTCRTPTransceiver *tmptrans =
6434           g_ptr_array_index (webrtc->priv->transceivers, i);
6435       GstWebRTCBinPad *pad2;
6436
6437       /* Ignore transceivers with a non-matching kind */
6438       if (tmptrans->kind != GST_WEBRTC_KIND_UNKNOWN &&
6439           kind != GST_WEBRTC_KIND_UNKNOWN && tmptrans->kind != kind)
6440         continue;
6441
6442       /* Ignore stopped transmitters */
6443       if (tmptrans->stopped)
6444         continue;
6445
6446       /* Ignore transceivers that are only for receiving ... */
6447       if (tmptrans->direction == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY
6448           || tmptrans->direction ==
6449           GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_INACTIVE)
6450         continue;
6451
6452       /* Ignore transceivers that already have a pad allocated */
6453       pad2 = _find_pad_for_transceiver (webrtc, GST_PAD_SINK, tmptrans);
6454       if (pad2) {
6455         gst_object_unref (pad2);
6456         continue;
6457       }
6458
6459       /* Ignore transceivers with non-matching caps */
6460       if (caps && tmptrans->codec_preferences &&
6461           !gst_caps_can_intersect (caps, tmptrans->codec_preferences)) {
6462         continue;
6463       }
6464
6465       trans = tmptrans;
6466       break;
6467     }
6468   }
6469
6470   if (!trans) {
6471     trans = GST_WEBRTC_RTP_TRANSCEIVER (_create_webrtc_transceiver (webrtc,
6472             GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV, -1));
6473     GST_LOG_OBJECT (webrtc, "Created new transceiver %" GST_PTR_FORMAT, trans);
6474   } else {
6475     GST_LOG_OBJECT (webrtc, "Using existing transceiver %" GST_PTR_FORMAT
6476         " for mline %u", trans, serial);
6477   }
6478   pad = _create_pad_for_sdp_media (webrtc, GST_PAD_SINK, trans, serial);
6479
6480   if (caps)
6481     _update_transceiver_kind_from_caps (trans, caps);
6482
6483   pad->block_id = gst_pad_add_probe (GST_PAD (pad), GST_PAD_PROBE_TYPE_BLOCK |
6484       GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST,
6485       (GstPadProbeCallback) sink_pad_block, NULL, NULL);
6486   webrtc->priv->pending_sink_transceivers =
6487       g_list_append (webrtc->priv->pending_sink_transceivers,
6488       gst_object_ref (pad));
6489
6490   if (lock_mline) {
6491     WebRTCTransceiver *wtrans = WEBRTC_TRANSCEIVER (trans);
6492     wtrans->mline_locked = TRUE;
6493     trans->mline = serial;
6494   }
6495
6496   PC_UNLOCK (webrtc);
6497
6498   _add_pad (webrtc, pad);
6499
6500   return GST_PAD (pad);
6501
6502 error_out:
6503   PC_UNLOCK (webrtc);
6504   return NULL;
6505 }
6506
6507 static void
6508 gst_webrtc_bin_release_pad (GstElement * element, GstPad * pad)
6509 {
6510   GstWebRTCBin *webrtc = GST_WEBRTC_BIN (element);
6511   GstWebRTCBinPad *webrtc_pad = GST_WEBRTC_BIN_PAD (pad);
6512
6513   GST_DEBUG_OBJECT (webrtc, "Releasing %" GST_PTR_FORMAT, webrtc_pad);
6514
6515   /* remove the transceiver from the pad so that subsequent code doesn't use
6516    * a possibly dead transceiver */
6517   PC_LOCK (webrtc);
6518   if (webrtc_pad->trans)
6519     gst_object_unref (webrtc_pad->trans);
6520   webrtc_pad->trans = NULL;
6521   gst_caps_replace (&webrtc_pad->received_caps, NULL);
6522   PC_UNLOCK (webrtc);
6523
6524   _remove_pad (webrtc, webrtc_pad);
6525
6526   PC_LOCK (webrtc);
6527   _update_need_negotiation (webrtc);
6528   PC_UNLOCK (webrtc);
6529 }
6530
6531 static void
6532 _update_rtpstorage_latency (GstWebRTCBin * webrtc)
6533 {
6534   guint i;
6535   guint64 latency_ns;
6536
6537   /* Add an extra 50 ms for safety */
6538   latency_ns = webrtc->priv->jb_latency + RTPSTORAGE_EXTRA_TIME;
6539   latency_ns *= GST_MSECOND;
6540
6541   for (i = 0; i < webrtc->priv->transports->len; i++) {
6542     TransportStream *stream = g_ptr_array_index (webrtc->priv->transports, i);
6543     GObject *storage = NULL;
6544
6545     g_signal_emit_by_name (webrtc->rtpbin, "get-storage", stream->session_id,
6546         &storage);
6547
6548     g_object_set (storage, "size-time", latency_ns, NULL);
6549
6550     g_object_unref (storage);
6551   }
6552 }
6553
6554 static void
6555 gst_webrtc_bin_set_property (GObject * object, guint prop_id,
6556     const GValue * value, GParamSpec * pspec)
6557 {
6558   GstWebRTCBin *webrtc = GST_WEBRTC_BIN (object);
6559
6560   switch (prop_id) {
6561     case PROP_STUN_SERVER:
6562       gst_webrtc_ice_set_stun_server (webrtc->priv->ice,
6563           g_value_get_string (value));
6564       break;
6565     case PROP_TURN_SERVER:
6566       gst_webrtc_ice_set_turn_server (webrtc->priv->ice,
6567           g_value_get_string (value));
6568       break;
6569     case PROP_BUNDLE_POLICY:
6570       if (g_value_get_enum (value) == GST_WEBRTC_BUNDLE_POLICY_BALANCED) {
6571         GST_ERROR_OBJECT (object, "Balanced bundle policy not implemented yet");
6572       } else {
6573         webrtc->bundle_policy = g_value_get_enum (value);
6574       }
6575       break;
6576     case PROP_ICE_TRANSPORT_POLICY:
6577       webrtc->ice_transport_policy = g_value_get_enum (value);
6578       gst_webrtc_ice_set_force_relay (webrtc->priv->ice,
6579           webrtc->ice_transport_policy ==
6580           GST_WEBRTC_ICE_TRANSPORT_POLICY_RELAY ? TRUE : FALSE);
6581       break;
6582     case PROP_LATENCY:
6583       g_object_set_property (G_OBJECT (webrtc->rtpbin), "latency", value);
6584       webrtc->priv->jb_latency = g_value_get_uint (value);
6585       _update_rtpstorage_latency (webrtc);
6586       break;
6587     default:
6588       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
6589       break;
6590   }
6591 }
6592
6593 static void
6594 gst_webrtc_bin_get_property (GObject * object, guint prop_id,
6595     GValue * value, GParamSpec * pspec)
6596 {
6597   GstWebRTCBin *webrtc = GST_WEBRTC_BIN (object);
6598
6599   PC_LOCK (webrtc);
6600   switch (prop_id) {
6601     case PROP_CONNECTION_STATE:
6602       g_value_set_enum (value, webrtc->peer_connection_state);
6603       break;
6604     case PROP_SIGNALING_STATE:
6605       g_value_set_enum (value, webrtc->signaling_state);
6606       break;
6607     case PROP_ICE_GATHERING_STATE:
6608       g_value_set_enum (value, webrtc->ice_gathering_state);
6609       break;
6610     case PROP_ICE_CONNECTION_STATE:
6611       g_value_set_enum (value, webrtc->ice_connection_state);
6612       break;
6613     case PROP_LOCAL_DESCRIPTION:
6614       if (webrtc->pending_local_description)
6615         g_value_set_boxed (value, webrtc->pending_local_description);
6616       else if (webrtc->current_local_description)
6617         g_value_set_boxed (value, webrtc->current_local_description);
6618       else
6619         g_value_set_boxed (value, NULL);
6620       break;
6621     case PROP_CURRENT_LOCAL_DESCRIPTION:
6622       g_value_set_boxed (value, webrtc->current_local_description);
6623       break;
6624     case PROP_PENDING_LOCAL_DESCRIPTION:
6625       g_value_set_boxed (value, webrtc->pending_local_description);
6626       break;
6627     case PROP_REMOTE_DESCRIPTION:
6628       if (webrtc->pending_remote_description)
6629         g_value_set_boxed (value, webrtc->pending_remote_description);
6630       else if (webrtc->current_remote_description)
6631         g_value_set_boxed (value, webrtc->current_remote_description);
6632       else
6633         g_value_set_boxed (value, NULL);
6634       break;
6635     case PROP_CURRENT_REMOTE_DESCRIPTION:
6636       g_value_set_boxed (value, webrtc->current_remote_description);
6637       break;
6638     case PROP_PENDING_REMOTE_DESCRIPTION:
6639       g_value_set_boxed (value, webrtc->pending_remote_description);
6640       break;
6641     case PROP_STUN_SERVER:
6642       g_value_take_string (value,
6643           gst_webrtc_ice_get_stun_server (webrtc->priv->ice));
6644       break;
6645     case PROP_TURN_SERVER:
6646       g_value_take_string (value,
6647           gst_webrtc_ice_get_turn_server (webrtc->priv->ice));
6648       break;
6649     case PROP_BUNDLE_POLICY:
6650       g_value_set_enum (value, webrtc->bundle_policy);
6651       break;
6652     case PROP_ICE_TRANSPORT_POLICY:
6653       g_value_set_enum (value, webrtc->ice_transport_policy);
6654       break;
6655     case PROP_ICE_AGENT:
6656       g_value_set_object (value, webrtc->priv->ice);
6657       break;
6658     case PROP_LATENCY:
6659       g_value_set_uint (value, webrtc->priv->jb_latency);
6660       break;
6661     default:
6662       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
6663       break;
6664   }
6665   PC_UNLOCK (webrtc);
6666 }
6667
6668 static void
6669 gst_webrtc_bin_constructed (GObject * object)
6670 {
6671   GstWebRTCBin *webrtc = GST_WEBRTC_BIN (object);
6672   gchar *name;
6673
6674   name = g_strdup_printf ("%s:ice", GST_OBJECT_NAME (webrtc));
6675   webrtc->priv->ice = gst_webrtc_ice_new (name);
6676
6677   gst_webrtc_ice_set_on_ice_candidate (webrtc->priv->ice,
6678       (GstWebRTCIceOnCandidateFunc) _on_local_ice_candidate_cb, webrtc, NULL);
6679
6680   g_free (name);
6681 }
6682
6683 static void
6684 _free_pending_pad (GstPad * pad)
6685 {
6686   gst_object_unref (pad);
6687 }
6688
6689 static void
6690 gst_webrtc_bin_dispose (GObject * object)
6691 {
6692   GstWebRTCBin *webrtc = GST_WEBRTC_BIN (object);
6693
6694   if (webrtc->priv->ice)
6695     gst_object_unref (webrtc->priv->ice);
6696   webrtc->priv->ice = NULL;
6697
6698   if (webrtc->priv->ice_stream_map)
6699     g_array_free (webrtc->priv->ice_stream_map, TRUE);
6700   webrtc->priv->ice_stream_map = NULL;
6701
6702   g_clear_object (&webrtc->priv->sctp_transport);
6703
6704   G_OBJECT_CLASS (parent_class)->dispose (object);
6705 }
6706
6707 static void
6708 gst_webrtc_bin_finalize (GObject * object)
6709 {
6710   GstWebRTCBin *webrtc = GST_WEBRTC_BIN (object);
6711
6712   if (webrtc->priv->transports)
6713     g_ptr_array_free (webrtc->priv->transports, TRUE);
6714   webrtc->priv->transports = NULL;
6715
6716   if (webrtc->priv->transceivers)
6717     g_ptr_array_free (webrtc->priv->transceivers, TRUE);
6718   webrtc->priv->transceivers = NULL;
6719
6720   if (webrtc->priv->data_channels)
6721     g_ptr_array_free (webrtc->priv->data_channels, TRUE);
6722   webrtc->priv->data_channels = NULL;
6723
6724   if (webrtc->priv->pending_data_channels)
6725     g_ptr_array_free (webrtc->priv->pending_data_channels, TRUE);
6726   webrtc->priv->pending_data_channels = NULL;
6727
6728   if (webrtc->priv->pending_remote_ice_candidates)
6729     g_array_free (webrtc->priv->pending_remote_ice_candidates, TRUE);
6730   webrtc->priv->pending_remote_ice_candidates = NULL;
6731
6732   if (webrtc->priv->pending_local_ice_candidates)
6733     g_array_free (webrtc->priv->pending_local_ice_candidates, TRUE);
6734   webrtc->priv->pending_local_ice_candidates = NULL;
6735
6736   if (webrtc->priv->pending_pads)
6737     g_list_free_full (webrtc->priv->pending_pads,
6738         (GDestroyNotify) _free_pending_pad);
6739   webrtc->priv->pending_pads = NULL;
6740
6741   if (webrtc->priv->pending_sink_transceivers)
6742     g_list_free_full (webrtc->priv->pending_sink_transceivers,
6743         (GDestroyNotify) gst_object_unref);
6744   webrtc->priv->pending_sink_transceivers = NULL;
6745
6746   if (webrtc->current_local_description)
6747     gst_webrtc_session_description_free (webrtc->current_local_description);
6748   webrtc->current_local_description = NULL;
6749   if (webrtc->pending_local_description)
6750     gst_webrtc_session_description_free (webrtc->pending_local_description);
6751   webrtc->pending_local_description = NULL;
6752
6753   if (webrtc->current_remote_description)
6754     gst_webrtc_session_description_free (webrtc->current_remote_description);
6755   webrtc->current_remote_description = NULL;
6756   if (webrtc->pending_remote_description)
6757     gst_webrtc_session_description_free (webrtc->pending_remote_description);
6758   webrtc->pending_remote_description = NULL;
6759
6760   if (webrtc->priv->last_generated_answer)
6761     gst_webrtc_session_description_free (webrtc->priv->last_generated_answer);
6762   webrtc->priv->last_generated_answer = NULL;
6763   if (webrtc->priv->last_generated_offer)
6764     gst_webrtc_session_description_free (webrtc->priv->last_generated_offer);
6765   webrtc->priv->last_generated_offer = NULL;
6766
6767   g_mutex_clear (ICE_GET_LOCK (webrtc));
6768   g_mutex_clear (PC_GET_LOCK (webrtc));
6769   g_cond_clear (PC_GET_COND (webrtc));
6770
6771   G_OBJECT_CLASS (parent_class)->finalize (object);
6772 }
6773
6774 static void
6775 gst_webrtc_bin_class_init (GstWebRTCBinClass * klass)
6776 {
6777   GObjectClass *gobject_class = (GObjectClass *) klass;
6778   GstElementClass *element_class = (GstElementClass *) klass;
6779
6780   element_class->request_new_pad = gst_webrtc_bin_request_new_pad;
6781   element_class->release_pad = gst_webrtc_bin_release_pad;
6782   element_class->change_state = gst_webrtc_bin_change_state;
6783
6784   gst_element_class_add_static_pad_template_with_gtype (element_class,
6785       &sink_template, GST_TYPE_WEBRTC_BIN_PAD);
6786   gst_element_class_add_static_pad_template (element_class, &src_template);
6787
6788   gst_element_class_set_metadata (element_class, "WebRTC Bin",
6789       "Filter/Network/WebRTC", "A bin for webrtc connections",
6790       "Matthew Waters <matthew@centricular.com>");
6791
6792   gobject_class->constructed = gst_webrtc_bin_constructed;
6793   gobject_class->get_property = gst_webrtc_bin_get_property;
6794   gobject_class->set_property = gst_webrtc_bin_set_property;
6795   gobject_class->dispose = gst_webrtc_bin_dispose;
6796   gobject_class->finalize = gst_webrtc_bin_finalize;
6797
6798   g_object_class_install_property (gobject_class,
6799       PROP_LOCAL_DESCRIPTION,
6800       g_param_spec_boxed ("local-description", "Local Description",
6801           "The local SDP description in use for this connection. "
6802           "Favours a pending description over the current description",
6803           GST_TYPE_WEBRTC_SESSION_DESCRIPTION,
6804           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
6805
6806   g_object_class_install_property (gobject_class,
6807       PROP_CURRENT_LOCAL_DESCRIPTION,
6808       g_param_spec_boxed ("current-local-description",
6809           "Current Local Description",
6810           "The local description that was successfully negotiated the last time "
6811           "the connection transitioned into the stable state",
6812           GST_TYPE_WEBRTC_SESSION_DESCRIPTION,
6813           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
6814
6815   g_object_class_install_property (gobject_class,
6816       PROP_PENDING_LOCAL_DESCRIPTION,
6817       g_param_spec_boxed ("pending-local-description",
6818           "Pending Local Description",
6819           "The local description that is in the process of being negotiated plus "
6820           "any local candidates that have been generated by the ICE Agent since the "
6821           "offer or answer was created",
6822           GST_TYPE_WEBRTC_SESSION_DESCRIPTION,
6823           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
6824
6825   g_object_class_install_property (gobject_class,
6826       PROP_REMOTE_DESCRIPTION,
6827       g_param_spec_boxed ("remote-description", "Remote Description",
6828           "The remote SDP description to use for this connection. "
6829           "Favours a pending description over the current description",
6830           GST_TYPE_WEBRTC_SESSION_DESCRIPTION,
6831           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
6832
6833   g_object_class_install_property (gobject_class,
6834       PROP_CURRENT_REMOTE_DESCRIPTION,
6835       g_param_spec_boxed ("current-remote-description",
6836           "Current Remote Description",
6837           "The last remote description that was successfully negotiated the last "
6838           "time the connection transitioned into the stable state plus any remote "
6839           "candidates that have been supplied via addIceCandidate() since the offer "
6840           "or answer was created",
6841           GST_TYPE_WEBRTC_SESSION_DESCRIPTION,
6842           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
6843
6844   g_object_class_install_property (gobject_class,
6845       PROP_PENDING_REMOTE_DESCRIPTION,
6846       g_param_spec_boxed ("pending-remote-description",
6847           "Pending Remote Description",
6848           "The remote description that is in the process of being negotiated, "
6849           "complete with any remote candidates that have been supplied via "
6850           "addIceCandidate() since the offer or answer was created",
6851           GST_TYPE_WEBRTC_SESSION_DESCRIPTION,
6852           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
6853
6854   g_object_class_install_property (gobject_class,
6855       PROP_STUN_SERVER,
6856       g_param_spec_string ("stun-server", "STUN Server",
6857           "The STUN server of the form stun://hostname:port",
6858           NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6859
6860   g_object_class_install_property (gobject_class,
6861       PROP_TURN_SERVER,
6862       g_param_spec_string ("turn-server", "TURN Server",
6863           "The TURN server of the form turn(s)://username:password@host:port. "
6864           "This is a convenience property, use #GstWebRTCBin::add-turn-server "
6865           "if you wish to use multiple TURN servers",
6866           NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6867
6868   g_object_class_install_property (gobject_class,
6869       PROP_CONNECTION_STATE,
6870       g_param_spec_enum ("connection-state", "Connection State",
6871           "The overall connection state of this element",
6872           GST_TYPE_WEBRTC_PEER_CONNECTION_STATE,
6873           GST_WEBRTC_PEER_CONNECTION_STATE_NEW,
6874           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
6875
6876   g_object_class_install_property (gobject_class,
6877       PROP_SIGNALING_STATE,
6878       g_param_spec_enum ("signaling-state", "Signaling State",
6879           "The signaling state of this element",
6880           GST_TYPE_WEBRTC_SIGNALING_STATE,
6881           GST_WEBRTC_SIGNALING_STATE_STABLE,
6882           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
6883
6884   g_object_class_install_property (gobject_class,
6885       PROP_ICE_CONNECTION_STATE,
6886       g_param_spec_enum ("ice-connection-state", "ICE connection state",
6887           "The collective connection state of all ICETransport's",
6888           GST_TYPE_WEBRTC_ICE_CONNECTION_STATE,
6889           GST_WEBRTC_ICE_CONNECTION_STATE_NEW,
6890           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
6891
6892   g_object_class_install_property (gobject_class,
6893       PROP_ICE_GATHERING_STATE,
6894       g_param_spec_enum ("ice-gathering-state", "ICE gathering state",
6895           "The collective gathering state of all ICETransport's",
6896           GST_TYPE_WEBRTC_ICE_GATHERING_STATE,
6897           GST_WEBRTC_ICE_GATHERING_STATE_NEW,
6898           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
6899
6900   g_object_class_install_property (gobject_class,
6901       PROP_BUNDLE_POLICY,
6902       g_param_spec_enum ("bundle-policy", "Bundle Policy",
6903           "The policy to apply for bundling",
6904           GST_TYPE_WEBRTC_BUNDLE_POLICY,
6905           GST_WEBRTC_BUNDLE_POLICY_NONE,
6906           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6907
6908   g_object_class_install_property (gobject_class,
6909       PROP_ICE_TRANSPORT_POLICY,
6910       g_param_spec_enum ("ice-transport-policy", "ICE Transport Policy",
6911           "The policy to apply for ICE transport",
6912           GST_TYPE_WEBRTC_ICE_TRANSPORT_POLICY,
6913           GST_WEBRTC_ICE_TRANSPORT_POLICY_ALL,
6914           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6915
6916   g_object_class_install_property (gobject_class,
6917       PROP_ICE_AGENT,
6918       g_param_spec_object ("ice-agent", "WebRTC ICE agent",
6919           "The WebRTC ICE agent",
6920           GST_TYPE_WEBRTC_ICE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
6921
6922   /**
6923    * GstWebRTCBin:latency:
6924    *
6925    * Default duration to buffer in the jitterbuffers (in ms)
6926    *
6927    * Since: 1.18
6928    */
6929
6930   g_object_class_install_property (gobject_class,
6931       PROP_LATENCY,
6932       g_param_spec_uint ("latency", "Latency",
6933           "Default duration to buffer in the jitterbuffers (in ms)",
6934           0, G_MAXUINT, 200, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
6935
6936   /**
6937    * GstWebRTCBin::create-offer:
6938    * @object: the #webrtcbin
6939    * @options: (nullable): create-offer options
6940    * @promise: a #GstPromise which will contain the offer
6941    */
6942   gst_webrtc_bin_signals[CREATE_OFFER_SIGNAL] =
6943       g_signal_new_class_handler ("create-offer", G_TYPE_FROM_CLASS (klass),
6944       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
6945       G_CALLBACK (gst_webrtc_bin_create_offer), NULL, NULL, NULL,
6946       G_TYPE_NONE, 2, GST_TYPE_STRUCTURE, GST_TYPE_PROMISE);
6947
6948   /**
6949    * GstWebRTCBin::create-answer:
6950    * @object: the #webrtcbin
6951    * @options: (nullable): create-answer options
6952    * @promise: a #GstPromise which will contain the answer
6953    */
6954   gst_webrtc_bin_signals[CREATE_ANSWER_SIGNAL] =
6955       g_signal_new_class_handler ("create-answer", G_TYPE_FROM_CLASS (klass),
6956       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
6957       G_CALLBACK (gst_webrtc_bin_create_answer), NULL, NULL, NULL,
6958       G_TYPE_NONE, 2, GST_TYPE_STRUCTURE, GST_TYPE_PROMISE);
6959
6960   /**
6961    * GstWebRTCBin::set-local-description:
6962    * @object: the #GstWebRTCBin
6963    * @desc: a #GstWebRTCSessionDescription description
6964    * @promise: (nullable): a #GstPromise to be notified when it's set
6965    */
6966   gst_webrtc_bin_signals[SET_LOCAL_DESCRIPTION_SIGNAL] =
6967       g_signal_new_class_handler ("set-local-description",
6968       G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
6969       G_CALLBACK (gst_webrtc_bin_set_local_description), NULL, NULL, NULL,
6970       G_TYPE_NONE, 2, GST_TYPE_WEBRTC_SESSION_DESCRIPTION, GST_TYPE_PROMISE);
6971
6972   /**
6973    * GstWebRTCBin::set-remote-description:
6974    * @object: the #GstWebRTCBin
6975    * @desc: a #GstWebRTCSessionDescription description
6976    * @promise: (nullable): a #GstPromise to be notified when it's set
6977    */
6978   gst_webrtc_bin_signals[SET_REMOTE_DESCRIPTION_SIGNAL] =
6979       g_signal_new_class_handler ("set-remote-description",
6980       G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
6981       G_CALLBACK (gst_webrtc_bin_set_remote_description), NULL, NULL, NULL,
6982       G_TYPE_NONE, 2, GST_TYPE_WEBRTC_SESSION_DESCRIPTION, GST_TYPE_PROMISE);
6983
6984   /**
6985    * GstWebRTCBin::add-ice-candidate:
6986    * @object: the #webrtcbin
6987    * @mline_index: the index of the media description in the SDP
6988    * @ice-candidate: an ice candidate or NULL/"" to mark that no more candidates
6989    * will arrive
6990    */
6991   gst_webrtc_bin_signals[ADD_ICE_CANDIDATE_SIGNAL] =
6992       g_signal_new_class_handler ("add-ice-candidate",
6993       G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
6994       G_CALLBACK (gst_webrtc_bin_add_ice_candidate), NULL, NULL, NULL,
6995       G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING);
6996
6997   /**
6998    * GstWebRTCBin::get-stats:
6999    * @object: the #webrtcbin
7000    * @pad: (nullable): A #GstPad to get the stats for, or %NULL for all
7001    * @promise: a #GstPromise for the result
7002    *
7003    * The @promise will contain the result of retrieving the session statistics.
7004    * The structure will be named 'application/x-webrtc-stats and contain the
7005    * following based on the webrtc-stats spec available from
7006    * https://www.w3.org/TR/webrtc-stats/.  As the webrtc-stats spec is a draft
7007    * and is constantly changing these statistics may be changed to fit with
7008    * the latest spec.
7009    *
7010    * Each field key is a unique identifier for each RTCStats
7011    * (https://www.w3.org/TR/webrtc/#rtcstats-dictionary) value (another
7012    * GstStructure) in the RTCStatsReport
7013    * (https://www.w3.org/TR/webrtc/#rtcstatsreport-object).  Each supported
7014    * field in the RTCStats subclass is outlined below.
7015    *
7016    * Each statistics structure contains the following values as defined by
7017    * the RTCStats dictionary (https://www.w3.org/TR/webrtc/#rtcstats-dictionary).
7018    *
7019    *  "timestamp"           G_TYPE_DOUBLE               timestamp the statistics were generated
7020    *  "type"                GST_TYPE_WEBRTC_STATS_TYPE  the type of statistics reported
7021    *  "id"                  G_TYPE_STRING               unique identifier
7022    *
7023    * RTCCodecStats supported fields (https://w3c.github.io/webrtc-stats/#codec-dict*)
7024    *
7025    *  "payload-type"        G_TYPE_UINT                 the rtp payload number in use
7026    *  "clock-rate"          G_TYPE_UINT                 the rtp clock-rate
7027    *
7028    * RTCRTPStreamStats supported fields (https://w3c.github.io/webrtc-stats/#streamstats-dict*)
7029    *
7030    *  "ssrc"                G_TYPE_STRING               the rtp sequence src in use
7031    *  "transport-id"        G_TYPE_STRING               identifier for the associated RTCTransportStats for this stream
7032    *  "codec-id"            G_TYPE_STRING               identifier for the associated RTCCodecStats for this stream
7033    *  "fir-count"           G_TYPE_UINT                 FIR requests received by the sender (only for local statistics)
7034    *  "pli-count"           G_TYPE_UINT                 PLI requests received by the sender (only for local statistics)
7035    *  "nack-count"          G_TYPE_UINT                 NACK requests received by the sender (only for local statistics)
7036    *
7037    * RTCReceivedStreamStats supported fields (https://w3c.github.io/webrtc-stats/#receivedrtpstats-dict*)
7038    *
7039    *  "packets-received"     G_TYPE_UINT64              number of packets received (only for local inbound)
7040    *  "bytes-received"       G_TYPE_UINT64              number of bytes received (only for local inbound)
7041    *  "packets-lost"         G_TYPE_UINT                number of packets lost
7042    *  "jitter"               G_TYPE_DOUBLE              packet jitter measured in secondss
7043    *
7044    * RTCInboundRTPStreamStats supported fields (https://w3c.github.io/webrtc-stats/#inboundrtpstats-dict*)
7045    *
7046    *  "remote-id"           G_TYPE_STRING               identifier for the associated RTCRemoteOutboundRTPStreamStats
7047    *
7048    * RTCRemoteInboundRTPStreamStats supported fields (https://w3c.github.io/webrtc-stats/#remoteinboundrtpstats-dict*)
7049    *
7050    *  "local-id"            G_TYPE_STRING               identifier for the associated RTCOutboundRTPSTreamStats
7051    *  "round-trip-time"     G_TYPE_DOUBLE               round trip time of packets measured in seconds
7052    *
7053    * RTCSentRTPStreamStats supported fields (https://w3c.github.io/webrtc-stats/#sentrtpstats-dict*)
7054    *
7055    *  "packets-sent"        G_TYPE_UINT64               number of packets sent (only for local outbound)
7056    *  "bytes-sent"          G_TYPE_UINT64               number of packets sent (only for local outbound)
7057    *
7058    * RTCOutboundRTPStreamStats supported fields (https://w3c.github.io/webrtc-stats/#outboundrtpstats-dict*)
7059    *
7060    *  "remote-id"           G_TYPE_STRING               identifier for the associated RTCRemoteInboundRTPSTreamStats
7061    *
7062    * RTCRemoteOutboundRTPStreamStats supported fields (https://w3c.github.io/webrtc-stats/#remoteoutboundrtpstats-dict*)
7063    *
7064    *  "local-id"            G_TYPE_STRING               identifier for the associated RTCInboundRTPSTreamStats
7065    *
7066    */
7067   gst_webrtc_bin_signals[GET_STATS_SIGNAL] =
7068       g_signal_new_class_handler ("get-stats",
7069       G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
7070       G_CALLBACK (gst_webrtc_bin_get_stats), NULL, NULL, NULL,
7071       G_TYPE_NONE, 2, GST_TYPE_PAD, GST_TYPE_PROMISE);
7072
7073   /**
7074    * GstWebRTCBin::on-negotiation-needed:
7075    * @object: the #webrtcbin
7076    */
7077   gst_webrtc_bin_signals[ON_NEGOTIATION_NEEDED_SIGNAL] =
7078       g_signal_new ("on-negotiation-needed", G_TYPE_FROM_CLASS (klass),
7079       G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
7080
7081   /**
7082    * GstWebRTCBin::on-ice-candidate:
7083    * @object: the #webrtcbin
7084    * @mline_index: the index of the media description in the SDP
7085    * @candidate: the ICE candidate
7086    */
7087   gst_webrtc_bin_signals[ON_ICE_CANDIDATE_SIGNAL] =
7088       g_signal_new ("on-ice-candidate", G_TYPE_FROM_CLASS (klass),
7089       G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
7090       G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING);
7091
7092   /**
7093    * GstWebRTCBin::on-new-transceiver:
7094    * @object: the #webrtcbin
7095    * @candidate: the new #GstWebRTCRTPTransceiver
7096    */
7097   gst_webrtc_bin_signals[ON_NEW_TRANSCEIVER_SIGNAL] =
7098       g_signal_new ("on-new-transceiver", G_TYPE_FROM_CLASS (klass),
7099       G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
7100       G_TYPE_NONE, 1, GST_TYPE_WEBRTC_RTP_TRANSCEIVER);
7101
7102   /**
7103    * GstWebRTCBin::on-data-channel:
7104    * @object: the #GstWebRTCBin
7105    * @candidate: the new `GstWebRTCDataChannel`
7106    */
7107   gst_webrtc_bin_signals[ON_DATA_CHANNEL_SIGNAL] =
7108       g_signal_new ("on-data-channel", G_TYPE_FROM_CLASS (klass),
7109       G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
7110       G_TYPE_NONE, 1, GST_TYPE_WEBRTC_DATA_CHANNEL);
7111
7112   /**
7113    * GstWebRTCBin::add-transceiver:
7114    * @object: the #webrtcbin
7115    * @direction: the direction of the new transceiver
7116    * @caps: (allow none): the codec preferences for this transceiver
7117    *
7118    * Returns: the new #GstWebRTCRTPTransceiver
7119    */
7120   gst_webrtc_bin_signals[ADD_TRANSCEIVER_SIGNAL] =
7121       g_signal_new_class_handler ("add-transceiver", G_TYPE_FROM_CLASS (klass),
7122       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
7123       G_CALLBACK (gst_webrtc_bin_add_transceiver), NULL, NULL,
7124       NULL, GST_TYPE_WEBRTC_RTP_TRANSCEIVER, 2,
7125       GST_TYPE_WEBRTC_RTP_TRANSCEIVER_DIRECTION, GST_TYPE_CAPS);
7126
7127   /**
7128    * GstWebRTCBin::get-transceivers:
7129    * @object: the #webrtcbin
7130    *
7131    * Returns: a #GArray of #GstWebRTCRTPTransceivers
7132    */
7133   gst_webrtc_bin_signals[GET_TRANSCEIVERS_SIGNAL] =
7134       g_signal_new_class_handler ("get-transceivers", G_TYPE_FROM_CLASS (klass),
7135       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
7136       G_CALLBACK (gst_webrtc_bin_get_transceivers), NULL, NULL, NULL,
7137       G_TYPE_ARRAY, 0);
7138
7139   /**
7140    * GstWebRTCBin::get-transceiver:
7141    * @object: the #GstWebRTCBin
7142    * @idx: The index of the transceiver
7143    *
7144    * Returns: (transfer full): the #GstWebRTCRTPTransceiver, or %NULL
7145    * Since: 1.16
7146    */
7147   gst_webrtc_bin_signals[GET_TRANSCEIVER_SIGNAL] =
7148       g_signal_new_class_handler ("get-transceiver", G_TYPE_FROM_CLASS (klass),
7149       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
7150       G_CALLBACK (gst_webrtc_bin_get_transceiver), NULL, NULL, NULL,
7151       GST_TYPE_WEBRTC_RTP_TRANSCEIVER, 1, G_TYPE_INT);
7152
7153   /**
7154    * GstWebRTCBin::add-turn-server:
7155    * @object: the #GstWebRTCBin
7156    * @uri: The uri of the server of the form turn(s)://username:password@host:port
7157    *
7158    * Add a turn server to obtain ICE candidates from
7159    */
7160   gst_webrtc_bin_signals[ADD_TURN_SERVER_SIGNAL] =
7161       g_signal_new_class_handler ("add-turn-server", G_TYPE_FROM_CLASS (klass),
7162       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
7163       G_CALLBACK (gst_webrtc_bin_add_turn_server), NULL, NULL, NULL,
7164       G_TYPE_BOOLEAN, 1, G_TYPE_STRING);
7165
7166   /*
7167    * GstWebRTCBin::create-data-channel:
7168    * @object: the #GstWebRTCBin
7169    * @label: the label for the data channel
7170    * @options: a #GstStructure of options for creating the data channel
7171    *
7172    * The options dictionary is the same format as the RTCDataChannelInit
7173    * members outlined https://www.w3.org/TR/webrtc/#dom-rtcdatachannelinit and
7174    * and reproduced below
7175    *
7176    *  ordered               G_TYPE_BOOLEAN        Whether the channal will send data with guaranteed ordering
7177    *  max-packet-lifetime   G_TYPE_INT            The time in milliseconds to attempt transmitting unacknowledged data. -1 for unset
7178    *  max-retransmits       G_TYPE_INT            The number of times data will be attempted to be transmitted without acknowledgement before dropping
7179    *  protocol              G_TYPE_STRING         The subprotocol used by this channel
7180    *  negotiated            G_TYPE_BOOLEAN        Whether the created data channel should not perform in-band chnanel announcement.  If %TRUE, then application must negotiate the channel itself and create the corresponding channel on the peer with the same id.
7181    *  id                    G_TYPE_INT            Override the default identifier selection of this channel
7182    *  priority              GST_TYPE_WEBRTC_PRIORITY_TYPE   The priority to use for this channel
7183    *
7184    * Returns: (transfer full): a new data channel object
7185    */
7186   gst_webrtc_bin_signals[CREATE_DATA_CHANNEL_SIGNAL] =
7187       g_signal_new_class_handler ("create-data-channel",
7188       G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
7189       G_CALLBACK (gst_webrtc_bin_create_data_channel), NULL, NULL,
7190       NULL, GST_TYPE_WEBRTC_DATA_CHANNEL, 2, G_TYPE_STRING, GST_TYPE_STRUCTURE);
7191
7192   gst_type_mark_as_plugin_api (GST_TYPE_WEBRTC_BIN_PAD, 0);
7193   gst_type_mark_as_plugin_api (GST_TYPE_WEBRTC_ICE, 0);
7194 }
7195
7196 static void
7197 _unparent_and_unref (GObject * object)
7198 {
7199   GstObject *obj = GST_OBJECT (object);
7200
7201   GST_OBJECT_PARENT (obj) = NULL;
7202
7203   gst_object_unref (obj);
7204 }
7205
7206 static void
7207 _transport_free (GObject * object)
7208 {
7209   TransportStream *stream = (TransportStream *) object;
7210   GstWebRTCBin *webrtc;
7211
7212   webrtc = GST_WEBRTC_BIN (GST_OBJECT_PARENT (stream));
7213
7214   if (stream->transport) {
7215     g_signal_handlers_disconnect_by_data (stream->transport->transport, webrtc);
7216     g_signal_handlers_disconnect_by_data (stream->transport, webrtc);
7217   }
7218
7219   gst_object_unref (object);
7220 }
7221
7222 static void
7223 gst_webrtc_bin_init (GstWebRTCBin * webrtc)
7224 {
7225   webrtc->priv = gst_webrtc_bin_get_instance_private (webrtc);
7226   g_mutex_init (PC_GET_LOCK (webrtc));
7227   g_cond_init (PC_GET_COND (webrtc));
7228
7229   g_mutex_init (ICE_GET_LOCK (webrtc));
7230
7231   webrtc->rtpbin = _create_rtpbin (webrtc);
7232   gst_bin_add (GST_BIN (webrtc), webrtc->rtpbin);
7233
7234   webrtc->priv->transceivers =
7235       g_ptr_array_new_with_free_func ((GDestroyNotify) _unparent_and_unref);
7236   webrtc->priv->transports =
7237       g_ptr_array_new_with_free_func ((GDestroyNotify) _transport_free);
7238
7239   webrtc->priv->data_channels =
7240       g_ptr_array_new_with_free_func ((GDestroyNotify) gst_object_unref);
7241
7242   webrtc->priv->pending_data_channels =
7243       g_ptr_array_new_with_free_func ((GDestroyNotify) gst_object_unref);
7244
7245   webrtc->priv->ice_stream_map =
7246       g_array_new (FALSE, TRUE, sizeof (IceStreamItem));
7247   webrtc->priv->pending_remote_ice_candidates =
7248       g_array_new (FALSE, TRUE, sizeof (IceCandidateItem));
7249   g_array_set_clear_func (webrtc->priv->pending_remote_ice_candidates,
7250       (GDestroyNotify) _clear_ice_candidate_item);
7251
7252   webrtc->priv->pending_local_ice_candidates =
7253       g_array_new (FALSE, TRUE, sizeof (IceCandidateItem));
7254   g_array_set_clear_func (webrtc->priv->pending_local_ice_candidates,
7255       (GDestroyNotify) _clear_ice_candidate_item);
7256
7257   /* we start off closed until we move to READY */
7258   webrtc->priv->is_closed = TRUE;
7259 }