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
15namespace webrtc {
16
17RTPPayloadRegistry::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
30RTPPayloadRegistry::~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
38int32_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
132int32_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.
146void 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
179int32_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
229bool RTPPayloadRegistry::RtxEnabled() const {
230  CriticalSectionScoped cs(crit_sect_.get());
231  return rtx_;
232}
233
234bool RTPPayloadRegistry::IsRtx(const RTPHeader& header) const {
235  CriticalSectionScoped cs(crit_sect_.get());
236  return IsRtxInternal(header);
237}
238
239bool RTPPayloadRegistry::IsRtxInternal(const RTPHeader& header) const {
240  return rtx_ && ssrc_rtx_ == header.ssrc;
241}
242
243bool 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
283void RTPPayloadRegistry::SetRtxSsrc(uint32_t ssrc) {
284  CriticalSectionScoped cs(crit_sect_.get());
285  ssrc_rtx_ = ssrc;
286  rtx_ = true;
287}
288
289void 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
296bool RTPPayloadRegistry::IsRed(const RTPHeader& header) const {
297  CriticalSectionScoped cs(crit_sect_.get());
298  return red_payload_type_ == header.payloadType;
299}
300
301bool RTPPayloadRegistry::IsEncapsulated(const RTPHeader& header) const {
302  return IsRed(header) || IsRtx(header);
303}
304
305bool 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
319int 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
329bool 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
346void RTPPayloadRegistry::SetIncomingPayloadType(const RTPHeader& header) {
347  CriticalSectionScoped cs(crit_sect_.get());
348  if (!IsRtxInternal(header))
349    incoming_payload_type_ = header.payloadType;
350}
351
352bool 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
362class RTPPayloadAudioStrategy : public RTPPayloadStrategy {
363 public:
364  virtual bool CodecsMustBeUnique() const OVERRIDE { return true; }
365
366  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
378  virtual void UpdatePayloadRate(RtpUtility::Payload* payload,
379                                 const uint32_t rate) const OVERRIDE {
380    payload->typeSpecific.Audio.rate = rate;
381  }
382
383  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
400  int GetPayloadTypeFrequency(const RtpUtility::Payload& payload) const {
401    return payload.typeSpecific.Audio.frequency;
402  }
403};
404
405class RTPPayloadVideoStrategy : public RTPPayloadStrategy {
406 public:
407  virtual bool CodecsMustBeUnique() const OVERRIDE { return false; }
408
409  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
416  virtual void UpdatePayloadRate(RtpUtility::Payload* payload,
417                                 const uint32_t rate) const OVERRIDE {
418    payload->typeSpecific.Video.maxRate = rate;
419  }
420
421  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
449  int GetPayloadTypeFrequency(const RtpUtility::Payload& payload) const {
450    return kVideoPayloadTypeFrequency;
451  }
452};
453
454RTPPayloadStrategy* 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