rtp_payload_registry.cc revision 9de89a6f6bd9e7635c41966a9ab4b8d818521e57
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/trace.h" 14 15namespace webrtc { 16 17RTPPayloadRegistry::RTPPayloadRegistry( 18 const int32_t id, 19 RTPPayloadStrategy* rtp_payload_strategy) 20 : id_(id), 21 rtp_payload_strategy_(rtp_payload_strategy), 22 red_payload_type_(-1), 23 last_received_payload_type_(-1), 24 last_received_media_payload_type_(-1) {} 25 26RTPPayloadRegistry::~RTPPayloadRegistry() { 27 while (!payload_type_map_.empty()) { 28 ModuleRTPUtility::PayloadTypeMap::iterator it = payload_type_map_.begin(); 29 delete it->second; 30 payload_type_map_.erase(it); 31 } 32} 33 34int32_t RTPPayloadRegistry::RegisterReceivePayload( 35 const char payload_name[RTP_PAYLOAD_NAME_SIZE], 36 const int8_t payload_type, 37 const uint32_t frequency, 38 const uint8_t channels, 39 const uint32_t rate, 40 bool* created_new_payload) { 41 assert(payload_type >= 0); 42 assert(payload_name); 43 *created_new_payload = false; 44 45 // Sanity check. 46 switch (payload_type) { 47 // Reserved payload types to avoid RTCP conflicts when marker bit is set. 48 case 64: // 192 Full INTRA-frame request. 49 case 72: // 200 Sender report. 50 case 73: // 201 Receiver report. 51 case 74: // 202 Source description. 52 case 75: // 203 Goodbye. 53 case 76: // 204 Application-defined. 54 case 77: // 205 Transport layer FB message. 55 case 78: // 206 Payload-specific FB message. 56 case 79: // 207 Extended report. 57 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, id_, 58 "%s invalid payloadtype:%d", 59 __FUNCTION__, payload_type); 60 return -1; 61 default: 62 break; 63 } 64 65 size_t payload_name_length = strlen(payload_name); 66 67 ModuleRTPUtility::PayloadTypeMap::iterator it = 68 payload_type_map_.find(payload_type); 69 70 if (it != payload_type_map_.end()) { 71 // We already use this payload type. 72 ModuleRTPUtility::Payload* payload = it->second; 73 74 assert(payload); 75 76 size_t name_length = strlen(payload->name); 77 78 // Check if it's the same as we already have. 79 // If same, ignore sending an error. 80 if (payload_name_length == name_length && 81 ModuleRTPUtility::StringCompare( 82 payload->name, payload_name, payload_name_length)) { 83 if (rtp_payload_strategy_->PayloadIsCompatible(*payload, frequency, 84 channels, rate)) { 85 rtp_payload_strategy_->UpdatePayloadRate(payload, rate); 86 return 0; 87 } 88 } 89 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, id_, 90 "%s invalid argument payload_type:%d already registered", 91 __FUNCTION__, payload_type); 92 return -1; 93 } 94 95 if (rtp_payload_strategy_->CodecsMustBeUnique()) { 96 DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType( 97 payload_name, payload_name_length, frequency, channels, rate); 98 } 99 100 ModuleRTPUtility::Payload* payload = NULL; 101 102 // Save the RED payload type. Used in both audio and video. 103 if (ModuleRTPUtility::StringCompare(payload_name, "red", 3)) { 104 red_payload_type_ = payload_type; 105 payload = new ModuleRTPUtility::Payload; 106 memset(payload, 0, sizeof(*payload)); 107 payload->audio = false; 108 payload->name[RTP_PAYLOAD_NAME_SIZE - 1] = 0; 109 strncpy(payload->name, payload_name, RTP_PAYLOAD_NAME_SIZE - 1); 110 } else { 111 *created_new_payload = true; 112 payload = rtp_payload_strategy_->CreatePayloadType( 113 payload_name, payload_type, frequency, channels, rate); 114 } 115 payload_type_map_[payload_type] = payload; 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 ModuleRTPUtility::PayloadTypeMap::iterator it = 127 payload_type_map_.find(payload_type); 128 129 if (it == payload_type_map_.end()) { 130 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, id_, 131 "%s failed to find payload_type:%d", 132 __FUNCTION__, payload_type); 133 return -1; 134 } 135 delete it->second; 136 payload_type_map_.erase(it); 137 return 0; 138} 139 140// There can't be several codecs with the same rate, frequency and channels 141// for audio codecs, but there can for video. 142void RTPPayloadRegistry::DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType( 143 const char payload_name[RTP_PAYLOAD_NAME_SIZE], 144 const size_t payload_name_length, 145 const uint32_t frequency, 146 const uint8_t channels, 147 const uint32_t rate) { 148 ModuleRTPUtility::PayloadTypeMap::iterator iterator = 149 payload_type_map_.begin(); 150 for (; iterator != payload_type_map_.end(); ++iterator) { 151 ModuleRTPUtility::Payload* payload = iterator->second; 152 size_t name_length = strlen(payload->name); 153 154 if (payload_name_length == name_length 155 && ModuleRTPUtility::StringCompare(payload->name, payload_name, 156 payload_name_length)) { 157 // We found the payload name in the list. 158 // If audio, check frequency and rate. 159 if (payload->audio) { 160 if (rtp_payload_strategy_->PayloadIsCompatible(*payload, frequency, 161 channels, rate)) { 162 // Remove old setting. 163 delete payload; 164 payload_type_map_.erase(iterator); 165 break; 166 } 167 } else if (ModuleRTPUtility::StringCompare(payload_name, "red", 3)) { 168 delete payload; 169 payload_type_map_.erase(iterator); 170 break; 171 } 172 } 173 } 174} 175 176int32_t RTPPayloadRegistry::ReceivePayloadType( 177 const char payload_name[RTP_PAYLOAD_NAME_SIZE], 178 const uint32_t frequency, 179 const uint8_t channels, 180 const uint32_t rate, 181 int8_t* payload_type) const { 182 if (payload_type == NULL) { 183 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, id_, 184 "%s invalid argument", __FUNCTION__); 185 return -1; 186 } 187 size_t payload_name_length = strlen(payload_name); 188 189 ModuleRTPUtility::PayloadTypeMap::const_iterator it = 190 payload_type_map_.begin(); 191 192 for (; it != payload_type_map_.end(); ++it) { 193 ModuleRTPUtility::Payload* payload = it->second; 194 assert(payload); 195 196 size_t name_length = strlen(payload->name); 197 if (payload_name_length == name_length && 198 ModuleRTPUtility::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 229bool RTPPayloadRegistry::GetPayloadSpecifics(uint8_t payload_type, 230 PayloadUnion* payload) const { 231 ModuleRTPUtility::PayloadTypeMap::const_iterator it = 232 payload_type_map_.find(payload_type); 233 234 // Check that this is a registered payload type. 235 if (it == payload_type_map_.end()) { 236 return false; 237 } 238 *payload = it->second->typeSpecific; 239 return true; 240} 241 242int RTPPayloadRegistry::GetPayloadTypeFrequency( 243 uint8_t payload_type) const { 244 ModuleRTPUtility::Payload* payload; 245 if (!PayloadTypeToPayload(payload_type, payload)) { 246 return -1; 247 } 248 return rtp_payload_strategy_->GetPayloadTypeFrequency(*payload); 249} 250 251bool RTPPayloadRegistry::PayloadTypeToPayload( 252 const uint8_t payload_type, 253 ModuleRTPUtility::Payload*& payload) const { 254 255 ModuleRTPUtility::PayloadTypeMap::const_iterator it = 256 payload_type_map_.find(payload_type); 257 258 // Check that this is a registered payload type. 259 if (it == payload_type_map_.end()) { 260 return false; 261 } 262 payload = it->second; 263 return true; 264} 265 266bool RTPPayloadRegistry::ReportMediaPayloadType( 267 uint8_t media_payload_type) { 268 if (last_received_media_payload_type_ == media_payload_type) { 269 // Media type unchanged. 270 return true; 271 } 272 last_received_media_payload_type_ = media_payload_type; 273 return false; 274} 275 276class RTPPayloadAudioStrategy : public RTPPayloadStrategy { 277 public: 278 bool CodecsMustBeUnique() const { return true; } 279 280 bool PayloadIsCompatible( 281 const ModuleRTPUtility::Payload& payload, 282 const uint32_t frequency, 283 const uint8_t channels, 284 const uint32_t rate) const { 285 return 286 payload.audio && 287 payload.typeSpecific.Audio.frequency == frequency && 288 payload.typeSpecific.Audio.channels == channels && 289 (payload.typeSpecific.Audio.rate == rate || 290 payload.typeSpecific.Audio.rate == 0 || rate == 0); 291 } 292 293 void UpdatePayloadRate( 294 ModuleRTPUtility::Payload* payload, 295 const uint32_t rate) const { 296 payload->typeSpecific.Audio.rate = rate; 297 } 298 299 ModuleRTPUtility::Payload* CreatePayloadType( 300 const char payloadName[RTP_PAYLOAD_NAME_SIZE], 301 const int8_t payloadType, 302 const uint32_t frequency, 303 const uint8_t channels, 304 const uint32_t rate) const { 305 ModuleRTPUtility::Payload* payload = new ModuleRTPUtility::Payload; 306 payload->name[RTP_PAYLOAD_NAME_SIZE - 1] = 0; 307 strncpy(payload->name, payloadName, RTP_PAYLOAD_NAME_SIZE - 1); 308 assert(frequency >= 1000); 309 payload->typeSpecific.Audio.frequency = frequency; 310 payload->typeSpecific.Audio.channels = channels; 311 payload->typeSpecific.Audio.rate = rate; 312 payload->audio = true; 313 return payload; 314 } 315 316 int GetPayloadTypeFrequency( 317 const ModuleRTPUtility::Payload& payload) const { 318 return payload.typeSpecific.Audio.frequency; 319 } 320}; 321 322class RTPPayloadVideoStrategy : public RTPPayloadStrategy { 323 public: 324 bool CodecsMustBeUnique() const { return false; } 325 326 bool PayloadIsCompatible( 327 const ModuleRTPUtility::Payload& payload, 328 const uint32_t frequency, 329 const uint8_t channels, 330 const uint32_t rate) const { 331 return !payload.audio; 332 } 333 334 void UpdatePayloadRate( 335 ModuleRTPUtility::Payload* payload, 336 const uint32_t rate) const { 337 payload->typeSpecific.Video.maxRate = rate; 338 } 339 340 ModuleRTPUtility::Payload* CreatePayloadType( 341 const char payloadName[RTP_PAYLOAD_NAME_SIZE], 342 const int8_t payloadType, 343 const uint32_t frequency, 344 const uint8_t channels, 345 const uint32_t rate) const { 346 RtpVideoCodecTypes videoType = kRtpVideoGeneric; 347 if (ModuleRTPUtility::StringCompare(payloadName, "VP8", 3)) { 348 videoType = kRtpVideoVp8; 349 } else if (ModuleRTPUtility::StringCompare(payloadName, "I420", 4)) { 350 videoType = kRtpVideoGeneric; 351 } else if (ModuleRTPUtility::StringCompare(payloadName, "ULPFEC", 6)) { 352 videoType = kRtpVideoFec; 353 } else { 354 videoType = kRtpVideoGeneric; 355 } 356 ModuleRTPUtility::Payload* payload = new ModuleRTPUtility::Payload; 357 358 payload->name[RTP_PAYLOAD_NAME_SIZE - 1] = 0; 359 strncpy(payload->name, payloadName, RTP_PAYLOAD_NAME_SIZE - 1); 360 payload->typeSpecific.Video.videoCodecType = videoType; 361 payload->typeSpecific.Video.maxRate = rate; 362 payload->audio = false; 363 return payload; 364 } 365 366 int GetPayloadTypeFrequency( 367 const ModuleRTPUtility::Payload& payload) const { 368 return kVideoPayloadTypeFrequency; 369 } 370}; 371 372RTPPayloadStrategy* RTPPayloadStrategy::CreateStrategy( 373 const bool handling_audio) { 374 if (handling_audio) { 375 return new RTPPayloadAudioStrategy(); 376 } else { 377 return new RTPPayloadVideoStrategy(); 378 } 379} 380 381} // namespace webrtc 382