diff --git a/webrtc/modules/audio_coding/BUILD.gn b/webrtc/modules/audio_coding/BUILD.gn index fac22743ac..7a0724759f 100644 --- a/webrtc/modules/audio_coding/BUILD.gn +++ b/webrtc/modules/audio_coding/BUILD.gn @@ -147,9 +147,7 @@ source_set("cng") { sources = [ "codecs/cng/audio_encoder_cng.cc", "codecs/cng/audio_encoder_cng.h", - "codecs/cng/cng_helpfuns.c", - "codecs/cng/cng_helpfuns.h", - "codecs/cng/webrtc_cng.c", + "codecs/cng/webrtc_cng.cc", "codecs/cng/webrtc_cng.h", ] diff --git a/webrtc/modules/audio_coding/codecs/audio_decoder.cc b/webrtc/modules/audio_coding/codecs/audio_decoder.cc index d2984b97b0..442ddc1e4b 100644 --- a/webrtc/modules/audio_coding/codecs/audio_decoder.cc +++ b/webrtc/modules/audio_coding/codecs/audio_decoder.cc @@ -82,11 +82,6 @@ bool AudioDecoder::PacketHasFec(const uint8_t* encoded, return false; } -CNG_dec_inst* AudioDecoder::CngDecoderInstance() { - FATAL() << "Not a CNG decoder"; - return NULL; -} - AudioDecoder::SpeechType AudioDecoder::ConvertSpeechType(int16_t type) { switch (type) { case 0: // TODO(hlundin): Both iSAC and Opus return 0 for speech. diff --git a/webrtc/modules/audio_coding/codecs/audio_decoder.h b/webrtc/modules/audio_coding/codecs/audio_decoder.h index 81ac873183..580ddbf74f 100644 --- a/webrtc/modules/audio_coding/codecs/audio_decoder.h +++ b/webrtc/modules/audio_coding/codecs/audio_decoder.h @@ -14,7 +14,6 @@ #include // NULL #include "webrtc/base/constructormagic.h" -#include "webrtc/modules/audio_coding/codecs/cng/webrtc_cng.h" #include "webrtc/typedefs.h" namespace webrtc { @@ -94,10 +93,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; - // If this is a CNG decoder, return the underlying CNG_dec_inst*. If this - // isn't a CNG decoder, don't call this method. - virtual CNG_dec_inst* CngDecoderInstance(); - virtual size_t Channels() const = 0; protected: diff --git a/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng.cc b/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng.cc index 04b635d8ca..09c25d9616 100644 --- a/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng.cc +++ b/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng.cc @@ -21,19 +21,6 @@ namespace { const int kMaxFrameSizeMs = 60; -std::unique_ptr CreateCngInst( - int sample_rate_hz, - int sid_frame_interval_ms, - int num_cng_coefficients) { - CNG_enc_inst* ci; - RTC_CHECK_EQ(0, WebRtcCng_CreateEnc(&ci)); - std::unique_ptr cng_inst(ci); - RTC_CHECK_EQ(0, - WebRtcCng_InitEnc(cng_inst.get(), sample_rate_hz, - sid_frame_interval_ms, num_cng_coefficients)); - return cng_inst; -} - } // namespace AudioEncoderCng::Config::Config() = default; @@ -65,9 +52,10 @@ AudioEncoderCng::AudioEncoderCng(Config&& config) sid_frame_interval_ms_(config.sid_frame_interval_ms), last_frame_active_(true), vad_(config.vad ? std::unique_ptr(config.vad) - : CreateVad(config.vad_mode)) { - cng_inst_ = CreateCngInst(SampleRateHz(), sid_frame_interval_ms_, - num_cng_coefficients_); + : CreateVad(config.vad_mode)), + cng_encoder_(new ComfortNoiseEncoder(SampleRateHz(), + sid_frame_interval_ms_, + num_cng_coefficients_)) { } AudioEncoderCng::~AudioEncoderCng() = default; @@ -170,8 +158,9 @@ void AudioEncoderCng::Reset() { rtp_timestamps_.clear(); last_frame_active_ = true; vad_->Reset(); - cng_inst_ = CreateCngInst(SampleRateHz(), sid_frame_interval_ms_, - num_cng_coefficients_); + cng_encoder_.reset( + new ComfortNoiseEncoder(SampleRateHz(), sid_frame_interval_ms_, + num_cng_coefficients_)); } bool AudioEncoderCng::SetFec(bool enable) { @@ -204,32 +193,27 @@ AudioEncoder::EncodedInfo AudioEncoderCng::EncodePassive( bool force_sid = last_frame_active_; bool output_produced = false; const size_t samples_per_10ms_frame = SamplesPer10msFrame(); - const size_t bytes_to_encode = frames_to_encode * samples_per_10ms_frame; AudioEncoder::EncodedInfo info; - encoded->AppendData(bytes_to_encode, [&] (rtc::ArrayView encoded) { - for (size_t i = 0; i < frames_to_encode; ++i) { - // It's important not to pass &info.encoded_bytes directly to - // WebRtcCng_Encode(), since later loop iterations may return zero in - // that value, in which case we don't want to overwrite any value from - // an earlier iteration. - size_t encoded_bytes_tmp = 0; - RTC_CHECK_GE( - WebRtcCng_Encode(cng_inst_.get(), - &speech_buffer_[i * samples_per_10ms_frame], - samples_per_10ms_frame, encoded.data(), - &encoded_bytes_tmp, force_sid), - 0); - if (encoded_bytes_tmp > 0) { - RTC_CHECK(!output_produced); - info.encoded_bytes = encoded_bytes_tmp; - output_produced = true; - force_sid = false; - } - } + for (size_t i = 0; i < frames_to_encode; ++i) { + // It's important not to pass &info.encoded_bytes directly to + // WebRtcCng_Encode(), since later loop iterations may return zero in + // that value, in which case we don't want to overwrite any value from + // an earlier iteration. + size_t encoded_bytes_tmp = + cng_encoder_->Encode( + rtc::ArrayView( + &speech_buffer_[i * samples_per_10ms_frame], + samples_per_10ms_frame), + force_sid, encoded); - return info.encoded_bytes; - }); + if (encoded_bytes_tmp > 0) { + RTC_CHECK(!output_produced); + info.encoded_bytes = encoded_bytes_tmp; + output_produced = true; + force_sid = false; + } + } info.encoded_timestamp = rtp_timestamps_.front(); info.payload_type = cng_payload_type_; diff --git a/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng.h b/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng.h index b52665d9c0..246e9519da 100644 --- a/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng.h +++ b/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng.h @@ -21,11 +21,6 @@ namespace webrtc { -// Deleter for use with unique_ptr. -struct CngInstDeleter { - void operator()(CNG_enc_inst* ptr) const { WebRtcCng_FreeEnc(ptr); } -}; - class Vad; class AudioEncoderCng final : public AudioEncoder { @@ -84,7 +79,7 @@ class AudioEncoderCng final : public AudioEncoder { std::vector rtp_timestamps_; bool last_frame_active_; std::unique_ptr vad_; - std::unique_ptr cng_inst_; + std::unique_ptr cng_encoder_; RTC_DISALLOW_COPY_AND_ASSIGN(AudioEncoderCng); }; diff --git a/webrtc/modules/audio_coding/codecs/cng/cng.gypi b/webrtc/modules/audio_coding/codecs/cng/cng.gypi index c020f4740d..bbff9f8edf 100644 --- a/webrtc/modules/audio_coding/codecs/cng/cng.gypi +++ b/webrtc/modules/audio_coding/codecs/cng/cng.gypi @@ -18,9 +18,7 @@ 'sources': [ 'audio_encoder_cng.cc', 'audio_encoder_cng.h', - 'cng_helpfuns.c', - 'cng_helpfuns.h', - 'webrtc_cng.c', + 'webrtc_cng.cc', 'webrtc_cng.h', ], }, diff --git a/webrtc/modules/audio_coding/codecs/cng/cng_helpfuns.c b/webrtc/modules/audio_coding/codecs/cng/cng_helpfuns.c deleted file mode 100644 index bc08d431a6..0000000000 --- a/webrtc/modules/audio_coding/codecs/cng/cng_helpfuns.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2011 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 "cng_helpfuns.h" - -#include "signal_processing_library.h" -#include "webrtc/typedefs.h" -#include "webrtc_cng.h" - -/* Values in |k| are Q15, and |a| Q12. */ -void WebRtcCng_K2a16(int16_t* k, int useOrder, int16_t* a) { - int16_t any[WEBRTC_SPL_MAX_LPC_ORDER + 1]; - int16_t *aptr, *aptr2, *anyptr; - const int16_t *kptr; - int m, i; - - kptr = k; - *a = 4096; /* i.e., (Word16_MAX >> 3) + 1 */ - *any = *a; - a[1] = (*k + 4) >> 3; - for (m = 1; m < useOrder; m++) { - kptr++; - aptr = a; - aptr++; - aptr2 = &a[m]; - anyptr = any; - anyptr++; - - any[m + 1] = (*kptr + 4) >> 3; - for (i = 0; i < m; i++) { - *anyptr++ = (*aptr++) + - (int16_t)((((int32_t)(*aptr2--) * (int32_t) * kptr) + 16384) >> 15); - } - - aptr = a; - anyptr = any; - for (i = 0; i < (m + 2); i++) { - *aptr++ = *anyptr++; - } - } -} diff --git a/webrtc/modules/audio_coding/codecs/cng/cng_helpfuns.h b/webrtc/modules/audio_coding/codecs/cng/cng_helpfuns.h deleted file mode 100644 index a553a7615e..0000000000 --- a/webrtc/modules/audio_coding/codecs/cng/cng_helpfuns.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2011 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_CODECS_CNG_CNG_HELPFUNS_H_ -#define WEBRTC_MODULES_AUDIO_CODING_CODECS_CNG_CNG_HELPFUNS_H_ - -#include "webrtc/typedefs.h" - -#ifdef __cplusplus -extern "C" { -#endif - -void WebRtcCng_K2a16(int16_t* k, int useOrder, int16_t* a); - -#ifdef __cplusplus -} -#endif - -#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_CNG_CNG_HELPFUNS_H_ diff --git a/webrtc/modules/audio_coding/codecs/cng/cng_unittest.cc b/webrtc/modules/audio_coding/codecs/cng/cng_unittest.cc index 1061dca69a..95132a9617 100644 --- a/webrtc/modules/audio_coding/codecs/cng/cng_unittest.cc +++ b/webrtc/modules/audio_coding/codecs/cng/cng_unittest.cc @@ -7,11 +7,12 @@ * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ +#include #include #include "testing/gtest/include/gtest/gtest.h" #include "webrtc/test/testsupport/fileutils.h" -#include "webrtc_cng.h" +#include "webrtc/modules/audio_coding/codecs/cng/webrtc_cng.h" namespace webrtc { @@ -21,7 +22,7 @@ enum { kSidLongIntervalUpdate = 10000 }; -enum { +enum : size_t { kCNGNumParamsLow = 0, kCNGNumParamsNormal = 8, kCNGNumParamsHigh = WEBRTC_CNG_MAX_LPC_ORDER, @@ -35,19 +36,13 @@ enum { class CngTest : public ::testing::Test { protected: - CngTest(); virtual void SetUp(); - CNG_enc_inst* cng_enc_inst_; - CNG_dec_inst* cng_dec_inst_; + void TestCngEncode(int sample_rate_hz, int quality); + int16_t speech_data_[640]; // Max size of CNG internal buffers. }; -CngTest::CngTest() - : cng_enc_inst_(NULL), - cng_dec_inst_(NULL) { -} - void CngTest::SetUp() { FILE* input_file; const std::string file_name = @@ -60,289 +55,187 @@ void CngTest::SetUp() { input_file = NULL; } -// Test failing Create. -TEST_F(CngTest, CngCreateFail) { - // Test to see that an invalid pointer is caught. - EXPECT_EQ(-1, WebRtcCng_CreateEnc(NULL)); - EXPECT_EQ(-1, WebRtcCng_CreateDec(NULL)); -} - -// Test normal Create. -TEST_F(CngTest, CngCreate) { - EXPECT_EQ(0, WebRtcCng_CreateEnc(&cng_enc_inst_)); - EXPECT_EQ(0, WebRtcCng_CreateDec(&cng_dec_inst_)); - EXPECT_TRUE(cng_enc_inst_ != NULL); - EXPECT_TRUE(cng_dec_inst_ != NULL); - // Free encoder and decoder memory. - EXPECT_EQ(0, WebRtcCng_FreeEnc(cng_enc_inst_)); - EXPECT_EQ(0, WebRtcCng_FreeDec(cng_dec_inst_)); +void CngTest::TestCngEncode(int sample_rate_hz, int quality) { + const size_t num_samples_10ms = rtc::CheckedDivExact(sample_rate_hz, 100); + rtc::Buffer sid_data; + + ComfortNoiseEncoder cng_encoder(sample_rate_hz, kSidNormalIntervalUpdate, + quality); + EXPECT_EQ(0U, cng_encoder.Encode(rtc::ArrayView( + speech_data_, num_samples_10ms), + kNoSid, &sid_data)); + EXPECT_EQ(static_cast(quality + 1), + cng_encoder.Encode( + rtc::ArrayView(speech_data_, num_samples_10ms), + kForceSid, &sid_data)); } +#if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) // Create CNG encoder, init with faulty values, free CNG encoder. TEST_F(CngTest, CngInitFail) { - // Create encoder memory. - EXPECT_EQ(0, WebRtcCng_CreateEnc(&cng_enc_inst_)); - // Call with too few parameters. - EXPECT_EQ(-1, WebRtcCng_InitEnc(cng_enc_inst_, 8000, kSidNormalIntervalUpdate, - kCNGNumParamsLow)); - EXPECT_EQ(6130, WebRtcCng_GetErrorCodeEnc(cng_enc_inst_)); - + EXPECT_DEATH({ ComfortNoiseEncoder(8000, kSidNormalIntervalUpdate, + kCNGNumParamsLow); }, ""); // Call with too many parameters. - EXPECT_EQ(-1, WebRtcCng_InitEnc(cng_enc_inst_, 8000, kSidNormalIntervalUpdate, - kCNGNumParamsTooHigh)); - EXPECT_EQ(6130, WebRtcCng_GetErrorCodeEnc(cng_enc_inst_)); - - // Free encoder memory. - EXPECT_EQ(0, WebRtcCng_FreeEnc(cng_enc_inst_)); -} - -TEST_F(CngTest, CngEncode) { - uint8_t sid_data[WEBRTC_CNG_MAX_LPC_ORDER + 1]; - size_t number_bytes; - - // Create encoder memory. - EXPECT_EQ(0, WebRtcCng_CreateEnc(&cng_enc_inst_)); - - // 8 kHz, Normal number of parameters - EXPECT_EQ(0, WebRtcCng_InitEnc(cng_enc_inst_, 8000, kSidNormalIntervalUpdate, - kCNGNumParamsNormal)); - EXPECT_EQ(0, WebRtcCng_Encode(cng_enc_inst_, speech_data_, 80, sid_data, - &number_bytes, kNoSid)); - EXPECT_EQ(kCNGNumParamsNormal + 1, WebRtcCng_Encode( - cng_enc_inst_, speech_data_, 80, sid_data, &number_bytes, kForceSid)); - - // 16 kHz, Normal number of parameters - EXPECT_EQ(0, WebRtcCng_InitEnc(cng_enc_inst_, 16000, kSidNormalIntervalUpdate, - kCNGNumParamsNormal)); - EXPECT_EQ(0, WebRtcCng_Encode(cng_enc_inst_, speech_data_, 160, sid_data, - &number_bytes, kNoSid)); - EXPECT_EQ(kCNGNumParamsNormal + 1, WebRtcCng_Encode( - cng_enc_inst_, speech_data_, 160, sid_data, &number_bytes, kForceSid)); - - // 32 kHz, Max number of parameters - EXPECT_EQ(0, WebRtcCng_InitEnc(cng_enc_inst_, 32000, kSidNormalIntervalUpdate, - kCNGNumParamsHigh)); - EXPECT_EQ(0, WebRtcCng_Encode(cng_enc_inst_, speech_data_, 320, sid_data, - &number_bytes, kNoSid)); - EXPECT_EQ(kCNGNumParamsHigh + 1, WebRtcCng_Encode( - cng_enc_inst_, speech_data_, 320, sid_data, &number_bytes, kForceSid)); - - // 48 kHz, Normal number of parameters - EXPECT_EQ(0, WebRtcCng_InitEnc(cng_enc_inst_, 48000, kSidNormalIntervalUpdate, - kCNGNumParamsNormal)); - EXPECT_EQ(0, WebRtcCng_Encode(cng_enc_inst_, speech_data_, 480, sid_data, - &number_bytes, kNoSid)); - EXPECT_EQ(kCNGNumParamsNormal + 1, WebRtcCng_Encode( - cng_enc_inst_, speech_data_, 480, sid_data, &number_bytes, kForceSid)); - - // 64 kHz, Normal number of parameters - EXPECT_EQ(0, WebRtcCng_InitEnc(cng_enc_inst_, 64000, kSidNormalIntervalUpdate, - kCNGNumParamsNormal)); - EXPECT_EQ(0, WebRtcCng_Encode(cng_enc_inst_, speech_data_, 640, sid_data, - &number_bytes, kNoSid)); - EXPECT_EQ(kCNGNumParamsNormal + 1, WebRtcCng_Encode( - cng_enc_inst_, speech_data_, 640, sid_data, &number_bytes, kForceSid)); - - // Free encoder memory. - EXPECT_EQ(0, WebRtcCng_FreeEnc(cng_enc_inst_)); + EXPECT_DEATH({ ComfortNoiseEncoder(8000, kSidNormalIntervalUpdate, + kCNGNumParamsTooHigh); }, ""); } // Encode Cng with too long input vector. TEST_F(CngTest, CngEncodeTooLong) { - uint8_t sid_data[WEBRTC_CNG_MAX_LPC_ORDER + 1]; - size_t number_bytes; - - // Create and init encoder memory. - EXPECT_EQ(0, WebRtcCng_CreateEnc(&cng_enc_inst_)); - EXPECT_EQ(0, WebRtcCng_InitEnc(cng_enc_inst_, 8000, kSidNormalIntervalUpdate, - kCNGNumParamsNormal)); + rtc::Buffer sid_data; + // Create encoder. + ComfortNoiseEncoder cng_encoder(8000, kSidNormalIntervalUpdate, + kCNGNumParamsNormal); // Run encoder with too much data. - EXPECT_EQ(-1, WebRtcCng_Encode(cng_enc_inst_, speech_data_, 641, sid_data, - &number_bytes, kNoSid)); - EXPECT_EQ(6140, WebRtcCng_GetErrorCodeEnc(cng_enc_inst_)); + EXPECT_DEATH( + cng_encoder.Encode(rtc::ArrayView(speech_data_, 641), + kNoSid, &sid_data), + ""); +} +#endif // GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) - // Free encoder memory. - EXPECT_EQ(0, WebRtcCng_FreeEnc(cng_enc_inst_)); +TEST_F(CngTest, CngEncode8000) { + TestCngEncode(8000, kCNGNumParamsNormal); } -// Call encode without calling init. -TEST_F(CngTest, CngEncodeNoInit) { - uint8_t sid_data[WEBRTC_CNG_MAX_LPC_ORDER + 1]; - size_t number_bytes; +TEST_F(CngTest, CngEncode16000) { + TestCngEncode(16000, kCNGNumParamsNormal); +} - // Create encoder memory. - EXPECT_EQ(0, WebRtcCng_CreateEnc(&cng_enc_inst_)); +TEST_F(CngTest, CngEncode32000) { + TestCngEncode(32000, kCNGNumParamsHigh); +} - // Run encoder without calling init. - EXPECT_EQ(-1, WebRtcCng_Encode(cng_enc_inst_, speech_data_, 640, sid_data, - &number_bytes, kNoSid)); - EXPECT_EQ(6120, WebRtcCng_GetErrorCodeEnc(cng_enc_inst_)); +TEST_F(CngTest, CngEncode48000) { + TestCngEncode(48000, kCNGNumParamsNormal); +} - // Free encoder memory. - EXPECT_EQ(0, WebRtcCng_FreeEnc(cng_enc_inst_)); +TEST_F(CngTest, CngEncode64000) { + TestCngEncode(64000, kCNGNumParamsNormal); } // Update SID parameters, for both 9 and 16 parameters. TEST_F(CngTest, CngUpdateSid) { - uint8_t sid_data[WEBRTC_CNG_MAX_LPC_ORDER + 1]; - size_t number_bytes; + rtc::Buffer sid_data; - // Create and initialize encoder and decoder memory. - EXPECT_EQ(0, WebRtcCng_CreateEnc(&cng_enc_inst_)); - EXPECT_EQ(0, WebRtcCng_CreateDec(&cng_dec_inst_)); - EXPECT_EQ(0, WebRtcCng_InitEnc(cng_enc_inst_, 16000, kSidNormalIntervalUpdate, - kCNGNumParamsNormal)); - WebRtcCng_InitDec(cng_dec_inst_); + // Create and initialize encoder and decoder. + ComfortNoiseEncoder cng_encoder(16000, kSidNormalIntervalUpdate, + kCNGNumParamsNormal); + ComfortNoiseDecoder cng_decoder; // Run normal Encode and UpdateSid. - EXPECT_EQ(kCNGNumParamsNormal + 1, WebRtcCng_Encode( - cng_enc_inst_, speech_data_, 160, sid_data, &number_bytes, kForceSid)); - EXPECT_EQ(0, WebRtcCng_UpdateSid(cng_dec_inst_, sid_data, - kCNGNumParamsNormal + 1)); + EXPECT_EQ(kCNGNumParamsNormal + 1, + cng_encoder.Encode(rtc::ArrayView(speech_data_, 160), + kForceSid, &sid_data)); + cng_decoder.UpdateSid(sid_data); // Reinit with new length. - EXPECT_EQ(0, WebRtcCng_InitEnc(cng_enc_inst_, 16000, kSidNormalIntervalUpdate, - kCNGNumParamsHigh)); - WebRtcCng_InitDec(cng_dec_inst_); + cng_encoder.Reset(16000, kSidNormalIntervalUpdate, kCNGNumParamsHigh); + cng_decoder.Reset(); // Expect 0 because of unstable parameters after switching length. - EXPECT_EQ(0, WebRtcCng_Encode(cng_enc_inst_, speech_data_, 160, sid_data, - &number_bytes, kForceSid)); - EXPECT_EQ(kCNGNumParamsHigh + 1, WebRtcCng_Encode( - cng_enc_inst_, speech_data_ + 160, 160, sid_data, &number_bytes, - kForceSid)); - EXPECT_EQ(0, WebRtcCng_UpdateSid(cng_dec_inst_, sid_data, - kCNGNumParamsNormal + 1)); - - // Free encoder and decoder memory. - EXPECT_EQ(0, WebRtcCng_FreeEnc(cng_enc_inst_)); - EXPECT_EQ(0, WebRtcCng_FreeDec(cng_dec_inst_)); + EXPECT_EQ(0U, + cng_encoder.Encode(rtc::ArrayView(speech_data_, 160), + kForceSid, &sid_data)); + EXPECT_EQ( + kCNGNumParamsHigh + 1, + cng_encoder.Encode(rtc::ArrayView(speech_data_ + 160, 160), + kForceSid, &sid_data)); + cng_decoder.UpdateSid( + rtc::ArrayView(sid_data.data(), kCNGNumParamsNormal + 1)); } // Update SID parameters, with wrong parameters or without calling decode. TEST_F(CngTest, CngUpdateSidErroneous) { - uint8_t sid_data[WEBRTC_CNG_MAX_LPC_ORDER + 1]; - size_t number_bytes; - - // Create encoder and decoder memory. - EXPECT_EQ(0, WebRtcCng_CreateEnc(&cng_enc_inst_)); - EXPECT_EQ(0, WebRtcCng_CreateDec(&cng_dec_inst_)); + rtc::Buffer sid_data; // Encode. - EXPECT_EQ(0, WebRtcCng_InitEnc(cng_enc_inst_, 16000, kSidNormalIntervalUpdate, - kCNGNumParamsNormal)); - EXPECT_EQ(kCNGNumParamsNormal + 1, WebRtcCng_Encode( - cng_enc_inst_, speech_data_, 160, sid_data, &number_bytes, kForceSid)); - - // Update Sid before initializing decoder. - EXPECT_EQ(-1, WebRtcCng_UpdateSid(cng_dec_inst_, sid_data, - kCNGNumParamsNormal + 1)); - EXPECT_EQ(6220, WebRtcCng_GetErrorCodeDec(cng_dec_inst_)); - - // Initialize decoder. - WebRtcCng_InitDec(cng_dec_inst_); + ComfortNoiseEncoder cng_encoder(16000, kSidNormalIntervalUpdate, + kCNGNumParamsNormal); + ComfortNoiseDecoder cng_decoder; + EXPECT_EQ(kCNGNumParamsNormal + 1, + cng_encoder.Encode(rtc::ArrayView(speech_data_, 160), + kForceSid, &sid_data)); // First run with valid parameters, then with too many CNG parameters. // The function will operate correctly by only reading the maximum number of // parameters, skipping the extra. - EXPECT_EQ(0, WebRtcCng_UpdateSid(cng_dec_inst_, sid_data, - kCNGNumParamsNormal + 1)); - EXPECT_EQ(0, WebRtcCng_UpdateSid(cng_dec_inst_, sid_data, - kCNGNumParamsTooHigh + 1)); + EXPECT_EQ(kCNGNumParamsNormal + 1, sid_data.size()); + cng_decoder.UpdateSid(sid_data); - // Free encoder and decoder memory. - EXPECT_EQ(0, WebRtcCng_FreeEnc(cng_enc_inst_)); - EXPECT_EQ(0, WebRtcCng_FreeDec(cng_dec_inst_)); + // Make sure the input buffer is large enough. Since Encode() appends data, we + // need to set the size manually only afterwards, or the buffer will be bigger + // than anticipated. + sid_data.SetSize(kCNGNumParamsTooHigh + 1); + cng_decoder.UpdateSid(sid_data); } // Test to generate cng data, by forcing SID. Both normal and faulty condition. TEST_F(CngTest, CngGenerate) { - uint8_t sid_data[WEBRTC_CNG_MAX_LPC_ORDER + 1]; + rtc::Buffer sid_data; int16_t out_data[640]; - size_t number_bytes; - // Create and initialize encoder and decoder memory. - EXPECT_EQ(0, WebRtcCng_CreateEnc(&cng_enc_inst_)); - EXPECT_EQ(0, WebRtcCng_CreateDec(&cng_dec_inst_)); - EXPECT_EQ(0, WebRtcCng_InitEnc(cng_enc_inst_, 16000, kSidNormalIntervalUpdate, - kCNGNumParamsNormal)); - WebRtcCng_InitDec(cng_dec_inst_); + // Create and initialize encoder and decoder. + ComfortNoiseEncoder cng_encoder(16000, kSidNormalIntervalUpdate, + kCNGNumParamsNormal); + ComfortNoiseDecoder cng_decoder; // Normal Encode. - EXPECT_EQ(kCNGNumParamsNormal + 1, WebRtcCng_Encode( - cng_enc_inst_, speech_data_, 160, sid_data, &number_bytes, kForceSid)); + EXPECT_EQ(kCNGNumParamsNormal + 1, + cng_encoder.Encode(rtc::ArrayView(speech_data_, 160), + kForceSid, &sid_data)); // Normal UpdateSid. - EXPECT_EQ(0, WebRtcCng_UpdateSid(cng_dec_inst_, sid_data, - kCNGNumParamsNormal + 1)); + cng_decoder.UpdateSid(sid_data); // Two normal Generate, one with new_period. - EXPECT_EQ(0, WebRtcCng_Generate(cng_dec_inst_, out_data, 640, 1)); - EXPECT_EQ(0, WebRtcCng_Generate(cng_dec_inst_, out_data, 640, 0)); + EXPECT_TRUE(cng_decoder.Generate(rtc::ArrayView(out_data, 640), 1)); + EXPECT_TRUE(cng_decoder.Generate(rtc::ArrayView(out_data, 640), 0)); // Call Genereate with too much data. - EXPECT_EQ(-1, WebRtcCng_Generate(cng_dec_inst_, out_data, 641, 0)); - EXPECT_EQ(6140, WebRtcCng_GetErrorCodeDec(cng_dec_inst_)); - - // Free encoder and decoder memory. - EXPECT_EQ(0, WebRtcCng_FreeEnc(cng_enc_inst_)); - EXPECT_EQ(0, WebRtcCng_FreeDec(cng_dec_inst_)); + EXPECT_FALSE(cng_decoder.Generate(rtc::ArrayView(out_data, 641), 0)); } // Test automatic SID. TEST_F(CngTest, CngAutoSid) { - uint8_t sid_data[WEBRTC_CNG_MAX_LPC_ORDER + 1]; - size_t number_bytes; + rtc::Buffer sid_data; - // Create and initialize encoder and decoder memory. - EXPECT_EQ(0, WebRtcCng_CreateEnc(&cng_enc_inst_)); - EXPECT_EQ(0, WebRtcCng_CreateDec(&cng_dec_inst_)); - EXPECT_EQ(0, WebRtcCng_InitEnc(cng_enc_inst_, 16000, kSidNormalIntervalUpdate, - kCNGNumParamsNormal)); - WebRtcCng_InitDec(cng_dec_inst_); + // Create and initialize encoder and decoder. + ComfortNoiseEncoder cng_encoder(16000, kSidNormalIntervalUpdate, + kCNGNumParamsNormal); + ComfortNoiseDecoder cng_decoder; // Normal Encode, 100 msec, where no SID data should be generated. for (int i = 0; i < 10; i++) { - EXPECT_EQ(0, WebRtcCng_Encode(cng_enc_inst_, speech_data_, 160, sid_data, - &number_bytes, kNoSid)); + EXPECT_EQ(0U, cng_encoder.Encode( + rtc::ArrayView(speech_data_, 160), kNoSid, &sid_data)); } // We have reached 100 msec, and SID data should be generated. - EXPECT_EQ(kCNGNumParamsNormal + 1, WebRtcCng_Encode( - cng_enc_inst_, speech_data_, 160, sid_data, &number_bytes, kNoSid)); - - // Free encoder and decoder memory. - EXPECT_EQ(0, WebRtcCng_FreeEnc(cng_enc_inst_)); - EXPECT_EQ(0, WebRtcCng_FreeDec(cng_dec_inst_)); + EXPECT_EQ(kCNGNumParamsNormal + 1, cng_encoder.Encode( + rtc::ArrayView(speech_data_, 160), kNoSid, &sid_data)); } // Test automatic SID, with very short interval. TEST_F(CngTest, CngAutoSidShort) { - uint8_t sid_data[WEBRTC_CNG_MAX_LPC_ORDER + 1]; - size_t number_bytes; + rtc::Buffer sid_data; - // Create and initialize encoder and decoder memory. - EXPECT_EQ(0, WebRtcCng_CreateEnc(&cng_enc_inst_)); - EXPECT_EQ(0, WebRtcCng_CreateDec(&cng_dec_inst_)); - EXPECT_EQ(0, WebRtcCng_InitEnc(cng_enc_inst_, 16000, kSidShortIntervalUpdate, - kCNGNumParamsNormal)); - WebRtcCng_InitDec(cng_dec_inst_); + // Create and initialize encoder and decoder. + ComfortNoiseEncoder cng_encoder(16000, kSidShortIntervalUpdate, + kCNGNumParamsNormal); + ComfortNoiseDecoder cng_decoder; // First call will never generate SID, unless forced to. - EXPECT_EQ(0, WebRtcCng_Encode(cng_enc_inst_, speech_data_, 160, sid_data, - &number_bytes, kNoSid)); + EXPECT_EQ(0U, cng_encoder.Encode( + rtc::ArrayView(speech_data_, 160), kNoSid, &sid_data)); // Normal Encode, 100 msec, SID data should be generated all the time. for (int i = 0; i < 10; i++) { - EXPECT_EQ(kCNGNumParamsNormal + 1, WebRtcCng_Encode( - cng_enc_inst_, speech_data_, 160, sid_data, &number_bytes, kNoSid)); + EXPECT_EQ(kCNGNumParamsNormal + 1, cng_encoder.Encode( + rtc::ArrayView(speech_data_, 160), kNoSid, &sid_data)); } - - // Free encoder and decoder memory. - EXPECT_EQ(0, WebRtcCng_FreeEnc(cng_enc_inst_)); - EXPECT_EQ(0, WebRtcCng_FreeDec(cng_dec_inst_)); } } // namespace webrtc diff --git a/webrtc/modules/audio_coding/codecs/cng/webrtc_cng.c b/webrtc/modules/audio_coding/codecs/cng/webrtc_cng.c deleted file mode 100644 index 8dddc5c717..0000000000 --- a/webrtc/modules/audio_coding/codecs/cng/webrtc_cng.c +++ /dev/null @@ -1,603 +0,0 @@ -/* - * 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_cng.h" - -#include -#include - -#include "cng_helpfuns.h" -#include "signal_processing_library.h" - -typedef struct WebRtcCngDecoder_ { - uint32_t dec_seed; - int32_t dec_target_energy; - int32_t dec_used_energy; - int16_t dec_target_reflCoefs[WEBRTC_CNG_MAX_LPC_ORDER + 1]; - int16_t dec_used_reflCoefs[WEBRTC_CNG_MAX_LPC_ORDER + 1]; - int16_t dec_filtstate[WEBRTC_CNG_MAX_LPC_ORDER + 1]; - int16_t dec_filtstateLow[WEBRTC_CNG_MAX_LPC_ORDER + 1]; - int16_t dec_Efiltstate[WEBRTC_CNG_MAX_LPC_ORDER + 1]; - int16_t dec_EfiltstateLow[WEBRTC_CNG_MAX_LPC_ORDER + 1]; - int16_t dec_order; - int16_t dec_target_scale_factor; /* Q29 */ - int16_t dec_used_scale_factor; /* Q29 */ - int16_t target_scale_factor; /* Q13 */ - int16_t errorcode; - int16_t initflag; -} WebRtcCngDecoder; - -typedef struct WebRtcCngEncoder_ { - size_t enc_nrOfCoefs; - int enc_sampfreq; - int16_t enc_interval; - int16_t enc_msSinceSID; - int32_t enc_Energy; - int16_t enc_reflCoefs[WEBRTC_CNG_MAX_LPC_ORDER + 1]; - int32_t enc_corrVector[WEBRTC_CNG_MAX_LPC_ORDER + 1]; - uint32_t enc_seed; - int16_t errorcode; - int16_t initflag; -} WebRtcCngEncoder; - -const int32_t WebRtcCng_kDbov[94] = { - 1081109975, 858756178, 682134279, 541838517, 430397633, 341876992, - 271562548, 215709799, 171344384, 136103682, 108110997, 85875618, - 68213428, 54183852, 43039763, 34187699, 27156255, 21570980, - 17134438, 13610368, 10811100, 8587562, 6821343, 5418385, - 4303976, 3418770, 2715625, 2157098, 1713444, 1361037, - 1081110, 858756, 682134, 541839, 430398, 341877, - 271563, 215710, 171344, 136104, 108111, 85876, - 68213, 54184, 43040, 34188, 27156, 21571, - 17134, 13610, 10811, 8588, 6821, 5418, - 4304, 3419, 2716, 2157, 1713, 1361, - 1081, 859, 682, 542, 430, 342, - 272, 216, 171, 136, 108, 86, - 68, 54, 43, 34, 27, 22, - 17, 14, 11, 9, 7, 5, - 4, 3, 3, 2, 2, 1, - 1, 1, 1, 1 -}; - -const int16_t WebRtcCng_kCorrWindow[WEBRTC_CNG_MAX_LPC_ORDER] = { - 32702, 32636, 32570, 32505, 32439, 32374, - 32309, 32244, 32179, 32114, 32049, 31985 -}; - -/**************************************************************************** - * WebRtcCng_CreateEnc/Dec(...) - * - * These functions create an instance to the specified structure - * - * Input: - * - XXX_inst : Pointer to created instance that should be created - * - * Return value : 0 - Ok - * -1 - Error - */ -int16_t WebRtcCng_CreateEnc(CNG_enc_inst** cng_inst) { - if (cng_inst != NULL) { - *cng_inst = (CNG_enc_inst*) malloc(sizeof(WebRtcCngEncoder)); - if (*cng_inst != NULL) { - (*(WebRtcCngEncoder**) cng_inst)->errorcode = 0; - (*(WebRtcCngEncoder**) cng_inst)->initflag = 0; - - /* Needed to get the right function pointers in SPLIB. */ - WebRtcSpl_Init(); - - return 0; - } else { - /* The memory could not be allocated. */ - return -1; - } - } else { - /* The input pointer is invalid (NULL). */ - return -1; - } -} - -int16_t WebRtcCng_CreateDec(CNG_dec_inst** cng_inst) { - if (cng_inst != NULL ) { - *cng_inst = (CNG_dec_inst*) malloc(sizeof(WebRtcCngDecoder)); - if (*cng_inst != NULL ) { - (*(WebRtcCngDecoder**) cng_inst)->errorcode = 0; - (*(WebRtcCngDecoder**) cng_inst)->initflag = 0; - - /* Needed to get the right function pointers in SPLIB. */ - WebRtcSpl_Init(); - - return 0; - } else { - /* The memory could not be allocated */ - return -1; - } - } else { - /* The input pointer is invalid (NULL). */ - return -1; - } -} - -/**************************************************************************** - * WebRtcCng_InitEnc/Dec(...) - * - * This function initializes a instance - * - * Input: - * - cng_inst : Instance that should be initialized - * - * - fs : 8000 for narrowband and 16000 for wideband - * - interval : generate SID data every interval ms - * - quality : TBD - * - * Output: - * - cng_inst : Initialized instance - * - * Return value : 0 - Ok - * -1 - Error - */ -int WebRtcCng_InitEnc(CNG_enc_inst* cng_inst, int fs, int16_t interval, - int16_t quality) { - int i; - WebRtcCngEncoder* inst = (WebRtcCngEncoder*) cng_inst; - memset(inst, 0, sizeof(WebRtcCngEncoder)); - - /* Check LPC order */ - if (quality > WEBRTC_CNG_MAX_LPC_ORDER || quality <= 0) { - inst->errorcode = CNG_DISALLOWED_LPC_ORDER; - return -1; - } - - inst->enc_sampfreq = fs; - inst->enc_interval = interval; - inst->enc_nrOfCoefs = quality; - inst->enc_msSinceSID = 0; - inst->enc_seed = 7777; /* For debugging only. */ - inst->enc_Energy = 0; - for (i = 0; i < (WEBRTC_CNG_MAX_LPC_ORDER + 1); i++) { - inst->enc_reflCoefs[i] = 0; - inst->enc_corrVector[i] = 0; - } - inst->initflag = 1; - - return 0; -} - -void WebRtcCng_InitDec(CNG_dec_inst* cng_inst) { - int i; - - WebRtcCngDecoder* inst = (WebRtcCngDecoder*) cng_inst; - - memset(inst, 0, sizeof(WebRtcCngDecoder)); - inst->dec_seed = 7777; /* For debugging only. */ - inst->dec_order = 5; - inst->dec_target_scale_factor = 0; - inst->dec_used_scale_factor = 0; - for (i = 0; i < (WEBRTC_CNG_MAX_LPC_ORDER + 1); i++) { - inst->dec_filtstate[i] = 0; - inst->dec_target_reflCoefs[i] = 0; - inst->dec_used_reflCoefs[i] = 0; - } - inst->dec_target_reflCoefs[0] = 0; - inst->dec_used_reflCoefs[0] = 0; - inst->dec_used_energy = 0; - inst->initflag = 1; -} - -/**************************************************************************** - * WebRtcCng_FreeEnc/Dec(...) - * - * These functions frees the dynamic memory of a specified instance - * - * Input: - * - cng_inst : Pointer to created instance that should be freed - * - * Return value : 0 - Ok - * -1 - Error - */ -int16_t WebRtcCng_FreeEnc(CNG_enc_inst* cng_inst) { - free(cng_inst); - return 0; -} - -int16_t WebRtcCng_FreeDec(CNG_dec_inst* cng_inst) { - free(cng_inst); - return 0; -} - -/**************************************************************************** - * WebRtcCng_Encode(...) - * - * These functions analyzes background noise - * - * Input: - * - cng_inst : Pointer to created instance - * - speech : Signal (noise) to be analyzed - * - nrOfSamples : Size of speech vector - * - bytesOut : Nr of bytes to transmit, might be 0 - * - * Return value : 0 - Ok - * -1 - Error - */ -int WebRtcCng_Encode(CNG_enc_inst* cng_inst, int16_t* speech, - size_t nrOfSamples, uint8_t* SIDdata, - size_t* bytesOut, int16_t forceSID) { - WebRtcCngEncoder* inst = (WebRtcCngEncoder*) cng_inst; - - int16_t arCoefs[WEBRTC_CNG_MAX_LPC_ORDER + 1]; - int32_t corrVector[WEBRTC_CNG_MAX_LPC_ORDER + 1]; - int16_t refCs[WEBRTC_CNG_MAX_LPC_ORDER + 1]; - int16_t hanningW[WEBRTC_CNG_MAX_OUTSIZE_ORDER]; - int16_t ReflBeta = 19661; /* 0.6 in q15. */ - int16_t ReflBetaComp = 13107; /* 0.4 in q15. */ - int32_t outEnergy; - int outShifts; - size_t i; - int stab; - int acorrScale; - size_t index; - size_t ind, factor; - int32_t* bptr; - int32_t blo, bhi; - int16_t negate; - const int16_t* aptr; - int16_t speechBuf[WEBRTC_CNG_MAX_OUTSIZE_ORDER]; - - /* Check if encoder initiated. */ - if (inst->initflag != 1) { - inst->errorcode = CNG_ENCODER_NOT_INITIATED; - return -1; - } - - /* Check framesize. */ - if (nrOfSamples > WEBRTC_CNG_MAX_OUTSIZE_ORDER) { - inst->errorcode = CNG_DISALLOWED_FRAME_SIZE; - return -1; - } - - for (i = 0; i < nrOfSamples; i++) { - speechBuf[i] = speech[i]; - } - - factor = nrOfSamples; - - /* Calculate energy and a coefficients. */ - outEnergy = WebRtcSpl_Energy(speechBuf, nrOfSamples, &outShifts); - while (outShifts > 0) { - /* We can only do 5 shifts without destroying accuracy in - * division factor. */ - if (outShifts > 5) { - outEnergy <<= (outShifts - 5); - outShifts = 5; - } else { - factor /= 2; - outShifts--; - } - } - outEnergy = WebRtcSpl_DivW32W16(outEnergy, (int16_t)factor); - - if (outEnergy > 1) { - /* Create Hanning Window. */ - WebRtcSpl_GetHanningWindow(hanningW, nrOfSamples / 2); - for (i = 0; i < (nrOfSamples / 2); i++) - hanningW[nrOfSamples - i - 1] = hanningW[i]; - - WebRtcSpl_ElementwiseVectorMult(speechBuf, hanningW, speechBuf, nrOfSamples, - 14); - - WebRtcSpl_AutoCorrelation(speechBuf, nrOfSamples, inst->enc_nrOfCoefs, - corrVector, &acorrScale); - - if (*corrVector == 0) - *corrVector = WEBRTC_SPL_WORD16_MAX; - - /* Adds the bandwidth expansion. */ - aptr = WebRtcCng_kCorrWindow; - bptr = corrVector; - - /* (zzz) lpc16_1 = 17+1+820+2+2 = 842 (ordo2=700). */ - for (ind = 0; ind < inst->enc_nrOfCoefs; ind++) { - /* The below code multiplies the 16 b corrWindow values (Q15) with - * the 32 b corrvector (Q0) and shifts the result down 15 steps. */ - negate = *bptr < 0; - if (negate) - *bptr = -*bptr; - - blo = (int32_t) * aptr * (*bptr & 0xffff); - bhi = ((blo >> 16) & 0xffff) - + ((int32_t)(*aptr++) * ((*bptr >> 16) & 0xffff)); - blo = (blo & 0xffff) | ((bhi & 0xffff) << 16); - - *bptr = (((bhi >> 16) & 0x7fff) << 17) | ((uint32_t) blo >> 15); - if (negate) - *bptr = -*bptr; - bptr++; - } - /* End of bandwidth expansion. */ - - stab = WebRtcSpl_LevinsonDurbin(corrVector, arCoefs, refCs, - inst->enc_nrOfCoefs); - - if (!stab) { - /* Disregard from this frame */ - *bytesOut = 0; - return 0; - } - - } else { - for (i = 0; i < inst->enc_nrOfCoefs; i++) - refCs[i] = 0; - } - - if (forceSID) { - /* Read instantaneous values instead of averaged. */ - for (i = 0; i < inst->enc_nrOfCoefs; i++) - inst->enc_reflCoefs[i] = refCs[i]; - inst->enc_Energy = outEnergy; - } else { - /* Average history with new values. */ - for (i = 0; i < (inst->enc_nrOfCoefs); i++) { - inst->enc_reflCoefs[i] = (int16_t) WEBRTC_SPL_MUL_16_16_RSFT( - inst->enc_reflCoefs[i], ReflBeta, 15); - inst->enc_reflCoefs[i] += (int16_t) WEBRTC_SPL_MUL_16_16_RSFT( - refCs[i], ReflBetaComp, 15); - } - inst->enc_Energy = (outEnergy >> 2) + (inst->enc_Energy >> 1) - + (inst->enc_Energy >> 2); - } - - if (inst->enc_Energy < 1) { - inst->enc_Energy = 1; - } - - if ((inst->enc_msSinceSID > (inst->enc_interval - 1)) || forceSID) { - - /* Search for best dbov value. */ - index = 0; - for (i = 1; i < 93; i++) { - /* Always round downwards. */ - if ((inst->enc_Energy - WebRtcCng_kDbov[i]) > 0) { - index = i; - break; - } - } - if ((i == 93) && (index == 0)) - index = 94; - SIDdata[0] = (uint8_t)index; - - /* Quantize coefficients with tweak for WebRtc implementation of RFC3389. */ - if (inst->enc_nrOfCoefs == WEBRTC_CNG_MAX_LPC_ORDER) { - for (i = 0; i < inst->enc_nrOfCoefs; i++) { - /* Q15 to Q7 with rounding. */ - SIDdata[i + 1] = ((inst->enc_reflCoefs[i] + 128) >> 8); - } - } else { - for (i = 0; i < inst->enc_nrOfCoefs; i++) { - /* Q15 to Q7 with rounding. */ - SIDdata[i + 1] = (127 + ((inst->enc_reflCoefs[i] + 128) >> 8)); - } - } - - inst->enc_msSinceSID = 0; - *bytesOut = inst->enc_nrOfCoefs + 1; - - inst->enc_msSinceSID += - (int16_t)((1000 * nrOfSamples) / inst->enc_sampfreq); - return (int)(inst->enc_nrOfCoefs + 1); - } else { - inst->enc_msSinceSID += - (int16_t)((1000 * nrOfSamples) / inst->enc_sampfreq); - *bytesOut = 0; - return 0; - } -} - -/**************************************************************************** - * WebRtcCng_UpdateSid(...) - * - * These functions updates the CN state, when a new SID packet arrives - * - * Input: - * - cng_inst : Pointer to created instance that should be freed - * - SID : SID packet, all headers removed - * - length : Length in bytes of SID packet - * - * Return value : 0 - Ok - * -1 - Error - */ -int16_t WebRtcCng_UpdateSid(CNG_dec_inst* cng_inst, uint8_t* SID, - size_t length) { - - WebRtcCngDecoder* inst = (WebRtcCngDecoder*) cng_inst; - int16_t refCs[WEBRTC_CNG_MAX_LPC_ORDER]; - int32_t targetEnergy; - int i; - - if (inst->initflag != 1) { - inst->errorcode = CNG_DECODER_NOT_INITIATED; - return -1; - } - - /* Throw away reflection coefficients of higher order than we can handle. */ - if (length > (WEBRTC_CNG_MAX_LPC_ORDER + 1)) - length = WEBRTC_CNG_MAX_LPC_ORDER + 1; - - inst->dec_order = (int16_t)length - 1; - - if (SID[0] > 93) - SID[0] = 93; - targetEnergy = WebRtcCng_kDbov[SID[0]]; - /* Take down target energy to 75%. */ - targetEnergy = targetEnergy >> 1; - targetEnergy += targetEnergy >> 2; - - inst->dec_target_energy = targetEnergy; - - /* Reconstruct coeffs with tweak for WebRtc implementation of RFC3389. */ - if (inst->dec_order == WEBRTC_CNG_MAX_LPC_ORDER) { - for (i = 0; i < (inst->dec_order); i++) { - refCs[i] = SID[i + 1] << 8; /* Q7 to Q15*/ - inst->dec_target_reflCoefs[i] = refCs[i]; - } - } else { - for (i = 0; i < (inst->dec_order); i++) { - refCs[i] = (SID[i + 1] - 127) << 8; /* Q7 to Q15. */ - inst->dec_target_reflCoefs[i] = refCs[i]; - } - } - - for (i = (inst->dec_order); i < WEBRTC_CNG_MAX_LPC_ORDER; i++) { - refCs[i] = 0; - inst->dec_target_reflCoefs[i] = refCs[i]; - } - - return 0; -} - -/**************************************************************************** - * WebRtcCng_Generate(...) - * - * These functions generates CN data when needed - * - * Input: - * - cng_inst : Pointer to created instance that should be freed - * - outData : pointer to area to write CN data - * - nrOfSamples : How much data to generate - * - * Return value : 0 - Ok - * -1 - Error - */ -int16_t WebRtcCng_Generate(CNG_dec_inst* cng_inst, int16_t* outData, - size_t nrOfSamples, int16_t new_period) { - WebRtcCngDecoder* inst = (WebRtcCngDecoder*) cng_inst; - - size_t i; - int16_t excitation[WEBRTC_CNG_MAX_OUTSIZE_ORDER]; - int16_t low[WEBRTC_CNG_MAX_OUTSIZE_ORDER]; - int16_t lpPoly[WEBRTC_CNG_MAX_LPC_ORDER + 1]; - int16_t ReflBetaStd = 26214; /* 0.8 in q15. */ - int16_t ReflBetaCompStd = 6553; /* 0.2 in q15. */ - int16_t ReflBetaNewP = 19661; /* 0.6 in q15. */ - int16_t ReflBetaCompNewP = 13107; /* 0.4 in q15. */ - int16_t Beta, BetaC, tmp1, tmp2, tmp3; - int32_t targetEnergy; - int16_t En; - int16_t temp16; - - if (nrOfSamples > WEBRTC_CNG_MAX_OUTSIZE_ORDER) { - inst->errorcode = CNG_DISALLOWED_FRAME_SIZE; - return -1; - } - - if (new_period) { - inst->dec_used_scale_factor = inst->dec_target_scale_factor; - Beta = ReflBetaNewP; - BetaC = ReflBetaCompNewP; - } else { - Beta = ReflBetaStd; - BetaC = ReflBetaCompStd; - } - - /* Here we use a 0.5 weighting, should possibly be modified to 0.6. */ - tmp1 = inst->dec_used_scale_factor << 2; /* Q13->Q15 */ - tmp2 = inst->dec_target_scale_factor << 2; /* Q13->Q15 */ - tmp3 = (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(tmp1, Beta, 15); - tmp3 += (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(tmp2, BetaC, 15); - inst->dec_used_scale_factor = tmp3 >> 2; /* Q15->Q13 */ - - inst->dec_used_energy = inst->dec_used_energy >> 1; - inst->dec_used_energy += inst->dec_target_energy >> 1; - - /* Do the same for the reflection coeffs. */ - for (i = 0; i < WEBRTC_CNG_MAX_LPC_ORDER; i++) { - inst->dec_used_reflCoefs[i] = (int16_t) WEBRTC_SPL_MUL_16_16_RSFT( - inst->dec_used_reflCoefs[i], Beta, 15); - inst->dec_used_reflCoefs[i] += (int16_t) WEBRTC_SPL_MUL_16_16_RSFT( - inst->dec_target_reflCoefs[i], BetaC, 15); - } - - /* Compute the polynomial coefficients. */ - WebRtcCng_K2a16(inst->dec_used_reflCoefs, WEBRTC_CNG_MAX_LPC_ORDER, lpPoly); - - - targetEnergy = inst->dec_used_energy; - - /* Calculate scaling factor based on filter energy. */ - En = 8192; /* 1.0 in Q13. */ - for (i = 0; i < (WEBRTC_CNG_MAX_LPC_ORDER); i++) { - - /* Floating point value for reference. - E *= 1.0 - (inst->dec_used_reflCoefs[i] / 32768.0) * - (inst->dec_used_reflCoefs[i] / 32768.0); - */ - - /* Same in fixed point. */ - /* K(i).^2 in Q15. */ - temp16 = (int16_t) WEBRTC_SPL_MUL_16_16_RSFT( - inst->dec_used_reflCoefs[i], inst->dec_used_reflCoefs[i], 15); - /* 1 - K(i).^2 in Q15. */ - temp16 = 0x7fff - temp16; - En = (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(En, temp16, 15); - } - - /* float scaling= sqrt(E * inst->dec_target_energy / (1 << 24)); */ - - /* Calculate sqrt(En * target_energy / excitation energy) */ - targetEnergy = WebRtcSpl_Sqrt(inst->dec_used_energy); - - En = (int16_t) WebRtcSpl_Sqrt(En) << 6; - En = (En * 3) >> 1; /* 1.5 estimates sqrt(2). */ - inst->dec_used_scale_factor = (int16_t)((En * targetEnergy) >> 12); - - /* Generate excitation. */ - /* Excitation energy per sample is 2.^24 - Q13 N(0,1). */ - for (i = 0; i < nrOfSamples; i++) { - excitation[i] = WebRtcSpl_RandN(&inst->dec_seed) >> 1; - } - - /* Scale to correct energy. */ - WebRtcSpl_ScaleVector(excitation, excitation, inst->dec_used_scale_factor, - nrOfSamples, 13); - - /* |lpPoly| - Coefficients in Q12. - * |excitation| - Speech samples. - * |nst->dec_filtstate| - State preservation. - * |outData| - Filtered speech samples. */ - WebRtcSpl_FilterAR(lpPoly, WEBRTC_CNG_MAX_LPC_ORDER + 1, excitation, - nrOfSamples, inst->dec_filtstate, WEBRTC_CNG_MAX_LPC_ORDER, - inst->dec_filtstateLow, WEBRTC_CNG_MAX_LPC_ORDER, outData, - low, nrOfSamples); - - return 0; -} - -/**************************************************************************** - * WebRtcCng_GetErrorCodeEnc/Dec(...) - * - * This functions can be used to check the error code of a CNG instance. When - * a function returns -1 a error code will be set for that instance. The - * function below extract the code of the last error that occured in the - * specified instance. - * - * Input: - * - CNG_inst : CNG enc/dec instance - * - * Return value : Error code - */ -int16_t WebRtcCng_GetErrorCodeEnc(CNG_enc_inst* cng_inst) { - /* Typecast pointer to real structure. */ - WebRtcCngEncoder* inst = (WebRtcCngEncoder*) cng_inst; - return inst->errorcode; -} - -int16_t WebRtcCng_GetErrorCodeDec(CNG_dec_inst* cng_inst) { - /* Typecast pointer to real structure. */ - WebRtcCngDecoder* inst = (WebRtcCngDecoder*) cng_inst; - return inst->errorcode; -} diff --git a/webrtc/modules/audio_coding/codecs/cng/webrtc_cng.cc b/webrtc/modules/audio_coding/codecs/cng/webrtc_cng.cc new file mode 100644 index 0000000000..b4da260dba --- /dev/null +++ b/webrtc/modules/audio_coding/codecs/cng/webrtc_cng.cc @@ -0,0 +1,442 @@ +/* + * 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/codecs/cng/webrtc_cng.h" + +#include + +#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h" + +namespace webrtc { + +namespace { + +const size_t kCngMaxOutsizeOrder = 640; + +// TODO(ossu): Rename the left-over WebRtcCng according to style guide. +void WebRtcCng_K2a16(int16_t* k, int useOrder, int16_t* a); + +const int32_t WebRtcCng_kDbov[94] = { + 1081109975, 858756178, 682134279, 541838517, 430397633, 341876992, + 271562548, 215709799, 171344384, 136103682, 108110997, 85875618, + 68213428, 54183852, 43039763, 34187699, 27156255, 21570980, + 17134438, 13610368, 10811100, 8587562, 6821343, 5418385, + 4303976, 3418770, 2715625, 2157098, 1713444, 1361037, + 1081110, 858756, 682134, 541839, 430398, 341877, + 271563, 215710, 171344, 136104, 108111, 85876, + 68213, 54184, 43040, 34188, 27156, 21571, + 17134, 13610, 10811, 8588, 6821, 5418, + 4304, 3419, 2716, 2157, 1713, 1361, + 1081, 859, 682, 542, 430, 342, + 272, 216, 171, 136, 108, 86, + 68, 54, 43, 34, 27, 22, + 17, 14, 11, 9, 7, 5, + 4, 3, 3, 2, 2, 1, + 1, 1, 1, 1 +}; + +const int16_t WebRtcCng_kCorrWindow[WEBRTC_CNG_MAX_LPC_ORDER] = { + 32702, 32636, 32570, 32505, 32439, 32374, + 32309, 32244, 32179, 32114, 32049, 31985 +}; + +} // namespace + +ComfortNoiseDecoder::ComfortNoiseDecoder() { + /* Needed to get the right function pointers in SPLIB. */ + WebRtcSpl_Init(); + Reset(); +} + +void ComfortNoiseDecoder::Reset() { + dec_seed_ = 7777; /* For debugging only. */ + dec_target_energy_ = 0; + dec_used_energy_ = 0; + for (auto& c : dec_target_reflCoefs_) + c = 0; + for (auto& c : dec_used_reflCoefs_) + c = 0; + for (auto& c : dec_filtstate_) + c = 0; + for (auto& c : dec_filtstateLow_) + c = 0; + dec_order_ = 5; + dec_target_scale_factor_ = 0; + dec_used_scale_factor_ = 0; +} + +void ComfortNoiseDecoder::UpdateSid(rtc::ArrayView sid) { + int16_t refCs[WEBRTC_CNG_MAX_LPC_ORDER]; + int32_t targetEnergy; + size_t length = sid.size(); + /* Throw away reflection coefficients of higher order than we can handle. */ + if (length > (WEBRTC_CNG_MAX_LPC_ORDER + 1)) + length = WEBRTC_CNG_MAX_LPC_ORDER + 1; + + dec_order_ = static_cast(length - 1); + + uint8_t sid0 = std::min(sid[0], 93); + targetEnergy = WebRtcCng_kDbov[sid0]; + /* Take down target energy to 75%. */ + targetEnergy = targetEnergy >> 1; + targetEnergy += targetEnergy >> 2; + + dec_target_energy_ = targetEnergy; + + /* Reconstruct coeffs with tweak for WebRtc implementation of RFC3389. */ + if (dec_order_ == WEBRTC_CNG_MAX_LPC_ORDER) { + for (size_t i = 0; i < (dec_order_); i++) { + refCs[i] = sid[i + 1] << 8; /* Q7 to Q15*/ + dec_target_reflCoefs_[i] = refCs[i]; + } + } else { + for (size_t i = 0; i < (dec_order_); i++) { + refCs[i] = (sid[i + 1] - 127) << 8; /* Q7 to Q15. */ + dec_target_reflCoefs_[i] = refCs[i]; + } + } + + for (size_t i = (dec_order_); i < WEBRTC_CNG_MAX_LPC_ORDER; i++) { + refCs[i] = 0; + dec_target_reflCoefs_[i] = refCs[i]; + } +} + +bool ComfortNoiseDecoder::Generate(rtc::ArrayView out_data, + bool new_period) { + int16_t excitation[kCngMaxOutsizeOrder]; + int16_t low[kCngMaxOutsizeOrder]; + int16_t lpPoly[WEBRTC_CNG_MAX_LPC_ORDER + 1]; + int16_t ReflBetaStd = 26214; /* 0.8 in q15. */ + int16_t ReflBetaCompStd = 6553; /* 0.2 in q15. */ + int16_t ReflBetaNewP = 19661; /* 0.6 in q15. */ + int16_t ReflBetaCompNewP = 13107; /* 0.4 in q15. */ + int16_t Beta, BetaC, tmp1, tmp2, tmp3; + int32_t targetEnergy; + int16_t En; + int16_t temp16; + const size_t num_samples = out_data.size(); + + if (num_samples > kCngMaxOutsizeOrder) { + return false; + } + + if (new_period) { + dec_used_scale_factor_ = dec_target_scale_factor_; + Beta = ReflBetaNewP; + BetaC = ReflBetaCompNewP; + } else { + Beta = ReflBetaStd; + BetaC = ReflBetaCompStd; + } + + /* Here we use a 0.5 weighting, should possibly be modified to 0.6. */ + tmp1 = dec_used_scale_factor_ << 2; /* Q13->Q15 */ + tmp2 = dec_target_scale_factor_ << 2; /* Q13->Q15 */ + tmp3 = (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(tmp1, Beta, 15); + tmp3 += (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(tmp2, BetaC, 15); + dec_used_scale_factor_ = tmp3 >> 2; /* Q15->Q13 */ + + dec_used_energy_ = dec_used_energy_ >> 1; + dec_used_energy_ += dec_target_energy_ >> 1; + + /* Do the same for the reflection coeffs. */ + for (size_t i = 0; i < WEBRTC_CNG_MAX_LPC_ORDER; i++) { + dec_used_reflCoefs_[i] = (int16_t) WEBRTC_SPL_MUL_16_16_RSFT( + dec_used_reflCoefs_[i], Beta, 15); + dec_used_reflCoefs_[i] += (int16_t) WEBRTC_SPL_MUL_16_16_RSFT( + dec_target_reflCoefs_[i], BetaC, 15); + } + + /* Compute the polynomial coefficients. */ + WebRtcCng_K2a16(dec_used_reflCoefs_, WEBRTC_CNG_MAX_LPC_ORDER, lpPoly); + + + targetEnergy = dec_used_energy_; + + /* Calculate scaling factor based on filter energy. */ + En = 8192; /* 1.0 in Q13. */ + for (size_t i = 0; i < (WEBRTC_CNG_MAX_LPC_ORDER); i++) { + /* Floating point value for reference. + E *= 1.0 - (dec_used_reflCoefs_[i] / 32768.0) * + (dec_used_reflCoefs_[i] / 32768.0); + */ + + /* Same in fixed point. */ + /* K(i).^2 in Q15. */ + temp16 = (int16_t) WEBRTC_SPL_MUL_16_16_RSFT( + dec_used_reflCoefs_[i], dec_used_reflCoefs_[i], 15); + /* 1 - K(i).^2 in Q15. */ + temp16 = 0x7fff - temp16; + En = (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(En, temp16, 15); + } + + /* float scaling= sqrt(E * dec_target_energy_ / (1 << 24)); */ + + /* Calculate sqrt(En * target_energy / excitation energy) */ + targetEnergy = WebRtcSpl_Sqrt(dec_used_energy_); + + En = (int16_t) WebRtcSpl_Sqrt(En) << 6; + En = (En * 3) >> 1; /* 1.5 estimates sqrt(2). */ + dec_used_scale_factor_ = (int16_t)((En * targetEnergy) >> 12); + + /* Generate excitation. */ + /* Excitation energy per sample is 2.^24 - Q13 N(0,1). */ + for (size_t i = 0; i < num_samples; i++) { + excitation[i] = WebRtcSpl_RandN(&dec_seed_) >> 1; + } + + /* Scale to correct energy. */ + WebRtcSpl_ScaleVector(excitation, excitation, dec_used_scale_factor_, + num_samples, 13); + + /* |lpPoly| - Coefficients in Q12. + * |excitation| - Speech samples. + * |nst->dec_filtstate| - State preservation. + * |out_data| - Filtered speech samples. */ + WebRtcSpl_FilterAR(lpPoly, WEBRTC_CNG_MAX_LPC_ORDER + 1, excitation, + num_samples, dec_filtstate_, WEBRTC_CNG_MAX_LPC_ORDER, + dec_filtstateLow_, WEBRTC_CNG_MAX_LPC_ORDER, + out_data.data(), low, num_samples); + + return true; +} + +ComfortNoiseEncoder::ComfortNoiseEncoder(int fs, int interval, int quality) + : enc_nrOfCoefs_(quality), + enc_sampfreq_(fs), + enc_interval_(interval), + enc_msSinceSid_(0), + enc_Energy_(0), + enc_reflCoefs_{0}, + enc_corrVector_{0}, + enc_seed_(7777) /* For debugging only. */ { + RTC_CHECK(quality <= WEBRTC_CNG_MAX_LPC_ORDER && quality > 0); + /* Needed to get the right function pointers in SPLIB. */ + WebRtcSpl_Init(); +} + +void ComfortNoiseEncoder::Reset(int fs, int interval, int quality) { + RTC_CHECK(quality <= WEBRTC_CNG_MAX_LPC_ORDER && quality > 0); + enc_nrOfCoefs_ = quality; + enc_sampfreq_ = fs; + enc_interval_ = interval; + enc_msSinceSid_ = 0; + enc_Energy_ = 0; + for (auto& c : enc_reflCoefs_) + c = 0; + for (auto& c : enc_corrVector_) + c = 0; + enc_seed_ = 7777; /* For debugging only. */ +} + +size_t ComfortNoiseEncoder::Encode(rtc::ArrayView speech, + bool force_sid, + rtc::Buffer* output) { + int16_t arCoefs[WEBRTC_CNG_MAX_LPC_ORDER + 1]; + int32_t corrVector[WEBRTC_CNG_MAX_LPC_ORDER + 1]; + int16_t refCs[WEBRTC_CNG_MAX_LPC_ORDER + 1]; + int16_t hanningW[kCngMaxOutsizeOrder]; + int16_t ReflBeta = 19661; /* 0.6 in q15. */ + int16_t ReflBetaComp = 13107; /* 0.4 in q15. */ + int32_t outEnergy; + int outShifts; + size_t i; + int stab; + int acorrScale; + size_t index; + size_t ind, factor; + int32_t* bptr; + int32_t blo, bhi; + int16_t negate; + const int16_t* aptr; + int16_t speechBuf[kCngMaxOutsizeOrder]; + + const size_t num_samples = speech.size(); + RTC_CHECK_LE(num_samples, static_cast(kCngMaxOutsizeOrder)); + + for (i = 0; i < num_samples; i++) { + speechBuf[i] = speech[i]; + } + + factor = num_samples; + + /* Calculate energy and a coefficients. */ + outEnergy = WebRtcSpl_Energy(speechBuf, num_samples, &outShifts); + while (outShifts > 0) { + /* We can only do 5 shifts without destroying accuracy in + * division factor. */ + if (outShifts > 5) { + outEnergy <<= (outShifts - 5); + outShifts = 5; + } else { + factor /= 2; + outShifts--; + } + } + outEnergy = WebRtcSpl_DivW32W16(outEnergy, (int16_t)factor); + + if (outEnergy > 1) { + /* Create Hanning Window. */ + WebRtcSpl_GetHanningWindow(hanningW, num_samples / 2); + for (i = 0; i < (num_samples / 2); i++) + hanningW[num_samples - i - 1] = hanningW[i]; + + WebRtcSpl_ElementwiseVectorMult(speechBuf, hanningW, speechBuf, num_samples, + 14); + + WebRtcSpl_AutoCorrelation(speechBuf, num_samples, enc_nrOfCoefs_, + corrVector, &acorrScale); + + if (*corrVector == 0) + *corrVector = WEBRTC_SPL_WORD16_MAX; + + /* Adds the bandwidth expansion. */ + aptr = WebRtcCng_kCorrWindow; + bptr = corrVector; + + /* (zzz) lpc16_1 = 17+1+820+2+2 = 842 (ordo2=700). */ + for (ind = 0; ind < enc_nrOfCoefs_; ind++) { + /* The below code multiplies the 16 b corrWindow values (Q15) with + * the 32 b corrvector (Q0) and shifts the result down 15 steps. */ + negate = *bptr < 0; + if (negate) + *bptr = -*bptr; + + blo = (int32_t) * aptr * (*bptr & 0xffff); + bhi = ((blo >> 16) & 0xffff) + + ((int32_t)(*aptr++) * ((*bptr >> 16) & 0xffff)); + blo = (blo & 0xffff) | ((bhi & 0xffff) << 16); + + *bptr = (((bhi >> 16) & 0x7fff) << 17) | ((uint32_t) blo >> 15); + if (negate) + *bptr = -*bptr; + bptr++; + } + /* End of bandwidth expansion. */ + + stab = WebRtcSpl_LevinsonDurbin(corrVector, arCoefs, refCs, + enc_nrOfCoefs_); + + if (!stab) { + /* Disregard from this frame */ + return 0; + } + + } else { + for (i = 0; i < enc_nrOfCoefs_; i++) + refCs[i] = 0; + } + + if (force_sid) { + /* Read instantaneous values instead of averaged. */ + for (i = 0; i < enc_nrOfCoefs_; i++) + enc_reflCoefs_[i] = refCs[i]; + enc_Energy_ = outEnergy; + } else { + /* Average history with new values. */ + for (i = 0; i < enc_nrOfCoefs_; i++) { + enc_reflCoefs_[i] = (int16_t) WEBRTC_SPL_MUL_16_16_RSFT( + enc_reflCoefs_[i], ReflBeta, 15); + enc_reflCoefs_[i] += + (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(refCs[i], ReflBetaComp, 15); + } + enc_Energy_ = + (outEnergy >> 2) + (enc_Energy_ >> 1) + (enc_Energy_ >> 2); + } + + if (enc_Energy_ < 1) { + enc_Energy_ = 1; + } + + if ((enc_msSinceSid_ > (enc_interval_ - 1)) || force_sid) { + /* Search for best dbov value. */ + index = 0; + for (i = 1; i < 93; i++) { + /* Always round downwards. */ + if ((enc_Energy_ - WebRtcCng_kDbov[i]) > 0) { + index = i; + break; + } + } + if ((i == 93) && (index == 0)) + index = 94; + + const size_t output_coefs = enc_nrOfCoefs_ + 1; + output->AppendData(output_coefs, [&] (rtc::ArrayView output) { + output[0] = (uint8_t)index; + + /* Quantize coefficients with tweak for WebRtc implementation of + * RFC3389. */ + if (enc_nrOfCoefs_ == WEBRTC_CNG_MAX_LPC_ORDER) { + for (i = 0; i < enc_nrOfCoefs_; i++) { + /* Q15 to Q7 with rounding. */ + output[i + 1] = ((enc_reflCoefs_[i] + 128) >> 8); + } + } else { + for (i = 0; i < enc_nrOfCoefs_; i++) { + /* Q15 to Q7 with rounding. */ + output[i + 1] = (127 + ((enc_reflCoefs_[i] + 128) >> 8)); + } + } + + return output_coefs; + }); + + enc_msSinceSid_ = + static_cast((1000 * num_samples) / enc_sampfreq_); + return output_coefs; + } else { + enc_msSinceSid_ += + static_cast((1000 * num_samples) / enc_sampfreq_); + return 0; + } +} + +namespace { +/* Values in |k| are Q15, and |a| Q12. */ +void WebRtcCng_K2a16(int16_t* k, int useOrder, int16_t* a) { + int16_t any[WEBRTC_SPL_MAX_LPC_ORDER + 1]; + int16_t* aptr; + int16_t* aptr2; + int16_t* anyptr; + const int16_t* kptr; + int m, i; + + kptr = k; + *a = 4096; /* i.e., (Word16_MAX >> 3) + 1 */ + *any = *a; + a[1] = (*k + 4) >> 3; + for (m = 1; m < useOrder; m++) { + kptr++; + aptr = a; + aptr++; + aptr2 = &a[m]; + anyptr = any; + anyptr++; + + any[m + 1] = (*kptr + 4) >> 3; + for (i = 0; i < m; i++) { + *anyptr++ = + (*aptr++) + + (int16_t)((((int32_t)(*aptr2--) * (int32_t)*kptr) + 16384) >> 15); + } + + aptr = a; + anyptr = any; + for (i = 0; i < (m + 2); i++) { + *aptr++ = *anyptr++; + } + } +} + +} // namespace + +} // namespace webrtc diff --git a/webrtc/modules/audio_coding/codecs/cng/webrtc_cng.h b/webrtc/modules/audio_coding/codecs/cng/webrtc_cng.h index 64bea1e26f..fb0a53df27 100644 --- a/webrtc/modules/audio_coding/codecs/cng/webrtc_cng.h +++ b/webrtc/modules/audio_coding/codecs/cng/webrtc_cng.h @@ -12,152 +12,88 @@ #ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_CNG_WEBRTC_CNG_H_ #define WEBRTC_MODULES_AUDIO_CODING_CODECS_CNG_WEBRTC_CNG_H_ -#include +#include + +#include "webrtc/base/array_view.h" +#include "webrtc/base/buffer.h" #include "webrtc/typedefs.h" -#ifdef __cplusplus -extern "C" { -#endif - #define WEBRTC_CNG_MAX_LPC_ORDER 12 -#define WEBRTC_CNG_MAX_OUTSIZE_ORDER 640 -/* Define Error codes. */ +namespace webrtc { -/* 6100 Encoder */ -#define CNG_ENCODER_NOT_INITIATED 6120 -#define CNG_DISALLOWED_LPC_ORDER 6130 -#define CNG_DISALLOWED_FRAME_SIZE 6140 -#define CNG_DISALLOWED_SAMPLING_FREQUENCY 6150 -/* 6200 Decoder */ -#define CNG_DECODER_NOT_INITIATED 6220 +class ComfortNoiseDecoder { + public: + ComfortNoiseDecoder(); + ~ComfortNoiseDecoder() = default; -typedef struct WebRtcCngEncInst CNG_enc_inst; -typedef struct WebRtcCngDecInst CNG_dec_inst; + ComfortNoiseDecoder(const ComfortNoiseDecoder&) = delete; + ComfortNoiseDecoder& operator=(const ComfortNoiseDecoder&) = delete; -/**************************************************************************** - * WebRtcCng_CreateEnc/Dec(...) - * - * These functions create an instance to the specified structure - * - * Input: - * - XXX_inst : Pointer to created instance that should be created - * - * Return value : 0 - Ok - * -1 - Error - */ -int16_t WebRtcCng_CreateEnc(CNG_enc_inst** cng_inst); -int16_t WebRtcCng_CreateDec(CNG_dec_inst** cng_inst); + void Reset(); -/**************************************************************************** - * WebRtcCng_InitEnc/Dec(...) - * - * This function initializes a instance - * - * Input: - * - cng_inst : Instance that should be initialized - * - * - fs : 8000 for narrowband and 16000 for wideband - * - interval : generate SID data every interval ms - * - quality : Number of refl. coefs, maximum allowed is 12 - * - * Output: - * - cng_inst : Initialized instance - * - * Return value : 0 - Ok - * -1 - Error - */ + // Updates the CN state when a new SID packet arrives. + // |sid| is a view of the SID packet without the headers. + void UpdateSid(rtc::ArrayView sid); -int WebRtcCng_InitEnc(CNG_enc_inst* cng_inst, int fs, int16_t interval, - int16_t quality); -void WebRtcCng_InitDec(CNG_dec_inst* cng_inst); + // Generates comfort noise. + // |out_data| will be filled with samples - its size determines the number of + // samples generated. When |new_period| is true, CNG history will be reset + // before any audio is generated. Returns |false| if outData is too large - + // currently 640 bytes (equalling 10ms at 64kHz). + // TODO(ossu): Specify better limits for the size of out_data. Either let it + // be unbounded or limit to 10ms in the current sample rate. + bool Generate(rtc::ArrayView out_data, bool new_period); -/**************************************************************************** - * WebRtcCng_FreeEnc/Dec(...) - * - * These functions frees the dynamic memory of a specified instance - * - * Input: - * - cng_inst : Pointer to created instance that should be freed - * - * Return value : 0 - Ok - * -1 - Error - */ -int16_t WebRtcCng_FreeEnc(CNG_enc_inst* cng_inst); -int16_t WebRtcCng_FreeDec(CNG_dec_inst* cng_inst); + private: + uint32_t dec_seed_; + int32_t dec_target_energy_; + int32_t dec_used_energy_; + int16_t dec_target_reflCoefs_[WEBRTC_CNG_MAX_LPC_ORDER + 1]; + int16_t dec_used_reflCoefs_[WEBRTC_CNG_MAX_LPC_ORDER + 1]; + int16_t dec_filtstate_[WEBRTC_CNG_MAX_LPC_ORDER + 1]; + int16_t dec_filtstateLow_[WEBRTC_CNG_MAX_LPC_ORDER + 1]; + uint16_t dec_order_; + int16_t dec_target_scale_factor_; /* Q29 */ + int16_t dec_used_scale_factor_; /* Q29 */ +}; -/**************************************************************************** - * WebRtcCng_Encode(...) - * - * These functions analyzes background noise - * - * Input: - * - cng_inst : Pointer to created instance - * - speech : Signal to be analyzed - * - nrOfSamples : Size of speech vector - * - forceSID : not zero to force SID frame and reset - * - * Output: - * - bytesOut : Nr of bytes to transmit, might be 0 - * - * Return value : 0 - Ok - * -1 - Error - */ -int WebRtcCng_Encode(CNG_enc_inst* cng_inst, int16_t* speech, - size_t nrOfSamples, uint8_t* SIDdata, - size_t* bytesOut, int16_t forceSID); +class ComfortNoiseEncoder { + public: + // Creates a comfort noise encoder. + // |fs| selects sample rate: 8000 for narrowband or 16000 for wideband. + // |interval| sets the interval at which to generate SID data (in ms). + // |quality| selects the number of refl. coeffs. Maximum allowed is 12. + ComfortNoiseEncoder(int fs, int interval, int quality); + ~ComfortNoiseEncoder() = default; -/**************************************************************************** - * WebRtcCng_UpdateSid(...) - * - * These functions updates the CN state, when a new SID packet arrives - * - * Input: - * - cng_inst : Pointer to created instance that should be freed - * - SID : SID packet, all headers removed - * - length : Length in bytes of SID packet - * - * Return value : 0 - Ok - * -1 - Error - */ -int16_t WebRtcCng_UpdateSid(CNG_dec_inst* cng_inst, uint8_t* SID, - size_t length); + ComfortNoiseEncoder(const ComfortNoiseEncoder&) = delete; + ComfortNoiseEncoder& operator=(const ComfortNoiseEncoder&) = delete; -/**************************************************************************** - * WebRtcCng_Generate(...) - * - * These functions generates CN data when needed - * - * Input: - * - cng_inst : Pointer to created instance that should be freed - * - outData : pointer to area to write CN data - * - nrOfSamples : How much data to generate - * - new_period : >0 if a new period of CNG, will reset history - * - * Return value : 0 - Ok - * -1 - Error - */ -int16_t WebRtcCng_Generate(CNG_dec_inst* cng_inst, int16_t* outData, - size_t nrOfSamples, int16_t new_period); + // Resets the comfort noise encoder to its initial state. + // Parameters are set as during construction. + void Reset(int fs, int interval, int quality); -/***************************************************************************** - * WebRtcCng_GetErrorCodeEnc/Dec(...) - * - * This functions can be used to check the error code of a CNG instance. When - * a function returns -1 a error code will be set for that instance. The - * function below extract the code of the last error that occurred in the - * specified instance. - * - * Input: - * - CNG_inst : CNG enc/dec instance - * - * Return value : Error code - */ -int16_t WebRtcCng_GetErrorCodeEnc(CNG_enc_inst* cng_inst); -int16_t WebRtcCng_GetErrorCodeDec(CNG_dec_inst* cng_inst); + // Analyzes background noise from |speech| and appends coefficients to + // |output|. Returns the number of coefficients generated. If |force_sid| is + // true, a SID frame is forced and the internal sid interval counter is reset. + // Will fail if the input size is too large (> 640 samples, see + // ComfortNoiseDecoder::Generate). + size_t Encode(rtc::ArrayView speech, + bool force_sid, + rtc::Buffer* output); -#ifdef __cplusplus -} -#endif + private: + size_t enc_nrOfCoefs_; + int enc_sampfreq_; + int16_t enc_interval_; + int16_t enc_msSinceSid_; + int32_t enc_Energy_; + int16_t enc_reflCoefs_[WEBRTC_CNG_MAX_LPC_ORDER + 1]; + int32_t enc_corrVector_[WEBRTC_CNG_MAX_LPC_ORDER + 1]; + uint32_t enc_seed_; +}; + +} // namespace webrtc #endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_CNG_WEBRTC_CNG_H_ diff --git a/webrtc/modules/audio_coding/neteq/audio_decoder_impl.cc b/webrtc/modules/audio_coding/neteq/audio_decoder_impl.cc index d800cc7dbe..c9b9b6ae67 100644 --- a/webrtc/modules/audio_coding/neteq/audio_decoder_impl.cc +++ b/webrtc/modules/audio_coding/neteq/audio_decoder_impl.cc @@ -13,7 +13,6 @@ #include #include "webrtc/base/checks.h" -#include "webrtc/modules/audio_coding/codecs/cng/webrtc_cng.h" #include "webrtc/modules/audio_coding/codecs/g711/audio_decoder_pcm.h" #ifdef WEBRTC_CODEC_G722 #include "webrtc/modules/audio_coding/codecs/g722/audio_decoder_g722.h" @@ -36,43 +35,6 @@ namespace webrtc { -AudioDecoderCng::AudioDecoderCng() { - RTC_CHECK_EQ(0, WebRtcCng_CreateDec(&dec_state_)); - WebRtcCng_InitDec(dec_state_); -} - -AudioDecoderCng::~AudioDecoderCng() { - WebRtcCng_FreeDec(dec_state_); -} - -void AudioDecoderCng::Reset() { - WebRtcCng_InitDec(dec_state_); -} - -int AudioDecoderCng::IncomingPacket(const uint8_t* payload, - size_t payload_len, - uint16_t rtp_sequence_number, - uint32_t rtp_timestamp, - uint32_t arrival_timestamp) { - return -1; -} - -CNG_dec_inst* AudioDecoderCng::CngDecoderInstance() { - return dec_state_; -} - -size_t AudioDecoderCng::Channels() const { - return 1; -} - -int AudioDecoderCng::DecodeInternal(const uint8_t* encoded, - size_t encoded_len, - int sample_rate_hz, - int16_t* decoded, - SpeechType* speech_type) { - return -1; -} - bool CodecSupported(NetEqDecoder codec_type) { switch (codec_type) { case NetEqDecoder::kDecoderPCMu: @@ -228,7 +190,7 @@ AudioDecoder* CreateAudioDecoder(NetEqDecoder codec_type) { case NetEqDecoder::kDecoderCNGwb: case NetEqDecoder::kDecoderCNGswb32kHz: case NetEqDecoder::kDecoderCNGswb48kHz: - return new AudioDecoderCng; + RTC_CHECK(false) << "CNG should not be created like this anymore!"; case NetEqDecoder::kDecoderRED: case NetEqDecoder::kDecoderAVT: case NetEqDecoder::kDecoderArbitrary: diff --git a/webrtc/modules/audio_coding/neteq/audio_decoder_impl.h b/webrtc/modules/audio_coding/neteq/audio_decoder_impl.h index bc8bdd9626..d9a1d814f1 100644 --- a/webrtc/modules/audio_coding/neteq/audio_decoder_impl.h +++ b/webrtc/modules/audio_coding/neteq/audio_decoder_impl.h @@ -16,7 +16,6 @@ #include "webrtc/engine_configurations.h" #include "webrtc/base/constructormagic.h" #include "webrtc/modules/audio_coding/codecs/audio_decoder.h" -#include "webrtc/modules/audio_coding/codecs/cng/webrtc_cng.h" #ifdef WEBRTC_CODEC_G722 #include "webrtc/modules/audio_coding/codecs/g722/g722_interface.h" #endif @@ -25,38 +24,6 @@ namespace webrtc { -// AudioDecoderCng is a special type of AudioDecoder. It inherits from -// AudioDecoder just to fit in the DecoderDatabase. None of the class methods -// should be used, except constructor, destructor, and accessors. -// TODO(hlundin): Consider the possibility to create a super-class to -// AudioDecoder that is stored in DecoderDatabase. Then AudioDecoder and a -// specific CngDecoder class could both inherit from that class. -class AudioDecoderCng : public AudioDecoder { - public: - explicit AudioDecoderCng(); - ~AudioDecoderCng() override; - void Reset() override; - int IncomingPacket(const uint8_t* payload, - size_t payload_len, - uint16_t rtp_sequence_number, - uint32_t rtp_timestamp, - uint32_t arrival_timestamp) override; - - CNG_dec_inst* CngDecoderInstance() override; - size_t Channels() const override; - - protected: - int DecodeInternal(const uint8_t* encoded, - size_t encoded_len, - int sample_rate_hz, - int16_t* decoded, - SpeechType* speech_type) override; - - private: - CNG_dec_inst* dec_state_; - RTC_DISALLOW_COPY_AND_ASSIGN(AudioDecoderCng); -}; - using NetEqDecoder = acm2::RentACodec::NetEqDecoder; // Returns true if |codec_type| is supported. diff --git a/webrtc/modules/audio_coding/neteq/comfort_noise.cc b/webrtc/modules/audio_coding/neteq/comfort_noise.cc index a5b08469be..2a512bd750 100644 --- a/webrtc/modules/audio_coding/neteq/comfort_noise.cc +++ b/webrtc/modules/audio_coding/neteq/comfort_noise.cc @@ -14,7 +14,6 @@ #include "webrtc/base/logging.h" #include "webrtc/modules/audio_coding/codecs/audio_decoder.h" -#include "webrtc/modules/audio_coding/codecs/cng/webrtc_cng.h" #include "webrtc/modules/audio_coding/neteq/decoder_database.h" #include "webrtc/modules/audio_coding/neteq/dsp_helper.h" #include "webrtc/modules/audio_coding/neteq/sync_buffer.h" @@ -23,31 +22,23 @@ namespace webrtc { void ComfortNoise::Reset() { first_call_ = true; - internal_error_code_ = 0; } int ComfortNoise::UpdateParameters(Packet* packet) { assert(packet); // Existence is verified by caller. // Get comfort noise decoder. - AudioDecoder* cng_decoder = decoder_database_->GetDecoder( - packet->header.payloadType); - if (!cng_decoder) { + if (decoder_database_->SetActiveCngDecoder(packet->header.payloadType) + != kOK) { delete [] packet->payload; delete packet; return kUnknownPayloadType; } - decoder_database_->SetActiveCngDecoder(packet->header.payloadType); - CNG_dec_inst* cng_inst = cng_decoder->CngDecoderInstance(); - int16_t ret = WebRtcCng_UpdateSid(cng_inst, - packet->payload, - packet->payload_length); + ComfortNoiseDecoder* cng_decoder = decoder_database_->GetActiveCngDecoder(); + RTC_DCHECK(cng_decoder); + cng_decoder->UpdateSid(rtc::ArrayView( + packet->payload, packet->payload_length)); delete [] packet->payload; delete packet; - if (ret < 0) { - internal_error_code_ = WebRtcCng_GetErrorCodeDec(cng_inst); - LOG(LS_ERROR) << "WebRtcCng_UpdateSid produced " << internal_error_code_; - return kInternalError; - } return kOK; } @@ -63,28 +54,28 @@ int ComfortNoise::Generate(size_t requested_length, } size_t number_of_samples = requested_length; - int16_t new_period = 0; + bool new_period = false; if (first_call_) { // Generate noise and overlap slightly with old data. number_of_samples = requested_length + overlap_length_; - new_period = 1; + new_period = true; } output->AssertSize(number_of_samples); // Get the decoder from the database. - AudioDecoder* cng_decoder = decoder_database_->GetActiveCngDecoder(); + ComfortNoiseDecoder* cng_decoder = decoder_database_->GetActiveCngDecoder(); if (!cng_decoder) { LOG(LS_ERROR) << "Unknwown payload type"; return kUnknownPayloadType; } - CNG_dec_inst* cng_inst = cng_decoder->CngDecoderInstance(); // The expression &(*output)[0][0] is a pointer to the first element in // the first channel. - if (WebRtcCng_Generate(cng_inst, &(*output)[0][0], number_of_samples, - new_period) < 0) { + if (!cng_decoder->Generate( + rtc::ArrayView(&(*output)[0][0], number_of_samples), + new_period)) { // Error returned. output->Zeros(requested_length); - internal_error_code_ = WebRtcCng_GetErrorCodeDec(cng_inst); - LOG(LS_ERROR) << "WebRtcCng_Generate produced " << internal_error_code_; + LOG(LS_ERROR) << + "ComfortNoiseDecoder::Genererate failed to generate comfort noise"; return kInternalError; } diff --git a/webrtc/modules/audio_coding/neteq/comfort_noise.h b/webrtc/modules/audio_coding/neteq/comfort_noise.h index 1fc2258663..f877bf63ef 100644 --- a/webrtc/modules/audio_coding/neteq/comfort_noise.h +++ b/webrtc/modules/audio_coding/neteq/comfort_noise.h @@ -38,8 +38,7 @@ class ComfortNoise { first_call_(true), overlap_length_(5 * fs_hz_ / 8000), decoder_database_(decoder_database), - sync_buffer_(sync_buffer), - internal_error_code_(0) { + sync_buffer_(sync_buffer) { } // Resets the state. Should be called before each new comfort noise period. diff --git a/webrtc/modules/audio_coding/neteq/decoder_database.cc b/webrtc/modules/audio_coding/neteq/decoder_database.cc index d501f3e588..c163bbdbf3 100644 --- a/webrtc/modules/audio_coding/neteq/decoder_database.cc +++ b/webrtc/modules/audio_coding/neteq/decoder_database.cc @@ -20,9 +20,10 @@ namespace webrtc { DecoderDatabase::DecoderDatabase() - : active_decoder_(-1), active_cng_decoder_(-1) {} + : active_decoder_type_(-1), active_cng_decoder_type_(-1) { +} -DecoderDatabase::~DecoderDatabase() {} +DecoderDatabase::~DecoderDatabase() = default; DecoderDatabase::DecoderInfo::DecoderInfo(NetEqDecoder ct, const std::string& nm, @@ -54,8 +55,8 @@ int DecoderDatabase::Size() const { return static_cast(decoders_.size()); } void DecoderDatabase::Reset() { decoders_.clear(); - active_decoder_ = -1; - active_cng_decoder_ = -1; + active_decoder_type_ = -1; + active_cng_decoder_type_ = -1; } int DecoderDatabase::RegisterPayload(uint8_t rtp_payload_type, @@ -110,11 +111,11 @@ int DecoderDatabase::Remove(uint8_t rtp_payload_type) { // No decoder with that |rtp_payload_type|. return kDecoderNotFound; } - if (active_decoder_ == rtp_payload_type) { - active_decoder_ = -1; // No active decoder. + if (active_decoder_type_ == rtp_payload_type) { + active_decoder_type_ = -1; // No active decoder. } - if (active_cng_decoder_ == rtp_payload_type) { - active_cng_decoder_ = -1; // No active CNG decoder. + if (active_cng_decoder_type_ == rtp_payload_type) { + active_cng_decoder_type_ = -1; // No active CNG decoder. } return kOK; } @@ -143,7 +144,8 @@ uint8_t DecoderDatabase::GetRtpPayloadType( } AudioDecoder* DecoderDatabase::GetDecoder(uint8_t rtp_payload_type) { - if (IsDtmf(rtp_payload_type) || IsRed(rtp_payload_type)) { + if (IsDtmf(rtp_payload_type) || IsRed(rtp_payload_type) || + IsComfortNoise(rtp_payload_type)) { // These are not real decoders. return NULL; } @@ -193,14 +195,15 @@ int DecoderDatabase::SetActiveDecoder(uint8_t rtp_payload_type, // Decoder not found. return kDecoderNotFound; } + RTC_CHECK(!IsComfortNoise(rtp_payload_type)); assert(new_decoder); *new_decoder = false; - if (active_decoder_ < 0) { + if (active_decoder_type_ < 0) { // This is the first active decoder. *new_decoder = true; - } else if (active_decoder_ != rtp_payload_type) { + } else if (active_decoder_type_ != rtp_payload_type) { // Moving from one active decoder to another. Delete the first one. - DecoderMap::iterator it = decoders_.find(active_decoder_); + DecoderMap::iterator it = decoders_.find(active_decoder_type_); if (it == decoders_.end()) { // Decoder not found. This should not be possible. assert(false); @@ -209,16 +212,16 @@ int DecoderDatabase::SetActiveDecoder(uint8_t rtp_payload_type, it->second.DropDecoder(); *new_decoder = true; } - active_decoder_ = rtp_payload_type; + active_decoder_type_ = rtp_payload_type; return kOK; } AudioDecoder* DecoderDatabase::GetActiveDecoder() { - if (active_decoder_ < 0) { + if (active_decoder_type_ < 0) { // No active decoder. return NULL; } - return GetDecoder(active_decoder_); + return GetDecoder(active_decoder_type_); } int DecoderDatabase::SetActiveCngDecoder(uint8_t rtp_payload_type) { @@ -228,26 +231,32 @@ int DecoderDatabase::SetActiveCngDecoder(uint8_t rtp_payload_type) { // Decoder not found. return kDecoderNotFound; } - if (active_cng_decoder_ >= 0 && active_cng_decoder_ != rtp_payload_type) { + if (active_cng_decoder_type_ >= 0 && + active_cng_decoder_type_ != rtp_payload_type) { // Moving from one active CNG decoder to another. Delete the first one. - DecoderMap::iterator it = decoders_.find(active_cng_decoder_); + DecoderMap::iterator it = decoders_.find(active_cng_decoder_type_); if (it == decoders_.end()) { // Decoder not found. This should not be possible. assert(false); return kDecoderNotFound; } - it->second.DropDecoder(); + // The CNG decoder should never be provided externally. + RTC_CHECK(!it->second.external_decoder); + active_cng_decoder_.reset(); } - active_cng_decoder_ = rtp_payload_type; + active_cng_decoder_type_ = rtp_payload_type; return kOK; } -AudioDecoder* DecoderDatabase::GetActiveCngDecoder() { - if (active_cng_decoder_ < 0) { +ComfortNoiseDecoder* DecoderDatabase::GetActiveCngDecoder() { + if (active_cng_decoder_type_ < 0) { // No active CNG decoder. return NULL; } - return GetDecoder(active_cng_decoder_); + if (!active_cng_decoder_) { + active_cng_decoder_.reset(new ComfortNoiseDecoder); + } + return active_cng_decoder_.get(); } int DecoderDatabase::CheckPayloadTypes(const PacketList& packet_list) const { diff --git a/webrtc/modules/audio_coding/neteq/decoder_database.h b/webrtc/modules/audio_coding/neteq/decoder_database.h index 37dbb5362c..8dbec22509 100644 --- a/webrtc/modules/audio_coding/neteq/decoder_database.h +++ b/webrtc/modules/audio_coding/neteq/decoder_database.h @@ -16,6 +16,7 @@ #include "webrtc/base/constructormagic.h" #include "webrtc/common_types.h" // NULL +#include "webrtc/modules/audio_coding/codecs/cng/webrtc_cng.h" #include "webrtc/modules/audio_coding/neteq/audio_decoder_impl.h" #include "webrtc/modules/audio_coding/neteq/packet.h" #include "webrtc/typedefs.h" @@ -142,7 +143,7 @@ class DecoderDatabase { // Returns the current active comfort noise decoder, or NULL if no active // comfort noise decoder exists. - virtual AudioDecoder* GetActiveCngDecoder(); + virtual ComfortNoiseDecoder* GetActiveCngDecoder(); // Returns kOK if all packets in |packet_list| carry payload types that are // registered in the database. Otherwise, returns kDecoderNotFound. @@ -152,8 +153,9 @@ class DecoderDatabase { typedef std::map DecoderMap; DecoderMap decoders_; - int active_decoder_; - int active_cng_decoder_; + int active_decoder_type_; + int active_cng_decoder_type_; + std::unique_ptr active_cng_decoder_; RTC_DISALLOW_COPY_AND_ASSIGN(DecoderDatabase); }; diff --git a/webrtc/modules/audio_coding/neteq/decoder_database_unittest.cc b/webrtc/modules/audio_coding/neteq/decoder_database_unittest.cc index 929f844f63..0da4d640f3 100644 --- a/webrtc/modules/audio_coding/neteq/decoder_database_unittest.cc +++ b/webrtc/modules/audio_coding/neteq/decoder_database_unittest.cc @@ -231,8 +231,8 @@ TEST(DecoderDatabase, IF_ISAC(ActiveDecoders)) { // Set active CNG codec. EXPECT_EQ(DecoderDatabase::kOK, db.SetActiveCngDecoder(13)); - decoder = db.GetActiveCngDecoder(); - ASSERT_FALSE(decoder == NULL); // Should get a decoder here. + ComfortNoiseDecoder* cng = db.GetActiveCngDecoder(); + ASSERT_FALSE(cng == NULL); // Should get a decoder here. // Remove the active CNG decoder, and verify that the active becomes NULL. EXPECT_EQ(DecoderDatabase::kOK, db.Remove(13)); diff --git a/webrtc/modules/audio_coding/neteq/mock/mock_decoder_database.h b/webrtc/modules/audio_coding/neteq/mock/mock_decoder_database.h index 1b4a3c9da5..d04181d55b 100644 --- a/webrtc/modules/audio_coding/neteq/mock/mock_decoder_database.h +++ b/webrtc/modules/audio_coding/neteq/mock/mock_decoder_database.h @@ -59,7 +59,7 @@ class MockDecoderDatabase : public DecoderDatabase { MOCK_METHOD1(SetActiveCngDecoder, int(uint8_t rtp_payload_type)); MOCK_METHOD0(GetActiveCngDecoder, - AudioDecoder*()); + ComfortNoiseDecoder*()); MOCK_CONST_METHOD1(CheckPayloadTypes, int(const PacketList& packet_list)); }; diff --git a/webrtc/modules/audio_coding/neteq/neteq_impl.cc b/webrtc/modules/audio_coding/neteq/neteq_impl.cc index db37e716d6..b6ec655af3 100644 --- a/webrtc/modules/audio_coding/neteq/neteq_impl.cc +++ b/webrtc/modules/audio_coding/neteq/neteq_impl.cc @@ -14,6 +14,7 @@ #include // memset #include +#include #include "webrtc/base/checks.h" #include "webrtc/base/logging.h" @@ -664,13 +665,15 @@ int NetEqImpl::InsertPacketInternal(const WebRtcRTPHeader& rtp_header, } } - // Update bandwidth estimate, if the packet is not sync-packet. - if (!packet_list.empty() && !packet_list.front()->sync_packet) { + // Update bandwidth estimate, if the packet is not sync-packet nor comfort + // noise. + if (!packet_list.empty() && !packet_list.front()->sync_packet && + !decoder_database_->IsComfortNoise(main_header.payloadType)) { // The list can be empty here if we got nothing but DTMF payloads. AudioDecoder* decoder = decoder_database_->GetDecoder(main_header.payloadType); assert(decoder); // Should always get a valid object, since we have - // already checked that the payload types are known. + // already checked that the payload types are known. decoder->IncomingPacket(packet_list.front()->payload, packet_list.front()->payload_length, packet_list.front()->header.sequenceNumber, @@ -728,14 +731,18 @@ int NetEqImpl::InsertPacketInternal(const WebRtcRTPHeader& rtp_header, const RTPHeader* rtp_header = packet_buffer_->NextRtpHeader(); assert(rtp_header); int payload_type = rtp_header->payloadType; - AudioDecoder* decoder = decoder_database_->GetDecoder(payload_type); - assert(decoder); // Payloads are already checked to be valid. + size_t channels = 1; + if (!decoder_database_->IsComfortNoise(payload_type)) { + AudioDecoder* decoder = decoder_database_->GetDecoder(payload_type); + assert(decoder); // Payloads are already checked to be valid. + channels = decoder->Channels(); + } const DecoderDatabase::DecoderInfo* decoder_info = decoder_database_->GetDecoderInfo(payload_type); assert(decoder_info); if (decoder_info->fs_hz != fs_hz_ || - decoder->Channels() != algorithm_buffer_->Channels()) { - SetSampleRateAndChannels(decoder_info->fs_hz, decoder->Channels()); + channels != algorithm_buffer_->Channels()) { + SetSampleRateAndChannels(decoder_info->fs_hz, channels); } if (nack_enabled_) { RTC_DCHECK(nack_); @@ -1297,7 +1304,7 @@ int NetEqImpl::Decode(PacketList* packet_list, Operations* operation, decoder->Reset(); // Reset comfort noise decoder. - AudioDecoder* cng_decoder = decoder_database_->GetActiveCngDecoder(); + ComfortNoiseDecoder* cng_decoder = decoder_database_->GetActiveCngDecoder(); if (cng_decoder) cng_decoder->Reset(); @@ -1955,7 +1962,7 @@ int NetEqImpl::ExtractPackets(size_t required_samples, stats_.SecondaryDecodedSamples(packet_duration); } } - } else { + } else if (!decoder_database_->IsComfortNoise(packet->header.payloadType)) { LOG(LS_WARNING) << "Unknown payload type " << static_cast(packet->header.payloadType); assert(false); @@ -2023,7 +2030,7 @@ void NetEqImpl::SetSampleRateAndChannels(int fs_hz, size_t channels) { mute_factor_array_[i] = 16384; // 1.0 in Q14. } - AudioDecoder* cng_decoder = decoder_database_->GetActiveCngDecoder(); + ComfortNoiseDecoder* cng_decoder = decoder_database_->GetActiveCngDecoder(); if (cng_decoder) cng_decoder->Reset(); diff --git a/webrtc/modules/audio_coding/neteq/normal.cc b/webrtc/modules/audio_coding/neteq/normal.cc index 9bddfe7765..4400afb3b0 100644 --- a/webrtc/modules/audio_coding/neteq/normal.cc +++ b/webrtc/modules/audio_coding/neteq/normal.cc @@ -16,7 +16,6 @@ #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h" #include "webrtc/modules/audio_coding/codecs/audio_decoder.h" -#include "webrtc/modules/audio_coding/codecs/cng/webrtc_cng.h" #include "webrtc/modules/audio_coding/neteq/audio_multi_vector.h" #include "webrtc/modules/audio_coding/neteq/background_noise.h" #include "webrtc/modules/audio_coding/neteq/decoder_database.h" @@ -149,12 +148,11 @@ int Normal::Process(const int16_t* input, int16_t cng_output[kCngLength]; // Reset mute factor and start up fresh. external_mute_factor_array[0] = 16384; - AudioDecoder* cng_decoder = decoder_database_->GetActiveCngDecoder(); + ComfortNoiseDecoder* cng_decoder = decoder_database_->GetActiveCngDecoder(); if (cng_decoder) { // Generate long enough for 32kHz. - if (WebRtcCng_Generate(cng_decoder->CngDecoderInstance(), cng_output, - kCngLength, 0) < 0) { + if (!cng_decoder->Generate(cng_output, 0)) { // Error returned; set return vector to all zeros. memset(cng_output, 0, sizeof(cng_output)); } diff --git a/webrtc/modules/audio_coding/neteq/payload_splitter.cc b/webrtc/modules/audio_coding/neteq/payload_splitter.cc index 8530718134..542863970b 100644 --- a/webrtc/modules/audio_coding/neteq/payload_splitter.cc +++ b/webrtc/modules/audio_coding/neteq/payload_splitter.cc @@ -143,8 +143,9 @@ int PayloadSplitter::SplitFec(PacketList* packet_list, // Not an FEC packet. AudioDecoder* decoder = decoder_database->GetDecoder(payload_type); - // decoder should not return NULL. - assert(decoder != NULL); + // decoder should not return NULL, except for comfort noise payloads which + // are handled separately. + assert(decoder != NULL || decoder_database->IsComfortNoise(payload_type)); if (!decoder || !decoder->PacketHasFec(packet->payload, packet->payload_length)) { ++it; diff --git a/webrtc/modules/audio_coding/neteq/test/RTPencode.cc b/webrtc/modules/audio_coding/neteq/test/RTPencode.cc index 45586ee111..149f282658 100644 --- a/webrtc/modules/audio_coding/neteq/test/RTPencode.cc +++ b/webrtc/modules/audio_coding/neteq/test/RTPencode.cc @@ -265,7 +265,7 @@ GSMFR_encinst_t* GSMFRenc_inst[2]; #endif #if (defined(CODEC_CNGCODEC8) || defined(CODEC_CNGCODEC16) || \ defined(CODEC_CNGCODEC32) || defined(CODEC_CNGCODEC48)) -CNG_enc_inst* CNGenc_inst[2]; +webrtc::ComfortNoiseEncoder *CNG_encoder[2]; #endif #ifdef CODEC_SPEEX_8 SPEEX_encinst_t* SPEEX8enc_inst[2]; @@ -928,18 +928,8 @@ int NetEQTest_init_coders(webrtc::NetEqDecoder coder, #if (defined(CODEC_CNGCODEC8) || defined(CODEC_CNGCODEC16) || \ defined(CODEC_CNGCODEC32) || defined(CODEC_CNGCODEC48)) - ok = WebRtcCng_CreateEnc(&CNGenc_inst[k]); - if (ok != 0) { - printf("Error: Couldn't allocate memory for CNG encoding instance\n"); - exit(0); - } if (sampfreq <= 16000) { - ok = WebRtcCng_InitEnc(CNGenc_inst[k], sampfreq, 200, 5); - if (ok == -1) { - printf("Error: Initialization of CNG struct failed. Error code %d\n", - WebRtcCng_GetErrorCodeEnc(CNGenc_inst[k])); - exit(0); - } + CNG_encoder[k] = new webrtc::ComfortNoiseEncoder(sampfreq, 200, 5); } #endif @@ -1461,7 +1451,8 @@ int NetEQTest_free_coders(webrtc::NetEqDecoder coder, size_t numChannels) { WebRtcVad_Free(VAD_inst[k]); #if (defined(CODEC_CNGCODEC8) || defined(CODEC_CNGCODEC16) || \ defined(CODEC_CNGCODEC32) || defined(CODEC_CNGCODEC48)) - WebRtcCng_FreeEnc(CNGenc_inst[k]); + delete CNG_encoder[k]; + CNG_encoder[k] = nullptr; #endif switch (coder) { @@ -1600,7 +1591,7 @@ size_t NetEQTest_encode(webrtc::NetEqDecoder coder, size_t numChannels) { size_t cdlen = 0; int16_t* tempdata; - static int first_cng = 1; + static bool first_cng = true; size_t tempLen; *vad = 1; @@ -1608,9 +1599,9 @@ size_t NetEQTest_encode(webrtc::NetEqDecoder coder, if (useVAD) { *vad = 0; - size_t sampleRate_10 = static_cast(10 * sampleRate / 1000); - size_t sampleRate_20 = static_cast(20 * sampleRate / 1000); - size_t sampleRate_30 = static_cast(30 * sampleRate / 1000); + const size_t sampleRate_10 = static_cast(10 * sampleRate / 1000); + const size_t sampleRate_20 = static_cast(20 * sampleRate / 1000); + const size_t sampleRate_30 = static_cast(30 * sampleRate / 1000); for (size_t k = 0; k < numChannels; k++) { tempLen = frameLen; tempdata = &indata[k * frameLen]; @@ -1642,16 +1633,22 @@ size_t NetEQTest_encode(webrtc::NetEqDecoder coder, if (!*vad) { // all channels are silent + rtc::Buffer workaround; cdlen = 0; for (size_t k = 0; k < numChannels; k++) { - WebRtcCng_Encode(CNGenc_inst[k], &indata[k * frameLen], - (frameLen <= 640 ? frameLen : 640) /* max 640 */, - encoded, &tempLen, first_cng); + workaround.Clear(); + tempLen = CNG_encoder[k]->Encode( + rtc::ArrayView( + &indata[k * frameLen], + (frameLen <= 640 ? frameLen : 640) /* max 640 */), + first_cng, + &workaround); + memcpy(encoded, workaround.data(), tempLen); encoded += tempLen; cdlen += tempLen; } *vad = 0; - first_cng = 0; + first_cng = false; return (cdlen); } } @@ -1734,7 +1731,7 @@ size_t NetEQTest_encode(webrtc::NetEqDecoder coder, } // end for - first_cng = 1; + first_cng = true; return (totalLen); }