summaryrefslogtreecommitdiff
path: root/modules/audio_coding/neteq
diff options
context:
space:
mode:
Diffstat (limited to 'modules/audio_coding/neteq')
-rw-r--r--modules/audio_coding/neteq/audio_decoder.cc22
-rw-r--r--modules/audio_coding/neteq/audio_decoder_impl.cc84
-rw-r--r--modules/audio_coding/neteq/audio_decoder_impl.h32
-rw-r--r--modules/audio_coding/neteq/audio_decoder_unittest.cc375
-rw-r--r--modules/audio_coding/neteq/audio_decoder_unittests.isolate9
-rw-r--r--modules/audio_coding/neteq/decision_logic_normal.cc10
-rw-r--r--modules/audio_coding/neteq/decoder_database_unittest.cc4
-rw-r--r--modules/audio_coding/neteq/expand.cc2
-rw-r--r--modules/audio_coding/neteq/interface/audio_decoder.h10
-rw-r--r--modules/audio_coding/neteq/interface/neteq.h2
-rw-r--r--modules/audio_coding/neteq/mock/mock_audio_decoder.h2
-rw-r--r--modules/audio_coding/neteq/mock/mock_external_decoder_pcm16b.h12
-rw-r--r--modules/audio_coding/neteq/mock/mock_packet_buffer.h4
-rw-r--r--modules/audio_coding/neteq/neteq.gypi6
-rw-r--r--modules/audio_coding/neteq/neteq_external_decoder_unittest.cc17
-rw-r--r--modules/audio_coding/neteq/neteq_impl.cc10
-rw-r--r--modules/audio_coding/neteq/neteq_impl.h2
-rw-r--r--modules/audio_coding/neteq/neteq_impl_unittest.cc98
-rw-r--r--modules/audio_coding/neteq/neteq_tests.gypi2
-rw-r--r--modules/audio_coding/neteq/packet_buffer.cc12
-rw-r--r--modules/audio_coding/neteq/packet_buffer.h28
-rw-r--r--modules/audio_coding/neteq/packet_buffer_unittest.cc59
-rw-r--r--modules/audio_coding/neteq/test/RTPencode.cc7
-rw-r--r--modules/audio_coding/neteq/tools/neteq_rtpplay.cc37
-rw-r--r--modules/audio_coding/neteq/tools/resample_input_audio_file.cc42
-rw-r--r--modules/audio_coding/neteq/tools/resample_input_audio_file.h40
26 files changed, 554 insertions, 374 deletions
diff --git a/modules/audio_coding/neteq/audio_decoder.cc b/modules/audio_coding/neteq/audio_decoder.cc
index 0fdaa44b..04a74eef 100644
--- a/modules/audio_coding/neteq/audio_decoder.cc
+++ b/modules/audio_coding/neteq/audio_decoder.cc
@@ -51,8 +51,6 @@ bool AudioDecoder::PacketHasFec(const uint8_t* encoded,
return false;
}
-NetEqDecoder AudioDecoder::codec_type() const { return codec_type_; }
-
bool AudioDecoder::CodecSupported(NetEqDecoder codec_type) {
switch (codec_type) {
case kDecoderPCMu:
@@ -197,26 +195,24 @@ AudioDecoder* AudioDecoder::CreateAudioDecoder(NetEqDecoder codec_type) {
return new AudioDecoderIsacFix;
#elif defined(WEBRTC_CODEC_ISAC)
case kDecoderISAC:
- return new AudioDecoderIsac;
-#endif
-#ifdef WEBRTC_CODEC_ISAC
+ return new AudioDecoderIsac(16000);
case kDecoderISACswb:
- return new AudioDecoderIsacSwb;
case kDecoderISACfb:
- return new AudioDecoderIsacFb;
+ return new AudioDecoderIsac(32000);
#endif
#ifdef WEBRTC_CODEC_PCM16
case kDecoderPCM16B:
case kDecoderPCM16Bwb:
case kDecoderPCM16Bswb32kHz:
case kDecoderPCM16Bswb48kHz:
- return new AudioDecoderPcm16B(codec_type);
+ return new AudioDecoderPcm16B;
case kDecoderPCM16B_2ch:
case kDecoderPCM16Bwb_2ch:
case kDecoderPCM16Bswb32kHz_2ch:
case kDecoderPCM16Bswb48kHz_2ch:
+ return new AudioDecoderPcm16BMultiCh(2);
case kDecoderPCM16B_5ch:
- return new AudioDecoderPcm16BMultiCh(codec_type);
+ return new AudioDecoderPcm16BMultiCh(5);
#endif
#ifdef WEBRTC_CODEC_G722
case kDecoderG722:
@@ -226,19 +222,21 @@ AudioDecoder* AudioDecoder::CreateAudioDecoder(NetEqDecoder codec_type) {
#endif
#ifdef WEBRTC_CODEC_CELT
case kDecoderCELT_32:
+ return new AudioDecoderCelt(1);
case kDecoderCELT_32_2ch:
- return new AudioDecoderCelt(codec_type);
+ return new AudioDecoderCelt(2);
#endif
#ifdef WEBRTC_CODEC_OPUS
case kDecoderOpus:
+ return new AudioDecoderOpus(1);
case kDecoderOpus_2ch:
- return new AudioDecoderOpus(codec_type);
+ return new AudioDecoderOpus(2);
#endif
case kDecoderCNGnb:
case kDecoderCNGwb:
case kDecoderCNGswb32kHz:
case kDecoderCNGswb48kHz:
- return new AudioDecoderCng(codec_type);
+ return new AudioDecoderCng;
case kDecoderRED:
case kDecoderAVT:
case kDecoderArbitrary:
diff --git a/modules/audio_coding/neteq/audio_decoder_impl.cc b/modules/audio_coding/neteq/audio_decoder_impl.cc
index 661f2b11..07b1b4be 100644
--- a/modules/audio_coding/neteq/audio_decoder_impl.cc
+++ b/modules/audio_coding/neteq/audio_decoder_impl.cc
@@ -13,6 +13,7 @@
#include <assert.h>
#include <string.h> // memmove
+#include "webrtc/base/checks.h"
#ifdef WEBRTC_CODEC_CELT
#include "webrtc/modules/audio_coding/codecs/celt/include/celt_interface.h"
#endif
@@ -44,7 +45,7 @@ int AudioDecoderPcmU::Decode(const uint8_t* encoded, size_t encoded_len,
int16_t* decoded, SpeechType* speech_type) {
int16_t temp_type = 1; // Default is speech.
int16_t ret = WebRtcG711_DecodeU(
- state_, reinterpret_cast<int16_t*>(const_cast<uint8_t*>(encoded)),
+ reinterpret_cast<int16_t*>(const_cast<uint8_t*>(encoded)),
static_cast<int16_t>(encoded_len), decoded, &temp_type);
*speech_type = ConvertSpeechType(temp_type);
return ret;
@@ -61,7 +62,7 @@ int AudioDecoderPcmA::Decode(const uint8_t* encoded, size_t encoded_len,
int16_t* decoded, SpeechType* speech_type) {
int16_t temp_type = 1; // Default is speech.
int16_t ret = WebRtcG711_DecodeA(
- state_, reinterpret_cast<int16_t*>(const_cast<uint8_t*>(encoded)),
+ reinterpret_cast<int16_t*>(const_cast<uint8_t*>(encoded)),
static_cast<int16_t>(encoded_len), decoded, &temp_type);
*speech_type = ConvertSpeechType(temp_type);
return ret;
@@ -75,19 +76,13 @@ int AudioDecoderPcmA::PacketDuration(const uint8_t* encoded,
// PCM16B
#ifdef WEBRTC_CODEC_PCM16
-AudioDecoderPcm16B::AudioDecoderPcm16B(enum NetEqDecoder type)
- : AudioDecoder(type) {
- assert(type == kDecoderPCM16B ||
- type == kDecoderPCM16Bwb ||
- type == kDecoderPCM16Bswb32kHz ||
- type == kDecoderPCM16Bswb48kHz);
-}
+AudioDecoderPcm16B::AudioDecoderPcm16B() {}
int AudioDecoderPcm16B::Decode(const uint8_t* encoded, size_t encoded_len,
int16_t* decoded, SpeechType* speech_type) {
int16_t temp_type = 1; // Default is speech.
int16_t ret = WebRtcPcm16b_DecodeW16(
- state_, reinterpret_cast<int16_t*>(const_cast<uint8_t*>(encoded)),
+ reinterpret_cast<int16_t*>(const_cast<uint8_t*>(encoded)),
static_cast<int16_t>(encoded_len), decoded, &temp_type);
*speech_type = ConvertSpeechType(temp_type);
return ret;
@@ -99,29 +94,15 @@ int AudioDecoderPcm16B::PacketDuration(const uint8_t* encoded,
return static_cast<int>(encoded_len / (2 * channels_));
}
-AudioDecoderPcm16BMultiCh::AudioDecoderPcm16BMultiCh(
- enum NetEqDecoder type)
- : AudioDecoderPcm16B(kDecoderPCM16B) { // This will be changed below.
- codec_type_ = type; // Changing to actual type here.
- switch (codec_type_) {
- case kDecoderPCM16B_2ch:
- case kDecoderPCM16Bwb_2ch:
- case kDecoderPCM16Bswb32kHz_2ch:
- case kDecoderPCM16Bswb48kHz_2ch:
- channels_ = 2;
- break;
- case kDecoderPCM16B_5ch:
- channels_ = 5;
- break;
- default:
- assert(false);
- }
+AudioDecoderPcm16BMultiCh::AudioDecoderPcm16BMultiCh(int num_channels) {
+ DCHECK(num_channels > 0);
+ channels_ = num_channels;
}
#endif
// iLBC
#ifdef WEBRTC_CODEC_ILBC
-AudioDecoderIlbc::AudioDecoderIlbc() : AudioDecoder(kDecoderILBC) {
+AudioDecoderIlbc::AudioDecoderIlbc() {
WebRtcIlbcfix_DecoderCreate(reinterpret_cast<iLBC_decinst_t**>(&state_));
}
@@ -152,9 +133,11 @@ int AudioDecoderIlbc::Init() {
// iSAC float
#ifdef WEBRTC_CODEC_ISAC
-AudioDecoderIsac::AudioDecoderIsac() : AudioDecoder(kDecoderISAC) {
+AudioDecoderIsac::AudioDecoderIsac(int decode_sample_rate_hz) {
+ DCHECK(decode_sample_rate_hz == 16000 || decode_sample_rate_hz == 32000);
WebRtcIsac_Create(reinterpret_cast<ISACStruct**>(&state_));
- WebRtcIsac_SetDecSampRate(static_cast<ISACStruct*>(state_), 16000);
+ WebRtcIsac_SetDecSampRate(static_cast<ISACStruct*>(state_),
+ decode_sample_rate_hz);
}
AudioDecoderIsac::~AudioDecoderIsac() {
@@ -209,22 +192,11 @@ int AudioDecoderIsac::IncomingPacket(const uint8_t* payload,
int AudioDecoderIsac::ErrorCode() {
return WebRtcIsac_GetErrorCode(static_cast<ISACStruct*>(state_));
}
-
-// iSAC SWB
-AudioDecoderIsacSwb::AudioDecoderIsacSwb() : AudioDecoderIsac() {
- codec_type_ = kDecoderISACswb;
- WebRtcIsac_SetDecSampRate(static_cast<ISACStruct*>(state_), 32000);
-}
-
-// iSAC FB
-AudioDecoderIsacFb::AudioDecoderIsacFb() : AudioDecoderIsacSwb() {
- codec_type_ = kDecoderISACfb;
-}
#endif
// iSAC fix
#ifdef WEBRTC_CODEC_ISACFX
-AudioDecoderIsacFix::AudioDecoderIsacFix() : AudioDecoder(kDecoderISAC) {
+AudioDecoderIsacFix::AudioDecoderIsacFix() {
WebRtcIsacfix_Create(reinterpret_cast<ISACFIX_MainStruct**>(&state_));
}
@@ -266,7 +238,7 @@ int AudioDecoderIsacFix::ErrorCode() {
// G.722
#ifdef WEBRTC_CODEC_G722
-AudioDecoderG722::AudioDecoderG722() : AudioDecoder(kDecoderG722) {
+AudioDecoderG722::AudioDecoderG722() {
WebRtcG722_CreateDecoder(reinterpret_cast<G722DecInst**>(&state_));
}
@@ -382,14 +354,9 @@ void AudioDecoderG722Stereo::SplitStereoPacket(const uint8_t* encoded,
// CELT
#ifdef WEBRTC_CODEC_CELT
-AudioDecoderCelt::AudioDecoderCelt(enum NetEqDecoder type)
- : AudioDecoder(type) {
- assert(type == kDecoderCELT_32 || type == kDecoderCELT_32_2ch);
- if (type == kDecoderCELT_32) {
- channels_ = 1;
- } else {
- channels_ = 2;
- }
+AudioDecoderCelt::AudioDecoderCelt(int num_channels) {
+ DCHECK(num_channels == 1 || num_channels == 2);
+ channels_ = num_channels;
WebRtcCelt_CreateDec(reinterpret_cast<CELT_decinst_t**>(&state_),
static_cast<int>(channels_));
}
@@ -431,13 +398,9 @@ int AudioDecoderCelt::DecodePlc(int num_frames, int16_t* decoded) {
// Opus
#ifdef WEBRTC_CODEC_OPUS
-AudioDecoderOpus::AudioDecoderOpus(enum NetEqDecoder type)
- : AudioDecoder(type) {
- if (type == kDecoderOpus_2ch) {
- channels_ = 2;
- } else {
- channels_ = 1;
- }
+AudioDecoderOpus::AudioDecoderOpus(int num_channels) {
+ DCHECK(num_channels == 1 || num_channels == 2);
+ channels_ = num_channels;
WebRtcOpus_DecoderCreate(reinterpret_cast<OpusDecInst**>(&state_),
static_cast<int>(channels_));
}
@@ -494,10 +457,7 @@ bool AudioDecoderOpus::PacketHasFec(const uint8_t* encoded,
}
#endif
-AudioDecoderCng::AudioDecoderCng(enum NetEqDecoder type)
- : AudioDecoder(type) {
- assert(type == kDecoderCNGnb || type == kDecoderCNGwb ||
- kDecoderCNGswb32kHz || type == kDecoderCNGswb48kHz);
+AudioDecoderCng::AudioDecoderCng() {
WebRtcCng_CreateDec(reinterpret_cast<CNG_dec_inst**>(&state_));
assert(state_);
}
diff --git a/modules/audio_coding/neteq/audio_decoder_impl.h b/modules/audio_coding/neteq/audio_decoder_impl.h
index 265d660b..214392e7 100644
--- a/modules/audio_coding/neteq/audio_decoder_impl.h
+++ b/modules/audio_coding/neteq/audio_decoder_impl.h
@@ -26,7 +26,7 @@ namespace webrtc {
class AudioDecoderPcmU : public AudioDecoder {
public:
- AudioDecoderPcmU() : AudioDecoder(kDecoderPCMu) {}
+ AudioDecoderPcmU() {}
virtual int Decode(const uint8_t* encoded, size_t encoded_len,
int16_t* decoded, SpeechType* speech_type);
virtual int Init() { return 0; }
@@ -38,7 +38,7 @@ class AudioDecoderPcmU : public AudioDecoder {
class AudioDecoderPcmA : public AudioDecoder {
public:
- AudioDecoderPcmA() : AudioDecoder(kDecoderPCMa) {}
+ AudioDecoderPcmA() {}
virtual int Decode(const uint8_t* encoded, size_t encoded_len,
int16_t* decoded, SpeechType* speech_type);
virtual int Init() { return 0; }
@@ -75,7 +75,7 @@ class AudioDecoderPcmAMultiCh : public AudioDecoderPcmA {
// The type is specified in the constructor parameter |type|.
class AudioDecoderPcm16B : public AudioDecoder {
public:
- explicit AudioDecoderPcm16B(enum NetEqDecoder type);
+ AudioDecoderPcm16B();
virtual int Decode(const uint8_t* encoded, size_t encoded_len,
int16_t* decoded, SpeechType* speech_type);
virtual int Init() { return 0; }
@@ -90,7 +90,7 @@ class AudioDecoderPcm16B : public AudioDecoder {
// of channels is derived from the type.
class AudioDecoderPcm16BMultiCh : public AudioDecoderPcm16B {
public:
- explicit AudioDecoderPcm16BMultiCh(enum NetEqDecoder type);
+ explicit AudioDecoderPcm16BMultiCh(int num_channels);
private:
DISALLOW_COPY_AND_ASSIGN(AudioDecoderPcm16BMultiCh);
@@ -116,7 +116,7 @@ class AudioDecoderIlbc : public AudioDecoder {
#ifdef WEBRTC_CODEC_ISAC
class AudioDecoderIsac : public AudioDecoder {
public:
- AudioDecoderIsac();
+ explicit AudioDecoderIsac(int decode_sample_rate_hz);
virtual ~AudioDecoderIsac();
virtual int Decode(const uint8_t* encoded, size_t encoded_len,
int16_t* decoded, SpeechType* speech_type);
@@ -135,22 +135,6 @@ class AudioDecoderIsac : public AudioDecoder {
private:
DISALLOW_COPY_AND_ASSIGN(AudioDecoderIsac);
};
-
-class AudioDecoderIsacSwb : public AudioDecoderIsac {
- public:
- AudioDecoderIsacSwb();
-
- private:
- DISALLOW_COPY_AND_ASSIGN(AudioDecoderIsacSwb);
-};
-
-class AudioDecoderIsacFb : public AudioDecoderIsacSwb {
- public:
- AudioDecoderIsacFb();
-
- private:
- DISALLOW_COPY_AND_ASSIGN(AudioDecoderIsacFb);
-};
#endif
#ifdef WEBRTC_CODEC_ISACFX
@@ -215,7 +199,7 @@ class AudioDecoderG722Stereo : public AudioDecoderG722 {
#ifdef WEBRTC_CODEC_CELT
class AudioDecoderCelt : public AudioDecoder {
public:
- explicit AudioDecoderCelt(enum NetEqDecoder type);
+ explicit AudioDecoderCelt(int num_channels);
virtual ~AudioDecoderCelt();
virtual int Decode(const uint8_t* encoded, size_t encoded_len,
@@ -232,7 +216,7 @@ class AudioDecoderCelt : public AudioDecoder {
#ifdef WEBRTC_CODEC_OPUS
class AudioDecoderOpus : public AudioDecoder {
public:
- explicit AudioDecoderOpus(enum NetEqDecoder type);
+ explicit AudioDecoderOpus(int num_channels);
virtual ~AudioDecoderOpus();
virtual int Decode(const uint8_t* encoded, size_t encoded_len,
int16_t* decoded, SpeechType* speech_type);
@@ -257,7 +241,7 @@ class AudioDecoderOpus : public AudioDecoder {
// specific CngDecoder class could both inherit from that class.
class AudioDecoderCng : public AudioDecoder {
public:
- explicit AudioDecoderCng(enum NetEqDecoder type);
+ explicit AudioDecoderCng();
virtual ~AudioDecoderCng();
virtual int Decode(const uint8_t* encoded, size_t encoded_len,
int16_t* decoded, SpeechType* speech_type) { return -1; }
diff --git a/modules/audio_coding/neteq/audio_decoder_unittest.cc b/modules/audio_coding/neteq/audio_decoder_unittest.cc
index 624e6a4d..c95214b2 100644
--- a/modules/audio_coding/neteq/audio_decoder_unittest.cc
+++ b/modules/audio_coding/neteq/audio_decoder_unittest.cc
@@ -14,56 +14,106 @@
#include <stdlib.h>
#include <string>
+#include <vector>
#include "testing/gtest/include/gtest/gtest.h"
-#include "webrtc/common_audio/resampler/include/resampler.h"
#ifdef WEBRTC_CODEC_CELT
#include "webrtc/modules/audio_coding/codecs/celt/include/celt_interface.h"
#endif
#include "webrtc/modules/audio_coding/codecs/g711/include/g711_interface.h"
+#include "webrtc/modules/audio_coding/codecs/g711/include/audio_encoder_pcm.h"
#include "webrtc/modules/audio_coding/codecs/g722/include/g722_interface.h"
#include "webrtc/modules/audio_coding/codecs/ilbc/interface/ilbc.h"
#include "webrtc/modules/audio_coding/codecs/isac/fix/interface/isacfix.h"
#include "webrtc/modules/audio_coding/codecs/isac/main/interface/isac.h"
-#include "webrtc/modules/audio_coding/codecs/opus/interface/opus_interface.h"
+#include "webrtc/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h"
#include "webrtc/modules/audio_coding/codecs/pcm16b/include/pcm16b.h"
+#include "webrtc/modules/audio_coding/neteq/tools/resample_input_audio_file.h"
#include "webrtc/system_wrappers/interface/data_log.h"
+#include "webrtc/system_wrappers/interface/scoped_ptr.h"
#include "webrtc/test/testsupport/fileutils.h"
namespace webrtc {
+namespace {
+// The absolute difference between the input and output (the first channel) is
+// compared vs |tolerance|. The parameter |delay| is used to correct for codec
+// delays.
+void CompareInputOutput(const std::vector<int16_t>& input,
+ const std::vector<int16_t>& output,
+ size_t num_samples,
+ size_t channels,
+ int tolerance,
+ int delay) {
+ ASSERT_LE(num_samples, input.size());
+ ASSERT_LE(num_samples * channels, output.size());
+ for (unsigned int n = 0; n < num_samples - delay; ++n) {
+ ASSERT_NEAR(input[n], output[channels * n + delay], tolerance)
+ << "Exit test on first diff; n = " << n;
+ DataLog::InsertCell("CodecTest", "input", input[n]);
+ DataLog::InsertCell("CodecTest", "output", output[channels * n]);
+ DataLog::NextRow("CodecTest");
+ }
+}
+
+// The absolute difference between the first two channels in |output| is
+// compared vs |tolerance|.
+void CompareTwoChannels(const std::vector<int16_t>& output,
+ size_t samples_per_channel,
+ size_t channels,
+ int tolerance) {
+ ASSERT_GE(channels, 2u);
+ ASSERT_LE(samples_per_channel * channels, output.size());
+ for (unsigned int n = 0; n < samples_per_channel; ++n)
+ ASSERT_NEAR(output[channels * n], output[channels * n + 1], tolerance)
+ << "Stereo samples differ.";
+}
+
+// Calculates mean-squared error between input and output (the first channel).
+// The parameter |delay| is used to correct for codec delays.
+double MseInputOutput(const std::vector<int16_t>& input,
+ const std::vector<int16_t>& output,
+ size_t num_samples,
+ size_t channels,
+ int delay) {
+ assert(delay < static_cast<int>(num_samples));
+ assert(num_samples <= input.size());
+ assert(num_samples * channels <= output.size());
+ if (num_samples == 0)
+ return 0.0;
+ double squared_sum = 0.0;
+ for (unsigned int n = 0; n < num_samples - delay; ++n) {
+ squared_sum += (input[n] - output[channels * n + delay]) *
+ (input[n] - output[channels * n + delay]);
+ }
+ return squared_sum / (num_samples - delay);
+}
+} // namespace
+
class AudioDecoderTest : public ::testing::Test {
protected:
AudioDecoderTest()
- : input_fp_(NULL),
- input_(NULL),
- encoded_(NULL),
- decoded_(NULL),
- frame_size_(0),
- data_length_(0),
- encoded_bytes_(0),
- channels_(1),
- decoder_(NULL) {
- input_file_ = webrtc::test::ProjectRootPath() +
- "resources/audio_coding/testfile32kHz.pcm";
- }
+ : input_audio_(webrtc::test::ProjectRootPath() +
+ "resources/audio_coding/testfile32kHz.pcm",
+ 32000),
+ codec_input_rate_hz_(32000), // Legacy default value.
+ encoded_(NULL),
+ frame_size_(0),
+ data_length_(0),
+ encoded_bytes_(0),
+ channels_(1),
+ output_timestamp_(0),
+ decoder_(NULL) {}
virtual ~AudioDecoderTest() {}
virtual void SetUp() {
+ if (audio_encoder_)
+ codec_input_rate_hz_ = audio_encoder_->sample_rate_hz();
// Create arrays.
ASSERT_GT(data_length_, 0u) << "The test must set data_length_ > 0";
- input_ = new int16_t[data_length_];
// Longest encoded data is produced by PCM16b with 2 bytes per sample.
encoded_ = new uint8_t[data_length_ * 2];
- decoded_ = new int16_t[data_length_ * channels_];
- // Open input file.
- input_fp_ = fopen(input_file_.c_str(), "rb");
- ASSERT_TRUE(input_fp_ != NULL) << "Failed to open file " << input_file_;
- // Read data to |input_|.
- ASSERT_EQ(data_length_,
- fread(input_, sizeof(int16_t), data_length_, input_fp_)) <<
- "Could not read enough data from file";
// Logging to view input and output in Matlab.
// Use 'gyp -Denable_data_logging=1' to enable logging.
DataLog::CreateLog();
@@ -75,24 +125,37 @@ class AudioDecoderTest : public ::testing::Test {
virtual void TearDown() {
delete decoder_;
decoder_ = NULL;
- // Close input file.
- fclose(input_fp_);
// Delete arrays.
- delete [] input_;
- input_ = NULL;
delete [] encoded_;
encoded_ = NULL;
- delete [] decoded_;
- decoded_ = NULL;
// Close log.
DataLog::ReturnLog();
}
virtual void InitEncoder() { }
- // This method must be implemented for all tests derived from this class.
- virtual int EncodeFrame(const int16_t* input, size_t input_len,
- uint8_t* output) = 0;
+ // TODO(henrik.lundin) Change return type to size_t once most/all overriding
+ // implementations are gone.
+ virtual int EncodeFrame(const int16_t* input,
+ size_t input_len_samples,
+ uint8_t* output) {
+ size_t enc_len_bytes = 0;
+ scoped_ptr<int16_t[]> interleaved_input(
+ new int16_t[channels_ * input_len_samples]);
+ for (int i = 0; i < audio_encoder_->Num10MsFramesInNextPacket(); ++i) {
+ EXPECT_EQ(0u, enc_len_bytes);
+
+ // Duplicate the mono input signal to however many channels the test
+ // wants.
+ test::InputAudioFile::DuplicateInterleaved(
+ input, input_len_samples, channels_, interleaved_input.get());
+
+ EXPECT_TRUE(audio_encoder_->Encode(
+ 0, interleaved_input.get(), audio_encoder_->sample_rate_hz() / 100,
+ data_length_ * 2, output, &enc_len_bytes, &output_timestamp_));
+ }
+ return static_cast<int>(enc_len_bytes);
+ }
// Encodes and decodes audio. The absolute difference between the input and
// output is compared vs |tolerance|, and the mean-squared error is compared
@@ -108,13 +171,23 @@ class AudioDecoderTest : public ::testing::Test {
encoded_bytes_ = 0u;
InitEncoder();
EXPECT_EQ(0, decoder_->Init());
+ std::vector<int16_t> input;
+ std::vector<int16_t> decoded;
while (processed_samples + frame_size_ <= data_length_) {
- size_t enc_len = EncodeFrame(&input_[processed_samples], frame_size_,
- &encoded_[encoded_bytes_]);
+ // Extend input vector with |frame_size_|.
+ input.resize(input.size() + frame_size_, 0);
+ // Read from input file.
+ ASSERT_GE(input.size() - processed_samples, frame_size_);
+ ASSERT_TRUE(input_audio_.Read(
+ frame_size_, codec_input_rate_hz_, &input[processed_samples]));
+ size_t enc_len = EncodeFrame(
+ &input[processed_samples], frame_size_, &encoded_[encoded_bytes_]);
+ // Make sure that frame_size_ * channels_ samples are allocated and free.
+ decoded.resize((processed_samples + frame_size_) * channels_, 0);
AudioDecoder::SpeechType speech_type;
- size_t dec_len = decoder_->Decode(&encoded_[encoded_bytes_], enc_len,
- &decoded_[processed_samples *
- channels_],
+ size_t dec_len = decoder_->Decode(&encoded_[encoded_bytes_],
+ enc_len,
+ &decoded[processed_samples * channels_],
&speech_type);
EXPECT_EQ(frame_size_ * channels_, dec_len);
encoded_bytes_ += enc_len;
@@ -126,65 +199,36 @@ class AudioDecoderTest : public ::testing::Test {
if (expected_bytes) {
EXPECT_EQ(expected_bytes, encoded_bytes_);
}
- CompareInputOutput(processed_samples, tolerance, delay);
+ CompareInputOutput(
+ input, decoded, processed_samples, channels_, tolerance, delay);
if (channels_ == 2)
- CompareTwoChannels(processed_samples, channel_diff_tolerance);
- EXPECT_LE(MseInputOutput(processed_samples, delay), mse);
- }
-
- // The absolute difference between the input and output (the first channel) is
- // compared vs |tolerance|. The parameter |delay| is used to correct for codec
- // delays.
- virtual void CompareInputOutput(size_t num_samples, int tolerance,
- int delay) const {
- assert(num_samples <= data_length_);
- for (unsigned int n = 0; n < num_samples - delay; ++n) {
- ASSERT_NEAR(input_[n], decoded_[channels_ * n + delay], tolerance) <<
- "Exit test on first diff; n = " << n;
- DataLog::InsertCell("CodecTest", "input", input_[n]);
- DataLog::InsertCell("CodecTest", "output", decoded_[channels_ * n]);
- DataLog::NextRow("CodecTest");
- }
- }
-
- // The absolute difference between the two channels in a stereo is compared vs
- // |tolerance|.
- virtual void CompareTwoChannels(size_t samples_per_channel,
- int tolerance) const {
- assert(samples_per_channel <= data_length_);
- for (unsigned int n = 0; n < samples_per_channel; ++n)
- ASSERT_NEAR(decoded_[channels_ * n], decoded_[channels_ * n + 1],
- tolerance) << "Stereo samples differ.";
- }
-
- // Calculates mean-squared error between input and output (the first channel).
- // The parameter |delay| is used to correct for codec delays.
- virtual double MseInputOutput(size_t num_samples, int delay) const {
- assert(num_samples <= data_length_);
- if (num_samples == 0) return 0.0;
- double squared_sum = 0.0;
- for (unsigned int n = 0; n < num_samples - delay; ++n) {
- squared_sum += (input_[n] - decoded_[channels_ * n + delay]) *
- (input_[n] - decoded_[channels_ * n + delay]);
- }
- return squared_sum / (num_samples - delay);
+ CompareTwoChannels(
+ decoded, processed_samples, channels_, channel_diff_tolerance);
+ EXPECT_LE(
+ MseInputOutput(input, decoded, processed_samples, channels_, delay),
+ mse);
}
// Encodes a payload and decodes it twice with decoder re-init before each
// decode. Verifies that the decoded result is the same.
void ReInitTest() {
- int16_t* output1 = decoded_;
- int16_t* output2 = decoded_ + frame_size_;
InitEncoder();
- size_t enc_len = EncodeFrame(input_, frame_size_, encoded_);
+ scoped_ptr<int16_t[]> input(new int16_t[frame_size_]);
+ ASSERT_TRUE(
+ input_audio_.Read(frame_size_, codec_input_rate_hz_, input.get()));
+ size_t enc_len = EncodeFrame(input.get(), frame_size_, encoded_);
size_t dec_len;
AudioDecoder::SpeechType speech_type1, speech_type2;
EXPECT_EQ(0, decoder_->Init());
- dec_len = decoder_->Decode(encoded_, enc_len, output1, &speech_type1);
+ scoped_ptr<int16_t[]> output1(new int16_t[frame_size_ * channels_]);
+ dec_len = decoder_->Decode(encoded_, enc_len, output1.get(), &speech_type1);
+ ASSERT_LE(dec_len, frame_size_ * channels_);
EXPECT_EQ(frame_size_ * channels_, dec_len);
// Re-init decoder and decode again.
EXPECT_EQ(0, decoder_->Init());
- dec_len = decoder_->Decode(encoded_, enc_len, output2, &speech_type2);
+ scoped_ptr<int16_t[]> output2(new int16_t[frame_size_ * channels_]);
+ dec_len = decoder_->Decode(encoded_, enc_len, output2.get(), &speech_type2);
+ ASSERT_LE(dec_len, frame_size_ * channels_);
EXPECT_EQ(frame_size_ * channels_, dec_len);
for (unsigned int n = 0; n < frame_size_; ++n) {
ASSERT_EQ(output1[n], output2[n]) << "Exit test on first diff; n = " << n;
@@ -195,29 +239,33 @@ class AudioDecoderTest : public ::testing::Test {
// Call DecodePlc and verify that the correct number of samples is produced.
void DecodePlcTest() {
InitEncoder();
- size_t enc_len = EncodeFrame(input_, frame_size_, encoded_);
+ scoped_ptr<int16_t[]> input(new int16_t[frame_size_]);
+ ASSERT_TRUE(
+ input_audio_.Read(frame_size_, codec_input_rate_hz_, input.get()));
+ size_t enc_len = EncodeFrame(input.get(), frame_size_, encoded_);
AudioDecoder::SpeechType speech_type;
EXPECT_EQ(0, decoder_->Init());
+ scoped_ptr<int16_t[]> output(new int16_t[frame_size_ * channels_]);
size_t dec_len =
- decoder_->Decode(encoded_, enc_len, decoded_, &speech_type);
+ decoder_->Decode(encoded_, enc_len, output.get(), &speech_type);
EXPECT_EQ(frame_size_ * channels_, dec_len);
// Call DecodePlc and verify that we get one frame of data.
// (Overwrite the output from the above Decode call, but that does not
// matter.)
- dec_len = decoder_->DecodePlc(1, decoded_);
+ dec_len = decoder_->DecodePlc(1, output.get());
EXPECT_EQ(frame_size_ * channels_, dec_len);
}
- std::string input_file_;
- FILE* input_fp_;
- int16_t* input_;
+ test::ResampleInputAudioFile input_audio_;
+ int codec_input_rate_hz_;
uint8_t* encoded_;
- int16_t* decoded_;
size_t frame_size_;
size_t data_length_;
size_t encoded_bytes_;
size_t channels_;
+ uint32_t output_timestamp_;
AudioDecoder* decoder_;
+ scoped_ptr<AudioEncoder> audio_encoder_;
};
class AudioDecoderPcmUTest : public AudioDecoderTest {
@@ -226,17 +274,9 @@ class AudioDecoderPcmUTest : public AudioDecoderTest {
frame_size_ = 160;
data_length_ = 10 * frame_size_;
decoder_ = new AudioDecoderPcmU;
- assert(decoder_);
- }
-
- virtual int EncodeFrame(const int16_t* input, size_t input_len_samples,
- uint8_t* output) {
- int enc_len_bytes =
- WebRtcG711_EncodeU(NULL, const_cast<int16_t*>(input),
- static_cast<int>(input_len_samples),
- reinterpret_cast<int16_t*>(output));
- EXPECT_EQ(input_len_samples, static_cast<size_t>(enc_len_bytes));
- return enc_len_bytes;
+ AudioEncoderPcmU::Config config;
+ config.frame_size_ms = static_cast<int>(frame_size_ / 8);
+ audio_encoder_.reset(new AudioEncoderPcmU(config));
}
};
@@ -246,26 +286,19 @@ class AudioDecoderPcmATest : public AudioDecoderTest {
frame_size_ = 160;
data_length_ = 10 * frame_size_;
decoder_ = new AudioDecoderPcmA;
- assert(decoder_);
- }
-
- virtual int EncodeFrame(const int16_t* input, size_t input_len_samples,
- uint8_t* output) {
- int enc_len_bytes =
- WebRtcG711_EncodeA(NULL, const_cast<int16_t*>(input),
- static_cast<int>(input_len_samples),
- reinterpret_cast<int16_t*>(output));
- EXPECT_EQ(input_len_samples, static_cast<size_t>(enc_len_bytes));
- return enc_len_bytes;
+ AudioEncoderPcmA::Config config;
+ config.frame_size_ms = static_cast<int>(frame_size_ / 8);
+ audio_encoder_.reset(new AudioEncoderPcmA(config));
}
};
class AudioDecoderPcm16BTest : public AudioDecoderTest {
protected:
AudioDecoderPcm16BTest() : AudioDecoderTest() {
+ codec_input_rate_hz_ = 8000;
frame_size_ = 160;
data_length_ = 10 * frame_size_;
- decoder_ = new AudioDecoderPcm16B(kDecoderPCM16B);
+ decoder_ = new AudioDecoderPcm16B;
assert(decoder_);
}
@@ -282,6 +315,7 @@ class AudioDecoderPcm16BTest : public AudioDecoderTest {
class AudioDecoderIlbcTest : public AudioDecoderTest {
protected:
AudioDecoderIlbcTest() : AudioDecoderTest() {
+ codec_input_rate_hz_ = 8000;
frame_size_ = 240;
data_length_ = 10 * frame_size_;
decoder_ = new AudioDecoderIlbc;
@@ -311,14 +345,18 @@ class AudioDecoderIlbcTest : public AudioDecoderTest {
// not return any data. It simply resets a few states and returns 0.
void DecodePlcTest() {
InitEncoder();
- size_t enc_len = EncodeFrame(input_, frame_size_, encoded_);
+ scoped_ptr<int16_t[]> input(new int16_t[frame_size_]);
+ ASSERT_TRUE(
+ input_audio_.Read(frame_size_, codec_input_rate_hz_, input.get()));
+ size_t enc_len = EncodeFrame(input.get(), frame_size_, encoded_);
AudioDecoder::SpeechType speech_type;
EXPECT_EQ(0, decoder_->Init());
+ scoped_ptr<int16_t[]> output(new int16_t[frame_size_ * channels_]);
size_t dec_len =
- decoder_->Decode(encoded_, enc_len, decoded_, &speech_type);
+ decoder_->Decode(encoded_, enc_len, output.get(), &speech_type);
EXPECT_EQ(frame_size_, dec_len);
// Simply call DecodePlc and verify that we get 0 as return value.
- EXPECT_EQ(0, decoder_->DecodePlc(1, decoded_));
+ EXPECT_EQ(0, decoder_->DecodePlc(1, output.get()));
}
iLBC_encinst_t* encoder_;
@@ -327,10 +365,11 @@ class AudioDecoderIlbcTest : public AudioDecoderTest {
class AudioDecoderIsacFloatTest : public AudioDecoderTest {
protected:
AudioDecoderIsacFloatTest() : AudioDecoderTest() {
+ codec_input_rate_hz_ = 16000;
input_size_ = 160;
frame_size_ = 480;
data_length_ = 10 * frame_size_;
- decoder_ = new AudioDecoderIsac;
+ decoder_ = new AudioDecoderIsac(16000);
assert(decoder_);
WebRtcIsac_Create(&encoder_);
WebRtcIsac_SetEncSampRate(encoder_, 16000);
@@ -364,10 +403,11 @@ class AudioDecoderIsacFloatTest : public AudioDecoderTest {
class AudioDecoderIsacSwbTest : public AudioDecoderTest {
protected:
AudioDecoderIsacSwbTest() : AudioDecoderTest() {
+ codec_input_rate_hz_ = 32000;
input_size_ = 320;
frame_size_ = 960;
data_length_ = 10 * frame_size_;
- decoder_ = new AudioDecoderIsacSwb;
+ decoder_ = new AudioDecoderIsac(32000);
assert(decoder_);
WebRtcIsac_Create(&encoder_);
WebRtcIsac_SetEncSampRate(encoder_, 32000);
@@ -398,22 +438,10 @@ class AudioDecoderIsacSwbTest : public AudioDecoderTest {
int input_size_;
};
-// This test is identical to AudioDecoderIsacSwbTest, except that it creates
-// an AudioDecoderIsacFb decoder object.
-class AudioDecoderIsacFbTest : public AudioDecoderIsacSwbTest {
- protected:
- AudioDecoderIsacFbTest() : AudioDecoderIsacSwbTest() {
- // Delete the |decoder_| that was created by AudioDecoderIsacSwbTest and
- // create an AudioDecoderIsacFb object instead.
- delete decoder_;
- decoder_ = new AudioDecoderIsacFb;
- assert(decoder_);
- }
-};
-
class AudioDecoderIsacFixTest : public AudioDecoderTest {
protected:
AudioDecoderIsacFixTest() : AudioDecoderTest() {
+ codec_input_rate_hz_ = 16000;
input_size_ = 160;
frame_size_ = 480;
data_length_ = 10 * frame_size_;
@@ -451,6 +479,7 @@ class AudioDecoderIsacFixTest : public AudioDecoderTest {
class AudioDecoderG722Test : public AudioDecoderTest {
protected:
AudioDecoderG722Test() : AudioDecoderTest() {
+ codec_input_rate_hz_ = 16000;
frame_size_ = 160;
data_length_ = 10 * frame_size_;
decoder_ = new AudioDecoderG722;
@@ -593,79 +622,26 @@ class AudioDecoderCeltStereoTest : public AudioDecoderTest {
class AudioDecoderOpusTest : public AudioDecoderTest {
protected:
AudioDecoderOpusTest() : AudioDecoderTest() {
+ codec_input_rate_hz_ = 48000;
frame_size_ = 480;
data_length_ = 10 * frame_size_;
- decoder_ = new AudioDecoderOpus(kDecoderOpus);
- assert(decoder_);
- WebRtcOpus_EncoderCreate(&encoder_, 1);
- }
-
- ~AudioDecoderOpusTest() {
- WebRtcOpus_EncoderFree(encoder_);
- }
-
- virtual void SetUp() OVERRIDE {
- AudioDecoderTest::SetUp();
- // Upsample from 32 to 48 kHz.
- // Because Opus is 48 kHz codec but the input file is 32 kHz, so the data
- // read in |AudioDecoderTest::SetUp| has to be upsampled.
- // |AudioDecoderTest::SetUp| has read |data_length_| samples, which is more
- // than necessary after upsampling, so the end of audio that has been read
- // is unused and the end of the buffer is overwritten by the resampled data.
- Resampler rs;
- rs.Reset(32000, 48000, kResamplerSynchronous);
- const int before_resamp_len_samples = static_cast<int>(data_length_) * 2
- / 3;
- int16_t* before_resamp_input = new int16_t[before_resamp_len_samples];
- memcpy(before_resamp_input, input_,
- sizeof(int16_t) * before_resamp_len_samples);
- int resamp_len_samples;
- EXPECT_EQ(0, rs.Push(before_resamp_input, before_resamp_len_samples,
- input_, static_cast<int>(data_length_),
- resamp_len_samples));
- EXPECT_EQ(static_cast<int>(data_length_), resamp_len_samples);
- delete[] before_resamp_input;
- }
-
- virtual void InitEncoder() {}
-
- virtual int EncodeFrame(const int16_t* input, size_t input_len_samples,
- uint8_t* output) OVERRIDE {
- int enc_len_bytes = WebRtcOpus_Encode(encoder_, const_cast<int16_t*>(input),
- static_cast<int16_t>(input_len_samples),
- static_cast<int16_t>(data_length_), output);
- EXPECT_GT(enc_len_bytes, 0);
- return enc_len_bytes;
+ decoder_ = new AudioDecoderOpus(1);
+ AudioEncoderOpus::Config config;
+ config.frame_size_ms = static_cast<int>(frame_size_) / 48;
+ audio_encoder_.reset(new AudioEncoderOpus(config));
}
-
- OpusEncInst* encoder_;
};
class AudioDecoderOpusStereoTest : public AudioDecoderOpusTest {
protected:
AudioDecoderOpusStereoTest() : AudioDecoderOpusTest() {
channels_ = 2;
- WebRtcOpus_EncoderFree(encoder_);
delete decoder_;
- decoder_ = new AudioDecoderOpus(kDecoderOpus_2ch);
- assert(decoder_);
- WebRtcOpus_EncoderCreate(&encoder_, 2);
- }
-
- virtual int EncodeFrame(const int16_t* input, size_t input_len_samples,
- uint8_t* output) OVERRIDE {
- // Create stereo by duplicating each sample in |input|.
- const int input_stereo_samples = static_cast<int>(input_len_samples) * 2;
- int16_t* input_stereo = new int16_t[input_stereo_samples];
- for (size_t i = 0; i < input_len_samples; i++)
- input_stereo[i * 2] = input_stereo[i * 2 + 1] = input[i];
-
- int enc_len_bytes = WebRtcOpus_Encode(
- encoder_, input_stereo, static_cast<int16_t>(input_len_samples),
- static_cast<int16_t>(data_length_), output);
- EXPECT_GT(enc_len_bytes, 0);
- delete[] input_stereo;
- return enc_len_bytes;
+ decoder_ = new AudioDecoderOpus(2);
+ AudioEncoderOpus::Config config;
+ config.frame_size_ms = static_cast<int>(frame_size_) / 48;
+ config.num_channels = 2;
+ audio_encoder_.reset(new AudioEncoderOpus(config));
}
};
@@ -732,17 +708,6 @@ TEST_F(AudioDecoderIsacSwbTest, EncodeDecode) {
DecodePlcTest();
}
-TEST_F(AudioDecoderIsacFbTest, EncodeDecode) {
- int tolerance = 19757;
- double mse = 8.18e6;
- int delay = 160; // Delay from input to output.
- EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderISACswb));
- EncodeDecodeTest(0, tolerance, mse, delay);
- ReInitTest();
- EXPECT_TRUE(decoder_->HasDecodePlc());
- DecodePlcTest();
-}
-
TEST_F(AudioDecoderIsacFixTest, DISABLED_EncodeDecode) {
int tolerance = 11034;
double mse = 3.46e6;
diff --git a/modules/audio_coding/neteq/audio_decoder_unittests.isolate b/modules/audio_coding/neteq/audio_decoder_unittests.isolate
index e4a18ca8..f10b327b 100644
--- a/modules/audio_coding/neteq/audio_decoder_unittests.isolate
+++ b/modules/audio_coding/neteq/audio_decoder_unittests.isolate
@@ -9,7 +9,7 @@
'conditions': [
['OS=="android"', {
'variables': {
- 'isolate_dependency_untracked': [
+ 'files': [
'<(DEPTH)/resources/',
'<(DEPTH)/data/',
],
@@ -21,17 +21,12 @@
'<(DEPTH)/testing/test_env.py',
'<(PRODUCT_DIR)/audio_decoder_unittests<(EXECUTABLE_SUFFIX)',
],
- 'isolate_dependency_touched': [
+ 'files': [
'<(DEPTH)/DEPS',
- ],
- 'isolate_dependency_tracked': [
'<(DEPTH)/resources/audio_coding/testfile32kHz.pcm',
'<(DEPTH)/testing/test_env.py',
'<(PRODUCT_DIR)/audio_decoder_unittests<(EXECUTABLE_SUFFIX)',
],
- 'isolate_dependency_untracked': [
- '<(DEPTH)/tools/swarming_client/',
- ],
},
}],
],
diff --git a/modules/audio_coding/neteq/decision_logic_normal.cc b/modules/audio_coding/neteq/decision_logic_normal.cc
index 9e422041..f2382845 100644
--- a/modules/audio_coding/neteq/decision_logic_normal.cc
+++ b/modules/audio_coding/neteq/decision_logic_normal.cc
@@ -67,19 +67,19 @@ Operations DecisionLogicNormal::GetDecisionSpecialized(
return kNormal;
}
+ const uint32_t five_seconds_samples = 5 * 8000 * fs_mult_;
// Check if the required packet is available.
if (target_timestamp == available_timestamp) {
return ExpectedPacketAvailable(prev_mode, play_dtmf);
- } else if (IsNewerTimestamp(available_timestamp, target_timestamp)) {
+ } else if (!PacketBuffer::IsObsoleteTimestamp(
+ available_timestamp, target_timestamp, five_seconds_samples)) {
return FuturePacketAvailable(sync_buffer, expand, decoder_frame_length,
prev_mode, target_timestamp,
available_timestamp, play_dtmf);
} else {
// This implies that available_timestamp < target_timestamp, which can
- // happen when a new stream or codec is received. Do Expand instead, and
- // wait for a newer packet to arrive, or for the buffer to flush (resulting
- // in a master reset).
- return kExpand;
+ // happen when a new stream or codec is received. Signal for a reset.
+ return kUndefined;
}
}
diff --git a/modules/audio_coding/neteq/decoder_database_unittest.cc b/modules/audio_coding/neteq/decoder_database_unittest.cc
index 6f497199..1e4e58af 100644
--- a/modules/audio_coding/neteq/decoder_database_unittest.cc
+++ b/modules/audio_coding/neteq/decoder_database_unittest.cc
@@ -189,21 +189,18 @@ TEST(DecoderDatabase, ActiveDecoders) {
EXPECT_TRUE(changed);
AudioDecoder* decoder = db.GetActiveDecoder();
ASSERT_FALSE(decoder == NULL); // Should get a decoder here.
- EXPECT_EQ(kDecoderPCMu, decoder->codec_type());
// Set the same again. Expect no change.
EXPECT_EQ(DecoderDatabase::kOK, db.SetActiveDecoder(0, &changed));
EXPECT_FALSE(changed);
decoder = db.GetActiveDecoder();
ASSERT_FALSE(decoder == NULL); // Should get a decoder here.
- EXPECT_EQ(kDecoderPCMu, decoder->codec_type());
// Change active decoder.
EXPECT_EQ(DecoderDatabase::kOK, db.SetActiveDecoder(103, &changed));
EXPECT_TRUE(changed);
decoder = db.GetActiveDecoder();
ASSERT_FALSE(decoder == NULL); // Should get a decoder here.
- EXPECT_EQ(kDecoderISAC, decoder->codec_type());
// Remove the active decoder, and verify that the active becomes NULL.
EXPECT_EQ(DecoderDatabase::kOK, db.Remove(103));
@@ -213,7 +210,6 @@ TEST(DecoderDatabase, ActiveDecoders) {
EXPECT_EQ(DecoderDatabase::kOK, db.SetActiveCngDecoder(13));
decoder = db.GetActiveCngDecoder();
ASSERT_FALSE(decoder == NULL); // Should get a decoder here.
- EXPECT_EQ(kDecoderCNGnb, decoder->codec_type());
// Remove the active CNG decoder, and verify that the active becomes NULL.
EXPECT_EQ(DecoderDatabase::kOK, db.Remove(13));
diff --git a/modules/audio_coding/neteq/expand.cc b/modules/audio_coding/neteq/expand.cc
index 1f46e66c..49ea45f4 100644
--- a/modules/audio_coding/neteq/expand.cc
+++ b/modules/audio_coding/neteq/expand.cc
@@ -488,7 +488,7 @@ void Expand::AnalyzeSignal(int16_t* random_vector) {
// Calculate scaled_energy1 / scaled_energy2 in Q13.
int32_t energy_ratio = WebRtcSpl_DivW32W16(
WEBRTC_SPL_SHIFT_W32(energy1, -scaled_energy1),
- WEBRTC_SPL_RSHIFT_W32(energy2, scaled_energy2));
+ energy2 >> scaled_energy2);
// Calculate sqrt ratio in Q13 (sqrt of en1/en2 in Q26).
amplitude_ratio = WebRtcSpl_SqrtFloor(energy_ratio << 13);
// Copy the two vectors and give them the same energy.
diff --git a/modules/audio_coding/neteq/interface/audio_decoder.h b/modules/audio_coding/neteq/interface/audio_decoder.h
index 9a2fb8b4..16d78c9e 100644
--- a/modules/audio_coding/neteq/interface/audio_decoder.h
+++ b/modules/audio_coding/neteq/interface/audio_decoder.h
@@ -63,12 +63,7 @@ class AudioDecoder {
// Used by PacketDuration below. Save the value -1 for errors.
enum { kNotImplemented = -2 };
- explicit AudioDecoder(enum NetEqDecoder type)
- : codec_type_(type),
- channels_(1),
- state_(NULL) {
- }
-
+ AudioDecoder() : channels_(1), state_(NULL) {}
virtual ~AudioDecoder() {}
// Decodes |encode_len| bytes from |encoded| and writes the result in
@@ -119,8 +114,6 @@ class AudioDecoder {
// Returns true if the packet has FEC and false otherwise.
virtual bool PacketHasFec(const uint8_t* encoded, size_t encoded_len) const;
- virtual NetEqDecoder codec_type() const;
-
// Returns the underlying decoder state.
void* state() { return state_; }
@@ -140,7 +133,6 @@ class AudioDecoder {
protected:
static SpeechType ConvertSpeechType(int16_t type);
- enum NetEqDecoder codec_type_;
size_t channels_;
void* state_;
diff --git a/modules/audio_coding/neteq/interface/neteq.h b/modules/audio_coding/neteq/interface/neteq.h
index 925cb231..560e77ba 100644
--- a/modules/audio_coding/neteq/interface/neteq.h
+++ b/modules/audio_coding/neteq/interface/neteq.h
@@ -248,7 +248,7 @@ class NetEq {
// Returns the error code for the last occurred error. If no error has
// occurred, 0 is returned.
- virtual int LastError() = 0;
+ virtual int LastError() const = 0;
// Returns the error code last returned by a decoder (audio or comfort noise).
// When LastError() returns kDecoderErrorCode or kComfortNoiseErrorCode, check
diff --git a/modules/audio_coding/neteq/mock/mock_audio_decoder.h b/modules/audio_coding/neteq/mock/mock_audio_decoder.h
index f3cecc24..95b564d1 100644
--- a/modules/audio_coding/neteq/mock/mock_audio_decoder.h
+++ b/modules/audio_coding/neteq/mock/mock_audio_decoder.h
@@ -19,7 +19,7 @@ namespace webrtc {
class MockAudioDecoder : public AudioDecoder {
public:
- MockAudioDecoder() : AudioDecoder(kDecoderArbitrary) {}
+ MockAudioDecoder() {}
virtual ~MockAudioDecoder() { Die(); }
MOCK_METHOD0(Die, void());
MOCK_METHOD4(Decode, int(const uint8_t*, size_t, int16_t*,
diff --git a/modules/audio_coding/neteq/mock/mock_external_decoder_pcm16b.h b/modules/audio_coding/neteq/mock/mock_external_decoder_pcm16b.h
index ef5e03e5..400c0b03 100644
--- a/modules/audio_coding/neteq/mock/mock_external_decoder_pcm16b.h
+++ b/modules/audio_coding/neteq/mock/mock_external_decoder_pcm16b.h
@@ -27,15 +27,13 @@ using ::testing::Invoke;
// audio_decoder_impl.{cc, h}.
class ExternalPcm16B : public AudioDecoder {
public:
- explicit ExternalPcm16B(enum NetEqDecoder type)
- : AudioDecoder(type) {
- }
+ ExternalPcm16B() {}
virtual int Decode(const uint8_t* encoded, size_t encoded_len,
int16_t* decoded, SpeechType* speech_type) {
int16_t temp_type;
int16_t ret = WebRtcPcm16b_DecodeW16(
- state_, reinterpret_cast<int16_t*>(const_cast<uint8_t*>(encoded)),
+ reinterpret_cast<int16_t*>(const_cast<uint8_t*>(encoded)),
static_cast<int16_t>(encoded_len), decoded, &temp_type);
*speech_type = ConvertSpeechType(temp_type);
return ret;
@@ -51,9 +49,7 @@ class ExternalPcm16B : public AudioDecoder {
// The reason is that we can then track that the correct calls are being made.
class MockExternalPcm16B : public ExternalPcm16B {
public:
- explicit MockExternalPcm16B(enum NetEqDecoder type)
- : ExternalPcm16B(type),
- real_(type) {
+ MockExternalPcm16B() {
// By default, all calls are delegated to the real object.
ON_CALL(*this, Decode(_, _, _, _))
.WillByDefault(Invoke(&real_, &ExternalPcm16B::Decode));
@@ -67,8 +63,6 @@ class MockExternalPcm16B : public ExternalPcm16B {
.WillByDefault(Invoke(&real_, &ExternalPcm16B::IncomingPacket));
ON_CALL(*this, ErrorCode())
.WillByDefault(Invoke(&real_, &ExternalPcm16B::ErrorCode));
- ON_CALL(*this, codec_type())
- .WillByDefault(Invoke(&real_, &ExternalPcm16B::codec_type));
}
virtual ~MockExternalPcm16B() { Die(); }
diff --git a/modules/audio_coding/neteq/mock/mock_packet_buffer.h b/modules/audio_coding/neteq/mock/mock_packet_buffer.h
index 74eea6f0..0eb7edc9 100644
--- a/modules/audio_coding/neteq/mock/mock_packet_buffer.h
+++ b/modules/audio_coding/neteq/mock/mock_packet_buffer.h
@@ -44,7 +44,9 @@ class MockPacketBuffer : public PacketBuffer {
Packet*(int* discard_count));
MOCK_METHOD0(DiscardNextPacket,
int());
- MOCK_METHOD1(DiscardOldPackets,
+ MOCK_METHOD2(DiscardOldPackets,
+ int(uint32_t timestamp_limit, uint32_t horizon_samples));
+ MOCK_METHOD1(DiscardAllOldPackets,
int(uint32_t timestamp_limit));
MOCK_CONST_METHOD0(NumPacketsInBuffer,
int());
diff --git a/modules/audio_coding/neteq/neteq.gypi b/modules/audio_coding/neteq/neteq.gypi
index 0901615a..c68651d6 100644
--- a/modules/audio_coding/neteq/neteq.gypi
+++ b/modules/audio_coding/neteq/neteq.gypi
@@ -136,6 +136,7 @@
'type': '<(gtest_target_type)',
'dependencies': [
'<@(codecs)',
+ 'neteq_unittest_tools',
'<(DEPTH)/testing/gtest.gyp:gtest',
'<(webrtc_root)/common_audio/common_audio.gyp:common_audio',
'<(webrtc_root)/test/test.gyp:test_support_main',
@@ -170,7 +171,7 @@
'type': 'static_library',
'dependencies': [
'rtp_rtcp',
- '<(webrtc_root)/test/webrtc_test_common.gyp:webrtc_test_common',
+ '<(webrtc_root)/test/test.gyp:rtp_test_utils',
],
'direct_dependent_settings': {
'include_dirs': [
@@ -193,6 +194,8 @@
'tools/packet.cc',
'tools/packet.h',
'tools/packet_source.h',
+ 'tools/resample_input_audio_file.cc',
+ 'tools/resample_input_audio_file.h',
'tools/rtp_file_source.cc',
'tools/rtp_file_source.h',
'tools/rtp_generator.cc',
@@ -222,7 +225,6 @@
],
'includes': [
'../../../build/isolate.gypi',
- 'audio_decoder_unittests.isolate',
],
'sources': [
'audio_decoder_unittests.isolate',
diff --git a/modules/audio_coding/neteq/neteq_external_decoder_unittest.cc b/modules/audio_coding/neteq/neteq_external_decoder_unittest.cc
index 6a8eafa1..d41bc543 100644
--- a/modules/audio_coding/neteq/neteq_external_decoder_unittest.cc
+++ b/modules/audio_coding/neteq/neteq_external_decoder_unittest.cc
@@ -47,7 +47,7 @@ class NetEqExternalDecoderTest : public ::testing::Test {
frame_size_ms_(10),
frame_size_samples_(frame_size_ms_ * samples_per_ms_),
output_size_samples_(frame_size_ms_ * samples_per_ms_),
- external_decoder_(new MockExternalPcm16B(kDecoderPCM16Bswb32kHz)),
+ external_decoder_(new MockExternalPcm16B),
rtp_generator_(new test::RtpGenerator(samples_per_ms_)),
payload_size_bytes_(0),
last_send_time_(0),
@@ -241,7 +241,7 @@ class LargeTimestampJumpTest : public NetEqExternalDecoderTest {
frame_size_samples_ = frame_size_ms_ * samples_per_ms_;
output_size_samples_ = frame_size_ms_ * samples_per_ms_;
EXPECT_CALL(*external_decoder_, Die()).Times(1);
- external_decoder_.reset(new MockExternalPcm16B(kDecoderPCM16B));
+ external_decoder_.reset(new MockExternalPcm16B);
}
void SetUp() OVERRIDE {
@@ -308,6 +308,8 @@ class LargeTimestampJumpTest : public NetEqExternalDecoderTest {
case kExpandPhase: {
if (output_type == kOutputPLCtoCNG) {
test_state_ = kFadedExpandPhase;
+ } else if (output_type == kOutputNormal) {
+ test_state_ = kRecovered;
}
break;
}
@@ -337,9 +339,14 @@ class LargeTimestampJumpTest : public NetEqExternalDecoderTest {
}
int NumExpectedDecodeCalls(int num_loops) const OVERRIDE {
- // Some packets won't be decoded because of the buffer being flushed after
- // the timestamp jump.
- return num_loops - (config_.max_packets_in_buffer + 1);
+ // Some packets at the end of the stream won't be decoded. When the jump in
+ // timestamp happens, NetEq will do Expand during one GetAudio call. In the
+ // next call it will decode the packet after the jump, but the net result is
+ // that the delay increased by 1 packet. In another call, a Pre-emptive
+ // Expand operation is performed, leading to delay increase by 1 packet. In
+ // total, the test will end with a 2-packet delay, which results in the 2
+ // last packets not being decoded.
+ return num_loops - 2;
}
TestStates test_state_;
diff --git a/modules/audio_coding/neteq/neteq_impl.cc b/modules/audio_coding/neteq/neteq_impl.cc
index edf618ef..f3d1a4f6 100644
--- a/modules/audio_coding/neteq/neteq_impl.cc
+++ b/modules/audio_coding/neteq/neteq_impl.cc
@@ -352,7 +352,7 @@ bool NetEqImpl::GetPlayoutTimestamp(uint32_t* timestamp) {
return true;
}
-int NetEqImpl::LastError() {
+int NetEqImpl::LastError() const {
CriticalSectionScoped lock(crit_sect_.get());
return error_code_;
}
@@ -868,6 +868,10 @@ int NetEqImpl::GetDecision(Operations* operation,
assert(sync_buffer_.get());
uint32_t end_timestamp = sync_buffer_->end_timestamp();
+ if (!new_codec_) {
+ const uint32_t five_seconds_samples = 5 * fs_hz_;
+ packet_buffer_->DiscardOldPackets(end_timestamp, five_seconds_samples);
+ }
const RTPHeader* header = packet_buffer_->NextRtpHeader();
if (decision_logic_->CngRfc3389On() || last_mode_ == kModeRfc3389Cng) {
@@ -884,7 +888,7 @@ int NetEqImpl::GetDecision(Operations* operation,
}
// Check buffer again.
if (!new_codec_) {
- packet_buffer_->DiscardOldPackets(end_timestamp);
+ packet_buffer_->DiscardOldPackets(end_timestamp, 5 * fs_hz_);
}
header = packet_buffer_->NextRtpHeader();
}
@@ -1823,7 +1827,7 @@ int NetEqImpl::ExtractPackets(int required_samples, PacketList* packet_list) {
// we could end up in the situation where we never decode anything, since
// all incoming packets are considered too old but the buffer will also
// never be flooded and flushed.
- packet_buffer_->DiscardOldPackets(timestamp_);
+ packet_buffer_->DiscardAllOldPackets(timestamp_);
}
return extracted_samples;
diff --git a/modules/audio_coding/neteq/neteq_impl.h b/modules/audio_coding/neteq/neteq_impl.h
index fc2284d9..348f483c 100644
--- a/modules/audio_coding/neteq/neteq_impl.h
+++ b/modules/audio_coding/neteq/neteq_impl.h
@@ -178,7 +178,7 @@ class NetEqImpl : public webrtc::NetEq {
// Returns the error code for the last occurred error. If no error has
// occurred, 0 is returned.
- virtual int LastError() OVERRIDE;
+ virtual int LastError() const OVERRIDE;
// Returns the error code last returned by a decoder (audio or comfort noise).
// When LastError() returns kDecoderErrorCode or kComfortNoiseErrorCode, check
diff --git a/modules/audio_coding/neteq/neteq_impl_unittest.cc b/modules/audio_coding/neteq/neteq_impl_unittest.cc
index d5676d7b..8047fe20 100644
--- a/modules/audio_coding/neteq/neteq_impl_unittest.cc
+++ b/modules/audio_coding/neteq/neteq_impl_unittest.cc
@@ -32,9 +32,11 @@ using ::testing::Return;
using ::testing::ReturnNull;
using ::testing::_;
using ::testing::SetArgPointee;
+using ::testing::SetArrayArgument;
using ::testing::InSequence;
using ::testing::Invoke;
using ::testing::WithArg;
+using ::testing::Pointee;
namespace webrtc {
@@ -422,8 +424,7 @@ TEST_F(NetEqImplTest, VerifyTimestampPropagation) {
// sample, and then increasing by 1 for each sample.
class CountingSamplesDecoder : public AudioDecoder {
public:
- explicit CountingSamplesDecoder(enum NetEqDecoder type)
- : AudioDecoder(type), next_value_(1) {}
+ CountingSamplesDecoder() : next_value_(1) {}
// Produce as many samples as input bytes (|encoded_len|).
virtual int Decode(const uint8_t* encoded,
@@ -446,7 +447,7 @@ TEST_F(NetEqImplTest, VerifyTimestampPropagation) {
private:
int16_t next_value_;
- } decoder_(kDecoderPCM16B);
+ } decoder_;
EXPECT_EQ(NetEq::kOK,
neteq_->RegisterExternalDecoder(
@@ -495,4 +496,95 @@ TEST_F(NetEqImplTest, VerifyTimestampPropagation) {
static_cast<int>(sync_buffer->FutureLength()));
}
+TEST_F(NetEqImplTest, ReorderedPacket) {
+ UseNoMocks();
+ CreateInstance();
+
+ const uint8_t kPayloadType = 17; // Just an arbitrary number.
+ const uint32_t kReceiveTime = 17; // Value doesn't matter for this test.
+ const int kSampleRateHz = 8000;
+ const int kPayloadLengthSamples = 10 * kSampleRateHz / 1000; // 10 ms.
+ const size_t kPayloadLengthBytes = kPayloadLengthSamples;
+ uint8_t payload[kPayloadLengthBytes] = {0};
+ WebRtcRTPHeader rtp_header;
+ rtp_header.header.payloadType = kPayloadType;
+ rtp_header.header.sequenceNumber = 0x1234;
+ rtp_header.header.timestamp = 0x12345678;
+ rtp_header.header.ssrc = 0x87654321;
+
+ // Create a mock decoder object.
+ MockAudioDecoder mock_decoder;
+ EXPECT_CALL(mock_decoder, Init()).WillRepeatedly(Return(0));
+ EXPECT_CALL(mock_decoder, IncomingPacket(_, kPayloadLengthBytes, _, _, _))
+ .WillRepeatedly(Return(0));
+ int16_t dummy_output[kPayloadLengthSamples] = {0};
+ // The below expectation will make the mock decoder write
+ // |kPayloadLengthSamples| zeros to the output array, and mark it as speech.
+ EXPECT_CALL(mock_decoder, Decode(Pointee(0), kPayloadLengthBytes, _, _))
+ .WillOnce(DoAll(SetArrayArgument<2>(dummy_output,
+ dummy_output + kPayloadLengthSamples),
+ SetArgPointee<3>(AudioDecoder::kSpeech),
+ Return(kPayloadLengthSamples)));
+ EXPECT_EQ(NetEq::kOK,
+ neteq_->RegisterExternalDecoder(
+ &mock_decoder, kDecoderPCM16B, kPayloadType));
+
+ // Insert one packet.
+ EXPECT_EQ(NetEq::kOK,
+ neteq_->InsertPacket(
+ rtp_header, payload, kPayloadLengthBytes, kReceiveTime));
+
+ // Pull audio once.
+ const int kMaxOutputSize = 10 * kSampleRateHz / 1000;
+ int16_t output[kMaxOutputSize];
+ int samples_per_channel;
+ int num_channels;
+ NetEqOutputType type;
+ EXPECT_EQ(
+ NetEq::kOK,
+ neteq_->GetAudio(
+ kMaxOutputSize, output, &samples_per_channel, &num_channels, &type));
+ ASSERT_EQ(kMaxOutputSize, samples_per_channel);
+ EXPECT_EQ(1, num_channels);
+ EXPECT_EQ(kOutputNormal, type);
+
+ // Insert two more packets. The first one is out of order, and is already too
+ // old, the second one is the expected next packet.
+ rtp_header.header.sequenceNumber -= 1;
+ rtp_header.header.timestamp -= kPayloadLengthSamples;
+ payload[0] = 1;
+ EXPECT_EQ(NetEq::kOK,
+ neteq_->InsertPacket(
+ rtp_header, payload, kPayloadLengthBytes, kReceiveTime));
+ rtp_header.header.sequenceNumber += 2;
+ rtp_header.header.timestamp += 2 * kPayloadLengthSamples;
+ payload[0] = 2;
+ EXPECT_EQ(NetEq::kOK,
+ neteq_->InsertPacket(
+ rtp_header, payload, kPayloadLengthBytes, kReceiveTime));
+
+ // Expect only the second packet to be decoded (the one with "2" as the first
+ // payload byte).
+ EXPECT_CALL(mock_decoder, Decode(Pointee(2), kPayloadLengthBytes, _, _))
+ .WillOnce(DoAll(SetArrayArgument<2>(dummy_output,
+ dummy_output + kPayloadLengthSamples),
+ SetArgPointee<3>(AudioDecoder::kSpeech),
+ Return(kPayloadLengthSamples)));
+
+ // Pull audio once.
+ EXPECT_EQ(
+ NetEq::kOK,
+ neteq_->GetAudio(
+ kMaxOutputSize, output, &samples_per_channel, &num_channels, &type));
+ ASSERT_EQ(kMaxOutputSize, samples_per_channel);
+ EXPECT_EQ(1, num_channels);
+ EXPECT_EQ(kOutputNormal, type);
+
+ // Now check the packet buffer, and make sure it is empty, since the
+ // out-of-order packet should have been discarded.
+ EXPECT_TRUE(packet_buffer_->Empty());
+
+ EXPECT_CALL(mock_decoder, Die());
+}
+
} // namespace webrtc
diff --git a/modules/audio_coding/neteq/neteq_tests.gypi b/modules/audio_coding/neteq/neteq_tests.gypi
index d134dcd4..48cd9ebe 100644
--- a/modules/audio_coding/neteq/neteq_tests.gypi
+++ b/modules/audio_coding/neteq/neteq_tests.gypi
@@ -87,7 +87,7 @@
'neteq_unittest_tools',
'<(DEPTH)/testing/gtest.gyp:gtest',
'<(DEPTH)/third_party/gflags/gflags.gyp:gflags',
- '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:field_trial_default',
+ '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers_default',
],
'sources': [
'tools/rtp_analyze.cc',
diff --git a/modules/audio_coding/neteq/packet_buffer.cc b/modules/audio_coding/neteq/packet_buffer.cc
index 4c484185..816713d8 100644
--- a/modules/audio_coding/neteq/packet_buffer.cc
+++ b/modules/audio_coding/neteq/packet_buffer.cc
@@ -216,12 +216,12 @@ int PacketBuffer::DiscardNextPacket() {
return kOK;
}
-int PacketBuffer::DiscardOldPackets(uint32_t timestamp_limit) {
- while (!Empty() &&
- timestamp_limit != buffer_.front()->header.timestamp &&
- static_cast<uint32_t>(timestamp_limit
- - buffer_.front()->header.timestamp) <
- 0xFFFFFFFF / 2) {
+int PacketBuffer::DiscardOldPackets(uint32_t timestamp_limit,
+ uint32_t horizon_samples) {
+ while (!Empty() && timestamp_limit != buffer_.front()->header.timestamp &&
+ IsObsoleteTimestamp(buffer_.front()->header.timestamp,
+ timestamp_limit,
+ horizon_samples)) {
if (DiscardNextPacket() != kOK) {
assert(false); // Must be ok by design.
}
diff --git a/modules/audio_coding/neteq/packet_buffer.h b/modules/audio_coding/neteq/packet_buffer.h
index 76c4ddd1..b9a16189 100644
--- a/modules/audio_coding/neteq/packet_buffer.h
+++ b/modules/audio_coding/neteq/packet_buffer.h
@@ -95,9 +95,19 @@ class PacketBuffer {
// PacketBuffer::kOK otherwise.
virtual int DiscardNextPacket();
- // Discards all packets that are (strictly) older than |timestamp_limit|.
+ // Discards all packets that are (strictly) older than timestamp_limit,
+ // but newer than timestamp_limit - horizon_samples. Setting horizon_samples
+ // to zero implies that the horizon is set to half the timestamp range. That
+ // is, if a packet is more than 2^31 timestamps into the future compared with
+ // timestamp_limit (including wrap-around), it is considered old.
// Returns number of packets discarded.
- virtual int DiscardOldPackets(uint32_t timestamp_limit);
+ virtual int DiscardOldPackets(uint32_t timestamp_limit,
+ uint32_t horizon_samples);
+
+ // Discards all packets that are (strictly) older than timestamp_limit.
+ virtual int DiscardAllOldPackets(uint32_t timestamp_limit) {
+ return DiscardOldPackets(timestamp_limit, 0);
+ }
// Returns the number of packets in the buffer, including duplicates and
// redundant packets.
@@ -125,6 +135,20 @@ class PacketBuffer {
// in |packet_list|.
static void DeleteAllPackets(PacketList* packet_list);
+ // Static method returning true if |timestamp| is older than |timestamp_limit|
+ // but less than |horizon_samples| behind |timestamp_limit|. For instance,
+ // with timestamp_limit = 100 and horizon_samples = 10, a timestamp in the
+ // range (90, 100) is considered obsolete, and will yield true.
+ // Setting |horizon_samples| to 0 is the same as setting it to 2^31, i.e.,
+ // half the 32-bit timestamp range.
+ static bool IsObsoleteTimestamp(uint32_t timestamp,
+ uint32_t timestamp_limit,
+ uint32_t horizon_samples) {
+ return IsNewerTimestamp(timestamp_limit, timestamp) &&
+ (horizon_samples == 0 ||
+ IsNewerTimestamp(timestamp, timestamp_limit - horizon_samples));
+ }
+
private:
size_t max_number_of_packets_;
PacketList buffer_;
diff --git a/modules/audio_coding/neteq/packet_buffer_unittest.cc b/modules/audio_coding/neteq/packet_buffer_unittest.cc
index 478328cb..dc8b68c3 100644
--- a/modules/audio_coding/neteq/packet_buffer_unittest.cc
+++ b/modules/audio_coding/neteq/packet_buffer_unittest.cc
@@ -391,7 +391,7 @@ TEST(PacketBuffer, Failures) {
EXPECT_EQ(NULL, buffer->NextRtpHeader());
EXPECT_EQ(NULL, buffer->GetNextPacket(NULL));
EXPECT_EQ(PacketBuffer::kBufferEmpty, buffer->DiscardNextPacket());
- EXPECT_EQ(0, buffer->DiscardOldPackets(0)); // 0 packets discarded.
+ EXPECT_EQ(0, buffer->DiscardAllOldPackets(0)); // 0 packets discarded.
// Insert one packet to make the buffer non-empty.
packet = gen.NextPacket(payload_len);
@@ -513,4 +513,61 @@ TEST(PacketBuffer, DeleteAllPackets) {
EXPECT_FALSE(PacketBuffer::DeleteFirstPacket(&list));
}
+namespace {
+void TestIsObsoleteTimestamp(uint32_t limit_timestamp) {
+ // Check with zero horizon, which implies that the horizon is at 2^31, i.e.,
+ // half the timestamp range.
+ static const uint32_t kZeroHorizon = 0;
+ static const uint32_t k2Pow31Minus1 = 0x7FFFFFFF;
+ // Timestamp on the limit is not old.
+ EXPECT_FALSE(PacketBuffer::IsObsoleteTimestamp(
+ limit_timestamp, limit_timestamp, kZeroHorizon));
+ // 1 sample behind is old.
+ EXPECT_TRUE(PacketBuffer::IsObsoleteTimestamp(
+ limit_timestamp - 1, limit_timestamp, kZeroHorizon));
+ // 2^31 - 1 samples behind is old.
+ EXPECT_TRUE(PacketBuffer::IsObsoleteTimestamp(
+ limit_timestamp - k2Pow31Minus1, limit_timestamp, kZeroHorizon));
+ // 1 sample ahead is not old.
+ EXPECT_FALSE(PacketBuffer::IsObsoleteTimestamp(
+ limit_timestamp + 1, limit_timestamp, kZeroHorizon));
+ // 2^31 samples ahead is not old.
+ EXPECT_FALSE(PacketBuffer::IsObsoleteTimestamp(
+ limit_timestamp + (1 << 31), limit_timestamp, kZeroHorizon));
+
+ // Fixed horizon at 10 samples.
+ static const uint32_t kHorizon = 10;
+ // Timestamp on the limit is not old.
+ EXPECT_FALSE(PacketBuffer::IsObsoleteTimestamp(
+ limit_timestamp, limit_timestamp, kHorizon));
+ // 1 sample behind is old.
+ EXPECT_TRUE(PacketBuffer::IsObsoleteTimestamp(
+ limit_timestamp - 1, limit_timestamp, kHorizon));
+ // 9 samples behind is old.
+ EXPECT_TRUE(PacketBuffer::IsObsoleteTimestamp(
+ limit_timestamp - 9, limit_timestamp, kHorizon));
+ // 10 samples behind is not old.
+ EXPECT_FALSE(PacketBuffer::IsObsoleteTimestamp(
+ limit_timestamp - 10, limit_timestamp, kHorizon));
+ // 2^31 - 1 samples behind is not old.
+ EXPECT_FALSE(PacketBuffer::IsObsoleteTimestamp(
+ limit_timestamp - k2Pow31Minus1, limit_timestamp, kHorizon));
+ // 1 sample ahead is not old.
+ EXPECT_FALSE(PacketBuffer::IsObsoleteTimestamp(
+ limit_timestamp + 1, limit_timestamp, kHorizon));
+ // 2^31 samples ahead is not old.
+ EXPECT_FALSE(PacketBuffer::IsObsoleteTimestamp(
+ limit_timestamp + (1 << 31), limit_timestamp, kHorizon));
+}
+} // namespace
+
+// Test the IsObsoleteTimestamp method with different limit timestamps.
+TEST(PacketBuffer, IsObsoleteTimestamp) {
+ TestIsObsoleteTimestamp(0);
+ TestIsObsoleteTimestamp(1);
+ TestIsObsoleteTimestamp(0xFFFFFFFF); // -1 in uint32_t.
+ TestIsObsoleteTimestamp(0x80000000); // 2^31.
+ TestIsObsoleteTimestamp(0x80000001); // 2^31 + 1.
+ TestIsObsoleteTimestamp(0x7FFFFFFF); // 2^31 - 1.
+}
} // namespace webrtc
diff --git a/modules/audio_coding/neteq/test/RTPencode.cc b/modules/audio_coding/neteq/test/RTPencode.cc
index ab338a73..b73e70e5 100644
--- a/modules/audio_coding/neteq/test/RTPencode.cc
+++ b/modules/audio_coding/neteq/test/RTPencode.cc
@@ -235,9 +235,6 @@ WebRtcVadInst *VAD_inst[2];
#ifdef CODEC_CELT_32
CELT_encinst_t *CELT32enc_inst[2];
#endif
-#ifdef CODEC_G711
- void *G711state[2]={NULL, NULL};
-#endif
int main(int argc, char* argv[])
@@ -1602,12 +1599,12 @@ int NetEQTest_encode(int coder, int16_t *indata, int frameLen, unsigned char * e
/* Encode with the selected coder type */
if (coder==webrtc::kDecoderPCMu) { /*g711 u-law */
#ifdef CODEC_G711
- cdlen = WebRtcG711_EncodeU(G711state[k], indata, frameLen, (int16_t*) encoded);
+ cdlen = WebRtcG711_EncodeU(indata, frameLen, (int16_t*) encoded);
#endif
}
else if (coder==webrtc::kDecoderPCMa) { /*g711 A-law */
#ifdef CODEC_G711
- cdlen = WebRtcG711_EncodeA(G711state[k], indata, frameLen, (int16_t*) encoded);
+ cdlen = WebRtcG711_EncodeA(indata, frameLen, (int16_t*) encoded);
}
#endif
#ifdef CODEC_PCM16B
diff --git a/modules/audio_coding/neteq/tools/neteq_rtpplay.cc b/modules/audio_coding/neteq/tools/neteq_rtpplay.cc
index 46ef3d08..ef2c0b6b 100644
--- a/modules/audio_coding/neteq/tools/neteq_rtpplay.cc
+++ b/modules/audio_coding/neteq/tools/neteq_rtpplay.cc
@@ -92,6 +92,9 @@ static const bool isac_dummy =
DEFINE_int32(isac_swb, 104, "RTP payload type for iSAC-swb (32 kHz)");
static const bool isac_swb_dummy =
google::RegisterFlagValidator(&FLAGS_isac_swb, &ValidatePayloadType);
+DEFINE_int32(opus, 111, "RTP payload type for Opus");
+static const bool opus_dummy =
+ google::RegisterFlagValidator(&FLAGS_opus, &ValidatePayloadType);
DEFINE_int32(pcm16b, 93, "RTP payload type for PCM16b-nb (8 kHz)");
static const bool pcm16b_dummy =
google::RegisterFlagValidator(&FLAGS_pcm16b, &ValidatePayloadType);
@@ -286,8 +289,24 @@ int main(int argc, char* argv[]) {
static_cast<int>(payload_len),
packet->time_ms() * sample_rate_hz / 1000);
if (error != NetEq::kOK) {
- std::cerr << "InsertPacket returned error code " << neteq->LastError()
- << std::endl;
+ if (neteq->LastError() == NetEq::kUnknownRtpPayloadType) {
+ std::cerr << "RTP Payload type "
+ << static_cast<int>(rtp_header.header.payloadType)
+ << " is unknown." << std::endl;
+ std::cerr << "Use --codec_map to view default mapping." << std::endl;
+ std::cerr << "Use --helpshort for information on how to make custom "
+ "mappings." << std::endl;
+ } else {
+ std::cerr << "InsertPacket returned error code " << neteq->LastError()
+ << std::endl;
+ std::cerr << "Header data:" << std::endl;
+ std::cerr << " PT = "
+ << static_cast<int>(rtp_header.header.payloadType)
+ << std::endl;
+ std::cerr << " SN = " << rtp_header.header.sequenceNumber
+ << std::endl;
+ std::cerr << " TS = " << rtp_header.header.timestamp << std::endl;
+ }
}
// Get next packet from file.
@@ -366,6 +385,8 @@ std::string CodecName(webrtc::NetEqDecoder codec) {
return "iSAC";
case webrtc::kDecoderISACswb:
return "iSAC-swb (32 kHz)";
+ case webrtc::kDecoderOpus:
+ return "Opus";
case webrtc::kDecoderPCM16B:
return "PCM16b-nb (8 kHz)";
case webrtc::kDecoderPCM16Bwb:
@@ -428,6 +449,12 @@ void RegisterPayloadTypes(NetEq* neteq) {
" as " << CodecName(webrtc::kDecoderISACswb).c_str() << std::endl;
exit(1);
}
+ error = neteq->RegisterPayloadType(webrtc::kDecoderOpus, FLAGS_opus);
+ if (error) {
+ std::cerr << "Cannot register payload type " << FLAGS_opus << " as "
+ << CodecName(webrtc::kDecoderOpus).c_str() << std::endl;
+ exit(1);
+ }
error = neteq->RegisterPayloadType(webrtc::kDecoderPCM16B, FLAGS_pcm16b);
if (error) {
std::cerr << "Cannot register payload type " << FLAGS_pcm16b <<
@@ -514,6 +541,8 @@ void PrintCodecMapping() {
std::endl;
std::cout << CodecName(webrtc::kDecoderISACswb).c_str() << ": " <<
FLAGS_isac_swb << std::endl;
+ std::cout << CodecName(webrtc::kDecoderOpus).c_str() << ": " << FLAGS_opus
+ << std::endl;
std::cout << CodecName(webrtc::kDecoderPCM16B).c_str() << ": " <<
FLAGS_pcm16b << std::endl;
std::cout << CodecName(webrtc::kDecoderPCM16Bwb).c_str() << ": " <<
@@ -637,8 +666,8 @@ int CodecSampleRate(uint8_t payload_type) {
payload_type == FLAGS_pcm16b_swb32 ||
payload_type == FLAGS_cn_swb32) {
return 32000;
- } else if (payload_type == FLAGS_pcm16b_swb48 ||
- payload_type == FLAGS_cn_swb48) {
+ } else if (payload_type == FLAGS_opus || payload_type == FLAGS_pcm16b_swb48 ||
+ payload_type == FLAGS_cn_swb48) {
return 48000;
} else if (payload_type == FLAGS_avt ||
payload_type == FLAGS_red) {
diff --git a/modules/audio_coding/neteq/tools/resample_input_audio_file.cc b/modules/audio_coding/neteq/tools/resample_input_audio_file.cc
new file mode 100644
index 00000000..f391466c
--- /dev/null
+++ b/modules/audio_coding/neteq/tools/resample_input_audio_file.cc
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/modules/audio_coding/neteq/tools/resample_input_audio_file.h"
+
+#include "webrtc/base/checks.h"
+#include "webrtc/system_wrappers/interface/scoped_ptr.h"
+
+namespace webrtc {
+namespace test {
+
+bool ResampleInputAudioFile::Read(size_t samples,
+ int output_rate_hz,
+ int16_t* destination) {
+ const size_t samples_to_read = samples * file_rate_hz_ / output_rate_hz;
+ CHECK_EQ(samples_to_read * output_rate_hz, samples * file_rate_hz_)
+ << "Frame size and sample rates don't add up to an integer.";
+ scoped_ptr<int16_t[]> temp_destination(new int16_t[samples_to_read]);
+ if (!InputAudioFile::Read(samples_to_read, temp_destination.get()))
+ return false;
+ resampler_.ResetIfNeeded(
+ file_rate_hz_, output_rate_hz, kResamplerSynchronous);
+ int output_length = 0;
+ CHECK_EQ(resampler_.Push(temp_destination.get(),
+ static_cast<int>(samples_to_read),
+ destination,
+ static_cast<int>(samples),
+ output_length),
+ 0);
+ CHECK_EQ(static_cast<int>(samples), output_length);
+ return true;
+}
+
+} // namespace test
+} // namespace webrtc
diff --git a/modules/audio_coding/neteq/tools/resample_input_audio_file.h b/modules/audio_coding/neteq/tools/resample_input_audio_file.h
new file mode 100644
index 00000000..8c028005
--- /dev/null
+++ b/modules/audio_coding/neteq/tools/resample_input_audio_file.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_AUDIO_CODING_NETEQ_TOOLS_RESAMPLE_INPUT_AUDIO_FILE_H_
+#define WEBRTC_MODULES_AUDIO_CODING_NETEQ_TOOLS_RESAMPLE_INPUT_AUDIO_FILE_H_
+
+#include <string>
+
+#include "webrtc/base/constructormagic.h"
+#include "webrtc/common_audio/resampler/include/resampler.h"
+#include "webrtc/modules/audio_coding/neteq/tools/input_audio_file.h"
+#include "webrtc/typedefs.h"
+
+namespace webrtc {
+namespace test {
+
+// Class for handling a looping input audio file with resampling.
+class ResampleInputAudioFile : public InputAudioFile {
+ public:
+ ResampleInputAudioFile(const std::string file_name, int file_rate_hz)
+ : InputAudioFile(file_name), file_rate_hz_(file_rate_hz) {}
+
+ bool Read(size_t samples, int output_rate_hz, int16_t* destination);
+
+ private:
+ const int file_rate_hz_;
+ Resampler resampler_;
+ DISALLOW_COPY_AND_ASSIGN(ResampleInputAudioFile);
+};
+
+} // namespace test
+} // namespace webrtc
+#endif // WEBRTC_MODULES_AUDIO_CODING_NETEQ_TOOLS_RESAMPLE_INPUT_AUDIO_FILE_H_