• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
RTPPayloadRegistry(RTPPayloadStrategy * rtp_payload_strategy)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 
~RTPPayloadRegistry()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 
RegisterReceivePayload(const char payload_name[RTP_PAYLOAD_NAME_SIZE],const int8_t payload_type,const uint32_t frequency,const size_t channels,const uint32_t rate,bool * created_new_payload)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 
DeRegisterReceivePayload(const int8_t payload_type)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.
DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType(const char payload_name[RTP_PAYLOAD_NAME_SIZE],const size_t payload_name_length,const uint32_t frequency,const size_t channels,const uint32_t rate)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 
ReceivePayloadType(const char payload_name[RTP_PAYLOAD_NAME_SIZE],const uint32_t frequency,const size_t channels,const uint32_t rate,int8_t * payload_type) const171 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 
RtxEnabled() const221 bool RTPPayloadRegistry::RtxEnabled() const {
222   CriticalSectionScoped cs(crit_sect_.get());
223   return rtx_;
224 }
225 
IsRtx(const RTPHeader & header) const226 bool RTPPayloadRegistry::IsRtx(const RTPHeader& header) const {
227   CriticalSectionScoped cs(crit_sect_.get());
228   return IsRtxInternal(header);
229 }
230 
IsRtxInternal(const RTPHeader & header) const231 bool RTPPayloadRegistry::IsRtxInternal(const RTPHeader& header) const {
232   return rtx_ && ssrc_rtx_ == header.ssrc;
233 }
234 
RestoreOriginalPacket(uint8_t ** restored_packet,const uint8_t * packet,size_t * packet_length,uint32_t original_ssrc,const RTPHeader & header) const235 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 
RestoreOriginalPacket(uint8_t * restored_packet,const uint8_t * packet,size_t * packet_length,uint32_t original_ssrc,const RTPHeader & header) const244 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 
SetRtxSsrc(uint32_t ssrc)296 void RTPPayloadRegistry::SetRtxSsrc(uint32_t ssrc) {
297   CriticalSectionScoped cs(crit_sect_.get());
298   ssrc_rtx_ = ssrc;
299   rtx_ = true;
300 }
301 
GetRtxSsrc(uint32_t * ssrc) const302 bool RTPPayloadRegistry::GetRtxSsrc(uint32_t* ssrc) const {
303   CriticalSectionScoped cs(crit_sect_.get());
304   *ssrc = ssrc_rtx_;
305   return rtx_;
306 }
307 
SetRtxPayloadType(int payload_type,int associated_payload_type)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 
IsRed(const RTPHeader & header) const321 bool RTPPayloadRegistry::IsRed(const RTPHeader& header) const {
322   CriticalSectionScoped cs(crit_sect_.get());
323   return red_payload_type_ == header.payloadType;
324 }
325 
IsEncapsulated(const RTPHeader & header) const326 bool RTPPayloadRegistry::IsEncapsulated(const RTPHeader& header) const {
327   return IsRed(header) || IsRtx(header);
328 }
329 
GetPayloadSpecifics(uint8_t payload_type,PayloadUnion * payload) const330 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 
GetPayloadTypeFrequency(uint8_t payload_type) const344 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 
PayloadTypeToPayload(uint8_t payload_type) const354 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 
SetIncomingPayloadType(const RTPHeader & header)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 
ReportMediaPayloadType(uint8_t media_payload_type)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:
CodecsMustBeUnique() const387   bool CodecsMustBeUnique() const override { return true; }
388 
PayloadIsCompatible(const RtpUtility::Payload & payload,const uint32_t frequency,const size_t channels,const uint32_t rate) const389   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 
UpdatePayloadRate(RtpUtility::Payload * payload,const uint32_t rate) const401   void UpdatePayloadRate(RtpUtility::Payload* payload,
402                          const uint32_t rate) const override {
403     payload->typeSpecific.Audio.rate = rate;
404   }
405 
CreatePayloadType(const char payloadName[RTP_PAYLOAD_NAME_SIZE],const int8_t payloadType,const uint32_t frequency,const size_t channels,const uint32_t rate) const406   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 
GetPayloadTypeFrequency(const RtpUtility::Payload & payload) const423   int GetPayloadTypeFrequency(const RtpUtility::Payload& payload) const {
424     return payload.typeSpecific.Audio.frequency;
425   }
426 };
427 
428 class RTPPayloadVideoStrategy : public RTPPayloadStrategy {
429  public:
CodecsMustBeUnique() const430   bool CodecsMustBeUnique() const override { return false; }
431 
PayloadIsCompatible(const RtpUtility::Payload & payload,const uint32_t frequency,const size_t channels,const uint32_t rate) const432   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 
UpdatePayloadRate(RtpUtility::Payload * payload,const uint32_t rate) const439   void UpdatePayloadRate(RtpUtility::Payload* payload,
440                          const uint32_t rate) const override {
441     payload->typeSpecific.Video.maxRate = rate;
442   }
443 
CreatePayloadType(const char payloadName[RTP_PAYLOAD_NAME_SIZE],const int8_t payloadType,const uint32_t frequency,const size_t channels,const uint32_t rate) const444   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 
GetPayloadTypeFrequency(const RtpUtility::Payload & payload) const476   int GetPayloadTypeFrequency(const RtpUtility::Payload& payload) const {
477     return kVideoPayloadTypeFrequency;
478   }
479 };
480 
CreateStrategy(const bool handling_audio)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