blob: 93e8a34836402f9e387ffb019cb1dbbb73037b8c [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,
Karl Wibergc62f6c72017-10-04 12:38:53 +020026 const SdpAudioFormat& audio_format) {
27 return payload.typeSpecific.is_audio() &&
28 audio_format.Matches(payload.typeSpecific.audio_payload().format);
magjedf3feeff2016-11-25 06:40:25 -080029}
30
31bool PayloadIsCompatible(const RtpUtility::Payload& payload,
32 const VideoCodec& video_codec) {
Karl Wibergc856dc22017-09-28 20:13:59 +020033 if (!payload.typeSpecific.is_video() ||
34 _stricmp(payload.name, video_codec.plName) != 0)
magjede69a1a92016-11-25 10:06:31 -080035 return false;
36 // For H264, profiles must match as well.
37 if (video_codec.codecType == kVideoCodecH264) {
38 return video_codec.H264().profile ==
Karl Wibergc856dc22017-09-28 20:13:59 +020039 payload.typeSpecific.video_payload().h264_profile;
magjede69a1a92016-11-25 10:06:31 -080040 }
41 return true;
magjedf3feeff2016-11-25 06:40:25 -080042}
43
Karl Wibergc62f6c72017-10-04 12:38:53 +020044RtpUtility::Payload CreatePayloadType(const SdpAudioFormat& audio_format) {
45 RTC_DCHECK_GE(audio_format.clockrate_hz, 1000);
46 return {audio_format.name.c_str(),
47 PayloadUnion(AudioPayload{audio_format, 0})};
magjedf3feeff2016-11-25 06:40:25 -080048}
49
50RtpVideoCodecTypes ConvertToRtpVideoCodecType(VideoCodecType type) {
51 switch (type) {
52 case kVideoCodecVP8:
53 return kRtpVideoVp8;
54 case kVideoCodecVP9:
55 return kRtpVideoVp9;
56 case kVideoCodecH264:
57 return kRtpVideoH264;
58 case kVideoCodecRED:
59 case kVideoCodecULPFEC:
60 return kRtpVideoNone;
61 default:
62 return kRtpVideoGeneric;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +000063 }
64}
65
magjedf3feeff2016-11-25 06:40:25 -080066RtpUtility::Payload CreatePayloadType(const VideoCodec& video_codec) {
Karl Wiberg83d3ec12017-09-28 19:54:38 +020067 VideoPayload p;
68 p.videoCodecType = ConvertToRtpVideoCodecType(video_codec.codecType);
magjede69a1a92016-11-25 10:06:31 -080069 if (video_codec.codecType == kVideoCodecH264)
Karl Wiberg83d3ec12017-09-28 19:54:38 +020070 p.h264_profile = video_codec.H264().profile;
71 return {video_codec.plName, PayloadUnion(p)};
magjed56124bd2016-11-24 09:34:46 -080072}
73
magjedf3feeff2016-11-25 06:40:25 -080074bool IsPayloadTypeValid(int8_t payload_type) {
pbos@webrtc.orgb5bf54c2013-04-05 13:27:38 +000075 assert(payload_type >= 0);
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +000076
77 // Sanity check.
78 switch (payload_type) {
79 // Reserved payload types to avoid RTCP conflicts when marker bit is set.
80 case 64: // 192 Full INTRA-frame request.
81 case 72: // 200 Sender report.
82 case 73: // 201 Receiver report.
83 case 74: // 202 Source description.
84 case 75: // 203 Goodbye.
85 case 76: // 204 Application-defined.
86 case 77: // 205 Transport layer FB message.
87 case 78: // 206 Payload-specific FB message.
88 case 79: // 207 Extended report.
Mirko Bonadei675513b2017-11-09 11:09:25 +010089 RTC_LOG(LS_ERROR) << "Can't register invalid receiver payload type: "
90 << payload_type;
magjedf3feeff2016-11-25 06:40:25 -080091 return false;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +000092 default:
magjedf3feeff2016-11-25 06:40:25 -080093 return true;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +000094 }
magjedf3feeff2016-11-25 06:40:25 -080095}
pbos@webrtc.orgb5bf54c2013-04-05 13:27:38 +000096
magjedf3feeff2016-11-25 06:40:25 -080097} // namespace
98
99RTPPayloadRegistry::RTPPayloadRegistry()
100 : incoming_payload_type_(-1),
101 last_received_payload_type_(-1),
102 last_received_media_payload_type_(-1),
103 rtx_(false),
104 ssrc_rtx_(0) {}
105
106RTPPayloadRegistry::~RTPPayloadRegistry() = default;
107
kwiberg1c07c702017-03-27 07:15:49 -0700108void RTPPayloadRegistry::SetAudioReceivePayloads(
109 std::map<int, SdpAudioFormat> codecs) {
110 rtc::CritScope cs(&crit_sect_);
111
112#if RTC_DCHECK_IS_ON
113 RTC_DCHECK(!used_for_video_);
114 used_for_audio_ = true;
115#endif
116
117 payload_type_map_.clear();
118 for (const auto& kv : codecs) {
119 const int& rtp_payload_type = kv.first;
120 const SdpAudioFormat& audio_format = kv.second;
kwiberg1c07c702017-03-27 07:15:49 -0700121 RTC_DCHECK(IsPayloadTypeValid(rtp_payload_type));
Karl Wibergc62f6c72017-10-04 12:38:53 +0200122 payload_type_map_.emplace(rtp_payload_type,
123 CreatePayloadType(audio_format));
kwiberg1c07c702017-03-27 07:15:49 -0700124 }
125
126 // Clear the value of last received payload type since it might mean
127 // something else now.
128 last_received_payload_type_ = -1;
129 last_received_media_payload_type_ = -1;
130}
131
Karl Wibergc62f6c72017-10-04 12:38:53 +0200132int32_t RTPPayloadRegistry::RegisterReceivePayload(
133 int payload_type,
134 const SdpAudioFormat& audio_format,
135 bool* created_new_payload) {
kwibergb0bf93a2017-03-23 00:10:09 -0700136 rtc::CritScope cs(&crit_sect_);
137
138#if RTC_DCHECK_IS_ON
139 RTC_DCHECK(!used_for_video_);
140 used_for_audio_ = true;
141#endif
142
magjedf3feeff2016-11-25 06:40:25 -0800143 *created_new_payload = false;
Karl Wibergc62f6c72017-10-04 12:38:53 +0200144 if (!IsPayloadTypeValid(payload_type))
magjedf3feeff2016-11-25 06:40:25 -0800145 return -1;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000146
Karl Wibergc62f6c72017-10-04 12:38:53 +0200147 const auto it = payload_type_map_.find(payload_type);
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000148 if (it != payload_type_map_.end()) {
magjedf3feeff2016-11-25 06:40:25 -0800149 // We already use this payload type. Check if it's the same as we already
150 // have. If same, ignore sending an error.
Karl Wibergc62f6c72017-10-04 12:38:53 +0200151 if (PayloadIsCompatible(it->second, audio_format)) {
Karl Wibergc856dc22017-09-28 20:13:59 +0200152 it->second.typeSpecific.audio_payload().rate = 0;
magjedf3feeff2016-11-25 06:40:25 -0800153 return 0;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000154 }
Mirko Bonadei675513b2017-11-09 11:09:25 +0100155 RTC_LOG(LS_ERROR) << "Payload type already registered: " << payload_type;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000156 return -1;
157 }
158
magjedf3feeff2016-11-25 06:40:25 -0800159 // Audio codecs must be unique.
Karl Wibergc62f6c72017-10-04 12:38:53 +0200160 DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType(audio_format);
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000161
Karl Wibergc62f6c72017-10-04 12:38:53 +0200162 const auto insert_status =
163 payload_type_map_.emplace(payload_type, CreatePayloadType(audio_format));
Karl Wiberg83d3ec12017-09-28 19:54:38 +0200164 RTC_DCHECK(insert_status.second); // Insertion succeeded.
Minyue Li190c3ca2015-03-25 16:11:24 +0100165 *created_new_payload = true;
166
magjedf3feeff2016-11-25 06:40:25 -0800167 // Successful set of payload type, clear the value of last received payload
168 // type since it might mean something else.
169 last_received_payload_type_ = -1;
170 last_received_media_payload_type_ = -1;
171 return 0;
172}
173
174int32_t RTPPayloadRegistry::RegisterReceivePayload(
175 const VideoCodec& video_codec) {
kwibergb0bf93a2017-03-23 00:10:09 -0700176 rtc::CritScope cs(&crit_sect_);
177
178#if RTC_DCHECK_IS_ON
179 RTC_DCHECK(!used_for_audio_);
180 used_for_video_ = true;
181#endif
182
magjedf3feeff2016-11-25 06:40:25 -0800183 if (!IsPayloadTypeValid(video_codec.plType))
184 return -1;
185
magjedf3feeff2016-11-25 06:40:25 -0800186 auto it = payload_type_map_.find(video_codec.plType);
187 if (it != payload_type_map_.end()) {
188 // We already use this payload type. Check if it's the same as we already
189 // have. If same, ignore sending an error.
190 if (PayloadIsCompatible(it->second, video_codec))
191 return 0;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100192 RTC_LOG(LS_ERROR) << "Payload type already registered: "
193 << static_cast<int>(video_codec.plType);
magjedf3feeff2016-11-25 06:40:25 -0800194 return -1;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000195 }
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000196
Karl Wiberg83d3ec12017-09-28 19:54:38 +0200197 const auto insert_status = payload_type_map_.emplace(
198 video_codec.plType, CreatePayloadType(video_codec));
199 RTC_DCHECK(insert_status.second); // Insertion succeeded.
magjedf3feeff2016-11-25 06:40:25 -0800200
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000201 // Successful set of payload type, clear the value of last received payload
202 // type since it might mean something else.
203 last_received_payload_type_ = -1;
204 last_received_media_payload_type_ = -1;
205 return 0;
206}
207
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000208int32_t RTPPayloadRegistry::DeRegisterReceivePayload(
209 const int8_t payload_type) {
danilchap7c9426c2016-04-14 03:05:31 -0700210 rtc::CritScope cs(&crit_sect_);
magjedf3feeff2016-11-25 06:40:25 -0800211 payload_type_map_.erase(payload_type);
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000212 return 0;
213}
214
phoglund@webrtc.org244251a2013-02-04 13:23:07 +0000215// There can't be several codecs with the same rate, frequency and channels
216// for audio codecs, but there can for video.
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000217// Always called from within a critical section.
phoglund@webrtc.org244251a2013-02-04 13:23:07 +0000218void RTPPayloadRegistry::DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType(
Karl Wibergc62f6c72017-10-04 12:38:53 +0200219 const SdpAudioFormat& audio_format) {
magjedf3feeff2016-11-25 06:40:25 -0800220 for (auto iterator = payload_type_map_.begin();
221 iterator != payload_type_map_.end(); ++iterator) {
Karl Wibergc62f6c72017-10-04 12:38:53 +0200222 if (PayloadIsCompatible(iterator->second, audio_format)) {
magjedf3feeff2016-11-25 06:40:25 -0800223 // Remove old setting.
224 payload_type_map_.erase(iterator);
225 break;
phoglund@webrtc.org244251a2013-02-04 13:23:07 +0000226 }
227 }
228}
229
Karl Wibergc62f6c72017-10-04 12:38:53 +0200230int32_t RTPPayloadRegistry::ReceivePayloadType(
231 const SdpAudioFormat& audio_format,
232 int8_t* payload_type) const {
magjedf3feeff2016-11-25 06:40:25 -0800233 assert(payload_type);
234 rtc::CritScope cs(&crit_sect_);
235
236 for (const auto& it : payload_type_map_) {
Karl Wibergc62f6c72017-10-04 12:38:53 +0200237 if (PayloadIsCompatible(it.second, audio_format)) {
magjedf3feeff2016-11-25 06:40:25 -0800238 *payload_type = it.first;
239 return 0;
240 }
241 }
242 return -1;
magjed56124bd2016-11-24 09:34:46 -0800243}
244
245int32_t RTPPayloadRegistry::ReceivePayloadType(const VideoCodec& video_codec,
246 int8_t* payload_type) const {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000247 assert(payload_type);
danilchap7c9426c2016-04-14 03:05:31 -0700248 rtc::CritScope cs(&crit_sect_);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000249
magjedf3feeff2016-11-25 06:40:25 -0800250 for (const auto& it : payload_type_map_) {
251 if (PayloadIsCompatible(it.second, video_codec)) {
252 *payload_type = it.first;
253 return 0;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000254 }
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000255 }
256 return -1;
257}
258
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000259bool RTPPayloadRegistry::RtxEnabled() const {
danilchap7c9426c2016-04-14 03:05:31 -0700260 rtc::CritScope cs(&crit_sect_);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000261 return rtx_;
262}
263
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000264bool RTPPayloadRegistry::IsRtxInternal(const RTPHeader& header) const {
265 return rtx_ && ssrc_rtx_ == header.ssrc;
266}
267
stefan@webrtc.orgef927552014-06-05 08:25:29 +0000268void RTPPayloadRegistry::SetRtxSsrc(uint32_t ssrc) {
danilchap7c9426c2016-04-14 03:05:31 -0700269 rtc::CritScope cs(&crit_sect_);
stefan@webrtc.orgef927552014-06-05 08:25:29 +0000270 ssrc_rtx_ = ssrc;
271 rtx_ = true;
272}
273
asapersson@webrtc.orgd952c402014-11-27 07:38:56 +0000274bool RTPPayloadRegistry::GetRtxSsrc(uint32_t* ssrc) const {
danilchap7c9426c2016-04-14 03:05:31 -0700275 rtc::CritScope cs(&crit_sect_);
asapersson@webrtc.orgd952c402014-11-27 07:38:56 +0000276 *ssrc = ssrc_rtx_;
277 return rtx_;
278}
279
Shao Changbine62202f2015-04-21 20:24:50 +0800280void RTPPayloadRegistry::SetRtxPayloadType(int payload_type,
281 int associated_payload_type) {
danilchap7c9426c2016-04-14 03:05:31 -0700282 rtc::CritScope cs(&crit_sect_);
Shao Changbine62202f2015-04-21 20:24:50 +0800283 if (payload_type < 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100284 RTC_LOG(LS_ERROR) << "Invalid RTX payload type: " << payload_type;
Shao Changbine62202f2015-04-21 20:24:50 +0800285 return;
286 }
287
288 rtx_payload_type_map_[payload_type] = associated_payload_type;
stefan@webrtc.orgef927552014-06-05 08:25:29 +0000289 rtx_ = true;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000290}
291
292bool RTPPayloadRegistry::IsRed(const RTPHeader& header) const {
danilchap7c9426c2016-04-14 03:05:31 -0700293 rtc::CritScope cs(&crit_sect_);
magjedf3feeff2016-11-25 06:40:25 -0800294 auto it = payload_type_map_.find(header.payloadType);
295 return it != payload_type_map_.end() && _stricmp(it->second.name, "red") == 0;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000296}
297
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000298int RTPPayloadRegistry::GetPayloadTypeFrequency(
299 uint8_t payload_type) const {
Karl Wiberg73b60b82017-09-21 15:00:58 +0200300 const auto payload = PayloadTypeToPayload(payload_type);
danilchap5c1def82015-12-10 09:51:54 -0800301 if (!payload) {
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000302 return -1;
303 }
danilchap7c9426c2016-04-14 03:05:31 -0700304 rtc::CritScope cs(&crit_sect_);
Karl Wibergc856dc22017-09-28 20:13:59 +0200305 return payload->typeSpecific.is_audio()
Karl Wibergc62f6c72017-10-04 12:38:53 +0200306 ? payload->typeSpecific.audio_payload().format.clockrate_hz
Karl Wibergc856dc22017-09-28 20:13:59 +0200307 : kVideoPayloadTypeFrequency;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000308}
309
Karl Wiberg73b60b82017-09-21 15:00:58 +0200310rtc::Optional<RtpUtility::Payload> RTPPayloadRegistry::PayloadTypeToPayload(
danilchap5c1def82015-12-10 09:51:54 -0800311 uint8_t payload_type) const {
danilchap7c9426c2016-04-14 03:05:31 -0700312 rtc::CritScope cs(&crit_sect_);
Karl Wiberg73b60b82017-09-21 15:00:58 +0200313 const auto it = payload_type_map_.find(payload_type);
314 return it == payload_type_map_.end()
Oskar Sundbom3419cf92017-11-16 10:55:48 +0100315 ? rtc::nullopt
Karl Wiberg73b60b82017-09-21 15:00:58 +0200316 : rtc::Optional<RtpUtility::Payload>(it->second);
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000317}
318
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000319void RTPPayloadRegistry::SetIncomingPayloadType(const RTPHeader& header) {
danilchap7c9426c2016-04-14 03:05:31 -0700320 rtc::CritScope cs(&crit_sect_);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000321 if (!IsRtxInternal(header))
322 incoming_payload_type_ = header.payloadType;
323}
324
325bool RTPPayloadRegistry::ReportMediaPayloadType(uint8_t media_payload_type) {
danilchap7c9426c2016-04-14 03:05:31 -0700326 rtc::CritScope cs(&crit_sect_);
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000327 if (last_received_media_payload_type_ == media_payload_type) {
328 // Media type unchanged.
329 return true;
330 }
331 last_received_media_payload_type_ = media_payload_type;
332 return false;
333}
334
magjedf3feeff2016-11-25 06:40:25 -0800335// Returns -1 if a payload with name |payload_name| is not registered.
336int8_t RTPPayloadRegistry::GetPayloadTypeWithName(
337 const char* payload_name) const {
338 rtc::CritScope cs(&crit_sect_);
339 for (const auto& it : payload_type_map_) {
340 if (_stricmp(it.second.name, payload_name) == 0)
341 return it.first;
phoglund@webrtc.org244251a2013-02-04 13:23:07 +0000342 }
magjedf3feeff2016-11-25 06:40:25 -0800343 return -1;
phoglund@webrtc.org244251a2013-02-04 13:23:07 +0000344}
345
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000346} // namespace webrtc