blob: 6619f5c28e9c3dd02b8b417e96bd4570a9f4441b [file] [log] [blame]
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +00001/*
phoglund@webrtc.org244251a2013-02-04 13:23:07 +00002 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +00003 *
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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/rtp_rtcp/include/rtp_payload_registry.h"
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +000012
magjedf3feeff2016-11-25 06:40:25 -080013#include <algorithm>
14
Mirko Bonadei71207422017-09-15 13:58:09 +020015#include "common_types.h" // NOLINT(build/include)
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020016#include "modules/audio_coding/codecs/audio_format_conversion.h"
17#include "rtc_base/checks.h"
18#include "rtc_base/logging.h"
19#include "rtc_base/stringutils.h"
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +000020
21namespace webrtc {
22
magjedf3feeff2016-11-25 06:40:25 -080023namespace {
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +000024
magjedf3feeff2016-11-25 06:40:25 -080025bool PayloadIsCompatible(const RtpUtility::Payload& payload,
26 const CodecInst& audio_codec) {
27 if (!payload.audio)
28 return false;
29 if (_stricmp(payload.name, audio_codec.plname) != 0)
30 return false;
31 const AudioPayload& audio_payload = payload.typeSpecific.Audio;
magjedf3feeff2016-11-25 06:40:25 -080032 return audio_payload.frequency == static_cast<uint32_t>(audio_codec.plfreq) &&
kwiberg68d32132016-12-06 03:52:18 -080033 audio_payload.channels == audio_codec.channels;
magjedf3feeff2016-11-25 06:40:25 -080034}
35
36bool PayloadIsCompatible(const RtpUtility::Payload& payload,
37 const VideoCodec& video_codec) {
magjede69a1a92016-11-25 10:06:31 -080038 if (payload.audio || _stricmp(payload.name, video_codec.plName) != 0)
39 return false;
40 // For H264, profiles must match as well.
41 if (video_codec.codecType == kVideoCodecH264) {
42 return video_codec.H264().profile ==
43 payload.typeSpecific.Video.h264_profile;
44 }
45 return true;
magjedf3feeff2016-11-25 06:40:25 -080046}
47
48RtpUtility::Payload CreatePayloadType(const CodecInst& audio_codec) {
49 RtpUtility::Payload payload;
50 payload.name[RTP_PAYLOAD_NAME_SIZE - 1] = 0;
51 strncpy(payload.name, audio_codec.plname, RTP_PAYLOAD_NAME_SIZE - 1);
52 RTC_DCHECK_GE(audio_codec.plfreq, 1000);
53 payload.typeSpecific.Audio.frequency = audio_codec.plfreq;
54 payload.typeSpecific.Audio.channels = audio_codec.channels;
kwiberg68d32132016-12-06 03:52:18 -080055 payload.typeSpecific.Audio.rate = 0;
magjedf3feeff2016-11-25 06:40:25 -080056 payload.audio = true;
57 return payload;
58}
59
60RtpVideoCodecTypes ConvertToRtpVideoCodecType(VideoCodecType type) {
61 switch (type) {
62 case kVideoCodecVP8:
63 return kRtpVideoVp8;
64 case kVideoCodecVP9:
65 return kRtpVideoVp9;
66 case kVideoCodecH264:
67 return kRtpVideoH264;
68 case kVideoCodecRED:
69 case kVideoCodecULPFEC:
70 return kRtpVideoNone;
71 default:
72 return kRtpVideoGeneric;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +000073 }
74}
75
magjedf3feeff2016-11-25 06:40:25 -080076RtpUtility::Payload CreatePayloadType(const VideoCodec& video_codec) {
77 RtpUtility::Payload payload;
78 payload.name[RTP_PAYLOAD_NAME_SIZE - 1] = 0;
79 strncpy(payload.name, video_codec.plName, RTP_PAYLOAD_NAME_SIZE - 1);
80 payload.typeSpecific.Video.videoCodecType =
81 ConvertToRtpVideoCodecType(video_codec.codecType);
magjede69a1a92016-11-25 10:06:31 -080082 if (video_codec.codecType == kVideoCodecH264)
83 payload.typeSpecific.Video.h264_profile = video_codec.H264().profile;
magjedf3feeff2016-11-25 06:40:25 -080084 payload.audio = false;
85 return payload;
magjed56124bd2016-11-24 09:34:46 -080086}
87
magjedf3feeff2016-11-25 06:40:25 -080088bool IsPayloadTypeValid(int8_t payload_type) {
pbos@webrtc.orgb5bf54c2013-04-05 13:27:38 +000089 assert(payload_type >= 0);
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +000090
91 // Sanity check.
92 switch (payload_type) {
93 // Reserved payload types to avoid RTCP conflicts when marker bit is set.
94 case 64: // 192 Full INTRA-frame request.
95 case 72: // 200 Sender report.
96 case 73: // 201 Receiver report.
97 case 74: // 202 Source description.
98 case 75: // 203 Goodbye.
99 case 76: // 204 Application-defined.
100 case 77: // 205 Transport layer FB message.
101 case 78: // 206 Payload-specific FB message.
102 case 79: // 207 Extended report.
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000103 LOG(LS_ERROR) << "Can't register invalid receiver payload type: "
104 << payload_type;
magjedf3feeff2016-11-25 06:40:25 -0800105 return false;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000106 default:
magjedf3feeff2016-11-25 06:40:25 -0800107 return true;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000108 }
magjedf3feeff2016-11-25 06:40:25 -0800109}
pbos@webrtc.orgb5bf54c2013-04-05 13:27:38 +0000110
magjedf3feeff2016-11-25 06:40:25 -0800111} // namespace
112
113RTPPayloadRegistry::RTPPayloadRegistry()
114 : incoming_payload_type_(-1),
115 last_received_payload_type_(-1),
116 last_received_media_payload_type_(-1),
117 rtx_(false),
118 ssrc_rtx_(0) {}
119
120RTPPayloadRegistry::~RTPPayloadRegistry() = default;
121
kwiberg1c07c702017-03-27 07:15:49 -0700122void RTPPayloadRegistry::SetAudioReceivePayloads(
123 std::map<int, SdpAudioFormat> codecs) {
124 rtc::CritScope cs(&crit_sect_);
125
126#if RTC_DCHECK_IS_ON
127 RTC_DCHECK(!used_for_video_);
128 used_for_audio_ = true;
129#endif
130
131 payload_type_map_.clear();
132 for (const auto& kv : codecs) {
133 const int& rtp_payload_type = kv.first;
134 const SdpAudioFormat& audio_format = kv.second;
135 const CodecInst ci = SdpToCodecInst(rtp_payload_type, audio_format);
136 RTC_DCHECK(IsPayloadTypeValid(rtp_payload_type));
137 payload_type_map_.insert(
138 std::make_pair(rtp_payload_type, CreatePayloadType(ci)));
139 }
140
141 // Clear the value of last received payload type since it might mean
142 // something else now.
143 last_received_payload_type_ = -1;
144 last_received_media_payload_type_ = -1;
145}
146
magjedf3feeff2016-11-25 06:40:25 -0800147int32_t RTPPayloadRegistry::RegisterReceivePayload(const CodecInst& audio_codec,
148 bool* created_new_payload) {
kwibergb0bf93a2017-03-23 00:10:09 -0700149 rtc::CritScope cs(&crit_sect_);
150
151#if RTC_DCHECK_IS_ON
152 RTC_DCHECK(!used_for_video_);
153 used_for_audio_ = true;
154#endif
155
magjedf3feeff2016-11-25 06:40:25 -0800156 *created_new_payload = false;
157 if (!IsPayloadTypeValid(audio_codec.pltype))
158 return -1;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000159
magjedf3feeff2016-11-25 06:40:25 -0800160 auto it = payload_type_map_.find(audio_codec.pltype);
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000161 if (it != payload_type_map_.end()) {
magjedf3feeff2016-11-25 06:40:25 -0800162 // We already use this payload type. Check if it's the same as we already
163 // have. If same, ignore sending an error.
164 if (PayloadIsCompatible(it->second, audio_codec)) {
kwiberg68d32132016-12-06 03:52:18 -0800165 it->second.typeSpecific.Audio.rate = 0;
magjedf3feeff2016-11-25 06:40:25 -0800166 return 0;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000167 }
magjedf3feeff2016-11-25 06:40:25 -0800168 LOG(LS_ERROR) << "Payload type already registered: " << audio_codec.pltype;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000169 return -1;
170 }
171
magjedf3feeff2016-11-25 06:40:25 -0800172 // Audio codecs must be unique.
173 DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType(audio_codec);
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000174
magjedf3feeff2016-11-25 06:40:25 -0800175 payload_type_map_[audio_codec.pltype] = CreatePayloadType(audio_codec);
Minyue Li190c3ca2015-03-25 16:11:24 +0100176 *created_new_payload = true;
177
magjedf3feeff2016-11-25 06:40:25 -0800178 // Successful set of payload type, clear the value of last received payload
179 // type since it might mean something else.
180 last_received_payload_type_ = -1;
181 last_received_media_payload_type_ = -1;
182 return 0;
183}
184
185int32_t RTPPayloadRegistry::RegisterReceivePayload(
186 const VideoCodec& video_codec) {
kwibergb0bf93a2017-03-23 00:10:09 -0700187 rtc::CritScope cs(&crit_sect_);
188
189#if RTC_DCHECK_IS_ON
190 RTC_DCHECK(!used_for_audio_);
191 used_for_video_ = true;
192#endif
193
magjedf3feeff2016-11-25 06:40:25 -0800194 if (!IsPayloadTypeValid(video_codec.plType))
195 return -1;
196
magjedf3feeff2016-11-25 06:40:25 -0800197 auto it = payload_type_map_.find(video_codec.plType);
198 if (it != payload_type_map_.end()) {
199 // We already use this payload type. Check if it's the same as we already
200 // have. If same, ignore sending an error.
201 if (PayloadIsCompatible(it->second, video_codec))
202 return 0;
203 LOG(LS_ERROR) << "Payload type already registered: "
204 << static_cast<int>(video_codec.plType);
205 return -1;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000206 }
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000207
magjedf3feeff2016-11-25 06:40:25 -0800208 payload_type_map_[video_codec.plType] = CreatePayloadType(video_codec);
209
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000210 // Successful set of payload type, clear the value of last received payload
211 // type since it might mean something else.
212 last_received_payload_type_ = -1;
213 last_received_media_payload_type_ = -1;
214 return 0;
215}
216
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000217int32_t RTPPayloadRegistry::DeRegisterReceivePayload(
218 const int8_t payload_type) {
danilchap7c9426c2016-04-14 03:05:31 -0700219 rtc::CritScope cs(&crit_sect_);
magjedf3feeff2016-11-25 06:40:25 -0800220 payload_type_map_.erase(payload_type);
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000221 return 0;
222}
223
phoglund@webrtc.org244251a2013-02-04 13:23:07 +0000224// There can't be several codecs with the same rate, frequency and channels
225// for audio codecs, but there can for video.
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000226// Always called from within a critical section.
phoglund@webrtc.org244251a2013-02-04 13:23:07 +0000227void RTPPayloadRegistry::DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType(
magjedf3feeff2016-11-25 06:40:25 -0800228 const CodecInst& audio_codec) {
229 for (auto iterator = payload_type_map_.begin();
230 iterator != payload_type_map_.end(); ++iterator) {
231 if (PayloadIsCompatible(iterator->second, audio_codec)) {
232 // Remove old setting.
233 payload_type_map_.erase(iterator);
234 break;
phoglund@webrtc.org244251a2013-02-04 13:23:07 +0000235 }
236 }
237}
238
magjed56124bd2016-11-24 09:34:46 -0800239int32_t RTPPayloadRegistry::ReceivePayloadType(const CodecInst& audio_codec,
240 int8_t* payload_type) const {
magjedf3feeff2016-11-25 06:40:25 -0800241 assert(payload_type);
242 rtc::CritScope cs(&crit_sect_);
243
244 for (const auto& it : payload_type_map_) {
245 if (PayloadIsCompatible(it.second, audio_codec)) {
246 *payload_type = it.first;
247 return 0;
248 }
249 }
250 return -1;
magjed56124bd2016-11-24 09:34:46 -0800251}
252
253int32_t RTPPayloadRegistry::ReceivePayloadType(const VideoCodec& video_codec,
254 int8_t* payload_type) const {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000255 assert(payload_type);
danilchap7c9426c2016-04-14 03:05:31 -0700256 rtc::CritScope cs(&crit_sect_);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000257
magjedf3feeff2016-11-25 06:40:25 -0800258 for (const auto& it : payload_type_map_) {
259 if (PayloadIsCompatible(it.second, video_codec)) {
260 *payload_type = it.first;
261 return 0;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000262 }
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000263 }
264 return -1;
265}
266
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000267bool RTPPayloadRegistry::RtxEnabled() const {
danilchap7c9426c2016-04-14 03:05:31 -0700268 rtc::CritScope cs(&crit_sect_);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000269 return rtx_;
270}
271
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000272bool RTPPayloadRegistry::IsRtxInternal(const RTPHeader& header) const {
273 return rtx_ && ssrc_rtx_ == header.ssrc;
274}
275
stefan@webrtc.orgef927552014-06-05 08:25:29 +0000276void RTPPayloadRegistry::SetRtxSsrc(uint32_t ssrc) {
danilchap7c9426c2016-04-14 03:05:31 -0700277 rtc::CritScope cs(&crit_sect_);
stefan@webrtc.orgef927552014-06-05 08:25:29 +0000278 ssrc_rtx_ = ssrc;
279 rtx_ = true;
280}
281
asapersson@webrtc.orgd952c402014-11-27 07:38:56 +0000282bool RTPPayloadRegistry::GetRtxSsrc(uint32_t* ssrc) const {
danilchap7c9426c2016-04-14 03:05:31 -0700283 rtc::CritScope cs(&crit_sect_);
asapersson@webrtc.orgd952c402014-11-27 07:38:56 +0000284 *ssrc = ssrc_rtx_;
285 return rtx_;
286}
287
Shao Changbine62202f2015-04-21 20:24:50 +0800288void RTPPayloadRegistry::SetRtxPayloadType(int payload_type,
289 int associated_payload_type) {
danilchap7c9426c2016-04-14 03:05:31 -0700290 rtc::CritScope cs(&crit_sect_);
Shao Changbine62202f2015-04-21 20:24:50 +0800291 if (payload_type < 0) {
292 LOG(LS_ERROR) << "Invalid RTX payload type: " << payload_type;
293 return;
294 }
295
296 rtx_payload_type_map_[payload_type] = associated_payload_type;
stefan@webrtc.orgef927552014-06-05 08:25:29 +0000297 rtx_ = true;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000298}
299
300bool RTPPayloadRegistry::IsRed(const RTPHeader& header) const {
danilchap7c9426c2016-04-14 03:05:31 -0700301 rtc::CritScope cs(&crit_sect_);
magjedf3feeff2016-11-25 06:40:25 -0800302 auto it = payload_type_map_.find(header.payloadType);
303 return it != payload_type_map_.end() && _stricmp(it->second.name, "red") == 0;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000304}
305
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000306bool RTPPayloadRegistry::GetPayloadSpecifics(uint8_t payload_type,
307 PayloadUnion* payload) const {
danilchap7c9426c2016-04-14 03:05:31 -0700308 rtc::CritScope cs(&crit_sect_);
magjedf3feeff2016-11-25 06:40:25 -0800309 auto it = payload_type_map_.find(payload_type);
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000310
311 // Check that this is a registered payload type.
312 if (it == payload_type_map_.end()) {
313 return false;
314 }
magjedf3feeff2016-11-25 06:40:25 -0800315 *payload = it->second.typeSpecific;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000316 return true;
317}
318
319int RTPPayloadRegistry::GetPayloadTypeFrequency(
320 uint8_t payload_type) const {
danilchap5c1def82015-12-10 09:51:54 -0800321 const RtpUtility::Payload* payload = PayloadTypeToPayload(payload_type);
322 if (!payload) {
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000323 return -1;
324 }
danilchap7c9426c2016-04-14 03:05:31 -0700325 rtc::CritScope cs(&crit_sect_);
magjedf3feeff2016-11-25 06:40:25 -0800326 return payload->audio ? payload->typeSpecific.Audio.frequency
327 : kVideoPayloadTypeFrequency;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000328}
329
danilchap5c1def82015-12-10 09:51:54 -0800330const RtpUtility::Payload* RTPPayloadRegistry::PayloadTypeToPayload(
331 uint8_t payload_type) const {
danilchap7c9426c2016-04-14 03:05:31 -0700332 rtc::CritScope cs(&crit_sect_);
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000333
magjedf3feeff2016-11-25 06:40:25 -0800334 auto it = payload_type_map_.find(payload_type);
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000335
336 // Check that this is a registered payload type.
337 if (it == payload_type_map_.end()) {
danilchap5c1def82015-12-10 09:51:54 -0800338 return nullptr;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000339 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000340
magjedf3feeff2016-11-25 06:40:25 -0800341 return &it->second;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000342}
343
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000344void RTPPayloadRegistry::SetIncomingPayloadType(const RTPHeader& header) {
danilchap7c9426c2016-04-14 03:05:31 -0700345 rtc::CritScope cs(&crit_sect_);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000346 if (!IsRtxInternal(header))
347 incoming_payload_type_ = header.payloadType;
348}
349
350bool RTPPayloadRegistry::ReportMediaPayloadType(uint8_t media_payload_type) {
danilchap7c9426c2016-04-14 03:05:31 -0700351 rtc::CritScope cs(&crit_sect_);
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000352 if (last_received_media_payload_type_ == media_payload_type) {
353 // Media type unchanged.
354 return true;
355 }
356 last_received_media_payload_type_ = media_payload_type;
357 return false;
358}
359
magjedf3feeff2016-11-25 06:40:25 -0800360// Returns -1 if a payload with name |payload_name| is not registered.
361int8_t RTPPayloadRegistry::GetPayloadTypeWithName(
362 const char* payload_name) const {
363 rtc::CritScope cs(&crit_sect_);
364 for (const auto& it : payload_type_map_) {
365 if (_stricmp(it.second.name, payload_name) == 0)
366 return it.first;
phoglund@webrtc.org244251a2013-02-04 13:23:07 +0000367 }
magjedf3feeff2016-11-25 06:40:25 -0800368 return -1;
phoglund@webrtc.org244251a2013-02-04 13:23:07 +0000369}
370
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000371} // namespace webrtc