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@4884 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..0ed13e2 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_, 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() {
@@ -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