Bug 1438290: Part 1: Implemented RsdparsaSdpMediaSection::AddDataChannel, r=dminor draft
authorJohannes Willbold <j.willbold@mozilla.com>
Wed, 20 Jun 2018 12:13:38 -0700
changeset 811531 f9e1457b45c63ae53b339ea43e8645a00d83e369
parent 811302 9c7bb8874337c2d40aef3d9945b10490a5115188
child 811532 18fc6f3bdc04ea0983ce5376177a41df68b93ac2
push id114329
push userbmo:johannes.willbold@rub.de
push dateWed, 27 Jun 2018 18:16:56 +0000
reviewersdminor
bugs1438290
milestone63.0a1
Bug 1438290: Part 1: Implemented RsdparsaSdpMediaSection::AddDataChannel, r=dminor Implemented RsdparsaSdpMediaSection::AddDataChannel Added C++/Rust glue code for the "sctp port" attribute Added C++/Rust glue code for the "max message size" attribute MozReview-Commit-ID: 5MQC7I1MiU0
media/webrtc/signaling/src/sdp/RsdparsaSdpAttributeList.cpp
media/webrtc/signaling/src/sdp/RsdparsaSdpAttributeList.h
media/webrtc/signaling/src/sdp/RsdparsaSdpInc.h
media/webrtc/signaling/src/sdp/RsdparsaSdpMediaSection.cpp
media/webrtc/signaling/src/sdp/rsdparsa/src/media_type.rs
media/webrtc/signaling/src/sdp/rsdparsa_capi/src/attribute.rs
media/webrtc/signaling/src/sdp/rsdparsa_capi/src/media_section.rs
--- a/media/webrtc/signaling/src/sdp/RsdparsaSdpAttributeList.cpp
+++ b/media/webrtc/signaling/src/sdp/RsdparsaSdpAttributeList.cpp
@@ -437,16 +437,19 @@ RsdparsaSdpAttributeList::LoadAttribute(
         LoadPtime(attributeList);
         return;
       case SdpAttribute::kIceLiteAttribute:
       case SdpAttribute::kRtcpMuxAttribute:
       case SdpAttribute::kBundleOnlyAttribute:
       case SdpAttribute::kEndOfCandidatesAttribute:
         LoadFlags(attributeList);
         return;
+      case SdpAttribute::kMaxMessageSizeAttribute:
+        LoadMaxMessageSize(attributeList);
+        return ;
       case SdpAttribute::kMidAttribute:
         LoadMid(attributeList);
         return;
       case SdpAttribute::kMsidAttribute:
         LoadMsid(attributeList);
         return;
       case SdpAttribute::kMsidSemanticAttribute:
         LoadMsidSemantics(attributeList);
@@ -470,30 +473,31 @@ RsdparsaSdpAttributeList::LoadAttribute(
         LoadDirection(attributeList);
         return;
       case SdpAttribute::kRemoteCandidatesAttribute:
         LoadRemoteCandidates(attributeList);
         return;
       case SdpAttribute::kRidAttribute:
         LoadRids(attributeList);
         return;
+      case SdpAttribute::kSctpPortAttribute:
+        LoadSctpPort(attributeList);
+        return ;
       case SdpAttribute::kExtmapAttribute:
         LoadExtmap(attributeList);
         return;
       case SdpAttribute::kSimulcastAttribute:
         LoadSimulcast(attributeList);
         return;
 
       case SdpAttribute::kDtlsMessageAttribute:
       case SdpAttribute::kLabelAttribute:
       case SdpAttribute::kMaxptimeAttribute:
       case SdpAttribute::kSsrcGroupAttribute:
-      case SdpAttribute::kMaxMessageSizeAttribute:
       case SdpAttribute::kRtcpRsizeAttribute:
-      case SdpAttribute::kSctpPortAttribute:
       case SdpAttribute::kCandidateAttribute:
       case SdpAttribute::kConnectionAttribute:
       case SdpAttribute::kIceMismatchAttribute:
         // TODO: Not implemented, or not applicable.
         // Sort this out in Bug 1437165.
         return;
     }
   }
@@ -805,16 +809,26 @@ RsdparsaSdpAttributeList::LoadFlags(Rust
     SetAttribute(new SdpFlagAttribute(SdpAttribute::kBundleOnlyAttribute));
   }
   if (flags.endOfCandidates) {
     SetAttribute(new SdpFlagAttribute(SdpAttribute::kEndOfCandidatesAttribute));
   }
 }
 
 void
