diff --git a/experiments/field_trials.py b/experiments/field_trials.py index 4c41b7e29e..5a95331ef8 100755 --- a/experiments/field_trials.py +++ b/experiments/field_trials.py @@ -472,9 +472,6 @@ POLICY_EXEMPT_FIELD_TRIALS: FrozenSet[FieldTrial] = frozenset([ FieldTrial('WebRTC-Audio-NetEqSmartFlushing', 42222334, date(2024, 4, 1)), - FieldTrial('WebRTC-Audio-OpusAvoidNoisePumpingDuringDtx', - 42222522, - date(2024, 4, 1)), FieldTrial('WebRTC-Audio-OpusBitrateMultipliers', 42221139, date(2024, 4, 1)), @@ -881,7 +878,7 @@ POLICY_EXEMPT_FIELD_TRIALS: FrozenSet[FieldTrial] = frozenset([ ]) # yapf: disable POLICY_EXEMPT_FIELD_TRIALS_DIGEST: str = \ - 'a3a5347c082f66bf6c338b8fed783ebff5a50561' + '95050aa4a628b16d1220b3674b543c035c24cb6c' REGISTERED_FIELD_TRIALS: FrozenSet[FieldTrial] = ACTIVE_FIELD_TRIALS.union( POLICY_EXEMPT_FIELD_TRIALS) diff --git a/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc b/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc index b0bf204a17..c12f70f6f5 100644 --- a/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc +++ b/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc @@ -26,7 +26,6 @@ #include "test/explicit_key_value_config.h" #include "test/gmock.h" #include "test/gtest.h" -#include "test/scoped_key_value_config.h" #include "test/testsupport/file_utils.h" namespace webrtc { @@ -822,107 +821,4 @@ TEST_P(AudioEncoderOpusTest, OpusFlagDtxAsNonSpeech) { EXPECT_GT(max_nonspeech_frames, 15); } -TEST(AudioEncoderOpusTest, OpusDtxFilteringHighEnergyRefreshPackets) { - // TODO: bugs.webrtc.org/343086059 - Use `ExplicitKeyValueConfig` type to - // ensure global field trial string is not used when this field trial is - // queried from the passed Environment. - // There are currently two complications for that: - // - field trial is queried by WebRtcOpus_EncoderCreate that follows c-style - // interface, and thus is not ready to accept c++ interface FieldTrialsView - // - field trial is queried during `RecreateEncoderInstance`, i.e., opus - // encoder needs to save field trials passed at construction. That will be - // simpler once all public constructors accept webrtc::Environment. - test::ScopedKeyValueConfig field_trials( - "WebRTC-Audio-OpusAvoidNoisePumpingDuringDtx/Enabled/"); - const std::string kInputFileName = - webrtc::test::ResourcePath("audio_coding/testfile16kHz", "pcm"); - constexpr int kSampleRateHz = 16000; - AudioEncoderOpusConfig config; - config.dtx_enabled = true; - config.sample_rate_hz = kSampleRateHz; - constexpr int payload_type = 17; - AudioEncoderOpusImpl encoder(CreateEnvironment(&field_trials), config, - payload_type); - test::AudioLoop audio_loop; - constexpr size_t kMaxLoopLengthSaples = kSampleRateHz * 11.6f; - constexpr size_t kInputBlockSizeSamples = kSampleRateHz / 100; - EXPECT_TRUE(audio_loop.Init(kInputFileName, kMaxLoopLengthSaples, - kInputBlockSizeSamples)); - AudioEncoder::EncodedInfo info; - rtc::Buffer encoded(500); - // Encode the audio file and store the last part that corresponds to silence. - constexpr size_t kSilenceDurationSamples = kSampleRateHz * 0.2f; - std::array silence; - uint32_t rtp_timestamp = 0; - bool last_packet_dtx_frame = false; - bool opus_entered_dtx = false; - bool silence_filled = false; - size_t timestamp_start_silence = 0; - while (!silence_filled && rtp_timestamp < kMaxLoopLengthSaples) { - encoded.Clear(); - // Every second call to the encoder will generate an Opus packet. - for (int j = 0; j < 2; j++) { - auto next_frame = audio_loop.GetNextBlock(); - info = encoder.Encode(rtp_timestamp, next_frame, &encoded); - if (opus_entered_dtx) { - size_t silence_frame_start = rtp_timestamp - timestamp_start_silence; - silence_filled = silence_frame_start >= kSilenceDurationSamples; - if (!silence_filled) { - std::copy(next_frame.begin(), next_frame.end(), - silence.begin() + silence_frame_start); - } - } - rtp_timestamp += kInputBlockSizeSamples; - } - EXPECT_TRUE(info.encoded_bytes > 0 || last_packet_dtx_frame); - last_packet_dtx_frame = info.encoded_bytes > 0 ? info.encoded_bytes <= 2 - : last_packet_dtx_frame; - if (info.encoded_bytes <= 2 && !opus_entered_dtx) { - timestamp_start_silence = rtp_timestamp; - } - opus_entered_dtx = info.encoded_bytes <= 2; - } - - EXPECT_TRUE(silence_filled); - // The copied 200 ms of silence is used for creating 6 bursts that are fed to - // the encoder, the first three ones with a larger energy and the last three - // with a lower energy. This test verifies that the encoder just sends refresh - // DTX packets during the last bursts. - int number_non_empty_packets_during_increase = 0; - int number_non_empty_packets_during_decrease = 0; - for (size_t burst = 0; burst < 6; ++burst) { - uint32_t rtp_timestamp_start = rtp_timestamp; - const bool increase_noise = burst < 3; - const float gain = increase_noise ? 1.4f : 0.0f; - while (rtp_timestamp < rtp_timestamp_start + kSilenceDurationSamples) { - encoded.Clear(); - // Every second call to the encoder will generate an Opus packet. - for (int j = 0; j < 2; j++) { - std::array silence_frame; - size_t silence_frame_start = rtp_timestamp - rtp_timestamp_start; - std::transform( - silence.begin() + silence_frame_start, - silence.begin() + silence_frame_start + kInputBlockSizeSamples, - silence_frame.begin(), [gain](float s) { return gain * s; }); - info = encoder.Encode(rtp_timestamp, silence_frame, &encoded); - rtp_timestamp += kInputBlockSizeSamples; - } - EXPECT_TRUE(info.encoded_bytes > 0 || last_packet_dtx_frame); - last_packet_dtx_frame = info.encoded_bytes > 0 ? info.encoded_bytes <= 2 - : last_packet_dtx_frame; - // Tracking the number of non empty packets. - if (increase_noise && info.encoded_bytes > 2) { - number_non_empty_packets_during_increase++; - } - if (!increase_noise && info.encoded_bytes > 2) { - number_non_empty_packets_during_decrease++; - } - } - } - // Check that the refresh DTX packets are just sent during the decrease energy - // region. - EXPECT_EQ(number_non_empty_packets_during_increase, 0); - EXPECT_GT(number_non_empty_packets_during_decrease, 0); -} - } // namespace webrtc diff --git a/modules/audio_coding/codecs/opus/opus_inst.h b/modules/audio_coding/codecs/opus/opus_inst.h index 92c5c354a7..34bb7710e5 100644 --- a/modules/audio_coding/codecs/opus/opus_inst.h +++ b/modules/audio_coding/codecs/opus/opus_inst.h @@ -25,9 +25,7 @@ struct WebRtcOpusEncInst { OpusMSEncoder* multistream_encoder; size_t channels; int in_dtx_mode; - bool avoid_noise_pumping_during_dtx; int sample_rate_hz; - float smooth_energy_non_active_frames; }; struct WebRtcOpusDecInst { diff --git a/modules/audio_coding/codecs/opus/opus_interface.cc b/modules/audio_coding/codecs/opus/opus_interface.cc index a3ba428120..e5ca678120 100644 --- a/modules/audio_coding/codecs/opus/opus_interface.cc +++ b/modules/audio_coding/codecs/opus/opus_interface.cc @@ -38,9 +38,6 @@ enum { constexpr char kPlcUsePrevDecodedSamplesFieldTrial[] = "WebRTC-Audio-OpusPlcUsePrevDecodedSamples"; -constexpr char kAvoidNoisePumpingDuringDtxFieldTrial[] = - "WebRTC-Audio-OpusAvoidNoisePumpingDuringDtx"; - static int FrameSizePerChannel(int frame_size_ms, int sample_rate_hz) { RTC_DCHECK_GT(frame_size_ms, 0); RTC_DCHECK_EQ(frame_size_ms % 10, 0); @@ -59,46 +56,6 @@ static int DefaultFrameSizePerChannel(int sample_rate_hz) { return FrameSizePerChannel(20, sample_rate_hz); } -// Returns true if the `encoded` payload corresponds to a refresh DTX packet -// whose energy is larger than the expected for non activity packets. -static bool WebRtcOpus_IsHighEnergyRefreshDtxPacket( - OpusEncInst* inst, - rtc::ArrayView frame, - rtc::ArrayView encoded) { - if (encoded.size() <= 2) { - return false; - } - int number_frames = - frame.size() / DefaultFrameSizePerChannel(inst->sample_rate_hz); - if (number_frames > 0 && - WebRtcOpus_PacketHasVoiceActivity(encoded.data(), encoded.size()) == 0) { - const float average_frame_energy = - std::accumulate(frame.begin(), frame.end(), 0.0f, - [](float a, int32_t b) { return a + b * b; }) / - number_frames; - if (WebRtcOpus_GetInDtx(inst) == 1 && - average_frame_energy >= inst->smooth_energy_non_active_frames * 0.5f) { - // This is a refresh DTX packet as the encoder is in DTX and has - // produced a payload > 2 bytes. This refresh packet has a higher energy - // than the smooth energy of non activity frames (with a 3 dB negative - // margin) and, therefore, it is flagged as a high energy refresh DTX - // packet. - return true; - } - // The average energy is tracked in a similar way as the modeling of the - // comfort noise in the Silk decoder in Opus - // (third_party/opus/src/silk/CNG.c). - if (average_frame_energy < inst->smooth_energy_non_active_frames * 0.5f) { - inst->smooth_energy_non_active_frames = average_frame_energy; - } else { - inst->smooth_energy_non_active_frames += - (average_frame_energy - inst->smooth_energy_non_active_frames) * - 0.25f; - } - } - return false; -} - int16_t WebRtcOpus_EncoderCreate(OpusEncInst** inst, size_t channels, int32_t application, @@ -134,9 +91,6 @@ int16_t WebRtcOpus_EncoderCreate(OpusEncInst** inst, state->in_dtx_mode = 0; state->channels = channels; state->sample_rate_hz = sample_rate_hz; - state->smooth_energy_non_active_frames = 0.0f; - state->avoid_noise_pumping_during_dtx = - webrtc::field_trial::IsEnabled(kAvoidNoisePumpingDuringDtxFieldTrial); *inst = state; return 0; @@ -182,8 +136,6 @@ int16_t WebRtcOpus_MultistreamEncoderCreate( state->in_dtx_mode = 0; state->channels = channels; state->sample_rate_hz = sample_rate_hz; - state->smooth_energy_non_active_frames = 0.0f; - state->avoid_noise_pumping_during_dtx = false; *inst = state; return 0; @@ -241,21 +193,6 @@ int WebRtcOpus_Encode(OpusEncInst* inst, } } - if (inst->avoid_noise_pumping_during_dtx && WebRtcOpus_GetUseDtx(inst) == 1 && - WebRtcOpus_IsHighEnergyRefreshDtxPacket( - inst, rtc::MakeArrayView(audio_in, samples), - rtc::MakeArrayView(encoded, res))) { - // This packet is a high energy refresh DTX packet. For avoiding an increase - // of the energy in the DTX region at the decoder, this packet is - // substituted by a TOC byte with one empty frame. - // The number of frames described in the TOC byte - // (https://tools.ietf.org/html/rfc6716#section-3.1) are overwritten to - // always indicate one frame (last two bits equal to 0). - encoded[0] = encoded[0] & 0b11111100; - inst->in_dtx_mode = 1; - // The payload is just the TOC byte and has 1 byte as length. - return 1; - } inst->in_dtx_mode = 0; return res; } @@ -438,19 +375,6 @@ int16_t WebRtcOpus_SetForceChannels(OpusEncInst* inst, size_t num_channels) { } } -int32_t WebRtcOpus_GetInDtx(OpusEncInst* inst) { - if (!inst) { - return -1; - } -#ifdef OPUS_GET_IN_DTX - int32_t in_dtx; - if (ENCODER_CTL(inst, OPUS_GET_IN_DTX(&in_dtx)) == 0) { - return in_dtx; - } -#endif - return -1; -} - int16_t WebRtcOpus_DecoderCreate(OpusDecInst** inst, size_t channels, int sample_rate_hz) { diff --git a/modules/audio_coding/codecs/opus/opus_interface.h b/modules/audio_coding/codecs/opus/opus_interface.h index 89159ce1c0..83f8cbe929 100644 --- a/modules/audio_coding/codecs/opus/opus_interface.h +++ b/modules/audio_coding/codecs/opus/opus_interface.h @@ -320,20 +320,6 @@ int32_t WebRtcOpus_GetBandwidth(OpusEncInst* inst); */ int16_t WebRtcOpus_SetBandwidth(OpusEncInst* inst, int32_t bandwidth); -/* - * WebRtcOpus_GetInDtx(...) - * - * Gets the DTX state of the encoder. - * - * Input: - * - inst : Encoder context - * - * Return value : -1 - Error. - * 1 - Last encoded frame was comfort noise update during DTX. - * 0 - Last encoded frame was encoded with encoder not in DTX. - */ -int32_t WebRtcOpus_GetInDtx(OpusEncInst* inst); - /* * WebRtcOpus_SetForceChannels(...) *