AcmReceiver: Look up last decoder in NetEq's table of decoders
AcmReceiver::decoders_ is now one step closer to being unused. BUG=webrtc:5801 Review-Url: https://codereview.webrtc.org/2339953002 Cr-Commit-Position: refs/heads/master@{#14274}
This commit is contained in:
@ -32,23 +32,8 @@ namespace webrtc {
|
|||||||
|
|
||||||
namespace acm2 {
|
namespace acm2 {
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
// Is the given codec a CNG codec?
|
|
||||||
// TODO(kwiberg): Move to RentACodec.
|
|
||||||
bool IsCng(int codec_id) {
|
|
||||||
auto i = RentACodec::CodecIdFromIndex(codec_id);
|
|
||||||
return (i && (*i == RentACodec::CodecId::kCNNB ||
|
|
||||||
*i == RentACodec::CodecId::kCNWB ||
|
|
||||||
*i == RentACodec::CodecId::kCNSWB ||
|
|
||||||
*i == RentACodec::CodecId::kCNFB));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
AcmReceiver::AcmReceiver(const AudioCodingModule::Config& config)
|
AcmReceiver::AcmReceiver(const AudioCodingModule::Config& config)
|
||||||
: last_audio_decoder_(nullptr),
|
: last_audio_buffer_(new int16_t[AudioFrame::kMaxDataSizeSamples]),
|
||||||
last_audio_buffer_(new int16_t[AudioFrame::kMaxDataSizeSamples]),
|
|
||||||
neteq_(NetEq::Create(config.neteq_config, config.decoder_factory)),
|
neteq_(NetEq::Create(config.neteq_config, config.decoder_factory)),
|
||||||
clock_(config.clock),
|
clock_(config.clock),
|
||||||
resampled_last_output_frame_(true) {
|
resampled_last_output_frame_(true) {
|
||||||
@ -95,29 +80,25 @@ int AcmReceiver::InsertPacket(const WebRtcRTPHeader& rtp_header,
|
|||||||
{
|
{
|
||||||
rtc::CritScope lock(&crit_sect_);
|
rtc::CritScope lock(&crit_sect_);
|
||||||
|
|
||||||
const Decoder* decoder = RtpHeaderToDecoder(*header, incoming_payload[0]);
|
const rtc::Optional<CodecInst> ci =
|
||||||
if (!decoder) {
|
RtpHeaderToDecoder(*header, incoming_payload[0]);
|
||||||
|
if (!ci) {
|
||||||
LOG_F(LS_ERROR) << "Payload-type "
|
LOG_F(LS_ERROR) << "Payload-type "
|
||||||
<< static_cast<int>(header->payloadType)
|
<< static_cast<int>(header->payloadType)
|
||||||
<< " is not registered.";
|
<< " is not registered.";
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
const int sample_rate_hz = [&decoder] {
|
receive_timestamp = NowInTimestamp(ci->plfreq);
|
||||||
const auto ci = RentACodec::CodecIdFromIndex(decoder->acm_codec_id);
|
|
||||||
return ci ? RentACodec::CodecInstById(*ci)->plfreq : -1;
|
|
||||||
}();
|
|
||||||
receive_timestamp = NowInTimestamp(sample_rate_hz);
|
|
||||||
|
|
||||||
// If this is a CNG while the audio codec is not mono, skip pushing in
|
if (STR_CASE_CMP(ci->plname, "cn") == 0) {
|
||||||
// packets into NetEq.
|
if (last_audio_decoder_ && last_audio_decoder_->channels > 1) {
|
||||||
if (IsCng(decoder->acm_codec_id) && last_audio_decoder_ &&
|
// This is a CNG and the audio codec is not mono, so skip pushing in
|
||||||
last_audio_decoder_->channels > 1)
|
// packets into NetEq.
|
||||||
return 0;
|
return 0;
|
||||||
if (!IsCng(decoder->acm_codec_id) &&
|
}
|
||||||
decoder->acm_codec_id !=
|
} else {
|
||||||
*RentACodec::CodecIndexFromId(RentACodec::CodecId::kAVT)) {
|
last_audio_decoder_ = ci;
|
||||||
last_audio_decoder_ = decoder;
|
last_packet_sample_rate_hz_ = rtc::Optional<int>(ci->plfreq);
|
||||||
last_packet_sample_rate_hz_ = rtc::Optional<int>(decoder->sample_rate_hz);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // |crit_sect_| is released.
|
} // |crit_sect_| is released.
|
||||||
@ -282,7 +263,7 @@ int AcmReceiver::RemoveAllCodecs() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// No codec is registered, invalidate last audio decoder.
|
// No codec is registered, invalidate last audio decoder.
|
||||||
last_audio_decoder_ = nullptr;
|
last_audio_decoder_ = rtc::Optional<CodecInst>();
|
||||||
last_packet_sample_rate_hz_ = rtc::Optional<int>();
|
last_packet_sample_rate_hz_ = rtc::Optional<int>();
|
||||||
return ret_val;
|
return ret_val;
|
||||||
}
|
}
|
||||||
@ -297,8 +278,8 @@ int AcmReceiver::RemoveCodec(uint8_t payload_type) {
|
|||||||
LOG(LERROR) << "AcmReceiver::RemoveCodec" << static_cast<int>(payload_type);
|
LOG(LERROR) << "AcmReceiver::RemoveCodec" << static_cast<int>(payload_type);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (last_audio_decoder_ == &it->second) {
|
if (last_audio_decoder_ && payload_type == last_audio_decoder_->pltype) {
|
||||||
last_audio_decoder_ = nullptr;
|
last_audio_decoder_ = rtc::Optional<CodecInst>();
|
||||||
last_packet_sample_rate_hz_ = rtc::Optional<int>();
|
last_packet_sample_rate_hz_ = rtc::Optional<int>();
|
||||||
}
|
}
|
||||||
decoders_.erase(it);
|
decoders_.erase(it);
|
||||||
@ -318,11 +299,7 @@ int AcmReceiver::LastAudioCodec(CodecInst* codec) const {
|
|||||||
if (!last_audio_decoder_) {
|
if (!last_audio_decoder_) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
*codec = *RentACodec::CodecInstById(
|
*codec = *last_audio_decoder_;
|
||||||
*RentACodec::CodecIdFromIndex(last_audio_decoder_->acm_codec_id));
|
|
||||||
codec->pltype = last_audio_decoder_->payload_type;
|
|
||||||
codec->channels = last_audio_decoder_->channels;
|
|
||||||
codec->plfreq = last_audio_decoder_->sample_rate_hz;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,20 +363,17 @@ void AcmReceiver::ResetInitialDelay() {
|
|||||||
// TODO(turajs): Should NetEq Buffer be flushed?
|
// TODO(turajs): Should NetEq Buffer be flushed?
|
||||||
}
|
}
|
||||||
|
|
||||||
const AcmReceiver::Decoder* AcmReceiver::RtpHeaderToDecoder(
|
const rtc::Optional<CodecInst> AcmReceiver::RtpHeaderToDecoder(
|
||||||
const RTPHeader& rtp_header,
|
const RTPHeader& rtp_header,
|
||||||
uint8_t payload_type) const {
|
uint8_t payload_type) const {
|
||||||
auto it = decoders_.find(rtp_header.payloadType);
|
const rtc::Optional<CodecInst> ci =
|
||||||
const auto red_index =
|
neteq_->GetDecoder(rtp_header.payloadType);
|
||||||
RentACodec::CodecIndexFromId(RentACodec::CodecId::kRED);
|
if (ci && STR_CASE_CMP(ci->plname, "red") == 0) {
|
||||||
if (red_index && // This ensures that RED is defined in WebRTC.
|
// This is a RED packet. Get the payload of the audio codec.
|
||||||
it != decoders_.end() && it->second.acm_codec_id == *red_index) {
|
return neteq_->GetDecoder(payload_type & 0x7f);
|
||||||
// This is a RED packet, get the payload of the audio codec.
|
} else {
|
||||||
it = decoders_.find(payload_type & 0x7F);
|
return ci;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the payload is registered.
|
|
||||||
return it != decoders_.end() ? &it->second : nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t AcmReceiver::NowInTimestamp(int decoder_sampling_rate) const {
|
uint32_t AcmReceiver::NowInTimestamp(int decoder_sampling_rate) const {
|
||||||
|
|||||||
@ -39,15 +39,6 @@ namespace acm2 {
|
|||||||
|
|
||||||
class AcmReceiver {
|
class AcmReceiver {
|
||||||
public:
|
public:
|
||||||
struct Decoder {
|
|
||||||
int acm_codec_id;
|
|
||||||
uint8_t payload_type;
|
|
||||||
// This field is meaningful for codecs where both mono and
|
|
||||||
// stereo versions are registered under the same ID.
|
|
||||||
size_t channels;
|
|
||||||
int sample_rate_hz;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Constructor of the class
|
// Constructor of the class
|
||||||
explicit AcmReceiver(const AudioCodingModule::Config& config);
|
explicit AcmReceiver(const AudioCodingModule::Config& config);
|
||||||
|
|
||||||
@ -262,14 +253,23 @@ class AcmReceiver {
|
|||||||
void GetDecodingCallStatistics(AudioDecodingCallStats* stats) const;
|
void GetDecodingCallStatistics(AudioDecodingCallStats* stats) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const Decoder* RtpHeaderToDecoder(const RTPHeader& rtp_header,
|
struct Decoder {
|
||||||
uint8_t payload_type) const
|
int acm_codec_id;
|
||||||
|
uint8_t payload_type;
|
||||||
|
// This field is meaningful for codecs where both mono and
|
||||||
|
// stereo versions are registered under the same ID.
|
||||||
|
size_t channels;
|
||||||
|
int sample_rate_hz;
|
||||||
|
};
|
||||||
|
|
||||||
|
const rtc::Optional<CodecInst> RtpHeaderToDecoder(const RTPHeader& rtp_header,
|
||||||
|
uint8_t payload_type) const
|
||||||
EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
|
EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
|
||||||
|
|
||||||
uint32_t NowInTimestamp(int decoder_sampling_rate) const;
|
uint32_t NowInTimestamp(int decoder_sampling_rate) const;
|
||||||
|
|
||||||
rtc::CriticalSection crit_sect_;
|
rtc::CriticalSection crit_sect_;
|
||||||
const Decoder* last_audio_decoder_ GUARDED_BY(crit_sect_);
|
rtc::Optional<CodecInst> last_audio_decoder_ GUARDED_BY(crit_sect_);
|
||||||
ACMResampler resampler_ GUARDED_BY(crit_sect_);
|
ACMResampler resampler_ GUARDED_BY(crit_sect_);
|
||||||
std::unique_ptr<int16_t[]> last_audio_buffer_ GUARDED_BY(crit_sect_);
|
std::unique_ptr<int16_t[]> last_audio_buffer_ GUARDED_BY(crit_sect_);
|
||||||
CallStatistics call_stats_ GUARDED_BY(crit_sect_);
|
CallStatistics call_stats_ GUARDED_BY(crit_sect_);
|
||||||
|
|||||||
@ -119,9 +119,9 @@ class AcmReceiverTestOldApi : public AudioPacketizationCallback,
|
|||||||
for (auto id : ids) {
|
for (auto id : ids) {
|
||||||
const auto i = RentACodec::CodecIndexFromId(id);
|
const auto i = RentACodec::CodecIndexFromId(id);
|
||||||
ASSERT_TRUE(i);
|
ASSERT_TRUE(i);
|
||||||
ASSERT_EQ(
|
ASSERT_EQ(0, receiver_->AddCodec(*i, codecs_[*i].pltype,
|
||||||
0, receiver_->AddCodec(*i, codecs_[*i].pltype, codecs_[*i].channels,
|
codecs_[*i].channels, codecs_[*i].plfreq,
|
||||||
codecs_[*i].plfreq, nullptr, ""));
|
nullptr, codecs_[*i].plname));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -252,6 +252,8 @@ class NetEq {
|
|||||||
// (Config::sample_rate_hz) is returned.
|
// (Config::sample_rate_hz) is returned.
|
||||||
virtual int last_output_sample_rate_hz() const = 0;
|
virtual int last_output_sample_rate_hz() const = 0;
|
||||||
|
|
||||||
|
virtual rtc::Optional<CodecInst> GetDecoder(int payload_type) const = 0;
|
||||||
|
|
||||||
// Not implemented.
|
// Not implemented.
|
||||||
virtual int SetTargetNumberOfChannels() = 0;
|
virtual int SetTargetNumberOfChannels() = 0;
|
||||||
|
|
||||||
|
|||||||
@ -431,6 +431,27 @@ int NetEqImpl::last_output_sample_rate_hz() const {
|
|||||||
return last_output_sample_rate_hz_;
|
return last_output_sample_rate_hz_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rtc::Optional<CodecInst> NetEqImpl::GetDecoder(int payload_type) const {
|
||||||
|
rtc::CritScope lock(&crit_sect_);
|
||||||
|
const DecoderDatabase::DecoderInfo* di =
|
||||||
|
decoder_database_->GetDecoderInfo(payload_type);
|
||||||
|
if (!di) {
|
||||||
|
return rtc::Optional<CodecInst>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a CodecInst with some fields set. The remaining fields are zeroed,
|
||||||
|
// but we tell MSan to consider them uninitialized.
|
||||||
|
CodecInst ci = {0};
|
||||||
|
rtc::MsanMarkUninitialized(rtc::MakeArrayView(&ci, 1));
|
||||||
|
ci.pltype = payload_type;
|
||||||
|
std::strncpy(ci.plname, di->name.c_str(), sizeof(ci.plname));
|
||||||
|
ci.plname[sizeof(ci.plname) - 1] = '\0';
|
||||||
|
ci.plfreq = di->IsRed() || di->IsDtmf() ? 8000 : di->SampleRateHz();
|
||||||
|
AudioDecoder* const decoder = di->GetDecoder();
|
||||||
|
ci.channels = decoder ? decoder->Channels() : 1;
|
||||||
|
return rtc::Optional<CodecInst>(ci);
|
||||||
|
}
|
||||||
|
|
||||||
int NetEqImpl::SetTargetNumberOfChannels() {
|
int NetEqImpl::SetTargetNumberOfChannels() {
|
||||||
return kNotImplemented;
|
return kNotImplemented;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -169,6 +169,8 @@ class NetEqImpl : public webrtc::NetEq {
|
|||||||
|
|
||||||
int last_output_sample_rate_hz() const override;
|
int last_output_sample_rate_hz() const override;
|
||||||
|
|
||||||
|
rtc::Optional<CodecInst> GetDecoder(int payload_type) const override;
|
||||||
|
|
||||||
int SetTargetNumberOfChannels() override;
|
int SetTargetNumberOfChannels() override;
|
||||||
|
|
||||||
int SetTargetSampleRate() override;
|
int SetTargetSampleRate() override;
|
||||||
|
|||||||
Reference in New Issue
Block a user