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
--- 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 {