Bug 1436080: Implemented RsdparsaSdp::AddMediaSection, r=dminor draft
authorJohannes Willbold <j.willbold@mozilla.com>
Thu, 14 Jun 2018 11:20:50 -0700
changeset 808810 8efee17758cdfd4927f630c383ec281db5a6a9ef
parent 808416 257c191e7903523a1132e04460a0b2460d950809
push id113499
push userbmo:johannes.willbold@rub.de
push dateWed, 20 Jun 2018 20:26:20 +0000
reviewersdminor
bugs1436080
milestone62.0a1
Bug 1436080: Implemented RsdparsaSdp::AddMediaSection, r=dminor Implemented RsdparsaSdp::AddMediaSection Added sdp_add_media_section to Rust/C++ glue code Added SdpSession::add_media in Rust Added C++ unit test CheckAddMediaSection MozReview-Commit-ID: 8cUviY3atsb
media/webrtc/signaling/gtest/sdp_unittests.cpp
media/webrtc/signaling/src/sdp/RsdparsaSdp.cpp
media/webrtc/signaling/src/sdp/RsdparsaSdpInc.h
media/webrtc/signaling/src/sdp/rsdparsa/src/lib.rs
media/webrtc/signaling/src/sdp/rsdparsa_capi/src/lib.rs
--- a/media/webrtc/signaling/gtest/sdp_unittests.cpp
+++ b/media/webrtc/signaling/gtest/sdp_unittests.cpp
@@ -3978,16 +3978,90 @@ TEST_P(NewSdpTest, CheckClearCodecs) {
 
      mSdp->GetMediaSection(0).ClearCodecs();
 
      ASSERT_EQ(0U,mSdp->GetMediaSection(0).GetFormats().size());
      ASSERT_FALSE(mSdp->GetMediaSection(0).GetAttributeList().
                   HasAttribute(SdpAttribute::kRtpmapAttribute));
 }
 
