Support for CELT in NetEq4.
BUG=1359
R=henrik.lundin@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/2291004
git-svn-id: http://webrtc.googlecode.com/svn/trunk/webrtc@4876 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/modules/audio_coding/neteq4/audio_decoder.cc b/modules/audio_coding/neteq4/audio_decoder.cc
index 77111eb..35422e3 100644
--- a/modules/audio_coding/neteq4/audio_decoder.cc
+++ b/modules/audio_coding/neteq4/audio_decoder.cc
@@ -74,6 +74,10 @@
case kDecoderG722:
case kDecoderG722_2ch:
#endif
+#ifdef WEBRTC_CODEC_CELT
+ case kDecoderCELT_32:
+ case kDecoderCELT_32_2ch:
+#endif
#ifdef WEBRTC_CODEC_OPUS
case kDecoderOpus:
case kDecoderOpus_2ch:
@@ -132,6 +136,10 @@
case kDecoderPCM16Bswb32kHz:
case kDecoderPCM16Bswb32kHz_2ch:
#endif
+#ifdef WEBRTC_CODEC_CELT
+ case kDecoderCELT_32:
+ case kDecoderCELT_32_2ch:
+#endif
case kDecoderCNGswb32kHz: {
return 32000;
}
@@ -206,6 +214,11 @@
case kDecoderG722_2ch:
return new AudioDecoderG722Stereo;
#endif
+#ifdef WEBRTC_CODEC_CELT
+ case kDecoderCELT_32:
+ case kDecoderCELT_32_2ch:
+ return new AudioDecoderCelt(codec_type);
+#endif
#ifdef WEBRTC_CODEC_OPUS
case kDecoderOpus:
case kDecoderOpus_2ch:
diff --git a/modules/audio_coding/neteq4/audio_decoder_impl.cc b/modules/audio_coding/neteq4/audio_decoder_impl.cc
index 53119b1..5296a1b 100644
--- a/modules/audio_coding/neteq4/audio_decoder_impl.cc
+++ b/modules/audio_coding/neteq4/audio_decoder_impl.cc
@@ -13,6 +13,9 @@
#include <assert.h>
#include <string.h> // memmove
+#ifdef WEBRTC_CODEC_CELT
+#include "webrtc/modules/audio_coding/codecs/celt/include/celt_interface.h"
+#endif
#include "webrtc/modules/audio_coding/codecs/cng/include/webrtc_cng.h"
#include "webrtc/modules/audio_coding/codecs/g711/include/g711_interface.h"
#ifdef WEBRTC_CODEC_G722
@@ -377,6 +380,55 @@
}
#endif
+// 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;
+ }
+ WebRtcCelt_CreateDec(reinterpret_cast<CELT_decinst_t**>(&state_),
+ static_cast<int>(channels_));
+}
+
+AudioDecoderCelt::~AudioDecoderCelt() {
+ WebRtcCelt_FreeDec(static_cast<CELT_decinst_t*>(state_));
+}
+
+int AudioDecoderCelt::Decode(const uint8_t* encoded, size_t encoded_len,
+ int16_t* decoded, SpeechType* speech_type) {
+ int16_t temp_type = 1; // Default to speech.
+ int ret = WebRtcCelt_DecodeUniversal(static_cast<CELT_decinst_t*>(state_),
+ encoded, static_cast<int>(encoded_len),
+ decoded, &temp_type);
+ *speech_type = ConvertSpeechType(temp_type);
+ if (ret < 0) {
+ return -1;
+ }
+ // Return the total number of samples.
+ return ret * static_cast<int>(channels_);
+}
+
+int AudioDecoderCelt::Init() {
+ return WebRtcCelt_DecoderInit(static_cast<CELT_decinst_t*>(state_));
+}
+
+bool AudioDecoderCelt::HasDecodePlc() const { return true; }
+
+int AudioDecoderCelt::DecodePlc(int num_frames, int16_t* decoded) {
+ int ret = WebRtcCelt_DecodePlc(static_cast<CELT_decinst_t*>(state_),
+ decoded, num_frames);
+ if (ret < 0) {
+ return -1;
+ }
+ // Return the total number of samples.
+ return ret * static_cast<int>(channels_);
+}
+#endif
+
// Opus
#ifdef WEBRTC_CODEC_OPUS
AudioDecoderOpus::AudioDecoderOpus(enum NetEqDecoder type)
diff --git a/modules/audio_coding/neteq4/audio_decoder_impl.h b/modules/audio_coding/neteq4/audio_decoder_impl.h
index b74aed8..aa35db7 100644
--- a/modules/audio_coding/neteq4/audio_decoder_impl.h
+++ b/modules/audio_coding/neteq4/audio_decoder_impl.h
@@ -212,6 +212,23 @@
};
#endif
+#ifdef WEBRTC_CODEC_CELT
+class AudioDecoderCelt : public AudioDecoder {
+ public:
+ explicit AudioDecoderCelt(enum NetEqDecoder type);
+ virtual ~AudioDecoderCelt();
+
+ virtual int Decode(const uint8_t* encoded, size_t encoded_len,
+ int16_t* decoded, SpeechType* speech_type);
+ virtual int Init();
+ virtual bool HasDecodePlc() const;
+ virtual int DecodePlc(int num_frames, int16_t* decoded);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AudioDecoderCelt);
+};
+#endif
+
#ifdef WEBRTC_CODEC_OPUS
class AudioDecoderOpus : public AudioDecoder {
public:
diff --git a/modules/audio_coding/neteq4/audio_decoder_unittest.cc b/modules/audio_coding/neteq4/audio_decoder_unittest.cc
index cb4d11d..0570226 100644
--- a/modules/audio_coding/neteq4/audio_decoder_unittest.cc
+++ b/modules/audio_coding/neteq4/audio_decoder_unittest.cc
@@ -17,6 +17,9 @@
#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"
@@ -143,11 +146,12 @@
// The absolute difference between the two channels in a stereo is compared vs
// |tolerance|.
- virtual void CompareTwoChannels(size_t num_samples, int tolerance) const {
- assert(num_samples <= data_length_);
- for (unsigned int n = 0; n < num_samples; ++n)
- ASSERT_NEAR(decoded_[channels_ * n], decoded_[channels_ * n + 1],
- tolerance) << "Stereo samples differ.";
+ 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).
@@ -199,12 +203,12 @@
EXPECT_EQ(0, decoder_->Init());
size_t dec_len =
decoder_->Decode(encoded_, enc_len, decoded_, &speech_type);
- EXPECT_EQ(frame_size_, dec_len);
+ 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_, dec_len);
+ EXPECT_EQ(frame_size_ * channels_, dec_len);
}
std::string input_file_;
@@ -527,6 +531,77 @@
}
};
+#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_, channels_);
+ }
+
+ ~AudioDecoderCeltTest() {
+ WebRtcCelt_FreeEnc(encoder_);
+ }
+
+ virtual void InitEncoder() {
+ assert(encoder_);
+ ASSERT_EQ(0, WebRtcCelt_EncoderInit(
+ encoder_, 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_, channels_);
+ }
+
+ ~AudioDecoderCeltStereoTest() {
+ delete [] stereo_input_;
+ WebRtcCelt_FreeEnc(encoder_);
+ }
+
+ virtual void InitEncoder() {
+ assert(encoder_);
+ ASSERT_EQ(0, WebRtcCelt_EncoderInit(
+ encoder_, 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() {
@@ -742,6 +817,38 @@
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));
@@ -772,8 +879,13 @@
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) {
@@ -805,8 +917,13 @@
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