blob: 9effcc291c0be0967a4523938c7ee7f235e6925b [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) {
magjedf3feeff2016-11-25 06:40:25 -080049 RTC_DCHECK_GE(audio_codec.plfreq, 1000);
Karl Wiberg83d3ec12017-09-28 19:54:38 +020050 return {audio_codec.plname,
51 PayloadUnion(
52 AudioPayload{rtc::dchecked_cast<uint32_t>(audio_codec.plfreq),
53 audio_codec.channels, 0})};
magjedf3feeff2016-11-25 06:40:25 -080054}
55
56RtpVideoCodecTypes ConvertToRtpVideoCodecType(VideoCodecType type) {
57 switch (type) {
58 case kVideoCodecVP8:
59 return kRtpVideoVp8;
60 case kVideoCodecVP9:
61 return kRtpVideoVp9;
62 case kVideoCodecH264:
63 return kRtpVideoH264;
64 case kVideoCodecRED:
65 case kVideoCodecULPFEC:
66 return kRtpVideoNone;
67 default:
68 return kRtpVideoGeneric;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +000069 }
70}
71
magjedf3feeff2016-11-25 06:40:25 -080072RtpUtility::Payload CreatePayloadType(const VideoCodec& video_codec) {
Karl Wiberg83d3ec12017-09-28 19:54:38 +020073 VideoPayload p;
74 p.videoCodecType = ConvertToRtpVideoCodecType(video_codec.codecType);
magjede69a1a92016-11-25 10:06:31 -080075 if (video_codec.codecType == kVideoCodecH264)
Karl Wiberg83d3ec12017-09-28 19:54:38 +020076 p.h264_profile = video_codec.H264().profile;
77 return {video_codec.plName, PayloadUnion(p)};
magjed56124bd2016-11-24 09:34:46 -080078}
79
magjedf3feeff2016-11-25 06:40:25 -080080bool IsPayloadTypeValid(int8_t payload_type) {
pbos@webrtc.orgb5bf54c2013-04-05 13:27:38 +000081 assert(payload_type >= 0);
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +000082
83 // Sanity check.
84 switch (payload_type) {
85 // Reserved payload types to avoid RTCP conflicts when marker bit is set.
86 case 64: // 192 Full INTRA-frame request.
87 case 72: // 200 Sender report.
88 case 73: // 201 Receiver report.
89 case 74: // 202 Source description.
90 case 75: // 203 Goodbye.
91 case 76: // 204 Application-defined.
92 case 77: // 205 Transport layer FB message.
93 case 78: // 206 Payload-specific FB message.
94 case 79: // 207 Extended report.
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +000095 LOG(LS_ERROR) << "Can't register invalid receiver payload type: "
96 << payload_type;
magjedf3feeff2016-11-25 06:40:25 -080097 return false;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +000098 default:
magjedf3feeff2016-11-25 06:40:25 -080099 return true;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000100 }
magjedf3feeff2016-11-25 06:40:25 -0800101}
pbos@webrtc.orgb5bf54c2013-04-05 13:27:38 +0000102
magjedf3feeff2016-11-25 06:40:25 -0800103} // namespace
104
105RTPPayloadRegistry::RTPPayloadRegistry()
106 : incoming_payload_type_(-1),
107 last_received_payload_type_(-1),
108 last_received_media_payload_type_(-1),
109 rtx_(false),
110 ssrc_rtx_(0) {}
111
112RTPPayloadRegistry::~RTPPayloadRegistry() = default;
113
kwiberg1c07c702017-03-27 07:15:49 -0700114void RTPPayloadRegistry::SetAudioReceivePayloads(
115 std::map<int, SdpAudioFormat> codecs) {
116 rtc::CritScope cs(&crit_sect_);
117
118#if RTC_DCHECK_IS_ON
119 RTC_DCHECK(!used_for_video_);
120 used_for_audio_ = true;
121#endif
122
123 payload_type_map_.clear();
124 for (const auto& kv : codecs) {
125 const int& rtp_payload_type = kv.first;
126 const SdpAudioFormat& audio_format = kv.second;
127 const CodecInst ci = SdpToCodecInst(rtp_payload_type, audio_format);
128 RTC_DCHECK(IsPayloadTypeValid(rtp_payload_type));
129 payload_type_map_.insert(
130 std::make_pair(rtp_payload_type, CreatePayloadType(ci)));
131 }
132
133 // Clear the value of last received payload type since it might mean
134 // something else now.
135 last_received_payload_type_ = -1;
136 last_received_media_payload_type_ = -1;
137}
138
magjedf3feeff2016-11-25 06:40:25 -0800139int32_t RTPPayloadRegistry::RegisterReceivePayload(const CodecInst& audio_codec,
140 bool* created_new_payload) {
kwibergb0bf93a2017-03-23 00:10:09 -0700141 rtc::CritScope cs(&crit_sect_);
142
143#if RTC_DCHECK_IS_ON
144 RTC_DCHECK(!used_for_video_);
145 used_for_audio_ = true;
146#endif
147
magjedf3feeff2016-11-25 06:40:25 -0800148 *created_new_payload = false;
149 if (!IsPayloadTypeValid(audio_codec.pltype))
150 return -1;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000151
magjedf3feeff2016-11-25 06:40:25 -0800152 auto it = payload_type_map_.find(audio_codec.pltype);
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000153 if (it != payload_type_map_.end()) {
magjedf3feeff2016-11-25 06:40:25 -0800154 // We already use this payload type. Check if it's the same as we already
155 // have. If same, ignore sending an error.
156 if (PayloadIsCompatible(it->second, audio_codec)) {
kwiberg68d32132016-12-06 03:52:18 -0800157 it->second.typeSpecific.Audio.rate = 0;
magjedf3feeff2016-11-25 06:40:25 -0800158 return 0;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000159 }
magjedf3feeff2016-11-25 06:40:25 -0800160 LOG(LS_ERROR) << "Payload type already registered: " << audio_codec.pltype;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000161 return -1;
162 }
163
magjedf3feeff2016-11-25 06:40:25 -0800164 // Audio codecs must be unique.
165 DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType(audio_codec);
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000166
Karl Wiberg83d3ec12017-09-28 19:54:38 +0200167 const auto insert_status = payload_type_map_.emplace(
168 audio_codec.pltype, CreatePayloadType(audio_codec));
169 RTC_DCHECK(insert_status.second); // Insertion succeeded.
Minyue Li190c3ca2015-03-25 16:11:24 +0100170 *created_new_payload = true;
171
magjedf3feeff2016-11-25 06:40:25 -0800172 // Successful set of payload type, clear the value of last received payload
173 // type since it might mean something else.
174 last_received_payload_type_ = -1;
175 last_received_media_payload_type_ = -1;
176 return 0;
177}
178
179int32_t RTPPayloadRegistry::RegisterReceivePayload(
180 const VideoCodec& video_codec) {
kwibergb0bf93a2017-03-23 00:10:09 -0700181 rtc::CritScope cs(&crit_sect_);
182
183#if RTC_DCHECK_IS_ON
184 RTC_DCHECK(!used_for_audio_);
185 used_for_video_ = true;
186#endif
187
magjedf3feeff2016-11-25 06:40:25 -0800188 if (!IsPayloadTypeValid(video_codec.plType))
189 return -1;
190
magjedf3feeff2016-11-25 06:40:25 -0800191 auto it = payload_type_map_.find(video_codec.plType);
192 if (it != payload_type_map_.end()) {
193 // We already use this payload type. Check if it's the same as we already
194 // have. If same, ignore sending an error.
195 if (PayloadIsCompatible(it->second, video_codec))
196 return 0;
197 LOG(LS_ERROR) << "Payload type already registered: "
198 << static_cast<int>(video_codec.plType);
199 return -1;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000200 }
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000201
Karl Wiberg83d3ec12017-09-28 19:54:38 +0200202 const auto insert_status = payload_type_map_.emplace(
203 video_codec.plType, CreatePayloadType(video_codec));
204 RTC_DCHECK(insert_status.second); // Insertion succeeded.
magjedf3feeff2016-11-25 06:40:25 -0800205
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000206 // Successful set of payload type, clear the value of last received payload
207 // type since it might mean something else.
208 last_received_payload_type_ = -1;
209 last_received_media_payload_type_ = -1;
210 return 0;
211}
212
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000213int32_t RTPPayloadRegistry::DeRegisterReceivePayload(
214 const int8_t payload_type) {
danilchap7c9426c2016-04-14 03:05:31 -0700215 rtc::CritScope cs(&crit_sect_);
magjedf3feeff2016-11-25 06:40:25 -0800216 payload_type_map_.erase(payload_type);
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000217 return 0;
218}
219
phoglund@webrtc.org244251a2013-02-04 13:23:07 +0000220// There can't be several codecs with the same rate, frequency and channels
221// for audio codecs, but there can for video.
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000222// Always called from within a critical section.
phoglund@webrtc.org244251a2013-02-04 13:23:07 +0000223void RTPPayloadRegistry::DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType(
magjedf3feeff2016-11-25 06:40:25 -0800224 const CodecInst& audio_codec) {
225 for (auto iterator = payload_type_map_.begin();
226 iterator != payload_type_map_.end(); ++iterator) {
227 if (PayloadIsCompatible(iterator->second, audio_codec)) {
228 // Remove old setting.
229 payload_type_map_.erase(iterator);
230 break;
phoglund@webrtc.org244251a2013-02-04 13:23:07 +0000231 }
232 }
233}
234
magjed56124bd2016-11-24 09:34:46 -0800235int32_t RTPPayloadRegistry::ReceivePayloadType(const CodecInst& audio_codec,
236 int8_t* payload_type) const {
magjedf3feeff2016-11-25 06:40:25 -0800237 assert(payload_type);
238 rtc::CritScope cs(&crit_sect_);
239
240 for (const auto& it : payload_type_map_) {
241 if (PayloadIsCompatible(it.second, audio_codec)) {
242 *payload_type = it.first;
243 return 0;
244 }
245 }
246 return -1;
magjed56124bd2016-11-24 09:34:46 -0800247}
248
249int32_t RTPPayloadRegistry::ReceivePayloadType(const VideoCodec& video_codec,
250 int8_t* payload_type) const {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000251 assert(payload_type);
danilchap7c9426c2016-04-14 03:05:31 -0700252 rtc::CritScope cs(&crit_sect_);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000253
magjedf3feeff2016-11-25 06:40:25 -0800254 for (const auto& it : payload_type_map_) {
255 if (PayloadIsCompatible(it.second, video_codec)) {
256 *payload_type = it.first;
257 return 0;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000258 }
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000259 }
260 return -1;
261}
262
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000263bool RTPPayloadRegistry::RtxEnabled() const {
danilchap7c9426c2016-04-14 03:05:31 -0700264 rtc::CritScope cs(&crit_sect_);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000265 return rtx_;
266}
267
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000268bool RTPPayloadRegistry::IsRtxInternal(const RTPHeader& header) const {
269 return rtx_ && ssrc_rtx_ == header.ssrc;
270}
271
stefan@webrtc.orgef927552014-06-05 08:25:29 +0000272void RTPPayloadRegistry::SetRtxSsrc(uint32_t ssrc) {
danilchap7c9426c2016-04-14 03:05:31 -0700273 rtc::CritScope cs(&crit_sect_);
stefan@webrtc.orgef927552014-06-05 08:25:29 +0000274 ssrc_rtx_ = ssrc;
275 rtx_ = true;
276}
277
asapersson@webrtc.orgd952c402014-11-27 07:38:56 +0000278bool RTPPayloadRegistry::GetRtxSsrc(uint32_t* ssrc) const {
danilchap7c9426c2016-04-14 03:05:31 -0700279 rtc::CritScope cs(&crit_sect_);
asapersson@webrtc.orgd952c402014-11-27 07:38:56 +0000280 *ssrc = ssrc_rtx_;
281 return rtx_;
282}
283
Shao Changbine62202f2015-04-21 20:24:50 +0800284void RTPPayloadRegistry::SetRtxPayloadType(int payload_type,
285 int associated_payload_type) {
danilchap7c9426c2016-04-14 03:05:31 -0700286 rtc::CritScope cs(&crit_sect_);
Shao Changbine62202f2015-04-21 20:24:50 +0800287 if (payload_type < 0) {
288 LOG(LS_ERROR) << "Invalid RTX payload type: " << payload_type;
289 return;
290 }
291
292 rtx_payload_type_map_[payload_type] = associated_payload_type;
stefan@webrtc.orgef927552014-06-05 08:25:29 +0000293 rtx_ = true;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000294}
295
296bool RTPPayloadRegistry::IsRed(const RTPHeader& header) const {
danilchap7c9426c2016-04-14 03:05:31 -0700297 rtc::CritScope cs(&crit_sect_);
magjedf3feeff2016-11-25 06:40:25 -0800298 auto it = payload_type_map_.find(header.payloadType);
299 return it != payload_type_map_.end() && _stricmp(it->second.name, "red") == 0;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000300}
301
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000302int RTPPayloadRegistry::GetPayloadTypeFrequency(
303 uint8_t payload_type) const {
Karl Wiberg73b60b82017-09-21 15:00:58 +0200304 const auto payload = PayloadTypeToPayload(payload_type);
danilchap5c1def82015-12-10 09:51:54 -0800305 if (!payload) {
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000306 return -1;
307 }
danilchap7c9426c2016-04-14 03:05:31 -0700308 rtc::CritScope cs(&crit_sect_);
magjedf3feeff2016-11-25 06:40:25 -0800309 return payload->audio ? payload->typeSpecific.Audio.frequency
310 : kVideoPayloadTypeFrequency;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000311}
312
Karl Wiberg73b60b82017-09-21 15:00:58 +0200313rtc::Optional<RtpUtility::Payload> RTPPayloadRegistry::PayloadTypeToPayload(
danilchap5c1def82015-12-10 09:51:54 -0800314 uint8_t payload_type) const {
danilchap7c9426c2016-04-14 03:05:31 -0700315 rtc::CritScope cs(&crit_sect_);
Karl Wiberg73b60b82017-09-21 15:00:58 +0200316 const auto it = payload_type_map_.find(payload_type);
317 return it == payload_type_map_.end()
318 ? rtc::Optional<RtpUtility::Payload>()
319 : rtc::Optional<RtpUtility::Payload>(it->second);
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000320}
321
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000322void RTPPayloadRegistry::SetIncomingPayloadType(const RTPHeader& header) {
danilchap7c9426c2016-04-14 03:05:31 -0700323 rtc::CritScope cs(&crit_sect_);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000324 if (!IsRtxInternal(header))
325 incoming_payload_type_ = header.payloadType;
326}
327
328bool RTPPayloadRegistry::ReportMediaPayloadType(uint8_t media_payload_type) {
danilchap7c9426c2016-04-14 03:05:31 -0700329 rtc::CritScope cs(&crit_sect_);
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000330 if (last_received_media_payload_type_ == media_payload_type) {
331 // Media type unchanged.
332 return true;
333 }
334 last_received_media_payload_type_ = media_payload_type;
335 return false;
336}
337
magjedf3feeff2016-11-25 06:40:25 -0800338// Returns -1 if a payload with name |payload_name| is not registered.
339int8_t RTPPayloadRegistry::GetPayloadTypeWithName(
340 const char* payload_name) const {
341 rtc::CritScope cs(&crit_sect_);
342 for (const auto& it : payload_type_map_) {
343 if (_stricmp(it.second.name, payload_name) == 0)
344 return it.first;
phoglund@webrtc.org244251a2013-02-04 13:23:07 +0000345 }
magjedf3feeff2016-11-25 06:40:25 -0800346 return -1;
phoglund@webrtc.org244251a2013-02-04 13:23:07 +0000347}
348
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000349} // namespace webrtc