diff --git a/webrtc/modules/audio_coding/neteq4/audio_decoder.cc b/webrtc/modules/audio_coding/neteq4/audio_decoder.cc index 77111ebf9..35422e3f9 100644 --- a/webrtc/modules/audio_coding/neteq4/audio_decoder.cc +++ b/webrtc/modules/audio_coding/neteq4/audio_decoder.cc @@ -74,6 +74,10 @@ bool AudioDecoder::CodecSupported(NetEqDecoder codec_type) { 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: @@ -131,6 +135,10 @@ int AudioDecoder::CodecSampleRateHz(NetEqDecoder codec_type) { #ifdef WEBRTC_CODEC_PCM16 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 @@ AudioDecoder* AudioDecoder::CreateAudioDecoder(NetEqDecoder codec_type) { 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/webrtc/modules/audio_coding/neteq4/audio_decoder_impl.cc b/webrtc/modules/audio_coding/neteq4/audio_decoder_impl.cc index 53119b1ab..5296a1bd0 100644 --- a/webrtc/modules/audio_coding/neteq4/audio_decoder_impl.cc +++ b/webrtc/modules/audio_coding/neteq4/audio_decoder_impl.cc @@ -13,6 +13,9 @@ #include #include // 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 @@ void AudioDecoderG722Stereo::SplitStereoPacket(const uint8_t* encoded, } #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(&state_), + static_cast(channels_)); +} + +AudioDecoderCelt::~AudioDecoderCelt() { + WebRtcCelt_FreeDec(static_cast(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(state_), + encoded, static_cast(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(channels_); +} + +int AudioDecoderCelt::Init() { + return WebRtcCelt_DecoderInit(static_cast(state_)); +} + +bool AudioDecoderCelt::HasDecodePlc() const { return true; } + +int AudioDecoderCelt::DecodePlc(int num_frames, int16_t* decoded) { + int ret = WebRtcCelt_DecodePlc(static_cast(state_), + decoded, num_frames); + if (ret < 0) { + return -1; + } + // Return the total number of samples. + return ret * static_cast(channels_); +} +#endif + // Opus #ifdef WEBRTC_CODEC_OPUS AudioDecoderOpus::AudioDecoderOpus(enum NetEqDecoder type) diff --git a/webrtc/modules/audio_coding/neteq4/audio_decoder_impl.h b/webrtc/modules/audio_coding/neteq4/audio_decoder_impl.h index b74aed897..aa35db780 100644 --- a/webrtc/modules/audio_coding/neteq4/audio_decoder_impl.h +++ b/webrtc/modules/audio_coding/neteq4/audio_decoder_impl.h @@ -212,6 +212,23 @@ class AudioDecoderG722Stereo : public AudioDecoderG722 { }; #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/webrtc/modules/audio_coding/neteq4/audio_decoder_unittest.cc b/webrtc/modules/audio_coding/neteq4/audio_decoder_unittest.cc index cb4d11d96..0ed13e25b 100644 --- a/webrtc/modules/audio_coding/neteq4/audio_decoder_unittest.cc +++ b/webrtc/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 @@ class AudioDecoderTest : public ::testing::Test { // 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 @@ class AudioDecoderTest : public ::testing::Test { 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 @@ class AudioDecoderG722StereoTest : public AudioDecoderG722Test { } }; +#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(channels_)); + } + + ~AudioDecoderCeltTest() { + WebRtcCelt_FreeEnc(encoder_); + } + + virtual void InitEncoder() { + assert(encoder_); + ASSERT_EQ(0, WebRtcCelt_EncoderInit( + encoder_, static_cast(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(channels_)); + } + + ~AudioDecoderCeltStereoTest() { + delete [] stereo_input_; + WebRtcCelt_FreeEnc(encoder_); + } + + virtual void InitEncoder() { + assert(encoder_); + ASSERT_EQ(0, WebRtcCelt_EncoderInit( + encoder_, static_cast(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 @@ TEST_F(AudioDecoderOpusStereoTest, EncodeDecode) { 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 @@ TEST(AudioDecoder, CodecSampleRateHz) { 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 @@ TEST(AudioDecoder, CodecSupported) { 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