2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
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.
11 #include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
13 #include "webrtc/system_wrappers/interface/logging.h"
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),
27 payload_type_rtx_(-1),
30 RTPPayloadRegistry::~RTPPayloadRegistry() {
31 while (!payload_type_map_.empty()) {
32 ModuleRTPUtility::PayloadTypeMap::iterator it = payload_type_map_.begin();
34 payload_type_map_.erase(it);
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,
44 bool* created_new_payload) {
45 assert(payload_type >= 0);
47 *created_new_payload = false;
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: "
68 size_t payload_name_length = strlen(payload_name);
70 CriticalSectionScoped cs(crit_sect_.get());
72 ModuleRTPUtility::PayloadTypeMap::iterator it =
73 payload_type_map_.find(payload_type);
75 if (it != payload_type_map_.end()) {
76 // We already use this payload type.
77 ModuleRTPUtility::Payload* payload = it->second;
81 size_t name_length = strlen(payload->name);
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 ModuleRTPUtility::StringCompare(
87 payload->name, payload_name, payload_name_length)) {
88 if (rtp_payload_strategy_->PayloadIsCompatible(*payload, frequency,
90 rtp_payload_strategy_->UpdatePayloadRate(payload, rate);
94 LOG(LS_ERROR) << "Payload type already registered: " << payload_type;
98 if (rtp_payload_strategy_->CodecsMustBeUnique()) {
99 DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType(
100 payload_name, payload_name_length, frequency, channels, rate);
103 ModuleRTPUtility::Payload* payload = NULL;
105 // Save the RED payload type. Used in both audio and video.
106 if (ModuleRTPUtility::StringCompare(payload_name, "red", 3)) {
107 red_payload_type_ = payload_type;
108 payload = new ModuleRTPUtility::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 (ModuleRTPUtility::StringCompare(payload_name, "ulpfec", 3)) {
113 ulpfec_payload_type_ = payload_type;
114 payload = new ModuleRTPUtility::Payload;
115 memset(payload, 0, sizeof(*payload));
116 payload->audio = false;
117 strncpy(payload->name, payload_name, RTP_PAYLOAD_NAME_SIZE - 1);
119 *created_new_payload = true;
120 payload = rtp_payload_strategy_->CreatePayloadType(
121 payload_name, payload_type, frequency, channels, rate);
123 payload_type_map_[payload_type] = payload;
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;
132 int32_t RTPPayloadRegistry::DeRegisterReceivePayload(
133 const int8_t payload_type) {
134 CriticalSectionScoped cs(crit_sect_.get());
135 ModuleRTPUtility::PayloadTypeMap::iterator it =
136 payload_type_map_.find(payload_type);
137 assert(it != payload_type_map_.end());
139 payload_type_map_.erase(it);
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 ModuleRTPUtility::PayloadTypeMap::iterator iterator =
153 payload_type_map_.begin();
154 for (; iterator != payload_type_map_.end(); ++iterator) {
155 ModuleRTPUtility::Payload* payload = iterator->second;
156 size_t name_length = strlen(payload->name);
158 if (payload_name_length == name_length
159 && ModuleRTPUtility::StringCompare(payload->name, payload_name,
160 payload_name_length)) {
161 // We found the payload name in the list.
162 // If audio, check frequency and rate.
163 if (payload->audio) {
164 if (rtp_payload_strategy_->PayloadIsCompatible(*payload, frequency,
166 // Remove old setting.
168 payload_type_map_.erase(iterator);
171 } else if (ModuleRTPUtility::StringCompare(payload_name, "red", 3)) {
173 payload_type_map_.erase(iterator);
180 int32_t RTPPayloadRegistry::ReceivePayloadType(
181 const char payload_name[RTP_PAYLOAD_NAME_SIZE],
182 const uint32_t frequency,
183 const uint8_t channels,
185 int8_t* payload_type) const {
186 assert(payload_type);
187 size_t payload_name_length = strlen(payload_name);
189 CriticalSectionScoped cs(crit_sect_.get());
191 ModuleRTPUtility::PayloadTypeMap::const_iterator it =
192 payload_type_map_.begin();
194 for (; it != payload_type_map_.end(); ++it) {
195 ModuleRTPUtility::Payload* payload = it->second;
198 size_t name_length = strlen(payload->name);
199 if (payload_name_length == name_length &&
200 ModuleRTPUtility::StringCompare(
201 payload->name, payload_name, payload_name_length)) {
203 if (payload->audio) {
205 // [default] audio, check freq and channels.
206 if (payload->typeSpecific.Audio.frequency == frequency &&
207 payload->typeSpecific.Audio.channels == channels) {
208 *payload_type = it->first;
212 // Non-default audio, check freq, channels and rate.
213 if (payload->typeSpecific.Audio.frequency == frequency &&
214 payload->typeSpecific.Audio.channels == channels &&
215 payload->typeSpecific.Audio.rate == rate) {
216 // extra rate condition added
217 *payload_type = it->first;
223 *payload_type = it->first;
231 void RTPPayloadRegistry::SetRtxStatus(bool enable, uint32_t ssrc) {
232 CriticalSectionScoped cs(crit_sect_.get());
237 bool RTPPayloadRegistry::RtxEnabled() const {
238 CriticalSectionScoped cs(crit_sect_.get());
242 bool RTPPayloadRegistry::IsRtx(const RTPHeader& header) const {
243 CriticalSectionScoped cs(crit_sect_.get());
244 return IsRtxInternal(header);
247 bool RTPPayloadRegistry::IsRtxInternal(const RTPHeader& header) const {
248 return rtx_ && ssrc_rtx_ == header.ssrc;
251 bool RTPPayloadRegistry::RestoreOriginalPacket(uint8_t** restored_packet,
252 const uint8_t* packet,
254 uint32_t original_ssrc,
255 const RTPHeader& header) const {
256 if (kRtxHeaderSize + header.headerLength > *packet_length) {
259 const uint8_t* rtx_header = packet + header.headerLength;
260 uint16_t original_sequence_number = (rtx_header[0] << 8) + rtx_header[1];
262 // Copy the packet into the restored packet, except for the RTX header.
263 memcpy(*restored_packet, packet, header.headerLength);
264 memcpy(*restored_packet + header.headerLength,
265 packet + header.headerLength + kRtxHeaderSize,
266 *packet_length - header.headerLength - kRtxHeaderSize);
267 *packet_length -= kRtxHeaderSize;
269 // Replace the SSRC and the sequence number with the originals.
270 ModuleRTPUtility::AssignUWord16ToBuffer(*restored_packet + 2,
271 original_sequence_number);
272 ModuleRTPUtility::AssignUWord32ToBuffer(*restored_packet + 8, original_ssrc);
274 CriticalSectionScoped cs(crit_sect_.get());
276 if (payload_type_rtx_ != -1) {
277 if (header.payloadType == payload_type_rtx_ &&
278 incoming_payload_type_ != -1) {
279 (*restored_packet)[1] = static_cast<uint8_t>(incoming_payload_type_);
280 if (header.markerBit) {
281 (*restored_packet)[1] |= kRtpMarkerBitMask; // Marker bit is set.
284 LOG(LS_WARNING) << "Incorrect RTX configuration, dropping packet.";
291 void RTPPayloadRegistry::SetRtxPayloadType(int payload_type) {
292 CriticalSectionScoped cs(crit_sect_.get());
293 payload_type_rtx_ = payload_type;
296 bool RTPPayloadRegistry::IsRed(const RTPHeader& header) const {
297 CriticalSectionScoped cs(crit_sect_.get());
298 return red_payload_type_ == header.payloadType;
301 bool RTPPayloadRegistry::IsEncapsulated(const RTPHeader& header) const {
302 return IsRed(header) || IsRtx(header);
305 bool RTPPayloadRegistry::GetPayloadSpecifics(uint8_t payload_type,
306 PayloadUnion* payload) const {
307 CriticalSectionScoped cs(crit_sect_.get());
308 ModuleRTPUtility::PayloadTypeMap::const_iterator it =
309 payload_type_map_.find(payload_type);
311 // Check that this is a registered payload type.
312 if (it == payload_type_map_.end()) {
315 *payload = it->second->typeSpecific;
319 int RTPPayloadRegistry::GetPayloadTypeFrequency(
320 uint8_t payload_type) const {
321 ModuleRTPUtility::Payload* payload;
322 if (!PayloadTypeToPayload(payload_type, payload)) {
325 CriticalSectionScoped cs(crit_sect_.get());
326 return rtp_payload_strategy_->GetPayloadTypeFrequency(*payload);
329 bool RTPPayloadRegistry::PayloadTypeToPayload(
330 const uint8_t payload_type,
331 ModuleRTPUtility::Payload*& payload) const {
332 CriticalSectionScoped cs(crit_sect_.get());
334 ModuleRTPUtility::PayloadTypeMap::const_iterator it =
335 payload_type_map_.find(payload_type);
337 // Check that this is a registered payload type.
338 if (it == payload_type_map_.end()) {
342 payload = it->second;
346 void RTPPayloadRegistry::SetIncomingPayloadType(const RTPHeader& header) {
347 CriticalSectionScoped cs(crit_sect_.get());
348 if (!IsRtxInternal(header))
349 incoming_payload_type_ = header.payloadType;
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.
358 last_received_media_payload_type_ = media_payload_type;
362 class RTPPayloadAudioStrategy : public RTPPayloadStrategy {
364 virtual bool CodecsMustBeUnique() const OVERRIDE { return true; }
366 virtual bool PayloadIsCompatible(
367 const ModuleRTPUtility::Payload& payload,
368 const uint32_t frequency,
369 const uint8_t channels,
370 const uint32_t rate) const OVERRIDE {
373 payload.typeSpecific.Audio.frequency == frequency &&
374 payload.typeSpecific.Audio.channels == channels &&
375 (payload.typeSpecific.Audio.rate == rate ||
376 payload.typeSpecific.Audio.rate == 0 || rate == 0);
379 virtual void UpdatePayloadRate(
380 ModuleRTPUtility::Payload* payload,
381 const uint32_t rate) const OVERRIDE {
382 payload->typeSpecific.Audio.rate = rate;
385 virtual ModuleRTPUtility::Payload* CreatePayloadType(
386 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
387 const int8_t payloadType,
388 const uint32_t frequency,
389 const uint8_t channels,
390 const uint32_t rate) const OVERRIDE {
391 ModuleRTPUtility::Payload* payload = new ModuleRTPUtility::Payload;
392 payload->name[RTP_PAYLOAD_NAME_SIZE - 1] = 0;
393 strncpy(payload->name, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
394 assert(frequency >= 1000);
395 payload->typeSpecific.Audio.frequency = frequency;
396 payload->typeSpecific.Audio.channels = channels;
397 payload->typeSpecific.Audio.rate = rate;
398 payload->audio = true;
402 int GetPayloadTypeFrequency(
403 const ModuleRTPUtility::Payload& payload) const {
404 return payload.typeSpecific.Audio.frequency;
408 class RTPPayloadVideoStrategy : public RTPPayloadStrategy {
410 virtual bool CodecsMustBeUnique() const OVERRIDE { return false; }
412 virtual bool PayloadIsCompatible(
413 const ModuleRTPUtility::Payload& payload,
414 const uint32_t frequency,
415 const uint8_t channels,
416 const uint32_t rate) const OVERRIDE {
417 return !payload.audio;
420 virtual void UpdatePayloadRate(
421 ModuleRTPUtility::Payload* payload,
422 const uint32_t rate) const OVERRIDE {
423 payload->typeSpecific.Video.maxRate = rate;
426 virtual ModuleRTPUtility::Payload* CreatePayloadType(
427 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
428 const int8_t payloadType,
429 const uint32_t frequency,
430 const uint8_t channels,
431 const uint32_t rate) const OVERRIDE {
432 RtpVideoCodecTypes videoType = kRtpVideoGeneric;
433 if (ModuleRTPUtility::StringCompare(payloadName, "VP8", 3)) {
434 videoType = kRtpVideoVp8;
435 } else if (ModuleRTPUtility::StringCompare(payloadName, "I420", 4)) {
436 videoType = kRtpVideoGeneric;
437 } else if (ModuleRTPUtility::StringCompare(payloadName, "ULPFEC", 6)) {
438 videoType = kRtpVideoNone;
440 videoType = kRtpVideoGeneric;
442 ModuleRTPUtility::Payload* payload = new ModuleRTPUtility::Payload;
444 payload->name[RTP_PAYLOAD_NAME_SIZE - 1] = 0;
445 strncpy(payload->name, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
446 payload->typeSpecific.Video.videoCodecType = videoType;
447 payload->typeSpecific.Video.maxRate = rate;
448 payload->audio = false;
452 int GetPayloadTypeFrequency(
453 const ModuleRTPUtility::Payload& payload) const {
454 return kVideoPayloadTypeFrequency;
458 RTPPayloadStrategy* RTPPayloadStrategy::CreateStrategy(
459 const bool handling_audio) {
460 if (handling_audio) {
461 return new RTPPayloadAudioStrategy();
463 return new RTPPayloadVideoStrategy();
467 } // namespace webrtc