Note: We no longer publish the latest version of our code here. We primarily use a kumc-bmi github organization. The heron ETL repository, in particular, is not public. Peers in the informatics community should see MultiSiteDev for details on requesting access.

source: webrtc/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.cc @ 0:4bda6873e34c

pub_scrub_3792 tip
Last change on this file since 0:4bda6873e34c was 0:4bda6873e34c, checked in by Michael Prittie <mprittie@…>, 6 years ago

Scrubbed password for publication.

File size: 16.0 KB
Line 
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/trace.h"
14
15namespace webrtc {
16
17RTPPayloadRegistry::RTPPayloadRegistry(
18    const int32_t id,
19    RTPPayloadStrategy* rtp_payload_strategy)
20    : crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
21      id_(id),
22      rtp_payload_strategy_(rtp_payload_strategy),
23      red_payload_type_(-1),
24      ulpfec_payload_type_(-1),
25      incoming_payload_type_(-1),
26      last_received_payload_type_(-1),
27      last_received_media_payload_type_(-1),
28      rtx_(false),
29      payload_type_rtx_(-1),
30      ssrc_rtx_(0) {}
31
32RTPPayloadRegistry::~RTPPayloadRegistry() {
33  while (!payload_type_map_.empty()) {
34    ModuleRTPUtility::PayloadTypeMap::iterator it = payload_type_map_.begin();
35    delete it->second;
36    payload_type_map_.erase(it);
37  }
38}
39
40int32_t RTPPayloadRegistry::RegisterReceivePayload(
41    const char payload_name[RTP_PAYLOAD_NAME_SIZE],
42    const int8_t payload_type,
43    const uint32_t frequency,
44    const uint8_t channels,
45    const uint32_t rate,
46    bool* created_new_payload) {
47  assert(payload_type >= 0);
48  assert(payload_name);
49  *created_new_payload = false;
50
51  // Sanity check.
52  switch (payload_type) {
53    // Reserved payload types to avoid RTCP conflicts when marker bit is set.
54    case 64:        //  192 Full INTRA-frame request.
55    case 72:        //  200 Sender report.
56    case 73:        //  201 Receiver report.
57    case 74:        //  202 Source description.
58    case 75:        //  203 Goodbye.
59    case 76:        //  204 Application-defined.
60    case 77:        //  205 Transport layer FB message.
61    case 78:        //  206 Payload-specific FB message.
62    case 79:        //  207 Extended report.
63      WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, id_,
64                   "%s invalid payloadtype:%d",
65                   __FUNCTION__, payload_type);
66      return -1;
67    default:
68      break;
69  }
70
71  size_t payload_name_length = strlen(payload_name);
72
73  CriticalSectionScoped cs(crit_sect_.get());
74
75  ModuleRTPUtility::PayloadTypeMap::iterator it =
76    payload_type_map_.find(payload_type);
77
78  if (it != payload_type_map_.end()) {
79    // We already use this payload type.
80    ModuleRTPUtility::Payload* payload = it->second;
81
82    assert(payload);
83
84    size_t name_length = strlen(payload->name);
85
86    // Check if it's the same as we already have.
87    // If same, ignore sending an error.
88    if (payload_name_length == name_length &&
89        ModuleRTPUtility::StringCompare(
90            payload->name, payload_name, payload_name_length)) {
91      if (rtp_payload_strategy_->PayloadIsCompatible(*payload, frequency,
92                                                     channels, rate)) {
93        rtp_payload_strategy_->UpdatePayloadRate(payload, rate);
94        return 0;
95      }
96    }
97    WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, id_,
98                 "%s invalid argument payload_type:%d already registered",
99                 __FUNCTION__, payload_type);
100    return -1;
101  }
102
103  if (rtp_payload_strategy_->CodecsMustBeUnique()) {
104    DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType(
105        payload_name, payload_name_length, frequency, channels, rate);
106  }
107
108  ModuleRTPUtility::Payload* payload = NULL;
109
110  // Save the RED payload type. Used in both audio and video.
111  if (ModuleRTPUtility::StringCompare(payload_name, "red", 3)) {
112    red_payload_type_ = payload_type;
113    payload = new ModuleRTPUtility::Payload;
114    memset(payload, 0, sizeof(*payload));
115    payload->audio = false;
116    strncpy(payload->name, payload_name, RTP_PAYLOAD_NAME_SIZE - 1);
117  } else if (ModuleRTPUtility::StringCompare(payload_name, "ulpfec", 3)) {
118    ulpfec_payload_type_ = payload_type;
119    payload = new ModuleRTPUtility::Payload;
120    memset(payload, 0, sizeof(*payload));
121    payload->audio = false;
122    strncpy(payload->name, payload_name, RTP_PAYLOAD_NAME_SIZE - 1);
123  } else {
124    *created_new_payload = true;
125    payload = rtp_payload_strategy_->CreatePayloadType(
126        payload_name, payload_type, frequency, channels, rate);
127  }
128  payload_type_map_[payload_type] = payload;
129
130  // Successful set of payload type, clear the value of last received payload
131  // type since it might mean something else.
132  last_received_payload_type_ = -1;
133  last_received_media_payload_type_ = -1;
134  return 0;
135}
136
137int32_t RTPPayloadRegistry::DeRegisterReceivePayload(
138    const int8_t payload_type) {
139  CriticalSectionScoped cs(crit_sect_.get());
140  ModuleRTPUtility::PayloadTypeMap::iterator it =
141    payload_type_map_.find(payload_type);
142
143  if (it == payload_type_map_.end()) {
144    WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, id_,
145                 "%s failed to find payload_type:%d",
146                 __FUNCTION__, payload_type);
147    return -1;
148  }
149  delete it->second;
150  payload_type_map_.erase(it);
151  return 0;
152}
153
154// There can't be several codecs with the same rate, frequency and channels
155// for audio codecs, but there can for video.
156// Always called from within a critical section.
157void RTPPayloadRegistry::DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType(
158    const char payload_name[RTP_PAYLOAD_NAME_SIZE],
159    const size_t payload_name_length,
160    const uint32_t frequency,
161    const uint8_t channels,
162    const uint32_t rate) {
163  ModuleRTPUtility::PayloadTypeMap::iterator iterator =
164      payload_type_map_.begin();
165  for (; iterator != payload_type_map_.end(); ++iterator) {
166    ModuleRTPUtility::Payload* payload = iterator->second;
167    size_t name_length = strlen(payload->name);
168
169    if (payload_name_length == name_length
170        && ModuleRTPUtility::StringCompare(payload->name, payload_name,
171                                           payload_name_length)) {
172      // We found the payload name in the list.
173      // If audio, check frequency and rate.
174      if (payload->audio) {
175        if (rtp_payload_strategy_->PayloadIsCompatible(*payload, frequency,
176                                                       channels, rate)) {
177          // Remove old setting.
178          delete payload;
179          payload_type_map_.erase(iterator);
180          break;
181        }
182      } else if (ModuleRTPUtility::StringCompare(payload_name, "red", 3)) {
183        delete payload;
184        payload_type_map_.erase(iterator);
185        break;
186      }
187    }
188  }
189}
190
191int32_t RTPPayloadRegistry::ReceivePayloadType(
192    const char payload_name[RTP_PAYLOAD_NAME_SIZE],
193    const uint32_t frequency,
194    const uint8_t channels,
195    const uint32_t rate,
196    int8_t* payload_type) const {
197  if (payload_type == NULL) {
198    WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, id_,
199                 "%s invalid argument", __FUNCTION__);
200    return -1;
201  }
202  size_t payload_name_length = strlen(payload_name);
203
204  CriticalSectionScoped cs(crit_sect_.get());
205
206  ModuleRTPUtility::PayloadTypeMap::const_iterator it =
207      payload_type_map_.begin();
208
209  for (; it != payload_type_map_.end(); ++it) {
210    ModuleRTPUtility::Payload* payload = it->second;
211    assert(payload);
212
213    size_t name_length = strlen(payload->name);
214    if (payload_name_length == name_length &&
215        ModuleRTPUtility::StringCompare(
216            payload->name, payload_name, payload_name_length)) {
217      // Name matches.
218      if (payload->audio) {
219        if (rate == 0) {
220          // [default] audio, check freq and channels.
221          if (payload->typeSpecific.Audio.frequency == frequency &&
222              payload->typeSpecific.Audio.channels == channels) {
223            *payload_type = it->first;
224            return 0;
225          }
226        } else {
227          // Non-default audio, check freq, channels and rate.
228          if (payload->typeSpecific.Audio.frequency == frequency &&
229              payload->typeSpecific.Audio.channels == channels &&
230              payload->typeSpecific.Audio.rate == rate) {
231            // extra rate condition added
232            *payload_type = it->first;
233            return 0;
234          }
235        }
236      } else {
237        // Video.
238        *payload_type = it->first;
239        return 0;
240      }
241    }
242  }
243  return -1;
244}
245
246void RTPPayloadRegistry::SetRtxStatus(bool enable, uint32_t ssrc) {
247  CriticalSectionScoped cs(crit_sect_.get());
248  rtx_ = enable;
249  ssrc_rtx_ = ssrc;
250}
251
252bool RTPPayloadRegistry::RtxEnabled() const {
253  CriticalSectionScoped cs(crit_sect_.get());
254  return rtx_;
255}
256
257bool RTPPayloadRegistry::IsRtx(const RTPHeader& header) const {
258  CriticalSectionScoped cs(crit_sect_.get());
259  return IsRtxInternal(header);
260}
261
262bool RTPPayloadRegistry::IsRtxInternal(const RTPHeader& header) const {
263  return rtx_ && ssrc_rtx_ == header.ssrc;
264}
265
266bool RTPPayloadRegistry::RestoreOriginalPacket(uint8_t** restored_packet,
267                                               const uint8_t* packet,
268                                               int* packet_length,
269                                               uint32_t original_ssrc,
270                                               const RTPHeader& header) const {
271  if (kRtxHeaderSize + header.headerLength > *packet_length) {
272    return false;
273  }
274  const uint8_t* rtx_header = packet + header.headerLength;
275  uint16_t original_sequence_number = (rtx_header[0] << 8) + rtx_header[1];
276
277  // Copy the packet into the restored packet, except for the RTX header.
278  memcpy(*restored_packet, packet, header.headerLength);
279  memcpy(*restored_packet + header.headerLength,
280         packet + header.headerLength + kRtxHeaderSize,
281         *packet_length - header.headerLength - kRtxHeaderSize);
282  *packet_length -= kRtxHeaderSize;
283
284  // Replace the SSRC and the sequence number with the originals.
285  ModuleRTPUtility::AssignUWord16ToBuffer(*restored_packet + 2,
286                                          original_sequence_number);
287  ModuleRTPUtility::AssignUWord32ToBuffer(*restored_packet + 8, original_ssrc);
288
289  CriticalSectionScoped cs(crit_sect_.get());
290
291  if (payload_type_rtx_ != -1) {
292    if (header.payloadType == payload_type_rtx_ &&
293        incoming_payload_type_ != -1) {
294      (*restored_packet)[1] = static_cast<uint8_t>(incoming_payload_type_);
295      if (header.markerBit) {
296        (*restored_packet)[1] |= kRtpMarkerBitMask;  // Marker bit is set.
297      }
298    } else {
299      WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, id_,
300                   "Incorrect RTX configuration, dropping packet.");
301      return false;
302    }
303  }
304  return true;
305}
306
307void RTPPayloadRegistry::SetRtxPayloadType(int payload_type) {
308  CriticalSectionScoped cs(crit_sect_.get());
309  payload_type_rtx_ = payload_type;
310}
311
312bool RTPPayloadRegistry::IsRed(const RTPHeader& header) const {
313  CriticalSectionScoped cs(crit_sect_.get());
314  return red_payload_type_ == header.payloadType;
315}
316
317bool RTPPayloadRegistry::IsEncapsulated(const RTPHeader& header) const {
318  return IsRed(header) || IsRtx(header);
319}
320
321bool RTPPayloadRegistry::GetPayloadSpecifics(uint8_t payload_type,
322                                             PayloadUnion* payload) const {
323  CriticalSectionScoped cs(crit_sect_.get());
324  ModuleRTPUtility::PayloadTypeMap::const_iterator it =
325    payload_type_map_.find(payload_type);
326
327  // Check that this is a registered payload type.
328  if (it == payload_type_map_.end()) {
329    return false;
330  }
331  *payload = it->second->typeSpecific;
332  return true;
333}
334
335int RTPPayloadRegistry::GetPayloadTypeFrequency(
336    uint8_t payload_type) const {
337  ModuleRTPUtility::Payload* payload;
338  if (!PayloadTypeToPayload(payload_type, payload)) {
339    return -1;
340  }
341  CriticalSectionScoped cs(crit_sect_.get());
342  return rtp_payload_strategy_->GetPayloadTypeFrequency(*payload);
343}
344
345bool RTPPayloadRegistry::PayloadTypeToPayload(
346  const uint8_t payload_type,
347  ModuleRTPUtility::Payload*& payload) const {
348  CriticalSectionScoped cs(crit_sect_.get());
349
350  ModuleRTPUtility::PayloadTypeMap::const_iterator it =
351    payload_type_map_.find(payload_type);
352
353  // Check that this is a registered payload type.
354  if (it == payload_type_map_.end()) {
355    return false;
356  }
357
358  payload = it->second;
359  return true;
360}
361
362void RTPPayloadRegistry::SetIncomingPayloadType(const RTPHeader& header) {
363  CriticalSectionScoped cs(crit_sect_.get());
364  if (!IsRtxInternal(header))
365    incoming_payload_type_ = header.payloadType;
366}
367
368bool RTPPayloadRegistry::ReportMediaPayloadType(uint8_t media_payload_type) {
369  CriticalSectionScoped cs(crit_sect_.get());
370  if (last_received_media_payload_type_ == media_payload_type) {
371    // Media type unchanged.
372    return true;
373  }
374  last_received_media_payload_type_ = media_payload_type;
375  return false;
376}
377
378class RTPPayloadAudioStrategy : public RTPPayloadStrategy {
379 public:
380  virtual bool CodecsMustBeUnique() const OVERRIDE { return true; }
381
382  virtual bool PayloadIsCompatible(
383       const ModuleRTPUtility::Payload& payload,
384       const uint32_t frequency,
385       const uint8_t channels,
386       const uint32_t rate) const OVERRIDE {
387    return
388        payload.audio &&
389        payload.typeSpecific.Audio.frequency == frequency &&
390        payload.typeSpecific.Audio.channels == channels &&
391        (payload.typeSpecific.Audio.rate == rate ||
392            payload.typeSpecific.Audio.rate == 0 || rate == 0);
393  }
394
395  virtual void UpdatePayloadRate(
396      ModuleRTPUtility::Payload* payload,
397      const uint32_t rate) const OVERRIDE {
398    payload->typeSpecific.Audio.rate = rate;
399  }
400
401  virtual ModuleRTPUtility::Payload* CreatePayloadType(
402      const char payloadName[RTP_PAYLOAD_NAME_SIZE],
403      const int8_t payloadType,
404      const uint32_t frequency,
405      const uint8_t channels,
406      const uint32_t rate) const OVERRIDE {
407    ModuleRTPUtility::Payload* payload = new ModuleRTPUtility::Payload;
408    payload->name[RTP_PAYLOAD_NAME_SIZE - 1] = 0;
409    strncpy(payload->name, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
410    assert(frequency >= 1000);
411    payload->typeSpecific.Audio.frequency = frequency;
412    payload->typeSpecific.Audio.channels = channels;
413    payload->typeSpecific.Audio.rate = rate;
414    payload->audio = true;
415    return payload;
416  }
417
418  int GetPayloadTypeFrequency(
419      const ModuleRTPUtility::Payload& payload) const {
420    return payload.typeSpecific.Audio.frequency;
421  }
422};
423
424class RTPPayloadVideoStrategy : public RTPPayloadStrategy {
425 public:
426  virtual bool CodecsMustBeUnique() const OVERRIDE { return false; }
427
428  virtual bool PayloadIsCompatible(
429      const ModuleRTPUtility::Payload& payload,
430      const uint32_t frequency,
431      const uint8_t channels,
432      const uint32_t rate) const OVERRIDE {
433    return !payload.audio;
434  }
435
436  virtual void UpdatePayloadRate(
437      ModuleRTPUtility::Payload* payload,
438      const uint32_t rate) const OVERRIDE {
439    payload->typeSpecific.Video.maxRate = rate;
440  }
441
442  virtual ModuleRTPUtility::Payload* CreatePayloadType(
443      const char payloadName[RTP_PAYLOAD_NAME_SIZE],
444      const int8_t payloadType,
445      const uint32_t frequency,
446      const uint8_t channels,
447      const uint32_t rate) const OVERRIDE {
448    RtpVideoCodecTypes videoType = kRtpVideoGeneric;
449    if (ModuleRTPUtility::StringCompare(payloadName, "VP8", 3)) {
450      videoType = kRtpVideoVp8;
451    } else if (ModuleRTPUtility::StringCompare(payloadName, "I420", 4)) {
452      videoType = kRtpVideoGeneric;
453    } else if (ModuleRTPUtility::StringCompare(payloadName, "ULPFEC", 6)) {
454      videoType = kRtpVideoNone;
455    } else {
456      videoType = kRtpVideoGeneric;
457    }
458    ModuleRTPUtility::Payload* payload = new ModuleRTPUtility::Payload;
459
460    payload->name[RTP_PAYLOAD_NAME_SIZE - 1] = 0;
461    strncpy(payload->name, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
462    payload->typeSpecific.Video.videoCodecType = videoType;
463    payload->typeSpecific.Video.maxRate = rate;
464    payload->audio = false;
465    return payload;
466  }
467
468  int GetPayloadTypeFrequency(
469      const ModuleRTPUtility::Payload& payload) const {
470    return kVideoPayloadTypeFrequency;
471  }
472};
473
474RTPPayloadStrategy* RTPPayloadStrategy::CreateStrategy(
475    const bool handling_audio) {
476  if (handling_audio) {
477    return new RTPPayloadAudioStrategy();
478  } else {
479    return new RTPPayloadVideoStrategy();
480  }
481}
482
483}  // namespace webrtc
Note: See TracBrowser for help on using the repository browser.