/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsCRT.h" #include "sdp/RsdparsaSdpAttributeList.h" #include "sdp/RsdparsaSdpInc.h" #include "sdp/RsdparsaSdpGlue.h" #include #include "mozilla/Assertions.h" #include namespace mozilla { const std::string RsdparsaSdpAttributeList::kEmptyString = ""; RsdparsaSdpAttributeList::~RsdparsaSdpAttributeList() { for (size_t i = 0; i < kNumAttributeTypes; ++i) { delete mAttributes[i]; } } bool RsdparsaSdpAttributeList::HasAttribute(AttributeType type, bool sessionFallback) const { return !!GetAttribute(type, sessionFallback); } const SdpAttribute* RsdparsaSdpAttributeList::GetAttribute( AttributeType type, bool sessionFallback) const { const SdpAttribute* value = mAttributes[static_cast(type)]; // Only do fallback when the attribute can appear at both the media and // session level if (!value && !AtSessionLevel() && sessionFallback && SdpAttribute::IsAllowedAtSessionLevel(type) && SdpAttribute::IsAllowedAtMediaLevel(type)) { return mSessionAttributes->GetAttribute(type, false); } return value; } void RsdparsaSdpAttributeList::RemoveAttribute(AttributeType type) { delete mAttributes[static_cast(type)]; mAttributes[static_cast(type)] = nullptr; } void RsdparsaSdpAttributeList::Clear() { for (size_t i = 0; i < kNumAttributeTypes; ++i) { RemoveAttribute(static_cast(i)); } } uint32_t RsdparsaSdpAttributeList::Count() const { uint32_t count = 0; for (size_t i = 0; i < kNumAttributeTypes; ++i) { if (mAttributes[i]) { count++; } } return count; } void RsdparsaSdpAttributeList::SetAttribute(SdpAttribute* attr) { if (!IsAllowedHere(attr->GetType())) { MOZ_ASSERT(false, "This type of attribute is not allowed here"); delete attr; return; } RemoveAttribute(attr->GetType()); mAttributes[attr->GetType()] = attr; } const std::vector& RsdparsaSdpAttributeList::GetCandidate() const { if (!HasAttribute(SdpAttribute::kCandidateAttribute)) { MOZ_CRASH(); } return static_cast( GetAttribute(SdpAttribute::kCandidateAttribute)) ->mValues; } const SdpConnectionAttribute& RsdparsaSdpAttributeList::GetConnection() const { if (!HasAttribute(SdpAttribute::kConnectionAttribute)) { MOZ_CRASH(); } return *static_cast( GetAttribute(SdpAttribute::kConnectionAttribute)); } SdpDirectionAttribute::Direction RsdparsaSdpAttributeList::GetDirection() const { if (!HasAttribute(SdpAttribute::kDirectionAttribute)) { MOZ_CRASH(); } const SdpAttribute* attr = GetAttribute(SdpAttribute::kDirectionAttribute); return static_cast(attr)->mValue; } const SdpDtlsMessageAttribute& RsdparsaSdpAttributeList::GetDtlsMessage() const { if (!HasAttribute(SdpAttribute::kDtlsMessageAttribute)) { MOZ_CRASH(); } const SdpAttribute* attr = GetAttribute(SdpAttribute::kDtlsMessageAttribute); return *static_cast(attr); } const SdpExtmapAttributeList& RsdparsaSdpAttributeList::GetExtmap() const { if (!HasAttribute(SdpAttribute::kExtmapAttribute)) { MOZ_CRASH(); } return *static_cast( GetAttribute(SdpAttribute::kExtmapAttribute)); } const SdpFingerprintAttributeList& RsdparsaSdpAttributeList::GetFingerprint() const { if (!HasAttribute(SdpAttribute::kFingerprintAttribute)) { MOZ_CRASH(); } const SdpAttribute* attr = GetAttribute(SdpAttribute::kFingerprintAttribute); return *static_cast(attr); } const SdpFmtpAttributeList& RsdparsaSdpAttributeList::GetFmtp() const { if (!HasAttribute(SdpAttribute::kFmtpAttribute)) { MOZ_CRASH(); } return *static_cast( GetAttribute(SdpAttribute::kFmtpAttribute)); } const SdpGroupAttributeList& RsdparsaSdpAttributeList::GetGroup() const { if (!HasAttribute(SdpAttribute::kGroupAttribute)) { MOZ_CRASH(); } return *static_cast( GetAttribute(SdpAttribute::kGroupAttribute)); } const SdpOptionsAttribute& RsdparsaSdpAttributeList::GetIceOptions() const { if (!HasAttribute(SdpAttribute::kIceOptionsAttribute)) { MOZ_CRASH(); } const SdpAttribute* attr = GetAttribute(SdpAttribute::kIceOptionsAttribute); return *static_cast(attr); } const std::string& RsdparsaSdpAttributeList::GetIcePwd() const { if (!HasAttribute(SdpAttribute::kIcePwdAttribute)) { return kEmptyString; } const SdpAttribute* attr = GetAttribute(SdpAttribute::kIcePwdAttribute); return static_cast(attr)->mValue; } const std::string& RsdparsaSdpAttributeList::GetIceUfrag() const { if (!HasAttribute(SdpAttribute::kIceUfragAttribute)) { return kEmptyString; } const SdpAttribute* attr = GetAttribute(SdpAttribute::kIceUfragAttribute); return static_cast(attr)->mValue; } const std::string& RsdparsaSdpAttributeList::GetIdentity() const { if (!HasAttribute(SdpAttribute::kIdentityAttribute)) { return kEmptyString; } const SdpAttribute* attr = GetAttribute(SdpAttribute::kIdentityAttribute); return static_cast(attr)->mValue; } const SdpImageattrAttributeList& RsdparsaSdpAttributeList::GetImageattr() const { if (!HasAttribute(SdpAttribute::kImageattrAttribute)) { MOZ_CRASH(); } const SdpAttribute* attr = GetAttribute(SdpAttribute::kImageattrAttribute); return *static_cast(attr); } const SdpSimulcastAttribute& RsdparsaSdpAttributeList::GetSimulcast() const { if (!HasAttribute(SdpAttribute::kSimulcastAttribute)) { MOZ_CRASH(); } const SdpAttribute* attr = GetAttribute(SdpAttribute::kSimulcastAttribute); return *static_cast(attr); } const std::string& RsdparsaSdpAttributeList::GetLabel() const { if (!HasAttribute(SdpAttribute::kLabelAttribute)) { return kEmptyString; } const SdpAttribute* attr = GetAttribute(SdpAttribute::kLabelAttribute); return static_cast(attr)->mValue; } uint32_t RsdparsaSdpAttributeList::GetMaxptime() const { if (!HasAttribute(SdpAttribute::kMaxptimeAttribute)) { MOZ_CRASH(); } const SdpAttribute* attr = GetAttribute(SdpAttribute::kMaxptimeAttribute); return static_cast(attr)->mValue; } const std::string& RsdparsaSdpAttributeList::GetMid() const { if (!HasAttribute(SdpAttribute::kMidAttribute)) { return kEmptyString; } const SdpAttribute* attr = GetAttribute(SdpAttribute::kMidAttribute); return static_cast(attr)->mValue; } const SdpMsidAttributeList& RsdparsaSdpAttributeList::GetMsid() const { if (!HasAttribute(SdpAttribute::kMsidAttribute)) { MOZ_CRASH(); } const SdpAttribute* attr = GetAttribute(SdpAttribute::kMsidAttribute); return *static_cast(attr); } const SdpMsidSemanticAttributeList& RsdparsaSdpAttributeList::GetMsidSemantic() const { if (!HasAttribute(SdpAttribute::kMsidSemanticAttribute)) { MOZ_CRASH(); } const SdpAttribute* attr = GetAttribute(SdpAttribute::kMsidSemanticAttribute); return *static_cast(attr); } const SdpRidAttributeList& RsdparsaSdpAttributeList::GetRid() const { if (!HasAttribute(SdpAttribute::kRidAttribute)) { MOZ_CRASH(); } const SdpAttribute* attr = GetAttribute(SdpAttribute::kRidAttribute); return *static_cast(attr); } uint32_t RsdparsaSdpAttributeList::GetPtime() const { if (!HasAttribute(SdpAttribute::kPtimeAttribute)) { MOZ_CRASH(); } const SdpAttribute* attr = GetAttribute(SdpAttribute::kPtimeAttribute); return static_cast(attr)->mValue; } const SdpRtcpAttribute& RsdparsaSdpAttributeList::GetRtcp() const { if (!HasAttribute(SdpAttribute::kRtcpAttribute)) { MOZ_CRASH(); } const SdpAttribute* attr = GetAttribute(SdpAttribute::kRtcpAttribute); return *static_cast(attr); } const SdpRtcpFbAttributeList& RsdparsaSdpAttributeList::GetRtcpFb() const { if (!HasAttribute(SdpAttribute::kRtcpFbAttribute)) { MOZ_CRASH(); } const SdpAttribute* attr = GetAttribute(SdpAttribute::kRtcpFbAttribute); return *static_cast(attr); } const SdpRemoteCandidatesAttribute& RsdparsaSdpAttributeList::GetRemoteCandidates() const { MOZ_CRASH("Not yet implemented"); } const SdpRtpmapAttributeList& RsdparsaSdpAttributeList::GetRtpmap() const { if (!HasAttribute(SdpAttribute::kRtpmapAttribute)) { MOZ_CRASH(); } const SdpAttribute* attr = GetAttribute(SdpAttribute::kRtpmapAttribute); return *static_cast(attr); } const SdpSctpmapAttributeList& RsdparsaSdpAttributeList::GetSctpmap() const { if (!HasAttribute(SdpAttribute::kSctpmapAttribute)) { MOZ_CRASH(); } const SdpAttribute* attr = GetAttribute(SdpAttribute::kSctpmapAttribute); return *static_cast(attr); } uint32_t RsdparsaSdpAttributeList::GetSctpPort() const { if (!HasAttribute(SdpAttribute::kSctpPortAttribute)) { MOZ_CRASH(); } const SdpAttribute* attr = GetAttribute(SdpAttribute::kSctpPortAttribute); return static_cast(attr)->mValue; } uint32_t RsdparsaSdpAttributeList::GetMaxMessageSize() const { if (!HasAttribute(SdpAttribute::kMaxMessageSizeAttribute)) { MOZ_CRASH(); } const SdpAttribute* attr = GetAttribute(SdpAttribute::kMaxMessageSizeAttribute); return static_cast(attr)->mValue; } const SdpSetupAttribute& RsdparsaSdpAttributeList::GetSetup() const { if (!HasAttribute(SdpAttribute::kSetupAttribute)) { MOZ_CRASH(); } const SdpAttribute* attr = GetAttribute(SdpAttribute::kSetupAttribute); return *static_cast(attr); } const SdpSsrcAttributeList& RsdparsaSdpAttributeList::GetSsrc() const { if (!HasAttribute(SdpAttribute::kSsrcAttribute)) { MOZ_CRASH(); } const SdpAttribute* attr = GetAttribute(SdpAttribute::kSsrcAttribute); return *static_cast(attr); } const SdpSsrcGroupAttributeList& RsdparsaSdpAttributeList::GetSsrcGroup() const { if (!HasAttribute(SdpAttribute::kSsrcGroupAttribute)) { MOZ_CRASH(); } const SdpAttribute* attr = GetAttribute(SdpAttribute::kSsrcGroupAttribute); return *static_cast(attr); } void RsdparsaSdpAttributeList::LoadAttribute(RustAttributeList* attributeList, AttributeType type) { if (!mAttributes[type]) { switch (type) { case SdpAttribute::kIceUfragAttribute: LoadIceUfrag(attributeList); return; case SdpAttribute::kIcePwdAttribute: LoadIcePwd(attributeList); return; case SdpAttribute::kIceOptionsAttribute: LoadIceOptions(attributeList); return; case SdpAttribute::kDtlsMessageAttribute: LoadDtlsMessage(attributeList); return; case SdpAttribute::kFingerprintAttribute: LoadFingerprint(attributeList); return; case SdpAttribute::kIdentityAttribute: LoadIdentity(attributeList); return; case SdpAttribute::kSetupAttribute: LoadSetup(attributeList); return; case SdpAttribute::kSsrcAttribute: LoadSsrc(attributeList); return; case SdpAttribute::kRtpmapAttribute: LoadRtpmap(attributeList); return; case SdpAttribute::kFmtpAttribute: LoadFmtp(attributeList); return; case SdpAttribute::kPtimeAttribute: LoadPtime(attributeList); return; case SdpAttribute::kIceLiteAttribute: case SdpAttribute::kRtcpMuxAttribute: case SdpAttribute::kRtcpRsizeAttribute: case SdpAttribute::kBundleOnlyAttribute: case SdpAttribute::kEndOfCandidatesAttribute: LoadFlags(attributeList); return; case SdpAttribute::kMaxMessageSizeAttribute: LoadMaxMessageSize(attributeList); return; case SdpAttribute::kMidAttribute: LoadMid(attributeList); return; case SdpAttribute::kMsidAttribute: LoadMsid(attributeList); return; case SdpAttribute::kMsidSemanticAttribute: LoadMsidSemantics(attributeList); return; case SdpAttribute::kGroupAttribute: LoadGroup(attributeList); return; case SdpAttribute::kRtcpAttribute: LoadRtcp(attributeList); return; case SdpAttribute::kRtcpFbAttribute: LoadRtcpFb(attributeList); return; case SdpAttribute::kImageattrAttribute: LoadImageattr(attributeList); return; case SdpAttribute::kSctpmapAttribute: LoadSctpmaps(attributeList); return; case SdpAttribute::kDirectionAttribute: LoadDirection(attributeList); return; case SdpAttribute::kRemoteCandidatesAttribute: LoadRemoteCandidates(attributeList); return; case SdpAttribute::kRidAttribute: LoadRids(attributeList); return; case SdpAttribute::kSctpPortAttribute: LoadSctpPort(attributeList); return; case SdpAttribute::kExtmapAttribute: LoadExtmap(attributeList); return; case SdpAttribute::kSimulcastAttribute: LoadSimulcast(attributeList); return; case SdpAttribute::kMaxptimeAttribute: LoadMaxPtime(attributeList); return; case SdpAttribute::kCandidateAttribute: LoadCandidate(attributeList); return; case SdpAttribute::kSsrcGroupAttribute: LoadSsrcGroup(attributeList); return; case SdpAttribute::kConnectionAttribute: case SdpAttribute::kIceMismatchAttribute: case SdpAttribute::kLabelAttribute: // These attributes are unused return; } } } void RsdparsaSdpAttributeList::LoadAll(RustAttributeList* attributeList) { for (int i = SdpAttribute::kFirstAttribute; i <= SdpAttribute::kLastAttribute; i++) { LoadAttribute(attributeList, static_cast(i)); } } void RsdparsaSdpAttributeList::LoadIceUfrag(RustAttributeList* attributeList) { StringView ufragStr; nsresult nr = sdp_get_iceufrag(attributeList, &ufragStr); if (NS_SUCCEEDED(nr)) { std::string iceufrag = convertStringView(ufragStr); SetAttribute( new SdpStringAttribute(SdpAttribute::kIceUfragAttribute, iceufrag)); } } void RsdparsaSdpAttributeList::LoadIcePwd(RustAttributeList* attributeList) { StringView pwdStr; nsresult nr = sdp_get_icepwd(attributeList, &pwdStr); if (NS_SUCCEEDED(nr)) { std::string icePwd = convertStringView(pwdStr); SetAttribute( new SdpStringAttribute(SdpAttribute::kIcePwdAttribute, icePwd)); } } void RsdparsaSdpAttributeList::LoadIdentity(RustAttributeList* attributeList) { StringView identityStr; nsresult nr = sdp_get_identity(attributeList, &identityStr); if (NS_SUCCEEDED(nr)) { std::string identity = convertStringView(identityStr); SetAttribute( new SdpStringAttribute(SdpAttribute::kIdentityAttribute, identity)); } } void RsdparsaSdpAttributeList::LoadIceOptions( RustAttributeList* attributeList) { StringVec* options; nsresult nr = sdp_get_iceoptions(attributeList, &options); if (NS_SUCCEEDED(nr)) { std::vector optionsVec; auto optionsAttr = MakeUnique(SdpAttribute::kIceOptionsAttribute); for (size_t i = 0; i < string_vec_len(options); i++) { StringView optionStr; string_vec_get_view(options, i, &optionStr); optionsAttr->PushEntry(convertStringView(optionStr)); } SetAttribute(optionsAttr.release()); } } void RsdparsaSdpAttributeList::LoadFingerprint( RustAttributeList* attributeList) { size_t nFp = sdp_get_fingerprint_count(attributeList); if (nFp == 0) { return; } auto rustFingerprints = MakeUnique(nFp); sdp_get_fingerprints(attributeList, nFp, rustFingerprints.get()); auto fingerprints = MakeUnique(); for (size_t i = 0; i < nFp; i++) { const RustSdpAttributeFingerprint& fingerprint = rustFingerprints[i]; std::string algorithm; switch (fingerprint.hashAlgorithm) { case RustSdpAttributeFingerprintHashAlgorithm::kSha1: algorithm = "sha-1"; break; case RustSdpAttributeFingerprintHashAlgorithm::kSha224: algorithm = "sha-224"; break; case RustSdpAttributeFingerprintHashAlgorithm::kSha256: algorithm = "sha-256"; break; case RustSdpAttributeFingerprintHashAlgorithm::kSha384: algorithm = "sha-384"; break; case RustSdpAttributeFingerprintHashAlgorithm::kSha512: algorithm = "sha-512"; break; } std::vector fingerprintBytes = convertU8Vec(fingerprint.fingerprint); fingerprints->PushEntry(algorithm, fingerprintBytes); } SetAttribute(fingerprints.release()); } void RsdparsaSdpAttributeList::LoadDtlsMessage( RustAttributeList* attributeList) { RustSdpAttributeDtlsMessage rustDtlsMessage; nsresult nr = sdp_get_dtls_message(attributeList, &rustDtlsMessage); if (NS_SUCCEEDED(nr)) { SdpDtlsMessageAttribute::Role role; if (rustDtlsMessage.role == RustSdpAttributeDtlsMessageType::kClient) { role = SdpDtlsMessageAttribute::kClient; } else { role = SdpDtlsMessageAttribute::kServer; } std::string value = convertStringView(rustDtlsMessage.value); SetAttribute(new SdpDtlsMessageAttribute(role, value)); } } void RsdparsaSdpAttributeList::LoadSetup(RustAttributeList* attributeList) { RustSdpSetup rustSetup; nsresult nr = sdp_get_setup(attributeList, &rustSetup); if (NS_SUCCEEDED(nr)) { SdpSetupAttribute::Role setupEnum; switch (rustSetup) { case RustSdpSetup::kRustActive: setupEnum = SdpSetupAttribute::kActive; break; case RustSdpSetup::kRustActpass: setupEnum = SdpSetupAttribute::kActpass; break; case RustSdpSetup::kRustHoldconn: setupEnum = SdpSetupAttribute::kHoldconn; break; case RustSdpSetup::kRustPassive: setupEnum = SdpSetupAttribute::kPassive; break; } SetAttribute(new SdpSetupAttribute(setupEnum)); } } void RsdparsaSdpAttributeList::LoadSsrc(RustAttributeList* attributeList) { size_t numSsrc = sdp_get_ssrc_count(attributeList); if (numSsrc == 0) { return; } auto rustSsrcs = MakeUnique(numSsrc); sdp_get_ssrcs(attributeList, numSsrc, rustSsrcs.get()); auto ssrcs = MakeUnique(); for (size_t i = 0; i < numSsrc; i++) { RustSdpAttributeSsrc& ssrc = rustSsrcs[i]; std::string attribute = convertStringView(ssrc.attribute); std::string value = convertStringView(ssrc.value); if (value.length() == 0) { ssrcs->PushEntry(ssrc.id, attribute); } else { ssrcs->PushEntry(ssrc.id, attribute + ":" + value); } } SetAttribute(ssrcs.release()); } void RsdparsaSdpAttributeList::LoadSsrcGroup(RustAttributeList* attributeList) { size_t numSsrcGroups = sdp_get_ssrc_group_count(attributeList); if (numSsrcGroups == 0) { return; } auto rustSsrcGroups = MakeUnique(numSsrcGroups); sdp_get_ssrc_groups(attributeList, numSsrcGroups, rustSsrcGroups.get()); auto ssrcGroups = MakeUnique(); for (size_t i = 0; i < numSsrcGroups; i++) { RustSdpAttributeSsrcGroup& ssrcGroup = rustSsrcGroups[i]; SdpSsrcGroupAttributeList::Semantics semantic; switch (ssrcGroup.semantic) { case RustSdpAttributeSsrcGroupSemantic ::kRustDup: semantic = SdpSsrcGroupAttributeList::kDup; break; case RustSdpAttributeSsrcGroupSemantic ::kRustFec: semantic = SdpSsrcGroupAttributeList::kFec; break; case RustSdpAttributeSsrcGroupSemantic ::kRustFecFr: semantic = SdpSsrcGroupAttributeList::kFecFr; break; case RustSdpAttributeSsrcGroupSemantic ::kRustFid: semantic = SdpSsrcGroupAttributeList::kFid; break; case RustSdpAttributeSsrcGroupSemantic ::kRustSim: semantic = SdpSsrcGroupAttributeList::kSim; break; } std::vector ssrcs; for (size_t i = 0; i < ssrc_vec_len(ssrcGroup.ssrcs); ++i) { uint32_t ssrc; ssrc_vec_get_id(ssrcGroup.ssrcs, i, &ssrc); ssrcs.push_back(ssrc); } ssrcGroups->PushEntry(semantic, ssrcs); } SetAttribute(ssrcGroups.release()); } struct FmtDefaults { uint32_t minimumChannels = 0; }; std::tuple strToCodecType( const std::string& name) { auto codec = SdpRtpmapAttributeList::kOtherCodec; FmtDefaults defaults = {0}; // This is tracked to match SIPCC behavior only if (!nsCRT::strcasecmp(name.c_str(), "opus")) { codec = SdpRtpmapAttributeList::kOpus; defaults = {0}; } else if (!nsCRT::strcasecmp(name.c_str(), "G722")) { codec = SdpRtpmapAttributeList::kG722; defaults = {1}; } else if (!nsCRT::strcasecmp(name.c_str(), "PCMU")) { codec = SdpRtpmapAttributeList::kPCMU; defaults = {1}; } else if (!nsCRT::strcasecmp(name.c_str(), "PCMA")) { codec = SdpRtpmapAttributeList::kPCMA; defaults = {1}; } else if (!nsCRT::strcasecmp(name.c_str(), "VP8")) { codec = SdpRtpmapAttributeList::kVP8; defaults = {0}; } else if (!nsCRT::strcasecmp(name.c_str(), "VP9")) { codec = SdpRtpmapAttributeList::kVP9; defaults = {0}; } else if (!nsCRT::strcasecmp(name.c_str(), "iLBC")) { codec = SdpRtpmapAttributeList::kiLBC; defaults = {1}; } else if (!nsCRT::strcasecmp(name.c_str(), "iSAC")) { codec = SdpRtpmapAttributeList::kiSAC; defaults = {1}; } else if (!nsCRT::strcasecmp(name.c_str(), "H264")) { codec = SdpRtpmapAttributeList::kH264; defaults = {0}; } else if (!nsCRT::strcasecmp(name.c_str(), "red")) { codec = SdpRtpmapAttributeList::kRed; defaults = {0}; } else if (!nsCRT::strcasecmp(name.c_str(), "ulpfec")) { codec = SdpRtpmapAttributeList::kUlpfec; defaults = {0}; } else if (!nsCRT::strcasecmp(name.c_str(), "telephone-event")) { codec = SdpRtpmapAttributeList::kTelephoneEvent; defaults = {1}; } else if (!nsCRT::strcasecmp(name.c_str(), "rtx")) { codec = SdpRtpmapAttributeList::kRtx; defaults = {0}; } return std::make_tuple(codec, defaults); } void RsdparsaSdpAttributeList::LoadRtpmap(RustAttributeList* attributeList) { size_t numRtpmap = sdp_get_rtpmap_count(attributeList); if (numRtpmap == 0) { return; } auto rustRtpmaps = MakeUnique(numRtpmap); sdp_get_rtpmaps(attributeList, numRtpmap, rustRtpmaps.get()); auto rtpmapList = MakeUnique(); for (size_t i = 0; i < numRtpmap; i++) { RustSdpAttributeRtpmap& rtpmap = rustRtpmaps[i]; std::string payloadType = std::to_string(rtpmap.payloadType); std::string name = convertStringView(rtpmap.codecName); auto [codec, defaults] = strToCodecType(name); uint32_t channels = rtpmap.channels; if (channels == 0) { channels = defaults.minimumChannels; } rtpmapList->PushEntry(payloadType, codec, name, rtpmap.frequency, channels); } SetAttribute(rtpmapList.release()); } void RsdparsaSdpAttributeList::LoadFmtp(RustAttributeList* attributeList) { size_t numFmtp = sdp_get_fmtp_count(attributeList); if (numFmtp == 0) { return; } auto rustFmtps = MakeUnique(numFmtp); size_t numValidFmtp = sdp_get_fmtp(attributeList, numFmtp, rustFmtps.get()); auto fmtpList = MakeUnique(); for (size_t i = 0; i < numValidFmtp; i++) { const RustSdpAttributeFmtp& fmtp = rustFmtps[i]; uint8_t payloadType = fmtp.payloadType; std::string codecName = convertStringView(fmtp.codecName); const RustSdpAttributeFmtpParameters& rustFmtpParameters = fmtp.parameters; UniquePtr fmtpParameters; // use the upper case version of the codec name std::transform(codecName.begin(), codecName.end(), codecName.begin(), ::toupper); if (codecName == "H264") { SdpFmtpAttributeList::H264Parameters h264Parameters; h264Parameters.packetization_mode = rustFmtpParameters.packetization_mode; h264Parameters.level_asymmetry_allowed = rustFmtpParameters.level_asymmetry_allowed; h264Parameters.profile_level_id = rustFmtpParameters.profile_level_id; h264Parameters.max_mbps = rustFmtpParameters.max_mbps; h264Parameters.max_fs = rustFmtpParameters.max_fs; h264Parameters.max_cpb = rustFmtpParameters.max_cpb; h264Parameters.max_dpb = rustFmtpParameters.max_dpb; h264Parameters.max_br = rustFmtpParameters.max_br; // TODO(bug 1466859): Support sprop-parameter-sets fmtpParameters.reset( new SdpFmtpAttributeList::H264Parameters(std::move(h264Parameters))); } else if (codecName == "OPUS") { SdpFmtpAttributeList::OpusParameters opusParameters; opusParameters.maxplaybackrate = rustFmtpParameters.maxplaybackrate; opusParameters.maxAverageBitrate = rustFmtpParameters.maxaveragebitrate; opusParameters.useDTX = rustFmtpParameters.usedtx; opusParameters.stereo = rustFmtpParameters.stereo; opusParameters.useInBandFec = rustFmtpParameters.useinbandfec; opusParameters.frameSizeMs = rustFmtpParameters.ptime; opusParameters.minFrameSizeMs = rustFmtpParameters.minptime; opusParameters.maxFrameSizeMs = rustFmtpParameters.maxptime; opusParameters.useCbr = rustFmtpParameters.cbr; fmtpParameters.reset( new SdpFmtpAttributeList::OpusParameters(std::move(opusParameters))); } else if ((codecName == "VP8") || (codecName == "VP9")) { SdpFmtpAttributeList::VP8Parameters vp8Parameters( codecName == "VP8" ? SdpRtpmapAttributeList::kVP8 : SdpRtpmapAttributeList::kVP9); vp8Parameters.max_fs = rustFmtpParameters.max_fs; vp8Parameters.max_fr = rustFmtpParameters.max_fr; fmtpParameters.reset( new SdpFmtpAttributeList::VP8Parameters(std::move(vp8Parameters))); } else if (codecName == "TELEPHONE-EVENT") { SdpFmtpAttributeList::TelephoneEventParameters telephoneEventParameters; telephoneEventParameters.dtmfTones = convertStringView(rustFmtpParameters.dtmf_tones); fmtpParameters.reset(new SdpFmtpAttributeList::TelephoneEventParameters( std::move(telephoneEventParameters))); } else if (codecName == "RED") { SdpFmtpAttributeList::RedParameters redParameters; redParameters.encodings = convertU8Vec(rustFmtpParameters.encodings); fmtpParameters.reset( new SdpFmtpAttributeList::RedParameters(std::move(redParameters))); } else if (codecName == "RTX") { SdpFmtpAttributeList::RtxParameters rtxParameters; rtxParameters.apt = rustFmtpParameters.rtx.apt; if (rustFmtpParameters.rtx.has_rtx_time) { rtxParameters.rtx_time = Some(rustFmtpParameters.rtx.rtx_time); } fmtpParameters.reset( new SdpFmtpAttributeList::RtxParameters(rtxParameters)); } else { // The parameter set is unknown so skip it continue; } fmtpList->PushEntry(std::to_string(payloadType), *fmtpParameters); } SetAttribute(fmtpList.release()); } void RsdparsaSdpAttributeList::LoadPtime(RustAttributeList* attributeList) { int64_t ptime = sdp_get_ptime(attributeList); if (ptime >= 0) { SetAttribute(new SdpNumberAttribute(SdpAttribute::kPtimeAttribute, static_cast(ptime))); } } void RsdparsaSdpAttributeList::LoadFlags(RustAttributeList* attributeList) { RustSdpAttributeFlags flags = sdp_get_attribute_flags(attributeList); if (flags.iceLite) { SetAttribute(new SdpFlagAttribute(SdpAttribute::kIceLiteAttribute)); } if (flags.rtcpMux) { SetAttribute(new SdpFlagAttribute(SdpAttribute::kRtcpMuxAttribute)); } if (flags.rtcpRsize) { SetAttribute(new SdpFlagAttribute(SdpAttribute::kRtcpRsizeAttribute)); } if (flags.bundleOnly) { SetAttribute(new SdpFlagAttribute(SdpAttribute::kBundleOnlyAttribute)); } if (flags.endOfCandidates) { SetAttribute(new SdpFlagAttribute(SdpAttribute::kEndOfCandidatesAttribute)); } } void RsdparsaSdpAttributeList::LoadMaxMessageSize( RustAttributeList* attributeList) { int64_t max_msg_size = sdp_get_max_msg_size(attributeList); if (max_msg_size >= 0) { SetAttribute(new SdpNumberAttribute(SdpAttribute::kMaxMessageSizeAttribute, static_cast(max_msg_size))); } } void RsdparsaSdpAttributeList::LoadMid(RustAttributeList* attributeList) { StringView rustMid; if (NS_SUCCEEDED(sdp_get_mid(attributeList, &rustMid))) { std::string mid = convertStringView(rustMid); SetAttribute(new SdpStringAttribute(SdpAttribute::kMidAttribute, mid)); } } void RsdparsaSdpAttributeList::LoadMsid(RustAttributeList* attributeList) { size_t numMsid = sdp_get_msid_count(attributeList); if (numMsid == 0) { return; } auto rustMsid = MakeUnique(numMsid); sdp_get_msids(attributeList, numMsid, rustMsid.get()); auto msids = MakeUnique(); for (size_t i = 0; i < numMsid; i++) { RustSdpAttributeMsid& msid = rustMsid[i]; std::string id = convertStringView(msid.id); std::string appdata = convertStringView(msid.appdata); msids->PushEntry(id, appdata); } SetAttribute(msids.release()); } void RsdparsaSdpAttributeList::LoadMsidSemantics( RustAttributeList* attributeList) { size_t numMsidSemantic = sdp_get_msid_semantic_count(attributeList); if (numMsidSemantic == 0) { return; } auto rustMsidSemantics = MakeUnique(numMsidSemantic); sdp_get_msid_semantics(attributeList, numMsidSemantic, rustMsidSemantics.get()); auto msidSemantics = MakeUnique(); for (size_t i = 0; i < numMsidSemantic; i++) { RustSdpAttributeMsidSemantic& rustMsidSemantic = rustMsidSemantics[i]; std::string semantic = convertStringView(rustMsidSemantic.semantic); std::vector msids = convertStringVec(rustMsidSemantic.msids); msidSemantics->PushEntry(semantic, msids); } SetAttribute(msidSemantics.release()); } void RsdparsaSdpAttributeList::LoadGroup(RustAttributeList* attributeList) { size_t numGroup = sdp_get_group_count(attributeList); if (numGroup == 0) { return; } auto rustGroups = MakeUnique(numGroup); sdp_get_groups(attributeList, numGroup, rustGroups.get()); auto groups = MakeUnique(); for (size_t i = 0; i < numGroup; i++) { RustSdpAttributeGroup& group = rustGroups[i]; SdpGroupAttributeList::Semantics semantic; switch (group.semantic) { case RustSdpAttributeGroupSemantic ::kRustLipSynchronization: semantic = SdpGroupAttributeList::kLs; break; case RustSdpAttributeGroupSemantic ::kRustFlowIdentification: semantic = SdpGroupAttributeList::kFid; break; case RustSdpAttributeGroupSemantic ::kRustSingleReservationFlow: semantic = SdpGroupAttributeList::kSrf; break; case RustSdpAttributeGroupSemantic ::kRustAlternateNetworkAddressType: semantic = SdpGroupAttributeList::kAnat; break; case RustSdpAttributeGroupSemantic ::kRustForwardErrorCorrection: semantic = SdpGroupAttributeList::kFec; break; case RustSdpAttributeGroupSemantic ::kRustDecodingDependency: semantic = SdpGroupAttributeList::kDdp; break; case RustSdpAttributeGroupSemantic ::kRustBundle: semantic = SdpGroupAttributeList::kBundle; break; } std::vector tags = convertStringVec(group.tags); groups->PushEntry(semantic, tags); } SetAttribute(groups.release()); } void RsdparsaSdpAttributeList::LoadRtcp(RustAttributeList* attributeList) { RustSdpAttributeRtcp rtcp; if (NS_SUCCEEDED(sdp_get_rtcp(attributeList, &rtcp))) { if (rtcp.has_address) { auto address = convertExplicitlyTypedAddress(&rtcp.unicastAddr); SetAttribute(new SdpRtcpAttribute(rtcp.port, sdp::kInternet, address.first, address.second)); } else { SetAttribute(new SdpRtcpAttribute(rtcp.port)); } } } void RsdparsaSdpAttributeList::LoadRtcpFb(RustAttributeList* attributeList) { auto rtcpfbsCount = sdp_get_rtcpfb_count(attributeList); if (!rtcpfbsCount) { return; } auto rustRtcpfbs = MakeUnique(rtcpfbsCount); sdp_get_rtcpfbs(attributeList, rtcpfbsCount, rustRtcpfbs.get()); auto rtcpfbList = MakeUnique(); for (size_t i = 0; i < rtcpfbsCount; i++) { RustSdpAttributeRtcpFb& rtcpfb = rustRtcpfbs[i]; uint32_t payloadTypeU32 = rtcpfb.payloadType; std::stringstream ss; if (payloadTypeU32 == std::numeric_limits::max()) { ss << "*"; } else { ss << payloadTypeU32; } uint32_t feedbackType = rtcpfb.feedbackType; std::string parameter = convertStringView(rtcpfb.parameter); std::string extra = convertStringView(rtcpfb.extra); rtcpfbList->PushEntry( ss.str(), static_cast(feedbackType), parameter, extra); } SetAttribute(rtcpfbList.release()); } SdpSimulcastAttribute::Versions LoadSimulcastVersions( const RustSdpAttributeSimulcastVersionVec* rustVersionList) { size_t rustVersionCount = sdp_simulcast_get_version_count(rustVersionList); auto rustVersionArray = MakeUnique(rustVersionCount); sdp_simulcast_get_versions(rustVersionList, rustVersionCount, rustVersionArray.get()); SdpSimulcastAttribute::Versions versions; 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(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( SdpSimulcastAttribute::Encoding(id, rustId.paused)); } versions.push_back(version); } return versions; } void RsdparsaSdpAttributeList::LoadSimulcast(RustAttributeList* attributeList) { RustSdpAttributeSimulcast rustSimulcast; if (NS_SUCCEEDED(sdp_get_simulcast(attributeList, &rustSimulcast))) { auto simulcast = MakeUnique(); simulcast->sendVersions = LoadSimulcastVersions(rustSimulcast.send); simulcast->recvVersions = LoadSimulcastVersions(rustSimulcast.recv); SetAttribute(simulcast.release()); } } SdpImageattrAttributeList::XYRange LoadImageattrXYRange( const RustSdpAttributeImageAttrXYRange& rustXYRange) { SdpImageattrAttributeList::XYRange xyRange; if (!rustXYRange.discrete_values) { xyRange.min = rustXYRange.min; xyRange.max = rustXYRange.max; xyRange.step = rustXYRange.step; } else { xyRange.discreteValues = convertU32Vec(rustXYRange.discrete_values); } return xyRange; } std::vector LoadImageattrSets( const RustSdpAttributeImageAttrSetVec* rustSets) { std::vector sets; size_t rustSetCount = sdp_imageattr_get_set_count(rustSets); if (!rustSetCount) { return sets; } auto rustSetArray = MakeUnique(rustSetCount); sdp_imageattr_get_sets(rustSets, rustSetCount, rustSetArray.get()); for (size_t i = 0; i < rustSetCount; i++) { const RustSdpAttributeImageAttrSet& rustSet = rustSetArray[i]; SdpImageattrAttributeList::Set set; set.xRange = LoadImageattrXYRange(rustSet.x); set.yRange = LoadImageattrXYRange(rustSet.y); if (rustSet.has_sar) { if (!rustSet.sar.discrete_values) { set.sRange.min = rustSet.sar.min; set.sRange.max = rustSet.sar.max; } else { set.sRange.discreteValues = convertF32Vec(rustSet.sar.discrete_values); } } if (rustSet.has_par) { set.pRange.min = rustSet.par.min; set.pRange.max = rustSet.par.max; } set.qValue = rustSet.q; sets.push_back(set); } return sets; } void RsdparsaSdpAttributeList::LoadImageattr(RustAttributeList* attributeList) { size_t numImageattrs = sdp_get_imageattr_count(attributeList); if (numImageattrs == 0) { return; } auto rustImageattrs = MakeUnique(numImageattrs); sdp_get_imageattrs(attributeList, numImageattrs, rustImageattrs.get()); auto imageattrList = MakeUnique(); for (size_t i = 0; i < numImageattrs; i++) { const RustSdpAttributeImageAttr& rustImageAttr = rustImageattrs[i]; SdpImageattrAttributeList::Imageattr imageAttr; if (rustImageAttr.payloadType != std::numeric_limits::max()) { imageAttr.pt = Some(rustImageAttr.payloadType); } if (rustImageAttr.send.sets) { imageAttr.sendSets = LoadImageattrSets(rustImageAttr.send.sets); } else { imageAttr.sendAll = true; } if (rustImageAttr.recv.sets) { imageAttr.recvSets = LoadImageattrSets(rustImageAttr.recv.sets); } else { imageAttr.recvAll = true; } imageattrList->mImageattrs.push_back(imageAttr); } SetAttribute(imageattrList.release()); } void RsdparsaSdpAttributeList::LoadSctpmaps(RustAttributeList* attributeList) { size_t numSctpmaps = sdp_get_sctpmap_count(attributeList); if (numSctpmaps == 0) { return; } auto rustSctpmaps = MakeUnique(numSctpmaps); sdp_get_sctpmaps(attributeList, numSctpmaps, rustSctpmaps.get()); auto sctpmapList = MakeUnique(); for (size_t i = 0; i < numSctpmaps; i++) { RustSdpAttributeSctpmap& sctpmap = rustSctpmaps[i]; sctpmapList->PushEntry(std::to_string(sctpmap.port), "webrtc-datachannel", sctpmap.channels); } SetAttribute(sctpmapList.release()); } void RsdparsaSdpAttributeList::LoadDirection(RustAttributeList* attributeList) { SdpDirectionAttribute::Direction dir; RustDirection rustDir = sdp_get_direction(attributeList); switch (rustDir) { case RustDirection::kRustRecvonly: dir = SdpDirectionAttribute::kRecvonly; break; case RustDirection::kRustSendonly: dir = SdpDirectionAttribute::kSendonly; break; case RustDirection::kRustSendrecv: dir = SdpDirectionAttribute::kSendrecv; break; case RustDirection::kRustInactive: dir = SdpDirectionAttribute::kInactive; break; } SetAttribute(new SdpDirectionAttribute(dir)); } void RsdparsaSdpAttributeList::LoadRemoteCandidates( RustAttributeList* attributeList) { size_t nC = sdp_get_remote_candidate_count(attributeList); if (nC == 0) { return; } auto rustCandidates = MakeUnique(nC); sdp_get_remote_candidates(attributeList, nC, rustCandidates.get()); std::vector candidates; for (size_t i = 0; i < nC; i++) { RustSdpAttributeRemoteCandidate& rustCandidate = rustCandidates[i]; SdpRemoteCandidatesAttribute::Candidate candidate; candidate.port = rustCandidate.port; candidate.id = std::to_string(rustCandidate.component); candidate.address = convertAddress(&rustCandidate.address); candidates.push_back(candidate); } SdpRemoteCandidatesAttribute* candidatesList; candidatesList = new SdpRemoteCandidatesAttribute(candidates); SetAttribute(candidatesList); } void RsdparsaSdpAttributeList::LoadRids(RustAttributeList* attributeList) { size_t numRids = sdp_get_rid_count(attributeList); if (numRids == 0) { return; } auto rustRids = MakeUnique(numRids); sdp_get_rids(attributeList, numRids, rustRids.get()); auto ridList = MakeUnique(); for (size_t i = 0; i < numRids; i++) { const RustSdpAttributeRid& rid = rustRids[i]; std::string id = convertStringView(rid.id); auto direction = static_cast(rid.direction); std::vector formats = convertU16Vec(rid.formats); EncodingConstraints parameters; parameters.maxWidth = rid.params.max_width; parameters.maxHeight = rid.params.max_height; // Right now, we treat max-fps=0 and the absence of max-fps as no limit. // We will eventually want to treat max-fps=0 as 0 frames per second, and // the absence of max-fps as no limit (bug 1762632). if (rid.params.max_fps) { parameters.maxFps = Some(rid.params.max_fps); } parameters.maxFs = rid.params.max_fs; parameters.maxBr = rid.params.max_br; parameters.maxPps = rid.params.max_pps; std::vector depends = convertStringVec(rid.depends); ridList->PushEntry(id, direction, formats, parameters, depends); } SetAttribute(ridList.release()); } void RsdparsaSdpAttributeList::LoadSctpPort(RustAttributeList* attributeList) { int64_t port = sdp_get_sctp_port(attributeList); if (port >= 0) { SetAttribute(new SdpNumberAttribute(SdpAttribute::kSctpPortAttribute, static_cast(port))); } } void RsdparsaSdpAttributeList::LoadExtmap(RustAttributeList* attributeList) { size_t numExtmap = sdp_get_extmap_count(attributeList); if (numExtmap == 0) { return; } auto rustExtmaps = MakeUnique(numExtmap); sdp_get_extmaps(attributeList, numExtmap, rustExtmaps.get()); auto extmaps = MakeUnique(); for (size_t i = 0; i < numExtmap; i++) { RustSdpAttributeExtmap& rustExtmap = rustExtmaps[i]; std::string name = convertStringView(rustExtmap.url); SdpDirectionAttribute::Direction direction; bool directionSpecified = rustExtmap.direction_specified; switch (rustExtmap.direction) { case RustDirection::kRustRecvonly: direction = SdpDirectionAttribute::kRecvonly; break; case RustDirection::kRustSendonly: direction = SdpDirectionAttribute::kSendonly; break; case RustDirection::kRustSendrecv: direction = SdpDirectionAttribute::kSendrecv; break; case RustDirection::kRustInactive: direction = SdpDirectionAttribute::kInactive; break; } std::string extensionAttributes; extensionAttributes = convertStringView(rustExtmap.extensionAttributes); extmaps->PushEntry((uint16_t)rustExtmap.id, direction, directionSpecified, name, extensionAttributes); } SetAttribute(extmaps.release()); } void RsdparsaSdpAttributeList::LoadMaxPtime(RustAttributeList* attributeList) { 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 candidatesStrings = convertStringVec(rustCandidatesStrings); free_boxed_string_vec(rustCandidatesStrings); auto candidates = MakeUnique(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)) { return false; } return true; } void RsdparsaSdpAttributeList::Serialize(std::ostream& os) const { for (size_t i = 0; i < kNumAttributeTypes; ++i) { if (mAttributes[i]) { os << *mAttributes[i]; } } } } // namespace mozilla