+TEST_P(NewSdpTest, CheckAddMediaSection) {
+  ParseSdp(kBasicAudioVideoOffer);
+
+  ASSERT_TRUE(!!mSdp) << "Parse failed: " << GetParseErrors();
+  ASSERT_EQ(3U, mSdp->GetMediaSectionCount())
+    << "Wrong number of media sections";
+
+  mSdp->AddMediaSection(SdpMediaSection::kVideo,
+                        SdpDirectionAttribute::Direction::kSendrecv,
+                        58000, SdpMediaSection::kUdpDtlsSctp,sdp::kIPv4,
+                        "127.0.0.1");
+
+  ASSERT_EQ(4U, mSdp->GetMediaSectionCount())
+    << "Wrong number of media sections after adding media section";
+
+  const SdpMediaSection& newMediaSection = mSdp->GetMediaSection(3);
+
+  ASSERT_EQ(SdpMediaSection::kVideo, newMediaSection.GetMediaType());
+  ASSERT_EQ(SdpDirectionAttribute::Direction::kSendrecv,
+            newMediaSection.GetDirectionAttribute().mValue);
+  ASSERT_EQ(58000U, newMediaSection.GetPort());
+  ASSERT_EQ(SdpMediaSection::kUdpDtlsSctp, newMediaSection.GetProtocol());
+  ASSERT_EQ(sdp::kIPv4, newMediaSection.GetConnection().GetAddrType());
+  ASSERT_EQ("127.0.0.1", newMediaSection.GetConnection().GetAddress());
+
+
+  mSdp->AddMediaSection(SdpMediaSection::kAudio,
+                        SdpDirectionAttribute::Direction::kSendonly,
+                        14006, SdpMediaSection::kTcpTlsRtpSavpf, sdp::kIPv6,
+                        "2607:f8b0:4004:801::2013");
+
+  ASSERT_EQ(5U, mSdp->GetMediaSectionCount())
+    << "Wrong number of media sections after adding media section";
+
+  const SdpMediaSection& nextNewMediaSection = mSdp->GetMediaSection(4);
+
+  ASSERT_EQ(SdpMediaSection::kAudio, nextNewMediaSection.GetMediaType());
+  ASSERT_EQ(SdpDirectionAttribute::Direction::kSendonly,
+            nextNewMediaSection.GetDirectionAttribute().mValue);
+  ASSERT_EQ(14006U, nextNewMediaSection.GetPort());
+  ASSERT_EQ(SdpMediaSection::kTcpTlsRtpSavpf,
+            nextNewMediaSection.GetProtocol());
+  ASSERT_EQ(sdp::kIPv6, nextNewMediaSection.GetConnection().GetAddrType());
+  ASSERT_EQ("2607:f8b0:4004:801::2013",
+            nextNewMediaSection.GetConnection().GetAddress());
+
+  if(!IsParsingWithSipccParser()) {
+    // All following AddMediaSection calls are expected to fail
+    // SdpMediaSection::kDccpRtpAvp is expected to cause a failure
+    mSdp->AddMediaSection(SdpMediaSection::kAudio,
+                          SdpDirectionAttribute::Direction::kSendonly,
+                          14006, SdpMediaSection::kDccpRtpAvp, sdp::kIPv6,
+                          "2607:f8b0:4004:801::2013");
+    ASSERT_EQ(5U, mSdp->GetMediaSectionCount())
+      << "Wrong number of media sections after adding media section";
+
+    // sdp::kAddrTypeNone is expected to cause a failure
+    mSdp->AddMediaSection(SdpMediaSection::kAudio,
+                          SdpDirectionAttribute::Direction::kSendonly,
+                          14006, SdpMediaSection::kDtlsSctp, sdp::kAddrTypeNone,
+                          "2607:f8b0:4004:801::2013");
+    ASSERT_EQ(5U, mSdp->GetMediaSectionCount())
+      << "Wrong number of media sections after adding media section";
+
+    // "NOT:AN.IP.ADDRESS" is expected to cause a failure
+    mSdp->AddMediaSection(SdpMediaSection::kAudio,
+                          SdpDirectionAttribute::Direction::kSendonly,
+                          14006, SdpMediaSection::kTcpTlsRtpSavpf, sdp::kIPv6,
+                          "NOT:AN.IP.ADDRESS");
+    ASSERT_EQ(5U, mSdp->GetMediaSectionCount())
+      << "Wrong number of media sections after adding media section";
+  }
+}
+
 TEST(NewSdpTestNoFixture, CheckAttributeTypeSerialize) {
   for (auto a = static_cast<size_t>(SdpAttribute::kFirstAttribute);
        a <= static_cast<size_t>(SdpAttribute::kLastAttribute);
        ++a) {
 
     SdpAttribute::AttributeType type =
       static_cast<SdpAttribute::AttributeType>(a);
 
--- a/media/webrtc/signaling/src/sdp/RsdparsaSdp.cpp
+++ b/media/webrtc/signaling/src/sdp/RsdparsaSdp.cpp
@@ -3,16 +3,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "signaling/src/sdp/RsdparsaSdp.h"
 
 #include <cstdlib>
 #include "mozilla/UniquePtr.h"
 #include "mozilla/Assertions.h"
 #include "nsError.h"
+#include <iostream>
 
 
 #include "signaling/src/sdp/SdpErrorHolder.h"
 #include "signaling/src/sdp/RsdparsaSdpInc.h"
 #include "signaling/src/sdp/RsdparsaSdpMediaSection.h"
 
 #ifdef CRLF
 #undef CRLF
@@ -80,18 +81,38 @@ RsdparsaSdp::GetMediaSection(size_t leve
 
 SdpMediaSection&
 RsdparsaSdp::AddMediaSection(SdpMediaSection::MediaType mediaType,
                              SdpDirectionAttribute::Direction dir,
                              uint16_t port,
                              SdpMediaSection::Protocol protocol,
                              sdp::AddrType addrType, const std::string& addr)
 {
-  //TODO: See Bug 1436080
-  MOZ_CRASH("Method not implemented");
+  StringView rustAddr{addr.c_str(),addr.size()};
+  auto nr = sdp_add_media_section(mSession.get(),mediaType,dir,port,
+                                                 protocol,addrType,rustAddr);
+
+  if (NS_SUCCEEDED(nr)) {
+    std::cout << "Hello World" << std::endl;
+    size_t level = mMediaSections.values.size();
+    RsdparsaSessionHandle newSessHandle(sdp_new_reference(mSession.get()));
+
+    auto rustMediaSection = sdp_get_media_section(mSession.get(), level);
+    auto mediaSection = new RsdparsaSdpMediaSection(level,
+                                                    std::move(newSessHandle),
+                                                    rustMediaSection,
+                                                    mAttributeList.get());
+    mMediaSections.values.push_back(mediaSection);
+
+    return *mediaSection;
+  } else {
+    // Return the last media section if the construction of this one fails
+    return GetMediaSection(mMediaSections.values.size()-1);
+  }
+
 }
 
 void
 RsdparsaSdp::Serialize(std::ostream& os) const
 {
   os << "v=0" << CRLF << mOrigin << "s=-" << CRLF;
 
   // We don't support creating i=, u=, e=, p=
--- a/media/webrtc/signaling/src/sdp/RsdparsaSdpInc.h
+++ b/media/webrtc/signaling/src/sdp/RsdparsaSdpInc.h
@@ -236,16 +236,20 @@ char* sdp_serialize_bandwidth(const Band
 bool sdp_session_has_connection(const RustSdpSession* aSess);
 nsresult sdp_get_session_connection(const RustSdpSession* aSess,
                                     RustSdpConnection* ret);
 RustAttributeList* get_sdp_session_attributes(const RustSdpSession* aSess);
 
 size_t sdp_media_section_count(const RustSdpSession* aSess);
 RustMediaSection* sdp_get_media_section(const RustSdpSession* aSess,
                                         size_t aLevel);
+nsresult sdp_add_media_section(RustSdpSession* aSess, uint32_t aMediaType,
+                               uint32_t aDirection, uint32_t aPort,
+                               uint32_t aProtocol, uint32_t aAddrType,
+                               StringView aAddr);
 RustSdpMediaValue sdp_rust_get_media_type(const RustMediaSection* aMediaSec);
 RustSdpProtocolValue
 sdp_get_media_protocol(const RustMediaSection* aMediaSec);
 RustSdpFormatType sdp_get_format_type(const RustMediaSection* aMediaSec);
 StringVec* sdp_get_format_string_vec(const RustMediaSection* aMediaSec);
 U32Vec* sdp_get_format_u32_vec(const RustMediaSection* aMediaSec);
 void sdp_set_media_port(const RustMediaSection* aMediaSec, uint32_t aPort);
 uint32_t sdp_get_media_port(const RustMediaSection* aMediaSec);
--- a/media/webrtc/signaling/src/sdp/rsdparsa/src/lib.rs
+++ b/media/webrtc/signaling/src/sdp/rsdparsa/src/lib.rs
@@ -2,27 +2,29 @@
 
 #[cfg(feature="serialize")]
 #[macro_use]
 extern crate serde_derive;
 #[cfg(feature="serialize")]
 extern crate serde;
 
 use std::net::IpAddr;
+use std::str::FromStr;
 use std::fmt;
 
 pub mod attribute_type;
 pub mod error;
 pub mod media_type;
 pub mod network;
 pub mod unsupported_types;
 
 use attribute_type::{SdpAttribute, SdpAttributeType, parse_attribute};
 use error::{SdpParserInternalError, SdpParserError};
-use media_type::{SdpMedia, SdpMediaLine, parse_media, parse_media_vector};
+use media_type::{SdpMedia, SdpMediaLine, parse_media, parse_media_vector, SdpProtocolValue,
+                 SdpMediaValue, SdpFormatList};
 use network::{parse_addrtype, parse_nettype, parse_unicast_addr};
 use unsupported_types::{parse_email, parse_information, parse_key, parse_phone, parse_repeat,
                         parse_uri, parse_zone};
 
 #[derive(Clone)]
 #[cfg_attr(feature="serialize", derive(Serialize))]
 pub enum SdpBandwidth {
     As(u32),
@@ -177,16 +179,40 @@ impl SdpSession {
 
     pub fn get_attribute(&self, t: SdpAttributeType) -> Option<&SdpAttribute> {
        self.attribute.iter().filter(|a| SdpAttributeType::from(*a) == t).next()
     }
 
     pub fn has_media(&self) -> bool {
         !self.media.is_empty()
     }
+
+    pub fn add_media(&mut self, media_type: SdpMediaValue, direction: SdpAttribute, port: u32,
+                     protocol: SdpProtocolValue, addr: String)
+                     -> Result<(),SdpParserInternalError> {
+       let mut media = SdpMedia::new(SdpMediaLine {
+           media: media_type,
+           port,
+           port_count: 1,
+           proto: protocol,
+           formats: SdpFormatList::Integers(Vec::new()),
+       });
+
+       media.add_attribute(&direction)?;
+
+       media.set_connection(&SdpConnection {
+           addr: IpAddr::from_str(addr.as_str())?,
+           ttl: None,
+           amount: None,
+       })?;
+
+       self.media.push(media);
+
+       Ok(())
+    }
 }
 
 fn parse_session(value: &str) -> Result<SdpType, SdpParserInternalError> {
     println!("session: {}", value);
     Ok(SdpType::Session(String::from(value)))
 }
 
 #[test]
--- a/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/lib.rs
+++ b/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/lib.rs
@@ -10,17 +10,18 @@ use std::error::Error;
 
 use libc::size_t;
 
 use std::rc::Rc;
 
 use nserror::{nsresult, NS_OK, NS_ERROR_INVALID_ARG};
 use rsdparsa::{SdpTiming, SdpBandwidth, SdpSession};
 use rsdparsa::error::SdpParserError;
-use rsdparsa::attribute_type::SdpAttribute;
+use rsdparsa::media_type::{SdpMediaValue, SdpProtocolValue};
+use rsdparsa::attribute_type::{SdpAttribute};
 
 pub mod types;
 pub mod network;
 pub mod attribute;
 pub mod media_section;
 
 pub use types::{StringView, NULL_STRING};
 use network::{RustSdpOrigin, origin_view_helper, RustSdpConnection,
@@ -135,16 +136,76 @@ pub unsafe extern "C" fn sdp_get_session
         Some(ref c) => {
             *connection = RustSdpConnection::from(c);
             NS_OK
         },
         None => NS_ERROR_INVALID_ARG
     }
 }
 
+#[no_mangle]
+pub unsafe extern "C" fn sdp_add_media_section(session: *mut SdpSession,
+                                               media_type: u32, direction: u32,
+                                               port: u16, protocol: u32,
+                                               addr_type: u32, addr: StringView) -> nsresult {
+
+    let addr_str:String = match addr.into() {
+       Ok(x) => x,
+       Err(boxed_error) => {
+           println!("Error while pasing string, description: {:?}", (*boxed_error).description());
+           return NS_ERROR_INVALID_ARG;
+       }
+    };
+
+    let media_type = match media_type {
+        0 => SdpMediaValue::Audio,       // MediaType::kAudio
+        1 => SdpMediaValue::Video,       // MediaType::kVideo
+        3 => SdpMediaValue::Application, // MediaType::kApplication
+        _ => {
+         return NS_ERROR_INVALID_ARG;
+     }
+    };
+    let protocol = match protocol {
+        20 => SdpProtocolValue::RtpSavpf,        // Protocol::kRtpSavpf
+        24 => SdpProtocolValue::UdpTlsRtpSavpf,  // Protocol::kUdpTlsRtpSavpf
+        25 => SdpProtocolValue::TcpTlsRtpSavpf,  // Protocol::kTcpTlsRtpSavpf
+        37 => SdpProtocolValue::DtlsSctp,        // Protocol::kDtlsSctp
+        38 => SdpProtocolValue::UdpDtlsSctp,     // Protocol::kUdpDtlsSctp
+        39 => SdpProtocolValue::TcpDtlsSctp,     // Protocol::kTcpDtlsSctp
+        _ => {
+            println!("INVALID PROTOCOL");
+          return NS_ERROR_INVALID_ARG;
+      }
+    };
+    let direction = match direction {
+        1 => SdpAttribute::Sendonly,
+        2 => SdpAttribute::Recvonly,
+        3 => SdpAttribute::Sendrecv,
+        _ => {
+          return NS_ERROR_INVALID_ARG;
+      }
+    };
+
+    // Check that the provided address type is valid. The rust parser will find out
+    // on his own which address type was provided
+    match addr_type {
+      // enum AddrType { kAddrTypeNone, kIPv4, kIPv6 };
+      // kAddrTypeNone is explicitly not covered as it is an 'invalid' flag
+      1...2 => (),
+      _ => {
+          return NS_ERROR_INVALID_ARG;
+      }
+    }
+
+    match (*session).add_media(media_type, direction, port as u32, protocol, addr_str) {
+        Ok(_) => NS_OK,
+        Err(_) => NS_ERROR_INVALID_ARG
+    }
+}
+
 #[repr(C)]
 #[derive(Clone)]
 pub struct RustSdpTiming {
     pub start: u64,
     pub stop: u64,
 }
 
 impl<'a> From<&'a SdpTiming> for RustSdpTiming {