diff --git a/ext/webrtc/gstwebrtcbin.c b/ext/webrtc/gstwebrtcbin.c index 77a8e98e7544f2c846d3a436fafde6bd808450fb..142df17192d4e4f9154891a24ca0d4abe2b48bcf 100644 --- a/ext/webrtc/gstwebrtcbin.c +++ b/ext/webrtc/gstwebrtcbin.c @@ -62,7 +62,21 @@ * * On the receiving side, RTPTransceiver's are created in response to setting * a remote description. Output pads for the receiving streams in the set - * description are also created. + * description are also created when data is received. + * + * A TransportStream is created when needed in order to transport the data over + * the necessary DTLS/ICE channel to the peer. The exact configuration depends + * on the negotiated SDP's between the peers based on the bundle and rtcp + * configuration. Some cases are outlined below for a simple single + * audio/video/data session: + * + * - max-bundle (requires rtcp-muxing) uses a single transport for all + * media/data transported. Renegotiation involves adding/removing the + * necessary streams to the existing transports. + * - max-compat without rtcp-mux involves two TransportStream per media stream + * to transport the rtp and the rtcp packets and a single TransportStream for + * all data channels. Each stream change involves modifying the associated + * TransportStream/s as necessary. */ /* @@ -216,41 +230,6 @@ gst_webrtc_bin_pad_class_init (GstWebRTCBinPadClass * klass) gobject_class->finalize = gst_webrtc_bin_pad_finalize; } -static GstCaps * -_transport_stream_get_caps_for_pt (TransportStream * stream, guint pt) -{ - guint i, len; - - len = stream->ptmap->len; - for (i = 0; i < len; i++) { - PtMapItem *item = &g_array_index (stream->ptmap, PtMapItem, i); - if (item->pt == pt) - return item->caps; - } - return NULL; -} - -static gint -_transport_stream_get_pt (TransportStream * stream, const gchar * encoding_name) -{ - guint i; - gint ret = 0; - - for (i = 0; i < stream->ptmap->len; i++) { - PtMapItem *item = &g_array_index (stream->ptmap, PtMapItem, i); - if (!gst_caps_is_empty (item->caps)) { - GstStructure *s = gst_caps_get_structure (item->caps, 0); - if (!g_strcmp0 (gst_structure_get_string (s, "encoding-name"), - encoding_name)) { - ret = item->pt; - break; - } - } - } - - return ret; -} - static gboolean gst_webrtcbin_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { @@ -356,30 +335,6 @@ enum static guint gst_webrtc_bin_signals[LAST_SIGNAL] = { 0 }; -static GstWebRTCDTLSTransport * -_transceiver_get_transport (GstWebRTCRTPTransceiver * trans) -{ - if (trans->sender) { - return trans->sender->transport; - } else if (trans->receiver) { - return trans->receiver->transport; - } - - return NULL; -} - -static GstWebRTCDTLSTransport * -_transceiver_get_rtcp_transport (GstWebRTCRTPTransceiver * trans) -{ - if (trans->sender) { - return trans->sender->rtcp_transport; - } else if (trans->receiver) { - return trans->receiver->rtcp_transport; - } - - return NULL; -} - typedef struct { guint session_id; @@ -827,7 +782,7 @@ _collate_ice_connection_states (GstWebRTCBin * webrtc) g_object_get (stream, "rtcp-mux", &rtcp_mux, NULL); - transport = _transceiver_get_transport (rtp_trans)->transport; + transport = webrtc_transceiver_get_dtls_transport (rtp_trans)->transport; /* get transport state */ g_object_get (transport, "state", &ice_state, NULL); @@ -835,7 +790,8 @@ _collate_ice_connection_states (GstWebRTCBin * webrtc) if (ice_state != STATE (CLOSED)) all_closed = FALSE; - rtcp_transport = _transceiver_get_rtcp_transport (rtp_trans)->transport; + rtcp_transport = + webrtc_transceiver_get_rtcp_dtls_transport (rtp_trans)->transport; if (!rtcp_mux && rtcp_transport && transport != rtcp_transport) { g_object_get (rtcp_transport, "state", &ice_state, NULL); @@ -921,7 +877,7 @@ _collate_ice_gathering_states (GstWebRTCBin * webrtc) g_object_get (stream, "rtcp-mux", &rtcp_mux, NULL); - transport = _transceiver_get_transport (rtp_trans)->transport; + transport = webrtc_transceiver_get_dtls_transport (rtp_trans)->transport; /* get gathering state */ g_object_get (transport, "gathering-state", &ice_state, NULL); @@ -929,7 +885,8 @@ _collate_ice_gathering_states (GstWebRTCBin * webrtc) if (ice_state != STATE (COMPLETE)) all_completed = FALSE; - rtcp_transport = _transceiver_get_rtcp_transport (rtp_trans)->transport; + rtcp_transport = + webrtc_transceiver_get_rtcp_dtls_transport (rtp_trans)->transport; if (!rtcp_mux && rtcp_transport && rtcp_transport != transport) { g_object_get (rtcp_transport, "gathering-state", &ice_state, NULL); @@ -988,7 +945,7 @@ _collate_peer_connection_states (GstWebRTCBin * webrtc) continue; g_object_get (stream, "rtcp-mux", &rtcp_mux, NULL); - transport = _transceiver_get_transport (rtp_trans); + transport = webrtc_transceiver_get_dtls_transport (rtp_trans); /* get transport state */ g_object_get (transport, "state", &dtls_state, NULL); @@ -996,7 +953,7 @@ _collate_peer_connection_states (GstWebRTCBin * webrtc) g_object_get (transport->transport, "state", &ice_state, NULL); any_ice_state |= (1 << ice_state); - rtcp_transport = _transceiver_get_rtcp_transport (rtp_trans); + rtcp_transport = webrtc_transceiver_get_rtcp_dtls_transport (rtp_trans); if (!rtcp_mux && rtcp_transport && rtcp_transport != transport) { g_object_get (rtcp_transport, "state", &dtls_state, NULL); @@ -1516,32 +1473,6 @@ _create_transport_channel (GstWebRTCBin * webrtc, guint session_id) return ret; } -static gboolean -_message_media_is_datachannel (const GstSDPMessage * msg, guint media_id) -{ - const GstSDPMedia *media; - - if (!msg) - return FALSE; - - if (gst_sdp_message_medias_len (msg) <= media_id) - return FALSE; - - media = gst_sdp_message_get_media (msg, media_id); - - if (g_strcmp0 (gst_sdp_media_get_media (media), "application") != 0) - return FALSE; - - if (gst_sdp_media_formats_len (media) != 1) - return FALSE; - - if (g_strcmp0 (gst_sdp_media_get_format (media, 0), - "webrtc-datachannel") != 0) - return FALSE; - - return TRUE; -} - static TransportStream * _get_or_create_rtp_transport_channel (GstWebRTCBin * webrtc, guint session_id) { @@ -1995,6 +1926,26 @@ _media_add_ssrcs (GstSDPMedia * media, GstCaps * caps, GstWebRTCBin * webrtc, (GstStructureForeachFunc) _media_add_rtx_ssrc, &data); } +static void +_add_fingerprint_to_media (GstWebRTCDTLSTransport * transport, + GstSDPMedia * media) +{ + gchar *cert, *fingerprint, *val; + + g_object_get (transport, "certificate", &cert, NULL); + + fingerprint = + _generate_fingerprint_from_certificate (cert, G_CHECKSUM_SHA256); + g_free (cert); + val = + g_strdup_printf ("%s %s", + _g_checksum_to_webrtc_string (G_CHECKSUM_SHA256), fingerprint); + g_free (fingerprint); + + gst_sdp_media_add_attribute (media, "fingerprint", val); + g_free (val); +} + /* based off https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-18#section-5.2.1 */ static gboolean sdp_media_from_transceiver (GstWebRTCBin * webrtc, GstSDPMedia * media, @@ -2119,8 +2070,6 @@ sdp_media_from_transceiver (GstWebRTCBin * webrtc, GstSDPMedia * media, g_free (sdp_mid); if (trans->sender) { - gchar *cert, *fingerprint, *val; - if (!trans->sender->transport) { TransportStream *item; @@ -2131,18 +2080,7 @@ sdp_media_from_transceiver (GstWebRTCBin * webrtc, GstSDPMedia * media, webrtc_transceiver_set_transport (WEBRTC_TRANSCEIVER (trans), item); } - g_object_get (trans->sender->transport, "certificate", &cert, NULL); - - fingerprint = - _generate_fingerprint_from_certificate (cert, G_CHECKSUM_SHA256); - g_free (cert); - val = - g_strdup_printf ("%s %s", - _g_checksum_to_webrtc_string (G_CHECKSUM_SHA256), fingerprint); - g_free (fingerprint); - - gst_sdp_media_add_attribute (media, "fingerprint", val); - g_free (val); + _add_fingerprint_to_media (trans->sender->transport, media); } gst_caps_unref (caps); @@ -2272,23 +2210,7 @@ _create_offer_task (GstWebRTCBin * webrtc, const GstStructure * options) _get_or_create_data_channel_transports (webrtc, bundled_mids ? 0 : webrtc->priv->transceivers->len); - { - gchar *cert, *fingerprint, *val; - - g_object_get (webrtc->priv->sctp_transport->transport, "certificate", - &cert, NULL); - - fingerprint = - _generate_fingerprint_from_certificate (cert, G_CHECKSUM_SHA256); - g_free (cert); - val = - g_strdup_printf ("%s %s", - _g_checksum_to_webrtc_string (G_CHECKSUM_SHA256), fingerprint); - g_free (fingerprint); - - gst_sdp_media_add_attribute (&media, "fingerprint", val); - g_free (val); - } + _add_fingerprint_to_media (webrtc->priv->sctp_transport->transport, &media); gst_sdp_message_add_media (ret, &media); } @@ -2423,54 +2345,6 @@ _get_rtx_target_pt_and_ssrc_from_caps (GstCaps * answer_caps, gint * target_pt, gst_structure_get_uint (s, "ssrc", target_ssrc); } -static gboolean -_parse_bundle (GstWebRTCBin * webrtc, GstSDPMessage * sdp, GStrv * bundled) -{ - const gchar *group; - gboolean ret = FALSE; - - group = gst_sdp_message_get_attribute_val (sdp, "group"); - - if (group && g_str_has_prefix (group, "BUNDLE ")) { - *bundled = g_strsplit (group + strlen ("BUNDLE "), " ", 0); - - if (!(*bundled)[0]) { - GST_ERROR_OBJECT (webrtc, - "Invalid format for BUNDLE group, expected at least one mid (%s)", - group); - goto done; - } - } else { - ret = TRUE; - goto done; - } - - ret = TRUE; - -done: - return ret; -} - -static gboolean -_get_bundle_index (GstSDPMessage * sdp, GStrv bundled, guint * idx) -{ - gboolean ret = FALSE; - guint i; - - for (i = 0; i < gst_sdp_message_medias_len (sdp); i++) { - const GstSDPMedia *media = gst_sdp_message_get_media (sdp, i); - const gchar *mid = gst_sdp_media_get_attribute_val (media, "mid"); - - if (!g_strcmp0 (mid, bundled[0])) { - *idx = i; - ret = TRUE; - break; - } - } - - return ret; -} - /* TODO: use the options argument */ static GstSDPMessage * _create_answer_task (GstWebRTCBin * webrtc, const GstStructure * options) @@ -2491,7 +2365,7 @@ _create_answer_task (GstWebRTCBin * webrtc, const GstStructure * options) return NULL; } - if (!_parse_bundle (webrtc, pending_remote->sdp, &bundled)) + if (!_parse_bundle (pending_remote->sdp, &bundled)) goto out; if (bundled) { @@ -2537,7 +2411,6 @@ _create_answer_task (GstWebRTCBin * webrtc, const GstStructure * options) GstWebRTCRTPTransceiverDirection offer_dir, answer_dir; GstWebRTCDTLSSetup offer_setup, answer_setup; GstCaps *offer_caps, *answer_caps = NULL; - gchar *cert; guint j; guint k; gint target_pt = -1; @@ -2634,23 +2507,8 @@ _create_answer_task (GstWebRTCBin * webrtc, const GstStructure * options) g_string_append_printf (bundled_mids, " %s", mid); } - { - gchar *cert, *fingerprint, *val; - - g_object_get (webrtc->priv->sctp_transport->transport, "certificate", - &cert, NULL); - - fingerprint = - _generate_fingerprint_from_certificate (cert, G_CHECKSUM_SHA256); - g_free (cert); - val = - g_strdup_printf ("%s %s", - _g_checksum_to_webrtc_string (G_CHECKSUM_SHA256), fingerprint); - g_free (fingerprint); - - gst_sdp_media_add_attribute (media, "fingerprint", val); - g_free (val); - } + _add_fingerprint_to_media (webrtc->priv->sctp_transport->transport, + media); } else if (g_strcmp0 (gst_sdp_media_get_media (offer_media), "audio") == 0 || g_strcmp0 (gst_sdp_media_get_media (offer_media), "video") == 0) { gst_sdp_media_set_proto (media, "UDP/TLS/RTP/SAVPF"); @@ -2785,23 +2643,9 @@ _create_answer_task (GstWebRTCBin * webrtc, const GstStructure * options) } webrtc_transceiver_set_transport (trans, item); } - /* set the a=fingerprint: for this transport */ - g_object_get (trans->stream->transport, "certificate", &cert, NULL); - { - gchar *fingerprint, *val; - - fingerprint = - _generate_fingerprint_from_certificate (cert, G_CHECKSUM_SHA256); - g_free (cert); - val = - g_strdup_printf ("%s %s", - _g_checksum_to_webrtc_string (G_CHECKSUM_SHA256), fingerprint); - g_free (fingerprint); - - gst_sdp_media_add_attribute (media, "fingerprint", val); - g_free (val); - } + /* set the a=fingerprint: for this transport */ + _add_fingerprint_to_media (trans->stream->transport, media); gst_caps_unref (offer_caps); } else { @@ -3078,6 +2922,9 @@ _connect_output_stream (GstWebRTCBin * webrtc, g_free (pad_name); gst_element_sync_state_with_parent (GST_ELEMENT (stream->receive_bin)); + + /* The webrtcbin src_%u output pads will be created when rtpbin receives + * data on that stream in on_rtpbin_pad_added() */ } typedef struct @@ -3280,8 +3127,7 @@ _update_transceiver_from_sdp_media (GstWebRTCBin * webrtc, gst_object_unref (pad); } else { GST_DEBUG_OBJECT (webrtc, - "creating new pad send pad for transceiver %" GST_PTR_FORMAT, - trans); + "creating new send pad for transceiver %" GST_PTR_FORMAT, trans); pad = _create_pad_for_sdp_media (webrtc, GST_PAD_SINK, media_idx); pad->trans = gst_object_ref (rtp_trans); _connect_input_stream (webrtc, pad); @@ -3520,7 +3366,7 @@ _update_transceivers_from_sdp (GstWebRTCBin * webrtc, SDPSource source, gboolean should_connect_bundle_stream = FALSE; TransportStream *bundle_stream = NULL; - if (!_parse_bundle (webrtc, sdp->sdp, &bundled)) + if (!_parse_bundle (sdp->sdp, &bundled)) goto done; if (bundled) { @@ -3607,57 +3453,6 @@ done: return ret; } -static void -_get_ice_credentials_from_sdp_media (const GstSDPMessage * sdp, guint media_idx, - gchar ** ufrag, gchar ** pwd) -{ - int i; - - *ufrag = NULL; - *pwd = NULL; - - { - /* search in the corresponding media section */ - const GstSDPMedia *media = gst_sdp_message_get_media (sdp, media_idx); - const gchar *tmp_ufrag = - gst_sdp_media_get_attribute_val (media, "ice-ufrag"); - const gchar *tmp_pwd = gst_sdp_media_get_attribute_val (media, "ice-pwd"); - if (tmp_ufrag && tmp_pwd) { - *ufrag = g_strdup (tmp_ufrag); - *pwd = g_strdup (tmp_pwd); - return; - } - } - - /* then in the sdp message itself */ - for (i = 0; i < gst_sdp_message_attributes_len (sdp); i++) { - const GstSDPAttribute *attr = gst_sdp_message_get_attribute (sdp, i); - - if (g_strcmp0 (attr->key, "ice-ufrag") == 0) { - g_assert (!*ufrag); - *ufrag = g_strdup (attr->value); - } else if (g_strcmp0 (attr->key, "ice-pwd") == 0) { - g_assert (!*pwd); - *pwd = g_strdup (attr->value); - } - } - if (!*ufrag && !*pwd) { - /* Check in the medias themselves. According to JSEP, they should be - * identical FIXME: only for bundle-d streams */ - for (i = 0; i < gst_sdp_message_medias_len (sdp); i++) { - const GstSDPMedia *media = gst_sdp_message_get_media (sdp, i); - const gchar *tmp_ufrag = - gst_sdp_media_get_attribute_val (media, "ice-ufrag"); - const gchar *tmp_pwd = gst_sdp_media_get_attribute_val (media, "ice-pwd"); - if (tmp_ufrag && tmp_pwd) { - *ufrag = g_strdup (tmp_ufrag); - *pwd = g_strdup (tmp_pwd); - break; - } - } - } -} - struct set_description { GstPromise *promise; @@ -3700,7 +3495,7 @@ _set_description_task (GstWebRTCBin * webrtc, struct set_description *sd) goto out; } - if (!_parse_bundle (webrtc, sd->sdp->sdp, &bundled)) + if (!_parse_bundle (sd->sdp->sdp, &bundled)) goto out; if (bundled) { @@ -4432,7 +4227,7 @@ on_rtpbin_request_pt_map (GstElement * rtpbin, guint session_id, guint pt, if (!stream) goto unknown_session; - if ((ret = _transport_stream_get_caps_for_pt (stream, pt))) + if ((ret = transport_stream_get_caps_for_pt (stream, pt))) gst_caps_ref (ret); GST_TRACE_OBJECT (webrtc, "Found caps %" GST_PTR_FORMAT " for pt %d in " @@ -4530,15 +4325,15 @@ on_rtpbin_request_aux_receiver (GstElement * rtpbin, guint session_id, stream = _find_transport_for_session (webrtc, session_id); if (stream) { - red_pt = _transport_stream_get_pt (stream, "RED"); - rtx_pt = _transport_stream_get_pt (stream, "RTX"); + red_pt = transport_stream_get_pt (stream, "RED"); + rtx_pt = transport_stream_get_pt (stream, "RTX"); } if (red_pt || rtx_pt) ret = gst_bin_new (NULL); if (rtx_pt) { - GstCaps *rtx_caps = _transport_stream_get_caps_for_pt (stream, rtx_pt); + GstCaps *rtx_caps = transport_stream_get_caps_for_pt (stream, rtx_pt); GstElement *rtx = gst_element_factory_make ("rtprtxreceive", NULL); GstStructure *pt_map; const GstStructure *s = gst_caps_get_structure (rtx_caps, 0); @@ -4615,7 +4410,7 @@ on_rtpbin_request_fec_decoder (GstElement * rtpbin, guint session_id, * example) */ if (stream) - pt = _transport_stream_get_pt (stream, "ULPFEC"); + pt = transport_stream_get_pt (stream, "ULPFEC"); if (pt) { GST_DEBUG_OBJECT (webrtc, "Creating ULPFEC decoder for pt %d in session %u", @@ -4648,8 +4443,8 @@ on_rtpbin_request_fec_encoder (GstElement * rtpbin, guint session_id, (FindTransceiverFunc) transceiver_match_for_mline); if (stream) { - ulpfec_pt = _transport_stream_get_pt (stream, "ULPFEC"); - red_pt = _transport_stream_get_pt (stream, "RED"); + ulpfec_pt = transport_stream_get_pt (stream, "ULPFEC"); + red_pt = transport_stream_get_pt (stream, "RED"); } if (ulpfec_pt || red_pt) @@ -4657,7 +4452,7 @@ on_rtpbin_request_fec_encoder (GstElement * rtpbin, guint session_id, if (ulpfec_pt) { GstElement *fecenc = gst_element_factory_make ("rtpulpfecenc", NULL); - GstCaps *caps = _transport_stream_get_caps_for_pt (stream, ulpfec_pt); + GstCaps *caps = transport_stream_get_caps_for_pt (stream, ulpfec_pt); GST_DEBUG_OBJECT (webrtc, "Creating ULPFEC encoder for session %d with pt %d", session_id, @@ -5275,7 +5070,7 @@ gst_webrtc_bin_class_init (GstWebRTCBinClass * klass) * * RTCInboundRTPStreamStats supported fields (https://w3c.github.io/webrtc-stats/#inboundrtpstats-dict*) * - * "remote-id" G_TYPE_STRING identifier for the associated RTCRemoteOutboundRTPSTreamStats + * "remote-id" G_TYPE_STRING identifier for the associated RTCRemoteOutboundRTPStreamStats * * RTCRemoteInboundRTPStreamStats supported fields (https://w3c.github.io/webrtc-stats/#remoteinboundrtpstats-dict*) * diff --git a/ext/webrtc/transportstream.c b/ext/webrtc/transportstream.c index 87a2a78ae747c7e9912da95a1c10ef634ead5e3e..01fa2dc91956294feeadfdfd50ec55e628ddd456 100644 --- a/ext/webrtc/transportstream.c +++ b/ext/webrtc/transportstream.c @@ -40,6 +40,41 @@ enum PROP_DTLS_CLIENT, }; +GstCaps * +transport_stream_get_caps_for_pt (TransportStream * stream, guint pt) +{ + guint i, len; + + len = stream->ptmap->len; + for (i = 0; i < len; i++) { + PtMapItem *item = &g_array_index (stream->ptmap, PtMapItem, i); + if (item->pt == pt) + return item->caps; + } + return NULL; +} + +int +transport_stream_get_pt (TransportStream * stream, const gchar * encoding_name) +{ + guint i; + gint ret = 0; + + for (i = 0; i < stream->ptmap->len; i++) { + PtMapItem *item = &g_array_index (stream->ptmap, PtMapItem, i); + if (!gst_caps_is_empty (item->caps)) { + GstStructure *s = gst_caps_get_structure (item->caps, 0); + if (!g_strcmp0 (gst_structure_get_string (s, "encoding-name"), + encoding_name)) { + ret = item->pt; + break; + } + } + } + + return ret; +} + static void transport_stream_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) diff --git a/ext/webrtc/transportstream.h b/ext/webrtc/transportstream.h index 5728176a991888c56708af30eb5f2ad9e0dca9c3..8b90a946ab9aae1d210c98aa6de8ca5a476ccd89 100644 --- a/ext/webrtc/transportstream.h +++ b/ext/webrtc/transportstream.h @@ -70,6 +70,10 @@ struct _TransportStreamClass TransportStream * transport_stream_new (GstWebRTCBin * webrtc, guint session_id); +int transport_stream_get_pt (TransportStream * stream, + const gchar * encoding_name); +GstCaps * transport_stream_get_caps_for_pt (TransportStream * stream, + guint pt); G_END_DECLS diff --git a/ext/webrtc/webrtcsdp.c b/ext/webrtc/webrtcsdp.c index 5d1b43c730248dca5eaf4e65fa05d4bcb9d6c3a3..7269ada27acb1178a2d5dc41bd15ff22826d217a 100644 --- a/ext/webrtc/webrtcsdp.c +++ b/ext/webrtc/webrtcsdp.c @@ -736,3 +736,127 @@ _get_sctp_max_message_size_from_media (const GstSDPMedia * media) return 65536; } + +gboolean +_message_media_is_datachannel (const GstSDPMessage * msg, guint media_id) +{ + const GstSDPMedia *media; + + if (!msg) + return FALSE; + + if (gst_sdp_message_medias_len (msg) <= media_id) + return FALSE; + + media = gst_sdp_message_get_media (msg, media_id); + + if (g_strcmp0 (gst_sdp_media_get_media (media), "application") != 0) + return FALSE; + + if (gst_sdp_media_formats_len (media) != 1) + return FALSE; + + if (g_strcmp0 (gst_sdp_media_get_format (media, 0), + "webrtc-datachannel") != 0) + return FALSE; + + return TRUE; +} + +void +_get_ice_credentials_from_sdp_media (const GstSDPMessage * sdp, guint media_idx, + gchar ** ufrag, gchar ** pwd) +{ + int i; + + *ufrag = NULL; + *pwd = NULL; + + { + /* search in the corresponding media section */ + const GstSDPMedia *media = gst_sdp_message_get_media (sdp, media_idx); + const gchar *tmp_ufrag = + gst_sdp_media_get_attribute_val (media, "ice-ufrag"); + const gchar *tmp_pwd = gst_sdp_media_get_attribute_val (media, "ice-pwd"); + if (tmp_ufrag && tmp_pwd) { + *ufrag = g_strdup (tmp_ufrag); + *pwd = g_strdup (tmp_pwd); + return; + } + } + + /* then in the sdp message itself */ + for (i = 0; i < gst_sdp_message_attributes_len (sdp); i++) { + const GstSDPAttribute *attr = gst_sdp_message_get_attribute (sdp, i); + + if (g_strcmp0 (attr->key, "ice-ufrag") == 0) { + g_assert (!*ufrag); + *ufrag = g_strdup (attr->value); + } else if (g_strcmp0 (attr->key, "ice-pwd") == 0) { + g_assert (!*pwd); + *pwd = g_strdup (attr->value); + } + } + if (!*ufrag && !*pwd) { + /* Check in the medias themselves. According to JSEP, they should be + * identical FIXME: only for bundle-d streams */ + for (i = 0; i < gst_sdp_message_medias_len (sdp); i++) { + const GstSDPMedia *media = gst_sdp_message_get_media (sdp, i); + const gchar *tmp_ufrag = + gst_sdp_media_get_attribute_val (media, "ice-ufrag"); + const gchar *tmp_pwd = gst_sdp_media_get_attribute_val (media, "ice-pwd"); + if (tmp_ufrag && tmp_pwd) { + *ufrag = g_strdup (tmp_ufrag); + *pwd = g_strdup (tmp_pwd); + break; + } + } + } +} + +gboolean +_parse_bundle (GstSDPMessage * sdp, GStrv * bundled) +{ + const gchar *group; + gboolean ret = FALSE; + + group = gst_sdp_message_get_attribute_val (sdp, "group"); + + if (group && g_str_has_prefix (group, "BUNDLE ")) { + *bundled = g_strsplit (group + strlen ("BUNDLE "), " ", 0); + + if (!(*bundled)[0]) { + GST_ERROR ("Invalid format for BUNDLE group, expected at least " + "one mid (%s)", group); + goto done; + } + } else { + ret = TRUE; + goto done; + } + + ret = TRUE; + +done: + return ret; +} + +gboolean +_get_bundle_index (GstSDPMessage * sdp, GStrv bundled, guint * idx) +{ + gboolean ret = FALSE; + guint i; + + for (i = 0; i < gst_sdp_message_medias_len (sdp); i++) { + const GstSDPMedia *media = gst_sdp_message_get_media (sdp, i); + const gchar *mid = gst_sdp_media_get_attribute_val (media, "mid"); + + if (!g_strcmp0 (mid, bundled[0])) { + *idx = i; + ret = TRUE; + break; + } + } + + return ret; +} diff --git a/ext/webrtc/webrtcsdp.h b/ext/webrtc/webrtcsdp.h index d5ea777b35942af1b78bbda3ad22b44771e2db9e..15a8e927025ea20652816465b2d1fbb1c130f586 100644 --- a/ext/webrtc/webrtcsdp.h +++ b/ext/webrtc/webrtcsdp.h @@ -81,4 +81,21 @@ int _get_sctp_port_from_media (con G_GNUC_INTERNAL guint64 _get_sctp_max_message_size_from_media (const GstSDPMedia * media); +G_GNUC_INTERNAL +void _get_ice_credentials_from_sdp_media (const GstSDPMessage * sdp, + guint media_idx, + gchar ** ufrag, + gchar ** pwd); +G_GNUC_INTERNAL +gboolean _message_media_is_datachannel (const GstSDPMessage * msg, + guint media_id); + +G_GNUC_INTERNAL +gboolean _get_bundle_index (GstSDPMessage * sdp, + GStrv bundled, + guint * idx); +G_GNUC_INTERNAL +gboolean _parse_bundle (GstSDPMessage * sdp, + GStrv * bundled); + #endif /* __WEBRTC_UTILS_H__ */ diff --git a/ext/webrtc/webrtctransceiver.c b/ext/webrtc/webrtctransceiver.c index 1735b1a8aa315f005591188ad453a616eeeca026..c1a3faa1c2aca1b194b6096345827bb7cf4827f5 100644 --- a/ext/webrtc/webrtctransceiver.c +++ b/ext/webrtc/webrtctransceiver.c @@ -69,6 +69,34 @@ webrtc_transceiver_set_transport (WebRTCTransceiver * trans, (GstObject *) stream->rtcp_transport); } +GstWebRTCDTLSTransport * +webrtc_transceiver_get_dtls_transport (GstWebRTCRTPTransceiver * trans) +{ + g_return_val_if_fail (WEBRTC_IS_TRANSCEIVER (trans), NULL); + + if (trans->sender) { + return trans->sender->transport; + } else if (trans->receiver) { + return trans->receiver->transport; + } + + return NULL; +} + +GstWebRTCDTLSTransport * +webrtc_transceiver_get_rtcp_dtls_transport (GstWebRTCRTPTransceiver * trans) +{ + g_return_val_if_fail (WEBRTC_IS_TRANSCEIVER (trans), NULL); + + if (trans->sender) { + return trans->sender->rtcp_transport; + } else if (trans->receiver) { + return trans->receiver->rtcp_transport; + } + + return NULL; +} + static void webrtc_transceiver_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) diff --git a/ext/webrtc/webrtctransceiver.h b/ext/webrtc/webrtctransceiver.h index 25bb24e82189782fcdc3bbe1857d68287edb4292..f1e338f66d0d13f1460d6dcdf5cc46c493cd01aa 100644 --- a/ext/webrtc/webrtctransceiver.h +++ b/ext/webrtc/webrtctransceiver.h @@ -58,6 +58,9 @@ WebRTCTransceiver * webrtc_transceiver_new (GstWebRTCBin * webr void webrtc_transceiver_set_transport (WebRTCTransceiver * trans, TransportStream * stream); +GstWebRTCDTLSTransport * webrtc_transceiver_get_dtls_transport (GstWebRTCRTPTransceiver * trans); +GstWebRTCDTLSTransport * webrtc_transceiver_get_rtcp_dtls_transport (GstWebRTCRTPTransceiver * trans); + G_END_DECLS #endif /* __WEBRTC_TRANSCEIVER_H__ */