diff --git a/webrtc/modules/audio_coding/acm2/acm_receiver.cc b/webrtc/modules/audio_coding/acm2/acm_receiver.cc index 7c96c28968..57d7bd344a 100644 --- a/webrtc/modules/audio_coding/acm2/acm_receiver.cc +++ b/webrtc/modules/audio_coding/acm2/acm_receiver.cc @@ -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(); diff --git a/webrtc/modules/audio_coding/neteq/include/neteq.h b/webrtc/modules/audio_coding/neteq/include/neteq.h index 89b0c54324..3a9de1d260 100644 --- a/webrtc/modules/audio_coding/neteq/include/neteq.h +++ b/webrtc/modules/audio_coding/neteq/include/neteq.h @@ -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. diff --git a/webrtc/modules/audio_coding/neteq/neteq.cc b/webrtc/modules/audio_coding/neteq/neteq.cc index edc29da435..2d1ce724ca 100644 --- a/webrtc/modules/audio_coding/neteq/neteq.cc +++ b/webrtc/modules/audio_coding/neteq/neteq.cc @@ -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(); } diff --git a/webrtc/modules/audio_coding/neteq/neteq_external_decoder_unittest.cc b/webrtc/modules/audio_coding/neteq/neteq_external_decoder_unittest.cc index 50c24a3b73..25fa1a7365 100644 --- a/webrtc/modules/audio_coding/neteq/neteq_external_decoder_unittest.cc +++ b/webrtc/modules/audio_coding/neteq/neteq_external_decoder_unittest.cc @@ -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(kOutputLengthMs * sample_rate_hz_ / 1000), output_internal_.samples_per_channel_); diff --git a/webrtc/modules/audio_coding/neteq/neteq_impl.cc b/webrtc/modules/audio_coding/neteq/neteq_impl.cc index 945ac5ce16..5e98b88ff4 100644 --- a/webrtc/modules/audio_coding/neteq/neteq_impl.cc +++ b/webrtc/modules/audio_coding/neteq/neteq_impl.cc @@ -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(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(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(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) { diff --git a/webrtc/modules/audio_coding/neteq/neteq_impl.h b/webrtc/modules/audio_coding/neteq/neteq_impl.h index 2be3ee4c70..cc5550411f 100644 --- a/webrtc/modules/audio_coding/neteq/neteq_impl.h +++ b/webrtc/modules/audio_coding/neteq/neteq_impl.h @@ -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_ 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 generated_noise_stopwatch_ diff --git a/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc b/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc index 8b47adb9c5..43db87f4fa 100644 --- a/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc +++ b/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc @@ -441,7 +441,9 @@ TEST_F(NetEqImplTest, VerifyTimestampPropagation) { // Pull audio once. const size_t kMaxOutputSize = static_cast(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(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(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 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(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(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(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()); } diff --git a/webrtc/modules/audio_coding/neteq/neteq_stereo_unittest.cc b/webrtc/modules/audio_coding/neteq/neteq_stereo_unittest.cc index 4ee17d2a44..e1a9922b0b 100644 --- a/webrtc/modules/audio_coding/neteq/neteq_stereo_unittest.cc +++ b/webrtc/modules/audio_coding/neteq/neteq_stereo_unittest.cc @@ -212,11 +212,14 @@ class NetEqStereoTest : public ::testing::TestWithParam { } 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_); diff --git a/webrtc/modules/audio_coding/neteq/neteq_unittest.cc b/webrtc/modules/audio_coding/neteq/neteq_unittest.cc index 69c3876354..4a6f505fc6 100644 --- a/webrtc/modules/audio_coding/neteq/neteq_unittest.cc +++ b/webrtc/modules/audio_coding/neteq/neteq_unittest.cc @@ -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(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(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(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 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 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 diff --git a/webrtc/modules/audio_coding/neteq/tools/neteq_external_decoder_test.cc b/webrtc/modules/audio_coding/neteq/tools/neteq_external_decoder_test.cc index 2608d9a03b..7a51256af2 100644 --- a/webrtc/modules/audio_coding/neteq/tools/neteq_external_decoder_test.cc +++ b/webrtc/modules/audio_coding/neteq/tools/neteq_external_decoder_test.cc @@ -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(kOutputLengthMs * sample_rate_hz_ / 1000), output->samples_per_channel_); diff --git a/webrtc/modules/audio_coding/neteq/tools/neteq_performance_test.cc b/webrtc/modules/audio_coding/neteq/tools/neteq_performance_test.cc index 59402a2029..d0052c28a8 100644 --- a/webrtc/modules/audio_coding/neteq/tools/neteq_performance_test.cc +++ b/webrtc/modules/audio_coding/neteq/tools/neteq_performance_test.cc @@ -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; diff --git a/webrtc/modules/audio_coding/neteq/tools/neteq_quality_test.cc b/webrtc/modules/audio_coding/neteq/tools/neteq_quality_test.cc index 5f874ad8db..2983cebe9d 100644 --- a/webrtc/modules/audio_coding/neteq/tools/neteq_quality_test.cc +++ b/webrtc/modules/audio_coding/neteq/tools/neteq_quality_test.cc @@ -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; diff --git a/webrtc/modules/audio_coding/neteq/tools/neteq_rtpplay.cc b/webrtc/modules/audio_coding/neteq/tools/neteq_rtpplay.cc index fdb66714cf..1d462b3c9f 100644 --- a/webrtc/modules/audio_coding/neteq/tools/neteq_rtpplay.cc +++ b/webrtc/modules/audio_coding/neteq/tools/neteq_rtpplay.cc @@ -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;