blob: de1e23201769e14c4d5cece19530d81ac578a258 [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) {
Karl Wibergc856dc22017-09-28 20:13:59 +020027 if (!payload.typeSpecific.is_audio())
magjedf3feeff2016-11-25 06:40:25 -080028 return false;
29 if (_stricmp(payload.name, audio_codec.plname) != 0)
30 return false;
Karl Wibergc856dc22017-09-28 20:13:59 +020031 const AudioPayload& audio_payload = payload.typeSpecific.audio_payload();
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) {
Karl Wibergc856dc22017-09-28 20:13:59 +020038 if (!payload.typeSpecific.is_video() ||
39 _stricmp(payload.name, video_codec.plName) != 0)
magjede69a1a92016-11-25 10:06:31 -080040 return false;
41 // For H264, profiles must match as well.
42 if (video_codec.codecType == kVideoCodecH264) {
43 return video_codec.H264().profile ==
Karl Wibergc856dc22017-09-28 20:13:59 +020044 payload.typeSpecific.video_payload().h264_profile;
magjede69a1a92016-11-25 10:06:31 -080045 }
46 return true;
magjedf3feeff2016-11-25 06:40:25 -080047}
48
49RtpUtility::Payload CreatePayloadType(const CodecInst& audio_codec) {
magjedf3feeff2016-11-25 06:40:25 -080050 RTC_DCHECK_GE(audio_codec.plfreq, 1000);
Karl Wiberg83d3ec12017-09-28 19:54:38 +020051 return {audio_codec.plname,
52 PayloadUnion(
53 AudioPayload{rtc::dchecked_cast<uint32_t>(audio_codec.plfreq),
54 audio_codec.channels, 0})};
magjedf3feeff2016-11-25 06:40:25 -080055}
56
57RtpVideoCodecTypes ConvertToRtpVideoCodecType(VideoCodecType type) {
58 switch (type) {
59 case kVideoCodecVP8:
60 return kRtpVideoVp8;
61 case kVideoCodecVP9:
62 return kRtpVideoVp9;
63 case kVideoCodecH264:
64 return kRtpVideoH264;
65 case kVideoCodecRED:
66 case kVideoCodecULPFEC:
67 return kRtpVideoNone;
68 default:
69 return kRtpVideoGeneric;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +000070 }
71}
72
magjedf3feeff2016-11-25 06:40:25 -080073RtpUtility::Payload CreatePayloadType(const VideoCodec& video_codec) {
Karl Wiberg83d3ec12017-09-28 19:54:38 +020074 VideoPayload p;
75 p.videoCodecType = ConvertToRtpVideoCodecType(video_codec.codecType);
magjede69a1a92016-11-25 10:06:31 -080076 if (video_codec.codecType == kVideoCodecH264)
Karl Wiberg83d3ec12017-09-28 19:54:38 +020077 p.h264_profile = video_codec.H264().profile;
78 return {video_codec.plName, PayloadUnion(p)};
magjed56124bd2016-11-24 09:34:46 -080079}
80
magjedf3feeff2016-11-25 06:40:25 -080081bool IsPayloadTypeValid(int8_t payload_type) {
pbos@webrtc.orgb5bf54c2013-04-05 13:27:38 +000082 assert(payload_type >= 0);
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +000083
84 // Sanity check.
85 switch (payload_type) {
86 // Reserved payload types to avoid RTCP conflicts when marker bit is set.
87 case 64: // 192 Full INTRA-frame request.
88 case 72: // 200 Sender report.
89 case 73: // 201 Receiver report.
90 case 74: // 202 Source description.
91 case 75: // 203 Goodbye.
92 case 76: // 204 Application-defined.
93 case 77: // 205 Transport layer FB message.
94 case 78: // 206 Payload-specific FB message.
95 case 79: // 207 Extended report.
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +000096 LOG(LS_ERROR) << "Can't register invalid receiver payload type: "
97 << payload_type;
magjedf3feeff2016-11-25 06:40:25 -080098 return false;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +000099 default:
magjedf3feeff2016-11-25 06:40:25 -0800100 return true;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000101 }
magjedf3feeff2016-11-25 06:40:25 -0800102}
pbos@webrtc.orgb5bf54c2013-04-05 13:27:38 +0000103
magjedf3feeff2016-11-25 06:40:25 -0800104} // namespace
105
106RTPPayloadRegistry::RTPPayloadRegistry()
107 : incoming_payload_type_(-1),
108 last_received_payload_type_(-1),
109 last_received_media_payload_type_(-1),
110 rtx_(false),
111 ssrc_rtx_(0) {}
112
113RTPPayloadRegistry::~RTPPayloadRegistry() = default;
114
kwiberg1c07c702017-03-27 07:15:49 -0700115void RTPPayloadRegistry::SetAudioReceivePayloads(
116 std::map<int, SdpAudioFormat> codecs) {
117 rtc::CritScope cs(&crit_sect_);
118
119#if RTC_DCHECK_IS_ON
120 RTC_DCHECK(!used_for_video_);
121 used_for_audio_ = true;
122#endif
123
124 payload_type_map_.clear();
125 for (const auto& kv : codecs) {
126 const int& rtp_payload_type = kv.first;
127 const SdpAudioFormat& audio_format = kv.second;
128 const CodecInst ci = SdpToCodecInst(rtp_payload_type, audio_format);
129 RTC_DCHECK(IsPayloadTypeValid(rtp_payload_type));
130 payload_type_map_.insert(
131 std::make_pair(rtp_payload_type, CreatePayloadType(ci)));
132 }
133
134 // Clear the value of last received payload type since it might mean
135 // something else now.
136 last_received_payload_type_ = -1;
137 last_received_media_payload_type_ = -1;
138}
139
magjedf3feeff2016-11-25 06:40:25 -0800140int32_t RTPPayloadRegistry::RegisterReceivePayload(const CodecInst& audio_codec,
141 bool* created_new_payload) {
kwibergb0bf93a2017-03-23 00:10:09 -0700142 rtc::CritScope cs(&crit_sect_);
143
144#if RTC_DCHECK_IS_ON
145 RTC_DCHECK(!used_for_video_);
146 used_for_audio_ = true;
147#endif
148
magjedf3feeff2016-11-25 06:40:25 -0800149 *created_new_payload = false;
150 if (!IsPayloadTypeValid(audio_codec.pltype))
151 return -1;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000152
magjedf3feeff2016-11-25 06:40:25 -0800153 auto it = payload_type_map_.find(audio_codec.pltype);
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000154 if (it != payload_type_map_.end()) {
magjedf3feeff2016-11-25 06:40:25 -0800155 // We already use this payload type. Check if it's the same as we already
156 // have. If same, ignore sending an error.
157 if (PayloadIsCompatible(it->second, audio_codec)) {
Karl Wibergc856dc22017-09-28 20:13:59 +0200158 it->second.typeSpecific.audio_payload().rate = 0;
magjedf3feeff2016-11-25 06:40:25 -0800159 return 0;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000160 }
magjedf3feeff2016-11-25 06:40:25 -0800161 LOG(LS_ERROR) << "Payload type already registered: " << audio_codec.pltype;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000162 return -1;
163 }
164
magjedf3feeff2016-11-25 06:40:25 -0800165 // Audio codecs must be unique.
166 DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType(audio_codec);
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000167
Karl Wiberg83d3ec12017-09-28 19:54:38 +0200168 const auto insert_status = payload_type_map_.emplace(
169 audio_codec.pltype, CreatePayloadType(audio_codec));
170 RTC_DCHECK(insert_status.second); // Insertion succeeded.
Minyue Li190c3ca2015-03-25 16:11:24 +0100171 *created_new_payload = true;
172
magjedf3feeff2016-11-25 06:40:25 -0800173 // Successful set of payload type, clear the value of last received payload
174 // type since it might mean something else.
175 last_received_payload_type_ = -1;
176 last_received_media_payload_type_ = -1;
177 return 0;
178}
179
180int32_t RTPPayloadRegistry::RegisterReceivePayload(
181 const VideoCodec& video_codec) {
kwibergb0bf93a2017-03-23 00:10:09 -0700182 rtc::CritScope cs(&crit_sect_);
183
184#if RTC_DCHECK_IS_ON
185 RTC_DCHECK(!used_for_audio_);
186 used_for_video_ = true;
187#endif
188
magjedf3feeff2016-11-25 06:40:25 -0800189 if (!IsPayloadTypeValid(video_codec.plType))
190 return -1;
191
magjedf3feeff2016-11-25 06:40:25 -0800192 auto it = payload_type_map_.find(video_codec.plType);
193 if (it != payload_type_map_.end()) {
194 // We already use this payload type. Check if it's the same as we already
195 // have. If same, ignore sending an error.
196 if (PayloadIsCompatible(it->second, video_codec))
197 return 0;
198 LOG(LS_ERROR) << "Payload type already registered: "
199 << static_cast<int>(video_codec.plType);
200 return -1;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000201 }
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000202
Karl Wiberg83d3ec12017-09-28 19:54:38 +0200203 const auto insert_status = payload_type_map_.emplace(
204 video_codec.plType, CreatePayloadType(video_codec));
205 RTC_DCHECK(insert_status.second); // Insertion succeeded.
magjedf3feeff2016-11-25 06:40:25 -0800206
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000207 // Successful set of payload type, clear the value of last received payload
208 // type since it might mean something else.
209 last_received_payload_type_ = -1;
210 last_received_media_payload_type_ = -1;
211 return 0;
212}
213
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000214int32_t RTPPayloadRegistry::DeRegisterReceivePayload(
215 const int8_t payload_type) {
danilchap7c9426c2016-04-14 03:05:31 -0700216 rtc::CritScope cs(&crit_sect_);
magjedf3feeff2016-11-25 06:40:25 -0800217 payload_type_map_.erase(payload_type);
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000218 return 0;
219}
220
phoglund@webrtc.org244251a2013-02-04 13:23:07 +0000221// There can't be several codecs with the same rate, frequency and channels
222// for audio codecs, but there can for video.
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000223// Always called from within a critical section.
phoglund@webrtc.org244251a2013-02-04 13:23:07 +0000224void RTPPayloadRegistry::DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType(
magjedf3feeff2016-11-25 06:40:25 -0800225 const CodecInst& audio_codec) {
226 for (auto iterator = payload_type_map_.begin();
227 iterator != payload_type_map_.end(); ++iterator) {
228 if (PayloadIsCompatible(iterator->second, audio_codec)) {
229 // Remove old setting.
230 payload_type_map_.erase(iterator);
231 break;
phoglund@webrtc.org244251a2013-02-04 13:23:07 +0000232 }
233 }
234}
235
magjed56124bd2016-11-24 09:34:46 -0800236int32_t RTPPayloadRegistry::ReceivePayloadType(const CodecInst& audio_codec,
237 int8_t* payload_type) const {
magjedf3feeff2016-11-25 06:40:25 -0800238 assert(payload_type);
239 rtc::CritScope cs(&crit_sect_);
240
241 for (const auto& it : payload_type_map_) {
242 if (PayloadIsCompatible(it.second, audio_codec)) {
243 *payload_type = it.first;
244 return 0;
245 }
246 }
247 return -1;
magjed56124bd2016-11-24 09:34:46 -0800248}
249
250int32_t RTPPayloadRegistry::ReceivePayloadType(const VideoCodec& video_codec,
251 int8_t* payload_type) const {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000252 assert(payload_type);
danilchap7c9426c2016-04-14 03:05:31 -0700253 rtc::CritScope cs(&crit_sect_);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000254
magjedf3feeff2016-11-25 06:40:25 -0800255 for (const auto& it : payload_type_map_) {
256 if (PayloadIsCompatible(it.second, video_codec)) {
257 *payload_type = it.first;
258 return 0;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000259 }
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000260 }
261 return -1;
262}
263
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000264bool RTPPayloadRegistry::RtxEnabled() const {
danilchap7c9426c2016-04-14 03:05:31 -0700265 rtc::CritScope cs(&crit_sect_);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000266 return rtx_;
267}
268
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000269bool RTPPayloadRegistry::IsRtxInternal(const RTPHeader& header) const {
270 return rtx_ && ssrc_rtx_ == header.ssrc;
271}
272
stefan@webrtc.orgef927552014-06-05 08:25:29 +0000273void RTPPayloadRegistry::SetRtxSsrc(uint32_t ssrc) {
danilchap7c9426c2016-04-14 03:05:31 -0700274 rtc::CritScope cs(&crit_sect_);
stefan@webrtc.orgef927552014-06-05 08:25:29 +0000275 ssrc_rtx_ = ssrc;
276 rtx_ = true;
277}
278
asapersson@webrtc.orgd952c402014-11-27 07:38:56 +0000279bool RTPPayloadRegistry::GetRtxSsrc(uint32_t* ssrc) const {
danilchap7c9426c2016-04-14 03:05:31 -0700280 rtc::CritScope cs(&crit_sect_);
asapersson@webrtc.orgd952c402014-11-27 07:38:56 +0000281 *ssrc = ssrc_rtx_;
282 return rtx_;
283}
284
Shao Changbine62202f2015-04-21 20:24:50 +0800285void RTPPayloadRegistry::SetRtxPayloadType(int payload_type,
286 int associated_payload_type) {
danilchap7c9426c2016-04-14 03:05:31 -0700287 rtc::CritScope cs(&crit_sect_);
Shao Changbine62202f2015-04-21 20:24:50 +0800288 if (payload_type < 0) {
289 LOG(LS_ERROR) << "Invalid RTX payload type: " << payload_type;
290 return;
291 }
292
293 rtx_payload_type_map_[payload_type] = associated_payload_type;
stefan@webrtc.orgef927552014-06-05 08:25:29 +0000294 rtx_ = true;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000295}
296
297bool RTPPayloadRegistry::IsRed(const RTPHeader& header) const {
danilchap7c9426c2016-04-14 03:05:31 -0700298 rtc::CritScope cs(&crit_sect_);
magjedf3feeff2016-11-25 06:40:25 -0800299 auto it = payload_type_map_.find(header.payloadType);
300 return it != payload_type_map_.end() && _stricmp(it->second.name, "red") == 0;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000301}
302
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000303int RTPPayloadRegistry::GetPayloadTypeFrequency(
304 uint8_t payload_type) const {
Karl Wiberg73b60b82017-09-21 15:00:58 +0200305 const auto payload = PayloadTypeToPayload(payload_type);
danilchap5c1def82015-12-10 09:51:54 -0800306 if (!payload) {
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000307 return -1;
308 }
danilchap7c9426c2016-04-14 03:05:31 -0700309 rtc::CritScope cs(&crit_sect_);
Karl Wibergc856dc22017-09-28 20:13:59 +0200310 return payload->typeSpecific.is_audio()
311 ? payload->typeSpecific.audio_payload().frequency
312 : kVideoPayloadTypeFrequency;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000313}
314
Karl Wiberg73b60b82017-09-21 15:00:58 +0200315rtc::Optional<RtpUtility::Payload> RTPPayloadRegistry::PayloadTypeToPayload(
danilchap5c1def82015-12-10 09:51:54 -0800316 uint8_t payload_type) const {
danilchap7c9426c2016-04-14 03:05:31 -0700317 rtc::CritScope cs(&crit_sect_);
Karl Wiberg73b60b82017-09-21 15:00:58 +0200318 const auto it = payload_type_map_.find(payload_type);
319 return it == payload_type_map_.end()
320 ? rtc::Optional<RtpUtility::Payload>()
321 : rtc::Optional<RtpUtility::Payload>(it->second);
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000322}
323
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000324void RTPPayloadRegistry::SetIncomingPayloadType(const RTPHeader& header) {
danilchap7c9426c2016-04-14 03:05:31 -0700325 rtc::CritScope cs(&crit_sect_);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000326 if (!IsRtxInternal(header))
327 incoming_payload_type_ = header.payloadType;
328}
329
330bool RTPPayloadRegistry::ReportMediaPayloadType(uint8_t media_payload_type) {
danilchap7c9426c2016-04-14 03:05:31 -0700331 rtc::CritScope cs(&crit_sect_);
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000332 if (last_received_media_payload_type_ == media_payload_type) {
333 // Media type unchanged.
334 return true;
335 }
336 last_received_media_payload_type_ = media_payload_type;
337 return false;
338}
339
magjedf3feeff2016-11-25 06:40:25 -0800340// Returns -1 if a payload with name |payload_name| is not registered.
341int8_t RTPPayloadRegistry::GetPayloadTypeWithName(
342 const char* payload_name) const {
343 rtc::CritScope cs(&crit_sect_);
344 for (const auto& it : payload_type_map_) {
345 if (_stricmp(it.second.name, payload_name) == 0)
346 return it.first;
phoglund@webrtc.org244251a2013-02-04 13:23:07 +0000347 }
magjedf3feeff2016-11-25 06:40:25 -0800348 return -1;
phoglund@webrtc.org244251a2013-02-04 13:23:07 +0000349}
350
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000351} // namespace webrtc