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
This commit is contained in:
parent
28d0140ed2
commit
a7d8387bdd
3
DEPS
3
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"),
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
123
src/modules/audio_coding/codecs/opus/interface/opus_interface.h
Normal file
123
src/modules/audio_coding/codecs/opus/interface/opus_interface.h
Normal file
@ -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_
|
||||
44
src/modules/audio_coding/codecs/opus/opus.gypi
Normal file
44
src/modules/audio_coding/codecs/opus/opus.gypi
Normal file
@ -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',
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
181
src/modules/audio_coding/codecs/opus/opus_interface.c
Normal file
181
src/modules/audio_coding/codecs/opus/opus_interface.c
Normal file
@ -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 <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
@ -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));
|
||||
|
||||
@ -62,7 +62,7 @@ protected:
|
||||
|
||||
WebRtcCngEncInst* _encoderInstPtr;
|
||||
WebRtcCngDecInst* _decoderInstPtr;
|
||||
WebRtc_Word16 _sampFreqHz;
|
||||
WebRtc_UWord16 _sampFreqHz;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -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)) {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -1310,6 +1310,7 @@ protected:
|
||||
WebRtc_UWord8 _numLPCParams;
|
||||
bool _sentCNPrevious;
|
||||
bool _isMaster;
|
||||
int16_t _prev_frame_cng;
|
||||
|
||||
WebRtcACMCodecParams _encoderParams;
|
||||
WebRtcACMCodecParams _decoderParams;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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_
|
||||
|
||||
@ -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': [
|
||||
|
||||
@ -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<uint8_t>(ACMCodecDB::database_[i].pltype);
|
||||
} else if (ACMCodecDB::database_[i].plfreq == 32000) {
|
||||
_cng_swb_pltype = static_cast<uint8_t>(ACMCodecDB::database_[i].pltype);
|
||||
} else if (ACMCodecDB::database_[i].plfreq == 48000) {
|
||||
_cng_fb_pltype = static_cast<uint8_t>(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<uint8_t>(send_codec.pltype);
|
||||
break;
|
||||
}
|
||||
case 48000: {
|
||||
_cng_fb_pltype = static_cast<uint8_t>(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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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
|
||||
|
||||
@ -62,6 +62,7 @@ enum WebRtcNetEQDecoder
|
||||
kDecoderG722_1C_24,
|
||||
kDecoderG722_1C_32,
|
||||
kDecoderG722_1C_48,
|
||||
kDecoderOpus,
|
||||
kDecoderSPEEX_8,
|
||||
kDecoderSPEEX_16,
|
||||
kDecoderCELT_32,
|
||||
|
||||
@ -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; \
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
|
||||
@ -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))
|
||||
{
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -30,6 +30,7 @@ public:
|
||||
kNbInHz = 8000,
|
||||
kWbInHz = 16000,
|
||||
kSwbInHz = 32000,
|
||||
kFbInHz = 48000,
|
||||
kLowestPossible = -1,
|
||||
kDefaultFrequency = kWbInHz
|
||||
};
|
||||
|
||||
@ -282,6 +282,12 @@ WebRtc_Word32 AudioConferenceMixerImpl::Process()
|
||||
SetOutputFrequency(kSwbInHz);
|
||||
}
|
||||
break;
|
||||
case 48000:
|
||||
if(OutputFrequency() != kFbInHz)
|
||||
{
|
||||
SetOutputFrequency(kFbInHz);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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/)
|
||||
|
||||
@ -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<WebRtc_UWord32>(timeStampDiff >> 3);
|
||||
break;
|
||||
case 16000:
|
||||
timeStampDiffMs = static_cast<WebRtc_UWord32>(timeStampDiff >> 4);
|
||||
break;
|
||||
case 32000:
|
||||
timeStampDiffMs = static_cast<WebRtc_UWord32>(timeStampDiff >> 5);
|
||||
break;
|
||||
case 48000:
|
||||
timeStampDiffMs = static_cast<WebRtc_UWord32>(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<WebRtc_UWord16>(
|
||||
(timestamp - _previousTimestamp) >> 3);
|
||||
break;
|
||||
case 16000:
|
||||
packetDelayMs = (WebRtc_UWord16)(
|
||||
case 16000:
|
||||
packetDelayMs = static_cast<WebRtc_UWord16>(
|
||||
(timestamp - _previousTimestamp) >> 4);
|
||||
break;
|
||||
case 32000:
|
||||
packetDelayMs = (WebRtc_UWord16)(
|
||||
case 32000:
|
||||
packetDelayMs = static_cast<WebRtc_UWord16>(
|
||||
(timestamp - _previousTimestamp) >> 5);
|
||||
break;
|
||||
case 48000:
|
||||
packetDelayMs = static_cast<WebRtc_UWord16>(
|
||||
(timestamp - _previousTimestamp) / 48);
|
||||
break;
|
||||
}
|
||||
|
||||
if (packetDelayMs >= 10 && packetDelayMs <= 60)
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
184
third_party/opus/opus.gyp
vendored
Normal file
184
third_party/opus/opus.gyp
vendored
Normal file
@ -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',
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -15,6 +15,7 @@ supplement_gypi = """#!/usr/bin/env python
|
||||
{
|
||||
'variables': {
|
||||
'build_with_chromium': 0,
|
||||
'build_with_mozilla': 0,
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user