Bug 1476085: Added SDP candidate serialization, r=bwc,dminor
Added SDP candidate serializaton in rust
Extended Rust unit test for candidates
Added C++/Rust glue code for candidates
Added free_boxed_string_vec
MozReview-Commit-ID: CeVM2p47fQ7
--- a/media/webrtc/signaling/gtest/sdp_unittests.cpp
+++ b/media/webrtc/signaling/gtest/sdp_unittests.cpp
@@ -2818,17 +2818,16 @@ TEST_P(NewSdpTest, CheckDirections) {
mSdp->GetMediaSection(0).GetAttributeList().GetDirection());
ASSERT_EQ(SdpDirectionAttribute::kRecvonly,
mSdp->GetMediaSection(1).GetAttributeList().GetDirection());
ASSERT_EQ(SdpDirectionAttribute::kSendrecv,
mSdp->GetMediaSection(2).GetAttributeList().GetDirection());
}
TEST_P(NewSdpTest, CheckCandidates) {
- SKIP_TEST_WITH_RUST_PARSER; // See Bug 1432920
ParseSdp(kBasicAudioVideoOffer);
ASSERT_TRUE(!!mSdp) << "Parse failed: " << GetParseErrors();
ASSERT_EQ(3U, mSdp->GetMediaSectionCount()) << "Wrong number of media sections";
ASSERT_TRUE(mSdp->GetMediaSection(0).GetAttributeList().HasAttribute(
SdpAttribute::kCandidateAttribute));
auto audio_candidates =
mSdp->GetMediaSection(0).GetAttributeList().GetCandidate();
--- a/media/webrtc/signaling/src/sdp/RsdparsaSdpAttributeList.cpp
+++ b/media/webrtc/signaling/src/sdp/RsdparsaSdpAttributeList.cpp
@@ -481,21 +481,24 @@ RsdparsaSdpAttributeList::LoadAttribute(
LoadExtmap(attributeList);
return;
case SdpAttribute::kSimulcastAttribute:
LoadSimulcast(attributeList);
return;
case SdpAttribute::kMaxptimeAttribute:
LoadMaxPtime(attributeList);
return;
+ case SdpAttribute::kCandidateAttribute:
+ LoadCandidate(attributeList);
+ return;
+
case SdpAttribute::kLabelAttribute:
case SdpAttribute::kSsrcGroupAttribute:
case SdpAttribute::kRtcpRsizeAttribute:
- case SdpAttribute::kCandidateAttribute:
case SdpAttribute::kConnectionAttribute:
case SdpAttribute::kIceMismatchAttribute:
// TODO: Not implemented, or not applicable.
// Sort this out in Bug 1437165.
return;
}
}
}
@@ -1284,16 +1287,38 @@ RsdparsaSdpAttributeList::LoadMaxPtime(R
uint64_t maxPtime = 0;
nsresult nr = sdp_get_maxptime(attributeList, &maxPtime);
if (NS_SUCCEEDED(nr)) {
SetAttribute(new SdpNumberAttribute(SdpAttribute::kMaxptimeAttribute,
maxPtime));
}
}
+void
+RsdparsaSdpAttributeList::LoadCandidate(RustAttributeList* attributeList)
+{
+ size_t candidatesCount = sdp_get_candidate_count(attributeList);
+ if (!candidatesCount) {
+ return;
+ }
+
+ StringVec* rustCandidatesStrings;
+ sdp_get_candidates(attributeList, candidatesCount, &rustCandidatesStrings);
+
+ std::vector<std::string> candidatesStrings =
+ convertStringVec(rustCandidatesStrings);
+ free_boxed_string_vec(rustCandidatesStrings);
+
+ auto candidates = MakeUnique<SdpMultiStringAttribute>(
+ SdpAttribute::kCandidateAttribute);
+ candidates->mValues = candidatesStrings;
+
+ SetAttribute(candidates.release());
+}
+
bool
RsdparsaSdpAttributeList::IsAllowedHere(SdpAttribute::AttributeType type)
{
if (AtSessionLevel() && !SdpAttribute::IsAllowedAtSessionLevel(type)) {
return false;
}
if (!AtSessionLevel() && !SdpAttribute::IsAllowedAtMediaLevel(type)) {
--- a/media/webrtc/signaling/src/sdp/RsdparsaSdpAttributeList.h
+++ b/media/webrtc/signaling/src/sdp/RsdparsaSdpAttributeList.h
@@ -141,16 +141,17 @@ private:
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);
void LoadMaxPtime(RustAttributeList* attributeList);
+ void LoadCandidate(RustAttributeList* attributeList);
void WarnAboutMisplacedAttribute(SdpAttribute::AttributeType type,
uint32_t lineNumber,
SdpErrorHolder& errorHolder);
SdpAttribute* mAttributes[kNumAttributeTypes];
--- a/media/webrtc/signaling/src/sdp/RsdparsaSdpInc.h
+++ b/media/webrtc/signaling/src/sdp/RsdparsaSdpInc.h
@@ -296,16 +296,17 @@ struct RustSdpAttributeExtmap {
StringView extensionAttributes;
};
extern "C" {
size_t string_vec_len(const StringVec* vec);
nsresult string_vec_get_view(const StringVec* vec, size_t index,
StringView* str);
+nsresult free_boxed_string_vec(StringVec* vec);
size_t f32_vec_len(const F32Vec* vec);
nsresult f32_vec_get(const F32Vec* vec, size_t index, float* ret);
size_t u32_vec_len(const U32Vec* vec);
nsresult u32_vec_get(const U32Vec* vec, size_t index, uint32_t* ret);
size_t u16_vec_len(const U16Vec* vec);
@@ -454,16 +455,21 @@ void sdp_simulcast_get_ids(const RustSdp
RustDirection sdp_get_direction(const RustAttributeList* aList);
size_t sdp_get_remote_candidate_count(const RustAttributeList* aList);
void sdp_get_remote_candidates(const RustAttributeList* aList,
size_t listSize,
RustSdpAttributeRemoteCandidate* ret);
+size_t sdp_get_candidate_count(const RustAttributeList* aList);
+void sdp_get_candidates(const RustAttributeList* aLisst,
+ size_t listSize,
+ StringVec** ret);
+
size_t sdp_get_rid_count(const RustAttributeList* aList);
void sdp_get_rids(const RustAttributeList* aList, size_t listSize,
RustSdpAttributeRid* ret);
size_t sdp_get_extmap_count(const RustAttributeList* aList);
void sdp_get_extmaps(const RustAttributeList* aList, size_t listSize,
RustSdpAttributeExtmap* ret);
--- a/media/webrtc/signaling/src/sdp/rsdparsa/src/attribute_type.rs
+++ b/media/webrtc/signaling/src/sdp/rsdparsa/src/attribute_type.rs
@@ -17,40 +17,70 @@ pub enum SdpSingleDirection{
#[derive(Debug, PartialEq, Clone)]
#[cfg_attr(feature="serialize", derive(Serialize))]
pub enum SdpAttributePayloadType {
PayloadType(u8),
Wildcard, // Wildcard means "*",
}
-#[derive(Clone)]
+#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature="serialize", derive(Serialize))]
pub enum SdpAttributeCandidateTransport {
Udp,
Tcp,
}
-#[derive(Clone)]
+impl ToString for SdpAttributeCandidateTransport {
+ fn to_string(&self) -> String {
+ match *self {
+ SdpAttributeCandidateTransport::Udp => "UDP".to_string(),
+ SdpAttributeCandidateTransport::Tcp => "TCP".to_string(),
+ }
+ }
+}
+
+#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature="serialize", derive(Serialize))]
pub enum SdpAttributeCandidateType {
Host,
Srflx,
Prflx,
Relay,
}
-#[derive(Clone)]
+impl ToString for SdpAttributeCandidateType {
+ fn to_string(&self) -> String {
+ match *self {
+ SdpAttributeCandidateType::Host => "host".to_string(),
+ SdpAttributeCandidateType::Srflx => "srflx".to_string(),
+ SdpAttributeCandidateType::Prflx => "prflx".to_string(),
+ SdpAttributeCandidateType::Relay => "relay".to_string(),
+ }
+ }
+}
+
+#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature="serialize", derive(Serialize))]
pub enum SdpAttributeCandidateTcpType {
Active,
Passive,
Simultaneous,
}
+impl ToString for SdpAttributeCandidateTcpType {
+ fn to_string(&self) -> String {
+ match *self {
+ SdpAttributeCandidateTcpType::Active => "active".to_string(),
+ SdpAttributeCandidateTcpType::Passive => "passive".to_string(),
+ SdpAttributeCandidateTcpType::Simultaneous => "so".to_string(),
+ }
+ }
+}
+
#[derive(Clone)]
#[cfg_attr(feature="serialize", derive(Serialize))]
pub struct SdpAttributeCandidate {
pub foundation: String,
pub component: u32,
pub transport: SdpAttributeCandidateTransport,
pub priority: u64,
pub address: IpAddr,
@@ -110,16 +140,46 @@ impl SdpAttributeCandidate {
self.ufrag = Some(u)
}
fn set_network_cost(&mut self, n: u32) {
self.networkcost = Some(n)
}
}
+impl ToString for SdpAttributeCandidate {
+ fn to_string(&self) -> String {
+ macro_rules! option_to_string {
+ ($fmt_str:expr, $opt:expr) => {
+ match $opt {
+ Some(ref x) => format!($fmt_str, x.to_string()),
+ None => "".to_string()
+ }
+ };
+ }
+
+ format!("candidate:{foundation} {component_id} {transport} {priority} \
+ {connection_address} {port} typ {cand_type}\
+ {rel_addr}{rel_port}{tcp_type}{generation}{ufrag}{network_cost}",
+ foundation = self.foundation,
+ component_id = self.component.to_string(),
+ transport = self.transport.to_string(),
+ priority = self.priority.to_string(),
+ connection_address = self.address.to_string(),
+ port = self.port.to_string(),
+ cand_type = self.c_type.to_string(),
+ rel_addr = option_to_string!(" raddr {}", self.raddr),
+ rel_port = option_to_string!(" rport {}", self.rport),
+ tcp_type = option_to_string!(" tcptype {}", self.tcp_type),
+ generation = option_to_string!(" generation {}", self.generation),
+ ufrag = option_to_string!(" ufrag {}", self.ufrag),
+ network_cost = option_to_string!(" network-cost {}", self.networkcost))
+ }
+}
+
#[derive(Clone)]
#[cfg_attr(feature="serialize", derive(Serialize))]
pub enum SdpAttributeDtlsMessage {
Client(String),
Server(String),
}
#[derive(Clone)]
@@ -2041,55 +2101,73 @@ fn parse_ssrc(to_parse: &str) -> Result<
};
Ok(SdpAttribute::Ssrc(ssrc))
}
pub fn parse_attribute(value: &str) -> Result<SdpType, SdpParserInternalError> {
Ok(SdpType::Attribute(value.trim().parse()?))
}
+
+#[cfg(test)]
+macro_rules! make_check_parse {
+ ($attr_type:ty, $attr_kind:path) => {
+ |attr_str: &str| -> $attr_type {
+ if let Ok(SdpType::Attribute($attr_kind(attr))) = parse_attribute(attr_str) {
+ attr
+ } else {
+ unreachable!();
+ }
+ }
+ }
+}
+
#[test]
fn test_parse_attribute_candidate() {
- assert!(parse_attribute("candidate:0 1 UDP 2122252543 172.16.156.106 49760 typ host").is_ok());
- assert!(parse_attribute("candidate:foo 1 UDP 2122252543 172.16.156.106 49760 typ host")
- .is_ok());
- assert!(parse_attribute("candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host").is_ok());
- assert!(parse_attribute("candidate:0 1 TCP 2122252543 ::1 49760 typ host").is_ok());
- assert!(parse_attribute("candidate:0 1 UDP 2122252543 172.16.156.106 49760 typ srflx").is_ok());
- assert!(parse_attribute("candidate:0 1 UDP 2122252543 172.16.156.106 49760 typ prflx").is_ok());
- assert!(parse_attribute("candidate:0 1 UDP 2122252543 172.16.156.106 49760 typ relay").is_ok());
- assert!(
- parse_attribute(
- "candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host tcptype active"
- ).is_ok()
- );
- assert!(
- parse_attribute(
- "candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host tcptype passive"
- ).is_ok()
- );
- assert!(
- parse_attribute("candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host tcptype so")
- .is_ok()
- );
- assert!(
- parse_attribute("candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host ufrag foobar")
- .is_ok()
- );
- assert!(
- parse_attribute(
- "candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host network-cost 50"
- ).is_ok()
- );
- assert!(parse_attribute("candidate:1 1 UDP 1685987071 24.23.204.141 54609 typ srflx raddr 192.168.1.4 rport 61665 generation 0").is_ok());
- assert!(parse_attribute("candidate:1 1 UDP 1685987071 24.23.204.141 54609 typ srflx raddr 192.168.1.4 rport 61665").is_ok());
- assert!(parse_attribute("candidate:1 1 TCP 1685987071 24.23.204.141 54609 typ srflx raddr 192.168.1.4 rport 61665 tcptype passive").is_ok());
- assert!(parse_attribute("candidate:1 1 TCP 1685987071 24.23.204.141 54609 typ srflx raddr 192.168.1.4 rport 61665 tcptype passive generation 1").is_ok());
- assert!(parse_attribute("candidate:1 1 TCP 1685987071 24.23.204.141 54609 typ srflx raddr 192.168.1.4 rport 61665 tcptype passive generation 1 ufrag +DGd").is_ok());
- assert!(parse_attribute("candidate:1 1 TCP 1685987071 24.23.204.141 54609 typ srflx raddr 192.168.1.4 rport 61665 tcptype passive generation 1 ufrag +DGd network-cost 1").is_ok());
+ let check_parse = make_check_parse!(SdpAttributeCandidate, SdpAttribute::Candidate);
+
+ let check_parse_and_serialize = |attr_str| {
+ let parsed = check_parse(attr_str);
+ assert_eq!(parsed.to_string(), attr_str.to_string());
+ };
+
+ check_parse_and_serialize("candidate:0 1 UDP 2122252543 172.16.156.106 49760 typ host");
+ check_parse_and_serialize("candidate:foo 1 UDP 2122252543 172.16.156.106 49760 typ host");
+ check_parse_and_serialize("candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host");
+ check_parse_and_serialize("candidate:0 1 TCP 2122252543 ::1 49760 typ host");
+ check_parse_and_serialize("candidate:0 1 UDP 2122252543 172.16.156.106 49760 typ srflx");
+ check_parse_and_serialize("candidate:0 1 UDP 2122252543 172.16.156.106 49760 typ prflx");
+ check_parse_and_serialize("candidate:0 1 UDP 2122252543 172.16.156.106 49760 typ relay");
+ check_parse_and_serialize("candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host tcptype active");
+ check_parse_and_serialize("candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host tcptype passive");
+ check_parse_and_serialize("candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host tcptype so");
+ check_parse_and_serialize("candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host ufrag foobar");
+ check_parse_and_serialize("candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host network-cost 50");
+ check_parse_and_serialize("candidate:1 1 UDP 1685987071 24.23.204.141 54609 typ srflx raddr 192.168.1.4 rport 61665 generation 0");
+ check_parse_and_serialize("candidate:1 1 UDP 1685987071 24.23.204.141 54609 typ srflx raddr 192.168.1.4 rport 61665");
+ check_parse_and_serialize("candidate:1 1 TCP 1685987071 24.23.204.141 54609 typ srflx raddr 192.168.1.4 rport 61665 tcptype passive");
+ check_parse_and_serialize("candidate:1 1 TCP 1685987071 24.23.204.141 54609 typ srflx raddr 192.168.1.4 rport 61665 tcptype passive generation 1");
+ check_parse_and_serialize("candidate:1 1 TCP 1685987071 24.23.204.141 54609 typ srflx raddr 192.168.1.4 rport 61665 tcptype passive generation 1 ufrag +DGd");
+ check_parse_and_serialize("candidate:1 1 TCP 1685987071 24.23.204.141 54609 typ srflx raddr 192.168.1.4 rport 61665 tcptype passive generation 1 ufrag +DGd network-cost 1");
+
+ let candidate = check_parse("candidate:1 1 TCP 1685987071 24.23.204.141 54609 typ srflx raddr 192.168.1.4 rport 61665 tcptype passive generation 1 ufrag +DGd network-cost 1");
+ assert_eq!(candidate.foundation, "1".to_string());
+ assert_eq!(candidate.component, 1);
+ assert_eq!(candidate.transport, SdpAttributeCandidateTransport::Tcp);
+ assert_eq!(candidate.priority, 1685987071);
+ assert_eq!(candidate.address, IpAddr::from_str("24.23.204.141").unwrap());
+ assert_eq!(candidate.port, 54609);
+ assert_eq!(candidate.c_type, SdpAttributeCandidateType::Srflx);
+ assert_eq!(candidate.raddr, Some(IpAddr::from_str("192.168.1.4").unwrap()));
+ assert_eq!(candidate.rport, Some(61665));
+ assert_eq!(candidate.tcp_type, Some(SdpAttributeCandidateTcpType::Passive));
+ assert_eq!(candidate.generation, Some(1));
+ assert_eq!(candidate.ufrag, Some("+DGd".to_string()));
+ assert_eq!(candidate.networkcost, Some(1));
+
assert!(parse_attribute("candidate:0 1 UDP 2122252543 172.16.156.106 49760 typ").is_err());
assert!(parse_attribute("candidate:0 foo UDP 2122252543 172.16.156.106 49760 typ host")
.is_err());
assert!(parse_attribute("candidate:0 1 FOO 2122252543 172.16.156.106 49760 typ host").is_err());
assert!(parse_attribute("candidate:0 1 UDP foo 172.16.156.106 49760 typ host").is_err());
assert!(parse_attribute("candidate:0 1 UDP 2122252543 172.16.156 49760 typ host").is_err());
assert!(parse_attribute("candidate:0 1 UDP 2122252543 172.16.156.106 70000 typ host").is_err());
--- a/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/attribute.rs
+++ b/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/attribute.rs
@@ -1146,16 +1146,36 @@ pub unsafe extern "C" fn sdp_get_remote_
None
});
let candidates = slice::from_raw_parts_mut(ret_candidates, ret_size);
for (source, destination) in attrs.zip(candidates) {
*destination = source
}
}
+#[no_mangle]
+pub unsafe extern "C" fn sdp_get_candidate_count(attributes: *const Vec<SdpAttribute>) -> size_t {
+ count_attribute((*attributes).as_slice(), RustSdpAttributeType::Candidate)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn sdp_get_candidates(attributes: *const Vec<SdpAttribute>, _ret_size: size_t,
+ ret: *mut *const Vec<String>) {
+ let attr_strings: Vec<String> = (*attributes).iter().filter_map( |x| {
+ if let SdpAttribute::Candidate(ref attr) = *x {
+ // The serialized attribute starts with "candidate:...", this needs to be removed
+ Some(attr.to_string()[10..].to_string())
+ } else {
+ None
+ }
+ }).collect();
+
+ *ret = Box::into_raw(Box::from(attr_strings));
+}
+
#[repr(C)]
#[derive(Clone, Copy)]
pub struct RustSdpAttributeRidParameters {
pub max_width: uint32_t,
pub max_height: uint32_t,
pub max_fps: uint32_t,
pub max_fs: uint32_t,
pub max_br: uint32_t,
--- a/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/types.rs
+++ b/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/types.rs
@@ -72,16 +72,22 @@ pub unsafe extern "C" fn string_vec_get_
*ret = StringView::from(string.as_str());
NS_OK
},
None => NS_ERROR_INVALID_ARG
}
}
#[no_mangle]
+pub unsafe extern "C" fn free_boxed_string_vec(ptr: *mut Vec<String>) -> nsresult {
+ drop(Box::from_raw(ptr));
+ NS_OK
+}
+
+#[no_mangle]
pub unsafe extern "C" fn f32_vec_len(vec: *const Vec<f32>) -> size_t {
(*vec).len()
}
#[no_mangle]
pub unsafe extern "C" fn f32_vec_get(vec: *const Vec<f32>,
index: size_t,
ret: *mut f32) -> nsresult {