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