diff options
Diffstat (limited to 'chromium/third_party/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc')
-rw-r--r-- | chromium/third_party/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc | 931 |
1 files changed, 931 insertions, 0 deletions
diff --git a/chromium/third_party/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc b/chromium/third_party/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc new file mode 100644 index 00000000000..f82644cbc26 --- /dev/null +++ b/chromium/third_party/webrtc/modules/audio_coding/neteq/audio_decoder_unittest.cc @@ -0,0 +1,931 @@ +/* + * Copyright (c) 2012 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/audio_decoder_impl.h" + +#include <assert.h> +#include <stdlib.h> + +#include <string> + +#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/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/pcm16b/include/pcm16b.h" +#include "webrtc/system_wrappers/interface/data_log.h" +#include "webrtc/test/testsupport/fileutils.h" + +namespace webrtc { + +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"; + } + + virtual ~AudioDecoderTest() {} + + virtual void SetUp() { + // Create arrays. + ASSERT_GT(data_length_, 0u) << "The test must set data_length_ > 0"; + input_ = new int16_t[data_length_]; + 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(); + DataLog::AddTable("CodecTest"); + DataLog::AddColumn("CodecTest", "input", 1); + DataLog::AddColumn("CodecTest", "output", 1); + } + + 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; + + // Encodes and decodes audio. The absolute difference between the input and + // output is compared vs |tolerance|, and the mean-squared error is compared + // with |mse|. The encoded stream should contain |expected_bytes|. For stereo + // audio, the absolute difference between the two channels is compared vs + // |channel_diff_tolerance|. + void EncodeDecodeTest(size_t expected_bytes, int tolerance, double mse, + int delay = 0, int channel_diff_tolerance = 0) { + ASSERT_GE(tolerance, 0) << "Test must define a tolerance >= 0"; + ASSERT_GE(channel_diff_tolerance, 0) << + "Test must define a channel_diff_tolerance >= 0"; + size_t processed_samples = 0u; + encoded_bytes_ = 0u; + InitEncoder(); + EXPECT_EQ(0, decoder_->Init()); + while (processed_samples + frame_size_ <= data_length_) { + size_t enc_len = EncodeFrame(&input_[processed_samples], frame_size_, + &encoded_[encoded_bytes_]); + AudioDecoder::SpeechType speech_type; + 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; + processed_samples += frame_size_; + } + // For some codecs it doesn't make sense to check expected number of bytes, + // since the number can vary for different platforms. Opus and iSAC are + // such codecs. In this case expected_bytes is set to 0. + if (expected_bytes) { + EXPECT_EQ(expected_bytes, encoded_bytes_); + } + CompareInputOutput(processed_samples, 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); + } + + // Encodes a payload and decodes it twice with decoder re-init before each + // decode. Verifies that the decoded result is the same. + void ReInitTest() { + uint8_t* encoded = encoded_; + uint8_t* encoded_copy = encoded_ + 2 * frame_size_; + int16_t* output1 = decoded_; + int16_t* output2 = decoded_ + frame_size_; + InitEncoder(); + size_t enc_len = EncodeFrame(input_, frame_size_, encoded); + size_t dec_len; + // Copy payload since iSAC fix destroys it during decode. + // Issue: http://code.google.com/p/webrtc/issues/detail?id=845. + // TODO(hlundin): Remove if the iSAC bug gets fixed. + memcpy(encoded_copy, encoded, enc_len); + AudioDecoder::SpeechType speech_type1, speech_type2; + EXPECT_EQ(0, decoder_->Init()); + dec_len = decoder_->Decode(encoded, enc_len, output1, &speech_type1); + EXPECT_EQ(frame_size_ * channels_, dec_len); + // Re-init decoder and decode again. + EXPECT_EQ(0, decoder_->Init()); + dec_len = decoder_->Decode(encoded_copy, enc_len, output2, &speech_type2); + 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; + } + EXPECT_EQ(speech_type1, speech_type2); + } + + // Call DecodePlc and verify that the correct number of samples is produced. + void DecodePlcTest() { + InitEncoder(); + size_t enc_len = EncodeFrame(input_, frame_size_, encoded_); + AudioDecoder::SpeechType speech_type; + EXPECT_EQ(0, decoder_->Init()); + size_t dec_len = + decoder_->Decode(encoded_, enc_len, decoded_, &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_); + EXPECT_EQ(frame_size_ * channels_, dec_len); + } + + std::string input_file_; + FILE* input_fp_; + int16_t* input_; + uint8_t* encoded_; + int16_t* decoded_; + size_t frame_size_; + size_t data_length_; + size_t encoded_bytes_; + size_t channels_; + AudioDecoder* decoder_; +}; + +class AudioDecoderPcmUTest : public AudioDecoderTest { + protected: + AudioDecoderPcmUTest() : 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; + } +}; + +class AudioDecoderPcmATest : public AudioDecoderTest { + protected: + AudioDecoderPcmATest() : 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; + } +}; + +class AudioDecoderPcm16BTest : public AudioDecoderTest { + protected: + AudioDecoderPcm16BTest() : AudioDecoderTest() { + frame_size_ = 160; + data_length_ = 10 * frame_size_; + decoder_ = new AudioDecoderPcm16B(kDecoderPCM16B); + assert(decoder_); + } + + virtual int EncodeFrame(const int16_t* input, size_t input_len_samples, + uint8_t* output) { + int enc_len_bytes = WebRtcPcm16b_EncodeW16( + const_cast<int16_t*>(input), static_cast<int>(input_len_samples), + reinterpret_cast<int16_t*>(output)); + EXPECT_EQ(2 * input_len_samples, static_cast<size_t>(enc_len_bytes)); + return enc_len_bytes; + } +}; + +class AudioDecoderIlbcTest : public AudioDecoderTest { + protected: + AudioDecoderIlbcTest() : AudioDecoderTest() { + frame_size_ = 240; + data_length_ = 10 * frame_size_; + decoder_ = new AudioDecoderIlbc; + assert(decoder_); + WebRtcIlbcfix_EncoderCreate(&encoder_); + } + + ~AudioDecoderIlbcTest() { + WebRtcIlbcfix_EncoderFree(encoder_); + } + + virtual void InitEncoder() { + ASSERT_EQ(0, WebRtcIlbcfix_EncoderInit(encoder_, 30)); // 30 ms. + } + + virtual int EncodeFrame(const int16_t* input, size_t input_len_samples, + uint8_t* output) { + int enc_len_bytes = + WebRtcIlbcfix_Encode(encoder_, input, + static_cast<int>(input_len_samples), + reinterpret_cast<int16_t*>(output)); + EXPECT_EQ(50, enc_len_bytes); + return enc_len_bytes; + } + + // Overload the default test since iLBC's function WebRtcIlbcfix_NetEqPlc does + // 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_); + AudioDecoder::SpeechType speech_type; + EXPECT_EQ(0, decoder_->Init()); + size_t dec_len = + decoder_->Decode(encoded_, enc_len, decoded_, &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_)); + } + + iLBC_encinst_t* encoder_; +}; + +class AudioDecoderIsacFloatTest : public AudioDecoderTest { + protected: + AudioDecoderIsacFloatTest() : AudioDecoderTest() { + input_size_ = 160; + frame_size_ = 480; + data_length_ = 10 * frame_size_; + decoder_ = new AudioDecoderIsac; + assert(decoder_); + WebRtcIsac_Create(&encoder_); + WebRtcIsac_SetEncSampRate(encoder_, 16000); + } + + ~AudioDecoderIsacFloatTest() { + WebRtcIsac_Free(encoder_); + } + + virtual void InitEncoder() { + ASSERT_EQ(0, WebRtcIsac_EncoderInit(encoder_, 1)); // Fixed mode. + ASSERT_EQ(0, WebRtcIsac_Control(encoder_, 32000, 30)); // 32 kbps, 30 ms. + } + + virtual int EncodeFrame(const int16_t* input, size_t input_len_samples, + uint8_t* output) { + // Insert 3 * 10 ms. Expect non-zero output on third call. + EXPECT_EQ(0, WebRtcIsac_Encode(encoder_, input, + reinterpret_cast<int16_t*>(output))); + input += input_size_; + EXPECT_EQ(0, WebRtcIsac_Encode(encoder_, input, + reinterpret_cast<int16_t*>(output))); + input += input_size_; + int enc_len_bytes = + WebRtcIsac_Encode(encoder_, input, reinterpret_cast<int16_t*>(output)); + EXPECT_GT(enc_len_bytes, 0); + return enc_len_bytes; + } + + ISACStruct* encoder_; + int input_size_; +}; + +class AudioDecoderIsacSwbTest : public AudioDecoderTest { + protected: + AudioDecoderIsacSwbTest() : AudioDecoderTest() { + input_size_ = 320; + frame_size_ = 960; + data_length_ = 10 * frame_size_; + decoder_ = new AudioDecoderIsacSwb; + assert(decoder_); + WebRtcIsac_Create(&encoder_); + WebRtcIsac_SetEncSampRate(encoder_, 32000); + } + + ~AudioDecoderIsacSwbTest() { + WebRtcIsac_Free(encoder_); + } + + virtual void InitEncoder() { + ASSERT_EQ(0, WebRtcIsac_EncoderInit(encoder_, 1)); // Fixed mode. + ASSERT_EQ(0, WebRtcIsac_Control(encoder_, 32000, 30)); // 32 kbps, 30 ms. + } + + virtual int EncodeFrame(const int16_t* input, size_t input_len_samples, + uint8_t* output) { + // Insert 3 * 10 ms. Expect non-zero output on third call. + EXPECT_EQ(0, WebRtcIsac_Encode(encoder_, input, + reinterpret_cast<int16_t*>(output))); + input += input_size_; + EXPECT_EQ(0, WebRtcIsac_Encode(encoder_, input, + reinterpret_cast<int16_t*>(output))); + input += input_size_; + int enc_len_bytes = + WebRtcIsac_Encode(encoder_, input, reinterpret_cast<int16_t*>(output)); + EXPECT_GT(enc_len_bytes, 0); + return enc_len_bytes; + } + + ISACStruct* encoder_; + 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() { + input_size_ = 160; + frame_size_ = 480; + data_length_ = 10 * frame_size_; + decoder_ = new AudioDecoderIsacFix; + assert(decoder_); + WebRtcIsacfix_Create(&encoder_); + } + + ~AudioDecoderIsacFixTest() { + WebRtcIsacfix_Free(encoder_); + } + + virtual void InitEncoder() { + ASSERT_EQ(0, WebRtcIsacfix_EncoderInit(encoder_, 1)); // Fixed mode. + ASSERT_EQ(0, + WebRtcIsacfix_Control(encoder_, 32000, 30)); // 32 kbps, 30 ms. + } + + virtual int EncodeFrame(const int16_t* input, size_t input_len_samples, + uint8_t* output) { + // Insert 3 * 10 ms. Expect non-zero output on third call. + EXPECT_EQ(0, WebRtcIsacfix_Encode(encoder_, input, + reinterpret_cast<int16_t*>(output))); + input += input_size_; + EXPECT_EQ(0, WebRtcIsacfix_Encode(encoder_, input, + reinterpret_cast<int16_t*>(output))); + input += input_size_; + int enc_len_bytes = WebRtcIsacfix_Encode( + encoder_, input, reinterpret_cast<int16_t*>(output)); + EXPECT_GT(enc_len_bytes, 0); + return enc_len_bytes; + } + + ISACFIX_MainStruct* encoder_; + int input_size_; +}; + +class AudioDecoderG722Test : public AudioDecoderTest { + protected: + AudioDecoderG722Test() : AudioDecoderTest() { + frame_size_ = 160; + data_length_ = 10 * frame_size_; + decoder_ = new AudioDecoderG722; + assert(decoder_); + WebRtcG722_CreateEncoder(&encoder_); + } + + ~AudioDecoderG722Test() { + WebRtcG722_FreeEncoder(encoder_); + } + + virtual void InitEncoder() { + ASSERT_EQ(0, WebRtcG722_EncoderInit(encoder_)); + } + + virtual int EncodeFrame(const int16_t* input, size_t input_len_samples, + uint8_t* output) { + int enc_len_bytes = + WebRtcG722_Encode(encoder_, const_cast<int16_t*>(input), + static_cast<int>(input_len_samples), + reinterpret_cast<int16_t*>(output)); + EXPECT_EQ(80, enc_len_bytes); + return enc_len_bytes; + } + + G722EncInst* encoder_; +}; + +class AudioDecoderG722StereoTest : public AudioDecoderG722Test { + protected: + AudioDecoderG722StereoTest() : AudioDecoderG722Test() { + channels_ = 2; + // Delete the |decoder_| that was created by AudioDecoderG722Test and + // create an AudioDecoderG722Stereo object instead. + delete decoder_; + decoder_ = new AudioDecoderG722Stereo; + assert(decoder_); + } + + virtual int EncodeFrame(const int16_t* input, size_t input_len_samples, + uint8_t* output) { + uint8_t* temp_output = new uint8_t[data_length_ * 2]; + // Encode a mono payload using the base test class. + int mono_enc_len_bytes = + AudioDecoderG722Test::EncodeFrame(input, input_len_samples, + temp_output); + // The bit-stream consists of 4-bit samples: + // +--------+--------+--------+ + // | s0 s1 | s2 s3 | s4 s5 | + // +--------+--------+--------+ + // + // Duplicate them to the |output| such that the stereo stream becomes: + // +--------+--------+--------+ + // | s0 s0 | s1 s1 | s2 s2 | + // +--------+--------+--------+ + EXPECT_LE(mono_enc_len_bytes * 2, static_cast<int>(data_length_ * 2)); + uint8_t* output_ptr = output; + for (int i = 0; i < mono_enc_len_bytes; ++i) { + *output_ptr = (temp_output[i] & 0xF0) + (temp_output[i] >> 4); + ++output_ptr; + *output_ptr = (temp_output[i] << 4) + (temp_output[i] & 0x0F); + ++output_ptr; + } + delete [] temp_output; + return mono_enc_len_bytes * 2; + } +}; + +#ifdef WEBRTC_CODEC_CELT +class AudioDecoderCeltTest : public AudioDecoderTest { + protected: + static const int kEncodingRateBitsPerSecond = 64000; + AudioDecoderCeltTest() : AudioDecoderTest(), encoder_(NULL) { + frame_size_ = 640; + data_length_ = 10 * frame_size_; + decoder_ = AudioDecoder::CreateAudioDecoder(kDecoderCELT_32); + assert(decoder_); + WebRtcCelt_CreateEnc(&encoder_, static_cast<int>(channels_)); + } + + ~AudioDecoderCeltTest() { + WebRtcCelt_FreeEnc(encoder_); + } + + virtual void InitEncoder() { + assert(encoder_); + ASSERT_EQ(0, WebRtcCelt_EncoderInit( + encoder_, static_cast<int>(channels_), kEncodingRateBitsPerSecond)); + } + + virtual int EncodeFrame(const int16_t* input, size_t input_len_samples, + uint8_t* output) { + assert(encoder_); + return WebRtcCelt_Encode(encoder_, input, output); + } + + CELT_encinst_t* encoder_; +}; + +class AudioDecoderCeltStereoTest : public AudioDecoderTest { + protected: + static const int kEncodingRateBitsPerSecond = 64000; + AudioDecoderCeltStereoTest() : AudioDecoderTest(), encoder_(NULL) { + channels_ = 2; + frame_size_ = 640; + data_length_ = 10 * frame_size_; + decoder_ = AudioDecoder::CreateAudioDecoder(kDecoderCELT_32_2ch); + assert(decoder_); + stereo_input_ = new int16_t[frame_size_ * channels_]; + WebRtcCelt_CreateEnc(&encoder_, static_cast<int>(channels_)); + } + + ~AudioDecoderCeltStereoTest() { + delete [] stereo_input_; + WebRtcCelt_FreeEnc(encoder_); + } + + virtual void InitEncoder() { + assert(encoder_); + ASSERT_EQ(0, WebRtcCelt_EncoderInit( + encoder_, static_cast<int>(channels_), kEncodingRateBitsPerSecond)); + } + + virtual int EncodeFrame(const int16_t* input, size_t input_len_samples, + uint8_t* output) { + assert(encoder_); + assert(stereo_input_); + for (size_t n = 0; n < frame_size_; ++n) { + stereo_input_[n * 2] = stereo_input_[n * 2 + 1] = input[n]; + } + return WebRtcCelt_Encode(encoder_, stereo_input_, output); + } + + int16_t* stereo_input_; + CELT_encinst_t* encoder_; +}; + +#endif + +class AudioDecoderOpusTest : public AudioDecoderTest { + protected: + AudioDecoderOpusTest() : AudioDecoderTest() { + frame_size_ = 320; + data_length_ = 10 * frame_size_; + decoder_ = new AudioDecoderOpus(kDecoderOpus); + assert(decoder_); + WebRtcOpus_EncoderCreate(&encoder_, 1); + } + + ~AudioDecoderOpusTest() { + WebRtcOpus_EncoderFree(encoder_); + } + + virtual void InitEncoder() {} + + virtual int EncodeFrame(const int16_t* input, size_t input_len_samples, + uint8_t* output) { + // Upsample from 32 to 48 kHz. + Resampler rs; + rs.Reset(32000, 48000, kResamplerSynchronous); + const int max_resamp_len_samples = static_cast<int>(input_len_samples) * + 3 / 2; + int16_t* resamp_input = new int16_t[max_resamp_len_samples]; + int resamp_len_samples; + EXPECT_EQ(0, rs.Push(input, static_cast<int>(input_len_samples), + resamp_input, max_resamp_len_samples, + resamp_len_samples)); + EXPECT_EQ(max_resamp_len_samples, resamp_len_samples); + int enc_len_bytes = + WebRtcOpus_Encode(encoder_, resamp_input, resamp_len_samples, + static_cast<int>(data_length_), output); + EXPECT_GT(enc_len_bytes, 0); + delete [] resamp_input; + return enc_len_bytes; + } + + OpusEncInst* encoder_; +}; + +class AudioDecoderOpusStereoTest : public AudioDecoderTest { + protected: + AudioDecoderOpusStereoTest() : AudioDecoderTest() { + channels_ = 2; + frame_size_ = 320; + data_length_ = 10 * frame_size_; + decoder_ = new AudioDecoderOpus(kDecoderOpus_2ch); + assert(decoder_); + WebRtcOpus_EncoderCreate(&encoder_, 2); + } + + ~AudioDecoderOpusStereoTest() { + WebRtcOpus_EncoderFree(encoder_); + } + + virtual void InitEncoder() {} + + virtual int EncodeFrame(const int16_t* input, size_t input_len_samples, + uint8_t* output) { + // 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]; + // Upsample from 32 to 48 kHz. + Resampler rs; + rs.Reset(32000, 48000, kResamplerSynchronousStereo); + const int max_resamp_len_samples = input_stereo_samples * 3 / 2; + int16_t* resamp_input = new int16_t[max_resamp_len_samples]; + int resamp_len_samples; + EXPECT_EQ(0, rs.Push(input_stereo, input_stereo_samples, resamp_input, + max_resamp_len_samples, resamp_len_samples)); + EXPECT_EQ(max_resamp_len_samples, resamp_len_samples); + int enc_len_bytes = + WebRtcOpus_Encode(encoder_, resamp_input, resamp_len_samples / 2, + static_cast<int16_t>(data_length_), output); + EXPECT_GT(enc_len_bytes, 0); + delete [] resamp_input; + delete [] input_stereo; + return enc_len_bytes; + } + + OpusEncInst* encoder_; +}; + +TEST_F(AudioDecoderPcmUTest, EncodeDecode) { + int tolerance = 251; + double mse = 1734.0; + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderPCMu)); + EncodeDecodeTest(data_length_, tolerance, mse); + ReInitTest(); + EXPECT_FALSE(decoder_->HasDecodePlc()); +} + +TEST_F(AudioDecoderPcmATest, EncodeDecode) { + int tolerance = 308; + double mse = 1931.0; + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderPCMa)); + EncodeDecodeTest(data_length_, tolerance, mse); + ReInitTest(); + EXPECT_FALSE(decoder_->HasDecodePlc()); +} + +TEST_F(AudioDecoderPcm16BTest, EncodeDecode) { + int tolerance = 0; + double mse = 0.0; + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderPCM16B)); + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderPCM16Bwb)); + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderPCM16Bswb32kHz)); + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderPCM16Bswb48kHz)); + EncodeDecodeTest(2 * data_length_, tolerance, mse); + ReInitTest(); + EXPECT_FALSE(decoder_->HasDecodePlc()); +} + +TEST_F(AudioDecoderIlbcTest, EncodeDecode) { + int tolerance = 6808; + double mse = 2.13e6; + int delay = 80; // Delay from input to output. + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderILBC)); + EncodeDecodeTest(500, tolerance, mse, delay); + ReInitTest(); + EXPECT_TRUE(decoder_->HasDecodePlc()); + DecodePlcTest(); +} + +TEST_F(AudioDecoderIsacFloatTest, EncodeDecode) { + int tolerance = 3399; + double mse = 434951.0; + int delay = 48; // Delay from input to output. + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderISAC)); + EncodeDecodeTest(0, tolerance, mse, delay); + ReInitTest(); + EXPECT_TRUE(decoder_->HasDecodePlc()); + DecodePlcTest(); +} + +TEST_F(AudioDecoderIsacSwbTest, 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(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; + int delay = 54; // Delay from input to output. + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderISAC)); + EncodeDecodeTest(735, tolerance, mse, delay); + ReInitTest(); + EXPECT_FALSE(decoder_->HasDecodePlc()); +} + +TEST_F(AudioDecoderG722Test, EncodeDecode) { + int tolerance = 6176; + double mse = 238630.0; + int delay = 22; // Delay from input to output. + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderG722)); + EncodeDecodeTest(data_length_ / 2, tolerance, mse, delay); + ReInitTest(); + EXPECT_FALSE(decoder_->HasDecodePlc()); +} + +TEST_F(AudioDecoderG722StereoTest, CreateAndDestroy) { + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderG722_2ch)); +} + +TEST_F(AudioDecoderG722StereoTest, EncodeDecode) { + int tolerance = 6176; + int channel_diff_tolerance = 0; + double mse = 238630.0; + int delay = 22; // Delay from input to output. + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderG722_2ch)); + EncodeDecodeTest(data_length_, tolerance, mse, delay, channel_diff_tolerance); + ReInitTest(); + EXPECT_FALSE(decoder_->HasDecodePlc()); +} + +TEST_F(AudioDecoderOpusTest, EncodeDecode) { + int tolerance = 6176; + double mse = 238630.0; + int delay = 22; // Delay from input to output. + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderOpus)); + EncodeDecodeTest(0, tolerance, mse, delay); + ReInitTest(); + EXPECT_FALSE(decoder_->HasDecodePlc()); +} + +TEST_F(AudioDecoderOpusStereoTest, EncodeDecode) { + int tolerance = 6176; + int channel_diff_tolerance = 0; + double mse = 238630.0; + int delay = 22; // Delay from input to output. + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderOpus_2ch)); + EncodeDecodeTest(0, tolerance, mse, delay, channel_diff_tolerance); + ReInitTest(); + EXPECT_FALSE(decoder_->HasDecodePlc()); +} + +#ifdef WEBRTC_CODEC_CELT +// In the two following CELT tests, the low amplitude of the test signal allow +// us to have such low error thresholds, i.e. |tolerance|, |mse|. Furthermore, +// in general, stereo signals with identical channels do not result in identical +// encoded channels. +TEST_F(AudioDecoderCeltTest, EncodeDecode) { + int tolerance = 20; + double mse = 17.0; + int delay = 80; // Delay from input to output in samples. + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderCELT_32)); + EncodeDecodeTest(1600, tolerance, mse, delay); + ReInitTest(); + EXPECT_TRUE(decoder_->HasDecodePlc()); + DecodePlcTest(); +} + +TEST_F(AudioDecoderCeltStereoTest, EncodeDecode) { + int tolerance = 20; + // If both channels are identical, CELT not necessarily decodes identical + // channels. However, for this input this is the case. + int channel_diff_tolerance = 0; + double mse = 20.0; + // Delay from input to output in samples, accounting for stereo. + int delay = 160; + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderCELT_32_2ch)); + EncodeDecodeTest(1600, tolerance, mse, delay, channel_diff_tolerance); + ReInitTest(); + EXPECT_TRUE(decoder_->HasDecodePlc()); + DecodePlcTest(); +} +#endif + +TEST(AudioDecoder, CodecSampleRateHz) { + EXPECT_EQ(8000, AudioDecoder::CodecSampleRateHz(kDecoderPCMu)); + EXPECT_EQ(8000, AudioDecoder::CodecSampleRateHz(kDecoderPCMa)); + EXPECT_EQ(8000, AudioDecoder::CodecSampleRateHz(kDecoderPCMu_2ch)); + EXPECT_EQ(8000, AudioDecoder::CodecSampleRateHz(kDecoderPCMa_2ch)); + EXPECT_EQ(8000, AudioDecoder::CodecSampleRateHz(kDecoderILBC)); + EXPECT_EQ(16000, AudioDecoder::CodecSampleRateHz(kDecoderISAC)); + EXPECT_EQ(32000, AudioDecoder::CodecSampleRateHz(kDecoderISACswb)); + EXPECT_EQ(32000, AudioDecoder::CodecSampleRateHz(kDecoderISACfb)); + EXPECT_EQ(8000, AudioDecoder::CodecSampleRateHz(kDecoderPCM16B)); + EXPECT_EQ(16000, AudioDecoder::CodecSampleRateHz(kDecoderPCM16Bwb)); + EXPECT_EQ(32000, AudioDecoder::CodecSampleRateHz(kDecoderPCM16Bswb32kHz)); + EXPECT_EQ(48000, AudioDecoder::CodecSampleRateHz(kDecoderPCM16Bswb48kHz)); + EXPECT_EQ(8000, AudioDecoder::CodecSampleRateHz(kDecoderPCM16B_2ch)); + EXPECT_EQ(16000, AudioDecoder::CodecSampleRateHz(kDecoderPCM16Bwb_2ch)); + EXPECT_EQ(32000, AudioDecoder::CodecSampleRateHz(kDecoderPCM16Bswb32kHz_2ch)); + EXPECT_EQ(48000, AudioDecoder::CodecSampleRateHz(kDecoderPCM16Bswb48kHz_2ch)); + EXPECT_EQ(8000, AudioDecoder::CodecSampleRateHz(kDecoderPCM16B_5ch)); + EXPECT_EQ(16000, AudioDecoder::CodecSampleRateHz(kDecoderG722)); + EXPECT_EQ(16000, AudioDecoder::CodecSampleRateHz(kDecoderG722_2ch)); + EXPECT_EQ(-1, AudioDecoder::CodecSampleRateHz(kDecoderRED)); + EXPECT_EQ(-1, AudioDecoder::CodecSampleRateHz(kDecoderAVT)); + EXPECT_EQ(8000, AudioDecoder::CodecSampleRateHz(kDecoderCNGnb)); + EXPECT_EQ(16000, AudioDecoder::CodecSampleRateHz(kDecoderCNGwb)); + EXPECT_EQ(32000, AudioDecoder::CodecSampleRateHz(kDecoderCNGswb32kHz)); + // TODO(tlegrand): Change 32000 to 48000 below once ACM has 48 kHz support. + EXPECT_EQ(32000, AudioDecoder::CodecSampleRateHz(kDecoderCNGswb48kHz)); + EXPECT_EQ(-1, AudioDecoder::CodecSampleRateHz(kDecoderArbitrary)); + EXPECT_EQ(32000, AudioDecoder::CodecSampleRateHz(kDecoderOpus)); + EXPECT_EQ(32000, AudioDecoder::CodecSampleRateHz(kDecoderOpus_2ch)); +#ifdef WEBRTC_CODEC_CELT + EXPECT_EQ(32000, AudioDecoder::CodecSampleRateHz(kDecoderCELT_32)); + EXPECT_EQ(32000, AudioDecoder::CodecSampleRateHz(kDecoderCELT_32_2ch)); +#else + EXPECT_EQ(-1, AudioDecoder::CodecSampleRateHz(kDecoderCELT_32)); + EXPECT_EQ(-1, AudioDecoder::CodecSampleRateHz(kDecoderCELT_32_2ch)); +#endif +} + +TEST(AudioDecoder, CodecSupported) { + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderPCMu)); + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderPCMa)); + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderPCMu_2ch)); + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderPCMa_2ch)); + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderILBC)); + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderISAC)); + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderISACswb)); + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderISACfb)); + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderPCM16B)); + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderPCM16Bwb)); + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderPCM16Bswb32kHz)); + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderPCM16Bswb48kHz)); + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderPCM16B_2ch)); + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderPCM16Bwb_2ch)); + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderPCM16Bswb32kHz_2ch)); + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderPCM16Bswb48kHz_2ch)); + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderPCM16B_5ch)); + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderG722)); + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderG722_2ch)); + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderRED)); + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderAVT)); + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderCNGnb)); + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderCNGwb)); + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderCNGswb32kHz)); + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderCNGswb48kHz)); + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderArbitrary)); + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderOpus)); + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderOpus_2ch)); +#ifdef WEBRTC_CODEC_CELT + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderCELT_32)); + EXPECT_TRUE(AudioDecoder::CodecSupported(kDecoderCELT_32_2ch)); +#else + EXPECT_FALSE(AudioDecoder::CodecSupported(kDecoderCELT_32)); + EXPECT_FALSE(AudioDecoder::CodecSupported(kDecoderCELT_32_2ch)); +#endif +} + +} // namespace webrtc |