+RsdparsaSdpAttributeList::LoadMaxMessageSize(RustAttributeList* attributeList)
+{
+  int64_t max_msg_size = sdp_get_max_msg_sizse(attributeList);
+  if (max_msg_size >= 0) {
+    SetAttribute(new SdpNumberAttribute(SdpAttribute::kMaxMessageSizeAttribute,
+                                        static_cast<uint32_t>(max_msg_size)));
+  }
+}
+
+void
 RsdparsaSdpAttributeList::LoadMid(RustAttributeList* attributeList)
 {
   StringView rustMid;
   if (NS_SUCCEEDED(sdp_get_mid(attributeList, &rustMid))) {
     std::string mid = convertStringView(rustMid);
     SetAttribute(new SdpStringAttribute(SdpAttribute::kMidAttribute, mid));
   }
 }
@@ -1121,16 +1135,26 @@ RsdparsaSdpAttributeList::LoadRids(RustA
 
     ridList->PushEntry(id, direction, formats, parameters, depends);
   }
 
   SetAttribute(ridList.release());
 }
 
 void
+RsdparsaSdpAttributeList::LoadSctpPort(RustAttributeList* attributeList)
+{
+  int64_t port = sdp_get_sctp_port(attributeList);
+  if (port >= 0) {
+    SetAttribute(new SdpNumberAttribute(SdpAttribute::kSctpPortAttribute,
+                                        static_cast<uint32_t>(port)));
+  }
+}
+
+void
 RsdparsaSdpAttributeList::LoadExtmap(RustAttributeList* attributeList)
 {
   size_t numExtmap = sdp_get_extmap_count(attributeList);
   if (numExtmap == 0) {
     return;
   }
   auto rustExtmaps = MakeUnique<RustSdpAttributeExtmap[]>(numExtmap);
   sdp_get_extmaps(attributeList, numExtmap,
--- a/media/webrtc/signaling/src/sdp/RsdparsaSdpAttributeList.h
+++ b/media/webrtc/signaling/src/sdp/RsdparsaSdpAttributeList.h
@@ -125,22 +125,24 @@ private:
   void LoadIceOptions(RustAttributeList* attributeList);
   void LoadFingerprint(RustAttributeList* attributeList);
   void LoadSetup(RustAttributeList* attributeList);
   void LoadSsrc(RustAttributeList* attributeList);
   void LoadRtpmap(RustAttributeList* attributeList);
   void LoadFmtp(RustAttributeList* attributeList);
   void LoadPtime(RustAttributeList* attributeList);
   void LoadFlags(RustAttributeList* attributeList);
+  void LoadMaxMessageSize(RustAttributeList* attributeList);
   void LoadMid(RustAttributeList* attributeList);
   void LoadMsid(RustAttributeList* attributeList);
   void LoadMsidSemantics(RustAttributeList* attributeList);
   void LoadGroup(RustAttributeList* attributeList);
   void LoadRtcp(RustAttributeList* attributeList);
   void LoadRtcpFb(RustAttributeList* attributeList);
+  void LoadSctpPort(RustAttributeList* attributeList);
   void LoadSimulcast(RustAttributeList* attributeList);
   void LoadImageattr(RustAttributeList* attributeList);
   void LoadSctpmaps(RustAttributeList* attributeList);
   void LoadDirection(RustAttributeList* attributeList);
   void LoadRemoteCandidates(RustAttributeList* attributeList);
   void LoadRids(RustAttributeList* attributeList);
   void LoadExtmap(RustAttributeList* attributeList);
 
--- a/media/webrtc/signaling/src/sdp/RsdparsaSdpInc.h
+++ b/media/webrtc/signaling/src/sdp/RsdparsaSdpInc.h
@@ -300,16 +300,19 @@ nsresult sdp_get_media_connection(const 
 
 RustAttributeList*
 sdp_get_media_attribute_list(const RustMediaSection* aMediaSec);
 
 nsresult sdp_media_add_codec(const RustMediaSection* aMediaSec,
                              uint8_t aPT, StringView aCodecName,
                              uint32_t aClockrate, uint16_t channels);
 void sdp_media_clear_codecs(const RustMediaSection* aMediaSec);
+nsresult sdp_media_add_datachannel(const RustMediaSection* aMediaSec,
+                                   StringView aName, uint16_t aPort,
+                                   uint16_t streams, uint32_t aMessageSize);
 
 nsresult sdp_get_iceufrag(const RustAttributeList* aList, StringView* ret);
 nsresult sdp_get_icepwd(const RustAttributeList* aList, StringView* ret);
 nsresult sdp_get_identity(const RustAttributeList* aList, StringView* ret);
 nsresult sdp_get_iceoptions(const RustAttributeList* aList, StringVec** ret);
 
 size_t sdp_get_fingerprint_count(const RustAttributeList* aList);
 void sdp_get_fingerprints(const RustAttributeList* aList, size_t listSize,
@@ -325,16 +328,18 @@ size_t sdp_get_rtpmap_count(const RustAt
 void sdp_get_rtpmaps(const RustAttributeList* aList, size_t listSize,
                      RustSdpAttributeRtpmap* ret);
 
 size_t sdp_get_fmtp_count(const RustAttributeList* aList);
 size_t sdp_get_fmtp(const RustAttributeList* aList, size_t listSize,
                     RustSdpAttributeFmtp* ret);
 
 int64_t sdp_get_ptime(const RustAttributeList* aList);
+int64_t sdp_get_max_msg_sizse(const RustAttributeList* aList);
+int64_t sdp_get_sctp_port(const RustAttributeList* aList);
 
 RustSdpAttributeFlags sdp_get_attribute_flags(const RustAttributeList* aList);
 
 nsresult sdp_get_mid(const RustAttributeList* aList, StringView* ret);
 
 size_t sdp_get_msid_count(const RustAttributeList* aList);
 void sdp_get_msids(const RustAttributeList* aList, size_t listSize,
                    RustSdpAttributeMsid* ret);
--- a/media/webrtc/signaling/src/sdp/RsdparsaSdpMediaSection.cpp
+++ b/media/webrtc/signaling/src/sdp/RsdparsaSdpMediaSection.cpp
@@ -185,17 +185,31 @@ RsdparsaSdpMediaSection::ClearCodecs()
   mAttributeList->RemoveAttribute(SdpAttribute::kSctpmapAttribute);
   mAttributeList->RemoveAttribute(SdpAttribute::kRtcpFbAttribute);
 }
 
 void
 RsdparsaSdpMediaSection::AddDataChannel(const std::string& name, uint16_t port,
                                         uint16_t streams, uint32_t message_size)
 {
-  //TODO: See 1438290
+  StringView rustName{name.c_str(), name.size()};
+  auto nr = sdp_media_add_datachannel(mSection, rustName, port,
+                                      streams, message_size);
+  if (NS_SUCCEEDED(nr)) {
+    // Update the formats
+    mFormats.clear();
+    LoadFormats();
+
+    // Update the attribute list
+    RsdparsaSessionHandle sessHandle(sdp_new_reference(mSession.get()));
+    auto sessAttributes = mAttributeList->mSessionAttributes;
+    mAttributeList.reset(new RsdparsaSdpAttributeList(std::move(sessHandle),
+                                                      mSection,
+                                                      sessAttributes));
+  }
 }
 
 void
 RsdparsaSdpMediaSection::Serialize(std::ostream& os) const
 {
   os << "m=" << mMediaType << " " << GetPort();
   if (GetPortCount()) {
     os << "/" << GetPortCount();
--- a/media/webrtc/signaling/src/sdp/rsdparsa/src/media_type.rs
+++ b/media/webrtc/signaling/src/sdp/rsdparsa/src/media_type.rs
@@ -1,11 +1,11 @@
 use std::fmt;
 use {SdpType, SdpLine, SdpBandwidth, SdpConnection};
-use attribute_type::{SdpAttribute, SdpAttributeType, SdpAttributeRtpmap};
+use attribute_type::{SdpAttribute, SdpAttributeType, SdpAttributeRtpmap, SdpAttributeSctpmap};
 use error::{SdpParserError, SdpParserInternalError};
 
 #[derive(Clone)]
 #[cfg_attr(feature="serialize", derive(Serialize))]
 pub struct SdpMediaLine {
     pub media: SdpMediaValue,
     pub port: u32,
     pub port_count: u32,
@@ -145,16 +145,25 @@ impl SdpMedia {
         }
         Ok(self.attribute.push(attr.clone()))
     }
 
     pub fn get_attribute(&self, t: SdpAttributeType) -> Option<&SdpAttribute> {
         self.attribute.iter().filter(|a| SdpAttributeType::from(*a) == t).next()
     }
 
+    pub fn remove_attribute(&mut self, t: SdpAttributeType) {
+        self.attribute.retain(|a| SdpAttributeType::from(a) != t);
+    }
+
+    pub fn set_attribute(&mut self, attr: &SdpAttribute) -> Result<(), SdpParserInternalError> {
+        self.remove_attribute(SdpAttributeType::from(attr));
+        self.add_attribute(attr)
+    }
+
     pub fn remove_codecs(&mut self) {
         match self.media.formats{
             SdpFormatList::Integers(_) => self.media.formats = SdpFormatList::Integers(Vec::new()),
             SdpFormatList::Strings(_) => self.media.formats = SdpFormatList::Strings(Vec::new()),
         }
 
         self.attribute.retain({|x|
             match x {
@@ -192,16 +201,43 @@ impl SdpMedia {
     pub fn set_connection(&mut self, c: &SdpConnection) -> Result<(), SdpParserInternalError> {
         if self.connection.is_some() {
             return Err(SdpParserInternalError::Generic("connection type already exists at this media level"
                                .to_string(),
                        ));
         }
         Ok(self.connection = Some(c.clone()))
     }
+
+    pub fn add_datachannel(&mut self, name: String, port: u16, streams: u16, msg_size:u32)
+                           -> Result<(),SdpParserInternalError> {
+         // Only one allowed, for now. This may change as the specs (and deployments) evolve.
+        match self.media.proto {
+            SdpProtocolValue::UdpDtlsSctp |
+            SdpProtocolValue::TcpDtlsSctp => {
+                // new data channel format according to draft 21
+                self.media.formats = SdpFormatList::Strings(vec![name]);
+                self.set_attribute(&SdpAttribute::SctpPort(port as u64))?;
+            }
+            _ => {
+                // old data channels format according to draft 05
+                self.media.formats = SdpFormatList::Integers(vec![port as u32]);
+                self.set_attribute(&SdpAttribute::Sctpmap(SdpAttributeSctpmap {
+                    port,
+                    channels: streams as u32,
+                }))?;
+            }
+        }
+
+        if msg_size > 0 {
+            self.set_attribute(&SdpAttribute::MaxMessageSize(msg_size as u64))?;
+        }
+
+        Ok(())
+    }
 }
 
 #[cfg(test)]
 #[cfg_attr(feature="serialize", derive(Serialize))]
 pub fn create_dummy_media_section() -> SdpMedia {
     let media_line = SdpMediaLine {
         media: SdpMediaValue::Audio,
         port: 9,
--- a/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/attribute.rs
+++ b/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/attribute.rs
@@ -434,16 +434,36 @@ pub unsafe extern "C" fn sdp_get_ptime(a
     for attribute in (*attributes).iter() {
         if let SdpAttribute::Ptime(time) = *attribute {
             return time as int64_t;
         }
     }
     -1
 }
 
+#[no_mangle]
+pub unsafe extern "C" fn sdp_get_max_msg_sizse(attributes: *const Vec<SdpAttribute>) -> int64_t {
+    for attribute in (*attributes).iter() {
+        if let SdpAttribute::MaxMessageSize(max_msg_size) = *attribute {
+            return max_msg_size as int64_t;
+        }
+    }
+    -1
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn sdp_get_sctp_port(attributes: *const Vec<SdpAttribute>) -> int64_t {
+    for attribute in (*attributes).iter() {
+        if let SdpAttribute::SctpPort(port) = *attribute {
+            return port as int64_t;
+        }
+    }
+    -1
+}
+
 #[repr(C)]
 #[derive(Clone, Copy)]
 pub struct RustSdpAttributeFlags {
     pub ice_lite: bool,
     pub rtcp_mux: bool,
     pub bundle_only: bool,
     pub end_of_candidates: bool
 }
--- a/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/media_section.rs
+++ b/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/media_section.rs
@@ -173,8 +173,24 @@ pub unsafe extern "C" fn sdp_media_add_c
                      channels: Some(channels as u32),
      };
 
     match (*sdp_media).add_codec(rtpmap) {
         Ok(_) => NS_OK,
         Err(_) => NS_ERROR_INVALID_ARG,
     }
 }
+
+#[no_mangle]
+pub unsafe extern "C" fn sdp_media_add_datachannel(sdp_media: *mut SdpMedia, name: StringView,
+                                                    port: u16, streams: u16, message_size: u32)
+                                                    -> nsresult {
+    let name_str = match name.into() {
+        Ok(x) => x,
+        Err(_) => {
+            return NS_ERROR_INVALID_ARG;
+        }
+    };
+    match (*sdp_media).add_datachannel(name_str, port, streams, message_size){
+        Ok(_) => NS_OK,
+        Err(_) => NS_ERROR_INVALID_ARG
+    }
+}