Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 #include "webrtc/modules/audio_coding/neteq/decoder_database.h" | 11 #include "webrtc/modules/audio_coding/neteq/decoder_database.h" |
| 12 | 12 |
| 13 #include <utility> // pair | 13 #include <utility> // pair |
| 14 | 14 |
| 15 #include "webrtc/base/checks.h" | 15 #include "webrtc/base/checks.h" |
| 16 #include "webrtc/base/logging.h" | 16 #include "webrtc/base/logging.h" |
| 17 #include "webrtc/modules/audio_coding/codecs/audio_decoder.h" | 17 #include "webrtc/modules/audio_coding/codecs/audio_decoder.h" |
| 18 | 18 |
| 19 namespace webrtc { | 19 namespace webrtc { |
| 20 | 20 |
| 21 DecoderDatabase::DecoderDatabase( | 21 DecoderDatabase::DecoderDatabase( |
| 22 const rtc::scoped_refptr<AudioDecoderFactory>& decoder_factory) | 22 const rtc::scoped_refptr<AudioDecoderFactory>& decoder_factory) |
| 23 : active_decoder_type_(-1), | 23 : active_decoder_type_(-1), |
| 24 active_cng_decoder_type_(-1), | 24 active_cng_decoder_type_(-1), |
| 25 decoder_factory_(decoder_factory) {} | 25 decoder_factory_(decoder_factory) {} |
| 26 | 26 |
| 27 DecoderDatabase::~DecoderDatabase() = default; | 27 DecoderDatabase::~DecoderDatabase() = default; |
| 28 | 28 |
| 29 DecoderDatabase::DecoderInfo::DecoderInfo( | 29 DecoderDatabase::DecoderInfo::DecoderInfo( |
| 30 NetEqDecoder ct, | 30 const SdpAudioFormat& audio_format, |
| 31 const std::string& nm, | |
| 32 AudioDecoderFactory* factory) | 31 AudioDecoderFactory* factory) |
| 33 : codec_type(ct), | 32 : audio_format_(audio_format), |
| 34 name(nm), | |
| 35 audio_format_(acm2::RentACodec::NetEqDecoderToSdpAudioFormat(ct)), | |
| 36 factory_(factory), | 33 factory_(factory), |
| 37 external_decoder_(nullptr), | 34 external_decoder_(nullptr), |
| 38 cng_decoder_(CngDecoder::Create(ct)) {} | 35 cng_decoder_(CngDecoder::Create(audio_format)) {} |
| 39 | 36 |
| 40 DecoderDatabase::DecoderInfo::DecoderInfo(NetEqDecoder ct, | 37 DecoderDatabase::DecoderInfo::DecoderInfo( |
| 41 const std::string& nm, | 38 NetEqDecoder ct, |
| 39 AudioDecoderFactory* factory) | |
| 40 : audio_format_(*acm2::RentACodec::NetEqDecoderToSdpAudioFormat(ct)), | |
|
kwiberg-webrtc
2016/09/20 16:05:43
This conversion can still fail, right? Maybe DCHEC
ossu
2016/09/21 09:10:55
Well if it fails, it'll do an RTC_DCHECK in Option
kwiberg-webrtc
2016/09/21 09:21:19
Yes, but a DCHECK here will make the problem much
| |
| 41 factory_(factory), | |
| 42 external_decoder_(nullptr), | |
| 43 cng_decoder_(CngDecoder::Create(audio_format_)) {} | |
| 44 | |
| 45 DecoderDatabase::DecoderInfo::DecoderInfo(const SdpAudioFormat& audio_format, | |
| 42 AudioDecoder* ext_dec) | 46 AudioDecoder* ext_dec) |
| 43 : codec_type(ct), | 47 : audio_format_(audio_format), |
| 44 name(nm), | |
| 45 audio_format_(acm2::RentACodec::NetEqDecoderToSdpAudioFormat(ct)), | |
| 46 external_decoder_(ext_dec) { | 48 external_decoder_(ext_dec) { |
| 47 RTC_CHECK(ext_dec); | 49 RTC_CHECK(ext_dec); |
| 48 } | 50 } |
| 49 | 51 |
| 50 DecoderDatabase::DecoderInfo::DecoderInfo(DecoderInfo&&) = default; | 52 DecoderDatabase::DecoderInfo::DecoderInfo(DecoderInfo&&) = default; |
| 51 DecoderDatabase::DecoderInfo::~DecoderInfo() = default; | 53 DecoderDatabase::DecoderInfo::~DecoderInfo() = default; |
| 52 | 54 |
| 53 AudioDecoder* DecoderDatabase::DecoderInfo::GetDecoder() const { | 55 AudioDecoder* DecoderDatabase::DecoderInfo::GetDecoder() const { |
| 56 if (IsDtmf() || IsRed() || IsComfortNoise()) { | |
| 57 // These are not real decoders. | |
|
kwiberg-webrtc
2016/09/20 16:05:43
// These are not the decoders you are looking for.
ossu
2016/09/21 09:10:55
Yeah, I should phrase this differently. It's dispa
kwiberg-webrtc
2016/09/21 09:21:19
Well, that too. But my suggestion was because we c
ossu
2016/09/21 15:46:30
:)
| |
| 58 return nullptr; | |
| 59 } | |
| 54 if (external_decoder_) { | 60 if (external_decoder_) { |
| 55 RTC_DCHECK(!decoder_); | 61 RTC_DCHECK(!decoder_); |
| 56 RTC_DCHECK(!cng_decoder_); | 62 RTC_DCHECK(!cng_decoder_); |
| 57 return external_decoder_; | 63 return external_decoder_; |
| 58 } | 64 } |
| 59 if (IsRed() || IsComfortNoise() || IsDtmf()) | |
| 60 return nullptr; | |
| 61 RTC_DCHECK(audio_format_); | |
| 62 if (!decoder_) { | 65 if (!decoder_) { |
| 66 // TODO(ossu): Keep a check here for now, since a number of tests create | |
| 67 // DecoderInfos without factories. | |
| 63 RTC_DCHECK(factory_); | 68 RTC_DCHECK(factory_); |
| 64 decoder_ = factory_->MakeAudioDecoder(*audio_format_); | 69 decoder_ = factory_->MakeAudioDecoder(audio_format_); |
| 65 } | 70 } |
| 66 RTC_DCHECK(decoder_) << "Failed to create: " << *audio_format_; | 71 RTC_DCHECK(decoder_) << "Failed to create: " << audio_format_; |
| 67 return decoder_.get(); | 72 return decoder_.get(); |
| 68 } | 73 } |
| 69 | 74 |
| 70 | |
| 71 bool DecoderDatabase::DecoderInfo::IsComfortNoise() const { | 75 bool DecoderDatabase::DecoderInfo::IsComfortNoise() const { |
| 72 return codec_type == NetEqDecoder::kDecoderCNGnb | 76 return IsType("CN"); |
|
kwiberg-webrtc
2016/09/20 16:05:43
Or
RTC_DCHECK_EQ(!!cng_decoder_, IsType("CN"));
ossu
2016/09/21 09:10:55
I guess that's fair. We've already done the string
kwiberg-webrtc
2016/09/21 09:21:19
Yes. And by relying on it, we strengthen the invar
| |
| 73 || codec_type == NetEqDecoder::kDecoderCNGwb | |
| 74 || codec_type == NetEqDecoder::kDecoderCNGswb32kHz | |
| 75 || codec_type == NetEqDecoder::kDecoderCNGswb48kHz; | |
| 76 } | 77 } |
| 77 | 78 |
| 78 bool DecoderDatabase::DecoderInfo::IsDtmf() const { | 79 bool DecoderDatabase::DecoderInfo::IsDtmf() const { |
| 79 return codec_type == NetEqDecoder::kDecoderAVT; | 80 return IsType("telephone-event"); |
| 80 } | 81 } |
| 81 | 82 |
| 82 bool DecoderDatabase::DecoderInfo::IsRed() const { | 83 bool DecoderDatabase::DecoderInfo::IsRed() const { |
| 83 return codec_type == NetEqDecoder::kDecoderRED; | 84 return IsType("red"); |
| 84 } | 85 } |
| 85 | 86 |
| 86 rtc::Optional<DecoderDatabase::DecoderInfo::CngDecoder> | 87 bool DecoderDatabase::DecoderInfo::IsType(const char* name) const { |
| 87 DecoderDatabase::DecoderInfo::CngDecoder::Create(NetEqDecoder ct) { | 88 return STR_CASE_CMP(audio_format_.name.c_str(), name) == 0; |
| 88 const auto cng = [](int sample_rate_hz) { | 89 } |
| 89 return rtc::Optional<DecoderDatabase::DecoderInfo::CngDecoder>( | 90 |
| 90 {sample_rate_hz}); | 91 bool DecoderDatabase::DecoderInfo::IsType(const std::string& name) const { |
| 91 }; | 92 return IsType(name.c_str()); |
| 92 switch (ct) { | 93 } |
| 93 case NetEqDecoder::kDecoderCNGnb: | 94 |
| 94 return cng(8000); | 95 rtc::Optional<DecoderDatabase::DecoderInfo::CngDecoder> DecoderDatabase:: |
| 95 case NetEqDecoder::kDecoderCNGwb: | 96 DecoderInfo::CngDecoder::Create(const SdpAudioFormat& format) { |
| 96 return cng(16000); | 97 if (STR_CASE_CMP(format.name.c_str(), "CN") == 0) { |
| 97 case NetEqDecoder::kDecoderCNGswb32kHz: | 98 return rtc::Optional<CngDecoder>({format.clockrate_hz}); |
| 98 return cng(32000); | 99 } else { |
| 99 case NetEqDecoder::kDecoderCNGswb48kHz: | 100 return rtc::Optional<CngDecoder>(); |
| 100 return cng(48000); | |
| 101 default: | |
| 102 return rtc::Optional<DecoderDatabase::DecoderInfo::CngDecoder>(); | |
| 103 } | 101 } |
| 104 } | 102 } |
| 105 | 103 |
| 106 bool DecoderDatabase::Empty() const { return decoders_.empty(); } | 104 bool DecoderDatabase::Empty() const { return decoders_.empty(); } |
| 107 | 105 |
| 108 int DecoderDatabase::Size() const { return static_cast<int>(decoders_.size()); } | 106 int DecoderDatabase::Size() const { return static_cast<int>(decoders_.size()); } |
| 109 | 107 |
| 110 void DecoderDatabase::Reset() { | 108 void DecoderDatabase::Reset() { |
| 111 decoders_.clear(); | 109 decoders_.clear(); |
| 112 active_decoder_type_ = -1; | 110 active_decoder_type_ = -1; |
| 113 active_cng_decoder_type_ = -1; | 111 active_cng_decoder_type_ = -1; |
| 114 } | 112 } |
| 115 | 113 |
| 116 int DecoderDatabase::RegisterPayload(uint8_t rtp_payload_type, | 114 int DecoderDatabase::RegisterPayload(uint8_t rtp_payload_type, |
| 117 NetEqDecoder codec_type, | 115 NetEqDecoder codec_type, |
| 118 const std::string& name) { | 116 const std::string& name) { |
| 119 if (rtp_payload_type > 0x7F) { | 117 if (rtp_payload_type > 0x7F) { |
| 120 return kInvalidRtpPayloadType; | 118 return kInvalidRtpPayloadType; |
| 121 } | 119 } |
| 122 if (!CodecSupported(codec_type)) { | 120 // kCodecArbitrary is only supported through InsertExternal. |
| 121 if (codec_type == NetEqDecoder::kDecoderArbitrary || | |
| 122 !CodecSupported(codec_type)) { | |
| 123 return kCodecNotSupported; | 123 return kCodecNotSupported; |
| 124 } | 124 } |
| 125 DecoderInfo info(codec_type, name, decoder_factory_.get()); | 125 auto opt_format = acm2::RentACodec::NetEqDecoderToSdpAudioFormat(codec_type); |
| 126 if (!opt_format) { | |
| 127 return kCodecNotSupported; | |
| 128 } | |
| 129 DecoderInfo info(*opt_format, decoder_factory_); | |
| 130 info.name = name; | |
| 126 auto ret = | 131 auto ret = |
| 127 decoders_.insert(std::make_pair(rtp_payload_type, std::move(info))); | 132 decoders_.insert(std::make_pair(rtp_payload_type, std::move(info))); |
| 128 if (ret.second == false) { | 133 if (ret.second == false) { |
| 129 // Database already contains a decoder with type |rtp_payload_type|. | 134 // Database already contains a decoder with type |rtp_payload_type|. |
| 130 return kDecoderExists; | 135 return kDecoderExists; |
| 131 } | 136 } |
| 132 return kOK; | 137 return kOK; |
| 133 } | 138 } |
| 134 | 139 |
| 135 int DecoderDatabase::InsertExternal(uint8_t rtp_payload_type, | 140 int DecoderDatabase::InsertExternal(uint8_t rtp_payload_type, |
| 136 NetEqDecoder codec_type, | 141 NetEqDecoder codec_type, |
| 137 const std::string& codec_name, | 142 const std::string& codec_name, |
| 138 AudioDecoder* decoder) { | 143 AudioDecoder* decoder) { |
| 139 if (rtp_payload_type > 0x7F) { | 144 if (rtp_payload_type > 0x7F) { |
| 140 return kInvalidRtpPayloadType; | 145 return kInvalidRtpPayloadType; |
| 141 } | 146 } |
| 142 if (!CodecSupported(codec_type)) { | |
| 143 return kCodecNotSupported; | |
| 144 } | |
| 145 if (!decoder) { | 147 if (!decoder) { |
| 146 return kInvalidPointer; | 148 return kInvalidPointer; |
| 147 } | 149 } |
| 150 | |
| 151 auto opt_db_format = | |
|
kwiberg-webrtc
2016/09/20 16:05:43
const
ossu
2016/09/21 09:10:55
Acknowledged.
| |
| 152 acm2::RentACodec::NetEqDecoderToSdpAudioFormat(codec_type); | |
| 153 SdpAudioFormat format = opt_db_format.value_or({"arbitrary", 0, 0}); | |
|
kwiberg-webrtc
2016/09/20 16:05:43
const
ossu
2016/09/21 09:10:55
Acknowledged.
| |
| 154 | |
| 148 std::pair<DecoderMap::iterator, bool> ret; | 155 std::pair<DecoderMap::iterator, bool> ret; |
| 149 DecoderInfo info(codec_type, codec_name, decoder); | 156 DecoderInfo info(format, decoder); |
| 157 info.name = codec_name; | |
| 150 ret = decoders_.insert(std::make_pair(rtp_payload_type, std::move(info))); | 158 ret = decoders_.insert(std::make_pair(rtp_payload_type, std::move(info))); |
| 151 if (ret.second == false) { | 159 if (ret.second == false) { |
| 152 // Database already contains a decoder with type |rtp_payload_type|. | 160 // Database already contains a decoder with type |rtp_payload_type|. |
| 153 return kDecoderExists; | 161 return kDecoderExists; |
| 154 } | 162 } |
| 155 return kOK; | 163 return kOK; |
| 156 } | 164 } |
| 157 | 165 |
| 158 int DecoderDatabase::Remove(uint8_t rtp_payload_type) { | 166 int DecoderDatabase::Remove(uint8_t rtp_payload_type) { |
| 159 if (decoders_.erase(rtp_payload_type) == 0) { | 167 if (decoders_.erase(rtp_payload_type) == 0) { |
| 160 // No decoder with that |rtp_payload_type|. | 168 // No decoder with that |rtp_payload_type|. |
| 161 return kDecoderNotFound; | 169 return kDecoderNotFound; |
| 162 } | 170 } |
| 163 if (active_decoder_type_ == rtp_payload_type) { | 171 if (active_decoder_type_ == rtp_payload_type) { |
| 164 active_decoder_type_ = -1; // No active decoder. | 172 active_decoder_type_ = -1; // No active decoder. |
| 165 } | 173 } |
| 166 if (active_cng_decoder_type_ == rtp_payload_type) { | 174 if (active_cng_decoder_type_ == rtp_payload_type) { |
| 167 active_cng_decoder_type_ = -1; // No active CNG decoder. | 175 active_cng_decoder_type_ = -1; // No active CNG decoder. |
| 168 } | 176 } |
| 169 return kOK; | 177 return kOK; |
| 170 } | 178 } |
| 171 | 179 |
| 172 const DecoderDatabase::DecoderInfo* DecoderDatabase::GetDecoderInfo( | 180 const DecoderDatabase::DecoderInfo* DecoderDatabase::GetDecoderInfo( |
| 173 uint8_t rtp_payload_type) const { | 181 uint8_t rtp_payload_type) const { |
| 174 DecoderMap::const_iterator it = decoders_.find(rtp_payload_type); | 182 DecoderMap::const_iterator it = decoders_.find(rtp_payload_type); |
| 175 if (it == decoders_.end()) { | 183 if (it == decoders_.end()) { |
| 176 // Decoder not found. | 184 // Decoder not found. |
| 177 return NULL; | 185 return NULL; |
| 178 } | 186 } |
| 179 return &(*it).second; | 187 return &it->second; |
| 180 } | |
| 181 | |
| 182 uint8_t DecoderDatabase::GetRtpPayloadType( | |
| 183 NetEqDecoder codec_type) const { | |
| 184 DecoderMap::const_iterator it; | |
| 185 for (it = decoders_.begin(); it != decoders_.end(); ++it) { | |
| 186 if ((*it).second.codec_type == codec_type) { | |
| 187 // Match found. | |
| 188 return (*it).first; | |
| 189 } | |
| 190 } | |
| 191 // No match. | |
| 192 return kRtpPayloadTypeError; | |
| 193 } | 188 } |
| 194 | 189 |
| 195 int DecoderDatabase::SetActiveDecoder(uint8_t rtp_payload_type, | 190 int DecoderDatabase::SetActiveDecoder(uint8_t rtp_payload_type, |
| 196 bool* new_decoder) { | 191 bool* new_decoder) { |
| 197 // Check that |rtp_payload_type| exists in the database. | 192 // Check that |rtp_payload_type| exists in the database. |
| 198 const DecoderInfo *info = GetDecoderInfo(rtp_payload_type); | 193 const DecoderInfo *info = GetDecoderInfo(rtp_payload_type); |
| 199 if (!info) { | 194 if (!info) { |
| 200 // Decoder not found. | 195 // Decoder not found. |
| 201 return kDecoderNotFound; | 196 return kDecoderNotFound; |
| 202 } | 197 } |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 251 active_cng_decoder_.reset(new ComfortNoiseDecoder); | 246 active_cng_decoder_.reset(new ComfortNoiseDecoder); |
| 252 } | 247 } |
| 253 return active_cng_decoder_.get(); | 248 return active_cng_decoder_.get(); |
| 254 } | 249 } |
| 255 | 250 |
| 256 AudioDecoder* DecoderDatabase::GetDecoder(uint8_t rtp_payload_type) const { | 251 AudioDecoder* DecoderDatabase::GetDecoder(uint8_t rtp_payload_type) const { |
| 257 const DecoderInfo *info = GetDecoderInfo(rtp_payload_type); | 252 const DecoderInfo *info = GetDecoderInfo(rtp_payload_type); |
| 258 return info ? info->GetDecoder() : nullptr; | 253 return info ? info->GetDecoder() : nullptr; |
| 259 } | 254 } |
| 260 | 255 |
| 256 bool DecoderDatabase::IsType(uint8_t rtp_payload_type, const char* name) const { | |
| 257 const DecoderInfo* info = GetDecoderInfo(rtp_payload_type); | |
| 258 return info && info->IsType(name); | |
| 259 } | |
| 260 | |
| 261 bool DecoderDatabase::IsType(uint8_t rtp_payload_type, | 261 bool DecoderDatabase::IsType(uint8_t rtp_payload_type, |
| 262 NetEqDecoder codec_type) const { | 262 const std::string& name) const { |
| 263 const DecoderInfo *info = GetDecoderInfo(rtp_payload_type); | 263 return IsType(rtp_payload_type, name.c_str()); |
| 264 return info && info->codec_type == codec_type; | |
| 265 } | 264 } |
| 266 | 265 |
| 267 bool DecoderDatabase::IsComfortNoise(uint8_t rtp_payload_type) const { | 266 bool DecoderDatabase::IsComfortNoise(uint8_t rtp_payload_type) const { |
| 268 const DecoderInfo *info = GetDecoderInfo(rtp_payload_type); | 267 const DecoderInfo *info = GetDecoderInfo(rtp_payload_type); |
| 269 return info && info->IsComfortNoise(); | 268 return info && info->IsComfortNoise(); |
| 270 } | 269 } |
| 271 | 270 |
| 272 bool DecoderDatabase::IsDtmf(uint8_t rtp_payload_type) const { | 271 bool DecoderDatabase::IsDtmf(uint8_t rtp_payload_type) const { |
| 273 const DecoderInfo *info = GetDecoderInfo(rtp_payload_type); | 272 const DecoderInfo *info = GetDecoderInfo(rtp_payload_type); |
| 274 return info && info->IsDtmf(); | 273 return info && info->IsDtmf(); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 285 if (!GetDecoderInfo((*it)->header.payloadType)) { | 284 if (!GetDecoderInfo((*it)->header.payloadType)) { |
| 286 // Payload type is not found. | 285 // Payload type is not found. |
| 287 LOG(LS_WARNING) << "CheckPayloadTypes: unknown RTP payload type " | 286 LOG(LS_WARNING) << "CheckPayloadTypes: unknown RTP payload type " |
| 288 << static_cast<int>((*it)->header.payloadType); | 287 << static_cast<int>((*it)->header.payloadType); |
| 289 return kDecoderNotFound; | 288 return kDecoderNotFound; |
| 290 } | 289 } |
| 291 } | 290 } |
| 292 return kOK; | 291 return kOK; |
| 293 } | 292 } |
| 294 | 293 |
| 295 | |
| 296 } // namespace webrtc | 294 } // namespace webrtc |
| OLD | NEW |