Home | History | Annotate | Download | only in source
      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 
     16 namespace webrtc {
     17 
     18 RTPPayloadRegistry::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 
     31 RTPPayloadRegistry::~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 
     39 int32_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 
    124 int32_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.
    138 void 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 
    171 int32_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 
    221 bool RTPPayloadRegistry::RtxEnabled() const {
    222   CriticalSectionScoped cs(crit_sect_.get());
    223   return rtx_;
    224 }
    225 
    226 bool RTPPayloadRegistry::IsRtx(const RTPHeader& header) const {
    227   CriticalSectionScoped cs(crit_sect_.get());
    228   return IsRtxInternal(header);
    229 }
    230 
    231 bool RTPPayloadRegistry::IsRtxInternal(const RTPHeader& header) const {
    232   return rtx_ && ssrc_rtx_ == header.ssrc;
    233 }
    234 
    235 bool 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 
    244 bool 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 
    296 void RTPPayloadRegistry::SetRtxSsrc(uint32_t ssrc) {
    297   CriticalSectionScoped cs(crit_sect_.get());
    298   ssrc_rtx_ = ssrc;
    299   rtx_ = true;
    300 }
    301 
    302 bool RTPPayloadRegistry::GetRtxSsrc(uint32_t* ssrc) const {
    303   CriticalSectionScoped cs(crit_sect_.get());
    304   *ssrc = ssrc_rtx_;
    305   return rtx_;
    306 }
    307 
    308 void 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 
    321 bool RTPPayloadRegistry::IsRed(const RTPHeader& header) const {
    322   CriticalSectionScoped cs(crit_sect_.get());
    323   return red_payload_type_ == header.payloadType;
    324 }
    325 
    326 bool RTPPayloadRegistry::IsEncapsulated(const RTPHeader& header) const {
    327   return IsRed(header) || IsRtx(header);
    328 }
    329 
    330 bool 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 
    344 int 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 
    354 const 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 
    369 void RTPPayloadRegistry::SetIncomingPayloadType(const RTPHeader& header) {
    370   CriticalSectionScoped cs(crit_sect_.get());
    371   if (!IsRtxInternal(header))
    372     incoming_payload_type_ = header.payloadType;
    373 }
    374 
    375 bool 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 
    385 class 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 
    428 class 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 
    481 RTPPayloadStrategy* 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