void SdpHelper::AddCommonExtmaps( const SdpMediaSection& remoteMsection, const std::vector<SdpExtmapAttributeList::Extmap>& localExtensions, SdpMediaSection* localMsection) { if (!remoteMsection.GetAttributeList().HasAttribute( SdpAttribute::kExtmapAttribute)) { return; } UniquePtr<SdpExtmapAttributeList> localExtmap(new SdpExtmapAttributeList); auto& theirExtmap = remoteMsection.GetAttributeList().GetExtmap().mExtmaps; for (auto i = theirExtmap.begin(); i != theirExtmap.end(); ++i) { for (auto j = localExtensions.begin(); j != localExtensions.end(); ++j) { if (i->extensionname == j->extensionname) { localExtmap->mExtmaps.push_back(*i); // RFC 5285 says that ids >= 4096 can be used by the offerer to // force the answerer to pick, otherwise the value in the offer is // used. if (localExtmap->mExtmaps.back().entry >= 4096) { localExtmap->mExtmaps.back().entry = j->entry; } } } } if (!localExtmap->mExtmaps.empty()) { localMsection->GetAttributeList().SetAttribute(localExtmap.release()); } }
nsresult SdpHelper::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) { std::string streamId; std::string trackId; nsresult rv = ParseMsid(i->attribute, &streamId, &trackId); NS_ENSURE_SUCCESS(rv, rv); msids->push_back({streamId, trackId}); } } } return NS_OK; }
std::string SdpHelper::GetCNAME(const SdpMediaSection& msection) const { 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("cname:") == 0) { return i->attribute.substr(6); } } } return ""; }
void JsepTrack::Negotiate(const SdpMediaSection& answer, const SdpMediaSection& remote) { PtrVector<JsepCodecDescription> negotiatedCodecs; negotiatedCodecs.values = GetCodecClones(); std::map<std::string, std::string> formatChanges; NegotiateCodecs(remote, &negotiatedCodecs.values, &formatChanges); // Use |formatChanges| to update mPrototypeCodecs size_t insertPos = 0; for (size_t i = 0; i < mPrototypeCodecs.values.size(); ++i) { if (formatChanges.count(mPrototypeCodecs.values[i]->mDefaultPt)) { // Update the payload type to what was negotiated mPrototypeCodecs.values[i]->mDefaultPt = formatChanges[mPrototypeCodecs.values[i]->mDefaultPt]; // Move this negotiated codec up front std::swap(mPrototypeCodecs.values[insertPos], mPrototypeCodecs.values[i]); ++insertPos; } } EnsureNoDuplicatePayloadTypes(&mPrototypeCodecs.values); UniquePtr<JsepTrackNegotiatedDetails> negotiatedDetails = MakeUnique<JsepTrackNegotiatedDetails>(); CreateEncodings(remote, negotiatedCodecs.values, negotiatedDetails.get()); if (answer.GetAttributeList().HasAttribute(SdpAttribute::kExtmapAttribute)) { for (auto& extmapAttr : answer.GetAttributeList().GetExtmap().mExtmaps) { negotiatedDetails->mExtmap[extmapAttr.extensionname] = extmapAttr; } } if (mDirection == sdp::kRecv) { mSsrcs.clear(); if (remote.GetAttributeList().HasAttribute(SdpAttribute::kSsrcAttribute)) { for (auto& ssrcAttr : remote.GetAttributeList().GetSsrc().mSsrcs) { AddSsrc(ssrcAttr.ssrc); } } } mNegotiatedDetails = Move(negotiatedDetails); }
bool SdpHelper::MsectionIsDisabled(const SdpMediaSection& msection) const { return !msection.GetPort() && !msection.GetAttributeList().HasAttribute( SdpAttribute::kBundleOnlyAttribute); }
void JsepTrack::GetRids(const SdpMediaSection& msection, sdp::Direction direction, std::vector<SdpRidAttributeList::Rid>* rids) const { rids->clear(); if (!msection.GetAttributeList().HasAttribute( SdpAttribute::kSimulcastAttribute)) { return; } const SdpSimulcastAttribute& simulcast( msection.GetAttributeList().GetSimulcast()); const SdpSimulcastAttribute::Versions* versions = nullptr; switch (direction) { case sdp::kSend: versions = &simulcast.sendVersions; break; case sdp::kRecv: versions = &simulcast.recvVersions; break; } if (!versions->IsSet()) { return; } if (versions->type != SdpSimulcastAttribute::Versions::kRid) { // No support for PT-based simulcast, yet. return; } for (const SdpSimulcastAttribute::Version& version : *versions) { if (!version.choices.empty()) { // We validate that rids are present (and sane) elsewhere. rids->push_back(*msection.FindRid(version.choices[0])); } } }
nsresult SdpHelper::CopyStickyParams(const SdpMediaSection& source, SdpMediaSection* dest) { auto& sourceAttrs = source.GetAttributeList(); auto& destAttrs = dest->GetAttributeList(); // There's no reason to renegotiate rtcp-mux if (sourceAttrs.HasAttribute(SdpAttribute::kRtcpMuxAttribute)) { destAttrs.SetAttribute( new SdpFlagAttribute(SdpAttribute::kRtcpMuxAttribute)); } // mid should stay the same if (sourceAttrs.HasAttribute(SdpAttribute::kMidAttribute)) { destAttrs.SetAttribute( new SdpStringAttribute(SdpAttribute::kMidAttribute, sourceAttrs.GetMid())); } return NS_OK; }
nsresult SdpHelper::CopyTransportParams(size_t numComponents, const SdpMediaSection& oldLocal, SdpMediaSection* newLocal) { // Copy over m-section details newLocal->SetPort(oldLocal.GetPort()); newLocal->GetConnection() = oldLocal.GetConnection(); const SdpAttributeList& oldLocalAttrs = oldLocal.GetAttributeList(); SdpAttributeList& newLocalAttrs = newLocal->GetAttributeList(); // Now we copy over attributes that won't be added by the usual logic if (oldLocalAttrs.HasAttribute(SdpAttribute::kCandidateAttribute) && numComponents) { UniquePtr<SdpMultiStringAttribute> candidateAttrs( new SdpMultiStringAttribute(SdpAttribute::kCandidateAttribute)); for (const std::string& candidate : oldLocalAttrs.GetCandidate()) { size_t component; nsresult rv = GetComponent(candidate, &component); NS_ENSURE_SUCCESS(rv, rv); if (numComponents >= component) { candidateAttrs->mValues.push_back(candidate); } } if (candidateAttrs->mValues.size()) { newLocalAttrs.SetAttribute(candidateAttrs.release()); } } if (numComponents == 2 && oldLocalAttrs.HasAttribute(SdpAttribute::kRtcpAttribute)) { // copy rtcp attribute if we had one that we are using newLocalAttrs.SetAttribute(new SdpRtcpAttribute(oldLocalAttrs.GetRtcp())); } return NS_OK; }
nsresult SdpHelper::AddCandidateToSdp(Sdp* sdp, const std::string& candidateUntrimmed, const std::string& mid, uint16_t level) { if (level >= sdp->GetMediaSectionCount()) { SDP_SET_ERROR("Index " << level << " out of range"); return NS_ERROR_INVALID_ARG; } // Trim off '[a=]candidate:' size_t begin = candidateUntrimmed.find(':'); if (begin == std::string::npos) { SDP_SET_ERROR("Invalid candidate, no ':' (" << candidateUntrimmed << ")"); return NS_ERROR_INVALID_ARG; } ++begin; std::string candidate = candidateUntrimmed.substr(begin); // https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-11#section-3.4.2.1 // Implementations receiving an ICE Candidate object MUST use the MID if // present, or the m= line index, if not (as it could have come from a // non-JSEP endpoint). (bug 1095793) SdpMediaSection* msection = 0; if (!mid.empty()) { // FindMsectionByMid could return nullptr msection = FindMsectionByMid(*sdp, mid); // Check to make sure mid matches what we'd get by // looking up the m= line using the level. (mjf) std::string checkMid; nsresult rv = GetMidFromLevel(*sdp, level, &checkMid); if (NS_FAILED(rv)) { return rv; } if (mid != checkMid) { SDP_SET_ERROR("Mismatch between mid and level - \"" << mid << "\" is not the mid for level " << level << "; \"" << checkMid << "\" is"); return NS_ERROR_INVALID_ARG; } } if (!msection) { msection = &(sdp->GetMediaSection(level)); } SdpAttributeList& attrList = msection->GetAttributeList(); UniquePtr<SdpMultiStringAttribute> candidates; if (!attrList.HasAttribute(SdpAttribute::kCandidateAttribute)) { // Create new candidates.reset( new SdpMultiStringAttribute(SdpAttribute::kCandidateAttribute)); } else { // Copy existing candidates.reset(new SdpMultiStringAttribute( *static_cast<const SdpMultiStringAttribute*>( attrList.GetAttribute(SdpAttribute::kCandidateAttribute)))); } candidates->PushEntry(candidate); attrList.SetAttribute(candidates.release()); return NS_OK; }