mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 07:42:04 +00:00
Bug 1095218 - Part 1: msid support. r=mt
--HG-- extra : rebase_source : 85f8a97d16496f2b00ea049ebe29d41becd15a62
This commit is contained in:
parent
7f1b16e03a
commit
d02c39d11f
@ -32,15 +32,10 @@ function theTest() {
|
||||
});
|
||||
test.setMediaConstraints([{
|
||||
audio: true,
|
||||
peerIdentity: id2
|
||||
}, {
|
||||
video: true,
|
||||
peerIdentity: id2
|
||||
}], [{
|
||||
audio: true,
|
||||
fake: true,
|
||||
peerIdentity: id1
|
||||
}, {
|
||||
video: true,
|
||||
fake: true,
|
||||
peerIdentity: id1
|
||||
|
@ -236,6 +236,9 @@ JsepSessionImpl::AddOfferMSectionsByType(SdpMediaSection::MediaType mediatype,
|
||||
|
||||
AddLocalSsrcs(*track->mTrack,
|
||||
&sdp->GetMediaSection(*track->mAssignedMLine));
|
||||
|
||||
AddLocalIds(*track->mTrack,
|
||||
&sdp->GetMediaSection(*track->mAssignedMLine));
|
||||
}
|
||||
|
||||
while (offerToReceive.isSome() && added < *offerToReceive) {
|
||||
@ -268,6 +271,133 @@ JsepSessionImpl::SetupBundle(Sdp* sdp) const
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
JsepSessionImpl::SetupMsidSemantic(const std::vector<std::string>& msids,
|
||||
Sdp* sdp) const
|
||||
{
|
||||
if (!msids.empty()) {
|
||||
UniquePtr<SdpMsidSemanticAttributeList> msidSemantics(
|
||||
new SdpMsidSemanticAttributeList);
|
||||
msidSemantics->PushEntry("WMS", msids);
|
||||
sdp->GetAttributeList().SetAttribute(msidSemantics.release());
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
JsepSessionImpl::GetIdsFromMsid(const Sdp& sdp,
|
||||
const SdpMediaSection& msection,
|
||||
std::string* streamId,
|
||||
std::string* trackId)
|
||||
{
|
||||
if (!sdp.GetAttributeList().HasAttribute(
|
||||
SdpAttribute::kMsidSemanticAttribute)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
auto& msidSemantics = sdp.GetAttributeList().GetMsidSemantic().mMsidSemantics;
|
||||
std::vector<SdpMsidAttributeList::Msid> allMsids;
|
||||
nsresult rv = GetMsids(msection, &allMsids);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool allMsidsAreWebrtc = false;
|
||||
std::set<std::string> webrtcMsids;
|
||||
|
||||
for (auto i = msidSemantics.begin(); i != msidSemantics.end(); ++i) {
|
||||
if (i->semantic == "WMS") {
|
||||
for (auto j = i->msids.begin(); j != i->msids.end(); ++j) {
|
||||
if (*j == "*") {
|
||||
allMsidsAreWebrtc = true;
|
||||
} else {
|
||||
webrtcMsids.insert(*j);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
|
||||
for (auto i = allMsids.begin(); i != allMsids.end(); ++i) {
|
||||
if (allMsidsAreWebrtc || webrtcMsids.count(i->identifier)) {
|
||||
// For now, we assume that there is exactly one streamId/trackId pair
|
||||
// per m-section. Later on, we'll add handling for multiple remote tracks
|
||||
// per m-section.
|
||||
if (!found) {
|
||||
*streamId = i->identifier;
|
||||
*trackId = i->appdata;
|
||||
found = true;
|
||||
} else if ((*streamId != i->identifier) || (*trackId != i->appdata)) {
|
||||
// Bail if there are multiple stream/track ids for now
|
||||
JSEP_SET_ERROR("Found multiple different webrtc msids in m-section "
|
||||
<< msection.GetLevel() << ". The behavior here is "
|
||||
"undefined.");
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
JsepSessionImpl::GetMsids(
|
||||
const SdpMediaSection& msection,
|
||||
std::vector<SdpMsidAttributeList::Msid>* msids)
|
||||
{
|
||||
if (msection.GetAttributeList().HasAttribute(SdpAttribute::kMsidAttribute)) {
|
||||
*msids = msection.GetAttributeList().GetMsid().mMsids;
|
||||
}
|
||||
|
||||
// Can we find some additional msids in ssrc attributes?
|
||||
// (Chrome does not put plain-old msid attributes in its SDP)
|
||||
if (msection.GetAttributeList().HasAttribute(SdpAttribute::kSsrcAttribute)) {
|
||||
auto& ssrcs = msection.GetAttributeList().GetSsrc().mSsrcs;
|
||||
|
||||
for (auto i = ssrcs.begin(); i != ssrcs.end(); ++i) {
|
||||
if (i->attribute.find("msid:") == 0) {
|
||||
// Would be nice if SdpSsrcAttributeList could parse out the contained
|
||||
// attribute, but at least the parse here is simple.
|
||||
size_t streamIdStart = i->attribute.find_first_not_of(" \t", 5);
|
||||
// We do not assume the appdata token is here, since this is not
|
||||
// necessarily a webrtc msid
|
||||
if (streamIdStart == std::string::npos) {
|
||||
JSEP_SET_ERROR("Malformed source-level msid attribute: "
|
||||
<< i->attribute);
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
size_t streamIdEnd = i->attribute.find_first_of(" \t", streamIdStart);
|
||||
if (streamIdEnd == std::string::npos) {
|
||||
streamIdEnd = i->attribute.size();
|
||||
}
|
||||
|
||||
size_t trackIdStart =
|
||||
i->attribute.find_first_not_of(" \t", streamIdEnd);
|
||||
if (trackIdStart == std::string::npos) {
|
||||
trackIdStart = i->attribute.size();
|
||||
}
|
||||
|
||||
size_t trackIdEnd = i->attribute.find_first_of(" \t", trackIdStart);
|
||||
if (trackIdEnd == std::string::npos) {
|
||||
trackIdEnd = i->attribute.size();
|
||||
}
|
||||
|
||||
size_t streamIdSize = streamIdEnd - streamIdStart;
|
||||
size_t trackIdSize = trackIdEnd - trackIdStart;
|
||||
|
||||
msids->push_back({i->attribute.substr(streamIdStart, streamIdSize),
|
||||
i->attribute.substr(trackIdStart, trackIdSize)});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
JsepSessionImpl::CreateOffer(const JsepOfferOptions& options,
|
||||
std::string* offer)
|
||||
@ -395,6 +525,24 @@ JsepSessionImpl::AddLocalSsrcs(const JsepTrack& track,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
JsepSessionImpl::AddLocalIds(const JsepTrack& track,
|
||||
SdpMediaSection* msection) const
|
||||
{
|
||||
if (track.GetMediaType() == SdpMediaSection::kApplication) {
|
||||
return;
|
||||
}
|
||||
|
||||
UniquePtr<SdpMsidAttributeList> msids(new SdpMsidAttributeList);
|
||||
if (msection->GetAttributeList().HasAttribute(SdpAttribute::kMsidAttribute)) {
|
||||
msids->mMsids = msection->GetAttributeList().GetMsid().mMsids;
|
||||
}
|
||||
|
||||
msids->PushEntry(track.GetStreamId(), track.GetTrackId());
|
||||
|
||||
msection->GetAttributeList().SetAttribute(msids.release());
|
||||
}
|
||||
|
||||
JsepCodecDescription*
|
||||
JsepSessionImpl::FindMatchingCodec(const std::string& fmt,
|
||||
const SdpMediaSection& msection) const
|
||||
@ -663,6 +811,8 @@ JsepSessionImpl::CreateAnswerMSection(const JsepAnswerOptions& options,
|
||||
|
||||
AddLocalSsrcs(*track->mTrack, msection);
|
||||
|
||||
AddLocalIds(*track->mTrack, msection);
|
||||
|
||||
localDirection = SdpDirectionAttribute::kSendonly;
|
||||
track->mAssignedMLine = Some(mlineIndex);
|
||||
found = true;
|
||||
@ -1462,7 +1612,7 @@ JsepSessionImpl::SetRemoteTracksFromDescription(const Sdp& remoteDescription)
|
||||
// TODO(bug 1017888): Suppress new track creation on renegotiation
|
||||
// of existing tracks.
|
||||
if (direction & SdpDirectionAttribute::kSendFlag) {
|
||||
nsresult rv = CreateReceivingTrack(i, msection);
|
||||
nsresult rv = CreateReceivingTrack(i, remoteDescription, msection);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
@ -1521,20 +1671,31 @@ JsepSessionImpl::ValidateLocalDescription(const Sdp& description)
|
||||
|
||||
nsresult
|
||||
JsepSessionImpl::CreateReceivingTrack(size_t mline,
|
||||
const Sdp& sdp,
|
||||
const SdpMediaSection& msection)
|
||||
{
|
||||
std::string streamId;
|
||||
std::string trackId;
|
||||
|
||||
// Generate random track ids.
|
||||
// TODO(bug 1095218): Pull track and stream IDs out of SDP if available.
|
||||
if (!mUuidGen->Generate(&trackId)) {
|
||||
JSEP_SET_ERROR("Failed to generate UUID for JsepTrack");
|
||||
return NS_ERROR_FAILURE;
|
||||
nsresult rv = GetIdsFromMsid(sdp, msection, &streamId, &trackId);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
if (rv != NS_ERROR_NOT_AVAILABLE) {
|
||||
// Malformed ssrc attribute, probably
|
||||
return rv;
|
||||
}
|
||||
|
||||
streamId = mDefaultRemoteStreamId;
|
||||
|
||||
// Generate random track ids.
|
||||
if (!mUuidGen->Generate(&trackId)) {
|
||||
JSEP_SET_ERROR("Failed to generate UUID for JsepTrack");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
JsepTrack* remote = new JsepTrack(msection.GetMediaType(),
|
||||
mDefaultRemoteStreamId,
|
||||
streamId,
|
||||
trackId,
|
||||
JsepTrack::kJsepTrackReceiving);
|
||||
|
||||
@ -1590,6 +1751,12 @@ JsepSessionImpl::CreateGenericSDP(UniquePtr<Sdp>* sdpp)
|
||||
iceOpts->PushEntry("trickle");
|
||||
sdp->GetAttributeList().SetAttribute(iceOpts);
|
||||
|
||||
// This assumes content doesn't add a bunch of msid attributes with a
|
||||
// different semantic in mind.
|
||||
std::vector<std::string> msids;
|
||||
msids.push_back("*");
|
||||
SetupMsidSemantic(msids, sdp.get());
|
||||
|
||||
*sdpp = Move(sdp);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -210,6 +210,7 @@ private:
|
||||
void AddExtmap(SdpMediaSection* msection) const;
|
||||
void AddMid(const std::string& mid, SdpMediaSection* msection) const;
|
||||
void AddLocalSsrcs(const JsepTrack& track, SdpMediaSection* msection) const;
|
||||
void AddLocalIds(const JsepTrack& track, SdpMediaSection* msection) const;
|
||||
JsepCodecDescription* FindMatchingCodec(
|
||||
const std::string& pt,
|
||||
const SdpMediaSection& msection) const;
|
||||
@ -231,7 +232,9 @@ private:
|
||||
nsresult ValidateLocalDescription(const Sdp& description);
|
||||
nsresult SetRemoteTracksFromDescription(const Sdp& remoteDescription);
|
||||
// Non-const because we use our Uuid generator
|
||||
nsresult CreateReceivingTrack(size_t mline, const SdpMediaSection& msection);
|
||||
nsresult CreateReceivingTrack(size_t mline,
|
||||
const Sdp& sdp,
|
||||
const SdpMediaSection& msection);
|
||||
nsresult HandleNegotiatedSession(const UniquePtr<Sdp>& local,
|
||||
const UniquePtr<Sdp>& remote);
|
||||
nsresult DetermineSendingDirection(SdpDirectionAttribute::Direction offer,
|
||||
@ -244,6 +247,13 @@ private:
|
||||
Maybe<size_t> offerToReceive,
|
||||
Sdp* sdp);
|
||||
void SetupBundle(Sdp* sdp) const;
|
||||
void SetupMsidSemantic(const std::vector<std::string>& msids, Sdp* sdp) const;
|
||||
nsresult GetIdsFromMsid(const Sdp& sdp,
|
||||
const SdpMediaSection& msection,
|
||||
std::string* streamId,
|
||||
std::string* trackId);
|
||||
nsresult GetMsids(const SdpMediaSection& msection,
|
||||
std::vector<SdpMsidAttributeList::Msid>* msids);
|
||||
nsresult CreateOfferMSection(SdpMediaSection::MediaType type,
|
||||
SdpDirectionAttribute::Direction direction,
|
||||
SdpMediaSection::Protocol proto,
|
||||
|
@ -200,12 +200,14 @@ public:
|
||||
for (uint32_t i = 0; i < tracks.Length(); i++) {
|
||||
JSErrorResult rv;
|
||||
mObserver->OnAddTrack(*tracks[i], rv);
|
||||
CSFLogInfo(logTag, "Calling OnAddTrack");
|
||||
if (rv.Failed()) {
|
||||
CSFLogError(logTag, ": OnAddTrack(%d) failed! Error: %u", i,
|
||||
static_cast<uint32_t>(rv.ErrorCode()));
|
||||
}
|
||||
}
|
||||
JSErrorResult rv;
|
||||
CSFLogInfo(logTag, "Calling OnAddStream");
|
||||
mObserver->OnAddStream(*aStream, rv);
|
||||
if (rv.Failed()) {
|
||||
CSFLogError(logTag, ": OnAddStream() failed! Error: %u", static_cast<uint32_t>(rv.ErrorCode()));
|
||||
|
@ -164,6 +164,18 @@ SdpMsidAttributeList::Serialize(std::ostream& os) const
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SdpMsidSemanticAttributeList::Serialize(std::ostream& os) const
|
||||
{
|
||||
for (auto i = mMsidSemantics.begin(); i != mMsidSemantics.end(); ++i) {
|
||||
os << "a=" << mType << ":" << i->semantic;
|
||||
for (auto j = i->msids.begin(); j != i->msids.end(); ++j) {
|
||||
os << " " << *j;
|
||||
}
|
||||
os << CRLF;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SdpRemoteCandidatesAttribute::Serialize(std::ostream& os) const
|
||||
{
|
||||
|
@ -630,6 +630,36 @@ public:
|
||||
std::vector<Msid> mMsids;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// a=msid-semantic, draft-ietf-mmusic-msid
|
||||
//-------------------------------------------------------------------------
|
||||
// msid-semantic-attr = "msid-semantic:" msid-semantic msid-list
|
||||
// msid-semantic = token ; see RFC 4566
|
||||
// msid-list = *(" " msid-id) / " *"
|
||||
class SdpMsidSemanticAttributeList : public SdpAttribute
|
||||
{
|
||||
public:
|
||||
SdpMsidSemanticAttributeList() : SdpAttribute(kMsidSemanticAttribute) {}
|
||||
|
||||
struct MsidSemantic
|
||||
{
|
||||
// TODO: Once we have some more of these, we might want to make an enum
|
||||
std::string semantic;
|
||||
std::vector<std::string> msids;
|
||||
};
|
||||
|
||||
void
|
||||
PushEntry(const std::string& semantic, const std::vector<std::string>& msids)
|
||||
{
|
||||
MsidSemantic value = {semantic, msids};
|
||||
mMsidSemantics.push_back(value);
|
||||
}
|
||||
|
||||
virtual void Serialize(std::ostream& os) const MOZ_OVERRIDE;
|
||||
|
||||
std::vector<MsidSemantic> mMsidSemantics;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// a=remote-candiate, RFC5245
|
||||
//-------------------------------------------------------------------------
|
||||
|
@ -70,7 +70,7 @@ public:
|
||||
virtual const std::string& GetLabel() const = 0;
|
||||
virtual unsigned int GetMaxptime() const = 0;
|
||||
virtual const std::string& GetMid() const = 0;
|
||||
virtual const std::string& GetMsidSemantic() const = 0;
|
||||
virtual const SdpMsidSemanticAttributeList& GetMsidSemantic() const = 0;
|
||||
virtual unsigned int GetPtime() const = 0;
|
||||
|
||||
// This is "special", because it's multiple things
|
||||
|
@ -108,8 +108,6 @@ SipccSdpAttributeList::LoadSimpleStrings(sdp_t* sdp, uint16_t level,
|
||||
errorHolder);
|
||||
LoadSimpleString(sdp, level, SDP_ATTR_IDENTITY,
|
||||
SdpAttribute::kIdentityAttribute, errorHolder);
|
||||
LoadSimpleString(sdp, level, SDP_ATTR_MSID_SEMANTIC,
|
||||
SdpAttribute::kMsidSemanticAttribute, errorHolder);
|
||||
}
|
||||
|
||||
void
|
||||
@ -547,6 +545,38 @@ SipccSdpAttributeList::LoadGroups(sdp_t* sdp, uint16_t level,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SipccSdpAttributeList::LoadMsidSemantics(sdp_t* sdp, uint16_t level,
|
||||
SdpErrorHolder& errorHolder)
|
||||
{
|
||||
auto msidSemantics = MakeUnique<SdpMsidSemanticAttributeList>();
|
||||
|
||||
for (uint16_t i = 1; i < UINT16_MAX; ++i) {
|
||||
sdp_attr_t* attr = sdp_find_attr(sdp, level, 0, SDP_ATTR_MSID_SEMANTIC, i);
|
||||
|
||||
if (!attr) {
|
||||
break;
|
||||
}
|
||||
|
||||
sdp_msid_semantic_t* msid_semantic = &(attr->attr.msid_semantic);
|
||||
std::vector<std::string> msids;
|
||||
for (size_t i = 0; i < SDP_MAX_MEDIA_STREAMS; ++i) {
|
||||
if (!msid_semantic->msids[i]) {
|
||||
break;
|
||||
}
|
||||
|
||||
msids.push_back(msid_semantic->msids[i]);
|
||||
}
|
||||
|
||||
msidSemantics->PushEntry(msid_semantic->semantic, msids);
|
||||
}
|
||||
|
||||
if (!msidSemantics->mMsidSemantics.empty()) {
|
||||
SetAttribute(msidSemantics.release());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
SipccSdpAttributeList::LoadFmtp(sdp_t* sdp, uint16_t level)
|
||||
{
|
||||
@ -829,6 +859,10 @@ SipccSdpAttributeList::Load(sdp_t* sdp, uint16_t level,
|
||||
if (!LoadGroups(sdp, level, errorHolder)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!LoadMsidSemantics(sdp, level, errorHolder)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
sdp_media_e mtype = sdp_get_media_type(sdp, level);
|
||||
if (mtype == SDP_MEDIA_APPLICATION) {
|
||||
@ -1045,14 +1079,14 @@ SipccSdpAttributeList::GetMsid() const
|
||||
return *static_cast<const SdpMsidAttributeList*>(attr);
|
||||
}
|
||||
|
||||
const std::string&
|
||||
const SdpMsidSemanticAttributeList&
|
||||
SipccSdpAttributeList::GetMsidSemantic() const
|
||||
{
|
||||
if (!HasAttribute(SdpAttribute::kMsidSemanticAttribute)) {
|
||||
return kEmptyString;
|
||||
MOZ_CRASH();
|
||||
}
|
||||
const SdpAttribute* attr = GetAttribute(SdpAttribute::kMsidSemanticAttribute);
|
||||
return static_cast<const SdpStringAttribute*>(attr)->mValue;
|
||||
return *static_cast<const SdpMsidSemanticAttributeList*>(attr);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
|
@ -69,7 +69,8 @@ public:
|
||||
virtual const std::string& GetLabel() const MOZ_OVERRIDE;
|
||||
virtual unsigned int GetMaxptime() const MOZ_OVERRIDE;
|
||||
virtual const std::string& GetMid() const MOZ_OVERRIDE;
|
||||
virtual const std::string& GetMsidSemantic() const MOZ_OVERRIDE;
|
||||
virtual const SdpMsidSemanticAttributeList& GetMsidSemantic()
|
||||
const MOZ_OVERRIDE;
|
||||
virtual unsigned int GetPtime() const MOZ_OVERRIDE;
|
||||
|
||||
virtual SdpDirectionAttribute::Direction GetDirection() const MOZ_OVERRIDE;
|
||||
@ -105,6 +106,9 @@ private:
|
||||
void LoadSetup(sdp_t* sdp, uint16_t level);
|
||||
void LoadSsrc(sdp_t* sdp, uint16_t level);
|
||||
bool LoadGroups(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder);
|
||||
bool LoadMsidSemantics(sdp_t* sdp,
|
||||
uint16_t level,
|
||||
SdpErrorHolder& errorHolder);
|
||||
void LoadFmtp(sdp_t* sdp, uint16_t level);
|
||||
void LoadMsids(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder);
|
||||
void LoadExtmap(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder);
|
||||
|
@ -556,7 +556,7 @@ typedef enum sdp_srtp_crypto_suite_t_ {
|
||||
|
||||
|
||||
/* Max number of stream ids that can be grouped together */
|
||||
#define SDP_MAX_GROUP_STREAM_ID 10
|
||||
#define SDP_MAX_MEDIA_STREAMS 10
|
||||
|
||||
|
||||
#define SDP_MAGIC_NUM 0xabcdabcd
|
||||
@ -838,9 +838,14 @@ typedef struct sdp_stream_data {
|
||||
char x_confid[SDP_MAX_STRING_LEN+1];
|
||||
sdp_group_attr_e group_attr; /* FID or LS */
|
||||
uint16_t num_group_id;
|
||||
char * group_ids[SDP_MAX_GROUP_STREAM_ID];
|
||||
char * group_ids[SDP_MAX_MEDIA_STREAMS];
|
||||
} sdp_stream_data_t;
|
||||
|
||||
typedef struct sdp_msid_semantic {
|
||||
char semantic[SDP_MAX_STRING_LEN+1];
|
||||
char * msids[SDP_MAX_MEDIA_STREAMS];
|
||||
} sdp_msid_semantic_t;
|
||||
|
||||
/*
|
||||
* a=source-filter:<filter-mode> <filter-spec>
|
||||
* <filter-spec> = <nettype> <addrtype> <dest-addr> <src_addr><src_addr>...
|
||||
@ -1009,6 +1014,7 @@ typedef struct sdp_attr {
|
||||
sdp_srtp_crypto_context_t srtp_context;
|
||||
sdp_mptime_t mptime;
|
||||
sdp_stream_data_t stream_data;
|
||||
sdp_msid_semantic_t msid_semantic;
|
||||
char unknown[SDP_MAX_STRING_LEN+1];
|
||||
sdp_source_filter_t source_filter;
|
||||
sdp_fmtp_fb_t rtcp_fb;
|
||||
|
@ -4101,7 +4101,7 @@ sdp_result_e sdp_parse_attr_group (sdp_t *sdp_p, sdp_attr_t *attr_p,
|
||||
*/
|
||||
attr_p->attr.stream_data.num_group_id =0;
|
||||
|
||||
for (i=0; i<SDP_MAX_GROUP_STREAM_ID; i++) {
|
||||
for (i=0; i<SDP_MAX_MEDIA_STREAMS; i++) {
|
||||
ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
|
||||
|
||||
if (result != SDP_SUCCESS) {
|
||||
@ -5315,6 +5315,82 @@ sdp_result_e sdp_build_attr_msid(sdp_t *sdp_p,
|
||||
return SDP_SUCCESS;
|
||||
}
|
||||
|
||||
sdp_result_e sdp_parse_attr_msid_semantic(sdp_t *sdp_p,
|
||||
sdp_attr_t *attr_p,
|
||||
const char *ptr)
|
||||
{
|
||||
sdp_result_e result;
|
||||
int i;
|
||||
|
||||
ptr = sdp_getnextstrtok(ptr,
|
||||
attr_p->attr.msid_semantic.semantic,
|
||||
sizeof(attr_p->attr.msid_semantic.semantic),
|
||||
" \t",
|
||||
&result);
|
||||
|
||||
if (result != SDP_SUCCESS) {
|
||||
sdp_parse_error(sdp_p, "%s Warning: Bad msid-semantic attribute; "
|
||||
"missing semantic",
|
||||
sdp_p->debug_str);
|
||||
sdp_p->conf_p->num_invalid_param++;
|
||||
return SDP_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
for (i = 0; i < SDP_MAX_MEDIA_STREAMS; ++i) {
|
||||
/* msid-id can be up to 64 characters long, plus null terminator */
|
||||
char temp[65];
|
||||
ptr = sdp_getnextstrtok(ptr, temp, sizeof(temp), " \t", &result);
|
||||
|
||||
if (result != SDP_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
|
||||
attr_p->attr.msid_semantic.msids[i] = cpr_strdup(temp);
|
||||
}
|
||||
|
||||
if ((result != SDP_SUCCESS) && (result != SDP_EMPTY_TOKEN)) {
|
||||
sdp_parse_error(sdp_p, "%s Warning: Bad msid-semantic attribute",
|
||||
sdp_p->debug_str);
|
||||
sdp_p->conf_p->num_invalid_param++;
|
||||
return SDP_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
|
||||
SDP_PRINT("%s Parsed a=msid-semantic, %s", sdp_p->debug_str,
|
||||
attr_p->attr.msid_semantic.semantic);
|
||||
for (i = 0; i < SDP_MAX_MEDIA_STREAMS; ++i) {
|
||||
if (!attr_p->attr.msid_semantic.msids[i]) {
|
||||
break;
|
||||
}
|
||||
|
||||
SDP_PRINT("%s ... msid %s", sdp_p->debug_str,
|
||||
attr_p->attr.msid_semantic.msids[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return SDP_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
sdp_result_e sdp_build_attr_msid_semantic(sdp_t *sdp_p,
|
||||
sdp_attr_t *attr_p,
|
||||
flex_string *fs)
|
||||
{
|
||||
int i;
|
||||
flex_string_sprintf(fs, "a=msid-semantic:%s",
|
||||
attr_p->attr.msid_semantic.semantic);
|
||||
for (i = 0; i < SDP_MAX_MEDIA_STREAMS; ++i) {
|
||||
if (!attr_p->attr.msid_semantic.msids[i]) {
|
||||
break;
|
||||
}
|
||||
|
||||
flex_string_sprintf(fs, " %s",
|
||||
attr_p->attr.msid_semantic.msids[i]);
|
||||
}
|
||||
flex_string_sprintf(fs, "\r\n");
|
||||
return SDP_SUCCESS;
|
||||
}
|
||||
|
||||
sdp_result_e sdp_parse_attr_ssrc(sdp_t *sdp_p,
|
||||
sdp_attr_t *attr_p,
|
||||
const char *ptr)
|
||||
|
@ -605,6 +605,20 @@ void sdp_copy_attr_fields (sdp_attr_t *src_attr_p, sdp_attr_t *dst_attr_p)
|
||||
}
|
||||
break;
|
||||
|
||||
case SDP_ATTR_MSID_SEMANTIC:
|
||||
sstrncpy(dst_attr_p->attr.msid_semantic.semantic,
|
||||
src_attr_p->attr.msid_semantic.semantic,
|
||||
SDP_MAX_STRING_LEN+1);
|
||||
for (i=0; i < SDP_MAX_MEDIA_STREAMS; ++i) {
|
||||
if (!src_attr_p->attr.msid_semantic.msids[i]) {
|
||||
break;
|
||||
}
|
||||
|
||||
dst_attr_p->attr.msid_semantic.msids[i] =
|
||||
cpr_strdup(src_attr_p->attr.msid_semantic.msids[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case SDP_ATTR_SOURCE_FILTER:
|
||||
dst_attr_p->attr.source_filter.mode =
|
||||
src_attr_p->attr.source_filter.mode;
|
||||
@ -1176,6 +1190,10 @@ void sdp_free_attr (sdp_attr_t *attr_p)
|
||||
for (i = 0; i < attr_p->attr.stream_data.num_group_id; i++) {
|
||||
SDP_FREE(attr_p->attr.stream_data.group_ids[i]);
|
||||
}
|
||||
} else if (attr_p->type == SDP_ATTR_MSID_SEMANTIC) {
|
||||
for (i = 0; i < SDP_MAX_MEDIA_STREAMS; ++i) {
|
||||
SDP_FREE(attr_p->attr.msid_semantic.msids[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Now free the actual attribute memory. */
|
||||
@ -1658,7 +1676,6 @@ static boolean sdp_attr_is_simple_string(sdp_attr_e attr_type) {
|
||||
(attr_type != SDP_ATTR_X_CONFID) &&
|
||||
(attr_type != SDP_ATTR_LABEL) &&
|
||||
(attr_type != SDP_ATTR_IDENTITY) &&
|
||||
(attr_type != SDP_ATTR_MSID_SEMANTIC) &&
|
||||
(attr_type != SDP_ATTR_ICE_OPTIONS)) {
|
||||
return FALSE;
|
||||
}
|
||||
@ -10305,7 +10322,7 @@ sdp_result_e sdp_set_group_num_id (void *sdp_ptr, uint16_t level,
|
||||
}
|
||||
sdp_p->conf_p->num_invalid_param++;
|
||||
return (SDP_INVALID_PARAMETER);
|
||||
} else if ((group_num_id == 0) || (group_num_id > SDP_MAX_GROUP_STREAM_ID)){
|
||||
} else if ((group_num_id == 0) || (group_num_id > SDP_MAX_MEDIA_STREAMS)){
|
||||
if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
|
||||
CSFLogError(logTag, "%s Number of group id value provided - %u is invalid",
|
||||
sdp_p->debug_str, (unsigned)group_num_id);
|
||||
@ -10388,7 +10405,7 @@ sdp_result_e sdp_set_group_id (void *sdp_ptr, uint16_t level,
|
||||
return (SDP_INVALID_PARAMETER);
|
||||
} else {
|
||||
num_group_id = attr_p->attr.stream_data.num_group_id;
|
||||
if (num_group_id == SDP_MAX_GROUP_STREAM_ID) {
|
||||
if (num_group_id == SDP_MAX_MEDIA_STREAMS) {
|
||||
if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
|
||||
CSFLogError(logTag, "%s Max number of Group Ids already defined "
|
||||
"for this group line %u", sdp_p->debug_str, (unsigned)level);
|
||||
|
@ -185,7 +185,7 @@ const sdp_attrarray_t sdp_attr[SDP_MAX_ATTR_TYPES] =
|
||||
{"msid", sizeof("msid"),
|
||||
sdp_parse_attr_msid, sdp_build_attr_msid},
|
||||
{"msid-semantic", sizeof("msid-semantic"),
|
||||
sdp_parse_attr_simple_string, sdp_build_attr_simple_string},
|
||||
sdp_parse_attr_msid_semantic, sdp_build_attr_msid_semantic},
|
||||
{"bundle-only", sizeof("bundle-only"),
|
||||
sdp_parse_attr_simple_flag, sdp_build_attr_simple_flag},
|
||||
{"end-of-candidates", sizeof("end-of-candidates"),
|
||||
|
@ -80,6 +80,12 @@ extern sdp_result_e sdp_parse_attr_msid(sdp_t *sdp_p, sdp_attr_t *attr_p,
|
||||
const char *ptr);
|
||||
extern sdp_result_e sdp_build_attr_msid(sdp_t *sdp_p, sdp_attr_t *attr_p,
|
||||
flex_string *fs);
|
||||
extern sdp_result_e sdp_parse_attr_msid_semantic(sdp_t *sdp_p,
|
||||
sdp_attr_t *attr_p,
|
||||
const char *ptr);
|
||||
extern sdp_result_e sdp_build_attr_msid_semantic(sdp_t *sdp_p,
|
||||
sdp_attr_t *attr_p,
|
||||
flex_string *fs);
|
||||
extern sdp_result_e sdp_parse_attr_ssrc(sdp_t *sdp_p, sdp_attr_t *attr_p,
|
||||
const char *ptr);
|
||||
extern sdp_result_e sdp_build_attr_ssrc(sdp_t *sdp_p, sdp_attr_t *attr_p,
|
||||
|
@ -246,6 +246,20 @@ protected:
|
||||
if (checkFlags & CHECK_TRACKS) {
|
||||
// Check that the transports exist.
|
||||
ASSERT_EQ(types.size(), mSessionOff.GetTransportCount());
|
||||
for (size_t i = 0; i < types.size(); ++i) {
|
||||
RefPtr<JsepTrack> ltrack;
|
||||
ASSERT_EQ(NS_OK, mSessionOff.GetLocalTrack(i, <rack));
|
||||
ASSERT_NE("", ltrack->GetStreamId());
|
||||
ASSERT_NE("", ltrack->GetTrackId());
|
||||
if (ltrack->GetMediaType() != SdpMediaSection::kApplication) {
|
||||
std::string msidAttr("a=msid:");
|
||||
msidAttr += ltrack->GetStreamId();
|
||||
msidAttr += " ";
|
||||
msidAttr += ltrack->GetTrackId();
|
||||
ASSERT_NE(std::string::npos, offer.find(msidAttr))
|
||||
<< "Did not find " << msidAttr << " in offer";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -265,6 +279,16 @@ protected:
|
||||
RefPtr<JsepTrack> rtrack;
|
||||
ASSERT_EQ(NS_OK, mSessionAns.GetRemoteTrack(i, &rtrack));
|
||||
ASSERT_EQ(types[i], rtrack->GetMediaType());
|
||||
ASSERT_NE("", rtrack->GetStreamId());
|
||||
ASSERT_NE("", rtrack->GetTrackId());
|
||||
if (rtrack->GetMediaType() != SdpMediaSection::kApplication) {
|
||||
std::string msidAttr("a=msid:");
|
||||
msidAttr += rtrack->GetStreamId();
|
||||
msidAttr += " ";
|
||||
msidAttr += rtrack->GetTrackId();
|
||||
ASSERT_NE(std::string::npos, offer.find(msidAttr))
|
||||
<< "Did not find " << msidAttr << " in offer";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -287,6 +311,21 @@ protected:
|
||||
ASSERT_EQ(types[i], pair->mSending->GetMediaType());
|
||||
ASSERT_TRUE(pair->mReceiving);
|
||||
ASSERT_EQ(types[i], pair->mReceiving->GetMediaType());
|
||||
ASSERT_NE("", pair->mSending->GetStreamId());
|
||||
ASSERT_NE("", pair->mSending->GetTrackId());
|
||||
// These might have been in the SDP, or might have been randomly
|
||||
// chosen by JsepSessionImpl
|
||||
ASSERT_NE("", pair->mReceiving->GetStreamId());
|
||||
ASSERT_NE("", pair->mReceiving->GetTrackId());
|
||||
|
||||
if (pair->mReceiving->GetMediaType() != SdpMediaSection::kApplication) {
|
||||
std::string msidAttr("a=msid:");
|
||||
msidAttr += pair->mSending->GetStreamId();
|
||||
msidAttr += " ";
|
||||
msidAttr += pair->mSending->GetTrackId();
|
||||
ASSERT_NE(std::string::npos, answer.find(msidAttr))
|
||||
<< "Did not find " << msidAttr << " in offer";
|
||||
}
|
||||
}
|
||||
}
|
||||
DumpTrackPairs(mSessionOff);
|
||||
@ -302,14 +341,29 @@ protected:
|
||||
|
||||
if (checkFlags & CHECK_TRACKS) {
|
||||
// Verify that the right stuff is in the tracks.
|
||||
ASSERT_EQ(types.size(), mSessionAns.GetNegotiatedTrackPairCount());
|
||||
ASSERT_EQ(types.size(), mSessionOff.GetNegotiatedTrackPairCount());
|
||||
for (size_t i = 0; i < types.size(); ++i) {
|
||||
const JsepTrackPair* pair;
|
||||
ASSERT_EQ(NS_OK, mSessionAns.GetNegotiatedTrackPair(i, &pair));
|
||||
ASSERT_EQ(NS_OK, mSessionOff.GetNegotiatedTrackPair(i, &pair));
|
||||
ASSERT_TRUE(pair->mSending);
|
||||
ASSERT_EQ(types[i], pair->mSending->GetMediaType());
|
||||
ASSERT_TRUE(pair->mReceiving);
|
||||
ASSERT_EQ(types[i], pair->mReceiving->GetMediaType());
|
||||
ASSERT_NE("", pair->mSending->GetStreamId());
|
||||
ASSERT_NE("", pair->mSending->GetTrackId());
|
||||
// These might have been in the SDP, or might have been randomly
|
||||
// chosen by JsepSessionImpl
|
||||
ASSERT_NE("", pair->mReceiving->GetStreamId());
|
||||
ASSERT_NE("", pair->mReceiving->GetTrackId());
|
||||
|
||||
if (pair->mReceiving->GetMediaType() != SdpMediaSection::kApplication) {
|
||||
std::string msidAttr("a=msid:");
|
||||
msidAttr += pair->mReceiving->GetStreamId();
|
||||
msidAttr += " ";
|
||||
msidAttr += pair->mReceiving->GetTrackId();
|
||||
ASSERT_NE(std::string::npos, answer.find(msidAttr))
|
||||
<< "Did not find " << msidAttr << " in offer";
|
||||
}
|
||||
}
|
||||
}
|
||||
DumpTrackPairs(mSessionAns);
|
||||
|
@ -1126,7 +1126,8 @@ const std::string kBasicAudioVideoOffer =
|
||||
"a=ice-pwd:e4cc12a910f106a0a744719425510e17" CRLF
|
||||
"a=ice-lite" CRLF
|
||||
"a=ice-options:trickle foo" CRLF
|
||||
"a=msid-semantic:WMS plus" CRLF
|
||||
"a=msid-semantic:WMS stream streama" CRLF
|
||||
"a=msid-semantic:foo stream" CRLF
|
||||
"a=fingerprint:sha-256 DF:2E:AC:8A:FD:0A:8E:99:BF:5D:E8:3C:E7:FA:FB:08:3B:3C:54:1D:D7:D4:05:77:A0:72:9B:14:08:6D:0F:4C" CRLF
|
||||
"a=identity:blahblahblah foo;bar" CRLF
|
||||
"a=group:BUNDLE first second" CRLF
|
||||
@ -1149,7 +1150,7 @@ const std::string kBasicAudioVideoOffer =
|
||||
"a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level" CRLF
|
||||
"a=setup:actpass" CRLF
|
||||
"a=rtcp-mux" CRLF
|
||||
"a=msid:track stream" CRLF
|
||||
"a=msid:stream track" CRLF
|
||||
"a=candidate:0 1 UDP 2130379007 10.0.0.36 62453 typ host" CRLF
|
||||
"a=candidate:2 1 UDP 1694236671 24.6.134.204 62453 typ srflx raddr 10.0.0.36 rport 62453" CRLF
|
||||
"a=candidate:3 1 UDP 100401151 162.222.183.171 49761 typ relay raddr 162.222.183.171 rport 49761" CRLF
|
||||
@ -1171,8 +1172,8 @@ const std::string kBasicAudioVideoOffer =
|
||||
"a=rtcp-fb:120 ccm fir" CRLF
|
||||
"a=setup:active" CRLF
|
||||
"a=rtcp-mux" CRLF
|
||||
"a=msid:tracka streama" CRLF
|
||||
"a=msid:trackb streamb" CRLF
|
||||
"a=msid:streama tracka" CRLF
|
||||
"a=msid:streamb trackb" CRLF
|
||||
"a=candidate:0 1 UDP 2130379007 10.0.0.36 59530 typ host" CRLF
|
||||
"a=candidate:0 2 UDP 2130379006 10.0.0.36 64378 typ host" CRLF
|
||||
"a=candidate:2 2 UDP 1694236670 24.6.134.204 64378 typ srflx raddr 10.0.0.36 rport 64378" CRLF
|
||||
@ -1426,7 +1427,7 @@ const std::string kH264AudioVideoOffer =
|
||||
"a=ice-ufrag:4a799b2e" CRLF
|
||||
"a=ice-pwd:e4cc12a910f106a0a744719425510e17" CRLF
|
||||
"a=ice-lite" CRLF
|
||||
"a=msid-semantic:WMS plus" CRLF
|
||||
"a=msid-semantic:WMS stream streama" CRLF
|
||||
"a=fingerprint:sha-256 DF:2E:AC:8A:FD:0A:8E:99:BF:5D:E8:3C:E7:FA:FB:08:3B:3C:54:1D:D7:D4:05:77:A0:72:9B:14:08:6D:0F:4C" CRLF
|
||||
"a=group:BUNDLE first second" CRLF
|
||||
"a=group:BUNDLE third" CRLF
|
||||
@ -1448,7 +1449,7 @@ const std::string kH264AudioVideoOffer =
|
||||
"a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level" CRLF
|
||||
"a=setup:actpass" CRLF
|
||||
"a=rtcp-mux" CRLF
|
||||
"a=msid:track stream" CRLF
|
||||
"a=msid:stream track" CRLF
|
||||
"a=candidate:0 1 UDP 2130379007 10.0.0.36 62453 typ host" CRLF
|
||||
"a=candidate:2 1 UDP 1694236671 24.6.134.204 62453 typ srflx raddr 10.0.0.36 rport 62453" CRLF
|
||||
"a=candidate:3 1 UDP 100401151 162.222.183.171 49761 typ relay raddr 162.222.183.171 rport 49761" CRLF
|
||||
@ -1469,8 +1470,8 @@ const std::string kH264AudioVideoOffer =
|
||||
"a=recvonly" CRLF
|
||||
"a=setup:active" CRLF
|
||||
"a=rtcp-mux" CRLF
|
||||
"a=msid:tracka streama" CRLF
|
||||
"a=msid:trackb streamb" CRLF
|
||||
"a=msid:streama tracka" CRLF
|
||||
"a=msid:streamb trackb" CRLF
|
||||
"a=candidate:0 1 UDP 2130379007 10.0.0.36 59530 typ host" CRLF
|
||||
"a=candidate:0 2 UDP 2130379006 10.0.0.36 64378 typ host" CRLF
|
||||
"a=candidate:2 2 UDP 1694236670 24.6.134.204 64378 typ srflx raddr 10.0.0.36 rport 64378" CRLF
|
||||
@ -1672,22 +1673,29 @@ TEST_P(NewSdpTest, CheckMsid) {
|
||||
ParseSdp(kBasicAudioVideoOffer);
|
||||
ASSERT_TRUE(mSdp->GetAttributeList().HasAttribute(
|
||||
SdpAttribute::kMsidSemanticAttribute));
|
||||
// note that we lose the extra pieces here
|
||||
// it's not worth it to save them until they mean something
|
||||
ASSERT_EQ("WMS", mSdp->GetAttributeList().GetMsidSemantic());
|
||||
auto semantics = mSdp->GetAttributeList().GetMsidSemantic().mMsidSemantics;
|
||||
ASSERT_EQ(2U, semantics.size());
|
||||
ASSERT_EQ("WMS", semantics[0].semantic);
|
||||
ASSERT_EQ(2U, semantics[0].msids.size());
|
||||
ASSERT_EQ("stream", semantics[0].msids[0]);
|
||||
ASSERT_EQ("streama", semantics[0].msids[1]);
|
||||
ASSERT_EQ("foo", semantics[1].semantic);
|
||||
ASSERT_EQ(1U, semantics[1].msids.size());
|
||||
ASSERT_EQ("stream", semantics[1].msids[0]);
|
||||
|
||||
|
||||
const SdpMsidAttributeList& msids1 =
|
||||
mSdp->GetMediaSection(0).GetAttributeList().GetMsid();
|
||||
ASSERT_EQ(1U, msids1.mMsids.size());
|
||||
ASSERT_EQ("track", msids1.mMsids[0].identifier);
|
||||
ASSERT_EQ("stream", msids1.mMsids[0].appdata);
|
||||
ASSERT_EQ("stream", msids1.mMsids[0].identifier);
|
||||
ASSERT_EQ("track", msids1.mMsids[0].appdata);
|
||||
const SdpMsidAttributeList& msids2 =
|
||||
mSdp->GetMediaSection(1).GetAttributeList().GetMsid();
|
||||
ASSERT_EQ(2U, msids2.mMsids.size());
|
||||
ASSERT_EQ("tracka", msids2.mMsids[0].identifier);
|
||||
ASSERT_EQ("streama", msids2.mMsids[0].appdata);
|
||||
ASSERT_EQ("trackb", msids2.mMsids[1].identifier);
|
||||
ASSERT_EQ("streamb", msids2.mMsids[1].appdata);
|
||||
ASSERT_EQ("streama", msids2.mMsids[0].identifier);
|
||||
ASSERT_EQ("tracka", msids2.mMsids[0].appdata);
|
||||
ASSERT_EQ("streamb", msids2.mMsids[1].identifier);
|
||||
ASSERT_EQ("trackb", msids2.mMsids[1].appdata);
|
||||
const SdpMsidAttributeList& msids3 =
|
||||
mSdp->GetMediaSection(2).GetAttributeList().GetMsid();
|
||||
ASSERT_EQ(1U, msids3.mMsids.size());
|
||||
|
Loading…
Reference in New Issue
Block a user