blob: 4bbb03a08b612fc4a9a14c68c9d601b331a9cc41 [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 Bonadei92ea95e2017-09-15 06:47:31 +020015#include "modules/audio_coding/codecs/audio_format_conversion.h"
16#include "rtc_base/checks.h"
17#include "rtc_base/logging.h"
18#include "rtc_base/stringutils.h"
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +000019
20namespace webrtc {
21
magjedf3feeff2016-11-25 06:40:25 -080022namespace {
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +000023
magjedf3feeff2016-11-25 06:40:25 -080024bool PayloadIsCompatible(const RtpUtility::Payload& payload,
Karl Wibergc62f6c72017-10-04 12:38:53 +020025 const SdpAudioFormat& audio_format) {
26 return payload.typeSpecific.is_audio() &&
27 audio_format.Matches(payload.typeSpecific.audio_payload().format);
magjedf3feeff2016-11-25 06:40:25 -080028}
29
30bool PayloadIsCompatible(const RtpUtility::Payload& payload,
31 const VideoCodec& video_codec) {
Karl Wibergc856dc22017-09-28 20:13:59 +020032 if (!payload.typeSpecific.is_video() ||
Yves Gerey665174f2018-06-19 15:03:05 +020033 _stricmp(payload.name, CodecTypeToPayloadString(video_codec.codecType)) !=
34 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
magjedf3feeff2016-11-25 06:40:25 -080050RtpUtility::Payload CreatePayloadType(const VideoCodec& video_codec) {
Karl Wiberg83d3ec12017-09-28 19:54:38 +020051 VideoPayload p;
Kári Tristan Helgason01a89902018-08-27 13:26:52 +020052 p.videoCodecType = video_codec.codecType;
magjede69a1a92016-11-25 10:06:31 -080053 if (video_codec.codecType == kVideoCodecH264)
Karl Wiberg83d3ec12017-09-28 19:54:38 +020054 p.h264_profile = video_codec.H264().profile;
Niels Möller2e1d7842018-02-23 15:41:13 +010055 return {CodecTypeToPayloadString(video_codec.codecType), PayloadUnion(p)};
magjed56124bd2016-11-24 09:34:46 -080056}
57
magjedf3feeff2016-11-25 06:40:25 -080058bool IsPayloadTypeValid(int8_t payload_type) {
pbos@webrtc.orgb5bf54c2013-04-05 13:27:38 +000059 assert(payload_type >= 0);
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +000060
61 // Sanity check.
62 switch (payload_type) {
63 // Reserved payload types to avoid RTCP conflicts when marker bit is set.
Yves Gerey665174f2018-06-19 15:03:05 +020064 case 64: // 192 Full INTRA-frame request.
65 case 72: // 200 Sender report.
66 case 73: // 201 Receiver report.
67 case 74: // 202 Source description.
68 case 75: // 203 Goodbye.
69 case 76: // 204 Application-defined.
70 case 77: // 205 Transport layer FB message.
71 case 78: // 206 Payload-specific FB message.
72 case 79: // 207 Extended report.
Mirko Bonadei675513b2017-11-09 11:09:25 +010073 RTC_LOG(LS_ERROR) << "Can't register invalid receiver payload type: "
74 << payload_type;
magjedf3feeff2016-11-25 06:40:25 -080075 return false;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +000076 default:
magjedf3feeff2016-11-25 06:40:25 -080077 return true;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +000078 }
magjedf3feeff2016-11-25 06:40:25 -080079}
pbos@webrtc.orgb5bf54c2013-04-05 13:27:38 +000080
magjedf3feeff2016-11-25 06:40:25 -080081} // namespace
82
Niels Möllerfd77b782018-08-06 12:40:58 +020083RTPPayloadRegistry::RTPPayloadRegistry() = default;
magjedf3feeff2016-11-25 06:40:25 -080084
85RTPPayloadRegistry::~RTPPayloadRegistry() = default;
86
kwiberg1c07c702017-03-27 07:15:49 -070087void RTPPayloadRegistry::SetAudioReceivePayloads(
88 std::map<int, SdpAudioFormat> codecs) {
89 rtc::CritScope cs(&crit_sect_);
90
91#if RTC_DCHECK_IS_ON
92 RTC_DCHECK(!used_for_video_);
93 used_for_audio_ = true;
94#endif
95
96 payload_type_map_.clear();
97 for (const auto& kv : codecs) {
98 const int& rtp_payload_type = kv.first;
99 const SdpAudioFormat& audio_format = kv.second;
kwiberg1c07c702017-03-27 07:15:49 -0700100 RTC_DCHECK(IsPayloadTypeValid(rtp_payload_type));
Karl Wibergc62f6c72017-10-04 12:38:53 +0200101 payload_type_map_.emplace(rtp_payload_type,
102 CreatePayloadType(audio_format));
kwiberg1c07c702017-03-27 07:15:49 -0700103 }
kwiberg1c07c702017-03-27 07:15:49 -0700104}
105
Karl Wibergc62f6c72017-10-04 12:38:53 +0200106int32_t RTPPayloadRegistry::RegisterReceivePayload(
107 int payload_type,
108 const SdpAudioFormat& audio_format,
109 bool* created_new_payload) {
kwibergb0bf93a2017-03-23 00:10:09 -0700110 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
magjedf3feeff2016-11-25 06:40:25 -0800117 *created_new_payload = false;
Karl Wibergc62f6c72017-10-04 12:38:53 +0200118 if (!IsPayloadTypeValid(payload_type))
magjedf3feeff2016-11-25 06:40:25 -0800119 return -1;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000120
Karl Wibergc62f6c72017-10-04 12:38:53 +0200121 const auto it = payload_type_map_.find(payload_type);
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000122 if (it != payload_type_map_.end()) {
magjedf3feeff2016-11-25 06:40:25 -0800123 // We already use this payload type. Check if it's the same as we already
124 // have. If same, ignore sending an error.
Karl Wibergc62f6c72017-10-04 12:38:53 +0200125 if (PayloadIsCompatible(it->second, audio_format)) {
Karl Wibergc856dc22017-09-28 20:13:59 +0200126 it->second.typeSpecific.audio_payload().rate = 0;
magjedf3feeff2016-11-25 06:40:25 -0800127 return 0;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000128 }
Mirko Bonadei675513b2017-11-09 11:09:25 +0100129 RTC_LOG(LS_ERROR) << "Payload type already registered: " << payload_type;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000130 return -1;
131 }
132
magjedf3feeff2016-11-25 06:40:25 -0800133 // Audio codecs must be unique.
Karl Wibergc62f6c72017-10-04 12:38:53 +0200134 DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType(audio_format);
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000135
Karl Wibergc62f6c72017-10-04 12:38:53 +0200136 const auto insert_status =
137 payload_type_map_.emplace(payload_type, CreatePayloadType(audio_format));
Karl Wiberg83d3ec12017-09-28 19:54:38 +0200138 RTC_DCHECK(insert_status.second); // Insertion succeeded.
Minyue Li190c3ca2015-03-25 16:11:24 +0100139 *created_new_payload = true;
140
Niels Möllerfd77b782018-08-06 12:40:58 +0200141 // Successful set of payload type.
magjedf3feeff2016-11-25 06:40:25 -0800142 return 0;
143}
144
145int32_t RTPPayloadRegistry::RegisterReceivePayload(
146 const VideoCodec& video_codec) {
kwibergb0bf93a2017-03-23 00:10:09 -0700147 rtc::CritScope cs(&crit_sect_);
148
149#if RTC_DCHECK_IS_ON
150 RTC_DCHECK(!used_for_audio_);
151 used_for_video_ = true;
152#endif
153
magjedf3feeff2016-11-25 06:40:25 -0800154 if (!IsPayloadTypeValid(video_codec.plType))
155 return -1;
156
magjedf3feeff2016-11-25 06:40:25 -0800157 auto it = payload_type_map_.find(video_codec.plType);
158 if (it != payload_type_map_.end()) {
159 // We already use this payload type. Check if it's the same as we already
160 // have. If same, ignore sending an error.
161 if (PayloadIsCompatible(it->second, video_codec))
162 return 0;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100163 RTC_LOG(LS_ERROR) << "Payload type already registered: "
164 << static_cast<int>(video_codec.plType);
magjedf3feeff2016-11-25 06:40:25 -0800165 return -1;
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000166 }
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 video_codec.plType, CreatePayloadType(video_codec));
170 RTC_DCHECK(insert_status.second); // Insertion succeeded.
magjedf3feeff2016-11-25 06:40:25 -0800171
Niels Möllerfd77b782018-08-06 12:40:58 +0200172 // Successful set of payload type.
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000173 return 0;
174}
175
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000176int32_t RTPPayloadRegistry::DeRegisterReceivePayload(
177 const int8_t payload_type) {
danilchap7c9426c2016-04-14 03:05:31 -0700178 rtc::CritScope cs(&crit_sect_);
magjedf3feeff2016-11-25 06:40:25 -0800179 payload_type_map_.erase(payload_type);
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000180 return 0;
181}
182
phoglund@webrtc.org244251a2013-02-04 13:23:07 +0000183// There can't be several codecs with the same rate, frequency and channels
184// for audio codecs, but there can for video.
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000185// Always called from within a critical section.
phoglund@webrtc.org244251a2013-02-04 13:23:07 +0000186void RTPPayloadRegistry::DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType(
Karl Wibergc62f6c72017-10-04 12:38:53 +0200187 const SdpAudioFormat& audio_format) {
magjedf3feeff2016-11-25 06:40:25 -0800188 for (auto iterator = payload_type_map_.begin();
189 iterator != payload_type_map_.end(); ++iterator) {
Karl Wibergc62f6c72017-10-04 12:38:53 +0200190 if (PayloadIsCompatible(iterator->second, audio_format)) {
magjedf3feeff2016-11-25 06:40:25 -0800191 // Remove old setting.
192 payload_type_map_.erase(iterator);
193 break;
phoglund@webrtc.org244251a2013-02-04 13:23:07 +0000194 }
195 }
196}
197
Yves Gerey665174f2018-06-19 15:03:05 +0200198int RTPPayloadRegistry::GetPayloadTypeFrequency(uint8_t payload_type) const {
Karl Wiberg73b60b82017-09-21 15:00:58 +0200199 const auto payload = PayloadTypeToPayload(payload_type);
danilchap5c1def82015-12-10 09:51:54 -0800200 if (!payload) {
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000201 return -1;
202 }
danilchap7c9426c2016-04-14 03:05:31 -0700203 rtc::CritScope cs(&crit_sect_);
Karl Wibergc856dc22017-09-28 20:13:59 +0200204 return payload->typeSpecific.is_audio()
Karl Wibergc62f6c72017-10-04 12:38:53 +0200205 ? payload->typeSpecific.audio_payload().format.clockrate_hz
Karl Wibergc856dc22017-09-28 20:13:59 +0200206 : kVideoPayloadTypeFrequency;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000207}
208
Danil Chapovalovd264df52018-06-14 12:59:38 +0200209absl::optional<RtpUtility::Payload> RTPPayloadRegistry::PayloadTypeToPayload(
danilchap5c1def82015-12-10 09:51:54 -0800210 uint8_t payload_type) const {
danilchap7c9426c2016-04-14 03:05:31 -0700211 rtc::CritScope cs(&crit_sect_);
Karl Wiberg73b60b82017-09-21 15:00:58 +0200212 const auto it = payload_type_map_.find(payload_type);
213 return it == payload_type_map_.end()
Danil Chapovalovd264df52018-06-14 12:59:38 +0200214 ? absl::nullopt
215 : absl::optional<RtpUtility::Payload>(it->second);
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000216}
217
phoglund@webrtc.orgefae5d52013-01-17 16:10:45 +0000218} // namespace webrtc