Bug 1432932: Sanity check for simulcast recv rids. r=bwc,dminor

Added Rid attribute parsing
Added C++/Rust glue code for the rid attribute
Added SdpInternalError for ParseFloatError
Added Rust unit test for parse_rid in Rust
Added U16Vec in C++/Rust glue code.
The C++ glue code no longer parses rid attributes on his own if the rust parser is used.
Reworked Simulcast parsing in rust
Added C++/rust glue code for Simulcast
Enabled CheckSimulcast c++ unit test
Added sanity check, that checks for simulcast rids that have nt been defined
Enabled ParseInvalidSimulcastNoSuchRecvRid C++ unit test
Added comments with bug number to remove redundant parsing functions.
Removed C++ unit test ParseInvalidSimulcastNoSuchPt
Added C++ unit test ParseInvalidRidNoSuchPt
Added sanity check for rid pts.

MozReview-Commit-ID: 7rvsOKIbxVP

--HG--
extra : rebase_source : abfc74e5f57b51158cf9acdf81078e5a4147fb29
This commit is contained in:
Johannes Willbold 2018-06-08 13:22:16 -07:00
parent 72fd93fa0f
commit ab3a514169
14 changed files with 716 additions and 124 deletions

View File

@ -34,6 +34,7 @@ extern "C" {
#define CRLF "\r\n"
#define SKIP_TEST_WITH_RUST_PARSER if (!::testing::get<1>(GetParam())) {return;}
#define SKIP_TEST_WITH_SIPCC_PARSER if (IsParsingWithSipccParser()) {return;}
using namespace mozilla;
@ -1905,8 +1906,9 @@ const std::string kBasicAudioVideoOffer =
"a=ssrc:1111 foo:bar" CRLF
"a=imageattr:120 send * recv *" CRLF
"a=imageattr:121 send [x=640,y=480] recv [x=640,y=480]" CRLF
"a=simulcast:recv pt=120;121" CRLF
"a=rid:bar recv pt=96;max-width=800;max-height=600" CRLF
"a=rid:bar recv pt=120;max-width=800;max-height=600" CRLF
"a=rid:bar123 recv max-width=1920;max-height=1080" CRLF
"a=simulcast:recv rid=bar;bar123" CRLF
"m=audio 9 RTP/SAVPF 0" CRLF
"a=mid:third" CRLF
"a=rtpmap:0 PCMU/8000" CRLF
@ -2895,8 +2897,7 @@ TEST_P(NewSdpTest, CheckMsid) {
ASSERT_EQ("", msids3.mMsids[0].appdata);
}
TEST_P(NewSdpTest, CheckRid)
{
TEST_P(NewSdpTest, CheckRid) {
ParseSdp(kBasicAudioVideoOffer);
ASSERT_TRUE(!!mSdp);
ASSERT_EQ(3U, mSdp->GetMediaSectionCount()) << "Wrong number of media sections";
@ -2913,13 +2914,20 @@ TEST_P(NewSdpTest, CheckRid)
const SdpRidAttributeList& rids =
mSdp->GetMediaSection(1).GetAttributeList().GetRid();
ASSERT_EQ(1U, rids.mRids.size());
ASSERT_EQ(2U, rids.mRids.size());
ASSERT_EQ("bar", rids.mRids[0].id);
ASSERT_EQ(sdp::kRecv, rids.mRids[0].direction);
ASSERT_EQ(1U, rids.mRids[0].formats.size());
ASSERT_EQ(96U, rids.mRids[0].formats[0]);
ASSERT_EQ(120U, rids.mRids[0].formats[0]);
ASSERT_EQ(800U, rids.mRids[0].constraints.maxWidth);
ASSERT_EQ(600U, rids.mRids[0].constraints.maxHeight);
ASSERT_EQ("bar123", rids.mRids[1].id);
ASSERT_EQ(sdp::kRecv, rids.mRids[1].direction);
ASSERT_EQ(0U, rids.mRids[1].formats.size());
ASSERT_EQ(1920U, rids.mRids[1].constraints.maxWidth);
ASSERT_EQ(1080U, rids.mRids[1].constraints.maxHeight);
}
TEST_P(NewSdpTest, CheckMediaLevelIceUfrag) {
@ -3217,9 +3225,7 @@ TEST_P(NewSdpTest, CheckImageattr)
ASSERT_EQ(480U, imageattr_1.recvSets[0].yRange.discreteValues.front());
}
TEST_P(NewSdpTest, CheckSimulcast)
{
SKIP_TEST_WITH_RUST_PARSER; // See Bug 1432920
TEST_P(NewSdpTest, CheckSimulcast) {
ParseSdp(kBasicAudioVideoOffer);
ASSERT_TRUE(!!mSdp);
ASSERT_EQ(3U, mSdp->GetMediaSectionCount()) << "Wrong number of media sections";
@ -3239,10 +3245,10 @@ TEST_P(NewSdpTest, CheckSimulcast)
ASSERT_EQ(2U, simulcast.recvVersions.size());
ASSERT_EQ(0U, simulcast.sendVersions.size());
ASSERT_EQ(1U, simulcast.recvVersions[0].choices.size());
ASSERT_EQ("120", simulcast.recvVersions[0].choices[0]);
ASSERT_EQ("bar", simulcast.recvVersions[0].choices[0]);
ASSERT_EQ(1U, simulcast.recvVersions[1].choices.size());
ASSERT_EQ("121", simulcast.recvVersions[1].choices[0]);
ASSERT_EQ(SdpSimulcastAttribute::Versions::kPt,
ASSERT_EQ("bar123", simulcast.recvVersions[1].choices[0]);
ASSERT_EQ(SdpSimulcastAttribute::Versions::kRid,
simulcast.recvVersions.type);
}
@ -3764,13 +3770,13 @@ TEST_P(NewSdpTest, ParseInvalidSimulcastNoSuchSendRid) {
"m=video 56436 RTP/SAVPF 120" CRLF
"a=rtpmap:120 VP8/90000" CRLF
"a=sendrecv" CRLF
"a=simulcast: send rid=9" CRLF,
"a=simulcast: send rid=9" CRLF
"a=rid:9 recv max-width=800;max-height=600" CRLF,
false);
ASSERT_NE("", GetParseErrors());
}
TEST_P(NewSdpTest, ParseInvalidSimulcastNoSuchRecvRid) {
SKIP_TEST_WITH_RUST_PARSER; // See Bug 1432932
ParseSdp("v=0" CRLF
"o=- 4294967296 2 IN IP4 127.0.0.1" CRLF
"s=SIP Call" CRLF
@ -3780,23 +3786,8 @@ TEST_P(NewSdpTest, ParseInvalidSimulcastNoSuchRecvRid) {
"m=video 56436 RTP/SAVPF 120" CRLF
"a=rtpmap:120 VP8/90000" CRLF
"a=sendrecv" CRLF
"a=simulcast: recv rid=9" CRLF,
false);
ASSERT_NE("", GetParseErrors());
}
TEST_P(NewSdpTest, ParseInvalidSimulcastNoSuchPt) {
SKIP_TEST_WITH_RUST_PARSER; // See Bug 1432933
ParseSdp("v=0" CRLF
"o=- 4294967296 2 IN IP4 127.0.0.1" CRLF
"s=SIP Call" CRLF
"c=IN IP4 198.51.100.7" CRLF
"b=CT:5000" CRLF
"t=0 0" CRLF
"m=video 56436 RTP/SAVPF 120" CRLF
"a=rtpmap:120 VP8/90000" CRLF
"a=sendrecv" CRLF
"a=simulcast: send pt=9" CRLF,
"a=simulcast: recv rid=9" CRLF
"a=rid:9 send max-width=800;max-height=600" CRLF,
false);
ASSERT_NE("", GetParseErrors());
}
@ -3811,7 +3802,7 @@ TEST_P(NewSdpTest, ParseInvalidSimulcastNotSending) {
"m=video 56436 RTP/SAVPF 120" CRLF
"a=rtpmap:120 VP8/90000" CRLF
"a=recvonly" CRLF
"a=simulcast: send pt=120" CRLF,
"a=simulcast: send rid=120" CRLF,
false);
ASSERT_NE("", GetParseErrors());
}
@ -3826,7 +3817,24 @@ TEST_P(NewSdpTest, ParseInvalidSimulcastNotReceiving) {
"m=video 56436 RTP/SAVPF 120" CRLF
"a=rtpmap:120 VP8/90000" CRLF
"a=sendonly" CRLF
"a=simulcast: recv pt=120" CRLF,
"a=simulcast: recv rid=120" CRLF,
false);
ASSERT_NE("", GetParseErrors());
}
TEST_P(NewSdpTest, ParseInvalidRidNoSuchPt) {
SKIP_TEST_WITH_SIPCC_PARSER
ParseSdp("v=0" CRLF
"o=- 4294967296 2 IN IP4 127.0.0.1" CRLF
"s=SIP Call" CRLF
"c=IN IP4 198.51.100.7" CRLF
"b=CT:5000" CRLF
"t=0 0" CRLF
"m=video 56436 RTP/SAVPF 120" CRLF
"a=rtpmap:120 VP8/90000" CRLF
"a=sendrecv" CRLF
"a=simulcast: recv rid=9" CRLF
"a=rid:9 recv pt=101;max-width=800;max-height=600" CRLF,
false);
ASSERT_NE("", GetParseErrors());
}
@ -4983,18 +4991,18 @@ TEST(NewSdpTestNoFixture, CheckSimulcastSerialize)
std::ostringstream os;
SdpSimulcastAttribute simulcast;
simulcast.recvVersions.type = SdpSimulcastAttribute::Versions::kPt;
simulcast.recvVersions.type = SdpSimulcastAttribute::Versions::kRid;
simulcast.recvVersions.push_back(SdpSimulcastAttribute::Version());
simulcast.recvVersions.back().choices.push_back("8");
simulcast.Serialize(os);
ASSERT_EQ("a=simulcast: recv pt=8" CRLF, os.str());
ASSERT_EQ("a=simulcast: recv rid=8" CRLF, os.str());
os.str("");
simulcast.sendVersions.type = SdpSimulcastAttribute::Versions::kRid;
simulcast.sendVersions.push_back(SdpSimulcastAttribute::Version());
simulcast.sendVersions.back().choices.push_back("9");
simulcast.Serialize(os);
ASSERT_EQ("a=simulcast: send rid=9 recv pt=8" CRLF, os.str());
os.str("");
ASSERT_EQ("a=simulcast: send rid=9 recv rid=8" CRLF, os.str());
}
static SdpSimulcastAttribute

View File

@ -478,6 +478,9 @@ RsdparsaSdpAttributeList::LoadAttribute(RustAttributeList *attributeList,
case SdpAttribute::kExtmapAttribute:
LoadExtmap(attributeList);
return;
case SdpAttribute::kSimulcastAttribute:
LoadSimulcast(attributeList);
return;
case SdpAttribute::kDtlsMessageAttribute:
case SdpAttribute::kLabelAttribute:
@ -487,7 +490,6 @@ RsdparsaSdpAttributeList::LoadAttribute(RustAttributeList *attributeList,
case SdpAttribute::kRtcpRsizeAttribute:
case SdpAttribute::kSctpPortAttribute:
case SdpAttribute::kCandidateAttribute:
case SdpAttribute::kSimulcastAttribute:
case SdpAttribute::kConnectionAttribute:
case SdpAttribute::kIceMismatchAttribute:
// TODO: Not implemented, or not applicable.
@ -950,6 +952,57 @@ RsdparsaSdpAttributeList::LoadRtcpFb(RustAttributeList* attributeList)
SetAttribute(rtcpfbList.release());
}
SdpSimulcastAttribute::Versions
LoadSimulcastVersions(const RustSdpAttributeSimulcastVersionVec*
rustVersionList)
{
size_t rustVersionCount = sdp_simulcast_get_version_count(rustVersionList);
auto rustVersionArray = MakeUnique<RustSdpAttributeSimulcastVersion[]>
(rustVersionCount);
sdp_simulcast_get_versions(rustVersionList, rustVersionCount,
rustVersionArray.get());
SdpSimulcastAttribute::Versions versions;
versions.type = SdpSimulcastAttribute::Versions::kRid;
for(size_t i = 0; i < rustVersionCount; i++) {
const RustSdpAttributeSimulcastVersion& rustVersion = rustVersionArray[i];
size_t rustIdCount = sdp_simulcast_get_ids_count(rustVersion.ids);
if (!rustIdCount) {
continue;
}
SdpSimulcastAttribute::Version version;
auto rustIdArray = MakeUnique<RustSdpAttributeSimulcastId[]>(rustIdCount);
sdp_simulcast_get_ids(rustVersion.ids, rustIdCount, rustIdArray.get());
for(size_t j = 0; j < rustIdCount; j++){
const RustSdpAttributeSimulcastId& rustId = rustIdArray[j];
std::string id = convertStringView(rustId.id);
// TODO: Bug 1225877. Added support for 'paused'-state
version.choices.push_back(id);
}
versions.push_back(version);
}
return versions;
}
void
RsdparsaSdpAttributeList::LoadSimulcast(RustAttributeList* attributeList)
{
RustSdpAttributeSimulcast rustSimulcast;
if (NS_SUCCEEDED(sdp_get_simulcast(attributeList, &rustSimulcast))) {
auto simulcast = MakeUnique<SdpSimulcastAttribute>();
simulcast->sendVersions = LoadSimulcastVersions(rustSimulcast.send);
simulcast->recvVersions = LoadSimulcastVersions(rustSimulcast.recv);
SetAttribute(simulcast.release());
}
}
void
RsdparsaSdpAttributeList::LoadImageattr(RustAttributeList* attributeList)
{
@ -1044,19 +1097,32 @@ RsdparsaSdpAttributeList::LoadRids(RustAttributeList* attributeList)
if (numRids == 0) {
return;
}
auto rustRids = MakeUnique<StringView[]>(numRids);
sdp_get_rids(attributeList, numRids,
rustRids.get());
auto rids = MakeUnique<SdpRidAttributeList>();
auto rustRids = MakeUnique<RustSdpAttributeRid[]>(numRids);
sdp_get_rids(attributeList, numRids, rustRids.get());
auto ridList = MakeUnique<SdpRidAttributeList>();
for(size_t i = 0; i < numRids; i++) {
std::string rid = convertStringView(rustRids[i]);
std::string error;
size_t errorPos;
if (!rids->PushEntry(rid, &error, &errorPos)) {
// TODO: handle error, see Bug 1438237
}
const RustSdpAttributeRid& rid = rustRids[i];
std::string id = convertStringView(rid.id);
auto direction = static_cast<sdp::Direction>(rid.direction);
std::vector<uint16_t> formats = convertU16Vec(rid.formats);
EncodingConstraints parameters;
parameters.maxWidth = rid.params.max_width;
parameters.maxHeight = rid.params.max_height;
parameters.maxFps = rid.params.max_fps;
parameters.maxFs = rid.params.max_fs;
parameters.maxBr = rid.params.max_br;
parameters.maxPps = rid.params.max_pps;
std::vector<std::string> depends = convertStringVec(rid.depends);
ridList->PushEntry(id, direction, formats, parameters, depends);
}
SetAttribute(rids.release());
SetAttribute(ridList.release());
}
void

View File

@ -136,6 +136,7 @@ private:
void LoadGroup(RustAttributeList* attributeList);
void LoadRtcp(RustAttributeList* attributeList);
void LoadRtcpFb(RustAttributeList* attributeList);
void LoadSimulcast(RustAttributeList* attributeList);
void LoadImageattr(RustAttributeList* attributeList);
void LoadSctpmaps(RustAttributeList* attributeList);
void LoadDirection(RustAttributeList* attributeList);

View File

@ -59,4 +59,18 @@ std::vector<uint8_t> convertU8Vec(U8Vec* vec)
return ret;
}
std::vector<uint16_t> convertU16Vec(U16Vec* vec)
{
std::vector<std::uint16_t> ret;
size_t len = u16_vec_len(vec);
for (size_t i = 0; i < len; i++) {
uint16_t word;
u16_vec_get(vec, i, &word);
ret.push_back(word);
}
return ret;
}
}

