rtp_payload_registry.cc revision 9de89a6f6bd9e7635c41966a9ab4b8d818521e57
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    : id_(id),
21      rtp_payload_strategy_(rtp_payload_strategy),
22      red_payload_type_(-1),
23      last_received_payload_type_(-1),
24      last_received_media_payload_type_(-1) {}
25
26RTPPayloadRegistry::~RTPPayloadRegistry() {
27  while (!payload_type_map_.empty()) {
28    ModuleRTPUtility::PayloadTypeMap::iterator it = payload_type_map_.begin();
29    delete it->second;
30    payload_type_map_.erase(it);
31  }
32}
33
34int32_t RTPPayloadRegistry::RegisterReceivePayload(
35    const char payload_name[RTP_PAYLOAD_NAME_SIZE],
36    const int8_t payload_type,
37    const uint32_t frequency,
38    const uint8_t channels,
39    const uint32_t rate,
40    bool* created_new_payload) {
41  assert(payload_type >= 0);
42  assert(payload_name);
43  *created_new_payload = false;
44
45  // Sanity check.
46  switch (payload_type) {
47    // Reserved payload types to avoid RTCP conflicts when marker bit is set.
48    case 64:        //  192 Full INTRA-frame request.
49    case 72:        //  200 Sender report.
50    case 73:        //  201 Receiver report.
51    case 74:        //  202 Source description.
52    case 75:        //  203 Goodbye.
53    case 76:        //  204 Application-defined.
54    case 77:        //  205 Transport layer FB message.
55    case 78:        //  206 Payload-specific FB message.
56    case 79:        //  207 Extended report.
57      WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, id_,
58                   "%s invalid payloadtype:%d",
59                   __FUNCTION__, payload_type);
60      return -1;
61    default:
62      break;
63  }
64
65  size_t payload_name_length = strlen(payload_name);
66
67  ModuleRTPUtility::PayloadTypeMap::iterator it =
68    payload_type_map_.find(payload_type);
69
70  if (it != payload_type_map_.end()) {
71    // We already use this payload type.
72    ModuleRTPUtility::Payload* payload = it->second;
73
74    assert(payload);
75
76    size_t name_length = strlen(payload->name);
77
78    // Check if it's the same as we already have.
79    // If same, ignore sending an error.
80    if (payload_name_length == name_length &&
81        ModuleRTPUtility::StringCompare(
82            payload->name, payload_name, payload_name_length)) {
83      if (rtp_payload_strategy_->PayloadIsCompatible(*payload, frequency,
84                                                     channels, rate)) {
85        rtp_payload_strategy_->UpdatePayloadRate(payload, rate);
86        return 0;
87      }
88    }
89    WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, id_,
90                 "%s invalid argument payload_type:%d already registered",
91                 __FUNCTION__, payload_type);
92    return -1;
93  }
94
95  if (rtp_payload_strategy_->CodecsMustBeUnique()) {
96    DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType(
97        payload_name, payload_name_length, frequency, channels, rate);
98  }
99
100  ModuleRTPUtility::Payload* payload = NULL;
101
102  // Save the RED payload type. Used in both audio and video.
103  if (ModuleRTPUtility::StringCompare(payload_name, "red", 3)) {
104    red_payload_type_ = payload_type;
105    payload = new ModuleRTPUtility::Payload;
106    memset(payload, 0, sizeof(*payload));
107    payload->audio = false;
108    payload->name[RTP_PAYLOAD_NAME_SIZE - 1] = 0;
109    strncpy(payload->name, payload_name, RTP_PAYLOAD_NAME_SIZE - 1);
110  } else {
111    *created_new_payload = true;
112    payload = rtp_payload_strategy_->CreatePayloadType(
113        payload_name, payload_type, frequency, channels, rate);
114  }
115  payload_type_map_[payload_type] = payload;
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
124int32_t RTPPayloadRegistry::DeRegisterReceivePayload(
125    const int8_t payload_type) {
126  ModuleRTPUtility::PayloadTypeMap::iterator it =
127    payload_type_map_.find(payload_type);
128
129  if (it == payload_type_map_.end()) {
130    WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, id_,
131                 "%s failed to find payload_type:%d",
132                 __FUNCTION__, payload_type);
133    return -1;
134  }
135  delete it->second;
136  payload_type_map_.erase(it);
137  return 0;
138}
139
140// There can't be several codecs with the same rate, frequency and channels
141// for audio codecs, but there can for video.
142void RTPPayloadRegistry::DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType(
143    const char payload_name[RTP_PAYLOAD_NAME_SIZE],
144    const size_t payload_name_length,
145    const uint32_t frequency,
146    const uint8_t channels,
147    const uint32_t rate) {
148  ModuleRTPUtility::PayloadTypeMap::iterator iterator =
149      payload_type_map_.begin();
150  for (; iterator != payload_type_map_.end(); ++iterator) {
151    ModuleRTPUtility::Payload* payload = iterator->second;
152    size_t name_length = strlen(payload->name);
153
154    if (payload_name_length == name_length
155        && ModuleRTPUtility::StringCompare(payload->name, payload_name,
156                                           payload_name_length)) {
157      // We found the payload name in the list.
158      // If audio, check frequency and rate.
159      if (payload->audio) {
160        if (rtp_payload_strategy_->PayloadIsCompatible(*payload, frequency,
161                                                       channels, rate)) {
162          // Remove old setting.
163          delete payload;
164          payload_type_map_.erase(iterator);
165          break;
166        }
167      } else if (ModuleRTPUtility::StringCompare(payload_name, "red", 3)) {
168        delete payload;
169        payload_type_map_.erase(iterator);
170        break;
171      }
172    }
173  }
174}
175
176int32_t RTPPayloadRegistry::ReceivePayloadType(
177    const char payload_name[RTP_PAYLOAD_NAME_SIZE],
178    const uint32_t frequency,
179    const uint8_t channels,
180    const uint32_t rate,
181    int8_t* payload_type) const {
182  if (payload_type == NULL) {
183    WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, id_,
184                 "%s invalid argument", __FUNCTION__);
185    return -1;
186  }
187  size_t payload_name_length = strlen(payload_name);
188
189  ModuleRTPUtility::PayloadTypeMap::const_iterator it =
190      payload_type_map_.begin();
191
192  for (; it != payload_type_map_.end(); ++it) {
193    ModuleRTPUtility::Payload* payload = it->second;
194    assert(payload);
195
196    size_t name_length = strlen(payload->name);
197    if (payload_name_length == name_length &&
198        ModuleRTPUtility::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::GetPayloadSpecifics(uint8_t payload_type,
230                                             PayloadUnion* payload) const {
231  ModuleRTPUtility::PayloadTypeMap::const_iterator it =
232    payload_type_map_.find(payload_type);
233
234  // Check that this is a registered payload type.
235  if (it == payload_type_map_.end()) {
236    return false;
237  }
238  *payload = it->second->typeSpecific;
239  return true;
240}
241
242int RTPPayloadRegistry::GetPayloadTypeFrequency(
243    uint8_t payload_type) const {
244  ModuleRTPUtility::Payload* payload;
245  if (!PayloadTypeToPayload(payload_type, payload)) {
246    return -1;
247  }
248  return rtp_payload_strategy_->GetPayloadTypeFrequency(*payload);
249}
250
251bool RTPPayloadRegistry::PayloadTypeToPayload(
252  const uint8_t payload_type,
253  ModuleRTPUtility::Payload*& payload) const {
254
255  ModuleRTPUtility::PayloadTypeMap::const_iterator it =
256    payload_type_map_.find(payload_type);
257
258  // Check that this is a registered payload type.
259  if (it == payload_type_map_.end()) {
260    return false;
261  }
262  payload = it->second;
263  return true;
264}
265
266bool RTPPayloadRegistry::ReportMediaPayloadType(
267    uint8_t media_payload_type) {
268  if (last_received_media_payload_type_ == media_payload_type) {
269    // Media type unchanged.
270    return true;
271  }
272  last_received_media_payload_type_ = media_payload_type;
273  return false;
274}
275
276class RTPPayloadAudioStrategy : public RTPPayloadStrategy {
277 public:
278  bool CodecsMustBeUnique() const { return true; }
279
280  bool PayloadIsCompatible(
281       const ModuleRTPUtility::Payload& payload,
282       const uint32_t frequency,
283       const uint8_t channels,
284       const uint32_t rate) const {
285    return
286        payload.audio &&
287        payload.typeSpecific.Audio.frequency == frequency &&
288        payload.typeSpecific.Audio.channels == channels &&
289        (payload.typeSpecific.Audio.rate == rate ||
290            payload.typeSpecific.Audio.rate == 0 || rate == 0);
291  }
292
293  void UpdatePayloadRate(
294      ModuleRTPUtility::Payload* payload,
295      const uint32_t rate) const {
296    payload->typeSpecific.Audio.rate = rate;
297  }
298
299  ModuleRTPUtility::Payload* CreatePayloadType(
300      const char payloadName[RTP_PAYLOAD_NAME_SIZE],
301      const int8_t payloadType,
302      const uint32_t frequency,
303      const uint8_t channels,
304      const uint32_t rate) const {
305    ModuleRTPUtility::Payload* payload = new ModuleRTPUtility::Payload;
306    payload->name[RTP_PAYLOAD_NAME_SIZE - 1] = 0;
307    strncpy(payload->name, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
308    assert(frequency >= 1000);
309    payload->typeSpecific.Audio.frequency = frequency;
310    payload->typeSpecific.Audio.channels = channels;
311    payload->typeSpecific.Audio.rate = rate;
312    payload->audio = true;
313    return payload;
314  }
315
316  int GetPayloadTypeFrequency(
317      const ModuleRTPUtility::Payload& payload) const {
318    return payload.typeSpecific.Audio.frequency;
319  }
320};
321
322class RTPPayloadVideoStrategy : public RTPPayloadStrategy {
323 public:
324  bool CodecsMustBeUnique() const { return false; }
325
326  bool PayloadIsCompatible(
327      const ModuleRTPUtility::Payload& payload,
328      const uint32_t frequency,
329      const uint8_t channels,
330      const uint32_t rate) const {
331    return !payload.audio;
332  }
333
334  void UpdatePayloadRate(
335      ModuleRTPUtility::Payload* payload,
336      const uint32_t rate) const {
337    payload->typeSpecific.Video.maxRate = rate;
338  }
339
340  ModuleRTPUtility::Payload* CreatePayloadType(
341      const char payloadName[RTP_PAYLOAD_NAME_SIZE],
342      const int8_t payloadType,
343      const uint32_t frequency,
344      const uint8_t channels,
345      const uint32_t rate) const {
346    RtpVideoCodecTypes videoType = kRtpVideoGeneric;
347    if (ModuleRTPUtility::StringCompare(payloadName, "VP8", 3)) {
348      videoType = kRtpVideoVp8;
349    } else if (ModuleRTPUtility::StringCompare(payloadName, "I420", 4)) {
350      videoType = kRtpVideoGeneric;
351    } else if (ModuleRTPUtility::StringCompare(payloadName, "ULPFEC", 6)) {
352      videoType = kRtpVideoFec;
353    } else {
354      videoType = kRtpVideoGeneric;
355    }
356    ModuleRTPUtility::Payload* payload = new ModuleRTPUtility::Payload;
357
358    payload->name[RTP_PAYLOAD_NAME_SIZE - 1] = 0;
359    strncpy(payload->name, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
360    payload->typeSpecific.Video.videoCodecType = videoType;
361    payload->typeSpecific.Video.maxRate = rate;
362    payload->audio = false;
363    return payload;
364  }
365
366  int GetPayloadTypeFrequency(
367      const ModuleRTPUtility::Payload& payload) const {
368    return kVideoPayloadTypeFrequency;
369  }
370};
371
372RTPPayloadStrategy* RTPPayloadStrategy::CreateStrategy(
373    const bool handling_audio) {
374  if (handling_audio) {
375    return new RTPPayloadAudioStrategy();
376  } else {
377    return new RTPPayloadVideoStrategy();
378  }
379}
380
381}  // namespace webrtc
382