webrtcbin: Support data channel SDP offers from Chrome
authorJakub Adam <jakub.adam@collabora.com>
Wed, 12 Jun 2019 13:00:38 +0000 (15:00 +0200)
committerMatthew Waters <matthew@centricular.com>
Mon, 29 Jul 2019 22:04:08 +0000 (22:04 +0000)
When negotiating a data channel, Chrome as recent as 75 still uses SDP
based on version 05 of the SCTP SDP draft, for example:

 m=application 9 DTLS/SCTP 5000
 a=sctpmap:5000 webrtc-datachannel 1024

Implement support for parsing SCTP port out of SDP message with sctpmap
attribute. Fixes data channel negotiation with Chrome browser.

ext/webrtc/gstwebrtcbin.c
ext/webrtc/webrtcsdp.c

index 337384c..923af6b 100644 (file)
@@ -2794,13 +2794,6 @@ _create_answer_task (GstWebRTCBin * webrtc, const GstStructure * options)
             "for webrtc-datachannel");
         goto rejected;
       }
-      if (g_strcmp0 (gst_sdp_media_get_format (offer_media, 0),
-              "webrtc-datachannel") != 0) {
-        GST_WARNING_OBJECT (webrtc,
-            "format field of data channel m= line "
-            "is not \'webrtc-datachannel\'");
-        goto rejected;
-      }
       sctp_port = _get_sctp_port_from_media (offer_media);
       if (sctp_port == -1) {
         GST_WARNING_OBJECT (webrtc, "media does not contain a sctp port");
index 56ecc79..42d650f 100644 (file)
@@ -712,21 +712,56 @@ _generate_ice_credentials (gchar ** ufrag, gchar ** password)
 int
 _get_sctp_port_from_media (const GstSDPMedia * media)
 {
-  int sctpmap = -1, i;
+  int i;
+  const gchar *format;
+  gchar *endptr;
 
-  for (i = 0; i < gst_sdp_media_attributes_len (media); i++) {
-    const GstSDPAttribute *attr = gst_sdp_media_get_attribute (media, i);
+  if (gst_sdp_media_formats_len (media) != 1) {
+    /* only exactly one format is supported */
+    return -1;
+  }
 
-    if (g_strcmp0 (attr->key, "sctp-port") == 0) {
-      return atoi (attr->value);
-    } else if (g_strcmp0 (attr->key, "sctpmap") == 0) {
-      sctpmap = atoi (attr->value);
+  format = gst_sdp_media_get_format (media, 0);
+
+  if (g_strcmp0 (format, "webrtc-datachannel") == 0) {
+    /* draft-ietf-mmusic-sctp-sdp-21, e.g. Firefox 63 and later */
+
+    for (i = 0; i < gst_sdp_media_attributes_len (media); i++) {
+      const GstSDPAttribute *attr = gst_sdp_media_get_attribute (media, i);
+
+      if (g_strcmp0 (attr->key, "sctp-port") == 0) {
+        gint64 port = g_ascii_strtoll (attr->value, &endptr, 10);
+        if (endptr == attr->value) {
+          /* conversion error */
+          return -1;
+        }
+        return port;
+      }
+    }
+  } else {
+    /* draft-ietf-mmusic-sctp-sdp-05, e.g. Chrome as recent as 75 */
+    gint64 port = g_ascii_strtoll (format, &endptr, 10);
+    if (endptr == format) {
+      /* conversion error */
+      return -1;
+    }
+
+    for (i = 0; i < gst_sdp_media_attributes_len (media); i++) {
+      const GstSDPAttribute *attr = gst_sdp_media_get_attribute (media, i);
+
+      if (g_strcmp0 (attr->key, "sctpmap") == 0 && atoi (attr->value) == port) {
+        /* a=sctpmap:5000 webrtc-datachannel 256 */
+        gchar **parts = g_strsplit (attr->value, " ", 3);
+        if (!parts[1] || g_strcmp0 (parts[1], "webrtc-datachannel") != 0) {
+          port = -1;
+        }
+        g_strfreev (parts);
+        return port;
+      }
     }
   }
 
-  if (sctpmap >= 0)
-    GST_LOG ("no sctp-port attribute in media");
-  return sctpmap;
+  return -1;
 }
 
 guint64