RsdparsaSdpMediaSection.cpp (8039B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "sdp/RsdparsaSdpMediaSection.h" 8 9 #include <ostream> 10 11 #include "sdp/RsdparsaSdpGlue.h" 12 #include "sdp/RsdparsaSdpInc.h" 13 #include "sdp/SdpMediaSection.h" 14 15 #ifdef CRLF 16 # undef CRLF 17 #endif 18 #define CRLF "\r\n" 19 20 namespace mozilla { 21 22 RsdparsaSdpMediaSection::RsdparsaSdpMediaSection( 23 size_t level, RsdparsaSessionHandle session, 24 const RustMediaSection* const section, 25 const RsdparsaSdpAttributeList* sessionLevel) 26 : SdpMediaSection(level), mSession(std::move(session)), mSection(section) { 27 switch (sdp_rust_get_media_type(section)) { 28 case RustSdpMediaValue::kRustAudio: 29 mMediaType = kAudio; 30 break; 31 case RustSdpMediaValue::kRustVideo: 32 mMediaType = kVideo; 33 break; 34 case RustSdpMediaValue::kRustApplication: 35 mMediaType = kApplication; 36 break; 37 } 38 39 RsdparsaSessionHandle attributeSession(sdp_new_reference(mSession.get())); 40 mAttributeList.reset(new RsdparsaSdpAttributeList(std::move(attributeSession), 41 section, sessionLevel)); 42 43 LoadFormats(); 44 LoadConnection(); 45 } 46 47 unsigned int RsdparsaSdpMediaSection::GetPort() const { 48 return sdp_get_media_port(mSection); 49 } 50 51 void RsdparsaSdpMediaSection::SetPort(unsigned int port) { 52 sdp_set_media_port(mSection, port); 53 } 54 55 unsigned int RsdparsaSdpMediaSection::GetPortCount() const { 56 return sdp_get_media_port_count(mSection); 57 } 58 59 SdpMediaSection::Protocol RsdparsaSdpMediaSection::GetProtocol() const { 60 switch (sdp_get_media_protocol(mSection)) { 61 case RustSdpProtocolValue::kRustRtpSavpf: 62 return kRtpSavpf; 63 case RustSdpProtocolValue::kRustUdpTlsRtpSavp: 64 return kUdpTlsRtpSavp; 65 case RustSdpProtocolValue::kRustTcpDtlsRtpSavp: 66 return kTcpDtlsRtpSavp; 67 case RustSdpProtocolValue::kRustUdpTlsRtpSavpf: 68 return kUdpTlsRtpSavpf; 69 case RustSdpProtocolValue::kRustTcpDtlsRtpSavpf: 70 return kTcpDtlsRtpSavpf; 71 case RustSdpProtocolValue::kRustDtlsSctp: 72 return kDtlsSctp; 73 case RustSdpProtocolValue::kRustUdpDtlsSctp: 74 return kUdpDtlsSctp; 75 case RustSdpProtocolValue::kRustTcpDtlsSctp: 76 return kTcpDtlsSctp; 77 case RustSdpProtocolValue::kRustRtpAvp: 78 return kRtpAvp; 79 case RustSdpProtocolValue::kRustRtpAvpf: 80 return kRtpAvpf; 81 case RustSdpProtocolValue::kRustRtpSavp: 82 return kRtpSavp; 83 } 84 MOZ_CRASH("invalid media protocol"); 85 } 86 87 const SdpConnection& RsdparsaSdpMediaSection::GetConnection() const { 88 MOZ_ASSERT(mConnection); 89 return *mConnection; 90 } 91 92 SdpConnection& RsdparsaSdpMediaSection::GetConnection() { 93 MOZ_ASSERT(mConnection); 94 return *mConnection; 95 } 96 97 uint32_t RsdparsaSdpMediaSection::GetBandwidth(const std::string& type) const { 98 return sdp_get_media_bandwidth(mSection, type.c_str()); 99 } 100 101 const std::vector<std::string>& RsdparsaSdpMediaSection::GetFormats() const { 102 return mFormats; 103 } 104 105 const SdpAttributeList& RsdparsaSdpMediaSection::GetAttributeList() const { 106 return *mAttributeList; 107 } 108 109 SdpAttributeList& RsdparsaSdpMediaSection::GetAttributeList() { 110 return *mAttributeList; 111 } 112 113 SdpDirectionAttribute RsdparsaSdpMediaSection::GetDirectionAttribute() const { 114 return SdpDirectionAttribute(mAttributeList->GetDirection()); 115 } 116 117 void RsdparsaSdpMediaSection::AddCodec(const std::string& pt, 118 const std::string& name, 119 uint32_t clockrate, uint16_t channels) { 120 StringView rustName{name.c_str(), name.size()}; 121 122 // call the rust interface 123 auto nr = sdp_media_add_codec(mSection, std::stoul(pt), rustName, clockrate, 124 channels); 125 126 if (NS_SUCCEEDED(nr)) { 127 // If the rust call was successful, adjust the shadow C++ structures 128 mFormats.push_back(pt); 129 130 // Add a rtpmap in mAttributeList 131 SdpRtpmapAttributeList* rtpmap = new SdpRtpmapAttributeList(); 132 if (mAttributeList->HasAttribute(SdpAttribute::kRtpmapAttribute)) { 133 const SdpRtpmapAttributeList& old = mAttributeList->GetRtpmap(); 134 for (auto it = old.mRtpmaps.begin(); it != old.mRtpmaps.end(); ++it) { 135 rtpmap->mRtpmaps.push_back(*it); 136 } 137 } 138 139 SdpRtpmapAttributeList::CodecType codec = 140 SdpRtpmapAttributeList::kOtherCodec; 141 if (name == "opus") { 142 codec = SdpRtpmapAttributeList::kOpus; 143 } else if (name == "VP8") { 144 codec = SdpRtpmapAttributeList::kVP8; 145 } else if (name == "VP9") { 146 codec = SdpRtpmapAttributeList::kVP9; 147 } else if (name == "H264") { 148 codec = SdpRtpmapAttributeList::kH264; 149 } 150 151 rtpmap->PushEntry(pt, codec, name, clockrate, channels); 152 mAttributeList->SetAttribute(rtpmap); 153 } 154 } 155 156 void RsdparsaSdpMediaSection::ClearCodecs() { 157 // Clear the codecs in rust 158 sdp_media_clear_codecs(mSection); 159 160 mFormats.clear(); 161 mAttributeList->RemoveAttribute(SdpAttribute::kRtpmapAttribute); 162 mAttributeList->RemoveAttribute(SdpAttribute::kFmtpAttribute); 163 mAttributeList->RemoveAttribute(SdpAttribute::kSctpmapAttribute); 164 mAttributeList->RemoveAttribute(SdpAttribute::kRtcpFbAttribute); 165 } 166 167 void RsdparsaSdpMediaSection::AddDataChannel(const std::string& name, 168 uint16_t port, uint16_t streams, 169 uint32_t message_size) { 170 StringView rustName{name.c_str(), name.size()}; 171 auto nr = sdp_media_add_datachannel(mSection, rustName, port, streams, 172 message_size); 173 if (NS_SUCCEEDED(nr)) { 174 // Update the formats 175 mFormats.clear(); 176 LoadFormats(); 177 178 // Update the attribute list 179 RsdparsaSessionHandle sessHandle(sdp_new_reference(mSession.get())); 180 auto sessAttributes = mAttributeList->mSessionAttributes; 181 mAttributeList.reset(new RsdparsaSdpAttributeList( 182 std::move(sessHandle), mSection, sessAttributes)); 183 } 184 } 185 186 void RsdparsaSdpMediaSection::Serialize(std::ostream& os) const { 187 os << "m=" << mMediaType << " " << GetPort(); 188 if (GetPortCount()) { 189 os << "/" << GetPortCount(); 190 } 191 os << " " << GetProtocol(); 192 for (auto i = mFormats.begin(); i != mFormats.end(); ++i) { 193 os << " " << (*i); 194 } 195 os << CRLF; 196 197 // We dont do i= 198 199 if (mConnection) { 200 os << *mConnection; 201 } 202 203 BandwidthVec* bwVec = sdp_get_media_bandwidth_vec(mSection); 204 char* bwString = sdp_serialize_bandwidth(bwVec); 205 if (bwString) { 206 os << bwString; 207 sdp_free_string(bwString); 208 } 209 210 // We dont do k= because they're evil 211 212 os << *mAttributeList; 213 } 214 215 void RsdparsaSdpMediaSection::LoadFormats() { 216 RustSdpFormatType formatType = sdp_get_format_type(mSection); 217 if (formatType == RustSdpFormatType::kRustIntegers) { 218 U32Vec* vec = sdp_get_format_u32_vec(mSection); 219 size_t len = u32_vec_len(vec); 220 for (size_t i = 0; i < len; i++) { 221 uint32_t val; 222 u32_vec_get(vec, i, &val); 223 mFormats.push_back(std::to_string(val)); 224 } 225 } else { 226 StringVec* vec = sdp_get_format_string_vec(mSection); 227 mFormats = convertStringVec(vec); 228 } 229 } 230 231 UniquePtr<SdpConnection> convertRustConnection(RustSdpConnection conn) { 232 auto address = convertExplicitlyTypedAddress(&conn.addr); 233 return MakeUnique<SdpConnection>(address.first, address.second, conn.ttl, 234 conn.amount); 235 } 236 237 void RsdparsaSdpMediaSection::LoadConnection() { 238 RustSdpConnection conn; 239 nsresult nr; 240 if (sdp_media_has_connection(mSection)) { 241 nr = sdp_get_media_connection(mSection, &conn); 242 if (NS_SUCCEEDED(nr)) { 243 mConnection = convertRustConnection(conn); 244 } 245 } else if (sdp_session_has_connection(mSession.get())) { 246 nr = sdp_get_session_connection(mSession.get(), &conn); 247 if (NS_SUCCEEDED(nr)) { 248 mConnection = convertRustConnection(conn); 249 } 250 } 251 } 252 253 } // namespace mozilla