From a7d8387bdd7f7c8901292ad57eb531aa82cef817 Mon Sep 17 00:00:00 2001 From: "tina.legrand@webrtc.org" Date: Thu, 18 Oct 2012 10:00:52 +0000 Subject: [PATCH] Opus integration First patch = delivery from August 22, 2012. Review URL: https://webrtc-codereview.appspot.com/756005 git-svn-id: http://webrtc.googlecode.com/svn/trunk@2945 4adac7df-926f-26a2-2b94-8c16560cd09d --- DEPS | 3 + src/build/common.gypi | 4 + src/engine_configurations.h | 18 +- .../audio_coding/codecs/cng/webrtc_cng.c | 2 +- .../codecs/opus/interface/opus_interface.h | 123 ++++ .../audio_coding/codecs/opus/opus.gypi | 44 ++ .../audio_coding/codecs/opus/opus_interface.c | 181 ++++++ .../audio_coding/main/source/acm_cng.cc | 3 +- .../audio_coding/main/source/acm_cng.h | 2 +- .../main/source/acm_codec_database.cc | 62 +- .../main/source/acm_codec_database.h | 8 + .../main/source/acm_common_defs.h | 5 +- .../main/source/acm_generic_codec.cc | 26 +- .../main/source/acm_generic_codec.h | 1 + .../audio_coding/main/source/acm_opus.cc | 562 ++++++------------ .../audio_coding/main/source/acm_opus.h | 72 +-- .../main/source/audio_coding_module.gypi | 3 + .../main/source/audio_coding_module_impl.cc | 16 + .../main/source/audio_coding_module_impl.h | 1 + .../audio_coding/main/test/TestAllCodecs.cc | 22 + .../audio_coding/main/test/TestVADDTX.cc | 15 + src/modules/audio_coding/neteq/codec_db.c | 8 +- .../neteq/interface/webrtc_neteq.h | 1 + .../interface/webrtc_neteq_help_macros.h | 12 +- .../audio_coding/neteq/neteq_defines.h | 28 +- .../audio_coding/neteq/packet_buffer.c | 5 + src/modules/audio_coding/neteq/recin.c | 28 +- src/modules/audio_coding/neteq/recout.c | 30 +- src/modules/audio_coding/neteq/signal_mcu.c | 8 +- .../interface/audio_conference_mixer.h | 1 + .../source/audio_conference_mixer_impl.cc | 6 + src/modules/modules.gyp | 1 + .../rtp_rtcp/source/rtp_receiver_audio.cc | 14 +- .../rtp_rtcp/source/rtp_receiver_audio.h | 1 + .../rtp_rtcp/source/rtp_sender_audio.cc | 14 + .../rtp_rtcp/source/rtp_sender_audio.h | 1 + src/voice_engine/channel.cc | 92 +-- src/voice_engine/transmit_mixer.cc | 8 +- third_party/opus/opus.gyp | 184 ++++++ tools/create_supplement_gypi.py | 1 + 40 files changed, 1098 insertions(+), 518 deletions(-) create mode 100644 src/modules/audio_coding/codecs/opus/interface/opus_interface.h create mode 100644 src/modules/audio_coding/codecs/opus/opus.gypi create mode 100644 src/modules/audio_coding/codecs/opus/opus_interface.c create mode 100644 third_party/opus/opus.gyp diff --git a/DEPS b/DEPS index 46c3d2caa3..224e94bd71 100644 --- a/DEPS +++ b/DEPS @@ -57,6 +57,9 @@ deps = { "third_party/libyuv": (Var("googlecode_url") % "libyuv") + "/trunk@389", + "third_party/opus/source": + "http://git.xiph.org/opus.git@v1.0.1", + "third_party/protobuf": Var("chromium_trunk") + "/src/third_party/protobuf@" + Var("chromium_revision"), diff --git a/src/build/common.gypi b/src/build/common.gypi index 6d02f202ba..d57b265aea 100644 --- a/src/build/common.gypi +++ b/src/build/common.gypi @@ -85,6 +85,10 @@ # Disable the use of protocol buffers in production code. 'enable_protobuf%': 0, + + # Disable Mozilla internal Opus version + 'build_with_mozilla%': 0, + }, { # Settings for the standalone (not-in-Chromium) build. 'include_pulse_audio%': 1, 'include_internal_audio_device%': 1, diff --git a/src/engine_configurations.h b/src/engine_configurations.h index 35dec151f0..553aed4def 100644 --- a/src/engine_configurations.h +++ b/src/engine_configurations.h @@ -27,19 +27,27 @@ // [Voice] Codec settings // ---------------------------------------------------------------------------- +// iSAC is not included in the Mozilla build, but in all other builds. +#ifndef WEBRTC_MOZILLA_BUILD #ifdef WEBRTC_ARCH_ARM -#define WEBRTC_CODEC_ISACFX // fix-point iSAC implementation +#define WEBRTC_CODEC_ISACFX // Fix-point iSAC implementation. #else -#define WEBRTC_CODEC_ISAC // floating-point iSAC implementation (default) -#endif +#define WEBRTC_CODEC_ISAC // Floating-point iSAC implementation (default). +#endif // WEBRTC_ARCH_ARM +#endif // !WEBRTC_MOZILLA_BUILD + +// AVT is included in all builds, along with G.711, NetEQ and CNG +// (which are mandatory and don't have any defines). #define WEBRTC_CODEC_AVT -#ifndef WEBRTC_CHROMIUM_BUILD +// iLBC, G.722, PCM16B and Redundancy coding are excluded from Chromium and +// Mozilla builds. +#if !defined(WEBRTC_CHROMIUM_BUILD) && !defined(WEBRTC_MOZILLA_BUILD) #define WEBRTC_CODEC_ILBC #define WEBRTC_CODEC_G722 #define WEBRTC_CODEC_PCM16 #define WEBRTC_CODEC_RED -#endif +#endif // !WEBRTC_CHROMIUM_BUILD && !WEBRTC_MOZILLA_BUILD // ---------------------------------------------------------------------------- // [Video] Codec settings diff --git a/src/modules/audio_coding/codecs/cng/webrtc_cng.c b/src/modules/audio_coding/codecs/cng/webrtc_cng.c index 7cc6cb9e58..28bfaae807 100644 --- a/src/modules/audio_coding/codecs/cng/webrtc_cng.c +++ b/src/modules/audio_coding/codecs/cng/webrtc_cng.c @@ -36,7 +36,7 @@ typedef struct WebRtcCngDecInst_t_ { typedef struct WebRtcCngEncInst_t_ { int16_t enc_nrOfCoefs; - int16_t enc_sampfreq; + uint16_t enc_sampfreq; int16_t enc_interval; int16_t enc_msSinceSID; int32_t enc_Energy; diff --git a/src/modules/audio_coding/codecs/opus/interface/opus_interface.h b/src/modules/audio_coding/codecs/opus/interface/opus_interface.h new file mode 100644 index 0000000000..dcfd87f3f6 --- /dev/null +++ b/src/modules/audio_coding/codecs/opus/interface/opus_interface.h @@ -0,0 +1,123 @@ +/* + * 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. + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_OPUS_INTERFACE_OPUS_INTERFACE_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_OPUS_INTERFACE_OPUS_INTERFACE_H_ + +#include "typedefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Opaque wrapper types for the codec state. +typedef struct WebRtcOpusEncInst OpusEncInst; +typedef struct WebRtcOpusDecInst OpusDecInst; + +int16_t WebRtcOpus_EncoderCreate(OpusEncInst** inst, int32_t channels); +int16_t WebRtcOpus_EncoderFree(OpusEncInst* inst); + +/**************************************************************************** + * WebRtcOpus_Encode(...) + * + * This function encodes audio as a series of Opus frames and inserts + * it into a packet. Input buffer can be any length. + * + * Input: + * - inst : Encoder context + * - audio_in : Input speech data buffer + * - samples : Samples in audio_in + * - length_encoded_buffer : Output buffer size + * + * Output: + * - encoded : Output compressed data buffer + * + * Return value : >0 - Length (in bytes) of coded data + * -1 - Error + */ +int16_t WebRtcOpus_Encode(OpusEncInst* inst, int16_t* audio_in, int16_t samples, + int16_t length_encoded_buffer, uint8_t* encoded); + +/**************************************************************************** + * WebRtcOpus_SetBitRate(...) + * + * This function adjusts the target bitrate of the encoder. + * + * Input: + * - inst : Encoder context + * - rate : New target bitrate + * + * Return value : 0 - Success + * -1 - Error + */ +int16_t WebRtcOpus_SetBitRate(OpusEncInst* inst, int32_t rate); + +int16_t WebRtcOpus_DecoderCreate(OpusDecInst** inst, int channels); +int16_t WebRtcOpus_DecoderFree(OpusDecInst* inst); + +/**************************************************************************** + * WebRtcOpus_DecoderInit(...) + * + * This function resets state of the decoder. + * + * Input: + * - inst : Decoder context + * + * Return value : 0 - Success + * -1 - Error + */ +int16_t WebRtcOpus_DecoderInit(OpusDecInst* inst); + +/**************************************************************************** + * WebRtcOpus_Decode(...) + * + * This function decodes an Opus packet into one or more audio frames at the + * ACM interface's sampling rate (32 kHz). + * + * Input: + * - inst : Decoder context + * - encoded : Encoded data + * - encoded_bytes : Bytes in encoded vector + * + * Output: + * - decoded : The decoded vector + * - audio_type : 1 normal, 2 CNG (for Opus it should + * always return 1 since we're not using Opus's + * built-in DTX/CNG scheme) + * + * Return value : >0 - Samples in decoded vector + * -1 - Error + */ +int16_t WebRtcOpus_Decode(OpusDecInst* inst, int16_t* encoded, + int16_t encoded_bytes, int16_t* decoded, + int16_t* audio_type); + +/**************************************************************************** + * WebRtcOpus_DecodePlc(...) + * + * This function precesses PLC for opus frame(s). + * Input: + * - inst : Decoder context + * - number_of_lost_frames : Number of PLC frames to produce + * + * Output: + * - decoded : The decoded vector + * + * Return value : >0 - number of samples in decoded PLC vector + * -1 - Error + */ +int16_t WebRtcOpus_DecodePlc(OpusDecInst* inst, int16_t* decoded, + int16_t number_of_lost_frames); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_OPUS_INTERFACE_OPUS_INTERFACE_H_ diff --git a/src/modules/audio_coding/codecs/opus/opus.gypi b/src/modules/audio_coding/codecs/opus/opus.gypi new file mode 100644 index 0000000000..809068c235 --- /dev/null +++ b/src/modules/audio_coding/codecs/opus/opus.gypi @@ -0,0 +1,44 @@ +# 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. + +{ + 'targets': [ + { + 'target_name': 'webrtc_opus', + 'type': 'static_library', + 'conditions': [ + ['build_with_mozilla==1', { + # Mozilla provides its own build of the opus library. + 'include_dirs': [ + '$(DIST)/include/opus', + ] + }, { + 'dependencies': [ + '<(DEPTH)/third_party/opus/opus.gyp:opus' + ], + 'include_dirs': [ + '<(webrtc_root)/../third_party/opus/source/include', + ], + }], + ], + 'direct_dependent_settings': { + 'conditions': [ + ['build_with_mozilla==1', { + 'include_dirs': [ + '$(DIST)/include/opus', + ], + }], + ], + }, + 'sources': [ + 'interface/opus_interface.h', + 'opus_interface.c', + ], + }, + ], +} diff --git a/src/modules/audio_coding/codecs/opus/opus_interface.c b/src/modules/audio_coding/codecs/opus/opus_interface.c new file mode 100644 index 0000000000..f61ecc5a97 --- /dev/null +++ b/src/modules/audio_coding/codecs/opus/opus_interface.c @@ -0,0 +1,181 @@ +/* + * 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 "modules/audio_coding/codecs/opus/interface/opus_interface.h" + +#include +#include + +#include "opus.h" + +#include "common_audio/signal_processing/resample_by_2_internal.h" +#include "common_audio/signal_processing/include/signal_processing_library.h" + +enum { + /* We always produce 20ms frames. */ + kWebRtcOpusMaxEncodeFrameSizeMs = 20, + + /* The format allows up to 120ms frames. Since we + * don't control the other side, we must allow + * for packets that large. NetEq is currently + * limited to 60 ms on the receive side. + */ + kWebRtcOpusMaxDecodeFrameSizeMs = 120, + + /* Sample count is 48 kHz * samples per frame. */ + kWebRtcOpusMaxFrameSize = 48 * kWebRtcOpusMaxDecodeFrameSizeMs, +}; + +struct WebRtcOpusEncInst { + OpusEncoder* encoder; +}; + +int16_t WebRtcOpus_EncoderCreate(OpusEncInst** inst, int32_t channels) { + OpusEncInst* state; + state = (OpusEncInst*) calloc(1, sizeof(OpusEncInst)); + if (state) { + int error; + state->encoder = opus_encoder_create(48000, channels, OPUS_APPLICATION_VOIP, + &error); + if (error == OPUS_OK || state->encoder != NULL ) { + *inst = state; + return 0; + } + free(state); + } + return -1; +} + +int16_t WebRtcOpus_EncoderFree(OpusEncInst* inst) { + opus_encoder_destroy(inst->encoder); + return 0; +} + +int16_t WebRtcOpus_Encode(OpusEncInst* inst, int16_t* audio_in, int16_t samples, + int16_t length_encoded_buffer, uint8_t* encoded) { + opus_int16* audio = (opus_int16*) audio_in; + unsigned char* coded = encoded; + int res; + + if (samples > 48 * kWebRtcOpusMaxEncodeFrameSizeMs) { + return -1; + } + + res = opus_encode(inst->encoder, audio, samples, coded, + length_encoded_buffer); + + if (res > 0) { + return res; + } + return -1; +} + +int16_t WebRtcOpus_SetBitRate(OpusEncInst* inst, int32_t rate) { + return opus_encoder_ctl(inst->encoder, OPUS_SET_BITRATE(rate)); +} + +struct WebRtcOpusDecInst { + int16_t state_48_32[8]; + OpusDecoder* decoder; +}; + +int16_t WebRtcOpus_DecoderCreate(OpusDecInst** inst, int channels) { + OpusDecInst* state; + state = (OpusDecInst*) calloc(1, sizeof(OpusDecInst)); + if (state) { + int error; + // Always create a 48000 Hz Opus decoder. + state->decoder = opus_decoder_create(48000, channels, &error); + if (error == OPUS_OK && state->decoder != NULL ) { + *inst = state; + return 0; + } + free(state); + state = NULL; + } + return -1; +} + +int16_t WebRtcOpus_DecoderFree(OpusDecInst* inst) { + opus_decoder_destroy(inst->decoder); + free(inst); + return 0; +} + +int16_t WebRtcOpus_DecoderInit(OpusDecInst* inst) { + int error = opus_decoder_ctl(inst->decoder, OPUS_RESET_STATE); + if (error == OPUS_OK) { + memset(inst->state_48_32, 0, sizeof(inst->state_48_32)); + return 0; + } + return -1; +} + +static int DecodeNative(OpusDecInst* inst, int16_t* encoded, + int16_t encoded_bytes, int16_t* decoded, + int16_t* audio_type) { + unsigned char* coded = (unsigned char*) encoded; + opus_int16* audio = (opus_int16*) decoded; + + int res = opus_decode(inst->decoder, coded, encoded_bytes, audio, + kWebRtcOpusMaxFrameSize, 0); + /* TODO(tlegrand): set to DTX for zero-length packets? */ + *audio_type = 0; + + if (res > 0) { + return res; + } + return -1; +} + +int16_t WebRtcOpus_Decode(OpusDecInst* inst, int16_t* encoded, + int16_t encoded_bytes, int16_t* decoded, + int16_t* audio_type) { + /* Enough for 120 ms (the largest Opus packet size) of mono audio at 48 kHz + * and resampler overlap. This will need to be enlarged for stereo decoding. + */ + int16_t buffer16[kWebRtcOpusMaxFrameSize]; + int32_t buffer32[kWebRtcOpusMaxFrameSize + 7]; + int decoded_samples; + int blocks; + int16_t output_samples; + int i; + + /* Decode to a temporary buffer. */ + decoded_samples = DecodeNative(inst, encoded, encoded_bytes, buffer16, + audio_type); + if (decoded_samples < 0) { + return -1; + } + /* Resample from 48 kHz to 32 kHz. */ + for (i = 0; i < 7; i++) { + buffer32[i] = inst->state_48_32[i]; + inst->state_48_32[i] = buffer16[decoded_samples -7 + i]; + } + for (i = 0; i < decoded_samples; i++) { + buffer32[7 + i] = buffer16[i]; + } + /* Resampling 3 samples to 2. Function divides the input in |blocks| number + * of 3-sample groups, and output is |blocks| number of 2-sample groups. */ + blocks = decoded_samples / 3; + WebRtcSpl_Resample48khzTo32khz(buffer32, buffer32, blocks); + output_samples = (int16_t) (blocks * 2); + WebRtcSpl_VectorBitShiftW32ToW16(decoded, output_samples, buffer32, 15); + + return output_samples; +} + +int16_t WebRtcOpus_DecodePlc(OpusDecInst* inst, int16_t* decoded, + int16_t number_of_lost_frames) { + /* TODO(tlegrand): We can pass NULL to opus_decode to activate packet + * loss concealment, but I don't know how many samples + * number_of_lost_frames corresponds to. */ + return -1; +} diff --git a/src/modules/audio_coding/main/source/acm_cng.cc b/src/modules/audio_coding/main/source/acm_cng.cc index 2393346a7c..4edfc05c8e 100644 --- a/src/modules/audio_coding/main/source/acm_cng.cc +++ b/src/modules/audio_coding/main/source/acm_cng.cc @@ -81,7 +81,8 @@ WebRtc_Word32 ACMCNG::CodecDef(WebRtcNetEQ_CodecDef& codecDef, // Then return the structure back to NetEQ to add the codec to it's // database. - if (_sampFreqHz == 8000 || _sampFreqHz == 16000 || _sampFreqHz == 32000) { + if (_sampFreqHz == 8000 || _sampFreqHz == 16000 || _sampFreqHz == 32000 || + _sampFreqHz == 48000) { SET_CODEC_PAR((codecDef), kDecoderCNG, codecInst.pltype, _decoderInstPtr, _sampFreqHz); SET_CNG_FUNCTIONS((codecDef)); diff --git a/src/modules/audio_coding/main/source/acm_cng.h b/src/modules/audio_coding/main/source/acm_cng.h index 6276c44d21..d204d02c68 100644 --- a/src/modules/audio_coding/main/source/acm_cng.h +++ b/src/modules/audio_coding/main/source/acm_cng.h @@ -62,7 +62,7 @@ protected: WebRtcCngEncInst* _encoderInstPtr; WebRtcCngDecInst* _decoderInstPtr; - WebRtc_Word16 _sampFreqHz; + WebRtc_UWord16 _sampFreqHz; }; } // namespace webrtc diff --git a/src/modules/audio_coding/main/source/acm_codec_database.cc b/src/modules/audio_coding/main/source/acm_codec_database.cc index b7821944fc..2e3db197ef 100644 --- a/src/modules/audio_coding/main/source/acm_codec_database.cc +++ b/src/modules/audio_coding/main/source/acm_codec_database.cc @@ -86,6 +86,10 @@ #include "acm_gsmfr.h" #include "gsmfr_interface.h" #endif +#ifdef WEBRTC_CODEC_OPUS + #include "acm_opus.h" + #include "opus_interface.h" +#endif #ifdef WEBRTC_CODEC_SPEEX #include "acm_speex.h" #include "speex_interface.h" @@ -103,22 +107,20 @@ namespace webrtc { // codecs. Note! There are a limited number of payload types. If more codecs // are defined they will receive reserved fixed payload types (values 69-95). const int kDynamicPayloadtypes[ACMCodecDB::kMaxNumCodecs] = { - 105, 107, 108, 109, 111, 112, 113, 114, 115, 116, 117, 120, - 121, 122, 123, 124, 125, 126, 101, 100, 97, 96, 95, 94, - 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, - 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, - 69, + 105, 107, 108, 109, 111, 112, 113, 114, 115, 116, 117, 121, + 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, + 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, + 68, 67 }; // Creates database with all supported codecs at compile time. // Each entry needs the following parameters in the given order: // payload type, name, sampling frequency, packet size in samples, // number of channels, and default rate. -#if (defined(WEBRTC_CODEC_PCM16) || \ - defined(WEBRTC_CODEC_AMR) || defined(WEBRTC_CODEC_AMRWB) || \ - defined(WEBRTC_CODEC_CELT) || defined(WEBRTC_CODEC_G729_1) || \ - defined(WEBRTC_CODEC_SPEEX) || defined(WEBRTC_CODEC_G722_1) || \ - defined(WEBRTC_CODEC_G722_1C)) +#if (defined(WEBRTC_CODEC_AMR) || defined(WEBRTC_CODEC_AMRWB) \ + || defined(WEBRTC_CODEC_CELT) || defined(WEBRTC_CODEC_G722_1) \ + || defined(WEBRTC_CODEC_G722_1C) || defined(WEBRTC_CODEC_G729_1) \ + || defined(WEBRTC_CODEC_PCM16) || defined(WEBRTC_CODEC_SPEEX)) static int count_database = 0; #endif @@ -186,14 +188,19 @@ const CodecInst ACMCodecDB::database_[] = { #ifdef WEBRTC_CODEC_GSMFR {3, "GSM", 8000, 160, 1, 13200}, #endif +#ifdef WEBRTC_CODEC_OPUS + // Opus supports 48, 24, 16, 12, 8 kHz. + {120, "opus", 48000, 960, 1, 32000}, +#endif #ifdef WEBRTC_CODEC_SPEEX {kDynamicPayloadtypes[count_database++], "speex", 8000, 160, 1, 11000}, {kDynamicPayloadtypes[count_database++], "speex", 16000, 320, 1, 22000}, #endif - // Comfort noise for three different sampling frequencies. + // Comfort noise for four different sampling frequencies. {13, "CN", 8000, 240, 1, 0}, {98, "CN", 16000, 480, 1, 0}, {99, "CN", 32000, 960, 1, 0}, + {100, "CN", 48000, 1440, 1, 0}, #ifdef WEBRTC_CODEC_AVT {106, "telephone-event", 8000, 240, 1, 0}, #endif @@ -272,6 +279,11 @@ const ACMCodecDB::CodecSettings ACMCodecDB::codec_settings_[] = { #ifdef WEBRTC_CODEC_GSMFR {3, {160, 320, 480}, 160, 1}, #endif +#ifdef WEBRTC_CODEC_OPUS + // Opus supports frames shorter than 10ms, + // but it doesn't help us to use them. + {1, {960}, 0, 2}, +#endif #ifdef WEBRTC_CODEC_SPEEX {3, {160, 320, 480}, 0, 1}, {3, {320, 640, 960}, 0, 1}, @@ -280,6 +292,7 @@ const ACMCodecDB::CodecSettings ACMCodecDB::codec_settings_[] = { {1, {240}, 240, 1}, {1, {480}, 480, 1}, {1, {960}, 960, 1}, + {1, {1440}, 1440, 1}, #ifdef WEBRTC_CODEC_AVT {1, {240}, 240, 1}, #endif @@ -355,6 +368,9 @@ const WebRtcNetEQDecoder ACMCodecDB::neteq_decoders_[] = { #ifdef WEBRTC_CODEC_GSMFR kDecoderGSMFR, #endif +#ifdef WEBRTC_CODEC_OPUS + kDecoderOpus, +#endif #ifdef WEBRTC_CODEC_SPEEX kDecoderSPEEX_8, kDecoderSPEEX_16, @@ -363,6 +379,7 @@ const WebRtcNetEQDecoder ACMCodecDB::neteq_decoders_[] = { kDecoderCNG, kDecoderCNG, kDecoderCNG, + kDecoderCNG, #ifdef WEBRTC_CODEC_AVT kDecoderAVT, #endif @@ -509,6 +526,9 @@ int ACMCodecDB::CodecNumber(const CodecInst* codec_inst, int* mirror_id) { } else if (STR_CASE_CMP("g7291", codec_inst->plname) == 0) { return IsG7291RateValid(codec_inst->rate) ? codec_id : kInvalidRate; + } else if (STR_CASE_CMP("opus", codec_inst->plname) == 0) { + return IsOpusRateValid(codec_inst->rate) + ? codec_id : kInvalidRate; } else if (STR_CASE_CMP("speex", codec_inst->plname) == 0) { return IsSpeexRateValid(codec_inst->rate) ? codec_id : kInvalidRate; @@ -719,6 +739,10 @@ ACMGenericCodec* ACMCodecDB::CreateCodecInstance(const CodecInst* codec_inst) { codec_id = kCNSWB; break; } + case 48000: { + codec_id = kCNFB; + break; + } default: { return NULL; } @@ -731,6 +755,10 @@ ACMGenericCodec* ACMCodecDB::CreateCodecInstance(const CodecInst* codec_inst) { } else if (!STR_CASE_CMP(codec_inst->plname, "G7291")) { #ifdef WEBRTC_CODEC_G729_1 return new ACMG729_1(kG729_1); +#endif + } else if (!STR_CASE_CMP(codec_inst->plname, "opus")) { +#ifdef WEBRTC_CODEC_OPUS + return new ACMOpus(kOpus); #endif } else if (!STR_CASE_CMP(codec_inst->plname, "speex")) { #ifdef WEBRTC_CODEC_SPEEX @@ -766,6 +794,10 @@ ACMGenericCodec* ACMCodecDB::CreateCodecInstance(const CodecInst* codec_inst) { codec_id = kCNSWB; break; } + case 48000: { + codec_id = kCNFB; + break; + } default: { return NULL; } @@ -928,6 +960,14 @@ bool ACMCodecDB::IsSpeexRateValid(int rate) { } } +// Checks if the bitrate is valid for Opus. +bool ACMCodecDB::IsOpusRateValid(int rate) { + if ((rate < 6000) || (rate > 510000)) { + return false; + } + return true; +} + // Checks if the bitrate is valid for Celt. bool ACMCodecDB::IsCeltRateValid(int rate) { if ((rate >= 48000) && (rate <= 128000)) { diff --git a/src/modules/audio_coding/main/source/acm_codec_database.h b/src/modules/audio_coding/main/source/acm_codec_database.h index 0fe3a5ee95..8baf24e94c 100644 --- a/src/modules/audio_coding/main/source/acm_codec_database.h +++ b/src/modules/audio_coding/main/source/acm_codec_database.h @@ -91,6 +91,9 @@ class ACMCodecDB { #ifdef WEBRTC_CODEC_GSMFR , kGSMFR #endif +#ifdef WEBRTC_CODEC_OPUS + , kOpus +#endif #ifdef WEBRTC_CODEC_SPEEX , kSPEEX8 , kSPEEX16 @@ -98,6 +101,7 @@ class ACMCodecDB { , kCNNB , kCNWB , kCNSWB + , kCNFB #ifdef WEBRTC_CODEC_AVT , kAVT #endif @@ -170,6 +174,9 @@ class ACMCodecDB { enum {kSPEEX8 = -1}; enum {kSPEEX16 = -1}; #endif +#ifndef WEBRTC_CODEC_OPUS + enum {kOpus = -1}; +#endif #ifndef WEBRTC_CODEC_AVT enum {kAVT = -1}; #endif @@ -298,6 +305,7 @@ class ACMCodecDB { static bool IsAMRwbRateValid(int rate); static bool IsG7291RateValid(int rate); static bool IsSpeexRateValid(int rate); + static bool IsOpusRateValid(int rate); static bool IsCeltRateValid(int rate); // Check if the payload type is valid, meaning that it is in the valid range diff --git a/src/modules/audio_coding/main/source/acm_common_defs.h b/src/modules/audio_coding/main/source/acm_common_defs.h index fd8dbd6ef7..cdff1c1c7d 100644 --- a/src/modules/audio_coding/main/source/acm_common_defs.h +++ b/src/modules/audio_coding/main/source/acm_common_defs.h @@ -63,14 +63,15 @@ const int kIsacPacSize960 = 960; // kPassiveDTXNB : Passive audio frame coded by narrow-band CN. // kPassiveDTXWB : Passive audio frame coded by wide-band CN. // kPassiveDTXSWB : Passive audio frame coded by super-wide-band CN. -// +// kPassiveDTXFB : Passive audio frame coded by full-band CN. enum WebRtcACMEncodingType { kNoEncoding, kActiveNormalEncoded, kPassiveNormalEncoded, kPassiveDTXNB, kPassiveDTXWB, - kPassiveDTXSWB + kPassiveDTXSWB, + kPassiveDTXFB }; // A structure which contains codec parameters. For instance, used when diff --git a/src/modules/audio_coding/main/source/acm_generic_codec.cc b/src/modules/audio_coding/main/source/acm_generic_codec.cc index f9a6a3aa07..f98f260f31 100644 --- a/src/modules/audio_coding/main/source/acm_generic_codec.cc +++ b/src/modules/audio_coding/main/source/acm_generic_codec.cc @@ -58,6 +58,7 @@ ACMGenericCodec::ACMGenericCodec() _numLPCParams(kNewCNGNumPLCParams), _sentCNPrevious(false), _isMaster(true), + _prev_frame_cng(0), _netEqDecodeLock(NULL), _codecWrapperLock(*RWLockWrapper::CreateRWLock()), _lastEncodedTimestamp(0), @@ -294,6 +295,8 @@ ACMGenericCodec::EncodeSafe( *encodingType = kPassiveDTXWB; } else if (sampFreqHz == 32000) { *encodingType = kPassiveDTXSWB; + } else if (sampFreqHz == 48000) { + *encodingType = kPassiveDTXFB; } else { status = -1; WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID, @@ -1169,7 +1172,7 @@ ACMGenericCodec::EnableDTX() } WebRtc_UWord16 freqHz; EncoderSampFreq(freqHz); - if(WebRtcCng_InitEnc(_ptrDTXInst, (WebRtc_Word16)freqHz, + if(WebRtcCng_InitEnc(_ptrDTXInst, freqHz, ACM_SID_INTERVAL_MSEC, _numLPCParams) < 0) { // Couldn't initialize, has to return -1, and free the memory @@ -1313,6 +1316,7 @@ ACMGenericCodec::ProcessFrameVADDTX( *samplesProcessed = 0; return 0; } + WebRtc_UWord16 freqHz; EncoderSampFreq(freqHz); @@ -1321,8 +1325,8 @@ ACMGenericCodec::ProcessFrameVADDTX( WebRtc_Word32 frameLenMsec = (((WebRtc_Word32)_frameLenSmpl * 1000) / freqHz); WebRtc_Word16 status; - // Vector for storing maximum 30 ms of mono audio at 32 kHz - WebRtc_Word16 audio[960]; + // Vector for storing maximum 30 ms of mono audio at 48 kHz. + WebRtc_Word16 audio[1440]; // Calculate number of VAD-blocks to process, and number of samples in each block. int noSamplesToProcess[2]; @@ -1378,25 +1382,33 @@ ACMGenericCodec::ProcessFrameVADDTX( *bitStreamLenByte = 0; for(WebRtc_Word16 n = 0; n < num10MsecFrames; n++) { - // This block is (passive) && (vad enabled) - status = WebRtcCng_Encode(_ptrDTXInst, &audio[n*samplesIn10Msec], - samplesIn10Msec, bitStream, &bitStreamLen, 0); + // This block is (passive) && (vad enabled). If first CNG after + // speech, force SID by setting last parameter to "1". + status = WebRtcCng_Encode(_ptrDTXInst, + &audio[n*samplesIn10Msec], + samplesIn10Msec, bitStream, + &bitStreamLen, !_prev_frame_cng); if (status < 0) { return -1; } + // Update previous frame was CNG. + _prev_frame_cng = 1; + *samplesProcessed += samplesIn10Msec*_noChannels; // bitStreamLen will only be > 0 once per 100 ms *bitStreamLenByte += bitStreamLen; } - // Check if all samples got processed by the DTX if(*samplesProcessed != noSamplesToProcess[i]*_noChannels) { // Set to zero since something went wrong. Shouldn't happen. *samplesProcessed = 0; } + } else { + // Update previous frame was not CNG. + _prev_frame_cng = 0; } if(*samplesProcessed > 0) diff --git a/src/modules/audio_coding/main/source/acm_generic_codec.h b/src/modules/audio_coding/main/source/acm_generic_codec.h index c138ed91a3..29c882c004 100644 --- a/src/modules/audio_coding/main/source/acm_generic_codec.h +++ b/src/modules/audio_coding/main/source/acm_generic_codec.h @@ -1310,6 +1310,7 @@ protected: WebRtc_UWord8 _numLPCParams; bool _sentCNPrevious; bool _isMaster; + int16_t _prev_frame_cng; WebRtcACMCodecParams _encoderParams; WebRtcACMCodecParams _decoderParams; diff --git a/src/modules/audio_coding/main/source/acm_opus.cc b/src/modules/audio_coding/main/source/acm_opus.cc index 87bdd8bcb6..034e57dbe1 100644 --- a/src/modules/audio_coding/main/source/acm_opus.cc +++ b/src/modules/audio_coding/main/source/acm_opus.cc @@ -8,442 +8,256 @@ * be found in the AUTHORS file in the root of the source tree. */ +#include "acm_opus.h" + +#include "acm_codec_database.h" #include "acm_common_defs.h" #include "acm_neteq.h" -#include "acm_opus.h" #include "trace.h" #include "webrtc_neteq.h" #include "webrtc_neteq_help_macros.h" #ifdef WEBRTC_CODEC_OPUS - // NOTE! Opus is not included in the open-source package. Modify this file or your codec - // API to match the function call and name of used Opus API file. - // #include "opus_interface.h" +#include "opus_interface.h" #endif -namespace webrtc -{ +namespace webrtc { #ifndef WEBRTC_CODEC_OPUS -ACMOPUS::ACMOPUS(WebRtc_Word16 /* codecID */) +ACMOpus::ACMOpus(int16_t /* codecID */) : _encoderInstPtr(NULL), _decoderInstPtr(NULL), - _mySampFreq(0), - _myRate(0), - _opusMode(0), - _flagVBR(0) { + _sampleFreq(0), + _bitrate(0) { return; } - -ACMOPUS::~ACMOPUS() -{ - return; +ACMOpus::~ACMOpus() { + return; } - -WebRtc_Word16 -ACMOPUS::InternalEncode( - WebRtc_UWord8* /* bitStream */, - WebRtc_Word16* /* bitStreamLenByte */) -{ - return -1; +int16_t ACMOpus::InternalEncode(uint8_t* /* bitStream */, + int16_t* /* bitStreamLenByte */) { + return -1; } - -WebRtc_Word16 -ACMOPUS::DecodeSafe( - WebRtc_UWord8* /* bitStream */, - WebRtc_Word16 /* bitStreamLenByte */, - WebRtc_Word16* /* audio */, - WebRtc_Word16* /* audioSamples */, - WebRtc_Word8* /* speechType */) -{ - return -1; +int16_t ACMOpus::DecodeSafe(uint8_t* /* bitStream */, + int16_t /* bitStreamLenByte */, + int16_t* /* audio */, + int16_t* /* audioSamples */, + int8_t* /* speechType */) { + return -1; } - -WebRtc_Word16 -ACMOPUS::InternalInitEncoder( - WebRtcACMCodecParams* /* codecParams */) -{ - return -1; +int16_t ACMOpus::InternalInitEncoder(WebRtcACMCodecParams* /* codecParams */) { + return -1; } - -WebRtc_Word16 -ACMOPUS::InternalInitDecoder( - WebRtcACMCodecParams* /* codecParams */) -{ - return -1; +int16_t ACMOpus::InternalInitDecoder(WebRtcACMCodecParams* /* codecParams */) { + return -1; } - -WebRtc_Word32 -ACMOPUS::CodecDef( - WebRtcNetEQ_CodecDef& /* codecDef */, - const CodecInst& /* codecInst */) -{ - return -1; +int32_t ACMOpus::CodecDef(WebRtcNetEQ_CodecDef& /* codecDef */, + const CodecInst& /* codecInst */) { + return -1; } - -ACMGenericCodec* -ACMOPUS::CreateInstance(void) -{ - return NULL; +ACMGenericCodec* ACMOpus::CreateInstance(void) { + return NULL; } - -WebRtc_Word16 -ACMOPUS::InternalCreateEncoder() -{ - return -1; +int16_t ACMOpus::InternalCreateEncoder() { + return -1; } - -void -ACMOPUS::DestructEncoderSafe() -{ - return; +void ACMOpus::DestructEncoderSafe() { + return; } - -WebRtc_Word16 -ACMOPUS::InternalCreateDecoder() -{ - return -1; +int16_t ACMOpus::InternalCreateDecoder() { + return -1; } - -void -ACMOPUS::DestructDecoderSafe() -{ - return; +void ACMOpus::DestructDecoderSafe() { + return; } - -void -ACMOPUS::InternalDestructEncoderInst( - void* /* ptrInst */) -{ - return; +void ACMOpus::InternalDestructEncoderInst(void* /* ptrInst */) { + return; } -WebRtc_Word16 -ACMOPUS::SetBitRateSafe( - const WebRtc_Word32 /*rate*/ ) -{ - return -1; +int16_t ACMOpus::SetBitRateSafe(const int32_t /*rate*/) { + return -1; } -#else //===================== Actual Implementation ======================= +#else //===================== Actual Implementation ======================= -// Remove when integrating a real Opus wrapper -extern WebRtc_Word16 WebRtcOpus_CreateEnc(OPUS_inst_t_** inst, WebRtc_Word16 samplFreq); -extern WebRtc_Word16 WebRtcOpus_CreateDec(OPUS_inst_t_** inst, WebRtc_Word16 samplFreq); -extern WebRtc_Word16 WebRtcOpus_FreeEnc(OPUS_inst_t_* inst); -extern WebRtc_Word16 WebRtcOpus_FreeDec(OPUS_inst_t_* inst); -extern WebRtc_Word16 WebRtcOpus_Encode(OPUS_inst_t_* encInst, - WebRtc_Word16* input, - WebRtc_Word16* output, - WebRtc_Word16 len, - WebRtc_Word16 byteLen); -extern WebRtc_Word16 WebRtcOpus_EncoderInit(OPUS_inst_t_* encInst, - WebRtc_Word16 samplFreq, - WebRtc_Word16 mode, - WebRtc_Word16 vbrFlag); -extern WebRtc_Word16 WebRtcOpus_Decode(OPUS_inst_t_* decInst); -extern WebRtc_Word16 WebRtcOpus_DecodeBwe(OPUS_inst_t_* decInst, WebRtc_Word16* input); -extern WebRtc_Word16 WebRtcOpus_DecodePlc(OPUS_inst_t_* decInst); -extern WebRtc_Word16 WebRtcOpus_DecoderInit(OPUS_inst_t_* decInst); - -ACMOPUS::ACMOPUS(WebRtc_Word16 codecID) +ACMOpus::ACMOpus(int16_t codecID) : _encoderInstPtr(NULL), _decoderInstPtr(NULL), - _mySampFreq(48000), // Default sampling frequency. - _myRate(50000), // Default rate. - _opusMode(1), // Default mode is the hybrid mode. - _flagVBR(0) { // Default VBR off. + _sampleFreq(32000), // Default sampling frequency. + _bitrate(20000) { // Default bit-rate. _codecID = codecID; - - // Current implementation doesn't have DTX. That might change. + // Opus has internal DTX, but we dont use it for now. _hasInternalDTX = false; + if (_codecID != ACMCodecDB::kOpus) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID, + "Wrong codec id for Opus."); + _sampleFreq = -1; + _bitrate = -1; + } return; } -ACMOPUS::~ACMOPUS() -{ - if(_encoderInstPtr != NULL) - { - WebRtcOpus_FreeEnc(_encoderInstPtr); - _encoderInstPtr = NULL; - } - if(_decoderInstPtr != NULL) - { - WebRtcOpus_FreeDec(_decoderInstPtr); - _decoderInstPtr = NULL; - } - return; +ACMOpus::~ACMOpus() { + if (_encoderInstPtr != NULL) { + WebRtcOpus_EncoderFree(_encoderInstPtr); + _encoderInstPtr = NULL; + } + if (_decoderInstPtr != NULL) { + WebRtcOpus_DecoderFree(_decoderInstPtr); + _decoderInstPtr = NULL; + } + return; } - -WebRtc_Word16 -ACMOPUS::InternalEncode( - WebRtc_UWord8* bitStream, - WebRtc_Word16* bitStreamLenByte) -{ - WebRtc_Word16 noEncodedSamples = 0; - WebRtc_Word16 tmpLenByte = 0; +int16_t ACMOpus::InternalEncode(uint8_t* bitStream, int16_t* bitStreamLenByte) { + // Call Encoder. + *bitStreamLenByte = WebRtcOpus_Encode(_encoderInstPtr, + &_inAudio[_inAudioIxRead], + _frameLenSmpl, + MAX_PAYLOAD_SIZE_BYTE, + bitStream); + // Check for error reported from encoder. + if (*bitStreamLenByte < 0) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID, + "InternalEncode: Encode error for Opus"); *bitStreamLenByte = 0; + return -1; + } - WebRtc_Word16 byteLengthFrame = 0; + // Increment the read index. This tells the caller how far + // we have gone forward in reading the audio buffer. + _inAudioIxRead += _frameLenSmpl; - // Derive what byte-length is requested - byteLengthFrame = _myRate*_frameLenSmpl/(8*_mySampFreq); - - // Call Encoder - *bitStreamLenByte = WebRtcOpus_Encode(_encoderInstPtr, &_inAudio[_inAudioIxRead], - (WebRtc_Word16*)bitStream, _frameLenSmpl, byteLengthFrame); - - // increment the read index this tell the caller that how far - // we have gone forward in reading the audio buffer - _inAudioIxRead += _frameLenSmpl; - - // sanity check - if(*bitStreamLenByte < 0) - { - // error has happened - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID, - "InternalEncode: Encode error for Opus"); - *bitStreamLenByte = 0; - return -1; - } - - return *bitStreamLenByte; + return *bitStreamLenByte; } +int16_t ACMOpus::DecodeSafe(uint8_t* bitStream, int16_t bitStreamLenByte, + int16_t* audio, int16_t* audioSamples, + int8_t* speechType) { + return 0; +} +int16_t ACMOpus::InternalInitEncoder(WebRtcACMCodecParams* codecParams) { + int16_t ret; + if (_encoderInstPtr != NULL) { + WebRtcOpus_EncoderFree(_encoderInstPtr); + _encoderInstPtr = NULL; + } + ret = WebRtcOpus_EncoderCreate(&_encoderInstPtr, + codecParams->codecInstant.channels); + if (ret < 0) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID, + "Encoder creation failed for Opus"); + return ret; + } + ret = WebRtcOpus_SetBitRate(_encoderInstPtr, codecParams->codecInstant.rate); + if (ret < 0) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID, + "Setting initial bitrate failed for Opus"); + return ret; + } + return 0; +} -WebRtc_Word16 -ACMOPUS::DecodeSafe( - WebRtc_UWord8* /* bitStream */, - WebRtc_Word16 /* bitStreamLenByte */, - WebRtc_Word16* /* audio */, - WebRtc_Word16* /* audioSamples */, - WebRtc_Word8* /* speechType */) -{ +int16_t ACMOpus::InternalInitDecoder(WebRtcACMCodecParams* codecParams) { + if (_decoderInstPtr != NULL) { + WebRtcOpus_DecoderFree(_decoderInstPtr); + _decoderInstPtr = NULL; + } + if (WebRtcOpus_DecoderCreate(&_decoderInstPtr, + codecParams->codecInstant.channels) < 0) { + return -1; + } + return WebRtcOpus_DecoderInit(_decoderInstPtr); +} + +int32_t ACMOpus::CodecDef(WebRtcNetEQ_CodecDef& codecDef, + const CodecInst& codecInst) { + if (!_decoderInitialized) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID, + "CodeDef: Decoder uninitialized for Opus"); + return -1; + } + + // Fill up the structure by calling "SET_CODEC_PAR" & "SET_OPUS_FUNCTION." + // Then call NetEQ to add the codec to its database. + // TODO(tlegrand): Decoder is registered in NetEQ as a 32 kHz decoder, which + // is true until we have a full 48 kHz system, and remove the downsampling + // in the Opus decoder wrapper. + SET_CODEC_PAR((codecDef), kDecoderOpus, codecInst.pltype, _decoderInstPtr, + 32000); + SET_OPUS_FUNCTIONS((codecDef)); + return 0; +} + +ACMGenericCodec* ACMOpus::CreateInstance(void) { + return NULL; +} + +int16_t ACMOpus::InternalCreateEncoder() { + // Real encoder will be created in InternalInitEncoder. + return 0; +} + +void ACMOpus::DestructEncoderSafe() { + if (_encoderInstPtr) { + WebRtcOpus_EncoderFree(_encoderInstPtr); + _encoderInstPtr = NULL; + } +} + +int16_t ACMOpus::InternalCreateDecoder() { + // Real decoder will be created in InternalInitDecoder + return 0; +} + +void ACMOpus::DestructDecoderSafe() { + _decoderInitialized = false; + if (_decoderInstPtr) { + WebRtcOpus_DecoderFree(_decoderInstPtr); + _decoderInstPtr = NULL; + } +} + +void ACMOpus::InternalDestructEncoderInst(void* ptrInst) { + if (ptrInst != NULL) { + WebRtcOpus_EncoderFree((OpusEncInst*) ptrInst); + } + return; +} + +int16_t ACMOpus::SetBitRateSafe(const int32_t rate) { + if (rate < 6000 || rate > 510000) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID, + "SetBitRateSafe: Invalid rate Opus"); + return -1; + } + + _bitrate = rate; + + // Ask the encoder for the new rate. + if (WebRtcOpus_SetBitRate(_encoderInstPtr, _bitrate) >= 0) { + _encoderParams.codecInstant.rate = _bitrate; return 0; + } + + return -1; } +#endif // WEBRTC_CODEC_OPUS -WebRtc_Word16 -ACMOPUS::InternalInitEncoder( - WebRtcACMCodecParams* codecParams) -{ - //set the bit rate and initialize - _myRate = codecParams->codecInstant.rate; - return SetBitRateSafe( (WebRtc_UWord32)_myRate); -} - - -WebRtc_Word16 -ACMOPUS::InternalInitDecoder( - WebRtcACMCodecParams* /* codecParams */) -{ - if (WebRtcOpus_DecoderInit(_decoderInstPtr) < 0) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID, - "InternalInitDecoder: init decoder failed for Opus"); - return -1; - } - return 0; -} - - -WebRtc_Word32 -ACMOPUS::CodecDef( - WebRtcNetEQ_CodecDef& codecDef, - const CodecInst& codecInst) -{ - if (!_decoderInitialized) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID, - "CodeDef: Decoder uninitialized for Opus"); - return -1; - } - - // Fill up the structure by calling - // "SET_CODEC_PAR" & "SET_G729_FUNCTION." - // Then call NetEQ to add the codec to it's - // database. - SET_CODEC_PAR((codecDef), kDecoderOpus, codecInst.pltype, - _decoderInstPtr, 16000); - SET_OPUS_FUNCTIONS((codecDef)); - return 0; -} - - -ACMGenericCodec* -ACMOPUS::CreateInstance(void) -{ - return NULL; -} - - -WebRtc_Word16 -ACMOPUS::InternalCreateEncoder() -{ - if (WebRtcOpus_CreateEnc(&_encoderInstPtr, _mySampFreq) < 0) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID, - "InternalCreateEncoder: create encoder failed for Opus"); - return -1; - } - return 0; -} - - -void -ACMOPUS::DestructEncoderSafe() -{ - _encoderExist = false; - _encoderInitialized = false; - if(_encoderInstPtr != NULL) - { - WebRtcOpus_FreeEnc(_encoderInstPtr); - _encoderInstPtr = NULL; - } -} - - -WebRtc_Word16 -ACMOPUS::InternalCreateDecoder() -{ - if (WebRtcOpus_CreateDec(&_decoderInstPtr, _mySampFreq) < 0) - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID, - "InternalCreateDecoder: create decoder failed for Opus"); - return -1; - } - return 0; -} - - -void -ACMOPUS::DestructDecoderSafe() -{ - _decoderExist = false; - _decoderInitialized = false; - if(_decoderInstPtr != NULL) - { - WebRtcOpus_FreeDec(_decoderInstPtr); - _decoderInstPtr = NULL; - } -} - - -void -ACMOPUS::InternalDestructEncoderInst( - void* ptrInst) -{ - if(ptrInst != NULL) - { - WebRtcOpus_FreeEnc((OPUS_inst_t*)ptrInst); - } - return; -} - -WebRtc_Word16 -ACMOPUS::SetBitRateSafe( - const WebRtc_Word32 rate) -{ - //allowed rates: {8000, 12000, 14000, 16000, 18000, 20000, - // 22000, 24000, 26000, 28000, 30000, 32000}; - switch(rate) - { - case 8000: - { - _myRate = 8000; - break; - } - case 12000: - { - _myRate = 12000; - break; - } - case 14000: - { - _myRate = 14000; - break; - } - case 16000: - { - _myRate = 16000; - break; - } - case 18000: - { - _myRate = 18000; - break; - } - case 20000: - { - _myRate = 20000; - break; - } - case 22000: - { - _myRate = 22000; - break; - } - case 24000: - { - _myRate = 24000; - break; - } - case 26000: - { - _myRate = 26000; - break; - } - case 28000: - { - _myRate = 28000; - break; - } - case 30000: - { - _myRate = 30000; - break; - } - case 32000: - { - _myRate = 32000; - break; - } - default: - { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID, - "SetBitRateSafe: Invalid rate Opus"); - return -1; - } - } - - // Re-init with new rate - if (WebRtcOpus_EncoderInit(_encoderInstPtr, _mySampFreq, _opusMode, _flagVBR) >= 0) - { - _encoderParams.codecInstant.rate = _myRate; - return 0; - } - else - { - return -1; - } -} - -#endif - -} // namespace webrtc +} // namespace webrtc diff --git a/src/modules/audio_coding/main/source/acm_opus.h b/src/modules/audio_coding/main/source/acm_opus.h index c6832fa8bd..d8baa302fd 100644 --- a/src/modules/audio_coding/main/source/acm_opus.h +++ b/src/modules/audio_coding/main/source/acm_opus.h @@ -12,68 +12,48 @@ #define WEBRTC_MODULES_AUDIO_CODING_MAIN_SOURCE_ACM_OPUS_H_ #include "acm_generic_codec.h" +#include "opus_interface.h" +#include "resampler.h" -// forward declaration -struct OPUS_inst_t_; -struct OPUS_inst_t_; +namespace webrtc { -namespace webrtc -{ +class ACMOpus : public ACMGenericCodec { + public: + ACMOpus(int16_t codecID); + ~ACMOpus(); -class ACMOPUS: public ACMGenericCodec -{ -public: - ACMOPUS(WebRtc_Word16 codecID); - ~ACMOPUS(); - // for FEC - ACMGenericCodec* CreateInstance(void); + ACMGenericCodec* CreateInstance(void); - WebRtc_Word16 InternalEncode( - WebRtc_UWord8* bitstream, - WebRtc_Word16* bitStreamLenByte); + int16_t InternalEncode(uint8_t* bitstream, int16_t* bitStreamLenByte); - WebRtc_Word16 InternalInitEncoder( - WebRtcACMCodecParams *codecParams); + int16_t InternalInitEncoder(WebRtcACMCodecParams *codecParams); - WebRtc_Word16 InternalInitDecoder( - WebRtcACMCodecParams *codecParams); + int16_t InternalInitDecoder(WebRtcACMCodecParams *codecParams); -protected: - WebRtc_Word16 DecodeSafe( - WebRtc_UWord8* bitStream, - WebRtc_Word16 bitStreamLenByte, - WebRtc_Word16* audio, - WebRtc_Word16* audioSamples, - WebRtc_Word8* speechType); + protected: + int16_t DecodeSafe(uint8_t* bitStream, int16_t bitStreamLenByte, + int16_t* audio, int16_t* audioSamples, int8_t* speechType); - WebRtc_Word32 CodecDef( - WebRtcNetEQ_CodecDef& codecDef, - const CodecInst& codecInst); + int32_t CodecDef(WebRtcNetEQ_CodecDef& codecDef, const CodecInst& codecInst); - void DestructEncoderSafe(); + void DestructEncoderSafe(); - void DestructDecoderSafe(); + void DestructDecoderSafe(); - WebRtc_Word16 InternalCreateEncoder(); + int16_t InternalCreateEncoder(); - WebRtc_Word16 InternalCreateDecoder(); + int16_t InternalCreateDecoder(); - void InternalDestructEncoderInst( - void* ptrInst); + void InternalDestructEncoderInst(void* ptrInst); - WebRtc_Word16 SetBitRateSafe( - const WebRtc_Word32 rate); - - OPUS_inst_t_* _encoderInstPtr; - OPUS_inst_t_* _decoderInstPtr; - - WebRtc_UWord16 _mySampFreq; - WebRtc_UWord16 _myRate; - WebRtc_Word16 _opusMode; - WebRtc_Word16 _flagVBR; + int16_t SetBitRateSafe(const int32_t rate); + OpusEncInst* _encoderInstPtr; + OpusDecInst* _decoderInstPtr; + uint16_t _sampleFreq; + uint16_t _bitrate; }; -} // namespace webrtc +} // namespace webrtc #endif // WEBRTC_MODULES_AUDIO_CODING_MAIN_SOURCE_ACM_OPUS_H_ diff --git a/src/modules/audio_coding/main/source/audio_coding_module.gypi b/src/modules/audio_coding/main/source/audio_coding_module.gypi index bc9ea7d946..f62ba360ea 100644 --- a/src/modules/audio_coding/main/source/audio_coding_module.gypi +++ b/src/modules/audio_coding/main/source/audio_coding_module.gypi @@ -15,6 +15,7 @@ 'iLBC', 'iSAC', 'iSACFix', + 'webrtc_opus', 'PCM16B', 'NetEq', '<(webrtc_root)/common_audio/common_audio.gyp:resampler', @@ -37,11 +38,13 @@ 'include_dirs': [ '../interface', '../../../interface', + '../../codecs/opus/interface', ], 'direct_dependent_settings': { 'include_dirs': [ '../interface', '../../../interface', + '../../codecs/opus/interface', ], }, 'sources': [ diff --git a/src/modules/audio_coding/main/source/audio_coding_module_impl.cc b/src/modules/audio_coding/main/source/audio_coding_module_impl.cc index c1341b9e12..0a399ba3ff 100644 --- a/src/modules/audio_coding/main/source/audio_coding_module_impl.cc +++ b/src/modules/audio_coding/main/source/audio_coding_module_impl.cc @@ -45,6 +45,7 @@ AudioCodingModuleImpl::AudioCodingModuleImpl(const WebRtc_Word32 id) _cng_nb_pltype(255), _cng_wb_pltype(255), _cng_swb_pltype(255), + _cng_fb_pltype(255), _red_pltype(255), _vadEnabled(false), _dtxEnabled(false), @@ -112,6 +113,8 @@ AudioCodingModuleImpl::AudioCodingModuleImpl(const WebRtc_Word32 id) _cng_wb_pltype = static_cast(ACMCodecDB::database_[i].pltype); } else if (ACMCodecDB::database_[i].plfreq == 32000) { _cng_swb_pltype = static_cast(ACMCodecDB::database_[i].pltype); + } else if (ACMCodecDB::database_[i].plfreq == 48000) { + _cng_fb_pltype = static_cast(ACMCodecDB::database_[i].pltype); } } } @@ -320,6 +323,12 @@ WebRtc_Word32 AudioCodingModuleImpl::Process() { _isFirstRED = true; break; } + case kPassiveDTXFB: { + current_payload_type = _cng_fb_pltype; + frame_type = kAudioFrameCN; + _isFirstRED = true; + break; + } } has_data_to_send = true; _previousPayloadType = current_payload_type; @@ -612,6 +621,10 @@ WebRtc_Word32 AudioCodingModuleImpl::RegisterSendCodec( _cng_swb_pltype = static_cast(send_codec.pltype); break; } + case 48000: { + _cng_fb_pltype = static_cast(send_codec.pltype); + break; + } default: { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, "RegisterSendCodec() failed, invalid frequency for CNG " @@ -1254,6 +1267,9 @@ WebRtc_Word32 AudioCodingModuleImpl::ReceiveFrequency() const { CriticalSectionScoped lock(_acmCritSect); if (DecoderParamByPlType(_lastRecvAudioCodecPlType, codec_params) < 0) { return _netEq.CurrentSampFreqHz(); + } else if (codec_params.codecInstant.plfreq == 48000) { + // TODO(tlegrand): Remove this option when we have full 48 kHz support. + return 32000; } else { return codec_params.codecInstant.plfreq; } diff --git a/src/modules/audio_coding/main/source/audio_coding_module_impl.h b/src/modules/audio_coding/main/source/audio_coding_module_impl.h index 145faf6f3d..0e7f2f37f7 100644 --- a/src/modules/audio_coding/main/source/audio_coding_module_impl.h +++ b/src/modules/audio_coding/main/source/audio_coding_module_impl.h @@ -279,6 +279,7 @@ class AudioCodingModuleImpl : public AudioCodingModule { uint8_t _cng_nb_pltype; uint8_t _cng_wb_pltype; uint8_t _cng_swb_pltype; + uint8_t _cng_fb_pltype; uint8_t _red_pltype; bool _vadEnabled; bool _dtxEnabled; diff --git a/src/modules/audio_coding/main/test/TestAllCodecs.cc b/src/modules/audio_coding/main/test/TestAllCodecs.cc index b3123901dd..89a9829a81 100644 --- a/src/modules/audio_coding/main/test/TestAllCodecs.cc +++ b/src/modules/audio_coding/main/test/TestAllCodecs.cc @@ -613,6 +613,28 @@ void TestAllCodecs::Perform() { RegisterSendCodec('A', codec_celt, 32000, 128000, 640, 0); Run(channel_a_to_b_); outfile_b_.Close(); +#endif +#ifdef WEBRTC_CODEC_OPUS + if (test_mode_ != 0) { + printf("===============================================================\n"); + } + test_count_++; + OpenOutFile(test_count_); + char codec_opus[] = "OPUS"; + RegisterSendCodec('A', codec_opus, 48000, 6000, 960, -1); + Run(channel_a_to_b_); + RegisterSendCodec('A', codec_opus, 48000, 20000, 960, -1); + Run(channel_a_to_b_); + RegisterSendCodec('A', codec_opus, 48000, 32000, 960, -1); + Run(channel_a_to_b_); + RegisterSendCodec('A', codec_opus, 48000, 48000, 960, -1); + Run(channel_a_to_b_); + RegisterSendCodec('A', codec_opus, 48000, 64000, 960, -1); + Run(channel_a_to_b_); + RegisterSendCodec('A', codec_opus, 48000, 96000, 960, -1); + Run(channel_a_to_b_); + RegisterSendCodec('A', codec_opus, 48000, 500000, 960, -1); + Run(channel_a_to_b_); #endif if (test_mode_ != 0) { printf("===============================================================\n"); diff --git a/src/modules/audio_coding/main/test/TestVADDTX.cc b/src/modules/audio_coding/main/test/TestVADDTX.cc index 793ab57976..fcca3748df 100644 --- a/src/modules/audio_coding/main/test/TestVADDTX.cc +++ b/src/modules/audio_coding/main/test/TestVADDTX.cc @@ -137,6 +137,21 @@ void TestVADDTX::Perform() // Close file _outFileB.Close(); +#endif +#ifdef WEBRTC_CODEC_OPUS + // Open outputfile + OpenOutFile(testCntr++); + + // Register Opus as send codec + char nameOPUS[] = "opus"; + RegisterSendCodec('A', nameOPUS); + + // Run the five test cased + runTestCases(); + + // Close file + _outFileB.Close(); + #endif if(_testMode) { printf("Done!\n"); diff --git a/src/modules/audio_coding/neteq/codec_db.c b/src/modules/audio_coding/neteq/codec_db.c index 5369cfd271..ebc92162b6 100644 --- a/src/modules/audio_coding/neteq/codec_db.c +++ b/src/modules/audio_coding/neteq/codec_db.c @@ -84,7 +84,7 @@ int WebRtcNetEQ_DbAdd(CodecDbInst_t *inst, enum WebRtcNetEQDecoder codec, #ifdef NETEQ_32KHZ_WIDEBAND &&(codec_fs!=32000) #endif -#ifdef NETEQ_48KHZ_WIDEBAND +#if defined(NETEQ_48KHZ_WIDEBAND) || defined(NETEQ_OPUS_CODEC) &&(codec_fs!=48000) #endif ) @@ -114,6 +114,9 @@ int WebRtcNetEQ_DbAdd(CodecDbInst_t *inst, enum WebRtcNetEQDecoder codec, #ifdef NETEQ_ISAC_SWB_CODEC case kDecoderISACswb : #endif +#ifdef NETEQ_OPUS_CODEC + case kDecoderOpus : +#endif #ifdef NETEQ_G722_CODEC case kDecoderG722 : case kDecoderG722_2ch : @@ -458,6 +461,9 @@ int WebRtcNetEQ_DbGetSplitInfo(SplitInfo_t *inst, enum WebRtcNetEQDecoder codecI #ifdef NETEQ_ISAC_SWB_CODEC case kDecoderISACswb: #endif +#ifdef NETEQ_OPUS_CODEC + case kDecoderOpus: +#endif #ifdef NETEQ_ARBITRARY_CODEC case kDecoderArbitrary: #endif diff --git a/src/modules/audio_coding/neteq/interface/webrtc_neteq.h b/src/modules/audio_coding/neteq/interface/webrtc_neteq.h index 39f6595fd0..9fc82973f8 100644 --- a/src/modules/audio_coding/neteq/interface/webrtc_neteq.h +++ b/src/modules/audio_coding/neteq/interface/webrtc_neteq.h @@ -62,6 +62,7 @@ enum WebRtcNetEQDecoder kDecoderG722_1C_24, kDecoderG722_1C_32, kDecoderG722_1C_48, + kDecoderOpus, kDecoderSPEEX_8, kDecoderSPEEX_16, kDecoderCELT_32, diff --git a/src/modules/audio_coding/neteq/interface/webrtc_neteq_help_macros.h b/src/modules/audio_coding/neteq/interface/webrtc_neteq_help_macros.h index c6f19bb546..d885faab70 100644 --- a/src/modules/audio_coding/neteq/interface/webrtc_neteq_help_macros.h +++ b/src/modules/audio_coding/neteq/interface/webrtc_neteq_help_macros.h @@ -151,7 +151,6 @@ inst.funcUpdBWEst=NULL; \ inst.funcGetErrorCode=NULL; - #define SET_PCM16B_SWB48_FUNCTIONS(inst) \ inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcPcm16b_DecodeW16; \ inst.funcDecodeRCU=NULL; \ @@ -317,6 +316,17 @@ inst.funcUpdBWEst=NULL; \ inst.funcGetErrorCode=NULL; +#define SET_OPUS_FUNCTIONS(inst) \ + inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcOpus_Decode; \ + inst.funcDecodeRCU=NULL; \ + inst.funcDecodePLC=NULL; \ + inst.funcDecodeInit=(WebRtcNetEQ_FuncDecodeInit)WebRtcOpus_DecoderInit; \ + inst.funcAddLatePkt=NULL; \ + inst.funcGetMDinfo=NULL; \ + inst.funcGetPitch=NULL; \ + inst.funcUpdBWEst=NULL; \ + inst.funcGetErrorCode=NULL; + #define SET_SPEEX_FUNCTIONS(inst) \ inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcSpeex_Decode; \ inst.funcDecodeRCU=NULL; \ diff --git a/src/modules/audio_coding/neteq/neteq_defines.h b/src/modules/audio_coding/neteq/neteq_defines.h index 318e6bb7f9..79cb144d8e 100644 --- a/src/modules/audio_coding/neteq/neteq_defines.h +++ b/src/modules/audio_coding/neteq/neteq_defines.h @@ -77,6 +77,8 @@ * * NETEQ_G722_1C_CODEC Enable G722.1 Annex C * + * NETEQ_OPUS_CODEC Enable Opus + * * NETEQ_SPEEX_CODEC Enable Speex (at 8 and 16 kHz sample rate) * * NETEQ_CELT_CODEC Enable Celt (at 32 kHz sample rate) @@ -244,6 +246,7 @@ #define NETEQ_G729_CODEC #define NETEQ_G726_CODEC #define NETEQ_GSMFR_CODEC + #define NETEQ_OPUS_CODEC #define NETEQ_AMR_CODEC #endif @@ -252,6 +255,7 @@ #define NETEQ_G722_CODEC #define NETEQ_G722_1_CODEC #define NETEQ_G729_1_CODEC + #define NETEQ_OPUS_CODEC #define NETEQ_SPEEX_CODEC #define NETEQ_AMRWB_CODEC #define NETEQ_WIDEBAND @@ -262,6 +266,7 @@ #define NETEQ_32KHZ_WIDEBAND #define NETEQ_G722_1C_CODEC #define NETEQ_CELT_CODEC + #define NETEQ_OPUS_CODEC #endif #if (defined(NETEQ_VOICEENGINE_CODECS)) @@ -295,6 +300,8 @@ #define NETEQ_G722_1C_CODEC #define NETEQ_CELT_CODEC + /* Fullband 48 kHz codecs */ + #define NETEQ_OPUS_CODEC #endif #if (defined(NETEQ_ALL_CODECS)) @@ -331,21 +338,26 @@ /* Super wideband 48kHz codecs */ #define NETEQ_48KHZ_WIDEBAND + #define NETEQ_OPUS_CODEC #endif /* Max output size from decoding one frame */ #if defined(NETEQ_48KHZ_WIDEBAND) - #define NETEQ_MAX_FRAME_SIZE 2880 /* 60 ms super wideband */ - #define NETEQ_MAX_OUTPUT_SIZE 3600 /* 60+15 ms super wideband (60 ms decoded + 15 ms for merge overlap) */ + #define NETEQ_MAX_FRAME_SIZE 5760 /* 120 ms super wideband */ + #define NETEQ_MAX_OUTPUT_SIZE 6480 /* 120+15 ms super wideband (120 ms + * decoded + 15 ms for merge overlap) */ #elif defined(NETEQ_32KHZ_WIDEBAND) - #define NETEQ_MAX_FRAME_SIZE 1920 /* 60 ms super wideband */ - #define NETEQ_MAX_OUTPUT_SIZE 2400 /* 60+15 ms super wideband (60 ms decoded + 15 ms for merge overlap) */ + #define NETEQ_MAX_FRAME_SIZE 3840 /* 120 ms super wideband */ + #define NETEQ_MAX_OUTPUT_SIZE 4320 /* 120+15 ms super wideband (120 ms + * decoded + 15 ms for merge overlap) */ #elif defined(NETEQ_WIDEBAND) - #define NETEQ_MAX_FRAME_SIZE 960 /* 60 ms wideband */ - #define NETEQ_MAX_OUTPUT_SIZE 1200 /* 60+15 ms wideband (60 ms decoded + 10 ms for merge overlap) */ + #define NETEQ_MAX_FRAME_SIZE 1920 /* 120 ms wideband */ + #define NETEQ_MAX_OUTPUT_SIZE 2160 /* 120+15 ms wideband (120 ms decoded + + * 15 ms for merge overlap) */ #else - #define NETEQ_MAX_FRAME_SIZE 480 /* 60 ms narrowband */ - #define NETEQ_MAX_OUTPUT_SIZE 600 /* 60+15 ms narrowband (60 ms decoded + 10 ms for merge overlap) */ + #define NETEQ_MAX_FRAME_SIZE 960 /* 120 ms narrowband */ + #define NETEQ_MAX_OUTPUT_SIZE 1080 /* 120+15 ms narrowband (120 ms decoded + * + 15 ms for merge overlap) */ #endif diff --git a/src/modules/audio_coding/neteq/packet_buffer.c b/src/modules/audio_coding/neteq/packet_buffer.c index 8f09b07267..7fbea58a42 100644 --- a/src/modules/audio_coding/neteq/packet_buffer.c +++ b/src/modules/audio_coding/neteq/packet_buffer.c @@ -578,6 +578,11 @@ int WebRtcNetEQ_GetDefaultCodecSettings(const enum WebRtcNetEQDecoder *codecID, codecBytes = 1560; /* 240ms @ 52kbps (30ms frames) */ codecBuffers = 8; } + else if (codecID[i] == kDecoderOpus) + { + codecBytes = 15300; /* 240ms @ 510kbps (60ms frames) */ + codecBuffers = 30; /* Replicating the value for PCMu/a */ + } else if ((codecID[i] == kDecoderPCM16B) || (codecID[i] == kDecoderPCM16B_2ch)) { diff --git a/src/modules/audio_coding/neteq/recin.c b/src/modules/audio_coding/neteq/recin.c index bce7c48f42..399250d357 100644 --- a/src/modules/audio_coding/neteq/recin.c +++ b/src/modules/audio_coding/neteq/recin.c @@ -202,6 +202,13 @@ int WebRtcNetEQ_RecInInternal(MCUInst_t *MCU_inst, RTPPacket_t *RTPpacketInput, /* Get CNG sample rate */ WebRtc_UWord16 fsCng = WebRtcNetEQ_DbGetSampleRate(&MCU_inst->codec_DB_inst, RTPpacket[i_k].payloadType); + + /* Force sampling frequency to 32000 Hz CNG 48000 Hz. */ + /* TODO(tlegrand): remove limitation once ACM has full 48 kHz + * support. */ + if (fsCng > 32000) { + fsCng = 32000; + } if ((fsCng != MCU_inst->fs) && (fsCng > 8000)) { /* @@ -370,10 +377,29 @@ int WebRtcNetEQ_GetTimestampScaling(MCUInst_t *MCU_inst, int rtpPayloadType) MCU_inst->scalingFactor = kTSscalingTwo; break; } + case kDecoderOpus: + { + /* We resample Opus internally to 32 kHz, but timestamps + * are counted at 48 kHz. So there are two output samples + * per three RTP timestamp ticks. */ + MCU_inst->scalingFactor = kTSscalingTwoThirds; + break; + } + case kDecoderAVT: case kDecoderCNG: { - /* do not change the timestamp scaling settings */ + /* TODO(tlegrand): remove scaling once ACM has full 48 kHz + * support. */ + WebRtc_UWord16 sample_freq = + WebRtcNetEQ_DbGetSampleRate(&MCU_inst->codec_DB_inst, + rtpPayloadType); + if (sample_freq == 48000) { + MCU_inst->scalingFactor = kTSscalingTwoThirds; + } + + /* For sample_freq <= 32 kHz, do not change the timestamp scaling + * settings. */ break; } default: diff --git a/src/modules/audio_coding/neteq/recout.c b/src/modules/audio_coding/neteq/recout.c index eb80f2ded0..1f47945939 100644 --- a/src/modules/audio_coding/neteq/recout.c +++ b/src/modules/audio_coding/neteq/recout.c @@ -41,8 +41,8 @@ /* Scratch usage: Type Name size startpos endpos - WebRtc_Word16 pw16_NetEqAlgorithm_buffer 600*fs/8000 0 600*fs/8000-1 - struct dspInfo 6 600*fs/8000 605*fs/8000 + WebRtc_Word16 pw16_NetEqAlgorithm_buffer 1080*fs/8000 0 1080*fs/8000-1 + struct dspInfo 6 1080*fs/8000 1085*fs/8000 func WebRtcNetEQ_Normal 40+495*fs/8000 0 39+495*fs/8000 func WebRtcNetEQ_Merge 40+496*fs/8000 0 39+496*fs/8000 @@ -50,7 +50,7 @@ func WebRtcNetEQ_Accelerate 210 240*fs/8000 209+240*fs/8000 func WebRtcNetEQ_BGNUpdate 69 480*fs/8000 68+480*fs/8000 - Total: 605*fs/8000 + Total: 1086*fs/8000 */ #define SCRATCH_ALGORITHM_BUFFER 0 @@ -58,35 +58,35 @@ #define SCRATCH_NETEQ_MERGE 0 #if (defined(NETEQ_48KHZ_WIDEBAND)) -#define SCRATCH_DSP_INFO 3600 +#define SCRATCH_DSP_INFO 6480 #define SCRATCH_NETEQ_ACCELERATE 1440 #define SCRATCH_NETEQ_BGN_UPDATE 2880 #define SCRATCH_NETEQ_EXPAND 756 #elif (defined(NETEQ_32KHZ_WIDEBAND)) -#define SCRATCH_DSP_INFO 2400 +#define SCRATCH_DSP_INFO 4320 #define SCRATCH_NETEQ_ACCELERATE 960 #define SCRATCH_NETEQ_BGN_UPDATE 1920 #define SCRATCH_NETEQ_EXPAND 504 #elif (defined(NETEQ_WIDEBAND)) -#define SCRATCH_DSP_INFO 1200 +#define SCRATCH_DSP_INFO 2160 #define SCRATCH_NETEQ_ACCELERATE 480 #define SCRATCH_NETEQ_BGN_UPDATE 960 #define SCRATCH_NETEQ_EXPAND 252 #else /* NB */ -#define SCRATCH_DSP_INFO 600 +#define SCRATCH_DSP_INFO 1080 #define SCRATCH_NETEQ_ACCELERATE 240 #define SCRATCH_NETEQ_BGN_UPDATE 480 #define SCRATCH_NETEQ_EXPAND 126 #endif #if (defined(NETEQ_48KHZ_WIDEBAND)) -#define SIZE_SCRATCH_BUFFER 3636 +#define SIZE_SCRATCH_BUFFER 6516 #elif (defined(NETEQ_32KHZ_WIDEBAND)) -#define SIZE_SCRATCH_BUFFER 2424 +#define SIZE_SCRATCH_BUFFER 4344 #elif (defined(NETEQ_WIDEBAND)) -#define SIZE_SCRATCH_BUFFER 1212 +#define SIZE_SCRATCH_BUFFER 2172 #else /* NB */ -#define SIZE_SCRATCH_BUFFER 606 +#define SIZE_SCRATCH_BUFFER 1086 #endif #ifdef NETEQ_DELAY_LOGGING @@ -110,13 +110,15 @@ int WebRtcNetEQ_RecOutInternal(DSPInst_t *inst, WebRtc_Word16 *pw16_outData, #ifdef SCRATCH char pw8_ScratchBuffer[((SIZE_SCRATCH_BUFFER + 1) * 2)]; WebRtc_Word16 *pw16_scratchPtr = (WebRtc_Word16*) pw8_ScratchBuffer; - WebRtc_Word16 pw16_decoded_buffer[NETEQ_MAX_FRAME_SIZE]; + /* pad with 240*fs_mult to match the overflow guard below */ + WebRtc_Word16 pw16_decoded_buffer[NETEQ_MAX_FRAME_SIZE+240*6]; WebRtc_Word16 *pw16_NetEqAlgorithm_buffer = pw16_scratchPtr + SCRATCH_ALGORITHM_BUFFER; DSP2MCU_info_t *dspInfo = (DSP2MCU_info_t*) (pw16_scratchPtr + SCRATCH_DSP_INFO); #else - WebRtc_Word16 pw16_decoded_buffer[NETEQ_MAX_FRAME_SIZE]; - WebRtc_Word16 pw16_NetEqAlgorithm_buffer[NETEQ_MAX_OUTPUT_SIZE]; + /* pad with 240*fs_mult to match the overflow guard below */ + WebRtc_Word16 pw16_decoded_buffer[NETEQ_MAX_FRAME_SIZE+240*6]; + WebRtc_Word16 pw16_NetEqAlgorithm_buffer[NETEQ_MAX_OUTPUT_SIZE+240*6]; DSP2MCU_info_t dspInfoStruct; DSP2MCU_info_t *dspInfo = &dspInfoStruct; #endif diff --git a/src/modules/audio_coding/neteq/signal_mcu.c b/src/modules/audio_coding/neteq/signal_mcu.c index b28f39c3d0..2cccf1a616 100644 --- a/src/modules/audio_coding/neteq/signal_mcu.c +++ b/src/modules/audio_coding/neteq/signal_mcu.c @@ -319,7 +319,13 @@ int WebRtcNetEQ_SignalMcu(MCUInst_t *inst) WebRtc_UWord16 tempFs; tempFs = WebRtcNetEQ_DbGetSampleRate(&inst->codec_DB_inst, payloadType); - if (tempFs > 0) + /* TODO(tlegrand): Remove this limitation once ACM has full + * 48 kHz support. */ + if (tempFs > 32000) + { + inst->fs = 32000; + } + else if (tempFs > 0) { inst->fs = tempFs; } diff --git a/src/modules/audio_conference_mixer/interface/audio_conference_mixer.h b/src/modules/audio_conference_mixer/interface/audio_conference_mixer.h index 4ece1bf394..9ffac2d2da 100644 --- a/src/modules/audio_conference_mixer/interface/audio_conference_mixer.h +++ b/src/modules/audio_conference_mixer/interface/audio_conference_mixer.h @@ -30,6 +30,7 @@ public: kNbInHz = 8000, kWbInHz = 16000, kSwbInHz = 32000, + kFbInHz = 48000, kLowestPossible = -1, kDefaultFrequency = kWbInHz }; diff --git a/src/modules/audio_conference_mixer/source/audio_conference_mixer_impl.cc b/src/modules/audio_conference_mixer/source/audio_conference_mixer_impl.cc index 851642c180..1fdd9dc229 100644 --- a/src/modules/audio_conference_mixer/source/audio_conference_mixer_impl.cc +++ b/src/modules/audio_conference_mixer/source/audio_conference_mixer_impl.cc @@ -282,6 +282,12 @@ WebRtc_Word32 AudioConferenceMixerImpl::Process() SetOutputFrequency(kSwbInHz); } break; + case 48000: + if(OutputFrequency() != kFbInHz) + { + SetOutputFrequency(kFbInHz); + } + break; default: assert(false); diff --git a/src/modules/modules.gyp b/src/modules/modules.gyp index 089f53868c..a5b31c6a77 100644 --- a/src/modules/modules.gyp +++ b/src/modules/modules.gyp @@ -15,6 +15,7 @@ 'audio_coding/codecs/ilbc/ilbc.gypi', 'audio_coding/codecs/isac/main/source/isac.gypi', 'audio_coding/codecs/isac/fix/source/isacfix.gypi', + 'audio_coding/codecs/opus/opus.gypi', 'audio_coding/codecs/pcm16b/pcm16b.gypi', 'audio_coding/main/source/audio_coding_module.gypi', 'audio_coding/neteq/neteq.gypi', diff --git a/src/modules/rtp_rtcp/source/rtp_receiver_audio.cc b/src/modules/rtp_rtcp/source/rtp_receiver_audio.cc index a57da755fd..c9fd3df09c 100644 --- a/src/modules/rtp_rtcp/source/rtp_receiver_audio.cc +++ b/src/modules/rtp_rtcp/source/rtp_receiver_audio.cc @@ -27,6 +27,7 @@ RTPReceiverAudio::RTPReceiverAudio(const WebRtc_Word32 id): _cngNBPayloadType(-1), _cngWBPayloadType(-1), _cngSWBPayloadType(-1), + _cngFBPayloadType(-1), _cngPayloadType(-1), _G722PayloadType(-1), _lastReceivedG722(false), @@ -94,7 +95,7 @@ bool RTPReceiverAudio::CNGPayloadType(const WebRtc_Word8 payloadType, WebRtc_UWord32& frequency) { - // we can have three CNG on 8000Hz, 16000Hz and 32000Hz + // We can have four CNG on 8000Hz, 16000Hz, 32000Hz and 48000Hz. if(_cngNBPayloadType == payloadType) { frequency = 8000; @@ -129,6 +130,15 @@ RTPReceiverAudio::CNGPayloadType(const WebRtc_Word8 payloadType, } _cngPayloadType = _cngSWBPayloadType; return true; + }else if(_cngFBPayloadType == payloadType) + { + frequency = 48000; + if ((_cngPayloadType != -1) &&(_cngPayloadType !=_cngFBPayloadType)) + { + ResetStatistics(); + } + _cngPayloadType = _cngFBPayloadType; + return true; }else { // not CNG @@ -195,6 +205,8 @@ ModuleRTPUtility::Payload* RTPReceiverAudio::RegisterReceiveAudioPayload( _cngWBPayloadType = payloadType; } else if(frequency == 32000) { _cngSWBPayloadType = payloadType; + } else if(frequency == 48000) { + _cngFBPayloadType = payloadType; } else { assert(false); return NULL; diff --git a/src/modules/rtp_rtcp/source/rtp_receiver_audio.h b/src/modules/rtp_rtcp/source/rtp_receiver_audio.h index 0b0ba3015a..e256dd1b8f 100644 --- a/src/modules/rtp_rtcp/source/rtp_receiver_audio.h +++ b/src/modules/rtp_rtcp/source/rtp_receiver_audio.h @@ -81,6 +81,7 @@ private: WebRtc_Word8 _cngNBPayloadType; WebRtc_Word8 _cngWBPayloadType; WebRtc_Word8 _cngSWBPayloadType; + WebRtc_Word8 _cngFBPayloadType; WebRtc_Word8 _cngPayloadType; // G722 is special since it use the wrong number of RTP samples in timestamp VS. number of samples in the frame diff --git a/src/modules/rtp_rtcp/source/rtp_sender_audio.cc b/src/modules/rtp_rtcp/source/rtp_sender_audio.cc index 0f6f69f353..0c422deaf7 100644 --- a/src/modules/rtp_rtcp/source/rtp_sender_audio.cc +++ b/src/modules/rtp_rtcp/source/rtp_sender_audio.cc @@ -38,6 +38,7 @@ RTPSenderAudio::RTPSenderAudio(const WebRtc_Word32 id, RtpRtcpClock* clock, _cngNBPayloadType(-1), _cngWBPayloadType(-1), _cngSWBPayloadType(-1), + _cngFBPayloadType(-1), _lastPayloadType(-1), _includeAudioLevelIndication(false), // @TODO - reset at Init()? _audioLevelIndicationID(0), @@ -101,6 +102,10 @@ WebRtc_Word32 RTPSenderAudio::RegisterAudioPayload( } else if (frequency == 32000) { _cngSWBPayloadType = payloadType; + + } else if (frequency == 48000) { + _cngFBPayloadType = payloadType; + } else { return -1; } @@ -159,6 +164,15 @@ RTPSenderAudio::MarkerBit(const FrameType frameType, return false; } } + if(_cngFBPayloadType != -1) + { + // we have configured SWB CNG + if(_cngFBPayloadType == payloadType) + { + // only set a marker bit when we change payload type to a non CNG + return false; + } + } // payloadType differ if(_lastPayloadType == -1) { diff --git a/src/modules/rtp_rtcp/source/rtp_sender_audio.h b/src/modules/rtp_rtcp/source/rtp_sender_audio.h index 5974441ba8..fe9a952fff 100644 --- a/src/modules/rtp_rtcp/source/rtp_sender_audio.h +++ b/src/modules/rtp_rtcp/source/rtp_sender_audio.h @@ -117,6 +117,7 @@ private: WebRtc_Word8 _cngNBPayloadType; WebRtc_Word8 _cngWBPayloadType; WebRtc_Word8 _cngSWBPayloadType; + WebRtc_Word8 _cngFBPayloadType; WebRtc_Word8 _lastPayloadType; // Audio level indication (https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/) diff --git a/src/voice_engine/channel.cc b/src/voice_engine/channel.cc index b4889e29ec..4370b74c97 100644 --- a/src/voice_engine/channel.cc +++ b/src/voice_engine/channel.cc @@ -6403,12 +6403,12 @@ Channel::GetPlayoutTimeStamp(WebRtc_UWord32& playoutTimestamp) } WebRtc_Word32 playoutFrequency = _audioCodingModule.PlayoutFrequency(); - if (_audioCodingModule.ReceiveCodec(currRecCodec) == 0) - { - if (STR_CASE_CMP("G722", currRecCodec.plname) == 0) - { - playoutFrequency = 8000; - } + if (_audioCodingModule.ReceiveCodec(currRecCodec) == 0) { + if (STR_CASE_CMP("G722", currRecCodec.plname) == 0) { + playoutFrequency = 8000; + } else if (STR_CASE_CMP("opus", currRecCodec.plname) == 0) { + playoutFrequency = 48000; + } } timestamp -= (delayMS * (playoutFrequency/1000)); @@ -6482,16 +6482,20 @@ Channel::UpdatePacketDelay(const WebRtc_UWord32 timestamp, rtpReceiveFrequency = _audioCodingModule.ReceiveFrequency(); CodecInst currRecCodec; - if (_audioCodingModule.ReceiveCodec(currRecCodec) == 0) - { - if (STR_CASE_CMP("G722", currRecCodec.plname) == 0) - { - // Even though the actual sampling rate for G.722 audio is - // 16,000 Hz, the RTP clock rate for the G722 payload format is - // 8,000 Hz because that value was erroneously assigned in - // RFC 1890 and must remain unchanged for backward compatibility. - rtpReceiveFrequency = 8000; - } + if (_audioCodingModule.ReceiveCodec(currRecCodec) == 0) { + if (STR_CASE_CMP("G722", currRecCodec.plname) == 0) { + // Even though the actual sampling rate for G.722 audio is + // 16,000 Hz, the RTP clock rate for the G722 payload format is + // 8,000 Hz because that value was erroneously assigned in + // RFC 1890 and must remain unchanged for backward compatibility. + rtpReceiveFrequency = 8000; + } else if (STR_CASE_CMP("opus", currRecCodec.plname) == 0) { + // We are resampling Opus internally to 32,000 Hz until all our + // DSP routines can operate at 48,000 Hz, but the RTP clock + // rate for the Opus payload format is standardized to 48,000 Hz, + // because that is the maximum supported decoding sampling rate. + rtpReceiveFrequency = 48000; + } } const WebRtc_UWord32 timeStampDiff = timestamp - _playoutTimeStampRTP; @@ -6499,24 +6503,25 @@ Channel::UpdatePacketDelay(const WebRtc_UWord32 timestamp, if (timeStampDiff > 0) { - switch (rtpReceiveFrequency) - { - case 8000: - timeStampDiffMs = timeStampDiff >> 3; - break; - case 16000: - timeStampDiffMs = timeStampDiff >> 4; - break; - case 32000: - timeStampDiffMs = timeStampDiff >> 5; - break; - default: - WEBRTC_TRACE(kTraceWarning, kTraceVoice, - VoEId(_instanceId, _channelId), - "Channel::UpdatePacketDelay() invalid sample " - "rate"); - timeStampDiffMs = 0; - return -1; + switch (rtpReceiveFrequency) { + case 8000: + timeStampDiffMs = static_cast(timeStampDiff >> 3); + break; + case 16000: + timeStampDiffMs = static_cast(timeStampDiff >> 4); + break; + case 32000: + timeStampDiffMs = static_cast(timeStampDiff >> 5); + break; + case 48000: + timeStampDiffMs = static_cast(timeStampDiff / 48); + break; + default: + WEBRTC_TRACE(kTraceWarning, kTraceVoice, + VoEId(_instanceId, _channelId), + "Channel::UpdatePacketDelay() invalid sample rate"); + timeStampDiffMs = 0; + return -1; } if (timeStampDiffMs > 5000) { @@ -6539,20 +6544,23 @@ Channel::UpdatePacketDelay(const WebRtc_UWord32 timestamp, if (sequenceNumber - _previousSequenceNumber == 1) { WebRtc_UWord16 packetDelayMs = 0; - switch (rtpReceiveFrequency) - { - case 8000: - packetDelayMs = (WebRtc_UWord16)( + switch (rtpReceiveFrequency) { + case 8000: + packetDelayMs = static_cast( (timestamp - _previousTimestamp) >> 3); break; - case 16000: - packetDelayMs = (WebRtc_UWord16)( + case 16000: + packetDelayMs = static_cast( (timestamp - _previousTimestamp) >> 4); break; - case 32000: - packetDelayMs = (WebRtc_UWord16)( + case 32000: + packetDelayMs = static_cast( (timestamp - _previousTimestamp) >> 5); break; + case 48000: + packetDelayMs = static_cast( + (timestamp - _previousTimestamp) / 48); + break; } if (packetDelayMs >= 10 && packetDelayMs <= 60) diff --git a/src/voice_engine/transmit_mixer.cc b/src/voice_engine/transmit_mixer.cc index 6153c5bace..d987c4e9ce 100644 --- a/src/voice_engine/transmit_mixer.cc +++ b/src/voice_engine/transmit_mixer.cc @@ -322,8 +322,14 @@ void TransmitMixer::CheckForSendCodecChanges() { if (codec.channels == 2) stereo_codec_ = true; - if (codec.plfreq > _mixingFrequency) + + // TODO(tlegrand): Remove once we have full 48 kHz support in + // Audio Coding Module. + if (codec.plfreq > 32000) { + _mixingFrequency = 32000; + } else if (codec.plfreq > _mixingFrequency) { _mixingFrequency = codec.plfreq; + } } channel = sc.GetNextChannel(iterator); } diff --git a/third_party/opus/opus.gyp b/third_party/opus/opus.gyp new file mode 100644 index 0000000000..88c826a821 --- /dev/null +++ b/third_party/opus/opus.gyp @@ -0,0 +1,184 @@ +# 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. + +{ + 'targets': [ + { + 'target_name': 'opus', + 'type': 'static_library', + 'defines': [ + 'OPUS_BUILD', + ], + 'conditions': [ + ['OS=="linux"', { + 'cflags': [ + '-std=c99', + ], + }], + ['OS != "win"', { + 'defines': [ + 'HAVE_LRINTF', + 'VAR_ARRAYS', + ], + }], + ['OS == "win"', { + 'defines': [ + 'USE_ALLOCA', + ['inline','__inline'], + ], + 'msvs_disabled_warnings':[ + 4305, # Disable truncation warning in /source/celt/pitch.c[line 80] + ], + }], + ], + 'include_dirs': [ + 'source/celt', + 'source/include', + 'source/silk', + 'source/silk/float', + 'source/src', + ], + 'sources': [ + # opus wrapper/glue + 'source/src/opus.c', + 'source/src/opus_decoder.c', + 'source/src/opus_encoder.c', + 'source/src/repacketizer.c', + + # celt sub-codec + 'source/celt/bands.c', + 'source/celt/celt.c', + 'source/celt/celt_lpc.c', + 'source/celt/cwrs.c', + 'source/celt/entcode.c', + 'source/celt/entdec.c', + 'source/celt/entenc.c', + 'source/celt/kiss_fft.c', + 'source/celt/laplace.c', + 'source/celt/mathops.c', + 'source/celt/mdct.c', + 'source/celt/modes.c', + 'source/celt/pitch.c', + 'source/celt/quant_bands.c', + 'source/celt/rate.c', + 'source/celt/vq.c', + + # silk sub-codec + 'source/silk/A2NLSF.c', + 'source/silk/ana_filt_bank_1.c', + 'source/silk/biquad_alt.c', + 'source/silk/bwexpander.c', + 'source/silk/bwexpander_32.c', + 'source/silk/check_control_input.c', + 'source/silk/CNG.c', + 'source/silk/code_signs.c', + 'source/silk/control_audio_bandwidth.c', + 'source/silk/control_codec.c', + 'source/silk/control_SNR.c', + 'source/silk/debug.c', + 'source/silk/decode_core.c', + 'source/silk/decode_frame.c', + 'source/silk/decode_indices.c', + 'source/silk/decode_parameters.c', + 'source/silk/decode_pitch.c', + 'source/silk/decode_pulses.c', + 'source/silk/decoder_set_fs.c', + 'source/silk/dec_API.c', + 'source/silk/enc_API.c', + 'source/silk/encode_indices.c', + 'source/silk/encode_pulses.c', + 'source/silk/gain_quant.c', + 'source/silk/HP_variable_cutoff.c', + 'source/silk/init_decoder.c', + 'source/silk/init_encoder.c', + 'source/silk/inner_prod_aligned.c', + 'source/silk/interpolate.c', + 'source/silk/lin2log.c', + 'source/silk/log2lin.c', + 'source/silk/LPC_analysis_filter.c', + 'source/silk/LPC_inv_pred_gain.c', + 'source/silk/LP_variable_cutoff.c', + 'source/silk/NLSF2A.c', + 'source/silk/NLSF_decode.c', + 'source/silk/NLSF_encode.c', + 'source/silk/NLSF_del_dec_quant.c', + 'source/silk/NLSF_stabilize.c', + 'source/silk/NLSF_unpack.c', + 'source/silk/NLSF_VQ.c', + 'source/silk/NLSF_VQ_weights_laroia.c', + 'source/silk/NSQ.c', + 'source/silk/NSQ_del_dec.c', + 'source/silk/pitch_est_tables.c', + 'source/silk/PLC.c', + 'source/silk/process_NLSFs.c', + 'source/silk/quant_LTP_gains.c', + 'source/silk/resampler.c', + 'source/silk/resampler_down2.c', + 'source/silk/resampler_down2_3.c', + 'source/silk/resampler_private_AR2.c', + 'source/silk/resampler_private_down_FIR.c', + 'source/silk/resampler_private_IIR_FIR.c', + 'source/silk/resampler_private_up2_HQ.c', + 'source/silk/resampler_rom.c', + 'source/silk/shell_coder.c', + 'source/silk/sigm_Q15.c', + 'source/silk/sort.c', + 'source/silk/stereo_decode_pred.c', + 'source/silk/stereo_encode_pred.c', + 'source/silk/stereo_find_predictor.c', + 'source/silk/stereo_LR_to_MS.c', + 'source/silk/stereo_MS_to_LR.c', + 'source/silk/stereo_quant_pred.c', + 'source/silk/sum_sqr_shift.c', + 'source/silk/table_LSF_cos.c', + 'source/silk/tables_gain.c', + 'source/silk/tables_LTP.c', + 'source/silk/tables_NLSF_CB_NB_MB.c', + 'source/silk/tables_NLSF_CB_WB.c', + 'source/silk/tables_other.c', + 'source/silk/tables_pitch_lag.c', + 'source/silk/tables_pulses_per_block.c', + 'source/silk/VAD.c', + 'source/silk/VQ_WMat_EC.c', + + # silk floating point engine + 'source/silk/float/apply_sine_window_FLP.c', + 'source/silk/float/autocorrelation_FLP.c', + 'source/silk/float/burg_modified_FLP.c', + 'source/silk/float/bwexpander_FLP.c', + 'source/silk/float/corrMatrix_FLP.c', + 'source/silk/float/encode_frame_FLP.c', + 'source/silk/float/energy_FLP.c', + 'source/silk/float/find_LPC_FLP.c', + 'source/silk/float/find_LTP_FLP.c', + 'source/silk/float/find_pitch_lags_FLP.c', + 'source/silk/float/find_pred_coefs_FLP.c', + 'source/silk/float/inner_product_FLP.c', + 'source/silk/float/k2a_FLP.c', + 'source/silk/float/levinsondurbin_FLP.c', + 'source/silk/float/LPC_analysis_filter_FLP.c', + 'source/silk/float/LPC_inv_pred_gain_FLP.c', + 'source/silk/float/LTP_analysis_filter_FLP.c', + 'source/silk/float/LTP_scale_ctrl_FLP.c', + 'source/silk/float/noise_shape_analysis_FLP.c', + 'source/silk/float/pitch_analysis_core_FLP.c', + 'source/silk/float/prefilter_FLP.c', + 'source/silk/float/process_gains_FLP.c', + 'source/silk/float/regularize_correlations_FLP.c', + 'source/silk/float/residual_energy_FLP.c', + 'source/silk/float/scale_copy_vector_FLP.c', + 'source/silk/float/scale_vector_FLP.c', + 'source/silk/float/schur_FLP.c', + 'source/silk/float/solve_LS_FLP.c', + 'source/silk/float/sort_FLP.c', + 'source/silk/float/warped_autocorrelation_FLP.c', + 'source/silk/float/wrappers_FLP.c', + ] + } + ] +} diff --git a/tools/create_supplement_gypi.py b/tools/create_supplement_gypi.py index 7f996e7472..f7b2696c4d 100644 --- a/tools/create_supplement_gypi.py +++ b/tools/create_supplement_gypi.py @@ -15,6 +15,7 @@ supplement_gypi = """#!/usr/bin/env python { 'variables': { 'build_with_chromium': 0, + 'build_with_mozilla': 0, } } """