NetEq: Add new method last_output_sample_rate_hz
This change moves the logics for keeping track of the last ouput sample rate from AcmReceiver to NetEq, where it fits better. The getter function AcmReceiver::current_sample_rate_hz() is renamed to last_output_sample_rate_hz(). BUG=webrtc:3520 Review URL: https://codereview.webrtc.org/1467163002 Cr-Commit-Position: refs/heads/master@{#10754}
This commit is contained in:

committed by
Commit bot

parent
dfafd12418
commit
d89814bfd7
@ -123,7 +123,6 @@ AcmReceiver::AcmReceiver(const AudioCodingModule::Config& config)
|
|||||||
id_(config.id),
|
id_(config.id),
|
||||||
last_audio_decoder_(nullptr),
|
last_audio_decoder_(nullptr),
|
||||||
previous_audio_activity_(AudioFrame::kVadPassive),
|
previous_audio_activity_(AudioFrame::kVadPassive),
|
||||||
current_sample_rate_hz_(config.neteq_config.sample_rate_hz),
|
|
||||||
audio_buffer_(new int16_t[AudioFrame::kMaxDataSizeSamples]),
|
audio_buffer_(new int16_t[AudioFrame::kMaxDataSizeSamples]),
|
||||||
last_audio_buffer_(new int16_t[AudioFrame::kMaxDataSizeSamples]),
|
last_audio_buffer_(new int16_t[AudioFrame::kMaxDataSizeSamples]),
|
||||||
neteq_(NetEq::Create(config.neteq_config)),
|
neteq_(NetEq::Create(config.neteq_config)),
|
||||||
@ -157,9 +156,8 @@ int AcmReceiver::LeastRequiredDelayMs() const {
|
|||||||
return neteq_->LeastRequiredDelayMs();
|
return neteq_->LeastRequiredDelayMs();
|
||||||
}
|
}
|
||||||
|
|
||||||
int AcmReceiver::current_sample_rate_hz() const {
|
int AcmReceiver::last_output_sample_rate_hz() const {
|
||||||
CriticalSectionScoped lock(crit_sect_.get());
|
return neteq_->last_output_sample_rate_hz();
|
||||||
return current_sample_rate_hz_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int AcmReceiver::InsertPacket(const WebRtcRTPHeader& rtp_header,
|
int AcmReceiver::InsertPacket(const WebRtcRTPHeader& rtp_header,
|
||||||
@ -224,23 +222,18 @@ int AcmReceiver::GetAudio(int desired_freq_hz, AudioFrame* audio_frame) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NetEq always returns 10 ms of audio.
|
const int current_sample_rate_hz = neteq_->last_output_sample_rate_hz();
|
||||||
current_sample_rate_hz_ = static_cast<int>(samples_per_channel * 100);
|
|
||||||
|
|
||||||
// Update if resampling is required.
|
// Update if resampling is required.
|
||||||
bool need_resampling = (desired_freq_hz != -1) &&
|
const bool need_resampling =
|
||||||
(current_sample_rate_hz_ != desired_freq_hz);
|
(desired_freq_hz != -1) && (current_sample_rate_hz != desired_freq_hz);
|
||||||
|
|
||||||
if (need_resampling && !resampled_last_output_frame_) {
|
if (need_resampling && !resampled_last_output_frame_) {
|
||||||
// Prime the resampler with the last frame.
|
// Prime the resampler with the last frame.
|
||||||
int16_t temp_output[AudioFrame::kMaxDataSizeSamples];
|
int16_t temp_output[AudioFrame::kMaxDataSizeSamples];
|
||||||
int samples_per_channel_int =
|
int samples_per_channel_int = resampler_.Resample10Msec(
|
||||||
resampler_.Resample10Msec(last_audio_buffer_.get(),
|
last_audio_buffer_.get(), current_sample_rate_hz, desired_freq_hz,
|
||||||
current_sample_rate_hz_,
|
num_channels, AudioFrame::kMaxDataSizeSamples, temp_output);
|
||||||
desired_freq_hz,
|
|
||||||
num_channels,
|
|
||||||
AudioFrame::kMaxDataSizeSamples,
|
|
||||||
temp_output);
|
|
||||||
if (samples_per_channel_int < 0) {
|
if (samples_per_channel_int < 0) {
|
||||||
LOG(LERROR) << "AcmReceiver::GetAudio - "
|
LOG(LERROR) << "AcmReceiver::GetAudio - "
|
||||||
"Resampling last_audio_buffer_ failed.";
|
"Resampling last_audio_buffer_ failed.";
|
||||||
@ -254,13 +247,9 @@ int AcmReceiver::GetAudio(int desired_freq_hz, AudioFrame* audio_frame) {
|
|||||||
// TODO(henrik.lundin) Glitches in the output may appear if the output rate
|
// TODO(henrik.lundin) Glitches in the output may appear if the output rate
|
||||||
// from NetEq changes. See WebRTC issue 3923.
|
// from NetEq changes. See WebRTC issue 3923.
|
||||||
if (need_resampling) {
|
if (need_resampling) {
|
||||||
int samples_per_channel_int =
|
int samples_per_channel_int = resampler_.Resample10Msec(
|
||||||
resampler_.Resample10Msec(audio_buffer_.get(),
|
audio_buffer_.get(), current_sample_rate_hz, desired_freq_hz,
|
||||||
current_sample_rate_hz_,
|
num_channels, AudioFrame::kMaxDataSizeSamples, audio_frame->data_);
|
||||||
desired_freq_hz,
|
|
||||||
num_channels,
|
|
||||||
AudioFrame::kMaxDataSizeSamples,
|
|
||||||
audio_frame->data_);
|
|
||||||
if (samples_per_channel_int < 0) {
|
if (samples_per_channel_int < 0) {
|
||||||
LOG(LERROR) << "AcmReceiver::GetAudio - Resampling audio_buffer_ failed.";
|
LOG(LERROR) << "AcmReceiver::GetAudio - Resampling audio_buffer_ failed.";
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -154,12 +154,8 @@ class AcmReceiver {
|
|||||||
//
|
//
|
||||||
void ResetInitialDelay();
|
void ResetInitialDelay();
|
||||||
|
|
||||||
//
|
// Returns last_output_sample_rate_hz from the NetEq instance.
|
||||||
// Get the current sampling frequency in Hz.
|
int last_output_sample_rate_hz() const;
|
||||||
//
|
|
||||||
// Return value : Sampling frequency in Hz.
|
|
||||||
//
|
|
||||||
int current_sample_rate_hz() const;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Get the current network statistics from NetEq.
|
// Get the current network statistics from NetEq.
|
||||||
@ -287,7 +283,6 @@ class AcmReceiver {
|
|||||||
int id_; // TODO(henrik.lundin) Make const.
|
int id_; // TODO(henrik.lundin) Make const.
|
||||||
const Decoder* last_audio_decoder_ GUARDED_BY(crit_sect_);
|
const Decoder* last_audio_decoder_ GUARDED_BY(crit_sect_);
|
||||||
AudioFrame::VADActivity previous_audio_activity_ GUARDED_BY(crit_sect_);
|
AudioFrame::VADActivity previous_audio_activity_ GUARDED_BY(crit_sect_);
|
||||||
int current_sample_rate_hz_ GUARDED_BY(crit_sect_);
|
|
||||||
ACMResampler resampler_ GUARDED_BY(crit_sect_);
|
ACMResampler resampler_ GUARDED_BY(crit_sect_);
|
||||||
// Used in GetAudio, declared as member to avoid allocating every 10ms.
|
// Used in GetAudio, declared as member to avoid allocating every 10ms.
|
||||||
// TODO(henrik.lundin) Stack-allocate in GetAudio instead?
|
// TODO(henrik.lundin) Stack-allocate in GetAudio instead?
|
||||||
|
@ -261,8 +261,7 @@ TEST_F(AcmReceiverTestOldApi, DISABLED_ON_ANDROID(SampleRate)) {
|
|||||||
for (int k = 0; k < num_10ms_frames; ++k) {
|
for (int k = 0; k < num_10ms_frames; ++k) {
|
||||||
EXPECT_EQ(0, receiver_->GetAudio(kOutSampleRateHz, &frame));
|
EXPECT_EQ(0, receiver_->GetAudio(kOutSampleRateHz, &frame));
|
||||||
}
|
}
|
||||||
EXPECT_EQ(std::min(32000, codec.inst.plfreq),
|
EXPECT_EQ(codec.inst.plfreq, receiver_->last_output_sample_rate_hz());
|
||||||
receiver_->current_sample_rate_hz());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -532,17 +532,14 @@ int AudioCodingModuleImpl::ReceiveFrequency() const {
|
|||||||
|
|
||||||
auto codec_id = RentACodec::CodecIdFromIndex(receiver_.last_audio_codec_id());
|
auto codec_id = RentACodec::CodecIdFromIndex(receiver_.last_audio_codec_id());
|
||||||
return codec_id ? RentACodec::CodecInstById(*codec_id)->plfreq
|
return codec_id ? RentACodec::CodecInstById(*codec_id)->plfreq
|
||||||
: receiver_.current_sample_rate_hz();
|
: receiver_.last_output_sample_rate_hz();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get current playout frequency.
|
// Get current playout frequency.
|
||||||
int AudioCodingModuleImpl::PlayoutFrequency() const {
|
int AudioCodingModuleImpl::PlayoutFrequency() const {
|
||||||
WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, id_,
|
WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, id_,
|
||||||
"PlayoutFrequency()");
|
"PlayoutFrequency()");
|
||||||
|
return receiver_.last_output_sample_rate_hz();
|
||||||
CriticalSectionScoped lock(acm_crit_sect_.get());
|
|
||||||
|
|
||||||
return receiver_.current_sample_rate_hz();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register possible receive codecs, can be called multiple times,
|
// Register possible receive codecs, can be called multiple times,
|
||||||
|
@ -251,6 +251,11 @@ class NetEq {
|
|||||||
// Returns true if the RTP timestamp is valid, otherwise false.
|
// Returns true if the RTP timestamp is valid, otherwise false.
|
||||||
virtual bool GetPlayoutTimestamp(uint32_t* timestamp) = 0;
|
virtual bool GetPlayoutTimestamp(uint32_t* timestamp) = 0;
|
||||||
|
|
||||||
|
// Returns the sample rate in Hz of the audio produced in the last GetAudio
|
||||||
|
// call. If GetAudio has not been called yet, the configured sample rate
|
||||||
|
// (Config::sample_rate_hz) is returned.
|
||||||
|
virtual int last_output_sample_rate_hz() const = 0;
|
||||||
|
|
||||||
// Not implemented.
|
// Not implemented.
|
||||||
virtual int SetTargetNumberOfChannels() = 0;
|
virtual int SetTargetNumberOfChannels() = 0;
|
||||||
|
|
||||||
|
@ -106,6 +106,7 @@ NetEqImpl::NetEqImpl(const NetEq::Config& config,
|
|||||||
}
|
}
|
||||||
fs_hz_ = fs;
|
fs_hz_ = fs;
|
||||||
fs_mult_ = fs / 8000;
|
fs_mult_ = fs / 8000;
|
||||||
|
last_output_sample_rate_hz_ = fs;
|
||||||
output_size_samples_ = static_cast<size_t>(kOutputSizeMs * 8 * fs_mult_);
|
output_size_samples_ = static_cast<size_t>(kOutputSizeMs * 8 * fs_mult_);
|
||||||
decoder_frame_length_ = 3 * output_size_samples_;
|
decoder_frame_length_ = 3 * output_size_samples_;
|
||||||
WebRtcSpl_Init();
|
WebRtcSpl_Init();
|
||||||
@ -160,6 +161,13 @@ int NetEqImpl::GetAudio(size_t max_length, int16_t* output_audio,
|
|||||||
if (type) {
|
if (type) {
|
||||||
*type = LastOutputType();
|
*type = LastOutputType();
|
||||||
}
|
}
|
||||||
|
last_output_sample_rate_hz_ =
|
||||||
|
rtc::checked_cast<int>(*samples_per_channel * 100);
|
||||||
|
RTC_DCHECK(last_output_sample_rate_hz_ == 8000 ||
|
||||||
|
last_output_sample_rate_hz_ == 16000 ||
|
||||||
|
last_output_sample_rate_hz_ == 32000 ||
|
||||||
|
last_output_sample_rate_hz_ == 48000)
|
||||||
|
<< "Unexpected sample rate " << last_output_sample_rate_hz_;
|
||||||
return kOK;
|
return kOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -359,6 +367,11 @@ bool NetEqImpl::GetPlayoutTimestamp(uint32_t* timestamp) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int NetEqImpl::last_output_sample_rate_hz() const {
|
||||||
|
CriticalSectionScoped lock(crit_sect_.get());
|
||||||
|
return last_output_sample_rate_hz_;
|
||||||
|
}
|
||||||
|
|
||||||
int NetEqImpl::SetTargetNumberOfChannels() {
|
int NetEqImpl::SetTargetNumberOfChannels() {
|
||||||
return kNotImplemented;
|
return kNotImplemented;
|
||||||
}
|
}
|
||||||
|
@ -168,6 +168,8 @@ class NetEqImpl : public webrtc::NetEq {
|
|||||||
|
|
||||||
bool GetPlayoutTimestamp(uint32_t* timestamp) override;
|
bool GetPlayoutTimestamp(uint32_t* timestamp) override;
|
||||||
|
|
||||||
|
int last_output_sample_rate_hz() const override;
|
||||||
|
|
||||||
int SetTargetNumberOfChannels() override;
|
int SetTargetNumberOfChannels() override;
|
||||||
|
|
||||||
int SetTargetSampleRate() override;
|
int SetTargetSampleRate() override;
|
||||||
@ -375,6 +377,7 @@ class NetEqImpl : public webrtc::NetEq {
|
|||||||
StatisticsCalculator stats_ GUARDED_BY(crit_sect_);
|
StatisticsCalculator stats_ GUARDED_BY(crit_sect_);
|
||||||
int fs_hz_ GUARDED_BY(crit_sect_);
|
int fs_hz_ GUARDED_BY(crit_sect_);
|
||||||
int fs_mult_ GUARDED_BY(crit_sect_);
|
int fs_mult_ GUARDED_BY(crit_sect_);
|
||||||
|
int last_output_sample_rate_hz_ GUARDED_BY(crit_sect_);
|
||||||
size_t output_size_samples_ GUARDED_BY(crit_sect_);
|
size_t output_size_samples_ GUARDED_BY(crit_sect_);
|
||||||
size_t decoder_frame_length_ GUARDED_BY(crit_sect_);
|
size_t decoder_frame_length_ GUARDED_BY(crit_sect_);
|
||||||
Modes last_mode_ GUARDED_BY(crit_sect_);
|
Modes last_mode_ GUARDED_BY(crit_sect_);
|
||||||
|
@ -1230,4 +1230,13 @@ TEST_F(NetEqImplTest, DecodingErrorDuringInternalCng) {
|
|||||||
EXPECT_CALL(mock_decoder, Die());
|
EXPECT_CALL(mock_decoder, Die());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tests that the return value from last_output_sample_rate_hz() is equal to the
|
||||||
|
// configured inital sample rate.
|
||||||
|
TEST_F(NetEqImplTest, InitialLastOutputSampleRate) {
|
||||||
|
UseNoMocks();
|
||||||
|
config_.sample_rate_hz = 48000;
|
||||||
|
CreateInstance();
|
||||||
|
EXPECT_EQ(48000, neteq_->last_output_sample_rate_hz());
|
||||||
|
}
|
||||||
|
|
||||||
}// namespace webrtc
|
}// namespace webrtc
|
||||||
|
@ -362,6 +362,7 @@ void NetEqDecodingTest::Process(size_t* out_len) {
|
|||||||
(*out_len == kBlockSize16kHz) ||
|
(*out_len == kBlockSize16kHz) ||
|
||||||
(*out_len == kBlockSize32kHz));
|
(*out_len == kBlockSize32kHz));
|
||||||
output_sample_rate_ = static_cast<int>(*out_len / 10 * 1000);
|
output_sample_rate_ = static_cast<int>(*out_len / 10 * 1000);
|
||||||
|
EXPECT_EQ(output_sample_rate_, neteq_->last_output_sample_rate_hz());
|
||||||
|
|
||||||
// Increase time.
|
// Increase time.
|
||||||
sim_clock_ += kTimeStepMs;
|
sim_clock_ += kTimeStepMs;
|
||||||
@ -895,6 +896,8 @@ TEST_F(NetEqDecodingTest, GetAudioBeforeInsertPacket) {
|
|||||||
SCOPED_TRACE(ss.str()); // Print out the parameter values on failure.
|
SCOPED_TRACE(ss.str()); // Print out the parameter values on failure.
|
||||||
EXPECT_EQ(0, out_data_[i]);
|
EXPECT_EQ(0, out_data_[i]);
|
||||||
}
|
}
|
||||||
|
// Verify that the sample rate did not change from the initial configuration.
|
||||||
|
EXPECT_EQ(config_.sample_rate_hz, neteq_->last_output_sample_rate_hz());
|
||||||
}
|
}
|
||||||
|
|
||||||
class NetEqBgnTest : public NetEqDecodingTest {
|
class NetEqBgnTest : public NetEqDecodingTest {
|
||||||
|
@ -56,6 +56,7 @@ size_t NetEqExternalDecoderTest::GetOutputAudio(size_t max_length,
|
|||||||
EXPECT_EQ(channels_, num_channels);
|
EXPECT_EQ(channels_, num_channels);
|
||||||
EXPECT_EQ(static_cast<size_t>(kOutputLengthMs * sample_rate_hz_ / 1000),
|
EXPECT_EQ(static_cast<size_t>(kOutputLengthMs * sample_rate_hz_ / 1000),
|
||||||
samples_per_channel);
|
samples_per_channel);
|
||||||
|
EXPECT_EQ(sample_rate_hz_, neteq_->last_output_sample_rate_hz());
|
||||||
return samples_per_channel;
|
return samples_per_channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user