NetEq: Implement muted output
This CL implements the muted output functionality in NetEq. Tests are added. The feature is currently off by default, and AcmReceiver makes sure that the muted state is not engaged. BUG=webrtc:5608 Review-Url: https://codereview.webrtc.org/1965733002 Cr-Commit-Position: refs/heads/master@{#12711}
This commit is contained in:
committed by
Commit bot
parent
53f7adad08
commit
7a926812d8
@ -136,10 +136,12 @@ int AcmReceiver::GetAudio(int desired_freq_hz, AudioFrame* audio_frame) {
|
||||
// Accessing members, take the lock.
|
||||
rtc::CritScope lock(&crit_sect_);
|
||||
|
||||
if (neteq_->GetAudio(audio_frame) != NetEq::kOK) {
|
||||
bool muted;
|
||||
if (neteq_->GetAudio(audio_frame, &muted) != NetEq::kOK) {
|
||||
LOG(LERROR) << "AcmReceiver::GetAudio - NetEq Failed.";
|
||||
return -1;
|
||||
}
|
||||
RTC_DCHECK(!muted);
|
||||
|
||||
const int current_sample_rate_hz = neteq_->last_output_sample_rate_hz();
|
||||
|
||||
|
||||
@ -93,6 +93,7 @@ class NetEq {
|
||||
BackgroundNoiseMode background_noise_mode;
|
||||
NetEqPlayoutMode playout_mode;
|
||||
bool enable_fast_accelerate;
|
||||
bool enable_muted_state = false;
|
||||
};
|
||||
|
||||
enum ReturnCodes {
|
||||
@ -161,8 +162,12 @@ class NetEq {
|
||||
// |num_channels_|, |sample_rate_hz_|, |samples_per_channel_|, and
|
||||
// |vad_activity_| are updated upon success. If an error is returned, some
|
||||
// fields may not have been updated.
|
||||
// If muted state is enabled (through Config::enable_muted_state), |muted|
|
||||
// may be set to true after a prolonged expand period. When this happens, the
|
||||
// |data_| in |audio_frame| is not written, but should be interpreted as being
|
||||
// all zeros.
|
||||
// Returns kOK on success, or kFail in case of an error.
|
||||
virtual int GetAudio(AudioFrame* audio_frame) = 0;
|
||||
virtual int GetAudio(AudioFrame* audio_frame, bool* muted) = 0;
|
||||
|
||||
// Associates |rtp_payload_type| with |codec| and |codec_name|, and stores the
|
||||
// information in the codec database. Returns 0 on success, -1 on failure.
|
||||
|
||||
@ -26,7 +26,9 @@ std::string NetEq::Config::ToString() const {
|
||||
<< ", max_packets_in_buffer=" << max_packets_in_buffer
|
||||
<< ", background_noise_mode=" << background_noise_mode
|
||||
<< ", playout_mode=" << playout_mode
|
||||
<< ", enable_fast_accelerate=" << enable_fast_accelerate;
|
||||
<< ", enable_fast_accelerate="
|
||||
<< (enable_fast_accelerate ? " true": "false")
|
||||
<< ", enable_muted_state=" << (enable_muted_state ? " true": "false");
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
@ -189,7 +189,9 @@ class NetEqExternalVsInternalDecoderTest : public NetEqExternalDecoderUnitTest,
|
||||
|
||||
void GetAndVerifyOutput() override {
|
||||
// Get audio from internal decoder instance.
|
||||
EXPECT_EQ(NetEq::kOK, neteq_internal_->GetAudio(&output_internal_));
|
||||
bool muted;
|
||||
EXPECT_EQ(NetEq::kOK, neteq_internal_->GetAudio(&output_internal_, &muted));
|
||||
ASSERT_FALSE(muted);
|
||||
EXPECT_EQ(1u, output_internal_.num_channels_);
|
||||
EXPECT_EQ(static_cast<size_t>(kOutputLengthMs * sample_rate_hz_ / 1000),
|
||||
output_internal_.samples_per_channel_);
|
||||
|
||||
@ -108,7 +108,8 @@ NetEqImpl::NetEqImpl(const NetEq::Config& config,
|
||||
background_noise_mode_(config.background_noise_mode),
|
||||
playout_mode_(config.playout_mode),
|
||||
enable_fast_accelerate_(config.enable_fast_accelerate),
|
||||
nack_enabled_(false) {
|
||||
nack_enabled_(false),
|
||||
enable_muted_state_(config.enable_muted_state) {
|
||||
LOG(LS_INFO) << "NetEq config: " << config.ToString();
|
||||
int fs = config.sample_rate_hz;
|
||||
if (fs != 8000 && fs != 16000 && fs != 32000 && fs != 48000) {
|
||||
@ -205,10 +206,10 @@ void SetAudioFrameActivityAndType(bool vad_enabled,
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int NetEqImpl::GetAudio(AudioFrame* audio_frame) {
|
||||
int NetEqImpl::GetAudio(AudioFrame* audio_frame, bool* muted) {
|
||||
TRACE_EVENT0("webrtc", "NetEqImpl::GetAudio");
|
||||
rtc::CritScope lock(&crit_sect_);
|
||||
int error = GetAudioInternal(audio_frame);
|
||||
int error = GetAudioInternal(audio_frame, muted);
|
||||
RTC_DCHECK_EQ(
|
||||
audio_frame->sample_rate_hz_,
|
||||
rtc::checked_cast<int>(audio_frame->samples_per_channel_ * 100));
|
||||
@ -809,13 +810,31 @@ int NetEqImpl::InsertPacketInternal(const WebRtcRTPHeader& rtp_header,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NetEqImpl::GetAudioInternal(AudioFrame* audio_frame) {
|
||||
int NetEqImpl::GetAudioInternal(AudioFrame* audio_frame, bool* muted) {
|
||||
PacketList packet_list;
|
||||
DtmfEvent dtmf_event;
|
||||
Operations operation;
|
||||
bool play_dtmf;
|
||||
*muted = false;
|
||||
tick_timer_->Increment();
|
||||
stats_.IncreaseCounter(output_size_samples_, fs_hz_);
|
||||
|
||||
// Check for muted state.
|
||||
if (enable_muted_state_ && expand_->Muted() && packet_buffer_->Empty()) {
|
||||
RTC_DCHECK_EQ(last_mode_, kModeExpand);
|
||||
playout_timestamp_ += static_cast<uint32_t>(output_size_samples_);
|
||||
audio_frame->sample_rate_hz_ = fs_hz_;
|
||||
audio_frame->samples_per_channel_ = output_size_samples_;
|
||||
audio_frame->timestamp_ =
|
||||
first_packet_
|
||||
? 0
|
||||
: timestamp_scaler_->ToExternal(playout_timestamp_) -
|
||||
static_cast<uint32_t>(audio_frame->samples_per_channel_);
|
||||
audio_frame->num_channels_ = sync_buffer_->Channels();
|
||||
*muted = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int return_value = GetDecision(&operation, &packet_list, &dtmf_event,
|
||||
&play_dtmf);
|
||||
if (return_value != 0) {
|
||||
|
||||
@ -117,7 +117,7 @@ class NetEqImpl : public webrtc::NetEq {
|
||||
int InsertSyncPacket(const WebRtcRTPHeader& rtp_header,
|
||||
uint32_t receive_timestamp) override;
|
||||
|
||||
int GetAudio(AudioFrame* audio_frame) override;
|
||||
int GetAudio(AudioFrame* audio_frame, bool* muted) override;
|
||||
|
||||
int RegisterPayloadType(NetEqDecoder codec,
|
||||
const std::string& codec_name,
|
||||
@ -225,7 +225,7 @@ class NetEqImpl : public webrtc::NetEq {
|
||||
|
||||
// Delivers 10 ms of audio data. The data is written to |audio_frame|.
|
||||
// Returns 0 on success, otherwise an error code.
|
||||
int GetAudioInternal(AudioFrame* audio_frame)
|
||||
int GetAudioInternal(AudioFrame* audio_frame, bool* muted)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
|
||||
|
||||
// Provides a decision to the GetAudioInternal method. The decision what to
|
||||
@ -405,6 +405,7 @@ class NetEqImpl : public webrtc::NetEq {
|
||||
bool enable_fast_accelerate_ GUARDED_BY(crit_sect_);
|
||||
std::unique_ptr<Nack> nack_ GUARDED_BY(crit_sect_);
|
||||
bool nack_enabled_ GUARDED_BY(crit_sect_);
|
||||
const bool enable_muted_state_ GUARDED_BY(crit_sect_);
|
||||
AudioFrame::VADActivity last_vad_activity_ GUARDED_BY(crit_sect_) =
|
||||
AudioFrame::kVadPassive;
|
||||
std::unique_ptr<TickTimer::Stopwatch> generated_noise_stopwatch_
|
||||
|
||||
@ -441,7 +441,9 @@ TEST_F(NetEqImplTest, VerifyTimestampPropagation) {
|
||||
// Pull audio once.
|
||||
const size_t kMaxOutputSize = static_cast<size_t>(10 * kSampleRateHz / 1000);
|
||||
AudioFrame output;
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output));
|
||||
bool muted;
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output, &muted));
|
||||
ASSERT_FALSE(muted);
|
||||
ASSERT_EQ(kMaxOutputSize, output.samples_per_channel_);
|
||||
EXPECT_EQ(1u, output.num_channels_);
|
||||
EXPECT_EQ(AudioFrame::kNormalSpeech, output.speech_type_);
|
||||
@ -518,7 +520,8 @@ TEST_F(NetEqImplTest, ReorderedPacket) {
|
||||
// Pull audio once.
|
||||
const size_t kMaxOutputSize = static_cast<size_t>(10 * kSampleRateHz / 1000);
|
||||
AudioFrame output;
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output));
|
||||
bool muted;
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output, &muted));
|
||||
ASSERT_EQ(kMaxOutputSize, output.samples_per_channel_);
|
||||
EXPECT_EQ(1u, output.num_channels_);
|
||||
EXPECT_EQ(AudioFrame::kNormalSpeech, output.speech_type_);
|
||||
@ -546,7 +549,7 @@ TEST_F(NetEqImplTest, ReorderedPacket) {
|
||||
Return(kPayloadLengthSamples)));
|
||||
|
||||
// Pull audio once.
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output));
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output, &muted));
|
||||
ASSERT_EQ(kMaxOutputSize, output.samples_per_channel_);
|
||||
EXPECT_EQ(1u, output.num_channels_);
|
||||
EXPECT_EQ(AudioFrame::kNormalSpeech, output.speech_type_);
|
||||
@ -586,7 +589,8 @@ TEST_F(NetEqImplTest, FirstPacketUnknown) {
|
||||
// Pull audio once.
|
||||
const size_t kMaxOutputSize = static_cast<size_t>(10 * kSampleRateHz / 1000);
|
||||
AudioFrame output;
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output));
|
||||
bool muted;
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output, &muted));
|
||||
ASSERT_LE(output.samples_per_channel_, kMaxOutputSize);
|
||||
EXPECT_EQ(kMaxOutputSize, output.samples_per_channel_);
|
||||
EXPECT_EQ(1u, output.num_channels_);
|
||||
@ -607,7 +611,7 @@ TEST_F(NetEqImplTest, FirstPacketUnknown) {
|
||||
|
||||
// Pull audio repeatedly and make sure we get normal output, that is not PLC.
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output));
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output, &muted));
|
||||
ASSERT_LE(output.samples_per_channel_, kMaxOutputSize);
|
||||
EXPECT_EQ(kMaxOutputSize, output.samples_per_channel_);
|
||||
EXPECT_EQ(1u, output.num_channels_);
|
||||
@ -711,7 +715,8 @@ TEST_F(NetEqImplTest, CodecInternalCng) {
|
||||
50 * kSampleRateKhz, 10 * kSampleRateKhz
|
||||
};
|
||||
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output));
|
||||
bool muted;
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output, &muted));
|
||||
rtc::Optional<uint32_t> last_timestamp = neteq_->GetPlayoutTimestamp();
|
||||
ASSERT_TRUE(last_timestamp);
|
||||
|
||||
@ -733,7 +738,7 @@ TEST_F(NetEqImplTest, CodecInternalCng) {
|
||||
ASSERT_EQ(kMaxOutputSize, output.samples_per_channel_);
|
||||
EXPECT_EQ(1u, output.num_channels_);
|
||||
EXPECT_EQ(expected_type[i - 1], output.speech_type_);
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output));
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output, &muted));
|
||||
SCOPED_TRACE("");
|
||||
verify_timestamp(neteq_->GetPlayoutTimestamp(), i);
|
||||
}
|
||||
@ -749,7 +754,7 @@ TEST_F(NetEqImplTest, CodecInternalCng) {
|
||||
ASSERT_EQ(kMaxOutputSize, output.samples_per_channel_);
|
||||
EXPECT_EQ(1u, output.num_channels_);
|
||||
EXPECT_EQ(expected_type[i - 1], output.speech_type_);
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output));
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output, &muted));
|
||||
SCOPED_TRACE("");
|
||||
verify_timestamp(neteq_->GetPlayoutTimestamp(), i);
|
||||
}
|
||||
@ -841,9 +846,10 @@ TEST_F(NetEqImplTest, UnsupportedDecoder) {
|
||||
neteq_->InsertPacket(rtp_header, payload, kReceiveTime));
|
||||
|
||||
AudioFrame output;
|
||||
bool muted;
|
||||
// First call to GetAudio will try to decode the "faulty" packet.
|
||||
// Expect kFail return value...
|
||||
EXPECT_EQ(NetEq::kFail, neteq_->GetAudio(&output));
|
||||
EXPECT_EQ(NetEq::kFail, neteq_->GetAudio(&output, &muted));
|
||||
// ... and kOtherDecoderError error code.
|
||||
EXPECT_EQ(NetEq::kOtherDecoderError, neteq_->LastError());
|
||||
// Output size and number of channels should be correct.
|
||||
@ -853,7 +859,7 @@ TEST_F(NetEqImplTest, UnsupportedDecoder) {
|
||||
|
||||
// Second call to GetAudio will decode the packet that is ok. No errors are
|
||||
// expected.
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output));
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output, &muted));
|
||||
EXPECT_EQ(kExpectedOutputSize, output.samples_per_channel_ * kChannels);
|
||||
EXPECT_EQ(kChannels, output.num_channels_);
|
||||
}
|
||||
@ -946,7 +952,8 @@ TEST_F(NetEqImplTest, DecodedPayloadTooShort) {
|
||||
// Pull audio once.
|
||||
const size_t kMaxOutputSize = static_cast<size_t>(10 * kSampleRateHz / 1000);
|
||||
AudioFrame output;
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output));
|
||||
bool muted;
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output, &muted));
|
||||
ASSERT_EQ(kMaxOutputSize, output.samples_per_channel_);
|
||||
EXPECT_EQ(1u, output.num_channels_);
|
||||
EXPECT_EQ(AudioFrame::kNormalSpeech, output.speech_type_);
|
||||
@ -1038,13 +1045,14 @@ TEST_F(NetEqImplTest, DecodingError) {
|
||||
// Pull audio.
|
||||
const size_t kMaxOutputSize = static_cast<size_t>(10 * kSampleRateHz / 1000);
|
||||
AudioFrame output;
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output));
|
||||
bool muted;
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output, &muted));
|
||||
EXPECT_EQ(kMaxOutputSize, output.samples_per_channel_);
|
||||
EXPECT_EQ(1u, output.num_channels_);
|
||||
EXPECT_EQ(AudioFrame::kNormalSpeech, output.speech_type_);
|
||||
|
||||
// Pull audio again. Decoder fails.
|
||||
EXPECT_EQ(NetEq::kFail, neteq_->GetAudio(&output));
|
||||
EXPECT_EQ(NetEq::kFail, neteq_->GetAudio(&output, &muted));
|
||||
EXPECT_EQ(NetEq::kDecoderErrorCode, neteq_->LastError());
|
||||
EXPECT_EQ(kDecoderErrorCode, neteq_->LastDecoderError());
|
||||
EXPECT_EQ(kMaxOutputSize, output.samples_per_channel_);
|
||||
@ -1053,13 +1061,13 @@ TEST_F(NetEqImplTest, DecodingError) {
|
||||
// returned.
|
||||
|
||||
// Pull audio again, should continue an expansion.
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output));
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output, &muted));
|
||||
EXPECT_EQ(kMaxOutputSize, output.samples_per_channel_);
|
||||
EXPECT_EQ(1u, output.num_channels_);
|
||||
EXPECT_EQ(AudioFrame::kPLC, output.speech_type_);
|
||||
|
||||
// Pull audio again, should behave normal.
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output));
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output, &muted));
|
||||
EXPECT_EQ(kMaxOutputSize, output.samples_per_channel_);
|
||||
EXPECT_EQ(1u, output.num_channels_);
|
||||
EXPECT_EQ(AudioFrame::kNormalSpeech, output.speech_type_);
|
||||
@ -1147,13 +1155,14 @@ TEST_F(NetEqImplTest, DecodingErrorDuringInternalCng) {
|
||||
// Pull audio.
|
||||
const size_t kMaxOutputSize = static_cast<size_t>(10 * kSampleRateHz / 1000);
|
||||
AudioFrame output;
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output));
|
||||
bool muted;
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output, &muted));
|
||||
EXPECT_EQ(kMaxOutputSize, output.samples_per_channel_);
|
||||
EXPECT_EQ(1u, output.num_channels_);
|
||||
EXPECT_EQ(AudioFrame::kCNG, output.speech_type_);
|
||||
|
||||
// Pull audio again. Decoder fails.
|
||||
EXPECT_EQ(NetEq::kFail, neteq_->GetAudio(&output));
|
||||
EXPECT_EQ(NetEq::kFail, neteq_->GetAudio(&output, &muted));
|
||||
EXPECT_EQ(NetEq::kDecoderErrorCode, neteq_->LastError());
|
||||
EXPECT_EQ(kDecoderErrorCode, neteq_->LastDecoderError());
|
||||
EXPECT_EQ(kMaxOutputSize, output.samples_per_channel_);
|
||||
@ -1162,7 +1171,7 @@ TEST_F(NetEqImplTest, DecodingErrorDuringInternalCng) {
|
||||
// returned.
|
||||
|
||||
// Pull audio again, should resume codec CNG.
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output));
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output, &muted));
|
||||
EXPECT_EQ(kMaxOutputSize, output.samples_per_channel_);
|
||||
EXPECT_EQ(1u, output.num_channels_);
|
||||
EXPECT_EQ(AudioFrame::kCNG, output.speech_type_);
|
||||
@ -1185,7 +1194,8 @@ TEST_F(NetEqImplTest, TickTimerIncrement) {
|
||||
ASSERT_TRUE(tick_timer_);
|
||||
EXPECT_EQ(0u, tick_timer_->ticks());
|
||||
AudioFrame output;
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output));
|
||||
bool muted;
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output, &muted));
|
||||
EXPECT_EQ(1u, tick_timer_->ticks());
|
||||
}
|
||||
|
||||
@ -1240,8 +1250,10 @@ class NetEqImplTest120ms : public NetEqImplTest {
|
||||
uint32_t first_timestamp() const { return 10u; }
|
||||
|
||||
void GetFirstPacket() {
|
||||
bool muted;
|
||||
for (int i = 0; i < 12; i++) {
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output_));
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output_, &muted));
|
||||
EXPECT_FALSE(muted);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1280,7 +1292,8 @@ TEST_F(NetEqImplTest120ms, AudioRepetition) {
|
||||
InsertPacket(first_timestamp());
|
||||
GetFirstPacket();
|
||||
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output_));
|
||||
bool muted;
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output_, &muted));
|
||||
EXPECT_EQ(kAudioRepetition, neteq_->last_operation_for_test());
|
||||
}
|
||||
|
||||
@ -1292,7 +1305,8 @@ TEST_F(NetEqImplTest120ms, AlternativePlc) {
|
||||
InsertPacket(first_timestamp());
|
||||
GetFirstPacket();
|
||||
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output_));
|
||||
bool muted;
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output_, &muted));
|
||||
EXPECT_EQ(kAlternativePlc, neteq_->last_operation_for_test());
|
||||
}
|
||||
|
||||
@ -1303,7 +1317,8 @@ TEST_F(NetEqImplTest120ms, CodecInternalCng) {
|
||||
InsertPacket(first_timestamp());
|
||||
GetFirstPacket();
|
||||
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output_));
|
||||
bool muted;
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output_, &muted));
|
||||
EXPECT_EQ(kCodecInternalCng, neteq_->last_operation_for_test());
|
||||
}
|
||||
|
||||
@ -1324,14 +1339,15 @@ TEST_F(NetEqImplTest120ms, Merge) {
|
||||
InsertPacket(first_timestamp());
|
||||
|
||||
GetFirstPacket();
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output_));
|
||||
bool muted;
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output_, &muted));
|
||||
|
||||
InsertPacket(first_timestamp() + 2 * timestamp_diff_between_packets());
|
||||
|
||||
// Delay manager reports a target level which should cause a Merge.
|
||||
EXPECT_CALL(*mock_delay_manager_, TargetLevel()).WillOnce(Return(-10));
|
||||
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output_));
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output_, &muted));
|
||||
EXPECT_EQ(kMerge, neteq_->last_operation_for_test());
|
||||
}
|
||||
|
||||
@ -1342,7 +1358,8 @@ TEST_F(NetEqImplTest120ms, Expand) {
|
||||
InsertPacket(first_timestamp());
|
||||
GetFirstPacket();
|
||||
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output_));
|
||||
bool muted;
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output_, &muted));
|
||||
EXPECT_EQ(kExpand, neteq_->last_operation_for_test());
|
||||
}
|
||||
|
||||
@ -1359,7 +1376,8 @@ TEST_F(NetEqImplTest120ms, FastAccelerate) {
|
||||
.Times(1)
|
||||
.WillOnce(DoAll(SetArgPointee<0>(0), SetArgPointee<1>(0)));
|
||||
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output_));
|
||||
bool muted;
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output_, &muted));
|
||||
EXPECT_EQ(kFastAccelerate, neteq_->last_operation_for_test());
|
||||
}
|
||||
|
||||
@ -1377,7 +1395,8 @@ TEST_F(NetEqImplTest120ms, PreemptiveExpand) {
|
||||
.Times(1)
|
||||
.WillOnce(DoAll(SetArgPointee<0>(100), SetArgPointee<1>(100)));
|
||||
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output_));
|
||||
bool muted;
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output_, &muted));
|
||||
EXPECT_EQ(kPreemptiveExpand, neteq_->last_operation_for_test());
|
||||
}
|
||||
|
||||
@ -1395,7 +1414,8 @@ TEST_F(NetEqImplTest120ms, Accelerate) {
|
||||
.Times(1)
|
||||
.WillOnce(DoAll(SetArgPointee<0>(1), SetArgPointee<1>(2)));
|
||||
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output_));
|
||||
bool muted;
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output_, &muted));
|
||||
EXPECT_EQ(kAccelerate, neteq_->last_operation_for_test());
|
||||
}
|
||||
|
||||
|
||||
@ -212,11 +212,14 @@ class NetEqStereoTest : public ::testing::TestWithParam<TestParameters> {
|
||||
} while (Lost()); // If lost, immediately read the next packet.
|
||||
}
|
||||
// Get audio from mono instance.
|
||||
EXPECT_EQ(NetEq::kOK, neteq_mono_->GetAudio(&output_));
|
||||
bool muted;
|
||||
EXPECT_EQ(NetEq::kOK, neteq_mono_->GetAudio(&output_, &muted));
|
||||
ASSERT_FALSE(muted);
|
||||
EXPECT_EQ(1u, output_.num_channels_);
|
||||
EXPECT_EQ(output_size_samples_, output_.samples_per_channel_);
|
||||
// Get audio from multi-channel instance.
|
||||
ASSERT_EQ(NetEq::kOK, neteq_->GetAudio(&output_multi_channel_));
|
||||
ASSERT_EQ(NetEq::kOK, neteq_->GetAudio(&output_multi_channel_, &muted));
|
||||
ASSERT_FALSE(muted);
|
||||
EXPECT_EQ(num_channels_, output_multi_channel_.num_channels_);
|
||||
EXPECT_EQ(output_size_samples_,
|
||||
output_multi_channel_.samples_per_channel_);
|
||||
|
||||
@ -119,6 +119,49 @@ void AddMessage(FILE* file, rtc::MessageDigest* digest,
|
||||
|
||||
#endif // WEBRTC_NETEQ_UNITTEST_BITEXACT
|
||||
|
||||
void LoadDecoders(webrtc::NetEq* neteq) {
|
||||
// Load PCMu.
|
||||
ASSERT_EQ(0, neteq->RegisterPayloadType(webrtc::NetEqDecoder::kDecoderPCMu,
|
||||
"pcmu", 0));
|
||||
// Load PCMa.
|
||||
ASSERT_EQ(0, neteq->RegisterPayloadType(webrtc::NetEqDecoder::kDecoderPCMa,
|
||||
"pcma", 8));
|
||||
#ifdef WEBRTC_CODEC_ILBC
|
||||
// Load iLBC.
|
||||
ASSERT_EQ(0, neteq->RegisterPayloadType(webrtc::NetEqDecoder::kDecoderILBC,
|
||||
"ilbc", 102));
|
||||
#endif
|
||||
#if defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)
|
||||
// Load iSAC.
|
||||
ASSERT_EQ(0, neteq->RegisterPayloadType(webrtc::NetEqDecoder::kDecoderISAC,
|
||||
"isac", 103));
|
||||
#endif
|
||||
#ifdef WEBRTC_CODEC_ISAC
|
||||
// Load iSAC SWB.
|
||||
ASSERT_EQ(0, neteq->RegisterPayloadType(webrtc::NetEqDecoder::kDecoderISACswb,
|
||||
"isac-swb", 104));
|
||||
#endif
|
||||
#ifdef WEBRTC_CODEC_OPUS
|
||||
ASSERT_EQ(0, neteq->RegisterPayloadType(webrtc::NetEqDecoder::kDecoderOpus,
|
||||
"opus", 111));
|
||||
#endif
|
||||
// Load PCM16B nb.
|
||||
ASSERT_EQ(0, neteq->RegisterPayloadType(webrtc::NetEqDecoder::kDecoderPCM16B,
|
||||
"pcm16-nb", 93));
|
||||
// Load PCM16B wb.
|
||||
ASSERT_EQ(0, neteq->RegisterPayloadType(
|
||||
webrtc::NetEqDecoder::kDecoderPCM16Bwb, "pcm16-wb", 94));
|
||||
// Load PCM16B swb32.
|
||||
ASSERT_EQ(
|
||||
0, neteq->RegisterPayloadType(
|
||||
webrtc::NetEqDecoder::kDecoderPCM16Bswb32kHz, "pcm16-swb32", 95));
|
||||
// Load CNG 8 kHz.
|
||||
ASSERT_EQ(0, neteq->RegisterPayloadType(webrtc::NetEqDecoder::kDecoderCNGnb,
|
||||
"cng-nb", 13));
|
||||
// Load CNG 16 kHz.
|
||||
ASSERT_EQ(0, neteq->RegisterPayloadType(webrtc::NetEqDecoder::kDecoderCNGwb,
|
||||
"cng-wb", 98));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace webrtc {
|
||||
@ -213,7 +256,6 @@ class NetEqDecodingTest : public ::testing::Test {
|
||||
virtual void SetUp();
|
||||
virtual void TearDown();
|
||||
void SelectDecoders(NetEqDecoder* used_codec);
|
||||
void LoadDecoders();
|
||||
void OpenInputFile(const std::string &rtp_file);
|
||||
void Process();
|
||||
|
||||
@ -278,56 +320,13 @@ void NetEqDecodingTest::SetUp() {
|
||||
ASSERT_EQ(0, neteq_->NetworkStatistics(&stat));
|
||||
algorithmic_delay_ms_ = stat.current_buffer_size_ms;
|
||||
ASSERT_TRUE(neteq_);
|
||||
LoadDecoders();
|
||||
LoadDecoders(neteq_);
|
||||
}
|
||||
|
||||
void NetEqDecodingTest::TearDown() {
|
||||
delete neteq_;
|
||||
}
|
||||
|
||||
void NetEqDecodingTest::LoadDecoders() {
|
||||
// Load PCMu.
|
||||
ASSERT_EQ(0,
|
||||
neteq_->RegisterPayloadType(NetEqDecoder::kDecoderPCMu, "pcmu", 0));
|
||||
// Load PCMa.
|
||||
ASSERT_EQ(0,
|
||||
neteq_->RegisterPayloadType(NetEqDecoder::kDecoderPCMa, "pcma", 8));
|
||||
#ifdef WEBRTC_CODEC_ILBC
|
||||
// Load iLBC.
|
||||
ASSERT_EQ(
|
||||
0, neteq_->RegisterPayloadType(NetEqDecoder::kDecoderILBC, "ilbc", 102));
|
||||
#endif
|
||||
#if defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)
|
||||
// Load iSAC.
|
||||
ASSERT_EQ(
|
||||
0, neteq_->RegisterPayloadType(NetEqDecoder::kDecoderISAC, "isac", 103));
|
||||
#endif
|
||||
#ifdef WEBRTC_CODEC_ISAC
|
||||
// Load iSAC SWB.
|
||||
ASSERT_EQ(0, neteq_->RegisterPayloadType(NetEqDecoder::kDecoderISACswb,
|
||||
"isac-swb", 104));
|
||||
#endif
|
||||
#ifdef WEBRTC_CODEC_OPUS
|
||||
ASSERT_EQ(0, neteq_->RegisterPayloadType(NetEqDecoder::kDecoderOpus,
|
||||
"opus", 111));
|
||||
#endif
|
||||
// Load PCM16B nb.
|
||||
ASSERT_EQ(0, neteq_->RegisterPayloadType(NetEqDecoder::kDecoderPCM16B,
|
||||
"pcm16-nb", 93));
|
||||
// Load PCM16B wb.
|
||||
ASSERT_EQ(0, neteq_->RegisterPayloadType(NetEqDecoder::kDecoderPCM16Bwb,
|
||||
"pcm16-wb", 94));
|
||||
// Load PCM16B swb32.
|
||||
ASSERT_EQ(0, neteq_->RegisterPayloadType(NetEqDecoder::kDecoderPCM16Bswb32kHz,
|
||||
"pcm16-swb32", 95));
|
||||
// Load CNG 8 kHz.
|
||||
ASSERT_EQ(0, neteq_->RegisterPayloadType(NetEqDecoder::kDecoderCNGnb,
|
||||
"cng-nb", 13));
|
||||
// Load CNG 16 kHz.
|
||||
ASSERT_EQ(0, neteq_->RegisterPayloadType(NetEqDecoder::kDecoderCNGwb,
|
||||
"cng-wb", 98));
|
||||
}
|
||||
|
||||
void NetEqDecodingTest::OpenInputFile(const std::string &rtp_file) {
|
||||
rtp_source_.reset(test::RtpFileSource::Create(rtp_file));
|
||||
}
|
||||
@ -354,7 +353,9 @@ void NetEqDecodingTest::Process() {
|
||||
}
|
||||
|
||||
// Get audio from NetEq.
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&out_frame_));
|
||||
bool muted;
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&out_frame_, &muted));
|
||||
ASSERT_FALSE(muted);
|
||||
ASSERT_TRUE((out_frame_.samples_per_channel_ == kBlockSize8kHz) ||
|
||||
(out_frame_.samples_per_channel_ == kBlockSize16kHz) ||
|
||||
(out_frame_.samples_per_channel_ == kBlockSize32kHz) ||
|
||||
@ -545,7 +546,8 @@ TEST_F(NetEqDecodingTestFaxMode, TestFrameWaitingTimeStatistics) {
|
||||
}
|
||||
// Pull out all data.
|
||||
for (size_t i = 0; i < num_frames; ++i) {
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&out_frame_));
|
||||
bool muted;
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&out_frame_, &muted));
|
||||
ASSERT_EQ(kBlockSize16kHz, out_frame_.samples_per_channel_);
|
||||
}
|
||||
|
||||
@ -586,7 +588,8 @@ TEST_F(NetEqDecodingTest, TestAverageInterArrivalTimeNegative) {
|
||||
}
|
||||
|
||||
// Pull out data once.
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&out_frame_));
|
||||
bool muted;
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&out_frame_, &muted));
|
||||
ASSERT_EQ(kBlockSize16kHz, out_frame_.samples_per_channel_);
|
||||
}
|
||||
|
||||
@ -613,7 +616,8 @@ TEST_F(NetEqDecodingTest, TestAverageInterArrivalTimePositive) {
|
||||
}
|
||||
|
||||
// Pull out data once.
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&out_frame_));
|
||||
bool muted;
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&out_frame_, &muted));
|
||||
ASSERT_EQ(kBlockSize16kHz, out_frame_.samples_per_channel_);
|
||||
}
|
||||
|
||||
@ -634,6 +638,7 @@ void NetEqDecodingTest::LongCngWithClockDrift(double drift_factor,
|
||||
const size_t kPayloadBytes = kSamples * 2;
|
||||
double next_input_time_ms = 0.0;
|
||||
double t_ms;
|
||||
bool muted;
|
||||
|
||||
// Insert speech for 5 seconds.
|
||||
const int kSpeechDurationMs = 5000;
|
||||
@ -650,7 +655,7 @@ void NetEqDecodingTest::LongCngWithClockDrift(double drift_factor,
|
||||
next_input_time_ms += static_cast<double>(kFrameSizeMs) * drift_factor;
|
||||
}
|
||||
// Pull out data once.
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&out_frame_));
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&out_frame_, &muted));
|
||||
ASSERT_EQ(kBlockSize16kHz, out_frame_.samples_per_channel_);
|
||||
}
|
||||
|
||||
@ -679,7 +684,7 @@ void NetEqDecodingTest::LongCngWithClockDrift(double drift_factor,
|
||||
next_input_time_ms += static_cast<double>(kCngPeriodMs) * drift_factor;
|
||||
}
|
||||
// Pull out data once.
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&out_frame_));
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&out_frame_, &muted));
|
||||
ASSERT_EQ(kBlockSize16kHz, out_frame_.samples_per_channel_);
|
||||
}
|
||||
|
||||
@ -692,7 +697,7 @@ void NetEqDecodingTest::LongCngWithClockDrift(double drift_factor,
|
||||
const double loop_end_time = t_ms + network_freeze_ms;
|
||||
for (; t_ms < loop_end_time; t_ms += 10) {
|
||||
// Pull out data once.
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&out_frame_));
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&out_frame_, &muted));
|
||||
ASSERT_EQ(kBlockSize16kHz, out_frame_.samples_per_channel_);
|
||||
EXPECT_EQ(AudioFrame::kCNG, out_frame_.speech_type_);
|
||||
}
|
||||
@ -704,7 +709,7 @@ void NetEqDecodingTest::LongCngWithClockDrift(double drift_factor,
|
||||
if (pull_once && next_input_time_ms >= pull_time_ms) {
|
||||
pull_once = false;
|
||||
// Pull out data once.
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&out_frame_));
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&out_frame_, &muted));
|
||||
ASSERT_EQ(kBlockSize16kHz, out_frame_.samples_per_channel_);
|
||||
EXPECT_EQ(AudioFrame::kCNG, out_frame_.speech_type_);
|
||||
t_ms += 10;
|
||||
@ -738,7 +743,7 @@ void NetEqDecodingTest::LongCngWithClockDrift(double drift_factor,
|
||||
next_input_time_ms += kFrameSizeMs * drift_factor;
|
||||
}
|
||||
// Pull out data once.
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&out_frame_));
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&out_frame_, &muted));
|
||||
ASSERT_EQ(kBlockSize16kHz, out_frame_.samples_per_channel_);
|
||||
// Increase clock.
|
||||
t_ms += 10;
|
||||
@ -866,7 +871,9 @@ TEST_F(NetEqDecodingTest, MAYBE_DecoderError) {
|
||||
for (size_t i = 0; i < AudioFrame::kMaxDataSizeSamples; ++i) {
|
||||
out_frame_.data_[i] = 1;
|
||||
}
|
||||
EXPECT_EQ(NetEq::kFail, neteq_->GetAudio(&out_frame_));
|
||||
bool muted;
|
||||
EXPECT_EQ(NetEq::kFail, neteq_->GetAudio(&out_frame_, &muted));
|
||||
ASSERT_FALSE(muted);
|
||||
// Verify that there is a decoder error to check.
|
||||
EXPECT_EQ(NetEq::kDecoderErrorCode, neteq_->LastError());
|
||||
|
||||
@ -903,7 +910,9 @@ TEST_F(NetEqDecodingTest, GetAudioBeforeInsertPacket) {
|
||||
for (size_t i = 0; i < AudioFrame::kMaxDataSizeSamples; ++i) {
|
||||
out_frame_.data_[i] = 1;
|
||||
}
|
||||
EXPECT_EQ(0, neteq_->GetAudio(&out_frame_));
|
||||
bool muted;
|
||||
EXPECT_EQ(0, neteq_->GetAudio(&out_frame_, &muted));
|
||||
ASSERT_FALSE(muted);
|
||||
// Verify that the first block of samples is set to 0.
|
||||
static const int kExpectedOutputLength =
|
||||
kInitSampleRateHz / 100; // 10 ms at initial sample rate.
|
||||
@ -955,6 +964,7 @@ class NetEqBgnTest : public NetEqDecodingTest {
|
||||
rtp_info.header.payloadType = payload_type;
|
||||
|
||||
uint32_t receive_timestamp = 0;
|
||||
bool muted;
|
||||
for (int n = 0; n < 10; ++n) { // Insert few packets and get audio.
|
||||
auto block = input.GetNextBlock();
|
||||
ASSERT_EQ(expected_samples_per_channel, block.size());
|
||||
@ -966,7 +976,7 @@ class NetEqBgnTest : public NetEqDecodingTest {
|
||||
payload, enc_len_bytes),
|
||||
receive_timestamp));
|
||||
output.Reset();
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&output));
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&output, &muted));
|
||||
ASSERT_EQ(1u, output.num_channels_);
|
||||
ASSERT_EQ(expected_samples_per_channel, output.samples_per_channel_);
|
||||
ASSERT_EQ(AudioFrame::kNormalSpeech, output.speech_type_);
|
||||
@ -982,7 +992,7 @@ class NetEqBgnTest : public NetEqDecodingTest {
|
||||
// Get audio without inserting packets, expecting PLC and PLC-to-CNG. Pull
|
||||
// one frame without checking speech-type. This is the first frame pulled
|
||||
// without inserting any packet, and might not be labeled as PLC.
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&output));
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&output, &muted));
|
||||
ASSERT_EQ(1u, output.num_channels_);
|
||||
ASSERT_EQ(expected_samples_per_channel, output.samples_per_channel_);
|
||||
|
||||
@ -997,7 +1007,8 @@ class NetEqBgnTest : public NetEqDecodingTest {
|
||||
for (int n = 0; n < kFadingThreshold + kNumPlcToCngTestFrames; ++n) {
|
||||
output.Reset();
|
||||
memset(output.data_, 1, sizeof(output.data_)); // Set to non-zero.
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&output));
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&output, &muted));
|
||||
ASSERT_FALSE(muted);
|
||||
ASSERT_EQ(1u, output.num_channels_);
|
||||
ASSERT_EQ(expected_samples_per_channel, output.samples_per_channel_);
|
||||
if (output.speech_type_ == AudioFrame::kPLCCNG) {
|
||||
@ -1171,9 +1182,10 @@ TEST_F(NetEqDecodingTest, SyncPacketDecode) {
|
||||
// Insert some packets which decode to noise. We are not interested in
|
||||
// actual decoded values.
|
||||
uint32_t receive_timestamp = 0;
|
||||
bool muted;
|
||||
for (int n = 0; n < 100; ++n) {
|
||||
ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, receive_timestamp));
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&output));
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&output, &muted));
|
||||
ASSERT_EQ(kBlockSize16kHz, output.samples_per_channel_);
|
||||
ASSERT_EQ(1u, output.num_channels_);
|
||||
|
||||
@ -1189,7 +1201,8 @@ TEST_F(NetEqDecodingTest, SyncPacketDecode) {
|
||||
// Insert sync-packets, the decoded sequence should be all-zero.
|
||||
for (int n = 0; n < kNumSyncPackets; ++n) {
|
||||
ASSERT_EQ(0, neteq_->InsertSyncPacket(rtp_info, receive_timestamp));
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&output));
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&output, &muted));
|
||||
ASSERT_FALSE(muted);
|
||||
ASSERT_EQ(kBlockSize16kHz, output.samples_per_channel_);
|
||||
ASSERT_EQ(1u, output.num_channels_);
|
||||
if (n > algorithmic_frame_delay) {
|
||||
@ -1205,7 +1218,8 @@ TEST_F(NetEqDecodingTest, SyncPacketDecode) {
|
||||
// network statistics would show some packet loss.
|
||||
for (int n = 0; n <= algorithmic_frame_delay + 10; ++n) {
|
||||
ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, receive_timestamp));
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&output));
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&output, &muted));
|
||||
ASSERT_FALSE(muted);
|
||||
if (n >= algorithmic_frame_delay + 1) {
|
||||
// Expect that this frame contain samples from regular RTP.
|
||||
EXPECT_TRUE(IsAllNonZero(
|
||||
@ -1241,9 +1255,10 @@ TEST_F(NetEqDecodingTest, SyncPacketBufferSizeAndOverridenByNetworkPackets) {
|
||||
// actual decoded values.
|
||||
uint32_t receive_timestamp = 0;
|
||||
int algorithmic_frame_delay = algorithmic_delay_ms_ / 10 + 1;
|
||||
bool muted;
|
||||
for (int n = 0; n < algorithmic_frame_delay; ++n) {
|
||||
ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, receive_timestamp));
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&output));
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&output, &muted));
|
||||
ASSERT_EQ(kBlockSize16kHz, output.samples_per_channel_);
|
||||
ASSERT_EQ(1u, output.num_channels_);
|
||||
rtp_info.header.sequenceNumber++;
|
||||
@ -1280,7 +1295,8 @@ TEST_F(NetEqDecodingTest, SyncPacketBufferSizeAndOverridenByNetworkPackets) {
|
||||
|
||||
// Decode.
|
||||
for (int n = 0; n < kNumSyncPackets; ++n) {
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&output));
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&output, &muted));
|
||||
ASSERT_FALSE(muted);
|
||||
ASSERT_EQ(kBlockSize16kHz, output.samples_per_channel_);
|
||||
ASSERT_EQ(1u, output.num_channels_);
|
||||
EXPECT_TRUE(IsAllNonZero(
|
||||
@ -1347,7 +1363,8 @@ void NetEqDecodingTest::WrapTest(uint16_t start_seq_no,
|
||||
}
|
||||
// Pull out data once.
|
||||
AudioFrame output;
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&output));
|
||||
bool muted;
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&output, &muted));
|
||||
ASSERT_EQ(kBlockSize16kHz, output.samples_per_channel_);
|
||||
ASSERT_EQ(1u, output.num_channels_);
|
||||
|
||||
@ -1403,6 +1420,7 @@ void NetEqDecodingTest::DuplicateCng() {
|
||||
// correct.
|
||||
uint8_t payload[kPayloadBytes] = {0};
|
||||
WebRtcRTPHeader rtp_info;
|
||||
bool muted;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
PopulateRtpInfo(seq_no, timestamp, &rtp_info);
|
||||
ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, 0));
|
||||
@ -1410,7 +1428,7 @@ void NetEqDecodingTest::DuplicateCng() {
|
||||
timestamp += kSamples;
|
||||
|
||||
// Pull audio once.
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&out_frame_));
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&out_frame_, &muted));
|
||||
ASSERT_EQ(kBlockSize16kHz, out_frame_.samples_per_channel_);
|
||||
}
|
||||
// Verify speech output.
|
||||
@ -1427,7 +1445,7 @@ void NetEqDecodingTest::DuplicateCng() {
|
||||
rtp_info, rtc::ArrayView<const uint8_t>(payload, payload_len), 0));
|
||||
|
||||
// Pull audio once and make sure CNG is played.
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&out_frame_));
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&out_frame_, &muted));
|
||||
ASSERT_EQ(kBlockSize16kHz, out_frame_.samples_per_channel_);
|
||||
EXPECT_EQ(AudioFrame::kCNG, out_frame_.speech_type_);
|
||||
EXPECT_FALSE(PlayoutTimestamp()); // Returns empty value during CNG.
|
||||
@ -1443,7 +1461,7 @@ void NetEqDecodingTest::DuplicateCng() {
|
||||
// Pull audio until we have played |kCngPeriodMs| of CNG. Start at 10 ms since
|
||||
// we have already pulled out CNG once.
|
||||
for (int cng_time_ms = 10; cng_time_ms < kCngPeriodMs; cng_time_ms += 10) {
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&out_frame_));
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&out_frame_, &muted));
|
||||
ASSERT_EQ(kBlockSize16kHz, out_frame_.samples_per_channel_);
|
||||
EXPECT_EQ(AudioFrame::kCNG, out_frame_.speech_type_);
|
||||
EXPECT_FALSE(PlayoutTimestamp()); // Returns empty value during CNG.
|
||||
@ -1458,7 +1476,7 @@ void NetEqDecodingTest::DuplicateCng() {
|
||||
ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, 0));
|
||||
|
||||
// Pull audio once and verify that the output is speech again.
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&out_frame_));
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&out_frame_, &muted));
|
||||
ASSERT_EQ(kBlockSize16kHz, out_frame_.samples_per_channel_);
|
||||
EXPECT_EQ(AudioFrame::kNormalSpeech, out_frame_.speech_type_);
|
||||
rtc::Optional<uint32_t> playout_timestamp = PlayoutTimestamp();
|
||||
@ -1496,7 +1514,8 @@ TEST_F(NetEqDecodingTest, CngFirst) {
|
||||
timestamp += kCngPeriodSamples;
|
||||
|
||||
// Pull audio once and make sure CNG is played.
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&out_frame_));
|
||||
bool muted;
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&out_frame_, &muted));
|
||||
ASSERT_EQ(kBlockSize16kHz, out_frame_.samples_per_channel_);
|
||||
EXPECT_EQ(AudioFrame::kCNG, out_frame_.speech_type_);
|
||||
|
||||
@ -1508,10 +1527,252 @@ TEST_F(NetEqDecodingTest, CngFirst) {
|
||||
timestamp += kSamples;
|
||||
|
||||
// Pull audio once.
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&out_frame_));
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&out_frame_, &muted));
|
||||
ASSERT_EQ(kBlockSize16kHz, out_frame_.samples_per_channel_);
|
||||
}
|
||||
// Verify speech output.
|
||||
EXPECT_EQ(AudioFrame::kNormalSpeech, out_frame_.speech_type_);
|
||||
}
|
||||
|
||||
class NetEqDecodingTestWithMutedState : public NetEqDecodingTest {
|
||||
public:
|
||||
NetEqDecodingTestWithMutedState() : NetEqDecodingTest() {
|
||||
config_.enable_muted_state = true;
|
||||
}
|
||||
|
||||
protected:
|
||||
static constexpr size_t kSamples = 10 * 16;
|
||||
static constexpr size_t kPayloadBytes = kSamples * 2;
|
||||
|
||||
void InsertPacket(uint32_t rtp_timestamp) {
|
||||
uint8_t payload[kPayloadBytes] = {0};
|
||||
WebRtcRTPHeader rtp_info;
|
||||
PopulateRtpInfo(0, rtp_timestamp, &rtp_info);
|
||||
EXPECT_EQ(0, neteq_->InsertPacket(rtp_info, payload, 0));
|
||||
}
|
||||
|
||||
bool GetAudioReturnMuted() {
|
||||
bool muted;
|
||||
EXPECT_EQ(0, neteq_->GetAudio(&out_frame_, &muted));
|
||||
return muted;
|
||||
}
|
||||
|
||||
void GetAudioUntilMuted() {
|
||||
while (!GetAudioReturnMuted()) {
|
||||
ASSERT_LT(counter_++, 1000) << "Test timed out";
|
||||
}
|
||||
}
|
||||
|
||||
void GetAudioUntilNormal() {
|
||||
bool muted = false;
|
||||
while (out_frame_.speech_type_ != AudioFrame::kNormalSpeech) {
|
||||
EXPECT_EQ(0, neteq_->GetAudio(&out_frame_, &muted));
|
||||
ASSERT_LT(counter_++, 1000) << "Test timed out";
|
||||
}
|
||||
EXPECT_FALSE(muted);
|
||||
}
|
||||
|
||||
int counter_ = 0;
|
||||
};
|
||||
|
||||
// Verifies that NetEq goes in and out of muted state as expected.
|
||||
TEST_F(NetEqDecodingTestWithMutedState, MutedState) {
|
||||
// Insert one speech packet.
|
||||
InsertPacket(0);
|
||||
// Pull out audio once and expect it not to be muted.
|
||||
EXPECT_FALSE(GetAudioReturnMuted());
|
||||
// Pull data until faded out.
|
||||
GetAudioUntilMuted();
|
||||
|
||||
// Verify that output audio is not written during muted mode. Other parameters
|
||||
// should be correct, though.
|
||||
AudioFrame new_frame;
|
||||
for (auto& d : new_frame.data_) {
|
||||
d = 17;
|
||||
}
|
||||
bool muted;
|
||||
EXPECT_EQ(0, neteq_->GetAudio(&new_frame, &muted));
|
||||
EXPECT_TRUE(muted);
|
||||
for (auto d : new_frame.data_) {
|
||||
EXPECT_EQ(17, d);
|
||||
}
|
||||
EXPECT_EQ(out_frame_.timestamp_ + out_frame_.samples_per_channel_,
|
||||
new_frame.timestamp_);
|
||||
EXPECT_EQ(out_frame_.samples_per_channel_, new_frame.samples_per_channel_);
|
||||
EXPECT_EQ(out_frame_.sample_rate_hz_, new_frame.sample_rate_hz_);
|
||||
EXPECT_EQ(out_frame_.num_channels_, new_frame.num_channels_);
|
||||
EXPECT_EQ(out_frame_.speech_type_, new_frame.speech_type_);
|
||||
EXPECT_EQ(out_frame_.vad_activity_, new_frame.vad_activity_);
|
||||
|
||||
// Insert new data. Timestamp is corrected for the time elapsed since the last
|
||||
// packet. Verify that normal operation resumes.
|
||||
InsertPacket(kSamples * counter_);
|
||||
GetAudioUntilNormal();
|
||||
}
|
||||
|
||||
// Verifies that NetEq goes out of muted state when given a delayed packet.
|
||||
TEST_F(NetEqDecodingTestWithMutedState, MutedStateDelayedPacket) {
|
||||
// Insert one speech packet.
|
||||
InsertPacket(0);
|
||||
// Pull out audio once and expect it not to be muted.
|
||||
EXPECT_FALSE(GetAudioReturnMuted());
|
||||
// Pull data until faded out.
|
||||
GetAudioUntilMuted();
|
||||
// Insert new data. Timestamp is only corrected for the half of the time
|
||||
// elapsed since the last packet. That is, the new packet is delayed. Verify
|
||||
// that normal operation resumes.
|
||||
InsertPacket(kSamples * counter_ / 2);
|
||||
GetAudioUntilNormal();
|
||||
}
|
||||
|
||||
// Verifies that NetEq goes out of muted state when given a future packet.
|
||||
TEST_F(NetEqDecodingTestWithMutedState, MutedStateFuturePacket) {
|
||||
// Insert one speech packet.
|
||||
InsertPacket(0);
|
||||
// Pull out audio once and expect it not to be muted.
|
||||
EXPECT_FALSE(GetAudioReturnMuted());
|
||||
// Pull data until faded out.
|
||||
GetAudioUntilMuted();
|
||||
// Insert new data. Timestamp is over-corrected for the time elapsed since the
|
||||
// last packet. That is, the new packet is too early. Verify that normal
|
||||
// operation resumes.
|
||||
InsertPacket(kSamples * counter_ * 2);
|
||||
GetAudioUntilNormal();
|
||||
}
|
||||
|
||||
// Verifies that NetEq goes out of muted state when given an old packet.
|
||||
TEST_F(NetEqDecodingTestWithMutedState, MutedStateOldPacket) {
|
||||
// Insert one speech packet.
|
||||
InsertPacket(0);
|
||||
// Pull out audio once and expect it not to be muted.
|
||||
EXPECT_FALSE(GetAudioReturnMuted());
|
||||
// Pull data until faded out.
|
||||
GetAudioUntilMuted();
|
||||
|
||||
EXPECT_NE(AudioFrame::kNormalSpeech, out_frame_.speech_type_);
|
||||
// Insert packet which is older than the first packet.
|
||||
InsertPacket(kSamples * (counter_ - 1000));
|
||||
EXPECT_FALSE(GetAudioReturnMuted());
|
||||
EXPECT_EQ(AudioFrame::kNormalSpeech, out_frame_.speech_type_);
|
||||
}
|
||||
|
||||
class NetEqDecodingTestTwoInstances : public NetEqDecodingTest {
|
||||
public:
|
||||
NetEqDecodingTestTwoInstances() : NetEqDecodingTest() {}
|
||||
|
||||
void SetUp() override {
|
||||
NetEqDecodingTest::SetUp();
|
||||
config2_ = config_;
|
||||
}
|
||||
|
||||
void CreateSecondInstance() {
|
||||
neteq2_.reset(NetEq::Create(config2_));
|
||||
ASSERT_TRUE(neteq2_);
|
||||
LoadDecoders(neteq2_.get());
|
||||
}
|
||||
|
||||
protected:
|
||||
std::unique_ptr<NetEq> neteq2_;
|
||||
NetEq::Config config2_;
|
||||
};
|
||||
|
||||
namespace {
|
||||
::testing::AssertionResult AudioFramesEqualExceptData(const AudioFrame& a,
|
||||
const AudioFrame& b) {
|
||||
if (a.timestamp_ != b.timestamp_)
|
||||
return ::testing::AssertionFailure() << "timestamp_ diff (" << a.timestamp_
|
||||
<< " != " << b.timestamp_ << ")";
|
||||
if (a.sample_rate_hz_ != b.sample_rate_hz_)
|
||||
return ::testing::AssertionFailure() << "sample_rate_hz_ diff ("
|
||||
<< a.sample_rate_hz_
|
||||
<< " != " << b.sample_rate_hz_ << ")";
|
||||
if (a.samples_per_channel_ != b.samples_per_channel_)
|
||||
return ::testing::AssertionFailure()
|
||||
<< "samples_per_channel_ diff (" << a.samples_per_channel_
|
||||
<< " != " << b.samples_per_channel_ << ")";
|
||||
if (a.num_channels_ != b.num_channels_)
|
||||
return ::testing::AssertionFailure() << "num_channels_ diff ("
|
||||
<< a.num_channels_
|
||||
<< " != " << b.num_channels_ << ")";
|
||||
if (a.speech_type_ != b.speech_type_)
|
||||
return ::testing::AssertionFailure() << "speech_type_ diff ("
|
||||
<< a.speech_type_
|
||||
<< " != " << b.speech_type_ << ")";
|
||||
if (a.vad_activity_ != b.vad_activity_)
|
||||
return ::testing::AssertionFailure() << "vad_activity_ diff ("
|
||||
<< a.vad_activity_
|
||||
<< " != " << b.vad_activity_ << ")";
|
||||
return ::testing::AssertionSuccess();
|
||||
}
|
||||
|
||||
::testing::AssertionResult AudioFramesEqual(const AudioFrame& a,
|
||||
const AudioFrame& b) {
|
||||
::testing::AssertionResult res = AudioFramesEqualExceptData(a, b);
|
||||
if (!res)
|
||||
return res;
|
||||
if (memcmp(
|
||||
a.data_, b.data_,
|
||||
a.samples_per_channel_ * a.num_channels_ * sizeof(a.data_[0])) != 0) {
|
||||
return ::testing::AssertionFailure() << "data_ diff";
|
||||
}
|
||||
return ::testing::AssertionSuccess();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_F(NetEqDecodingTestTwoInstances, CompareMutedStateOnOff) {
|
||||
ASSERT_FALSE(config_.enable_muted_state);
|
||||
config2_.enable_muted_state = true;
|
||||
CreateSecondInstance();
|
||||
|
||||
// Insert one speech packet into both NetEqs.
|
||||
const size_t kSamples = 10 * 16;
|
||||
const size_t kPayloadBytes = kSamples * 2;
|
||||
uint8_t payload[kPayloadBytes] = {0};
|
||||
WebRtcRTPHeader rtp_info;
|
||||
PopulateRtpInfo(0, 0, &rtp_info);
|
||||
EXPECT_EQ(0, neteq_->InsertPacket(rtp_info, payload, 0));
|
||||
EXPECT_EQ(0, neteq2_->InsertPacket(rtp_info, payload, 0));
|
||||
|
||||
AudioFrame out_frame1, out_frame2;
|
||||
bool muted;
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
std::ostringstream ss;
|
||||
ss << "i = " << i;
|
||||
SCOPED_TRACE(ss.str()); // Print out the loop iterator on failure.
|
||||
EXPECT_EQ(0, neteq_->GetAudio(&out_frame1, &muted));
|
||||
EXPECT_FALSE(muted);
|
||||
EXPECT_EQ(0, neteq2_->GetAudio(&out_frame2, &muted));
|
||||
if (muted) {
|
||||
EXPECT_TRUE(AudioFramesEqualExceptData(out_frame1, out_frame2));
|
||||
} else {
|
||||
EXPECT_TRUE(AudioFramesEqual(out_frame1, out_frame2));
|
||||
}
|
||||
}
|
||||
EXPECT_TRUE(muted);
|
||||
|
||||
// Insert new data. Timestamp is corrected for the time elapsed since the last
|
||||
// packet.
|
||||
PopulateRtpInfo(0, kSamples * 1000, &rtp_info);
|
||||
EXPECT_EQ(0, neteq_->InsertPacket(rtp_info, payload, 0));
|
||||
EXPECT_EQ(0, neteq2_->InsertPacket(rtp_info, payload, 0));
|
||||
|
||||
int counter = 0;
|
||||
while (out_frame1.speech_type_ != AudioFrame::kNormalSpeech) {
|
||||
ASSERT_LT(counter++, 1000) << "Test timed out";
|
||||
std::ostringstream ss;
|
||||
ss << "counter = " << counter;
|
||||
SCOPED_TRACE(ss.str()); // Print out the loop iterator on failure.
|
||||
EXPECT_EQ(0, neteq_->GetAudio(&out_frame1, &muted));
|
||||
EXPECT_FALSE(muted);
|
||||
EXPECT_EQ(0, neteq2_->GetAudio(&out_frame2, &muted));
|
||||
if (muted) {
|
||||
EXPECT_TRUE(AudioFramesEqualExceptData(out_frame1, out_frame2));
|
||||
} else {
|
||||
EXPECT_TRUE(AudioFramesEqual(out_frame1, out_frame2));
|
||||
}
|
||||
}
|
||||
EXPECT_FALSE(muted);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -45,7 +45,9 @@ void NetEqExternalDecoderTest::InsertPacket(
|
||||
|
||||
void NetEqExternalDecoderTest::GetOutputAudio(AudioFrame* output) {
|
||||
// Get audio from regular instance.
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(output));
|
||||
bool muted;
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(output, &muted));
|
||||
ASSERT_FALSE(muted);
|
||||
EXPECT_EQ(channels_, output->num_channels_);
|
||||
EXPECT_EQ(static_cast<size_t>(kOutputLengthMs * sample_rate_hz_ / 1000),
|
||||
output->samples_per_channel_);
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
|
||||
#include "webrtc/modules/audio_coding/neteq/tools/neteq_performance_test.h"
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/modules/audio_coding/codecs/pcm16b/pcm16b.h"
|
||||
#include "webrtc/modules/audio_coding/neteq/include/neteq.h"
|
||||
#include "webrtc/modules/audio_coding/neteq/tools/audio_loop.h"
|
||||
@ -105,7 +106,9 @@ int64_t NetEqPerformanceTest::Run(int runtime_ms,
|
||||
}
|
||||
|
||||
// Get output audio, but don't do anything with it.
|
||||
int error = neteq->GetAudio(&out_frame);
|
||||
bool muted;
|
||||
int error = neteq->GetAudio(&out_frame, &muted);
|
||||
RTC_CHECK(!muted);
|
||||
if (error != NetEq::kOK)
|
||||
return -1;
|
||||
|
||||
|
||||
@ -391,7 +391,9 @@ int NetEqQualityTest::Transmit() {
|
||||
}
|
||||
|
||||
int NetEqQualityTest::DecodeBlock() {
|
||||
int ret = neteq_->GetAudio(&out_frame_);
|
||||
bool muted;
|
||||
int ret = neteq_->GetAudio(&out_frame_, &muted);
|
||||
RTC_CHECK(!muted);
|
||||
|
||||
if (ret != NetEq::kOK) {
|
||||
return -1;
|
||||
|
||||
@ -605,7 +605,9 @@ int main(int argc, char* argv[]) {
|
||||
// Check if it is time to get output audio.
|
||||
while (time_now_ms >= next_output_time_ms && output_event_available) {
|
||||
webrtc::AudioFrame out_frame;
|
||||
int error = neteq->GetAudio(&out_frame);
|
||||
bool muted;
|
||||
int error = neteq->GetAudio(&out_frame, &muted);
|
||||
RTC_CHECK(!muted);
|
||||
if (error != NetEq::kOK) {
|
||||
std::cerr << "GetAudio returned error code " <<
|
||||
neteq->LastError() << std::endl;
|
||||
|
||||
Reference in New Issue
Block a user