void SdpHelper::SetDefaultAddresses(const std::string& defaultCandidateAddr, uint16_t defaultCandidatePort, const std::string& defaultRtcpCandidateAddr, uint16_t defaultRtcpCandidatePort, Sdp* sdp, uint16_t level, BundledMids bundledMids) { SdpMediaSection& msection = sdp->GetMediaSection(level); if (msection.GetAttributeList().HasAttribute(SdpAttribute::kMidAttribute)) { std::string mid(msection.GetAttributeList().GetMid()); if (bundledMids.count(mid)) { const SdpMediaSection* masterBundleMsection(bundledMids[mid]); if (msection.GetLevel() != masterBundleMsection->GetLevel()) { // Slave bundle m-section. Skip. return; } // Master bundle m-section. Set defaultCandidateAddr and // defaultCandidatePort on all bundled m-sections. for (auto i = bundledMids.begin(); i != bundledMids.end(); ++i) { if (i->second != masterBundleMsection) { continue; } SdpMediaSection* bundledMsection = FindMsectionByMid(*sdp, i->first); if (!bundledMsection) { MOZ_ASSERT(false); continue; } SetDefaultAddresses(defaultCandidateAddr, defaultCandidatePort, defaultRtcpCandidateAddr, defaultRtcpCandidatePort, bundledMsection); } } } SetDefaultAddresses(defaultCandidateAddr, defaultCandidatePort, defaultRtcpCandidateAddr, defaultRtcpCandidatePort, &msection); // TODO(bug 1095793): Will this have an mid someday? SdpAttributeList& attrs = msection.GetAttributeList(); attrs.SetAttribute( new SdpFlagAttribute(SdpAttribute::kEndOfCandidatesAttribute)); // Remove trickle-ice option attrs.RemoveAttribute(SdpAttribute::kIceOptionsAttribute); }
nsresult SdpHelper::GetBundledMids(const Sdp& sdp, BundledMids* bundledMids) { std::vector<SdpGroupAttributeList::Group> bundleGroups; GetBundleGroups(sdp, &bundleGroups); for (SdpGroupAttributeList::Group& group : bundleGroups) { if (group.tags.empty()) { SDP_SET_ERROR("Empty BUNDLE group"); return NS_ERROR_INVALID_ARG; } const SdpMediaSection* masterBundleMsection( FindMsectionByMid(sdp, group.tags[0])); if (!masterBundleMsection) { SDP_SET_ERROR("mid specified for bundle transport in group attribute" " does not exist in the SDP. (mid=" << group.tags[0] << ")"); return NS_ERROR_INVALID_ARG; } if (MsectionIsDisabled(*masterBundleMsection)) { SDP_SET_ERROR("mid specified for bundle transport in group attribute" " points at a disabled m-section. (mid=" << group.tags[0] << ")"); return NS_ERROR_INVALID_ARG; } for (const std::string& mid : group.tags) { if (bundledMids->count(mid)) { SDP_SET_ERROR("mid \'" << mid << "\' appears more than once in a " "BUNDLE group"); return NS_ERROR_INVALID_ARG; } (*bundledMids)[mid] = masterBundleMsection; } } 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; }