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