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/include/rtp_payload_registry.h"
12
13 #include "webrtc/base/logging.h"
14 #include "webrtc/modules/rtp_rtcp/source/byte_io.h"
15
16 namespace webrtc {
17
RTPPayloadRegistry(RTPPayloadStrategy * rtp_payload_strategy)18 RTPPayloadRegistry::RTPPayloadRegistry(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 rtx_payload_type_(-1),
28 use_rtx_payload_mapping_on_restore_(false),
29 ssrc_rtx_(0) {}
30
~RTPPayloadRegistry()31 RTPPayloadRegistry::~RTPPayloadRegistry() {
32 while (!payload_type_map_.empty()) {
33 RtpUtility::PayloadTypeMap::iterator it = payload_type_map_.begin();
34 delete it->second;
35 payload_type_map_.erase(it);
36 }
37 }
38
RegisterReceivePayload(const char payload_name[RTP_PAYLOAD_NAME_SIZE],const int8_t payload_type,const uint32_t frequency,const size_t channels,const uint32_t rate,bool * created_new_payload)39 int32_t RTPPayloadRegistry::RegisterReceivePayload(
40 const char payload_name[RTP_PAYLOAD_NAME_SIZE],
41 const int8_t payload_type,
42 const uint32_t frequency,
43 const size_t channels,
44 const uint32_t rate,
45 bool* created_new_payload) {
46 assert(payload_type >= 0);
47 assert(payload_name);
48 *created_new_payload = false;
49
50 // Sanity check.
51 switch (payload_type) {
52 // Reserved payload types to avoid RTCP conflicts when marker bit is set.
53 case 64: // 192 Full INTRA-frame request.
54 case 72: // 200 Sender report.
55 case 73: // 201 Receiver report.
56 case 74: // 202 Source description.
57 case 75: // 203 Goodbye.
58 case 76: // 204 Application-defined.
59 case 77: // 205 Transport layer FB message.
60 case 78: // 206 Payload-specific FB message.
61 case 79: // 207 Extended report.
62 LOG(LS_ERROR) << "Can't register invalid receiver payload type: "
63 << payload_type;
64 return -1;
65 default:
66 break;
67 }
68
69 size_t payload_name_length = strlen(payload_name);
70
71 CriticalSectionScoped cs(crit_sect_.get());
72
73 RtpUtility::PayloadTypeMap::iterator it =
74 payload_type_map_.find(payload_type);
75
76 if (it != payload_type_map_.end()) {
77 // We already use this payload type.
78 RtpUtility::Payload* payload = it->second;
79
80 assert(payload);
81
82 size_t name_length = strlen(payload->name);
83
84 // Check if it's the same as we already have.
85 // If same, ignore sending an error.
86 if (payload_name_length == name_length &&
87 RtpUtility::StringCompare(
88 payload->name, payload_name, payload_name_length)) {
89 if (rtp_payload_strategy_->PayloadIsCompatible(*payload, frequency,
90 channels, rate)) {
91 rtp_payload_strategy_->UpdatePayloadRate(payload, rate);
92 return 0;
93 }
94 }
95 LOG(LS_ERROR) << "Payload type already registered: "
96 << static_cast<int>(payload_type);
97 return -1;
98 }
99
100 if (rtp_payload_strategy_->CodecsMustBeUnique()) {
101 DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType(
102 payload_name, payload_name_length, frequency, channels, rate);
103 }
104
105 RtpUtility::Payload* payload = rtp_payload_strategy_->CreatePayloadType(
106 payload_name, payload_type, frequency, channels, rate);
107
108 payload_type_map_[payload_type] = payload;
109 *created_new_payload = true;
110
111 if (RtpUtility::StringCompare(payload_name, "red", 3)) {
112 red_payload_type_ = payload_type;
113 } else if (RtpUtility::StringCompare(payload_name, "ulpfec", 6)) {
114 ulpfec_payload_type_ = payload_type;
115 }
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
DeRegisterReceivePayload(const int8_t payload_type)124 int32_t RTPPayloadRegistry::DeRegisterReceivePayload(
125 const int8_t payload_type) {
126 CriticalSectionScoped cs(crit_sect_.get());
127 RtpUtility::PayloadTypeMap::iterator it =
128 payload_type_map_.find(payload_type);
129 assert(it != payload_type_map_.end());
130 delete it->second;
131 payload_type_map_.erase(it);
132 return 0;
133 }
134
135 // There can't be several codecs with the same rate, frequency and channels
136 // for audio codecs, but there can for video.
137 // 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 size_t channels,const uint32_t rate)138 void RTPPayloadRegistry::DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType(
139 const char payload_name[RTP_PAYLOAD_NAME_SIZE],
140 const size_t payload_name_length,
141 const uint32_t frequency,
142 const size_t channels,
143 const uint32_t rate) {
144 RtpUtility::PayloadTypeMap::iterator iterator = payload_type_map_.begin();
145 for (; iterator != payload_type_map_.end(); ++iterator) {
146 RtpUtility::Payload* payload = iterator->second;
147 size_t name_length = strlen(payload->name);
148
149 if (payload_name_length == name_length &&
150 RtpUtility::StringCompare(
151 payload->name, payload_name, payload_name_length)) {
152 // We found the payload name in the list.
153 // If audio, check frequency and rate.
154 if (payload->audio) {
155 if (rtp_payload_strategy_->PayloadIsCompatible(*payload, frequency,
156 channels, rate)) {
157 // Remove old setting.
158 delete payload;
159 payload_type_map_.erase(iterator);
160 break;
161 }
162 } else if (RtpUtility::StringCompare(payload_name, "red", 3)) {
163 delete payload;
164 payload_type_map_.erase(iterator);
165 break;
166 }
167 }
168 }
169 }
170
ReceivePayloadType(const char payload_name[RTP_PAYLOAD_NAME_SIZE],const uint32_t frequency,const size_t channels,const uint32_t rate,int8_t * payload_type) const171 int32_t RTPPayloadRegistry::ReceivePayloadType(
172 const char payload_name[RTP_PAYLOAD_NAME_SIZE],
173 const uint32_t frequency,
174 const size_t channels,
175 const uint32_t rate,
176 int8_t* payload_type) const {
177 assert(payload_type);
178 size_t payload_name_length = strlen(payload_name);
179
180 CriticalSectionScoped cs(crit_sect_.get());
181
182 RtpUtility::PayloadTypeMap::const_iterator it = payload_type_map_.begin();
183
184 for (; it != payload_type_map_.end(); ++it) {
185 RtpUtility::Payload* payload = it->second;
186 assert(payload);
187
188 size_t name_length = strlen(payload->name);
189 if (payload_name_length == name_length &&
190 RtpUtility::StringCompare(
191 payload->name, payload_name, payload_name_length)) {
192 // Name matches.
193 if (payload->audio) {
194 if (rate == 0) {
195 // [default] audio, check freq and channels.
196 if (payload->typeSpecific.Audio.frequency == frequency &&
197 payload->typeSpecific.Audio.channels == channels) {
198 *payload_type = it->first;
199 return 0;
200 }
201 } else {
202 // Non-default audio, check freq, channels and rate.
203 if (payload->typeSpecific.Audio.frequency == frequency &&
204 payload->typeSpecific.Audio.channels == channels &&
205 payload->typeSpecific.Audio.rate == rate) {
206 // extra rate condition added
207 *payload_type = it->first;
208 return 0;
209 }
210 }
211 } else {
212 // Video.
213 *payload_type = it->first;
214 return 0;
215 }
216 }
217 }
218 return -1;
219 }
220
RtxEnabled() const221 bool RTPPayloadRegistry::RtxEnabled() const {
222 CriticalSectionScoped cs(crit_sect_.get());
223 return rtx_;
224 }
225
IsRtx(const RTPHeader & header) const226 bool RTPPayloadRegistry::IsRtx(const RTPHeader& header) const {
227 CriticalSectionScoped cs(crit_sect_.get());
228 return IsRtxInternal(header);
229 }
230
IsRtxInternal(const RTPHeader & header) const231 bool RTPPayloadRegistry::IsRtxInternal(const RTPHeader& header) const {
232 return rtx_ && ssrc_rtx_ == header.ssrc;
233 }
234
RestoreOriginalPacket(uint8_t ** restored_packet,const uint8_t * packet,size_t * packet_length,uint32_t original_ssrc,const RTPHeader & header) const235 bool RTPPayloadRegistry::RestoreOriginalPacket(uint8_t** restored_packet,
236 const uint8_t* packet,
237 size_t* packet_length,
238 uint32_t original_ssrc,
239 const RTPHeader& header) const {
240 return RestoreOriginalPacket(*restored_packet, packet, packet_length,
241 original_ssrc, header);
242 }
243
RestoreOriginalPacket(uint8_t * restored_packet,const uint8_t * packet,size_t * packet_length,uint32_t original_ssrc,const RTPHeader & header) const244 bool RTPPayloadRegistry::RestoreOriginalPacket(uint8_t* restored_packet,
245 const uint8_t* packet,
246 size_t* packet_length,
247 uint32_t original_ssrc,
248 const RTPHeader& header) const {
249 if (kRtxHeaderSize + header.headerLength + header.paddingLength >
250 *packet_length) {
251 return false;
252 }
253 const uint8_t* rtx_header = packet + header.headerLength;
254 uint16_t original_sequence_number = (rtx_header[0] << 8) + rtx_header[1];
255
256 // Copy the packet into the restored packet, except for the RTX header.
257 memcpy(restored_packet, packet, header.headerLength);
258 memcpy(restored_packet + header.headerLength,
259 packet + header.headerLength + kRtxHeaderSize,
260 *packet_length - header.headerLength - kRtxHeaderSize);
261 *packet_length -= kRtxHeaderSize;
262
263 // Replace the SSRC and the sequence number with the originals.
264 ByteWriter<uint16_t>::WriteBigEndian(restored_packet + 2,
265 original_sequence_number);
266 ByteWriter<uint32_t>::WriteBigEndian(restored_packet + 8, original_ssrc);
267
268 CriticalSectionScoped cs(crit_sect_.get());
269 if (!rtx_)
270 return true;
271
272 int associated_payload_type;
273 auto apt_mapping = rtx_payload_type_map_.find(header.payloadType);
274 if (use_rtx_payload_mapping_on_restore_ &&
275 apt_mapping != rtx_payload_type_map_.end()) {
276 associated_payload_type = apt_mapping->second;
277 } else {
278 // In the future, this will be a bug. For now, just assume this RTX packet
279 // matches the last non-RTX payload type we received. There are cases where
280 // this could break, especially where RTX is sent outside of NACKing (e.g.
281 // padding with redundant payloads).
282 if (rtx_payload_type_ == -1 || incoming_payload_type_ == -1) {
283 LOG(LS_WARNING) << "Incorrect RTX configuration, dropping packet.";
284 return false;
285 }
286 associated_payload_type = incoming_payload_type_;
287 }
288
289 restored_packet[1] = static_cast<uint8_t>(associated_payload_type);
290 if (header.markerBit) {
291 restored_packet[1] |= kRtpMarkerBitMask; // Marker bit is set.
292 }
293 return true;
294 }
295
SetRtxSsrc(uint32_t ssrc)296 void RTPPayloadRegistry::SetRtxSsrc(uint32_t ssrc) {
297 CriticalSectionScoped cs(crit_sect_.get());
298 ssrc_rtx_ = ssrc;
299 rtx_ = true;
300 }
301
GetRtxSsrc(uint32_t * ssrc) const302 bool RTPPayloadRegistry::GetRtxSsrc(uint32_t* ssrc) const {
303 CriticalSectionScoped cs(crit_sect_.get());
304 *ssrc = ssrc_rtx_;
305 return rtx_;
306 }
307
SetRtxPayloadType(int payload_type,int associated_payload_type)308 void RTPPayloadRegistry::SetRtxPayloadType(int payload_type,
309 int associated_payload_type) {
310 CriticalSectionScoped cs(crit_sect_.get());
311 if (payload_type < 0) {
312 LOG(LS_ERROR) << "Invalid RTX payload type: " << payload_type;
313 return;
314 }
315
316 rtx_payload_type_map_[payload_type] = associated_payload_type;
317 rtx_ = true;
318 rtx_payload_type_ = payload_type;
319 }
320
IsRed(const RTPHeader & header) const321 bool RTPPayloadRegistry::IsRed(const RTPHeader& header) const {
322 CriticalSectionScoped cs(crit_sect_.get());
323 return red_payload_type_ == header.payloadType;
324 }
325
IsEncapsulated(const RTPHeader & header) const326 bool RTPPayloadRegistry::IsEncapsulated(const RTPHeader& header) const {
327 return IsRed(header) || IsRtx(header);
328 }
329
GetPayloadSpecifics(uint8_t payload_type,PayloadUnion * payload) const330 bool RTPPayloadRegistry::GetPayloadSpecifics(uint8_t payload_type,
331 PayloadUnion* payload) const {
332 CriticalSectionScoped cs(crit_sect_.get());
333 RtpUtility::PayloadTypeMap::const_iterator it =
334 payload_type_map_.find(payload_type);
335
336 // Check that this is a registered payload type.
337 if (it == payload_type_map_.end()) {
338 return false;
339 }
340 *payload = it->second->typeSpecific;
341 return true;
342 }
343
GetPayloadTypeFrequency(uint8_t payload_type) const344 int RTPPayloadRegistry::GetPayloadTypeFrequency(
345 uint8_t payload_type) const {
346 const RtpUtility::Payload* payload = PayloadTypeToPayload(payload_type);
347 if (!payload) {
348 return -1;
349 }
350 CriticalSectionScoped cs(crit_sect_.get());
351 return rtp_payload_strategy_->GetPayloadTypeFrequency(*payload);
352 }
353
PayloadTypeToPayload(uint8_t payload_type) const354 const RtpUtility::Payload* RTPPayloadRegistry::PayloadTypeToPayload(
355 uint8_t payload_type) const {
356 CriticalSectionScoped cs(crit_sect_.get());
357
358 RtpUtility::PayloadTypeMap::const_iterator it =
359 payload_type_map_.find(payload_type);
360
361 // Check that this is a registered payload type.
362 if (it == payload_type_map_.end()) {
363 return nullptr;
364 }
365
366 return it->second;
367 }
368
SetIncomingPayloadType(const RTPHeader & header)369 void RTPPayloadRegistry::SetIncomingPayloadType(const RTPHeader& header) {
370 CriticalSectionScoped cs(crit_sect_.get());
371 if (!IsRtxInternal(header))
372 incoming_payload_type_ = header.payloadType;
373 }
374
ReportMediaPayloadType(uint8_t media_payload_type)375 bool RTPPayloadRegistry::ReportMediaPayloadType(uint8_t media_payload_type) {
376 CriticalSectionScoped cs(crit_sect_.get());
377 if (last_received_media_payload_type_ == media_payload_type) {
378 // Media type unchanged.
379 return true;
380 }
381 last_received_media_payload_type_ = media_payload_type;
382 return false;
383 }
384
385 class RTPPayloadAudioStrategy : public RTPPayloadStrategy {
386 public:
CodecsMustBeUnique() const387 bool CodecsMustBeUnique() const override { return true; }
388
PayloadIsCompatible(const RtpUtility::Payload & payload,const uint32_t frequency,const size_t channels,const uint32_t rate) const389 bool PayloadIsCompatible(const RtpUtility::Payload& payload,
390 const uint32_t frequency,
391 const size_t channels,
392 const uint32_t rate) const override {
393 return
394 payload.audio &&
395 payload.typeSpecific.Audio.frequency == frequency &&
396 payload.typeSpecific.Audio.channels == channels &&
397 (payload.typeSpecific.Audio.rate == rate ||
398 payload.typeSpecific.Audio.rate == 0 || rate == 0);
399 }
400
UpdatePayloadRate(RtpUtility::Payload * payload,const uint32_t rate) const401 void UpdatePayloadRate(RtpUtility::Payload* payload,
402 const uint32_t rate) const override {
403 payload->typeSpecific.Audio.rate = rate;
404 }
405
CreatePayloadType(const char payloadName[RTP_PAYLOAD_NAME_SIZE],const int8_t payloadType,const uint32_t frequency,const size_t channels,const uint32_t rate) const406 RtpUtility::Payload* CreatePayloadType(
407 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
408 const int8_t payloadType,
409 const uint32_t frequency,
410 const size_t channels,
411 const uint32_t rate) const override {
412 RtpUtility::Payload* payload = new RtpUtility::Payload;
413 payload->name[RTP_PAYLOAD_NAME_SIZE - 1] = 0;
414 strncpy(payload->name, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
415 assert(frequency >= 1000);
416 payload->typeSpecific.Audio.frequency = frequency;
417 payload->typeSpecific.Audio.channels = channels;
418 payload->typeSpecific.Audio.rate = rate;
419 payload->audio = true;
420 return payload;
421 }
422
GetPayloadTypeFrequency(const RtpUtility::Payload & payload) const423 int GetPayloadTypeFrequency(const RtpUtility::Payload& payload) const {
424 return payload.typeSpecific.Audio.frequency;
425 }
426 };
427
428 class RTPPayloadVideoStrategy : public RTPPayloadStrategy {
429 public:
CodecsMustBeUnique() const430 bool CodecsMustBeUnique() const override { return false; }
431
PayloadIsCompatible(const RtpUtility::Payload & payload,const uint32_t frequency,const size_t channels,const uint32_t rate) const432 bool PayloadIsCompatible(const RtpUtility::Payload& payload,
433 const uint32_t frequency,
434 const size_t channels,
435 const uint32_t rate) const override {
436 return !payload.audio;
437 }
438
UpdatePayloadRate(RtpUtility::Payload * payload,const uint32_t rate) const439 void UpdatePayloadRate(RtpUtility::Payload* payload,
440 const uint32_t rate) const override {
441 payload->typeSpecific.Video.maxRate = rate;
442 }
443
CreatePayloadType(const char payloadName[RTP_PAYLOAD_NAME_SIZE],const int8_t payloadType,const uint32_t frequency,const size_t channels,const uint32_t rate) const444 RtpUtility::Payload* CreatePayloadType(
445 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
446 const int8_t payloadType,
447 const uint32_t frequency,
448 const size_t channels,
449 const uint32_t rate) const override {
450 RtpVideoCodecTypes videoType = kRtpVideoGeneric;
451
452 if (RtpUtility::StringCompare(payloadName, "VP8", 3)) {
453 videoType = kRtpVideoVp8;
454 } else if (RtpUtility::StringCompare(payloadName, "VP9", 3)) {
455 videoType = kRtpVideoVp9;
456 } else if (RtpUtility::StringCompare(payloadName, "H264", 4)) {
457 videoType = kRtpVideoH264;
458 } else if (RtpUtility::StringCompare(payloadName, "I420", 4)) {
459 videoType = kRtpVideoGeneric;
460 } else if (RtpUtility::StringCompare(payloadName, "ULPFEC", 6) ||
461 RtpUtility::StringCompare(payloadName, "RED", 3)) {
462 videoType = kRtpVideoNone;
463 } else {
464 videoType = kRtpVideoGeneric;
465 }
466 RtpUtility::Payload* payload = new RtpUtility::Payload;
467
468 payload->name[RTP_PAYLOAD_NAME_SIZE - 1] = 0;
469 strncpy(payload->name, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
470 payload->typeSpecific.Video.videoCodecType = videoType;
471 payload->typeSpecific.Video.maxRate = rate;
472 payload->audio = false;
473 return payload;
474 }
475
GetPayloadTypeFrequency(const RtpUtility::Payload & payload) const476 int GetPayloadTypeFrequency(const RtpUtility::Payload& payload) const {
477 return kVideoPayloadTypeFrequency;
478 }
479 };
480
CreateStrategy(const bool handling_audio)481 RTPPayloadStrategy* RTPPayloadStrategy::CreateStrategy(
482 const bool handling_audio) {
483 if (handling_audio) {
484 return new RTPPayloadAudioStrategy();
485 } else {
486 return new RTPPayloadVideoStrategy();
487 }
488 }
489
490 } // namespace webrtc
491