aboutsummaryrefslogtreecommitdiff
path: root/webrtc/modules/audio_coding/codecs/opus
diff options
context:
space:
mode:
Diffstat (limited to 'webrtc/modules/audio_coding/codecs/opus')
-rw-r--r--webrtc/modules/audio_coding/codecs/opus/audio_decoder_opus.cc4
-rw-r--r--webrtc/modules/audio_coding/codecs/opus/audio_decoder_opus.h (renamed from webrtc/modules/audio_coding/codecs/opus/include/audio_decoder_opus.h)8
-rw-r--r--webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc28
-rw-r--r--webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h (renamed from webrtc/modules/audio_coding/codecs/opus/include/audio_encoder_opus.h)18
-rw-r--r--webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc2
-rw-r--r--webrtc/modules/audio_coding/codecs/opus/opus.gypi12
-rw-r--r--webrtc/modules/audio_coding/codecs/opus/opus_fec_test.cc9
-rw-r--r--webrtc/modules/audio_coding/codecs/opus/opus_inst.h11
-rw-r--r--webrtc/modules/audio_coding/codecs/opus/opus_interface.c115
-rw-r--r--webrtc/modules/audio_coding/codecs/opus/opus_interface.h (renamed from webrtc/modules/audio_coding/codecs/opus/include/opus_interface.h)12
-rw-r--r--webrtc/modules/audio_coding/codecs/opus/opus_speed_test.cc4
-rw-r--r--webrtc/modules/audio_coding/codecs/opus/opus_unittest.cc190
12 files changed, 253 insertions, 160 deletions
diff --git a/webrtc/modules/audio_coding/codecs/opus/audio_decoder_opus.cc b/webrtc/modules/audio_coding/codecs/opus/audio_decoder_opus.cc
index d1390e2ca4..f64e811afe 100644
--- a/webrtc/modules/audio_coding/codecs/opus/audio_decoder_opus.cc
+++ b/webrtc/modules/audio_coding/codecs/opus/audio_decoder_opus.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_coding/codecs/opus/include/audio_decoder_opus.h"
+#include "webrtc/modules/audio_coding/codecs/opus/audio_decoder_opus.h"
#include "webrtc/base/checks.h"
@@ -17,7 +17,7 @@ namespace webrtc {
AudioDecoderOpus::AudioDecoderOpus(size_t num_channels)
: channels_(num_channels) {
RTC_DCHECK(num_channels == 1 || num_channels == 2);
- WebRtcOpus_DecoderCreate(&dec_state_, static_cast<int>(channels_));
+ WebRtcOpus_DecoderCreate(&dec_state_, channels_);
WebRtcOpus_DecoderInit(dec_state_);
}
diff --git a/webrtc/modules/audio_coding/codecs/opus/include/audio_decoder_opus.h b/webrtc/modules/audio_coding/codecs/opus/audio_decoder_opus.h
index 6b0a88ae97..af32a84512 100644
--- a/webrtc/modules/audio_coding/codecs/opus/include/audio_decoder_opus.h
+++ b/webrtc/modules/audio_coding/codecs/opus/audio_decoder_opus.h
@@ -8,11 +8,11 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_OPUS_INCLUDE_AUDIO_DECODER_OPUS_H
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_OPUS_INCLUDE_AUDIO_DECODER_OPUS_H
+#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_OPUS_AUDIO_DECODER_OPUS_H_
+#define WEBRTC_MODULES_AUDIO_CODING_CODECS_OPUS_AUDIO_DECODER_OPUS_H_
#include "webrtc/modules/audio_coding/codecs/audio_decoder.h"
-#include "webrtc/modules/audio_coding/codecs/opus/include/opus_interface.h"
+#include "webrtc/modules/audio_coding/codecs/opus/opus_interface.h"
namespace webrtc {
@@ -48,4 +48,4 @@ class AudioDecoderOpus final : public AudioDecoder {
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_OPUS_INCLUDE_AUDIO_DECODER_OPUS_H
+#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_OPUS_AUDIO_DECODER_OPUS_H_
diff --git a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc
index eac7412178..707d6c2488 100644
--- a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc
+++ b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc
@@ -8,12 +8,12 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_coding/codecs/opus/include/audio_encoder_opus.h"
+#include "webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h"
#include "webrtc/base/checks.h"
#include "webrtc/base/safe_conversions.h"
#include "webrtc/common_types.h"
-#include "webrtc/modules/audio_coding/codecs/opus/include/opus_interface.h"
+#include "webrtc/modules/audio_coding/codecs/opus/opus_interface.h"
namespace webrtc {
@@ -114,7 +114,7 @@ int AudioEncoderOpus::SampleRateHz() const {
return kSampleRateHz;
}
-int AudioEncoderOpus::NumChannels() const {
+size_t AudioEncoderOpus::NumChannels() const {
return config_.num_channels;
}
@@ -132,24 +132,22 @@ int AudioEncoderOpus::GetTargetBitrate() const {
AudioEncoder::EncodedInfo AudioEncoderOpus::EncodeInternal(
uint32_t rtp_timestamp,
- const int16_t* audio,
+ rtc::ArrayView<const int16_t> audio,
size_t max_encoded_bytes,
uint8_t* encoded) {
if (input_buffer_.empty())
first_timestamp_in_buffer_ = rtp_timestamp;
- input_buffer_.insert(input_buffer_.end(), audio,
- audio + SamplesPer10msFrame());
+ RTC_DCHECK_EQ(SamplesPer10msFrame(), audio.size());
+ input_buffer_.insert(input_buffer_.end(), audio.cbegin(), audio.cend());
if (input_buffer_.size() <
- (static_cast<size_t>(Num10msFramesPerPacket()) * SamplesPer10msFrame())) {
+ (Num10msFramesPerPacket() * SamplesPer10msFrame())) {
return EncodedInfo();
}
- RTC_CHECK_EQ(
- input_buffer_.size(),
- static_cast<size_t>(Num10msFramesPerPacket()) * SamplesPer10msFrame());
+ RTC_CHECK_EQ(input_buffer_.size(),
+ Num10msFramesPerPacket() * SamplesPer10msFrame());
int status = WebRtcOpus_Encode(
inst_, &input_buffer_[0],
- rtc::CheckedDivExact(input_buffer_.size(),
- static_cast<size_t>(config_.num_channels)),
+ rtc::CheckedDivExact(input_buffer_.size(), config_.num_channels),
rtc::saturated_cast<int16_t>(max_encoded_bytes), encoded);
RTC_CHECK_GE(status, 0); // Fails only if fed invalid data.
input_buffer_.clear();
@@ -214,11 +212,11 @@ void AudioEncoderOpus::SetTargetBitrate(int bits_per_second) {
RTC_CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, config_.bitrate_bps));
}
-int AudioEncoderOpus::Num10msFramesPerPacket() const {
- return rtc::CheckedDivExact(config_.frame_size_ms, 10);
+size_t AudioEncoderOpus::Num10msFramesPerPacket() const {
+ return static_cast<size_t>(rtc::CheckedDivExact(config_.frame_size_ms, 10));
}
-int AudioEncoderOpus::SamplesPer10msFrame() const {
+size_t AudioEncoderOpus::SamplesPer10msFrame() const {
return rtc::CheckedDivExact(kSampleRateHz, 100) * config_.num_channels;
}
diff --git a/webrtc/modules/audio_coding/codecs/opus/include/audio_encoder_opus.h b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h
index 7f2b563fd9..59c8f796ee 100644
--- a/webrtc/modules/audio_coding/codecs/opus/include/audio_encoder_opus.h
+++ b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h
@@ -8,13 +8,13 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_OPUS_INCLUDE_AUDIO_ENCODER_OPUS_H_
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_OPUS_INCLUDE_AUDIO_ENCODER_OPUS_H_
+#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_OPUS_AUDIO_ENCODER_OPUS_H_
+#define WEBRTC_MODULES_AUDIO_CODING_CODECS_OPUS_AUDIO_ENCODER_OPUS_H_
#include <vector>
#include "webrtc/base/constructormagic.h"
-#include "webrtc/modules/audio_coding/codecs/opus/include/opus_interface.h"
+#include "webrtc/modules/audio_coding/codecs/opus/opus_interface.h"
#include "webrtc/modules/audio_coding/codecs/audio_encoder.h"
namespace webrtc {
@@ -31,7 +31,7 @@ class AudioEncoderOpus final : public AudioEncoder {
struct Config {
bool IsOk() const;
int frame_size_ms = 20;
- int num_channels = 1;
+ size_t num_channels = 1;
int payload_type = 120;
ApplicationMode application = kVoip;
int bitrate_bps = 64000;
@@ -56,13 +56,13 @@ class AudioEncoderOpus final : public AudioEncoder {
size_t MaxEncodedBytes() const override;
int SampleRateHz() const override;
- int NumChannels() const override;
+ size_t NumChannels() const override;
size_t Num10MsFramesInNextPacket() const override;
size_t Max10MsFramesInAPacket() const override;
int GetTargetBitrate() const override;
EncodedInfo EncodeInternal(uint32_t rtp_timestamp,
- const int16_t* audio,
+ rtc::ArrayView<const int16_t> audio,
size_t max_encoded_bytes,
uint8_t* encoded) override;
@@ -85,8 +85,8 @@ class AudioEncoderOpus final : public AudioEncoder {
bool dtx_enabled() const { return config_.dtx_enabled; }
private:
- int Num10msFramesPerPacket() const;
- int SamplesPer10msFrame() const;
+ size_t Num10msFramesPerPacket() const;
+ size_t SamplesPer10msFrame() const;
bool RecreateEncoderInstance(const Config& config);
Config config_;
@@ -99,4 +99,4 @@ class AudioEncoderOpus final : public AudioEncoder {
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_OPUS_INCLUDE_AUDIO_ENCODER_OPUS_H_
+#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_OPUS_AUDIO_ENCODER_OPUS_H_
diff --git a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc
index e69f259554..441e807b4f 100644
--- a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc
+++ b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc
@@ -12,7 +12,7 @@
#include "webrtc/base/checks.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/common_types.h"
-#include "webrtc/modules/audio_coding/codecs/opus/include/audio_encoder_opus.h"
+#include "webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h"
namespace webrtc {
diff --git a/webrtc/modules/audio_coding/codecs/opus/opus.gypi b/webrtc/modules/audio_coding/codecs/opus/opus.gypi
index 05da3e5e47..d7454d632d 100644
--- a/webrtc/modules/audio_coding/codecs/opus/opus.gypi
+++ b/webrtc/modules/audio_coding/codecs/opus/opus.gypi
@@ -39,17 +39,14 @@
'dependencies': [
'audio_encoder_interface',
],
- 'include_dirs': [
- '<(webrtc_root)',
- ],
'sources': [
'audio_decoder_opus.cc',
+ 'audio_decoder_opus.h',
'audio_encoder_opus.cc',
- 'include/audio_decoder_opus.h',
- 'include/audio_encoder_opus.h',
- 'include/opus_interface.h',
+ 'audio_encoder_opus.h',
'opus_inst.h',
'opus_interface.c',
+ 'opus_interface.h',
],
},
],
@@ -65,9 +62,6 @@
'<(webrtc_root)/test/test.gyp:test_support_main',
'<(DEPTH)/testing/gtest.gyp:gtest',
],
- 'include_dirs': [
- '<(webrtc_root)',
- ],
'sources': [
'opus_fec_test.cc',
],
diff --git a/webrtc/modules/audio_coding/codecs/opus/opus_fec_test.cc b/webrtc/modules/audio_coding/codecs/opus/opus_fec_test.cc
index f257210431..4f9f7ff7bb 100644
--- a/webrtc/modules/audio_coding/codecs/opus/opus_fec_test.cc
+++ b/webrtc/modules/audio_coding/codecs/opus/opus_fec_test.cc
@@ -9,8 +9,9 @@
*/
#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/base/format_macros.h"
#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/modules/audio_coding/codecs/opus/include/opus_interface.h"
+#include "webrtc/modules/audio_coding/codecs/opus/opus_interface.h"
#include "webrtc/test/testsupport/fileutils.h"
using ::std::string;
@@ -21,7 +22,7 @@ using ::testing::TestWithParam;
namespace webrtc {
// Define coding parameter as <channels, bit_rate, filename, extension>.
-typedef tuple<int, int, string, string> coding_param;
+typedef tuple<size_t, int, string, string> coding_param;
typedef struct mode mode;
struct mode {
@@ -47,7 +48,7 @@ class OpusFecTest : public TestWithParam<coding_param> {
int sampling_khz_;
size_t block_length_sample_;
- int channels_;
+ size_t channels_;
int bit_rate_;
size_t data_pointer_;
@@ -68,7 +69,7 @@ class OpusFecTest : public TestWithParam<coding_param> {
void OpusFecTest::SetUp() {
channels_ = get<0>(GetParam());
bit_rate_ = get<1>(GetParam());
- printf("Coding %d channel signal at %d bps.\n", channels_, bit_rate_);
+ printf("Coding %" PRIuS " channel signal at %d bps.\n", channels_, bit_rate_);
in_filename_ = test::ResourcePath(get<2>(GetParam()), get<3>(GetParam()));
diff --git a/webrtc/modules/audio_coding/codecs/opus/opus_inst.h b/webrtc/modules/audio_coding/codecs/opus/opus_inst.h
index 373db392a6..8d032baf35 100644
--- a/webrtc/modules/audio_coding/codecs/opus/opus_inst.h
+++ b/webrtc/modules/audio_coding/codecs/opus/opus_inst.h
@@ -11,17 +11,26 @@
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_OPUS_OPUS_INST_H_
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_OPUS_OPUS_INST_H_
+#include <stddef.h>
+
#include "opus.h"
struct WebRtcOpusEncInst {
OpusEncoder* encoder;
+ size_t channels;
int in_dtx_mode;
+ // When Opus is in DTX mode, we use |zero_counts| to count consecutive zeros
+ // to break long zero segment so as to prevent DTX from going wrong. We use
+ // one counter for each channel. After each encoding, |zero_counts| contain
+ // the remaining zeros from the last frame.
+ // TODO(minyue): remove this when Opus gets an internal fix to DTX.
+ size_t* zero_counts;
};
struct WebRtcOpusDecInst {
OpusDecoder* decoder;
int prev_decoded_samples;
- int channels;
+ size_t channels;
int in_dtx_mode;
};
diff --git a/webrtc/modules/audio_coding/codecs/opus/opus_interface.c b/webrtc/modules/audio_coding/codecs/opus/opus_interface.c
index 1a632422c5..9dc7ef95fe 100644
--- a/webrtc/modules/audio_coding/codecs/opus/opus_interface.c
+++ b/webrtc/modules/audio_coding/codecs/opus/opus_interface.c
@@ -8,9 +8,10 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_coding/codecs/opus/include/opus_interface.h"
+#include "webrtc/modules/audio_coding/codecs/opus/opus_interface.h"
#include "webrtc/modules/audio_coding/codecs/opus/opus_inst.h"
+#include <assert.h>
#include <stdlib.h>
#include <string.h>
@@ -29,48 +30,61 @@ enum {
/* Default frame size, 20 ms @ 48 kHz, in samples (for one channel). */
kWebRtcOpusDefaultFrameSize = 960,
+
+ // Maximum number of consecutive zeros, beyond or equal to which DTX can fail.
+ kZeroBreakCount = 157,
+
+#if defined(OPUS_FIXED_POINT)
+ kZeroBreakValue = 10,
+#else
+ kZeroBreakValue = 1,
+#endif
};
int16_t WebRtcOpus_EncoderCreate(OpusEncInst** inst,
- int32_t channels,
+ size_t channels,
int32_t application) {
- OpusEncInst* state;
- if (inst != NULL) {
- state = (OpusEncInst*) calloc(1, sizeof(OpusEncInst));
- if (state) {
- int opus_app;
- switch (application) {
- case 0: {
- opus_app = OPUS_APPLICATION_VOIP;
- break;
- }
- case 1: {
- opus_app = OPUS_APPLICATION_AUDIO;
- break;
- }
- default: {
- free(state);
- return -1;
- }
- }
+ int opus_app;
+ if (!inst)
+ return -1;
- int error;
- state->encoder = opus_encoder_create(48000, channels, opus_app,
- &error);
- state->in_dtx_mode = 0;
- if (error == OPUS_OK && state->encoder != NULL) {
- *inst = state;
- return 0;
- }
- free(state);
- }
+ switch (application) {
+ case 0:
+ opus_app = OPUS_APPLICATION_VOIP;
+ break;
+ case 1:
+ opus_app = OPUS_APPLICATION_AUDIO;
+ break;
+ default:
+ return -1;
}
- return -1;
+
+ OpusEncInst* state = calloc(1, sizeof(OpusEncInst));
+ assert(state);
+
+ // Allocate zero counters.
+ state->zero_counts = calloc(channels, sizeof(size_t));
+ assert(state->zero_counts);
+
+ int error;
+ state->encoder = opus_encoder_create(48000, (int)channels, opus_app,
+ &error);
+ if (error != OPUS_OK || !state->encoder) {
+ WebRtcOpus_EncoderFree(state);
+ return -1;
+ }
+
+ state->in_dtx_mode = 0;
+ state->channels = channels;
+
+ *inst = state;
+ return 0;
}
int16_t WebRtcOpus_EncoderFree(OpusEncInst* inst) {
if (inst) {
opus_encoder_destroy(inst->encoder);
+ free(inst->zero_counts);
free(inst);
return 0;
} else {
@@ -84,13 +98,42 @@ int WebRtcOpus_Encode(OpusEncInst* inst,
size_t length_encoded_buffer,
uint8_t* encoded) {
int res;
+ size_t i;
+ size_t c;
+
+ int16_t buffer[2 * 48 * kWebRtcOpusMaxEncodeFrameSizeMs];
if (samples > 48 * kWebRtcOpusMaxEncodeFrameSizeMs) {
return -1;
}
+ const size_t channels = inst->channels;
+ int use_buffer = 0;
+
+ // Break long consecutive zeros by forcing a "1" every |kZeroBreakCount|
+ // samples.
+ if (inst->in_dtx_mode) {
+ for (i = 0; i < samples; ++i) {
+ for (c = 0; c < channels; ++c) {
+ if (audio_in[i * channels + c] == 0) {
+ ++inst->zero_counts[c];
+ if (inst->zero_counts[c] == kZeroBreakCount) {
+ if (!use_buffer) {
+ memcpy(buffer, audio_in, samples * channels * sizeof(int16_t));
+ use_buffer = 1;
+ }
+ buffer[i * channels + c] = kZeroBreakValue;
+ inst->zero_counts[c] = 0;
+ }
+ } else {
+ inst->zero_counts[c] = 0;
+ }
+ }
+ }
+ }
+
res = opus_encode(inst->encoder,
- (const opus_int16*)audio_in,
+ use_buffer ? buffer : audio_in,
(int)samples,
encoded,
(opus_int32)length_encoded_buffer);
@@ -205,7 +248,7 @@ int16_t WebRtcOpus_SetComplexity(OpusEncInst* inst, int32_t complexity) {
}
}
-int16_t WebRtcOpus_DecoderCreate(OpusDecInst** inst, int channels) {
+int16_t WebRtcOpus_DecoderCreate(OpusDecInst** inst, size_t channels) {
int error;
OpusDecInst* state;
@@ -217,7 +260,7 @@ int16_t WebRtcOpus_DecoderCreate(OpusDecInst** inst, int channels) {
}
/* Create new memory, always at 48000 Hz. */
- state->decoder = opus_decoder_create(48000, channels, &error);
+ state->decoder = opus_decoder_create(48000, (int)channels, &error);
if (error == OPUS_OK && state->decoder != NULL) {
/* Creation of memory all ok. */
state->channels = channels;
@@ -246,7 +289,7 @@ int16_t WebRtcOpus_DecoderFree(OpusDecInst* inst) {
}
}
-int WebRtcOpus_DecoderChannels(OpusDecInst* inst) {
+size_t WebRtcOpus_DecoderChannels(OpusDecInst* inst) {
return inst->channels;
}
diff --git a/webrtc/modules/audio_coding/codecs/opus/include/opus_interface.h b/webrtc/modules/audio_coding/codecs/opus/opus_interface.h
index 50b2338ab5..754b49c808 100644
--- a/webrtc/modules/audio_coding/codecs/opus/include/opus_interface.h
+++ b/webrtc/modules/audio_coding/codecs/opus/opus_interface.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_OPUS_INCLUDE_OPUS_INTERFACE_H_
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_OPUS_INCLUDE_OPUS_INTERFACE_H_
+#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_OPUS_OPUS_INTERFACE_H_
+#define WEBRTC_MODULES_AUDIO_CODING_CODECS_OPUS_OPUS_INTERFACE_H_
#include <stddef.h>
@@ -43,7 +43,7 @@ typedef struct WebRtcOpusDecInst OpusDecInst;
* -1 - Error
*/
int16_t WebRtcOpus_EncoderCreate(OpusEncInst** inst,
- int32_t channels,
+ size_t channels,
int32_t application);
int16_t WebRtcOpus_EncoderFree(OpusEncInst* inst);
@@ -195,7 +195,7 @@ int16_t WebRtcOpus_DisableDtx(OpusEncInst* inst);
*/
int16_t WebRtcOpus_SetComplexity(OpusEncInst* inst, int32_t complexity);
-int16_t WebRtcOpus_DecoderCreate(OpusDecInst** inst, int channels);
+int16_t WebRtcOpus_DecoderCreate(OpusDecInst** inst, size_t channels);
int16_t WebRtcOpus_DecoderFree(OpusDecInst* inst);
/****************************************************************************
@@ -203,7 +203,7 @@ int16_t WebRtcOpus_DecoderFree(OpusDecInst* inst);
*
* This function returns the number of channels created for Opus decoder.
*/
-int WebRtcOpus_DecoderChannels(OpusDecInst* inst);
+size_t WebRtcOpus_DecoderChannels(OpusDecInst* inst);
/****************************************************************************
* WebRtcOpus_DecoderInit(...)
@@ -346,4 +346,4 @@ int WebRtcOpus_PacketHasFec(const uint8_t* payload,
} // extern "C"
#endif
-#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_OPUS_INCLUDE_OPUS_INCLUDE_H_
+#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_OPUS_OPUS_INTERFACE_H_
diff --git a/webrtc/modules/audio_coding/codecs/opus/opus_speed_test.cc b/webrtc/modules/audio_coding/codecs/opus/opus_speed_test.cc
index 29def14bf8..4d1aa42c89 100644
--- a/webrtc/modules/audio_coding/codecs/opus/opus_speed_test.cc
+++ b/webrtc/modules/audio_coding/codecs/opus/opus_speed_test.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_coding/codecs/opus/include/opus_interface.h"
+#include "webrtc/modules/audio_coding/codecs/opus/opus_interface.h"
#include "webrtc/modules/audio_coding/codecs/tools/audio_codec_speed_test.h"
using ::std::string;
@@ -77,7 +77,7 @@ float OpusSpeedTest::DecodeABlock(const uint8_t* bit_stream,
value = WebRtcOpus_Decode(opus_decoder_, bit_stream, encoded_bytes, out_data,
&audio_type);
clocks = clock() - clocks;
- EXPECT_EQ(output_length_sample_, value);
+ EXPECT_EQ(output_length_sample_, static_cast<size_t>(value));
return 1000.0 * clocks / CLOCKS_PER_SEC;
}
diff --git a/webrtc/modules/audio_coding/codecs/opus/opus_unittest.cc b/webrtc/modules/audio_coding/codecs/opus/opus_unittest.cc
index 4630e44807..c82b184b38 100644
--- a/webrtc/modules/audio_coding/codecs/opus/opus_unittest.cc
+++ b/webrtc/modules/audio_coding/codecs/opus/opus_unittest.cc
@@ -10,7 +10,8 @@
#include <string>
#include "testing/gtest/include/gtest/gtest.h"
-#include "webrtc/modules/audio_coding/codecs/opus/include/opus_interface.h"
+#include "webrtc/base/checks.h"
+#include "webrtc/modules/audio_coding/codecs/opus/opus_interface.h"
#include "webrtc/modules/audio_coding/codecs/opus/opus_inst.h"
#include "webrtc/modules/audio_coding/neteq/tools/audio_loop.h"
#include "webrtc/test/testsupport/fileutils.h"
@@ -35,17 +36,18 @@ class OpusTest : public TestWithParam<::testing::tuple<int, int>> {
protected:
OpusTest();
- void TestDtxEffect(bool dtx);
+ void TestDtxEffect(bool dtx, int block_length_ms);
// Prepare |speech_data_| for encoding, read from a hard-coded file.
// After preparation, |speech_data_.GetNextBlock()| returns a pointer to a
// block of |block_length_ms| milliseconds. The data is looped every
// |loop_length_ms| milliseconds.
- void PrepareSpeechData(int channel, int block_length_ms, int loop_length_ms);
+ void PrepareSpeechData(size_t channel,
+ int block_length_ms,
+ int loop_length_ms);
int EncodeDecode(WebRtcOpusEncInst* encoder,
- const int16_t* input_audio,
- size_t input_samples,
+ rtc::ArrayView<const int16_t> input_audio,
WebRtcOpusDecInst* decoder,
int16_t* output_audio,
int16_t* audio_type);
@@ -53,13 +55,16 @@ class OpusTest : public TestWithParam<::testing::tuple<int, int>> {
void SetMaxPlaybackRate(WebRtcOpusEncInst* encoder,
opus_int32 expect, int32_t set);
+ void CheckAudioBounded(const int16_t* audio, size_t samples, size_t channels,
+ uint16_t bound) const;
+
WebRtcOpusEncInst* opus_encoder_;
WebRtcOpusDecInst* opus_decoder_;
AudioLoop speech_data_;
uint8_t bitstream_[kMaxBytes];
size_t encoded_bytes_;
- int channels_;
+ size_t channels_;
int application_;
};
@@ -67,11 +72,11 @@ OpusTest::OpusTest()
: opus_encoder_(NULL),
opus_decoder_(NULL),
encoded_bytes_(0),
- channels_(::testing::get<0>(GetParam())),
+ channels_(static_cast<size_t>(::testing::get<0>(GetParam()))),
application_(::testing::get<1>(GetParam())) {
}
-void OpusTest::PrepareSpeechData(int channel, int block_length_ms,
+void OpusTest::PrepareSpeechData(size_t channel, int block_length_ms,
int loop_length_ms) {
const std::string file_name =
webrtc::test::ResourcePath((channel == 1) ?
@@ -95,14 +100,25 @@ void OpusTest::SetMaxPlaybackRate(WebRtcOpusEncInst* encoder,
EXPECT_EQ(expect, bandwidth);
}
+void OpusTest::CheckAudioBounded(const int16_t* audio, size_t samples,
+ size_t channels, uint16_t bound) const {
+ for (size_t i = 0; i < samples; ++i) {
+ for (size_t c = 0; c < channels; ++c) {
+ ASSERT_GE(audio[i * channels + c], -bound);
+ ASSERT_LE(audio[i * channels + c], bound);
+ }
+ }
+}
+
int OpusTest::EncodeDecode(WebRtcOpusEncInst* encoder,
- const int16_t* input_audio,
- size_t input_samples,
+ rtc::ArrayView<const int16_t> input_audio,
WebRtcOpusDecInst* decoder,
int16_t* output_audio,
int16_t* audio_type) {
- int encoded_bytes_int = WebRtcOpus_Encode(encoder, input_audio, input_samples,
- kMaxBytes, bitstream_);
+ int encoded_bytes_int = WebRtcOpus_Encode(
+ encoder, input_audio.data(),
+ rtc::CheckedDivExact(input_audio.size(), channels_),
+ kMaxBytes, bitstream_);
EXPECT_GE(encoded_bytes_int, 0);
encoded_bytes_ = static_cast<size_t>(encoded_bytes_int);
int est_len = WebRtcOpus_DurationEst(decoder, bitstream_, encoded_bytes_);
@@ -115,8 +131,9 @@ int OpusTest::EncodeDecode(WebRtcOpusEncInst* encoder,
// Test if encoder/decoder can enter DTX mode properly and do not enter DTX when
// they should not. This test is signal dependent.
-void OpusTest::TestDtxEffect(bool dtx) {
- PrepareSpeechData(channels_, 20, 2000);
+void OpusTest::TestDtxEffect(bool dtx, int block_length_ms) {
+ PrepareSpeechData(channels_, block_length_ms, 2000);
+ const size_t samples = kOpusRateKhz * block_length_ms;
// Create encoder memory.
EXPECT_EQ(0, WebRtcOpus_EncoderCreate(&opus_encoder_,
@@ -129,22 +146,20 @@ void OpusTest::TestDtxEffect(bool dtx) {
channels_ == 1 ? 32000 : 64000));
// Set input audio as silence.
- int16_t* silence = new int16_t[kOpus20msFrameSamples * channels_];
- memset(silence, 0, sizeof(int16_t) * kOpus20msFrameSamples * channels_);
+ std::vector<int16_t> silence(samples * channels_, 0);
// Setting DTX.
EXPECT_EQ(0, dtx ? WebRtcOpus_EnableDtx(opus_encoder_) :
WebRtcOpus_DisableDtx(opus_encoder_));
int16_t audio_type;
- int16_t* output_data_decode = new int16_t[kOpus20msFrameSamples * channels_];
+ int16_t* output_data_decode = new int16_t[samples * channels_];
for (int i = 0; i < 100; ++i) {
- EXPECT_EQ(kOpus20msFrameSamples,
+ EXPECT_EQ(samples,
static_cast<size_t>(EncodeDecode(
- opus_encoder_, speech_data_.GetNextBlock(),
- kOpus20msFrameSamples, opus_decoder_, output_data_decode,
- &audio_type)));
+ opus_encoder_, speech_data_.GetNextBlock(), opus_decoder_,
+ output_data_decode, &audio_type)));
// If not DTX, it should never enter DTX mode. If DTX, we do not care since
// whether it enters DTX depends on the signal type.
if (!dtx) {
@@ -158,10 +173,10 @@ void OpusTest::TestDtxEffect(bool dtx) {
// We input some silent segments. In DTX mode, the encoder will stop sending.
// However, DTX may happen after a while.
for (int i = 0; i < 30; ++i) {
- EXPECT_EQ(kOpus20msFrameSamples,
+ EXPECT_EQ(samples,
static_cast<size_t>(EncodeDecode(
- opus_encoder_, silence, kOpus20msFrameSamples, opus_decoder_,
- output_data_decode, &audio_type)));
+ opus_encoder_, silence, opus_decoder_, output_data_decode,
+ &audio_type)));
if (!dtx) {
EXPECT_GT(encoded_bytes_, 1U);
EXPECT_EQ(0, opus_encoder_->in_dtx_mode);
@@ -177,21 +192,47 @@ void OpusTest::TestDtxEffect(bool dtx) {
// When Opus is in DTX, it wakes up in a regular basis. It sends two packets,
// one with an arbitrary size and the other of 1-byte, then stops sending for
- // 19 frames.
- const int cycles = 5;
- for (int j = 0; j < cycles; ++j) {
- // DTX mode is maintained 19 frames.
- for (int i = 0; i < 19; ++i) {
- EXPECT_EQ(kOpus20msFrameSamples,
+ // a certain number of frames.
+
+ // |max_dtx_frames| is the maximum number of frames Opus can stay in DTX.
+ const int max_dtx_frames = 400 / block_length_ms + 1;
+
+ // We run |kRunTimeMs| milliseconds of pure silence.
+ const int kRunTimeMs = 2000;
+
+ // We check that, after a |kCheckTimeMs| milliseconds (given that the CNG in
+ // Opus needs time to adapt), the absolute values of DTX decoded signal are
+ // bounded by |kOutputValueBound|.
+ const int kCheckTimeMs = 1500;
+
+#if defined(OPUS_FIXED_POINT)
+ const uint16_t kOutputValueBound = 20;
+#else
+ const uint16_t kOutputValueBound = 2;
+#endif
+
+ int time = 0;
+ while (time < kRunTimeMs) {
+ // DTX mode is maintained for maximum |max_dtx_frames| frames.
+ int i = 0;
+ for (; i < max_dtx_frames; ++i) {
+ time += block_length_ms;
+ EXPECT_EQ(samples,
static_cast<size_t>(EncodeDecode(
- opus_encoder_, silence, kOpus20msFrameSamples,
- opus_decoder_, output_data_decode, &audio_type)));
+ opus_encoder_, silence, opus_decoder_, output_data_decode,
+ &audio_type)));
if (dtx) {
+ if (encoded_bytes_ > 1)
+ break;
EXPECT_EQ(0U, encoded_bytes_) // Send 0 byte.
<< "Opus should have entered DTX mode.";
EXPECT_EQ(1, opus_encoder_->in_dtx_mode);
EXPECT_EQ(1, opus_decoder_->in_dtx_mode);
EXPECT_EQ(2, audio_type); // Comfort noise.
+ if (time >= kCheckTimeMs) {
+ CheckAudioBounded(output_data_decode, samples, channels_,
+ kOutputValueBound);
+ }
} else {
EXPECT_GT(encoded_bytes_, 1U);
EXPECT_EQ(0, opus_encoder_->in_dtx_mode);
@@ -200,27 +241,31 @@ void OpusTest::TestDtxEffect(bool dtx) {
}
}
- // Quit DTX after 19 frames.
- EXPECT_EQ(kOpus20msFrameSamples,
- static_cast<size_t>(EncodeDecode(
- opus_encoder_, silence, kOpus20msFrameSamples, opus_decoder_,
- output_data_decode, &audio_type)));
+ if (dtx) {
+ // With DTX, Opus must stop transmission for some time.
+ EXPECT_GT(i, 1);
+ }
- EXPECT_GT(encoded_bytes_, 1U);
+ // We expect a normal payload.
EXPECT_EQ(0, opus_encoder_->in_dtx_mode);
EXPECT_EQ(0, opus_decoder_->in_dtx_mode);
EXPECT_EQ(0, audio_type); // Speech.
// Enters DTX again immediately.
- EXPECT_EQ(kOpus20msFrameSamples,
+ time += block_length_ms;
+ EXPECT_EQ(samples,
static_cast<size_t>(EncodeDecode(
- opus_encoder_, silence, kOpus20msFrameSamples, opus_decoder_,
- output_data_decode, &audio_type)));
+ opus_encoder_, silence, opus_decoder_, output_data_decode,
+ &audio_type)));
if (dtx) {
EXPECT_EQ(1U, encoded_bytes_); // Send 1 byte.
EXPECT_EQ(1, opus_encoder_->in_dtx_mode);
EXPECT_EQ(1, opus_decoder_->in_dtx_mode);
EXPECT_EQ(2, audio_type); // Comfort noise.
+ if (time >= kCheckTimeMs) {
+ CheckAudioBounded(output_data_decode, samples, channels_,
+ kOutputValueBound);
+ }
} else {
EXPECT_GT(encoded_bytes_, 1U);
EXPECT_EQ(0, opus_encoder_->in_dtx_mode);
@@ -232,10 +277,10 @@ void OpusTest::TestDtxEffect(bool dtx) {
silence[0] = 10000;
if (dtx) {
// Verify that encoder/decoder can jump out from DTX mode.
- EXPECT_EQ(kOpus20msFrameSamples,
+ EXPECT_EQ(samples,
static_cast<size_t>(EncodeDecode(
- opus_encoder_, silence, kOpus20msFrameSamples, opus_decoder_,
- output_data_decode, &audio_type)));
+ opus_encoder_, silence, opus_decoder_, output_data_decode,
+ &audio_type)));
EXPECT_GT(encoded_bytes_, 1U);
EXPECT_EQ(0, opus_encoder_->in_dtx_mode);
EXPECT_EQ(0, opus_decoder_->in_dtx_mode);
@@ -244,7 +289,6 @@ void OpusTest::TestDtxEffect(bool dtx) {
// Free memory.
delete[] output_data_decode;
- delete[] silence;
EXPECT_EQ(0, WebRtcOpus_EncoderFree(opus_encoder_));
EXPECT_EQ(0, WebRtcOpus_DecoderFree(opus_decoder_));
}
@@ -314,10 +358,9 @@ TEST_P(OpusTest, OpusEncodeDecode) {
int16_t audio_type;
int16_t* output_data_decode = new int16_t[kOpus20msFrameSamples * channels_];
EXPECT_EQ(kOpus20msFrameSamples,
- static_cast<size_t>(EncodeDecode(
- opus_encoder_, speech_data_.GetNextBlock(),
- kOpus20msFrameSamples, opus_decoder_, output_data_decode,
- &audio_type)));
+ static_cast<size_t>(
+ EncodeDecode(opus_encoder_, speech_data_.GetNextBlock(),
+ opus_decoder_, output_data_decode, &audio_type)));
// Free memory.
delete[] output_data_decode;
@@ -374,10 +417,9 @@ TEST_P(OpusTest, OpusDecodeInit) {
int16_t audio_type;
int16_t* output_data_decode = new int16_t[kOpus20msFrameSamples * channels_];
EXPECT_EQ(kOpus20msFrameSamples,
- static_cast<size_t>(EncodeDecode(
- opus_encoder_, speech_data_.GetNextBlock(),
- kOpus20msFrameSamples, opus_decoder_, output_data_decode,
- &audio_type)));
+ static_cast<size_t>(
+ EncodeDecode(opus_encoder_, speech_data_.GetNextBlock(),
+ opus_decoder_, output_data_decode, &audio_type)));
WebRtcOpus_DecoderInit(opus_decoder_);
@@ -444,11 +486,15 @@ TEST_P(OpusTest, OpusEnableDisableDtx) {
}
TEST_P(OpusTest, OpusDtxOff) {
- TestDtxEffect(false);
+ TestDtxEffect(false, 10);
+ TestDtxEffect(false, 20);
+ TestDtxEffect(false, 40);
}
TEST_P(OpusTest, OpusDtxOn) {
- TestDtxEffect(true);
+ TestDtxEffect(true, 10);
+ TestDtxEffect(true, 20);
+ TestDtxEffect(true, 40);
}
TEST_P(OpusTest, OpusSetPacketLossRate) {
@@ -513,10 +559,9 @@ TEST_P(OpusTest, OpusDecodePlc) {
int16_t audio_type;
int16_t* output_data_decode = new int16_t[kOpus20msFrameSamples * channels_];
EXPECT_EQ(kOpus20msFrameSamples,
- static_cast<size_t>(EncodeDecode(
- opus_encoder_, speech_data_.GetNextBlock(),
- kOpus20msFrameSamples, opus_decoder_, output_data_decode,
- &audio_type)));
+ static_cast<size_t>(
+ EncodeDecode(opus_encoder_, speech_data_.GetNextBlock(),
+ opus_decoder_, output_data_decode, &audio_type)));
// Call decoder PLC.
int16_t* plc_buffer = new int16_t[kOpus20msFrameSamples * channels_];
@@ -542,10 +587,11 @@ TEST_P(OpusTest, OpusDurationEstimation) {
EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_));
// 10 ms. We use only first 10 ms of a 20 ms block.
- int encoded_bytes_int = WebRtcOpus_Encode(opus_encoder_,
- speech_data_.GetNextBlock(),
- kOpus10msFrameSamples,
- kMaxBytes, bitstream_);
+ auto speech_block = speech_data_.GetNextBlock();
+ int encoded_bytes_int = WebRtcOpus_Encode(
+ opus_encoder_, speech_block.data(),
+ rtc::CheckedDivExact(speech_block.size(), 2 * channels_),
+ kMaxBytes, bitstream_);
EXPECT_GE(encoded_bytes_int, 0);
EXPECT_EQ(kOpus10msFrameSamples,
static_cast<size_t>(WebRtcOpus_DurationEst(
@@ -553,10 +599,11 @@ TEST_P(OpusTest, OpusDurationEstimation) {
static_cast<size_t>(encoded_bytes_int))));
// 20 ms
- encoded_bytes_int = WebRtcOpus_Encode(opus_encoder_,
- speech_data_.GetNextBlock(),
- kOpus20msFrameSamples,
- kMaxBytes, bitstream_);
+ speech_block = speech_data_.GetNextBlock();
+ encoded_bytes_int = WebRtcOpus_Encode(
+ opus_encoder_, speech_block.data(),
+ rtc::CheckedDivExact(speech_block.size(), channels_),
+ kMaxBytes, bitstream_);
EXPECT_GE(encoded_bytes_int, 0);
EXPECT_EQ(kOpus20msFrameSamples,
static_cast<size_t>(WebRtcOpus_DurationEst(
@@ -594,10 +641,11 @@ TEST_P(OpusTest, OpusDecodeRepacketized) {
OpusRepacketizer* rp = opus_repacketizer_create();
for (int idx = 0; idx < kPackets; idx++) {
- encoded_bytes_ = WebRtcOpus_Encode(opus_encoder_,
- speech_data_.GetNextBlock(),
- kOpus20msFrameSamples, kMaxBytes,
- bitstream_);
+ auto speech_block = speech_data_.GetNextBlock();
+ encoded_bytes_ =
+ WebRtcOpus_Encode(opus_encoder_, speech_block.data(),
+ rtc::CheckedDivExact(speech_block.size(), channels_),
+ kMaxBytes, bitstream_);
EXPECT_EQ(OPUS_OK, opus_repacketizer_cat(rp, bitstream_, encoded_bytes_));
}