Make Opus PLC always output 10ms audio.
BUG: b/143582588 Change-Id: I41ad5f4f91d9af3f595666a8f32b7ab5382605bd Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/158672 Commit-Queue: Minyue Li <minyue@webrtc.org> Reviewed-by: Jakob Ivarsson <jakobi@webrtc.org> Reviewed-by: Henrik Lundin <henrik.lundin@webrtc.org> Cr-Commit-Position: refs/heads/master@{#29733}
This commit is contained in:
@ -840,6 +840,7 @@ rtc_library("webrtc_opus_wrapper") {
|
|||||||
"../../rtc_base:checks",
|
"../../rtc_base:checks",
|
||||||
"../../rtc_base:ignore_wundef",
|
"../../rtc_base:ignore_wundef",
|
||||||
"../../rtc_base:rtc_base_approved",
|
"../../rtc_base:rtc_base_approved",
|
||||||
|
"../../system_wrappers:field_trial",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -154,8 +154,13 @@ void OpusFecTest::DecodeABlock(bool lost_previous, bool lost_current) {
|
|||||||
WebRtcOpus_DecodeFec(opus_decoder_, &bit_stream_[0], encoded_bytes_,
|
WebRtcOpus_DecodeFec(opus_decoder_, &bit_stream_[0], encoded_bytes_,
|
||||||
&out_data_[0], &audio_type);
|
&out_data_[0], &audio_type);
|
||||||
} else {
|
} else {
|
||||||
value_1 =
|
// Call decoder PLC.
|
||||||
WebRtcOpus_Decode(opus_decoder_, NULL, 0, &out_data_[0], &audio_type);
|
while (value_1 < static_cast<int>(block_length_sample_)) {
|
||||||
|
int ret = WebRtcOpus_Decode(opus_decoder_, NULL, 0, &out_data_[value_1],
|
||||||
|
&audio_type);
|
||||||
|
EXPECT_EQ(ret, sampling_khz_ * 10); // Should return 10 ms of samples.
|
||||||
|
value_1 += ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
EXPECT_EQ(static_cast<int>(block_length_sample_), value_1);
|
EXPECT_EQ(static_cast<int>(block_length_sample_), value_1);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,6 +31,7 @@ struct WebRtcOpusDecInst {
|
|||||||
OpusDecoder* decoder;
|
OpusDecoder* decoder;
|
||||||
OpusMSDecoder* multistream_decoder;
|
OpusMSDecoder* multistream_decoder;
|
||||||
int prev_decoded_samples;
|
int prev_decoded_samples;
|
||||||
|
bool plc_use_prev_decoded_samples;
|
||||||
size_t channels;
|
size_t channels;
|
||||||
int in_dtx_mode;
|
int in_dtx_mode;
|
||||||
int sample_rate_hz;
|
int sample_rate_hz;
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
#include "modules/audio_coding/codecs/opus/opus_interface.h"
|
#include "modules/audio_coding/codecs/opus/opus_interface.h"
|
||||||
|
|
||||||
#include "rtc_base/checks.h"
|
#include "rtc_base/checks.h"
|
||||||
|
#include "system_wrappers/include/field_trial.h"
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
#if WEBRTC_OPUS_SUPPORT_120MS_PTIME
|
#if WEBRTC_OPUS_SUPPORT_120MS_PTIME
|
||||||
@ -25,8 +26,14 @@ enum {
|
|||||||
* side, we must allow for packets of that size. NetEq is currently limited
|
* side, we must allow for packets of that size. NetEq is currently limited
|
||||||
* to 60 ms on the receive side. */
|
* to 60 ms on the receive side. */
|
||||||
kWebRtcOpusMaxDecodeFrameSizeMs = 120,
|
kWebRtcOpusMaxDecodeFrameSizeMs = 120,
|
||||||
|
|
||||||
|
// Duration of audio that each call to packet loss concealment covers.
|
||||||
|
kWebRtcOpusPlcFrameSizeMs = 10,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr char kPlcUsePrevDecodedSamplesFieldTrial[] =
|
||||||
|
"WebRTC-Audio-OpusPlcUsePrevDecodedSamples";
|
||||||
|
|
||||||
static int FrameSizePerChannel(int frame_size_ms, int sample_rate_hz) {
|
static int FrameSizePerChannel(int frame_size_ms, int sample_rate_hz) {
|
||||||
RTC_DCHECK_GT(frame_size_ms, 0);
|
RTC_DCHECK_GT(frame_size_ms, 0);
|
||||||
RTC_DCHECK_EQ(frame_size_ms % 10, 0);
|
RTC_DCHECK_EQ(frame_size_ms % 10, 0);
|
||||||
@ -381,9 +388,14 @@ int16_t WebRtcOpus_DecoderCreate(OpusDecInst** inst,
|
|||||||
if (error == OPUS_OK && state->decoder) {
|
if (error == OPUS_OK && state->decoder) {
|
||||||
// Creation of memory all ok.
|
// Creation of memory all ok.
|
||||||
state->channels = channels;
|
state->channels = channels;
|
||||||
state->prev_decoded_samples = DefaultFrameSizePerChannel(sample_rate_hz);
|
|
||||||
state->in_dtx_mode = 0;
|
|
||||||
state->sample_rate_hz = sample_rate_hz;
|
state->sample_rate_hz = sample_rate_hz;
|
||||||
|
state->plc_use_prev_decoded_samples =
|
||||||
|
webrtc::field_trial::IsEnabled(kPlcUsePrevDecodedSamplesFieldTrial);
|
||||||
|
if (state->plc_use_prev_decoded_samples) {
|
||||||
|
state->prev_decoded_samples =
|
||||||
|
DefaultFrameSizePerChannel(state->sample_rate_hz);
|
||||||
|
}
|
||||||
|
state->in_dtx_mode = 0;
|
||||||
*inst = state;
|
*inst = state;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -420,9 +432,14 @@ int16_t WebRtcOpus_MultistreamDecoderCreate(
|
|||||||
if (error == OPUS_OK && state->multistream_decoder) {
|
if (error == OPUS_OK && state->multistream_decoder) {
|
||||||
// Creation of memory all ok.
|
// Creation of memory all ok.
|
||||||
state->channels = channels;
|
state->channels = channels;
|
||||||
state->prev_decoded_samples = DefaultFrameSizePerChannel(48000);
|
|
||||||
state->in_dtx_mode = 0;
|
|
||||||
state->sample_rate_hz = 48000;
|
state->sample_rate_hz = 48000;
|
||||||
|
state->plc_use_prev_decoded_samples =
|
||||||
|
webrtc::field_trial::IsEnabled(kPlcUsePrevDecodedSamplesFieldTrial);
|
||||||
|
if (state->plc_use_prev_decoded_samples) {
|
||||||
|
state->prev_decoded_samples =
|
||||||
|
DefaultFrameSizePerChannel(state->sample_rate_hz);
|
||||||
|
}
|
||||||
|
state->in_dtx_mode = 0;
|
||||||
*inst = state;
|
*inst = state;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -517,8 +534,10 @@ static int DecodeNative(OpusDecInst* inst,
|
|||||||
static int DecodePlc(OpusDecInst* inst, int16_t* decoded) {
|
static int DecodePlc(OpusDecInst* inst, int16_t* decoded) {
|
||||||
int16_t audio_type = 0;
|
int16_t audio_type = 0;
|
||||||
int decoded_samples;
|
int decoded_samples;
|
||||||
int plc_samples;
|
int plc_samples =
|
||||||
|
FrameSizePerChannel(kWebRtcOpusPlcFrameSizeMs, inst->sample_rate_hz);
|
||||||
|
|
||||||
|
if (inst->plc_use_prev_decoded_samples) {
|
||||||
/* The number of samples we ask for is |number_of_lost_frames| times
|
/* The number of samples we ask for is |number_of_lost_frames| times
|
||||||
* |prev_decoded_samples_|. Limit the number of samples to maximum
|
* |prev_decoded_samples_|. Limit the number of samples to maximum
|
||||||
* |MaxFrameSizePerChannel()|. */
|
* |MaxFrameSizePerChannel()|. */
|
||||||
@ -528,6 +547,7 @@ static int DecodePlc(OpusDecInst* inst, int16_t* decoded) {
|
|||||||
plc_samples = plc_samples <= max_samples_per_channel
|
plc_samples = plc_samples <= max_samples_per_channel
|
||||||
? plc_samples
|
? plc_samples
|
||||||
: max_samples_per_channel;
|
: max_samples_per_channel;
|
||||||
|
}
|
||||||
decoded_samples =
|
decoded_samples =
|
||||||
DecodeNative(inst, NULL, 0, plc_samples, decoded, &audio_type, 0);
|
DecodeNative(inst, NULL, 0, plc_samples, decoded, &audio_type, 0);
|
||||||
if (decoded_samples < 0) {
|
if (decoded_samples < 0) {
|
||||||
@ -556,8 +576,10 @@ int WebRtcOpus_Decode(OpusDecInst* inst,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (inst->plc_use_prev_decoded_samples) {
|
||||||
/* Update decoded sample memory, to be used by the PLC in case of losses. */
|
/* Update decoded sample memory, to be used by the PLC in case of losses. */
|
||||||
inst->prev_decoded_samples = decoded_samples;
|
inst->prev_decoded_samples = decoded_samples;
|
||||||
|
}
|
||||||
|
|
||||||
return decoded_samples;
|
return decoded_samples;
|
||||||
}
|
}
|
||||||
@ -612,6 +634,7 @@ int WebRtcOpus_DurationEst(OpusDecInst* inst,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int WebRtcOpus_PlcDuration(OpusDecInst* inst) {
|
int WebRtcOpus_PlcDuration(OpusDecInst* inst) {
|
||||||
|
if (inst->plc_use_prev_decoded_samples) {
|
||||||
/* The number of samples we ask for is |number_of_lost_frames| times
|
/* The number of samples we ask for is |number_of_lost_frames| times
|
||||||
* |prev_decoded_samples_|. Limit the number of samples to maximum
|
* |prev_decoded_samples_|. Limit the number of samples to maximum
|
||||||
* |MaxFrameSizePerChannel()|. */
|
* |MaxFrameSizePerChannel()|. */
|
||||||
@ -621,6 +644,8 @@ int WebRtcOpus_PlcDuration(OpusDecInst* inst) {
|
|||||||
return plc_samples <= max_samples_per_channel ? plc_samples
|
return plc_samples <= max_samples_per_channel ? plc_samples
|
||||||
: max_samples_per_channel;
|
: max_samples_per_channel;
|
||||||
}
|
}
|
||||||
|
return FrameSizePerChannel(kWebRtcOpusPlcFrameSizeMs, inst->sample_rate_hz);
|
||||||
|
}
|
||||||
|
|
||||||
int WebRtcOpus_FecDurationEst(const uint8_t* payload,
|
int WebRtcOpus_FecDurationEst(const uint8_t* payload,
|
||||||
size_t payload_length_bytes,
|
size_t payload_length_bytes,
|
||||||
|
|||||||
@ -213,17 +213,34 @@ int OpusTest::EncodeDecode(WebRtcOpusEncInst* encoder,
|
|||||||
WebRtcOpusDecInst* decoder,
|
WebRtcOpusDecInst* decoder,
|
||||||
int16_t* output_audio,
|
int16_t* output_audio,
|
||||||
int16_t* audio_type) {
|
int16_t* audio_type) {
|
||||||
|
const int input_samples_per_channel =
|
||||||
|
rtc::CheckedDivExact(input_audio.size(), channels_);
|
||||||
int encoded_bytes_int =
|
int encoded_bytes_int =
|
||||||
WebRtcOpus_Encode(encoder, input_audio.data(),
|
WebRtcOpus_Encode(encoder, input_audio.data(), input_samples_per_channel,
|
||||||
rtc::CheckedDivExact(input_audio.size(), channels_),
|
|
||||||
kMaxBytes, bitstream_);
|
kMaxBytes, bitstream_);
|
||||||
EXPECT_GE(encoded_bytes_int, 0);
|
EXPECT_GE(encoded_bytes_int, 0);
|
||||||
encoded_bytes_ = static_cast<size_t>(encoded_bytes_int);
|
encoded_bytes_ = static_cast<size_t>(encoded_bytes_int);
|
||||||
|
if (encoded_bytes_ != 0) {
|
||||||
int est_len = WebRtcOpus_DurationEst(decoder, bitstream_, encoded_bytes_);
|
int est_len = WebRtcOpus_DurationEst(decoder, bitstream_, encoded_bytes_);
|
||||||
int act_len = WebRtcOpus_Decode(decoder, bitstream_, encoded_bytes_,
|
int act_len = WebRtcOpus_Decode(decoder, bitstream_, encoded_bytes_,
|
||||||
output_audio, audio_type);
|
output_audio, audio_type);
|
||||||
EXPECT_EQ(est_len, act_len);
|
EXPECT_EQ(est_len, act_len);
|
||||||
return act_len;
|
return act_len;
|
||||||
|
} else {
|
||||||
|
int total_dtx_len = 0;
|
||||||
|
const int output_samples_per_channel = input_samples_per_channel *
|
||||||
|
decoder_sample_rate_hz_ /
|
||||||
|
encoder_sample_rate_hz_;
|
||||||
|
while (total_dtx_len < output_samples_per_channel) {
|
||||||
|
int est_len = WebRtcOpus_DurationEst(decoder, NULL, 0);
|
||||||
|
int act_len = WebRtcOpus_Decode(decoder, NULL, 0,
|
||||||
|
&output_audio[total_dtx_len * channels_],
|
||||||
|
audio_type);
|
||||||
|
EXPECT_EQ(est_len, act_len);
|
||||||
|
total_dtx_len += act_len;
|
||||||
|
}
|
||||||
|
return total_dtx_len;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test if encoder/decoder can enter DTX mode properly and do not enter DTX when
|
// Test if encoder/decoder can enter DTX mode properly and do not enter DTX when
|
||||||
@ -808,8 +825,10 @@ TEST_P(OpusTest, OpusDecodePlc) {
|
|||||||
opus_decoder_, output_data_decode, &audio_type));
|
opus_decoder_, output_data_decode, &audio_type));
|
||||||
|
|
||||||
// Call decoder PLC.
|
// Call decoder PLC.
|
||||||
int16_t* plc_buffer = new int16_t[decode_samples_per_channel * channels_];
|
constexpr int kPlcDurationMs = 10;
|
||||||
EXPECT_EQ(decode_samples_per_channel,
|
const int plc_samples = decoder_sample_rate_hz_ * kPlcDurationMs / 1000;
|
||||||
|
int16_t* plc_buffer = new int16_t[plc_samples * channels_];
|
||||||
|
EXPECT_EQ(plc_samples,
|
||||||
WebRtcOpus_Decode(opus_decoder_, NULL, 0, plc_buffer, &audio_type));
|
WebRtcOpus_Decode(opus_decoder_, NULL, 0, plc_buffer, &audio_type));
|
||||||
|
|
||||||
// Free memory.
|
// Free memory.
|
||||||
|
|||||||
@ -508,11 +508,11 @@ TEST_F(NetEqDecodingTest, MAYBE_TestOpusDtxBitExactness) {
|
|||||||
webrtc::test::ResourcePath("audio_coding/neteq_opus_dtx", "rtp");
|
webrtc::test::ResourcePath("audio_coding/neteq_opus_dtx", "rtp");
|
||||||
|
|
||||||
const std::string maybe_sse =
|
const std::string maybe_sse =
|
||||||
"713af6c92881f5aab1285765ee6680da9d1c06ce|"
|
"0bdeb4ccf95a2577e38274360903ad099fc46787|"
|
||||||
"2ac10c4e79aeedd0df2863b079da5848b40f00b5";
|
"f7bbf5d92a0595a2a3445ffbaddfb20e98b6e94e";
|
||||||
const std::string output_checksum = PlatformChecksum(
|
const std::string output_checksum = PlatformChecksum(
|
||||||
maybe_sse, "3ec991b96872123f1554c03c543ca5d518431e46",
|
maybe_sse, "6d200cc51a001b6137abf67db2bb8eeb0375cdee",
|
||||||
"da9f9a2d94e0c2d67342fad4965d7b91cda50b25", maybe_sse, maybe_sse);
|
"36d43761de86b12520cf2e63f97372a2b7c6f939", maybe_sse, maybe_sse);
|
||||||
|
|
||||||
const std::string network_stats_checksum =
|
const std::string network_stats_checksum =
|
||||||
"8caf49765f35b6862066d3f17531ce44d8e25f60";
|
"8caf49765f35b6862066d3f17531ce44d8e25f60";
|
||||||
|
|||||||
@ -299,9 +299,19 @@ void OpusTest::Run(TestPackStereo* channel,
|
|||||||
opus_mono_decoder_, bitstream, bitstream_len_byte,
|
opus_mono_decoder_, bitstream, bitstream_len_byte,
|
||||||
&out_audio[decoded_samples * channels], &audio_type);
|
&out_audio[decoded_samples * channels], &audio_type);
|
||||||
} else {
|
} else {
|
||||||
decoded_samples += WebRtcOpus_Decode(
|
// Call decoder PLC.
|
||||||
|
constexpr int kPlcDurationMs = 10;
|
||||||
|
constexpr int kPlcSamples = 48 * kPlcDurationMs;
|
||||||
|
size_t total_plc_samples = 0;
|
||||||
|
while (total_plc_samples < frame_length) {
|
||||||
|
int ret = WebRtcOpus_Decode(
|
||||||
opus_mono_decoder_, NULL, 0,
|
opus_mono_decoder_, NULL, 0,
|
||||||
&out_audio[decoded_samples * channels], &audio_type);
|
&out_audio[decoded_samples * channels], &audio_type);
|
||||||
|
EXPECT_EQ(ret, kPlcSamples);
|
||||||
|
decoded_samples += ret;
|
||||||
|
total_plc_samples += ret;
|
||||||
|
}
|
||||||
|
EXPECT_EQ(total_plc_samples, frame_length);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!lost_packet) {
|
if (!lost_packet) {
|
||||||
@ -309,9 +319,19 @@ void OpusTest::Run(TestPackStereo* channel,
|
|||||||
opus_stereo_decoder_, bitstream, bitstream_len_byte,
|
opus_stereo_decoder_, bitstream, bitstream_len_byte,
|
||||||
&out_audio[decoded_samples * channels], &audio_type);
|
&out_audio[decoded_samples * channels], &audio_type);
|
||||||
} else {
|
} else {
|
||||||
decoded_samples += WebRtcOpus_Decode(
|
// Call decoder PLC.
|
||||||
|
constexpr int kPlcDurationMs = 10;
|
||||||
|
constexpr int kPlcSamples = 48 * kPlcDurationMs;
|
||||||
|
size_t total_plc_samples = 0;
|
||||||
|
while (total_plc_samples < frame_length) {
|
||||||
|
int ret = WebRtcOpus_Decode(
|
||||||
opus_stereo_decoder_, NULL, 0,
|
opus_stereo_decoder_, NULL, 0,
|
||||||
&out_audio[decoded_samples * channels], &audio_type);
|
&out_audio[decoded_samples * channels], &audio_type);
|
||||||
|
EXPECT_EQ(ret, kPlcSamples);
|
||||||
|
decoded_samples += ret;
|
||||||
|
total_plc_samples += ret;
|
||||||
|
}
|
||||||
|
EXPECT_EQ(total_plc_samples, frame_length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user