blob: 299cedcd32ae7c3efd585a29d908171037ad93ac [file] [log] [blame]
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +00001/*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
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
henrik.lundin@webrtc.org9c55f0f2014-06-09 08:10:28 +000011#include "webrtc/modules/audio_coding/neteq/decoder_database.h"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000012
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000013#include <utility> // pair
14
henrik.lundin4cf61dd2015-12-09 06:20:58 -080015#include "webrtc/base/checks.h"
Henrik Lundind67a2192015-08-03 12:54:37 +020016#include "webrtc/base/logging.h"
kwiberg@webrtc.orge04a93b2014-12-09 10:12:53 +000017#include "webrtc/modules/audio_coding/codecs/audio_decoder.h"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000018
19namespace webrtc {
20
kwiberg5178ee82016-05-03 01:39:01 -070021DecoderDatabase::DecoderDatabase(
ossue725f7c2016-05-19 10:48:04 -070022 const rtc::scoped_refptr<AudioDecoderFactory>& decoder_factory)
kwiberg5178ee82016-05-03 01:39:01 -070023 : active_decoder_type_(-1),
24 active_cng_decoder_type_(-1),
ossue725f7c2016-05-19 10:48:04 -070025 decoder_factory_(decoder_factory) {}
pbos@webrtc.org2d1a55c2013-07-31 15:54:00 +000026
ossu97ba30e2016-04-25 07:55:58 -070027DecoderDatabase::~DecoderDatabase() = default;
pbos@webrtc.org2d1a55c2013-07-31 15:54:00 +000028
ossuf1b08da2016-09-23 02:19:43 -070029DecoderDatabase::DecoderInfo::DecoderInfo(const SdpAudioFormat& audio_format,
30 AudioDecoderFactory* factory)
31 : audio_format_(audio_format),
ossu84bc9852016-08-26 05:41:23 -070032 factory_(factory),
kwiberg342f7402016-06-16 03:18:00 -070033 external_decoder_(nullptr),
ossu9f38c212016-10-04 05:23:32 -070034 cng_decoder_(CngDecoder::Create(audio_format)),
35 subtype_(SubtypeFromFormat(audio_format)) {}
kwibergc0f2dcf2016-05-31 06:28:03 -070036
37DecoderDatabase::DecoderInfo::DecoderInfo(NetEqDecoder ct,
ossuf1b08da2016-09-23 02:19:43 -070038 AudioDecoderFactory* factory)
39 : audio_format_(*acm2::RentACodec::NetEqDecoderToSdpAudioFormat(ct)),
40 factory_(factory),
41 external_decoder_(nullptr),
ossu9f38c212016-10-04 05:23:32 -070042 cng_decoder_(CngDecoder::Create(audio_format_)),
43 subtype_(SubtypeFromFormat(audio_format_)) {}
ossuf1b08da2016-09-23 02:19:43 -070044
45DecoderDatabase::DecoderInfo::DecoderInfo(const SdpAudioFormat& audio_format,
kwiberg0fa0a972016-04-19 05:03:45 -070046 AudioDecoder* ext_dec)
ossuf1b08da2016-09-23 02:19:43 -070047 : audio_format_(audio_format),
48 factory_(nullptr),
ossu9f38c212016-10-04 05:23:32 -070049 external_decoder_(ext_dec),
50 subtype_(Subtype::kNormal) {
kwibergc0f2dcf2016-05-31 06:28:03 -070051 RTC_CHECK(ext_dec);
52}
kwiberg0fa0a972016-04-19 05:03:45 -070053
54DecoderDatabase::DecoderInfo::DecoderInfo(DecoderInfo&&) = default;
55DecoderDatabase::DecoderInfo::~DecoderInfo() = default;
56
ossu84bc9852016-08-26 05:41:23 -070057AudioDecoder* DecoderDatabase::DecoderInfo::GetDecoder() const {
ossu9f38c212016-10-04 05:23:32 -070058 if (subtype_ != Subtype::kNormal) {
ossuf1b08da2016-09-23 02:19:43 -070059 // These are handled internally, so they have no AudioDecoder objects.
60 return nullptr;
61 }
kwiberg342f7402016-06-16 03:18:00 -070062 if (external_decoder_) {
kwiberg0fa0a972016-04-19 05:03:45 -070063 RTC_DCHECK(!decoder_);
kwiberg342f7402016-06-16 03:18:00 -070064 RTC_DCHECK(!cng_decoder_);
65 return external_decoder_;
kwiberg0fa0a972016-04-19 05:03:45 -070066 }
67 if (!decoder_) {
ossuf1b08da2016-09-23 02:19:43 -070068 // TODO(ossu): Keep a check here for now, since a number of tests create
69 // DecoderInfos without factories.
ossu84bc9852016-08-26 05:41:23 -070070 RTC_DCHECK(factory_);
ossuf1b08da2016-09-23 02:19:43 -070071 decoder_ = factory_->MakeAudioDecoder(audio_format_);
kwiberg0fa0a972016-04-19 05:03:45 -070072 }
ossuf1b08da2016-09-23 02:19:43 -070073 RTC_DCHECK(decoder_) << "Failed to create: " << audio_format_;
kwiberg0fa0a972016-04-19 05:03:45 -070074 return decoder_.get();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000075}
76
ossuf1b08da2016-09-23 02:19:43 -070077bool DecoderDatabase::DecoderInfo::IsType(const char* name) const {
78 return STR_CASE_CMP(audio_format_.name.c_str(), name) == 0;
79}
80
81bool DecoderDatabase::DecoderInfo::IsType(const std::string& name) const {
82 return IsType(name.c_str());
ossu84bc9852016-08-26 05:41:23 -070083}
84
kwibergc0f2dcf2016-05-31 06:28:03 -070085rtc::Optional<DecoderDatabase::DecoderInfo::CngDecoder>
ossuf1b08da2016-09-23 02:19:43 -070086DecoderDatabase::DecoderInfo::CngDecoder::Create(const SdpAudioFormat& format) {
87 if (STR_CASE_CMP(format.name.c_str(), "CN") == 0) {
kwiberg5adaf732016-10-04 09:33:27 -070088 // CN has a 1:1 RTP clock rate to sample rate ratio.
89 const int sample_rate_hz = format.clockrate_hz;
90 RTC_DCHECK(sample_rate_hz == 8000 || sample_rate_hz == 16000 ||
91 sample_rate_hz == 32000 || sample_rate_hz == 48000);
92 return rtc::Optional<DecoderDatabase::DecoderInfo::CngDecoder>(
93 {sample_rate_hz});
ossuf1b08da2016-09-23 02:19:43 -070094 } else {
95 return rtc::Optional<CngDecoder>();
kwibergc0f2dcf2016-05-31 06:28:03 -070096 }
97}
98
ossu9f38c212016-10-04 05:23:32 -070099DecoderDatabase::DecoderInfo::Subtype
100DecoderDatabase::DecoderInfo::SubtypeFromFormat(const SdpAudioFormat& format) {
101 if (STR_CASE_CMP(format.name.c_str(), "CN") == 0) {
102 return Subtype::kComfortNoise;
103 } else if (STR_CASE_CMP(format.name.c_str(), "telephone-event") == 0) {
104 return Subtype::kDtmf;
105 } else if (STR_CASE_CMP(format.name.c_str(), "red") == 0) {
106 return Subtype::kRed;
107 }
108
109 return Subtype::kNormal;
110}
111
pbos@webrtc.org2d1a55c2013-07-31 15:54:00 +0000112bool DecoderDatabase::Empty() const { return decoders_.empty(); }
113
turaj@webrtc.org362a55e2013-09-20 16:25:28 +0000114int DecoderDatabase::Size() const { return static_cast<int>(decoders_.size()); }
pbos@webrtc.org2d1a55c2013-07-31 15:54:00 +0000115
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000116void DecoderDatabase::Reset() {
117 decoders_.clear();
ossu97ba30e2016-04-25 07:55:58 -0700118 active_decoder_type_ = -1;
119 active_cng_decoder_type_ = -1;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000120}
121
122int DecoderDatabase::RegisterPayload(uint8_t rtp_payload_type,
henrik.lundin4cf61dd2015-12-09 06:20:58 -0800123 NetEqDecoder codec_type,
124 const std::string& name) {
pkasting@chromium.orgd3245462015-02-23 21:28:22 +0000125 if (rtp_payload_type > 0x7F) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000126 return kInvalidRtpPayloadType;
127 }
ossuf1b08da2016-09-23 02:19:43 -0700128 // kCodecArbitrary is only supported through InsertExternal.
129 if (codec_type == NetEqDecoder::kDecoderArbitrary ||
130 !CodecSupported(codec_type)) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000131 return kCodecNotSupported;
132 }
ossuf1b08da2016-09-23 02:19:43 -0700133 const auto opt_format =
134 acm2::RentACodec::NetEqDecoderToSdpAudioFormat(codec_type);
135 if (!opt_format) {
136 return kCodecNotSupported;
137 }
138 DecoderInfo info(*opt_format, decoder_factory_);
139 info.name = name;
kwiberg0fa0a972016-04-19 05:03:45 -0700140 auto ret =
141 decoders_.insert(std::make_pair(rtp_payload_type, std::move(info)));
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000142 if (ret.second == false) {
143 // Database already contains a decoder with type |rtp_payload_type|.
144 return kDecoderExists;
145 }
146 return kOK;
147}
148
kwiberg5adaf732016-10-04 09:33:27 -0700149int DecoderDatabase::RegisterPayload(int rtp_payload_type,
150 const SdpAudioFormat& audio_format) {
151 if (rtp_payload_type < 0 || rtp_payload_type > 0x7f) {
152 return kInvalidRtpPayloadType;
153 }
154 const auto ret = decoders_.insert(std::make_pair(
155 rtp_payload_type, DecoderInfo(audio_format, decoder_factory_.get())));
156 if (ret.second == false) {
157 // Database already contains a decoder with type |rtp_payload_type|.
158 return kDecoderExists;
159 }
160 return kOK;
161}
162
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000163int DecoderDatabase::InsertExternal(uint8_t rtp_payload_type,
164 NetEqDecoder codec_type,
henrik.lundin4cf61dd2015-12-09 06:20:58 -0800165 const std::string& codec_name,
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000166 AudioDecoder* decoder) {
167 if (rtp_payload_type > 0x7F) {
168 return kInvalidRtpPayloadType;
169 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000170 if (!decoder) {
171 return kInvalidPointer;
172 }
ossuf1b08da2016-09-23 02:19:43 -0700173
174 const auto opt_db_format =
175 acm2::RentACodec::NetEqDecoderToSdpAudioFormat(codec_type);
176 const SdpAudioFormat format = opt_db_format.value_or({"arbitrary", 0, 0});
177
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000178 std::pair<DecoderMap::iterator, bool> ret;
ossuf1b08da2016-09-23 02:19:43 -0700179 DecoderInfo info(format, decoder);
180 info.name = codec_name;
kwiberg0fa0a972016-04-19 05:03:45 -0700181 ret = decoders_.insert(std::make_pair(rtp_payload_type, std::move(info)));
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000182 if (ret.second == false) {
183 // Database already contains a decoder with type |rtp_payload_type|.
184 return kDecoderExists;
185 }
186 return kOK;
187}
188
189int DecoderDatabase::Remove(uint8_t rtp_payload_type) {
190 if (decoders_.erase(rtp_payload_type) == 0) {
191 // No decoder with that |rtp_payload_type|.
192 return kDecoderNotFound;
193 }
ossu97ba30e2016-04-25 07:55:58 -0700194 if (active_decoder_type_ == rtp_payload_type) {
195 active_decoder_type_ = -1; // No active decoder.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000196 }
ossu97ba30e2016-04-25 07:55:58 -0700197 if (active_cng_decoder_type_ == rtp_payload_type) {
198 active_cng_decoder_type_ = -1; // No active CNG decoder.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000199 }
200 return kOK;
201}
202
kwiberg6b19b562016-09-20 04:02:25 -0700203void DecoderDatabase::RemoveAll() {
204 decoders_.clear();
205 active_decoder_type_ = -1; // No active decoder.
206 active_cng_decoder_type_ = -1; // No active CNG decoder.
207}
208
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000209const DecoderDatabase::DecoderInfo* DecoderDatabase::GetDecoderInfo(
210 uint8_t rtp_payload_type) const {
211 DecoderMap::const_iterator it = decoders_.find(rtp_payload_type);
212 if (it == decoders_.end()) {
213 // Decoder not found.
214 return NULL;
215 }
ossuf1b08da2016-09-23 02:19:43 -0700216 return &it->second;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000217}
218
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000219int DecoderDatabase::SetActiveDecoder(uint8_t rtp_payload_type,
220 bool* new_decoder) {
221 // Check that |rtp_payload_type| exists in the database.
ossu84bc9852016-08-26 05:41:23 -0700222 const DecoderInfo *info = GetDecoderInfo(rtp_payload_type);
223 if (!info) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000224 // Decoder not found.
225 return kDecoderNotFound;
226 }
ossu84bc9852016-08-26 05:41:23 -0700227 RTC_CHECK(!info->IsComfortNoise());
228 RTC_DCHECK(new_decoder);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000229 *new_decoder = false;
ossu97ba30e2016-04-25 07:55:58 -0700230 if (active_decoder_type_ < 0) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000231 // This is the first active decoder.
232 *new_decoder = true;
ossu97ba30e2016-04-25 07:55:58 -0700233 } else if (active_decoder_type_ != rtp_payload_type) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000234 // Moving from one active decoder to another. Delete the first one.
ossu84bc9852016-08-26 05:41:23 -0700235 const DecoderInfo *old_info = GetDecoderInfo(active_decoder_type_);
236 RTC_DCHECK(old_info);
237 old_info->DropDecoder();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000238 *new_decoder = true;
239 }
ossu97ba30e2016-04-25 07:55:58 -0700240 active_decoder_type_ = rtp_payload_type;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000241 return kOK;
242}
243
ossu84bc9852016-08-26 05:41:23 -0700244AudioDecoder* DecoderDatabase::GetActiveDecoder() const {
ossu97ba30e2016-04-25 07:55:58 -0700245 if (active_decoder_type_ < 0) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000246 // No active decoder.
247 return NULL;
248 }
ossu97ba30e2016-04-25 07:55:58 -0700249 return GetDecoder(active_decoder_type_);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000250}
251
252int DecoderDatabase::SetActiveCngDecoder(uint8_t rtp_payload_type) {
253 // Check that |rtp_payload_type| exists in the database.
ossu84bc9852016-08-26 05:41:23 -0700254 const DecoderInfo *info = GetDecoderInfo(rtp_payload_type);
255 if (!info) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000256 // Decoder not found.
257 return kDecoderNotFound;
258 }
ossu97ba30e2016-04-25 07:55:58 -0700259 if (active_cng_decoder_type_ >= 0 &&
260 active_cng_decoder_type_ != rtp_payload_type) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000261 // Moving from one active CNG decoder to another. Delete the first one.
ossu84bc9852016-08-26 05:41:23 -0700262 RTC_DCHECK(active_cng_decoder_);
ossu97ba30e2016-04-25 07:55:58 -0700263 active_cng_decoder_.reset();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000264 }
ossu97ba30e2016-04-25 07:55:58 -0700265 active_cng_decoder_type_ = rtp_payload_type;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000266 return kOK;
267}
268
ossu84bc9852016-08-26 05:41:23 -0700269ComfortNoiseDecoder* DecoderDatabase::GetActiveCngDecoder() const {
ossu97ba30e2016-04-25 07:55:58 -0700270 if (active_cng_decoder_type_ < 0) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000271 // No active CNG decoder.
272 return NULL;
273 }
ossu97ba30e2016-04-25 07:55:58 -0700274 if (!active_cng_decoder_) {
275 active_cng_decoder_.reset(new ComfortNoiseDecoder);
276 }
277 return active_cng_decoder_.get();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000278}
279
ossu84bc9852016-08-26 05:41:23 -0700280AudioDecoder* DecoderDatabase::GetDecoder(uint8_t rtp_payload_type) const {
281 const DecoderInfo *info = GetDecoderInfo(rtp_payload_type);
282 return info ? info->GetDecoder() : nullptr;
283}
284
ossuf1b08da2016-09-23 02:19:43 -0700285bool DecoderDatabase::IsType(uint8_t rtp_payload_type, const char* name) const {
286 const DecoderInfo* info = GetDecoderInfo(rtp_payload_type);
287 return info && info->IsType(name);
288}
289
ossu84bc9852016-08-26 05:41:23 -0700290bool DecoderDatabase::IsType(uint8_t rtp_payload_type,
ossuf1b08da2016-09-23 02:19:43 -0700291 const std::string& name) const {
292 return IsType(rtp_payload_type, name.c_str());
ossu84bc9852016-08-26 05:41:23 -0700293}
294
295bool DecoderDatabase::IsComfortNoise(uint8_t rtp_payload_type) const {
296 const DecoderInfo *info = GetDecoderInfo(rtp_payload_type);
297 return info && info->IsComfortNoise();
298}
299
300bool DecoderDatabase::IsDtmf(uint8_t rtp_payload_type) const {
301 const DecoderInfo *info = GetDecoderInfo(rtp_payload_type);
302 return info && info->IsDtmf();
303}
304
305bool DecoderDatabase::IsRed(uint8_t rtp_payload_type) const {
306 const DecoderInfo *info = GetDecoderInfo(rtp_payload_type);
307 return info && info->IsRed();
308}
309
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000310int DecoderDatabase::CheckPayloadTypes(const PacketList& packet_list) const {
311 PacketList::const_iterator it;
312 for (it = packet_list.begin(); it != packet_list.end(); ++it) {
ossu7a377612016-10-18 04:06:13 -0700313 if (!GetDecoderInfo((*it)->payload_type)) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000314 // Payload type is not found.
Henrik Lundind67a2192015-08-03 12:54:37 +0200315 LOG(LS_WARNING) << "CheckPayloadTypes: unknown RTP payload type "
ossu7a377612016-10-18 04:06:13 -0700316 << static_cast<int>((*it)->payload_type);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000317 return kDecoderNotFound;
318 }
319 }
320 return kOK;
321}
322
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000323} // namespace webrtc