1 /* 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h" 12 13 #include "webrtc/system_wrappers/interface/logging.h" 14 15 namespace webrtc { 16 17 RTPPayloadRegistry::RTPPayloadRegistry( 18 RTPPayloadStrategy* rtp_payload_strategy) 19 : crit_sect_(CriticalSectionWrapper::CreateCriticalSection()), 20 rtp_payload_strategy_(rtp_payload_strategy), 21 red_payload_type_(-1), 22 ulpfec_payload_type_(-1), 23 incoming_payload_type_(-1), 24 last_received_payload_type_(-1), 25 last_received_media_payload_type_(-1), 26 rtx_(false), 27 payload_type_rtx_(-1), 28 ssrc_rtx_(0) {} 29 30 RTPPayloadRegistry::~RTPPayloadRegistry() { 31 while (!payload_type_map_.empty()) { 32 RtpUtility::PayloadTypeMap::iterator it = payload_type_map_.begin(); 33 delete it->second; 34 payload_type_map_.erase(it); 35 } 36 } 37 38 int32_t RTPPayloadRegistry::RegisterReceivePayload( 39 const char payload_name[RTP_PAYLOAD_NAME_SIZE], 40 const int8_t payload_type, 41 const uint32_t frequency, 42 const uint8_t channels, 43 const uint32_t rate, 44 bool* created_new_payload) { 45 assert(payload_type >= 0); 46 assert(payload_name); 47 *created_new_payload = false; 48 49 // Sanity check. 50 switch (payload_type) { 51 // Reserved payload types to avoid RTCP conflicts when marker bit is set. 52 case 64: // 192 Full INTRA-frame request. 53 case 72: // 200 Sender report. 54 case 73: // 201 Receiver report. 55 case 74: // 202 Source description. 56 case 75: // 203 Goodbye. 57 case 76: // 204 Application-defined. 58 case 77: // 205 Transport layer FB message. 59 case 78: // 206 Payload-specific FB message. 60 case 79: // 207 Extended report. 61 LOG(LS_ERROR) << "Can't register invalid receiver payload type: " 62 << payload_type; 63 return -1; 64 default: 65 break; 66 } 67 68 size_t payload_name_length = strlen(payload_name); 69 70 CriticalSectionScoped cs(crit_sect_.get()); 71 72 RtpUtility::PayloadTypeMap::iterator it = 73 payload_type_map_.find(payload_type); 74 75 if (it != payload_type_map_.end()) { 76 // We already use this payload type. 77 RtpUtility::Payload* payload = it->second; 78 79 assert(payload); 80 81 size_t name_length = strlen(payload->name); 82 83 // Check if it's the same as we already have. 84 // If same, ignore sending an error. 85 if (payload_name_length == name_length && 86 RtpUtility::StringCompare( 87 payload->name, payload_name, payload_name_length)) { 88 if (rtp_payload_strategy_->PayloadIsCompatible(*payload, frequency, 89 channels, rate)) { 90 rtp_payload_strategy_->UpdatePayloadRate(payload, rate); 91 return 0; 92 } 93 } 94 LOG(LS_ERROR) << "Payload type already registered: " << payload_type; 95 return -1; 96 } 97 98 if (rtp_payload_strategy_->CodecsMustBeUnique()) { 99 DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType( 100 payload_name, payload_name_length, frequency, channels, rate); 101 } 102 103 RtpUtility::Payload* payload = NULL; 104 105 // Save the RED payload type. Used in both audio and video. 106 if (RtpUtility::StringCompare(payload_name, "red", 3)) { 107 red_payload_type_ = payload_type; 108 payload = new RtpUtility::Payload; 109 memset(payload, 0, sizeof(*payload)); 110 payload->audio = false; 111 strncpy(payload->name, payload_name, RTP_PAYLOAD_NAME_SIZE - 1); 112 } else if (RtpUtility::StringCompare(payload_name, "ulpfec", 3)) { 113 ulpfec_payload_type_ = payload_type; 114 payload = new RtpUtility::Payload; 115 memset(payload, 0, sizeof(*payload)); 116 payload->audio = false; 117 strncpy(payload->name, payload_name, RTP_PAYLOAD_NAME_SIZE - 1); 118 } else { 119 *created_new_payload = true; 120 payload = rtp_payload_strategy_->CreatePayloadType( 121 payload_name, payload_type, frequency, channels, rate); 122 } 123 payload_type_map_[payload_type] = payload; 124 125 // Successful set of payload type, clear the value of last received payload 126 // type since it might mean something else. 127 last_received_payload_type_ = -1; 128 last_received_media_payload_type_ = -1; 129 return 0; 130 } 131 132 int32_t RTPPayloadRegistry::DeRegisterReceivePayload( 133 const int8_t payload_type) { 134 CriticalSectionScoped cs(crit_sect_.get()); 135 RtpUtility::PayloadTypeMap::iterator it = 136 payload_type_map_.find(payload_type); 137 assert(it != payload_type_map_.end()); 138 delete it->second; 139 payload_type_map_.erase(it); 140 return 0; 141 } 142 143 // There can't be several codecs with the same rate, frequency and channels 144 // for audio codecs, but there can for video. 145 // Always called from within a critical section. 146 void RTPPayloadRegistry::DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType( 147 const char payload_name[RTP_PAYLOAD_NAME_SIZE], 148 const size_t payload_name_length, 149 const uint32_t frequency, 150 const uint8_t channels, 151 const uint32_t rate) { 152 RtpUtility::PayloadTypeMap::iterator iterator = payload_type_map_.begin(); 153 for (; iterator != payload_type_map_.end(); ++iterator) { 154 RtpUtility::Payload* payload = iterator->second; 155 size_t name_length = strlen(payload->name); 156 157 if (payload_name_length == name_length && 158 RtpUtility::StringCompare( 159 payload->name, payload_name, payload_name_length)) { 160 // We found the payload name in the list. 161 // If audio, check frequency and rate. 162 if (payload->audio) { 163 if (rtp_payload_strategy_->PayloadIsCompatible(*payload, frequency, 164 channels, rate)) { 165 // Remove old setting. 166 delete payload; 167 payload_type_map_.erase(iterator); 168 break; 169 } 170 } else if (RtpUtility::StringCompare(payload_name, "red", 3)) { 171 delete payload; 172 payload_type_map_.erase(iterator); 173 break; 174 } 175 } 176 } 177 } 178 179 int32_t RTPPayloadRegistry::ReceivePayloadType( 180 const char payload_name[RTP_PAYLOAD_NAME_SIZE], 181 const uint32_t frequency, 182 const uint8_t channels, 183 const uint32_t rate, 184 int8_t* payload_type) const { 185 assert(payload_type); 186 size_t payload_name_length = strlen(payload_name); 187 188 CriticalSectionScoped cs(crit_sect_.get()); 189 190 RtpUtility::PayloadTypeMap::const_iterator it = payload_type_map_.begin(); 191 192 for (; it != payload_type_map_.end(); ++it) { 193 RtpUtility::Payload* payload = it->second; 194 assert(payload); 195 196 size_t name_length = strlen(payload->name); 197 if (payload_name_length == name_length && 198 RtpUtility::StringCompare( 199 payload->name, payload_name, payload_name_length)) { 200 // Name matches. 201 if (payload->audio) { 202 if (rate == 0) { 203 // [default] audio, check freq and channels. 204 if (payload->typeSpecific.Audio.frequency == frequency && 205 payload->typeSpecific.Audio.channels == channels) { 206 *payload_type = it->first; 207 return 0; 208 } 209 } else { 210 // Non-default audio, check freq, channels and rate. 211 if (payload->typeSpecific.Audio.frequency == frequency && 212 payload->typeSpecific.Audio.channels == channels && 213 payload->typeSpecific.Audio.rate == rate) { 214 // extra rate condition added 215 *payload_type = it->first; 216 return 0; 217 } 218 } 219 } else { 220 // Video. 221 *payload_type = it->first; 222 return 0; 223 } 224 } 225 } 226 return -1; 227 } 228 229 bool RTPPayloadRegistry::RtxEnabled() const { 230 CriticalSectionScoped cs(crit_sect_.get()); 231 return rtx_; 232 } 233 234 bool RTPPayloadRegistry::IsRtx(const RTPHeader& header) const { 235 CriticalSectionScoped cs(crit_sect_.get()); 236 return IsRtxInternal(header); 237 } 238 239 bool RTPPayloadRegistry::IsRtxInternal(const RTPHeader& header) const { 240 return rtx_ && ssrc_rtx_ == header.ssrc; 241 } 242 243 bool RTPPayloadRegistry::RestoreOriginalPacket(uint8_t** restored_packet, 244 const uint8_t* packet, 245 int* packet_length, 246 uint32_t original_ssrc, 247 const RTPHeader& header) const { 248 if (kRtxHeaderSize + header.headerLength > *packet_length) { 249 return false; 250 } 251 const uint8_t* rtx_header = packet + header.headerLength; 252 uint16_t original_sequence_number = (rtx_header[0] << 8) + rtx_header[1]; 253 254 // Copy the packet into the restored packet, except for the RTX header. 255 memcpy(*restored_packet, packet, header.headerLength); 256 memcpy(*restored_packet + header.headerLength, 257 packet + header.headerLength + kRtxHeaderSize, 258 *packet_length - header.headerLength - kRtxHeaderSize); 259 *packet_length -= kRtxHeaderSize; 260 261 // Replace the SSRC and the sequence number with the originals. 262 RtpUtility::AssignUWord16ToBuffer(*restored_packet + 2, 263 original_sequence_number); 264 RtpUtility::AssignUWord32ToBuffer(*restored_packet + 8, original_ssrc); 265 266 CriticalSectionScoped cs(crit_sect_.get()); 267 268 if (payload_type_rtx_ != -1) { 269 if (header.payloadType == payload_type_rtx_ && 270 incoming_payload_type_ != -1) { 271 (*restored_packet)[1] = static_cast<uint8_t>(incoming_payload_type_); 272 if (header.markerBit) { 273 (*restored_packet)[1] |= kRtpMarkerBitMask; // Marker bit is set. 274 } 275 } else { 276 LOG(LS_WARNING) << "Incorrect RTX configuration, dropping packet."; 277 return false; 278 } 279 } 280 return true; 281 } 282 283 void RTPPayloadRegistry::SetRtxSsrc(uint32_t ssrc) { 284 CriticalSectionScoped cs(crit_sect_.get()); 285 ssrc_rtx_ = ssrc; 286 rtx_ = true; 287 } 288 289 void RTPPayloadRegistry::SetRtxPayloadType(int payload_type) { 290 CriticalSectionScoped cs(crit_sect_.get()); 291 assert(payload_type >= 0); 292 payload_type_rtx_ = payload_type; 293 rtx_ = true; 294 } 295 296 bool RTPPayloadRegistry::IsRed(const RTPHeader& header) const { 297 CriticalSectionScoped cs(crit_sect_.get()); 298 return red_payload_type_ == header.payloadType; 299 } 300 301 bool RTPPayloadRegistry::IsEncapsulated(const RTPHeader& header) const { 302 return IsRed(header) || IsRtx(header); 303 } 304 305 bool RTPPayloadRegistry::GetPayloadSpecifics(uint8_t payload_type, 306 PayloadUnion* payload) const { 307 CriticalSectionScoped cs(crit_sect_.get()); 308 RtpUtility::PayloadTypeMap::const_iterator it = 309 payload_type_map_.find(payload_type); 310 311 // Check that this is a registered payload type. 312 if (it == payload_type_map_.end()) { 313 return false; 314 } 315 *payload = it->second->typeSpecific; 316 return true; 317 } 318 319 int RTPPayloadRegistry::GetPayloadTypeFrequency( 320 uint8_t payload_type) const { 321 RtpUtility::Payload* payload; 322 if (!PayloadTypeToPayload(payload_type, payload)) { 323 return -1; 324 } 325 CriticalSectionScoped cs(crit_sect_.get()); 326 return rtp_payload_strategy_->GetPayloadTypeFrequency(*payload); 327 } 328 329 bool RTPPayloadRegistry::PayloadTypeToPayload( 330 const uint8_t payload_type, 331 RtpUtility::Payload*& payload) const { 332 CriticalSectionScoped cs(crit_sect_.get()); 333 334 RtpUtility::PayloadTypeMap::const_iterator it = 335 payload_type_map_.find(payload_type); 336 337 // Check that this is a registered payload type. 338 if (it == payload_type_map_.end()) { 339 return false; 340 } 341 342 payload = it->second; 343 return true; 344 } 345 346 void RTPPayloadRegistry::SetIncomingPayloadType(const RTPHeader& header) { 347 CriticalSectionScoped cs(crit_sect_.get()); 348 if (!IsRtxInternal(header)) 349 incoming_payload_type_ = header.payloadType; 350 } 351 352 bool RTPPayloadRegistry::ReportMediaPayloadType(uint8_t media_payload_type) { 353 CriticalSectionScoped cs(crit_sect_.get()); 354 if (last_received_media_payload_type_ == media_payload_type) { 355 // Media type unchanged. 356 return true; 357 } 358 last_received_media_payload_type_ = media_payload_type; 359 return false; 360 } 361 362 class RTPPayloadAudioStrategy : public RTPPayloadStrategy { 363 public: 364 virtual bool CodecsMustBeUnique() const OVERRIDE { return true; } 365 366 virtual bool PayloadIsCompatible(const RtpUtility::Payload& payload, 367 const uint32_t frequency, 368 const uint8_t channels, 369 const uint32_t rate) const OVERRIDE { 370 return 371 payload.audio && 372 payload.typeSpecific.Audio.frequency == frequency && 373 payload.typeSpecific.Audio.channels == channels && 374 (payload.typeSpecific.Audio.rate == rate || 375 payload.typeSpecific.Audio.rate == 0 || rate == 0); 376 } 377 378 virtual void UpdatePayloadRate(RtpUtility::Payload* payload, 379 const uint32_t rate) const OVERRIDE { 380 payload->typeSpecific.Audio.rate = rate; 381 } 382 383 virtual RtpUtility::Payload* CreatePayloadType( 384 const char payloadName[RTP_PAYLOAD_NAME_SIZE], 385 const int8_t payloadType, 386 const uint32_t frequency, 387 const uint8_t channels, 388 const uint32_t rate) const OVERRIDE { 389 RtpUtility::Payload* payload = new RtpUtility::Payload; 390 payload->name[RTP_PAYLOAD_NAME_SIZE - 1] = 0; 391 strncpy(payload->name, payloadName, RTP_PAYLOAD_NAME_SIZE - 1); 392 assert(frequency >= 1000); 393 payload->typeSpecific.Audio.frequency = frequency; 394 payload->typeSpecific.Audio.channels = channels; 395 payload->typeSpecific.Audio.rate = rate; 396 payload->audio = true; 397 return payload; 398 } 399 400 int GetPayloadTypeFrequency(const RtpUtility::Payload& payload) const { 401 return payload.typeSpecific.Audio.frequency; 402 } 403 }; 404 405 class RTPPayloadVideoStrategy : public RTPPayloadStrategy { 406 public: 407 virtual bool CodecsMustBeUnique() const OVERRIDE { return false; } 408 409 virtual bool PayloadIsCompatible(const RtpUtility::Payload& payload, 410 const uint32_t frequency, 411 const uint8_t channels, 412 const uint32_t rate) const OVERRIDE { 413 return !payload.audio; 414 } 415 416 virtual void UpdatePayloadRate(RtpUtility::Payload* payload, 417 const uint32_t rate) const OVERRIDE { 418 payload->typeSpecific.Video.maxRate = rate; 419 } 420 421 virtual RtpUtility::Payload* CreatePayloadType( 422 const char payloadName[RTP_PAYLOAD_NAME_SIZE], 423 const int8_t payloadType, 424 const uint32_t frequency, 425 const uint8_t channels, 426 const uint32_t rate) const OVERRIDE { 427 RtpVideoCodecTypes videoType = kRtpVideoGeneric; 428 if (RtpUtility::StringCompare(payloadName, "VP8", 3)) { 429 videoType = kRtpVideoVp8; 430 } else if (RtpUtility::StringCompare(payloadName, "H264", 4)) { 431 videoType = kRtpVideoH264; 432 } else if (RtpUtility::StringCompare(payloadName, "I420", 4)) { 433 videoType = kRtpVideoGeneric; 434 } else if (RtpUtility::StringCompare(payloadName, "ULPFEC", 6)) { 435 videoType = kRtpVideoNone; 436 } else { 437 videoType = kRtpVideoGeneric; 438 } 439 RtpUtility::Payload* payload = new RtpUtility::Payload; 440 441 payload->name[RTP_PAYLOAD_NAME_SIZE - 1] = 0; 442 strncpy(payload->name, payloadName, RTP_PAYLOAD_NAME_SIZE - 1); 443 payload->typeSpecific.Video.videoCodecType = videoType; 444 payload->typeSpecific.Video.maxRate = rate; 445 payload->audio = false; 446 return payload; 447 } 448 449 int GetPayloadTypeFrequency(const RtpUtility::Payload& payload) const { 450 return kVideoPayloadTypeFrequency; 451 } 452 }; 453 454 RTPPayloadStrategy* RTPPayloadStrategy::CreateStrategy( 455 const bool handling_audio) { 456 if (handling_audio) { 457 return new RTPPayloadAudioStrategy(); 458 } else { 459 return new RTPPayloadVideoStrategy(); 460 } 461 } 462 463 } // namespace webrtc 464