View File

@ -25,6 +25,7 @@ std::string convertStringView(StringView str);
std::vector<std::string> convertStringVec(StringVec* vec);
sdp::AddrType convertAddressType(RustSdpAddrType addr);
std::vector<uint8_t> convertU8Vec(U8Vec* vec);
std::vector<uint16_t> convertU16Vec(U16Vec* vec);
}

View File

@ -19,6 +19,7 @@ struct RustAttributeList;
struct StringVec;
struct U8Vec;
struct U32Vec;
struct U16Vec;
struct RustHeapString;
enum class RustSdpAddrType {
@ -102,6 +103,24 @@ struct RustSdpAttributeRtcpFb {
StringView extra;
};
struct RustSdpAttributeRidParameters {
uint32_t max_width;
uint32_t max_height;
uint32_t max_fps;
uint32_t max_fs;
uint32_t max_br;
uint32_t max_pps;
StringVec* unknown;
};
struct RustSdpAttributeRid {
StringView id;
uint32_t direction;
U16Vec* formats;
RustSdpAttributeRidParameters params;
StringVec* depends;
};
struct RustSdpAttributeFmtpParameters {
// H264
uint32_t packetization_mode;
@ -182,6 +201,22 @@ struct RustSdpAttributeSctpmap {
uint32_t channels;
};
struct RustSdpAttributeSimulcastId {
StringView id;
bool paused;
};
struct RustSdpAttributeSimulcastIdVec;
struct RustSdpAttributeSimulcastVersion {
RustSdpAttributeSimulcastIdVec* ids;
};
struct RustSdpAttributeSimulcastVersionVec;
struct RustSdpAttributeSimulcast {
RustSdpAttributeSimulcastVersionVec* send;
RustSdpAttributeSimulcastVersionVec* recv;
};
enum class RustDirection {
kRustRecvonly,
kRustSendonly,
@ -213,6 +248,9 @@ nsresult string_vec_get_view(const StringVec* vec, size_t index,
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);
nsresult u16_vec_get(const U16Vec* vec, size_t index, uint16_t* ret);
size_t u8_vec_len(const U8Vec* vec);
nsresult u8_vec_get(const U8Vec* vec, size_t index, uint8_t* ret);
@ -325,6 +363,21 @@ size_t sdp_get_sctpmap_count(const RustAttributeList* aList);
void sdp_get_sctpmaps(const RustAttributeList* aList, size_t listSize,
RustSdpAttributeSctpmap* ret);
nsresult sdp_get_simulcast(const RustAttributeList* aList,
RustSdpAttributeSimulcast* ret);
size_t sdp_simulcast_get_version_count(
const RustSdpAttributeSimulcastVersionVec* aVersionList);
void sdp_simulcast_get_versions(
const RustSdpAttributeSimulcastVersionVec* aversionList,
size_t listSize,
RustSdpAttributeSimulcastVersion* ret);
size_t sdp_simulcast_get_ids_count(const RustSdpAttributeSimulcastIdVec* aAlts);
void sdp_simulcast_get_ids(const RustSdpAttributeSimulcastIdVec* aAlts,
size_t listSize,
RustSdpAttributeSimulcastId* ret);
RustDirection sdp_get_direction(const RustAttributeList* aList);
@ -335,7 +388,7 @@ void sdp_get_remote_candidates(const RustAttributeList* aList,
size_t sdp_get_rid_count(const RustAttributeList* aList);
void sdp_get_rids(const RustAttributeList* aList, size_t listSize,
StringView* ret);
RustSdpAttributeRid* ret);
size_t sdp_get_extmap_count(const RustAttributeList* aList);

View File

@ -861,6 +861,7 @@ SdpRemoteCandidatesAttribute::Serialize(std::ostream& os) const
os << CRLF;
}
// Remove this function. See Bug 1469702
bool
SdpRidAttributeList::Rid::ParseParameters(std::istream& is, std::string* error)
{
@ -923,6 +924,7 @@ SdpRidAttributeList::Rid::ParseParameters(std::istream& is, std::string* error)
return true;
}
// Remove this function. See Bug 1469702
bool
SdpRidAttributeList::Rid::ParseDepend(
std::istream& is,
@ -939,6 +941,7 @@ SdpRidAttributeList::Rid::ParseDepend(
return true;
}
// Remove this function. See Bug 1469702
bool
SdpRidAttributeList::Rid::ParseFormats(
std::istream& is,
@ -1007,6 +1010,7 @@ SdpRidAttributeList::Rid::SerializeParameters(std::ostream& os) const
}
}
// Remove this function. See Bug 1469702
bool
SdpRidAttributeList::Rid::Parse(std::istream& is, std::string* error)
{
@ -1062,6 +1066,7 @@ SdpRidAttributeList::Serialize(std::ostream& os) const
}
}
// Remove this function. See Bug 1469702
bool
SdpRidAttributeList::PushEntry(const std::string& raw,
std::string* error,
@ -1080,6 +1085,23 @@ SdpRidAttributeList::PushEntry(const std::string& raw,
return true;
}
void
SdpRidAttributeList::PushEntry(const std::string& id, sdp::Direction dir,
const std::vector<uint16_t>& formats,
const EncodingConstraints& constraints,
const std::vector<std::string>& dependIds)
{
SdpRidAttributeList::Rid rid;
rid.id = id;
rid.direction = dir;
rid.formats = formats;
rid.constraints = constraints;
rid.dependIds = dependIds;
mRids.push_back(std::move(rid));
}
void
SdpRtcpAttribute::Serialize(std::ostream& os) const
{

View File

@ -942,10 +942,15 @@ public:
direction(sdp::kSend)
{}
// Remove this function. See Bug 1469702
bool Parse(std::istream& is, std::string* error);
// Remove this function. See Bug 1469702
bool ParseParameters(std::istream& is, std::string* error);
// Remove this function. See Bug 1469702
bool ParseDepend(std::istream& is, std::string* error);
// Remove this function. See Bug 1469702
bool ParseFormats(std::istream& is, std::string* error);
void Serialize(std::ostream& os) const;
void SerializeParameters(std::ostream& os) const;
bool HasFormat(const std::string& format) const;
@ -970,8 +975,16 @@ public:
};
virtual void Serialize(std::ostream& os) const override;
// Remove this function. See Bug 1469702
bool PushEntry(const std::string& raw, std::string* error, size_t* errorPos);
void PushEntry(const std::string& id, sdp::Direction dir,
const std::vector<uint16_t>& formats,
const EncodingConstraints& constraints,
const std::vector<std::string>& dependIds);
std::vector<Rid> mRids;
};

View File

@ -6,6 +6,13 @@ use SdpType;
use error::SdpParserInternalError;
use network::{parse_nettype, parse_addrtype, parse_unicast_addr};
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature="serialize", derive(Serialize))]
pub enum SdpSingleDirection{
// This is explicitly 1 and 2 to match the defines in the C++ glue code.
Send = 1,
Recv = 2,
}
#[derive(Clone)]
#[cfg_attr(feature="serialize", derive(Serialize))]
@ -123,7 +130,7 @@ pub struct SdpAttributeSimulcastId {
}
impl SdpAttributeSimulcastId {
pub fn new(idstr: String) -> SdpAttributeSimulcastId {
pub fn new(idstr: &str) -> SdpAttributeSimulcastId {
if idstr.starts_with('~') {
SdpAttributeSimulcastId {
id: idstr[1..].to_string(),
@ -131,25 +138,25 @@ impl SdpAttributeSimulcastId {
}
} else {
SdpAttributeSimulcastId {
id: idstr,
id: idstr.to_string(),
paused: false,
}
}
}
}
#[repr(C)]
#[derive(Clone)]
#[cfg_attr(feature="serialize", derive(Serialize))]
pub struct SdpAttributeSimulcastAlternatives {
pub struct SdpAttributeSimulcastVersion {
pub ids: Vec<SdpAttributeSimulcastId>,
}
impl SdpAttributeSimulcastAlternatives {
pub fn new(idlist: String) -> SdpAttributeSimulcastAlternatives {
SdpAttributeSimulcastAlternatives {
impl SdpAttributeSimulcastVersion {
pub fn new(idlist: &str) -> SdpAttributeSimulcastVersion {
SdpAttributeSimulcastVersion {
ids: idlist
.split(',')
.map(|x| x.to_string())
.map(SdpAttributeSimulcastId::new)
.collect(),
}
@ -159,24 +166,8 @@ impl SdpAttributeSimulcastAlternatives {
#[derive(Clone)]
#[cfg_attr(feature="serialize", derive(Serialize))]
pub struct SdpAttributeSimulcast {
pub send: Vec<SdpAttributeSimulcastAlternatives>,
pub receive: Vec<SdpAttributeSimulcastAlternatives>,
}
impl SdpAttributeSimulcast {
fn parse_ids(&mut self, direction: SdpAttributeDirection, idlist: String) {
let list = idlist
.split(';')
.map(|x| x.to_string())
.map(SdpAttributeSimulcastAlternatives::new)
.collect();
// TODO prevent over-writing existing values
match direction {
SdpAttributeDirection::Recvonly => self.receive = list,
SdpAttributeDirection::Sendonly => self.send = list,
_ => (),
}
}
pub send: Vec<SdpAttributeSimulcastVersion>,
pub receive: Vec<SdpAttributeSimulcastVersion>,
}
#[derive(Clone)]
@ -331,6 +322,29 @@ pub struct SdpAttributeMsidSemantic {
pub msids: Vec<String>,
}
#[derive(Clone)]
#[cfg_attr(feature="serialize", derive(Serialize))]
pub struct SdpAttributeRidParameters{
pub max_width: u32,
pub max_height: u32,
pub max_fps: u32,
pub max_fs: u32,
pub max_br: u32,
pub max_pps: u32,
pub unknown: Vec<String>
}
#[derive(Clone)]
#[cfg_attr(feature="serialize", derive(Serialize))]
pub struct SdpAttributeRid {
pub id: String,
pub direction: SdpSingleDirection,
pub formats: Vec<u16>,
pub params: SdpAttributeRidParameters,
pub depends: Vec<String>
}
#[derive(Clone)]
#[cfg_attr(feature="serialize", derive(Serialize))]
pub struct SdpAttributeRtpmap {
@ -417,7 +431,7 @@ pub enum SdpAttribute {
Msid(SdpAttributeMsid),
MsidSemantic(SdpAttributeMsidSemantic),
Ptime(u64),
Rid(String),
Rid(SdpAttributeRid),
Recvonly,
RemoteCandidate(SdpAttributeRemoteCandidate),
Rtpmap(SdpAttributeRtpmap),
@ -614,7 +628,7 @@ impl FromStr for SdpAttribute {
"mid" => Ok(SdpAttribute::Mid(string_or_empty(val)?)),
"msid-semantic" => parse_msid_semantic(val),
"ptime" => Ok(SdpAttribute::Ptime(val.parse()?)),
"rid" => Ok(SdpAttribute::Rid(string_or_empty(val)?)),
"rid" => parse_rid(val),
"recvonly" => Ok(SdpAttribute::Recvonly),
"rtcp-mux" => Ok(SdpAttribute::RtcpMux),
"rtcp-rsize" => Ok(SdpAttribute::RtcpRsize),
@ -749,6 +763,17 @@ fn parse_payload_type(to_parse: &str) -> Result<SdpAttributePayloadType, SdpPars
})
}
fn parse_single_direction(to_parse: &str) -> Result<SdpSingleDirection, SdpParserInternalError> {
match to_parse {
"send" => Ok(SdpSingleDirection::Send),
"recv" => Ok(SdpSingleDirection::Recv),
x @ _ => Err(SdpParserInternalError::Generic(
format!("Unknown direction description found: '{:}'",x).to_string()
))
}
}
fn parse_sctp_port(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
let port = to_parse.parse()?;
if port > 65535 {
@ -1145,6 +1170,78 @@ fn parse_msid_semantic(to_parse: &str) -> Result<SdpAttribute, SdpParserInternal
Ok(SdpAttribute::MsidSemantic(semantic))
}
fn parse_rid(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
let tokens: Vec<&str> = to_parse.splitn(3, " ").collect();
if tokens.len() < 2 {
return Err(SdpParserInternalError::Generic(
"A rid attribute must at least have an id and a direction token.".to_string()
));
}
// Default initilize
let mut params = SdpAttributeRidParameters {
max_width: 0,
max_height: 0,
max_fps: 0,
max_fs: 0,
max_br: 0,
max_pps: 0,
unknown: Vec::new(),
};
let mut formats: Vec<u16> = Vec::new();
let mut depends: Vec<String> = Vec::new();
if let Some(param_token) = tokens.get(2) {
let mut parameters = param_token.split(";").peekable();
// The 'pt' parameter must be the first parameter if present, so it
// cannot be checked along with the other parameters below
if let Some(maybe_fmt_parameter) = parameters.clone().peek() {
if maybe_fmt_parameter.starts_with("pt=") {
let fmt_list = maybe_fmt_parameter[3..].split(",");
for fmt in fmt_list {
formats.push(fmt.trim().parse::<u16>()?);
}
parameters.next();
}
}
for param in parameters {
// TODO: Bug 1225877. Add support for params without '='
let param_value_pair: Vec<&str> = param.splitn(2,"=").collect();
if param_value_pair.len() != 2 {
return Err(SdpParserInternalError::Generic(
"A rid parameter needs to be of form 'param=value'".to_string()
));
}
match param_value_pair[0] {
"max-width" => params.max_width = param_value_pair[1].parse::<u32>()?,
"max-height" => params.max_height = param_value_pair[1].parse::<u32>()?,
"max-fps" => params.max_fps = param_value_pair[1].parse::<u32>()?,
"max-fs" => params.max_fs = param_value_pair[1].parse::<u32>()?,
"max-br" => params.max_br = param_value_pair[1].parse::<u32>()?,
"max-pps" => params.max_pps = param_value_pair[1].parse::<u32>()?,
"depends" => {
depends.extend(param_value_pair[1].split(",").map(|x| x.to_string()));
},
_ => params.unknown.push(param.to_string()),
}
}
}
Ok(SdpAttribute::Rid(SdpAttributeRid{
id: tokens[0].to_string(),
direction: parse_single_direction(tokens[1])?,
formats: formats,
params: params,
depends: depends,
}))
}
fn parse_remote_candidates(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
let mut tokens = to_parse.split_whitespace();
let component = match tokens.next() {
@ -1421,46 +1518,86 @@ fn parse_setup(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
}))
}
fn parse_simulcast_version_list(to_parse: &str) -> Result<Vec<SdpAttributeSimulcastVersion>,
SdpParserInternalError> {
let make_version_list = |to_parse: &str| {
to_parse.split(';').map(SdpAttributeSimulcastVersion::new).collect()
};
if to_parse.contains("=") {
let mut descriptor_versionlist_pair = to_parse.splitn(2,"=");
match descriptor_versionlist_pair.next().unwrap() {
// TODO Bug 1470568
"rid" => Ok(make_version_list(descriptor_versionlist_pair.next().unwrap())),
descriptor @ _ => {
return Err(SdpParserInternalError::Generic(
format!("Simulcast attribute has unknown list descriptor '{:?}'",
descriptor)
.to_string()
))
}
}
} else {
Ok(make_version_list(to_parse))
}
}
fn parse_simulcast(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
let mut tokens = to_parse.split_whitespace();
let mut token = match tokens.next() {
// TODO: Bug 1225877: Stop accepting all kinds of whitespace here, and only accept SP
let mut tokens = to_parse.trim().split_whitespace();
let first_direction = match tokens.next() {
Some(x) => parse_single_direction(x)?,
None => {
return Err(SdpParserInternalError::Generic(
"Simulcast attribute is missing send/recv value".to_string(),
))
}
Some(x) => x,
};
let mut sc = SdpAttributeSimulcast {
send: Vec::new(),
receive: Vec::new(),
let first_version_list = match tokens.next() {
Some(x) => {
parse_simulcast_version_list(x)?
},
None => {
return Err(SdpParserInternalError::Generic(
"Simulcast attribute must have an alternatives list after the direction token"
.to_string(),
));
}
};
loop {
let sendrecv = match token.to_lowercase().as_ref() {
"send" => SdpAttributeDirection::Sendonly,
"recv" => SdpAttributeDirection::Recvonly,
_ => {
let mut second_version_list = Vec::new();
if let Some(x) = tokens.next() {
if parse_single_direction(x)? == first_direction {
return Err(SdpParserInternalError::Generic(
"Simulcast attribute has defined two times the same direction".to_string()
));
}
second_version_list = match tokens.next() {
Some(x) => {
parse_simulcast_version_list(x)?
},
None => {
return Err(SdpParserInternalError::Generic(
"Unsupported send/recv value in simulcast attribute"
.to_string(),
))
format!("{:?}{:?}",
"Simulcast has defined a second direction but",
"no second list of simulcast stream versions")
.to_string()
));
}
};
match tokens.next() {
None => {
return Err(SdpParserInternalError::Generic("Simulcast attribute is missing id list"
.to_string()))
}
Some(x) => sc.parse_ids(sendrecv, x.to_string()),
};
token = match tokens.next() {
None => {
break;
}
Some(x) => x,
};
}
}
Ok(SdpAttribute::Simulcast(sc))
Ok(SdpAttribute::Simulcast(match first_direction {
SdpSingleDirection::Send => SdpAttributeSimulcast {
send: first_version_list,
receive: second_version_list,
},
SdpSingleDirection::Recv => SdpAttributeSimulcast {
send: second_version_list,
receive: first_version_list,
},
}))
}
fn parse_ssrc(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
@ -1741,10 +1878,64 @@ fn test_parse_attribute_ptime() {
#[test]
fn test_parse_attribute_rid() {
assert!(parse_attribute("rid:foo send").is_ok());
assert!(parse_attribute("rid:foo").is_ok());
let check_parse = |x| -> SdpAttributeRid {
if let Ok(SdpType::Attribute(SdpAttribute::Rid(x))) = parse_attribute(x) {
x
} else {
unreachable!();
}
};
// assert!(parse_attribute("rid:foo send").is_ok());
let mut rid = check_parse("rid:foo send");
assert_eq!(rid.id, "foo");
assert_eq!(rid.direction, SdpSingleDirection::Send);
// assert!(parse_attribute("rid:110 send pt=9").is_ok());
rid = check_parse("rid:110 send pt=9");
assert_eq!(rid.id, "110");
assert_eq!(rid.direction, SdpSingleDirection::Send);
assert_eq!(rid.formats, vec![9]);
assert!(parse_attribute("rid:foo send pt=10").is_ok());
assert!(parse_attribute("rid:110 send pt=9,10").is_ok());
assert!(parse_attribute("rid:110 send pt=9,10;max-fs=10").is_ok());
assert!(parse_attribute("rid:110 send pt=9,10;max-width=10;depends=1,2,3").is_ok());
// assert!(parse_attribute("rid:110 send pt=9,10;max-fs=10;UNKNOWN=100;depends=1,2,3").is_ok());
rid = check_parse("rid:110 send pt=9,10;max-fs=10;UNKNOWN=100;depends=1,2,3");
assert_eq!(rid.id, "110");
assert_eq!(rid.direction, SdpSingleDirection::Send);
assert_eq!(rid.formats, vec![9,10]);
assert_eq!(rid.params.max_fs, 10);
assert_eq!(rid.params.unknown, vec!["UNKNOWN=100"]);
assert_eq!(rid.depends, vec!["1","2","3"]);
assert!(parse_attribute("rid:110 send pt=9, 10;max-fs=10;UNKNOWN=100; depends=1, 2, 3").is_ok());
assert!(parse_attribute("rid:110 send max-fs=10").is_ok());
assert!(parse_attribute("rid:110 recv max-width=1920;max-height=1080").is_ok());
// assert!(parse_attribute("rid:110 recv max-fps=42;max-fs=10;max-br=3;max-pps=1000").is_ok());
rid = check_parse("rid:110 recv max-fps=42;max-fs=10;max-br=3;max-pps=1000");
assert_eq!(rid.id, "110");
assert_eq!(rid.direction, SdpSingleDirection::Recv);
assert_eq!(rid.params.max_fps, 42);
assert_eq!(rid.params.max_fs, 10);
assert_eq!(rid.params.max_br, 3);
assert_eq!(rid.params.max_pps, 1000);
assert!(parse_attribute("rid:110 recv max-mbps=420;max-cpb=3;max-dpb=3").is_ok());
assert!(parse_attribute("rid:110 recv scale-down-by=1.35;depends=1,2,3").is_ok());
assert!(parse_attribute("rid:110 recv max-width=10;depends=1,2,3").is_ok());
assert!(parse_attribute("rid:110 recv max-fs=10;UNKNOWN=100;depends=1,2,3").is_ok());
assert!(parse_attribute("rid:").is_err());
assert!(parse_attribute("rid:120 send pt=").is_err());
assert!(parse_attribute("rid:120 send pt=;max-width=10").is_err());
assert!(parse_attribute("rid:120 send pt=9;max-width=").is_err());
assert!(parse_attribute("rid:120 send pt=9;max-width=;max-width=10").is_err());
}
#[test]
@ -1873,6 +2064,8 @@ fn test_parse_attribute_simulcast() {
assert!(parse_attribute("simulcast:send").is_err());
assert!(parse_attribute("simulcast:foobar 1").is_err());
assert!(parse_attribute("simulcast:send 1 foobar 2").is_err());
// old draft 03 notation used by Firefox 55
assert!(parse_attribute("simulcast: send foo=8;10").is_err());
}
#[test]

View File

@ -1,4 +1,5 @@
use std::num::ParseIntError;
use std::num::ParseFloatError;
use std::net::AddrParseError;
use std::fmt;
use std::error;
@ -12,6 +13,7 @@ pub enum SdpParserInternalError {
Generic(String),
Unsupported(String),
Integer(ParseIntError),
Float(ParseFloatError),
Address(AddrParseError),
}
@ -27,6 +29,9 @@ impl fmt::Display for SdpParserInternalError {
SdpParserInternalError::Integer(ref error) => {
write!(f, "Integer parsing error: {}", error.description())
}
SdpParserInternalError::Float(ref error) => {
write!(f, "Float parsing error: {}", error.description())
}
SdpParserInternalError::Address(ref error) => {
write!(f, "IP address parsing error: {}", error.description())
}
@ -40,6 +45,7 @@ impl error::Error for SdpParserInternalError {
SdpParserInternalError::Generic(ref message) |
SdpParserInternalError::Unsupported(ref message) => message,
SdpParserInternalError::Integer(ref error) => error.description(),
SdpParserInternalError::Float(ref error) => error.description(),
SdpParserInternalError::Address(ref error) => error.description(),
}
}
@ -47,6 +53,7 @@ impl error::Error for SdpParserInternalError {
fn cause(&self) -> Option<&error::Error> {
match *self {
SdpParserInternalError::Integer(ref error) => Some(error),
SdpParserInternalError::Float(ref error) => Some(error),
SdpParserInternalError::Address(ref error) => Some(error),
// Can't tell much more about our internal errors
_ => None,
@ -211,6 +218,12 @@ impl From<AddrParseError> for SdpParserInternalError {
}
}
impl From<ParseFloatError> for SdpParserInternalError {
fn from(err: ParseFloatError) -> SdpParserInternalError {
SdpParserInternalError::Float(err)
}
}
#[test]
fn test_sdp_parser_error_line() {
let line1 = SdpParserError::Line {

View File

@ -16,7 +16,8 @@ pub mod media_type;
pub mod network;
pub mod unsupported_types;
use attribute_type::{SdpAttribute, SdpAttributeType, parse_attribute};
use attribute_type::{SdpAttribute, SdpSingleDirection, SdpAttributeType, parse_attribute,
SdpAttributeSimulcastVersion, SdpAttributeRid};
use error::{SdpParserInternalError, SdpParserError};
use media_type::{SdpMedia, SdpMediaLine, parse_media, parse_media_vector, SdpProtocolValue,
SdpMediaValue, SdpFormatList};
@ -552,6 +553,7 @@ fn parse_sdp_line(line: &str, line_number: usize) -> Result<SdpLine, SdpParserEr
.map_err(|e| match e {
SdpParserInternalError::Generic(..) |
SdpParserInternalError::Integer(..) |
SdpParserInternalError::Float(..) |
SdpParserInternalError::Address(..) => {
SdpParserError::Line {
error: e,
@ -619,6 +621,11 @@ fn test_parse_sdp_line_invalid_a_line() {
}
fn sanity_check_sdp_session(session: &SdpSession) -> Result<(), SdpParserError> {
let make_error = |x: &str| SdpParserError::Sequence {
message: x.to_string(),
line_number: 0,
};
if !session.has_timing() {
return Err(SdpParserError::Sequence {
message: "Missing timing type".to_string(),
@ -667,6 +674,52 @@ fn sanity_check_sdp_session(session: &SdpSession) -> Result<(), SdpParserError>
}
}
}
let rids:Vec<&SdpAttributeRid> = msection.get_attributes().iter().filter_map(|attr| {
match attr {
&SdpAttribute::Rid(ref rid) => Some(rid),
_ => None,
}
}).collect();
let recv_rids:Vec<&str> = rids.iter().filter_map(|rid| {
match rid.direction {
SdpSingleDirection::Recv => Some(rid.id.as_str()),
_ => None,
}
}).collect();
for rid_format in rids.iter().flat_map(|rid| &rid.formats) {
match msection.get_formats() {
&SdpFormatList::Integers(ref int_fmt) => {
if !int_fmt.contains(&(*rid_format as u32)) {
return Err(make_error("Rid pts must be declared in the media section"));
}
},
&SdpFormatList::Strings(ref str_fmt) => {
if !str_fmt.contains(&rid_format.to_string()) {
return Err(make_error("Rid pts must be declared in the media section"));
}
}
}
}
if let Some(&SdpAttribute::Simulcast(ref simulcast)) =
msection.get_attribute(SdpAttributeType::Simulcast) {
// This is already a closure as the next Bug 1432931 will require the same procedure
let check_defined_rids = |simulcast_version_list: &Vec<SdpAttributeSimulcastVersion>,
rid_ids: &[&str]| -> Result<(),SdpParserError> {
for simulcast_rid in simulcast_version_list.iter().flat_map(|x| &x.ids) {
if !rid_ids.contains(&simulcast_rid.id.as_str()) {
return Err(make_error(
"Simulcast RIDs must be defined in any rid attribute"));
}
}
Ok(())
};
check_defined_rids(&simulcast.receive, &recv_rids)?
}
}
Ok(())

View File

@ -149,7 +149,7 @@ impl SdpMedia {
pub fn get_attribute(&self, t: SdpAttributeType) -> Option<&SdpAttribute> {
self.attribute.iter().filter(|a| SdpAttributeType::from(*a) == t).next()
}
pub fn remove_codecs(&mut self) {
match self.media.formats{
SdpFormatList::Integers(_) => self.media.formats = SdpFormatList::Integers(Vec::new()),
@ -175,7 +175,11 @@ impl SdpMedia {
self.add_attribute(&SdpAttribute::Rtpmap(rtpmap))?;
Ok(())
}
}
pub fn get_attributes_of_type(&self, t: SdpAttributeType) -> Vec<&SdpAttribute> {
self.attribute.iter().filter(|a| SdpAttributeType::from(*a) == t).collect()
}
pub fn has_connection(&self) -> bool {
self.connection.is_some()

View File

@ -2,14 +2,7 @@ use std::slice;
use libc::{size_t, uint8_t, uint16_t, uint32_t, int64_t};
use rsdparsa::SdpSession;
use rsdparsa::attribute_type::{SdpAttribute, SdpAttributeType, SdpAttributePayloadType,
SdpAttributeFingerprint, SdpAttributeSetup, SdpAttributeSsrc,
SdpAttributeRtpmap, SdpAttributeFmtpParameters,
SdpAttributeMsid, SdpAttributeMsidSemantic,
SdpAttributeGroupSemantic, SdpAttributeGroup, SdpAttributeRtcp,
SdpAttributeRtcpFb, SdpAttributeSctpmap,
SdpAttributeRemoteCandidate, SdpAttributeExtmap,
SdpAttributeDirection};
use rsdparsa::attribute_type::*;
use nserror::{nsresult, NS_OK, NS_ERROR_INVALID_ARG};
use types::StringView;
@ -727,6 +720,98 @@ pub unsafe extern "C" fn sdp_get_sctpmaps(attributes: *const Vec<SdpAttribute>,
sctpmaps.copy_from_slice(attrs.as_slice());
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct RustSdpAttributeSimulcastId {
pub id: StringView,
pub paused: bool,
}
impl<'a> From<&'a SdpAttributeSimulcastId> for RustSdpAttributeSimulcastId {
fn from(other: &SdpAttributeSimulcastId) -> Self {
RustSdpAttributeSimulcastId{
id: StringView::from(other.id.as_str()),
paused: other.paused
}
}
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct RustSdpAttributeSimulcastVersion {
pub ids: *const Vec<SdpAttributeSimulcastId>
}
impl<'a> From<&'a SdpAttributeSimulcastVersion> for RustSdpAttributeSimulcastVersion {
fn from(other: &SdpAttributeSimulcastVersion) -> Self {
RustSdpAttributeSimulcastVersion {
ids: &other.ids,
}
}
}
#[no_mangle]
pub unsafe extern "C" fn sdp_simulcast_get_ids_count(ids: *const Vec<SdpAttributeSimulcastId>)
-> size_t {
(*ids).len()
}
#[no_mangle]
pub unsafe extern "C" fn sdp_simulcast_get_ids(ids: *const Vec<SdpAttributeSimulcastId>,
ret_size: size_t,
ret: *mut RustSdpAttributeSimulcastId) {
let rust_ids: Vec<_> = (*ids).iter().map(RustSdpAttributeSimulcastId::from).collect();
let ids = slice::from_raw_parts_mut(ret, ret_size);
ids.clone_from_slice(rust_ids.as_slice());
}
#[repr(C)]
pub struct RustSdpAttributeSimulcast {
pub send: *const Vec<SdpAttributeSimulcastVersion>,
pub receive: *const Vec<SdpAttributeSimulcastVersion>,
}
impl<'a> From<&'a SdpAttributeSimulcast> for RustSdpAttributeSimulcast {
fn from(other: &SdpAttributeSimulcast) -> Self {
RustSdpAttributeSimulcast {
send: &other.send,
receive: &other.receive,
}
}
}
#[no_mangle]
pub unsafe extern "C" fn sdp_simulcast_get_version_count(
version_list: *const Vec<SdpAttributeSimulcastVersion>)
-> size_t {
(*version_list).len()
}
#[no_mangle]
pub unsafe extern "C" fn sdp_simulcast_get_versions(
version_list: *const Vec<SdpAttributeSimulcastVersion>,
ret_size: size_t, ret: *mut RustSdpAttributeSimulcastVersion) {
let rust_versions_list: Vec<_> = (*version_list).iter()
.map(RustSdpAttributeSimulcastVersion::from)
.collect();
let versions = slice::from_raw_parts_mut(ret, ret_size);
versions.clone_from_slice(rust_versions_list.as_slice())
}
#[no_mangle]
pub unsafe extern "C" fn sdp_get_simulcast(attributes: *const Vec<SdpAttribute>,
ret: *mut RustSdpAttributeSimulcast) -> nsresult {
let attr = get_attribute((*attributes).as_slice(), RustSdpAttributeType::Simulcast);
if let Some(&SdpAttribute::Simulcast(ref data)) = attr {
*ret = RustSdpAttributeSimulcast::from(data);
return NS_OK;
}
NS_ERROR_INVALID_ARG
}
#[repr(C)]
#[derive(Clone, Copy)]
pub enum RustDirection {
@ -809,20 +894,69 @@ pub unsafe extern "C" fn sdp_get_remote_candidates(attributes: *const Vec<SdpAtt
}
}
#[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,
pub max_pps: uint32_t,
pub unknown:*const Vec<String>
}
impl<'a> From<&'a SdpAttributeRidParameters> for RustSdpAttributeRidParameters {
fn from(other: &SdpAttributeRidParameters) -> Self {
RustSdpAttributeRidParameters {
max_width: other.max_width,
max_height: other.max_height,
max_fps: other.max_fps,
max_fs: other.max_fs,
max_br: other.max_br,
max_pps: other.max_pps,
unknown: &other.unknown
}
}
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct RustSdpAttributeRid {
pub id: StringView,
pub direction: uint32_t,
pub formats: *const Vec<uint16_t>,
pub params: RustSdpAttributeRidParameters,
pub depends: *const Vec<String>,
}
impl<'a> From<&'a SdpAttributeRid> for RustSdpAttributeRid {
fn from(other: &SdpAttributeRid) -> Self {
RustSdpAttributeRid {
id: StringView::from(other.id.as_str()),
direction: other.direction.clone() as uint32_t,
formats: &other.formats,
params: RustSdpAttributeRidParameters::from(&other.params),
depends: &other.depends,
}
}
}
#[no_mangle]
pub unsafe extern "C" fn sdp_get_rid_count(attributes: *const Vec<SdpAttribute>) -> size_t {
count_attribute((*attributes).as_slice(), RustSdpAttributeType::Rid)
}
#[no_mangle]
pub unsafe extern "C" fn sdp_get_rids(attributes: *const Vec<SdpAttribute>, ret_size: size_t, ret_rids: *mut StringView) {
let attrs: Vec<_> = (*attributes).iter().filter_map(|x| if let SdpAttribute::Rid(ref string) = *x {
Some(StringView::from(string.as_str()))
pub unsafe extern "C" fn sdp_get_rids(attributes: *const Vec<SdpAttribute>, ret_size: size_t, ret_rids: *mut RustSdpAttributeRid) {
let attrs: Vec<_> = (*attributes).iter().filter_map(|x| if let SdpAttribute::Rid(ref data) = *x {
Some(RustSdpAttributeRid::from(data))
} else {
None
}).collect();
let rids = slice::from_raw_parts_mut(ret_rids, ret_size);
rids.copy_from_slice(attrs.as_slice());
rids.clone_from_slice(attrs.as_slice());
}
#[repr(C)]

View File

@ -1,4 +1,4 @@
use libc::{size_t, uint8_t, uint32_t};
use libc::{size_t, uint8_t, uint16_t, uint32_t};
use std::ffi::CStr;
use std::{str, slice};
use std::error::Error;
@ -94,6 +94,23 @@ pub unsafe extern "C" fn u32_vec_get(vec: *const Vec<u32>,
}
}
#[no_mangle]
pub unsafe extern "C" fn u16_vec_len(vec: *const Vec<u16>) -> size_t {
(*vec).len()
}
#[no_mangle]
pub unsafe extern "C" fn u16_vec_get(vec: *const Vec<u16>,
index: size_t,
ret: *mut uint16_t) -> nsresult {
match (*vec).get(index) {
Some(val) => {
*ret = *val;
NS_OK
},
None => NS_ERROR_INVALID_ARG
}
}
#[no_mangle]
pub unsafe extern "C" fn u8_vec_len(vec: *const Vec<u8>) -> size_t {