• 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/interface/rtp_payload_registry.h"
12 
13 #include "webrtc/system_wrappers/interface/logging.h"
14 
15 namespace webrtc {
16 
RTPPayloadRegistry(RTPPayloadStrategy * rtp_payload_strategy)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),
26       rtx_(false),
27       payload_type_rtx_(-1),
28       ssrc_rtx_(0) {}
29 
~RTPPayloadRegistry()30 RTPPayloadRegistry::~RTPPayloadRegistry() {
31   while (!payload_type_map_.empty()) {
32     RtpUtility::PayloadTypeMap::iterator it = payload_type_map_.begin();
33     delete it->second;
34     payload_type_map_.erase(it);
35   }
36 }
37 
RegisterReceivePayload(const char payload_name[RTP_PAYLOAD_NAME_SIZE],const int8_t payload_type,const uint32_t frequency,const uint8_t channels,const uint32_t rate,bool * created_new_payload)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,
43     const uint32_t rate,
44     bool* created_new_payload) {
45   assert(payload_type >= 0);
46   assert(payload_name);
47   *created_new_payload = false;
48 
49   // Sanity check.
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: "
62                     << payload_type;
63       return -1;
64     default:
65       break;
66   }
67 
68   size_t payload_name_length = strlen(payload_name);
69 
70   CriticalSectionScoped cs(crit_sect_.get());
71 
72   RtpUtility::PayloadTypeMap::iterator it =
73       payload_type_map_.find(payload_type);
74 
75   if (it != payload_type_map_.end()) {
76     // We already use this payload type.
77     RtpUtility::Payload* payload = it->second;
78 
79     assert(payload);
80 
81     size_t name_length = strlen(payload->name);
82 
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         RtpUtility::StringCompare(
87             payload->name, payload_name, payload_name_length)) {
88       if (rtp_payload_strategy_->PayloadIsCompatible(*payload, frequency,
89                                                      channels, rate)) {
90         rtp_payload_strategy_->UpdatePayloadRate(payload, rate);
91         return 0;
92       }
93     }
94     LOG(LS_ERROR) << "Payload type already registered: " << payload_type;
95     return -1;
96   }
97 
98   if (rtp_payload_strategy_->CodecsMustBeUnique()) {
99     DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType(
100         payload_name, payload_name_length, frequency, channels, rate);
101   }
102 
103   RtpUtility::Payload* payload = NULL;
104 
105   // Save the RED payload type. Used in both audio and video.
106   if (RtpUtility::StringCompare(payload_name, "red", 3)) {
107     red_payload_type_ = payload_type;
108     payload = new RtpUtility::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 (RtpUtility::StringCompare(payload_name, "ulpfec", 3)) {
113     ulpfec_payload_type_ = payload_type;
114     payload = new RtpUtility::Payload;
115     memset(payload, 0, sizeof(*payload));
116     payload->audio = false;
117     strncpy(payload->name, payload_name, RTP_PAYLOAD_NAME_SIZE - 1);
118   } else {
119     *created_new_payload = true;
120     payload = rtp_payload_strategy_->CreatePayloadType(
121         payload_name, payload_type, frequency, channels, rate);
122   }
123   payload_type_map_[payload_type] = payload;
124 
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;
129   return 0;
130 }
131 
DeRegisterReceivePayload(const int8_t payload_type)132 int32_t RTPPayloadRegistry::DeRegisterReceivePayload(
133     const int8_t payload_type) {
134   CriticalSectionScoped cs(crit_sect_.get());
135   RtpUtility::PayloadTypeMap::iterator it =
136       payload_type_map_.find(payload_type);
137   assert(it != payload_type_map_.end());
138   delete it->second;
139   payload_type_map_.erase(it);
140   return 0;
141 }
142 
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.
DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType(const char payload_name[RTP_PAYLOAD_NAME_SIZE],const size_t payload_name_length,const uint32_t frequency,const uint8_t channels,const uint32_t rate)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   RtpUtility::PayloadTypeMap::iterator iterator = payload_type_map_.begin();
153   for (; iterator != payload_type_map_.end(); ++iterator) {
154     RtpUtility::Payload* payload = iterator->second;
155     size_t name_length = strlen(payload->name);
156 
157     if (payload_name_length == name_length &&
158         RtpUtility::StringCompare(
159             payload->name, payload_name, payload_name_length)) {
160       // We found the payload name in the list.
161       // If audio, check frequency and rate.
162       if (payload->audio) {
163         if (rtp_payload_strategy_->PayloadIsCompatible(*payload, frequency,
164                                                        channels, rate)) {
165           // Remove old setting.
166           delete payload;
167           payload_type_map_.erase(iterator);
168           break;
169         }
170       } else if (RtpUtility::StringCompare(payload_name, "red", 3)) {
171         delete payload;
172         payload_type_map_.erase(iterator);
173         break;
174       }
175     }
176   }
177 }
178 
ReceivePayloadType(const char payload_name[RTP_PAYLOAD_NAME_SIZE],const uint32_t frequency,const uint8_t channels,const uint32_t rate,int8_t * payload_type) const179 int32_t RTPPayloadRegistry::ReceivePayloadType(
180     const char payload_name[RTP_PAYLOAD_NAME_SIZE],
181     const uint32_t frequency,
182     const uint8_t channels,
183     const uint32_t rate,
184     int8_t* payload_type) const {
185   assert(payload_type);
186   size_t payload_name_length = strlen(payload_name);
187 
188   CriticalSectionScoped cs(crit_sect_.get());
189 
190   RtpUtility::PayloadTypeMap::const_iterator it = payload_type_map_.begin();
191 
192   for (; it != payload_type_map_.end(); ++it) {
193     RtpUtility::Payload* payload = it->second;
194     assert(payload);
195 
196     size_t name_length = strlen(payload->name);
197     if (payload_name_length == name_length &&
198         RtpUtility::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 
RtxEnabled() const229 bool RTPPayloadRegistry::RtxEnabled() const {
230   CriticalSectionScoped cs(crit_sect_.get());
231   return rtx_;
232 }
233 
IsRtx(const RTPHeader & header) const234 bool RTPPayloadRegistry::IsRtx(const RTPHeader& header) const {
235   CriticalSectionScoped cs(crit_sect_.get());
236   return IsRtxInternal(header);
237 }
238 
IsRtxInternal(const RTPHeader & header) const239 bool RTPPayloadRegistry::IsRtxInternal(const RTPHeader& header) const {
240   return rtx_ && ssrc_rtx_ == header.ssrc;
241 }
242 
RestoreOriginalPacket(uint8_t ** restored_packet,const uint8_t * packet,int * packet_length,uint32_t original_ssrc,const RTPHeader & header) const243 bool RTPPayloadRegistry::RestoreOriginalPacket(uint8_t** restored_packet,
244                                                const uint8_t* packet,
245                                                int* packet_length,
246                                                uint32_t original_ssrc,
247                                                const RTPHeader& header) const {
248   if (kRtxHeaderSize + header.headerLength > *packet_length) {
249     return false;
250   }
251   const uint8_t* rtx_header = packet + header.headerLength;
252   uint16_t original_sequence_number = (rtx_header[0] << 8) + rtx_header[1];
253 
254   // Copy the packet into the restored packet, except for the RTX header.
255   memcpy(*restored_packet, packet, header.headerLength);
256   memcpy(*restored_packet + header.headerLength,
257          packet + header.headerLength + kRtxHeaderSize,
258          *packet_length - header.headerLength - kRtxHeaderSize);
259   *packet_length -= kRtxHeaderSize;
260 
261   // Replace the SSRC and the sequence number with the originals.
262   RtpUtility::AssignUWord16ToBuffer(*restored_packet + 2,
263                                     original_sequence_number);
264   RtpUtility::AssignUWord32ToBuffer(*restored_packet + 8, original_ssrc);
265 
266   CriticalSectionScoped cs(crit_sect_.get());
267 
268   if (payload_type_rtx_ != -1) {
269     if (header.payloadType == payload_type_rtx_ &&
270         incoming_payload_type_ != -1) {
271       (*restored_packet)[1] = static_cast<uint8_t>(incoming_payload_type_);
272       if (header.markerBit) {
273         (*restored_packet)[1] |= kRtpMarkerBitMask;  // Marker bit is set.
274       }
275     } else {
276       LOG(LS_WARNING) << "Incorrect RTX configuration, dropping packet.";
277       return false;
278     }
279   }
280   return true;
281 }
282 
SetRtxSsrc(uint32_t ssrc)283 void RTPPayloadRegistry::SetRtxSsrc(uint32_t ssrc) {
284   CriticalSectionScoped cs(crit_sect_.get());
285   ssrc_rtx_ = ssrc;
286   rtx_ = true;
287 }
288 
SetRtxPayloadType(int payload_type)289 void RTPPayloadRegistry::SetRtxPayloadType(int payload_type) {
290   CriticalSectionScoped cs(crit_sect_.get());
291   assert(payload_type >= 0);
292   payload_type_rtx_ = payload_type;
293   rtx_ = true;
294 }
295 
IsRed(const RTPHeader & header) const296 bool RTPPayloadRegistry::IsRed(const RTPHeader& header) const {
297   CriticalSectionScoped cs(crit_sect_.get());
298   return red_payload_type_ == header.payloadType;
299 }
300 
IsEncapsulated(const RTPHeader & header) const301 bool RTPPayloadRegistry::IsEncapsulated(const RTPHeader& header) const {
302   return IsRed(header) || IsRtx(header);
303 }
304 
GetPayloadSpecifics(uint8_t payload_type,PayloadUnion * payload) const305 bool RTPPayloadRegistry::GetPayloadSpecifics(uint8_t payload_type,
306                                              PayloadUnion* payload) const {
307   CriticalSectionScoped cs(crit_sect_.get());
308   RtpUtility::PayloadTypeMap::const_iterator it =
309       payload_type_map_.find(payload_type);
310 
311   // Check that this is a registered payload type.
312   if (it == payload_type_map_.end()) {
313     return false;
314   }
315   *payload = it->second->typeSpecific;
316   return true;
317 }
318 
GetPayloadTypeFrequency(uint8_t payload_type) const319 int RTPPayloadRegistry::GetPayloadTypeFrequency(
320     uint8_t payload_type) const {
321   RtpUtility::Payload* payload;
322   if (!PayloadTypeToPayload(payload_type, payload)) {
323     return -1;
324   }
325   CriticalSectionScoped cs(crit_sect_.get());
326   return rtp_payload_strategy_->GetPayloadTypeFrequency(*payload);
327 }
328 
PayloadTypeToPayload(const uint8_t payload_type,RtpUtility::Payload * & payload) const329 bool RTPPayloadRegistry::PayloadTypeToPayload(
330     const uint8_t payload_type,
331     RtpUtility::Payload*& payload) const {
332   CriticalSectionScoped cs(crit_sect_.get());
333 
334   RtpUtility::PayloadTypeMap::const_iterator it =
335       payload_type_map_.find(payload_type);
336 
337   // Check that this is a registered payload type.
338   if (it == payload_type_map_.end()) {
339     return false;
340   }
341 
342   payload = it->second;
343   return true;
344 }
345 
SetIncomingPayloadType(const RTPHeader & header)346 void RTPPayloadRegistry::SetIncomingPayloadType(const RTPHeader& header) {
347   CriticalSectionScoped cs(crit_sect_.get());
348   if (!IsRtxInternal(header))
349     incoming_payload_type_ = header.payloadType;
350 }
351 
ReportMediaPayloadType(uint8_t media_payload_type)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.
356     return true;
357   }
358   last_received_media_payload_type_ = media_payload_type;
359   return false;
360 }
361 
362 class RTPPayloadAudioStrategy : public RTPPayloadStrategy {
363  public:
CodecsMustBeUnique() const364   virtual bool CodecsMustBeUnique() const OVERRIDE { return true; }
365 
PayloadIsCompatible(const RtpUtility::Payload & payload,const uint32_t frequency,const uint8_t channels,const uint32_t rate) const366   virtual bool PayloadIsCompatible(const RtpUtility::Payload& payload,
367                                    const uint32_t frequency,
368                                    const uint8_t channels,
369                                    const uint32_t rate) const OVERRIDE {
370     return
371         payload.audio &&
372         payload.typeSpecific.Audio.frequency == frequency &&
373         payload.typeSpecific.Audio.channels == channels &&
374         (payload.typeSpecific.Audio.rate == rate ||
375             payload.typeSpecific.Audio.rate == 0 || rate == 0);
376   }
377 
UpdatePayloadRate(RtpUtility::Payload * payload,const uint32_t rate) const378   virtual void UpdatePayloadRate(RtpUtility::Payload* payload,
379                                  const uint32_t rate) const OVERRIDE {
380     payload->typeSpecific.Audio.rate = rate;
381   }
382 
CreatePayloadType(const char payloadName[RTP_PAYLOAD_NAME_SIZE],const int8_t payloadType,const uint32_t frequency,const uint8_t channels,const uint32_t rate) const383   virtual RtpUtility::Payload* CreatePayloadType(
384       const char payloadName[RTP_PAYLOAD_NAME_SIZE],
385       const int8_t payloadType,
386       const uint32_t frequency,
387       const uint8_t channels,
388       const uint32_t rate) const OVERRIDE {
389     RtpUtility::Payload* payload = new RtpUtility::Payload;
390     payload->name[RTP_PAYLOAD_NAME_SIZE - 1] = 0;
391     strncpy(payload->name, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
392     assert(frequency >= 1000);
393     payload->typeSpecific.Audio.frequency = frequency;
394     payload->typeSpecific.Audio.channels = channels;
395     payload->typeSpecific.Audio.rate = rate;
396     payload->audio = true;
397     return payload;
398   }
399 
GetPayloadTypeFrequency(const RtpUtility::Payload & payload) const400   int GetPayloadTypeFrequency(const RtpUtility::Payload& payload) const {
401     return payload.typeSpecific.Audio.frequency;
402   }
403 };
404 
405 class RTPPayloadVideoStrategy : public RTPPayloadStrategy {
406  public:
CodecsMustBeUnique() const407   virtual bool CodecsMustBeUnique() const OVERRIDE { return false; }
408 
PayloadIsCompatible(const RtpUtility::Payload & payload,const uint32_t frequency,const uint8_t channels,const uint32_t rate) const409   virtual bool PayloadIsCompatible(const RtpUtility::Payload& payload,
410                                    const uint32_t frequency,
411                                    const uint8_t channels,
412                                    const uint32_t rate) const OVERRIDE {
413     return !payload.audio;
414   }
415 
UpdatePayloadRate(RtpUtility::Payload * payload,const uint32_t rate) const416   virtual void UpdatePayloadRate(RtpUtility::Payload* payload,
417                                  const uint32_t rate) const OVERRIDE {
418     payload->typeSpecific.Video.maxRate = rate;
419   }
420 
CreatePayloadType(const char payloadName[RTP_PAYLOAD_NAME_SIZE],const int8_t payloadType,const uint32_t frequency,const uint8_t channels,const uint32_t rate) const421   virtual RtpUtility::Payload* CreatePayloadType(
422       const char payloadName[RTP_PAYLOAD_NAME_SIZE],
423       const int8_t payloadType,
424       const uint32_t frequency,
425       const uint8_t channels,
426       const uint32_t rate) const OVERRIDE {
427     RtpVideoCodecTypes videoType = kRtpVideoGeneric;
428     if (RtpUtility::StringCompare(payloadName, "VP8", 3)) {
429       videoType = kRtpVideoVp8;
430     } else if (RtpUtility::StringCompare(payloadName, "H264", 4)) {
431       videoType = kRtpVideoH264;
432     } else if (RtpUtility::StringCompare(payloadName, "I420", 4)) {
433       videoType = kRtpVideoGeneric;
434     } else if (RtpUtility::StringCompare(payloadName, "ULPFEC", 6)) {
435       videoType = kRtpVideoNone;
436     } else {
437       videoType = kRtpVideoGeneric;
438     }
439     RtpUtility::Payload* payload = new RtpUtility::Payload;
440 
441     payload->name[RTP_PAYLOAD_NAME_SIZE - 1] = 0;
442     strncpy(payload->name, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
443     payload->typeSpecific.Video.videoCodecType = videoType;
444     payload->typeSpecific.Video.maxRate = rate;
445     payload->audio = false;
446     return payload;
447   }
448 
GetPayloadTypeFrequency(const RtpUtility::Payload & payload) const449   int GetPayloadTypeFrequency(const RtpUtility::Payload& payload) const {
450     return kVideoPayloadTypeFrequency;
451   }
452 };
453 
CreateStrategy(const bool handling_audio)454 RTPPayloadStrategy* RTPPayloadStrategy::CreateStrategy(
455     const bool handling_audio) {
456   if (handling_audio) {
457     return new RTPPayloadAudioStrategy();
458   } else {
459     return new RTPPayloadVideoStrategy();
460   }
461 }
462 
463 }  // namespace webrtc
464