blob: 52f51146b0e11114a7e0d8a6a02f64de3a040f04 [file] [log] [blame]
andrew@webrtc.orgb015cbe2012-10-22 18:19:231/*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
turaj@webrtc.org4c9b8192012-12-13 22:46:4311#include "webrtc/modules/audio_coding/main/source/acm_generic_codec.h"
12
andrew@webrtc.orgb015cbe2012-10-22 18:19:2313#include <assert.h>
14#include <string.h>
15
turaj@webrtc.org4c9b8192012-12-13 22:46:4316#include "webrtc/common_audio/vad/include/webrtc_vad.h"
17#include "webrtc/modules/audio_coding/codecs/cng/include/webrtc_cng.h"
18#include "webrtc/modules/audio_coding/main/source/acm_codec_database.h"
stefan@webrtc.orgec09fcb2013-09-18 12:34:0519#include "webrtc/modules/audio_coding/main/source/acm_common_defs.h"
turaj@webrtc.org4c9b8192012-12-13 22:46:4320#include "webrtc/modules/audio_coding/main/source/acm_neteq.h"
21#include "webrtc/system_wrappers/interface/trace.h"
andrew@webrtc.orgb015cbe2012-10-22 18:19:2322
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:5123namespace webrtc {
andrew@webrtc.orgb015cbe2012-10-22 18:19:2324
turaj@webrtc.orged0b4fb2013-09-13 23:06:5925namespace acm1 {
26
andrew@webrtc.orgb015cbe2012-10-22 18:19:2327// Enum for CNG
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:5128enum {
29 kMaxPLCParamsCNG = WEBRTC_CNG_MAX_LPC_ORDER,
30 kNewCNGNumPLCParams = 8
andrew@webrtc.orgb015cbe2012-10-22 18:19:2331};
32
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:3533// Interval for sending new CNG parameters (SID frames) is 100 msec.
34enum {
turaj@webrtc.org1952f252012-12-03 22:13:3135 kCngSidIntervalMsec = 100
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:3536};
andrew@webrtc.orgb015cbe2012-10-22 18:19:2337
38// We set some of the variables to invalid values as a check point
39// if a proper initialization has happened. Another approach is
40// to initialize to a default codec that we are sure is always included.
41ACMGenericCodec::ACMGenericCodec()
turaj@webrtc.org4c9b8192012-12-13 22:46:4342 : in_audio_ix_write_(0),
43 in_audio_ix_read_(0),
44 in_timestamp_ix_write_(0),
45 in_audio_(NULL),
46 in_timestamp_(NULL),
47 frame_len_smpl_(-1), // invalid value
48 num_channels_(1),
49 codec_id_(-1), // invalid value
50 num_missed_samples_(0),
51 encoder_exist_(false),
52 decoder_exist_(false),
53 encoder_initialized_(false),
54 decoder_initialized_(false),
55 registered_in_neteq_(false),
56 has_internal_dtx_(false),
57 ptr_vad_inst_(NULL),
58 vad_enabled_(false),
59 vad_mode_(VADNormal),
60 dtx_enabled_(false),
61 ptr_dtx_inst_(NULL),
62 num_lpc_params_(kNewCNGNumPLCParams),
63 sent_cn_previous_(false),
64 is_master_(true),
65 prev_frame_cng_(0),
66 neteq_decode_lock_(NULL),
67 codec_wrapper_lock_(*RWLockWrapper::CreateRWLock()),
68 last_encoded_timestamp_(0),
69 last_timestamp_(0xD87F3F9F),
70 is_audio_buff_fresh_(true),
71 unique_id_(0) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:2372 // Initialize VAD vector.
73 for (int i = 0; i < MAX_FRAME_SIZE_10MSEC; i++) {
turaj@webrtc.org4c9b8192012-12-13 22:46:4374 vad_label_[i] = 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:2375 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:2376 // Nullify memory for encoder and decoder, and set payload type to an
77 // invalid value.
turaj@webrtc.org4c9b8192012-12-13 22:46:4378 memset(&encoder_params_, 0, sizeof(WebRtcACMCodecParams));
79 encoder_params_.codec_inst.pltype = -1;
80 memset(&decoder_params_, 0, sizeof(WebRtcACMCodecParams));
81 decoder_params_.codec_inst.pltype = -1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:2382}
83
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:5184ACMGenericCodec::~ACMGenericCodec() {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:3585 // Check all the members which are pointers, and if they are not NULL
86 // delete/free them.
turaj@webrtc.org4c9b8192012-12-13 22:46:4387 if (ptr_vad_inst_ != NULL) {
88 WebRtcVad_Free(ptr_vad_inst_);
89 ptr_vad_inst_ = NULL;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:5190 }
turaj@webrtc.org4c9b8192012-12-13 22:46:4391 if (in_audio_ != NULL) {
92 delete[] in_audio_;
93 in_audio_ = NULL;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:5194 }
turaj@webrtc.org4c9b8192012-12-13 22:46:4395 if (in_timestamp_ != NULL) {
96 delete[] in_timestamp_;
97 in_timestamp_ = NULL;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:5198 }
turaj@webrtc.org4c9b8192012-12-13 22:46:4399 if (ptr_dtx_inst_ != NULL) {
100 WebRtcCng_FreeEnc(ptr_dtx_inst_);
101 ptr_dtx_inst_ = NULL;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51102 }
turaj@webrtc.org4c9b8192012-12-13 22:46:43103 delete &codec_wrapper_lock_;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23104}
105
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35106int32_t ACMGenericCodec::Add10MsData(const uint32_t timestamp,
107 const int16_t* data,
turaj@webrtc.org4c9b8192012-12-13 22:46:43108 const uint16_t length_smpl,
109 const uint8_t audio_channel) {
110 WriteLockScoped wl(codec_wrapper_lock_);
111 return Add10MsDataSafe(timestamp, data, length_smpl, audio_channel);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23112}
113
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35114int32_t ACMGenericCodec::Add10MsDataSafe(const uint32_t timestamp,
115 const int16_t* data,
turaj@webrtc.org4c9b8192012-12-13 22:46:43116 const uint16_t length_smpl,
117 const uint8_t audio_channel) {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35118 // The codec expects to get data in correct sampling rate. Get the sampling
119 // frequency of the codec.
turaj@webrtc.org4c9b8192012-12-13 22:46:43120 uint16_t plfreq_hz;
121 if (EncoderSampFreq(plfreq_hz) < 0) {
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51122 return -1;
123 }
124
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35125 // Sanity check to make sure the length of the input corresponds to 10 ms.
turaj@webrtc.org4c9b8192012-12-13 22:46:43126 if ((plfreq_hz / 100) != length_smpl) {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35127 // This is not 10 ms of audio, given the sampling frequency of the codec.
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51128 return -1;
129 }
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35130
turaj@webrtc.org4c9b8192012-12-13 22:46:43131 if (last_timestamp_ == timestamp) {
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51132 // Same timestamp as the last time, overwrite.
turaj@webrtc.org4c9b8192012-12-13 22:46:43133 if ((in_audio_ix_write_ >= length_smpl * audio_channel) &&
134 (in_timestamp_ix_write_ > 0)) {
135 in_audio_ix_write_ -= length_smpl * audio_channel;
136 in_timestamp_ix_write_--;
137 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceAudioCoding, unique_id_,
138 "Adding 10ms with previous timestamp, overwriting the "
139 "previous 10ms");
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51140 } else {
turaj@webrtc.org4c9b8192012-12-13 22:46:43141 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceAudioCoding, unique_id_,
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51142 "Adding 10ms with previous timestamp, this will sound bad");
andrew@webrtc.orgb015cbe2012-10-22 18:19:23143 }
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51144 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23145
turaj@webrtc.org4c9b8192012-12-13 22:46:43146 last_timestamp_ = timestamp;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23147
turaj@webrtc.org1952f252012-12-03 22:13:31148 // If the data exceeds the buffer size, we throw away the oldest data and
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35149 // add the newly received 10 msec at the end.
turaj@webrtc.org4c9b8192012-12-13 22:46:43150 if ((in_audio_ix_write_ + length_smpl * audio_channel) >
151 AUDIO_BUFFER_SIZE_W16) {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35152 // Get the number of samples to be overwritten.
turaj@webrtc.org4c9b8192012-12-13 22:46:43153 int16_t missed_samples = in_audio_ix_write_ + length_smpl * audio_channel -
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35154 AUDIO_BUFFER_SIZE_W16;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23155
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35156 // Move the data (overwrite the old data).
turaj@webrtc.org4c9b8192012-12-13 22:46:43157 memmove(in_audio_, in_audio_ + missed_samples,
158 (AUDIO_BUFFER_SIZE_W16 - length_smpl * audio_channel) *
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35159 sizeof(int16_t));
andrew@webrtc.orgb015cbe2012-10-22 18:19:23160
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35161 // Copy the new data.
turaj@webrtc.org4c9b8192012-12-13 22:46:43162 memcpy(in_audio_ + (AUDIO_BUFFER_SIZE_W16 - length_smpl * audio_channel),
163 data, length_smpl * audio_channel * sizeof(int16_t));
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35164
165 // Get the number of 10 ms blocks which are overwritten.
turaj@webrtc.org4c9b8192012-12-13 22:46:43166 int16_t missed_10ms_blocks =static_cast<int16_t>(
167 (missed_samples / audio_channel * 100) / plfreq_hz);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23168
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35169 // Move the timestamps.
turaj@webrtc.org4c9b8192012-12-13 22:46:43170 memmove(in_timestamp_, in_timestamp_ + missed_10ms_blocks,
171 (in_timestamp_ix_write_ - missed_10ms_blocks) * sizeof(uint32_t));
172 in_timestamp_ix_write_ -= missed_10ms_blocks;
173 in_timestamp_[in_timestamp_ix_write_] = timestamp;
174 in_timestamp_ix_write_++;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51175
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35176 // Buffer is full.
turaj@webrtc.org4c9b8192012-12-13 22:46:43177 in_audio_ix_write_ = AUDIO_BUFFER_SIZE_W16;
178 IncreaseNoMissedSamples(missed_samples);
179 is_audio_buff_fresh_ = false;
180 return -missed_samples;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51181 }
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35182
183 // Store the input data in our data buffer.
turaj@webrtc.org4c9b8192012-12-13 22:46:43184 memcpy(in_audio_ + in_audio_ix_write_, data,
185 length_smpl * audio_channel * sizeof(int16_t));
186 in_audio_ix_write_ += length_smpl * audio_channel;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51187
turaj@webrtc.org4c9b8192012-12-13 22:46:43188 assert(in_timestamp_ix_write_ < TIMESTAMP_BUFFER_SIZE_W32);
189 assert(in_timestamp_ix_write_ >= 0);
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51190
turaj@webrtc.org4c9b8192012-12-13 22:46:43191 in_timestamp_[in_timestamp_ix_write_] = timestamp;
192 in_timestamp_ix_write_++;
193 is_audio_buff_fresh_ = false;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51194 return 0;
195}
196
turaj@webrtc.org1952f252012-12-03 22:13:31197bool ACMGenericCodec::HasFrameToEncode() const {
turaj@webrtc.org4c9b8192012-12-13 22:46:43198 ReadLockScoped lockCodec(codec_wrapper_lock_);
199 if (in_audio_ix_write_ < frame_len_smpl_ * num_channels_)
turaj@webrtc.org1952f252012-12-03 22:13:31200 return false;
201 return true;
202}
203
turaj@webrtc.org4c9b8192012-12-13 22:46:43204int16_t ACMGenericCodec::Encode(uint8_t* bitstream,
205 int16_t* bitstream_len_byte,
206 uint32_t* timestamp,
207 WebRtcACMEncodingType* encoding_type) {
turaj@webrtc.org1952f252012-12-03 22:13:31208 if (!HasFrameToEncode()) {
209 // There is not enough audio
turaj@webrtc.org4c9b8192012-12-13 22:46:43210 *timestamp = 0;
211 *bitstream_len_byte = 0;
turaj@webrtc.org1952f252012-12-03 22:13:31212 // Doesn't really matter what this parameter set to
turaj@webrtc.org4c9b8192012-12-13 22:46:43213 *encoding_type = kNoEncoding;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23214 return 0;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51215 }
turaj@webrtc.org4c9b8192012-12-13 22:46:43216 WriteLockScoped lockCodec(codec_wrapper_lock_);
217 ReadLockScoped lockNetEq(*neteq_decode_lock_);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23218
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35219 // Not all codecs accept the whole frame to be pushed into encoder at once.
220 // Some codecs needs to be feed with a specific number of samples different
221 // from the frame size. If this is the case, |myBasicCodingBlockSmpl| will
222 // report a number different from 0, and we will loop over calls to encoder
223 // further down, until we have encode a complete frame.
turaj@webrtc.org4c9b8192012-12-13 22:46:43224 const int16_t my_basic_coding_block_smpl =
225 ACMCodecDB::BasicCodingBlock(codec_id_);
226 if (my_basic_coding_block_smpl < 0 || !encoder_initialized_ ||
227 !encoder_exist_) {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35228 // This should not happen, but in case it does, report no encoding done.
turaj@webrtc.org4c9b8192012-12-13 22:46:43229 *timestamp = 0;
230 *bitstream_len_byte = 0;
231 *encoding_type = kNoEncoding;
232 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51233 "EncodeSafe: error, basic coding sample block is negative");
234 return -1;
235 }
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35236 // This makes the internal encoder read from the beginning of the buffer.
turaj@webrtc.org4c9b8192012-12-13 22:46:43237 in_audio_ix_read_ = 0;
238 *timestamp = in_timestamp_[0];
andrew@webrtc.orgb015cbe2012-10-22 18:19:23239
turaj@webrtc.org4c9b8192012-12-13 22:46:43240 // Process the audio through VAD. The function will set |_vad_labels|.
241 // If VAD is disabled all entries in |_vad_labels| are set to ONE (active).
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35242 int16_t status = 0;
turaj@webrtc.org4c9b8192012-12-13 22:46:43243 int16_t dtx_processed_samples = 0;
244 status = ProcessFrameVADDTX(bitstream, bitstream_len_byte,
245 &dtx_processed_samples);
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51246 if (status < 0) {
turaj@webrtc.org4c9b8192012-12-13 22:46:43247 *timestamp = 0;
248 *bitstream_len_byte = 0;
249 *encoding_type = kNoEncoding;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51250 } else {
turaj@webrtc.org4c9b8192012-12-13 22:46:43251 if (dtx_processed_samples > 0) {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35252 // Dtx have processed some samples, and even if a bit-stream is generated
253 // we should not do any encoding (normally there won't be enough data).
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51254
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35255 // Setting the following makes sure that the move of audio data and
256 // timestamps done correctly.
turaj@webrtc.org4c9b8192012-12-13 22:46:43257 in_audio_ix_read_ = dtx_processed_samples;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51258 // This will let the owner of ACMGenericCodec to know that the
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35259 // generated bit-stream is DTX to use correct payload type.
turaj@webrtc.org4c9b8192012-12-13 22:46:43260 uint16_t samp_freq_hz;
261 EncoderSampFreq(samp_freq_hz);
262 if (samp_freq_hz == 8000) {
263 *encoding_type = kPassiveDTXNB;
264 } else if (samp_freq_hz == 16000) {
265 *encoding_type = kPassiveDTXWB;
266 } else if (samp_freq_hz == 32000) {
267 *encoding_type = kPassiveDTXSWB;
268 } else if (samp_freq_hz == 48000) {
269 *encoding_type = kPassiveDTXFB;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51270 } else {
271 status = -1;
turaj@webrtc.org4c9b8192012-12-13 22:46:43272 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51273 "EncodeSafe: Wrong sampling frequency for DTX.");
274 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23275
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35276 // Transport empty frame if we have an empty bitstream.
turaj@webrtc.org4c9b8192012-12-13 22:46:43277 if ((*bitstream_len_byte == 0) &&
278 (sent_cn_previous_ ||
279 ((in_audio_ix_write_ - in_audio_ix_read_) <= 0))) {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35280 // Makes sure we transmit an empty frame.
turaj@webrtc.org4c9b8192012-12-13 22:46:43281 *bitstream_len_byte = 1;
282 *encoding_type = kNoEncoding;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51283 }
turaj@webrtc.org4c9b8192012-12-13 22:46:43284 sent_cn_previous_ = true;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51285 } else {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35286 // We should encode the audio frame. Either VAD and/or DTX is off, or the
287 // audio was considered "active".
andrew@webrtc.orgb015cbe2012-10-22 18:19:23288
turaj@webrtc.org4c9b8192012-12-13 22:46:43289 sent_cn_previous_ = false;
290 if (my_basic_coding_block_smpl == 0) {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35291 // This codec can handle all allowed frame sizes as basic coding block.
turaj@webrtc.org4c9b8192012-12-13 22:46:43292 status = InternalEncode(bitstream, bitstream_len_byte);
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51293 if (status < 0) {
294 // TODO(tlegrand): Maybe reseting the encoder to be fresh for the next
295 // frame.
296 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding,
turaj@webrtc.org4c9b8192012-12-13 22:46:43297 unique_id_, "EncodeSafe: error in internal_encode");
298 *bitstream_len_byte = 0;
299 *encoding_type = kNoEncoding;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23300 }
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51301 } else {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35302 // A basic-coding-block for this codec is defined so we loop over the
303 // audio with the steps of the basic-coding-block.
turaj@webrtc.org4c9b8192012-12-13 22:46:43304 int16_t tmp_bitstream_len_byte;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23305
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35306 // Reset the variables which will be incremented in the loop.
turaj@webrtc.org4c9b8192012-12-13 22:46:43307 *bitstream_len_byte = 0;
tina.legrand@webrtc.orgcbb535a2013-07-03 09:25:34308 do {
turaj@webrtc.org4c9b8192012-12-13 22:46:43309 status = InternalEncode(&bitstream[*bitstream_len_byte],
310 &tmp_bitstream_len_byte);
311 *bitstream_len_byte += tmp_bitstream_len_byte;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23312
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35313 // Guard Against errors and too large payloads.
turaj@webrtc.org4c9b8192012-12-13 22:46:43314 if ((status < 0) || (*bitstream_len_byte > MAX_PAYLOAD_SIZE_BYTE)) {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35315 // Error has happened, and even if we are in the middle of a full
316 // frame we have to exit. Before exiting, whatever bits are in the
317 // buffer are probably corrupted, so we ignore them.
turaj@webrtc.org4c9b8192012-12-13 22:46:43318 *bitstream_len_byte = 0;
319 *encoding_type = kNoEncoding;
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35320 // We might have come here because of the second condition.
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51321 status = -1;
322 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding,
turaj@webrtc.org4c9b8192012-12-13 22:46:43323 unique_id_, "EncodeSafe: error in InternalEncode");
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51324 // break from the loop
325 break;
326 }
tina.legrand@webrtc.orgcbb535a2013-07-03 09:25:34327 } while (in_audio_ix_read_ < frame_len_smpl_ * num_channels_);
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51328 }
329 if (status >= 0) {
turaj@webrtc.org4c9b8192012-12-13 22:46:43330 *encoding_type = (vad_label_[0] == 1) ? kActiveNormalEncoded :
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51331 kPassiveNormalEncoded;
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35332 // Transport empty frame if we have an empty bitstream.
turaj@webrtc.org4c9b8192012-12-13 22:46:43333 if ((*bitstream_len_byte == 0) &&
334 ((in_audio_ix_write_ - in_audio_ix_read_) <= 0)) {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35335 // Makes sure we transmit an empty frame.
turaj@webrtc.org4c9b8192012-12-13 22:46:43336 *bitstream_len_byte = 1;
337 *encoding_type = kNoEncoding;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51338 }
339 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23340 }
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51341 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23342
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35343 // Move the timestamp buffer according to the number of 10 ms blocks
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51344 // which are read.
turaj@webrtc.org4c9b8192012-12-13 22:46:43345 uint16_t samp_freq_hz;
346 EncoderSampFreq(samp_freq_hz);
347 int16_t num_10ms_blocks = static_cast<int16_t>(
348 (in_audio_ix_read_ / num_channels_ * 100) / samp_freq_hz);
349 if (in_timestamp_ix_write_ > num_10ms_blocks) {
350 memmove(in_timestamp_, in_timestamp_ + num_10ms_blocks,
351 (in_timestamp_ix_write_ - num_10ms_blocks) * sizeof(int32_t));
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51352 }
turaj@webrtc.org4c9b8192012-12-13 22:46:43353 in_timestamp_ix_write_ -= num_10ms_blocks;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23354
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35355 // Remove encoded audio and move next audio to be encoded to the beginning
356 // of the buffer. Accordingly, adjust the read and write indices.
turaj@webrtc.org4c9b8192012-12-13 22:46:43357 if (in_audio_ix_read_ < in_audio_ix_write_) {
358 memmove(in_audio_, &in_audio_[in_audio_ix_read_],
359 (in_audio_ix_write_ - in_audio_ix_read_) * sizeof(int16_t));
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51360 }
turaj@webrtc.org4c9b8192012-12-13 22:46:43361 in_audio_ix_write_ -= in_audio_ix_read_;
362 in_audio_ix_read_ = 0;
363 last_encoded_timestamp_ = *timestamp;
364 return (status < 0) ? (-1) : (*bitstream_len_byte);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23365}
366
turaj@webrtc.org4c9b8192012-12-13 22:46:43367int16_t ACMGenericCodec::Decode(uint8_t* bitstream,
368 int16_t bitstream_len_byte,
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35369 int16_t* audio,
turaj@webrtc.org4c9b8192012-12-13 22:46:43370 int16_t* audio_samples,
371 int8_t* speech_type) {
372 WriteLockScoped wl(codec_wrapper_lock_);
373 return DecodeSafe(bitstream, bitstream_len_byte, audio, audio_samples,
374 speech_type);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23375}
376
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51377bool ACMGenericCodec::EncoderInitialized() {
turaj@webrtc.org4c9b8192012-12-13 22:46:43378 ReadLockScoped rl(codec_wrapper_lock_);
379 return encoder_initialized_;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23380}
381
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51382bool ACMGenericCodec::DecoderInitialized() {
turaj@webrtc.org4c9b8192012-12-13 22:46:43383 ReadLockScoped rl(codec_wrapper_lock_);
384 return decoder_initialized_;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23385}
386
turaj@webrtc.org4c9b8192012-12-13 22:46:43387int32_t ACMGenericCodec::RegisterInNetEq(ACMNetEQ* neteq,
388 const CodecInst& codec_inst) {
389 WebRtcNetEQ_CodecDef codec_def;
390 WriteLockScoped wl(codec_wrapper_lock_);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23391
turaj@webrtc.org4c9b8192012-12-13 22:46:43392 if (CodecDef(codec_def, codec_inst) < 0) {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35393 // Failed to register the decoder.
turaj@webrtc.org4c9b8192012-12-13 22:46:43394 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51395 "RegisterInNetEq: error, failed to register");
turaj@webrtc.org4c9b8192012-12-13 22:46:43396 registered_in_neteq_ = false;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51397 return -1;
398 } else {
turaj@webrtc.org4c9b8192012-12-13 22:46:43399 if (neteq->AddCodec(&codec_def, is_master_) < 0) {
400 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51401 "RegisterInNetEq: error, failed to add codec");
turaj@webrtc.org4c9b8192012-12-13 22:46:43402 registered_in_neteq_ = false;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51403 return -1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23404 }
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35405 // Succeeded registering the decoder.
turaj@webrtc.org4c9b8192012-12-13 22:46:43406 registered_in_neteq_ = true;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23407 return 0;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51408 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23409}
410
turaj@webrtc.org4c9b8192012-12-13 22:46:43411int16_t ACMGenericCodec::EncoderParams(WebRtcACMCodecParams* enc_params) {
412 ReadLockScoped rl(codec_wrapper_lock_);
413 return EncoderParamsSafe(enc_params);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23414}
415
turaj@webrtc.org4c9b8192012-12-13 22:46:43416int16_t ACMGenericCodec::EncoderParamsSafe(WebRtcACMCodecParams* enc_params) {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35417 // Codec parameters are valid only if the encoder is initialized.
turaj@webrtc.org4c9b8192012-12-13 22:46:43418 if (encoder_initialized_) {
419 int32_t current_rate;
420 memcpy(enc_params, &encoder_params_, sizeof(WebRtcACMCodecParams));
421 current_rate = enc_params->codec_inst.rate;
422 CurrentRate(current_rate);
423 enc_params->codec_inst.rate = current_rate;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51424 return 0;
425 } else {
turaj@webrtc.org4c9b8192012-12-13 22:46:43426 enc_params->codec_inst.plname[0] = '\0';
427 enc_params->codec_inst.pltype = -1;
428 enc_params->codec_inst.pacsize = 0;
429 enc_params->codec_inst.rate = 0;
430 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51431 "EncoderParamsSafe: error, encoder not initialized");
432 return -1;
433 }
434}
435
turaj@webrtc.org4c9b8192012-12-13 22:46:43436bool ACMGenericCodec::DecoderParams(WebRtcACMCodecParams* dec_params,
437 const uint8_t payload_type) {
438 ReadLockScoped rl(codec_wrapper_lock_);
439 return DecoderParamsSafe(dec_params, payload_type);
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51440}
441
turaj@webrtc.org4c9b8192012-12-13 22:46:43442bool ACMGenericCodec::DecoderParamsSafe(WebRtcACMCodecParams* dec_params,
443 const uint8_t payload_type) {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35444 // Decoder parameters are valid only if decoder is initialized.
turaj@webrtc.org4c9b8192012-12-13 22:46:43445 if (decoder_initialized_) {
446 if (payload_type == decoder_params_.codec_inst.pltype) {
447 memcpy(dec_params, &decoder_params_, sizeof(WebRtcACMCodecParams));
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51448 return true;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23449 }
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51450 }
451
turaj@webrtc.org4c9b8192012-12-13 22:46:43452 dec_params->codec_inst.plname[0] = '\0';
453 dec_params->codec_inst.pltype = -1;
454 dec_params->codec_inst.pacsize = 0;
455 dec_params->codec_inst.rate = 0;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51456 return false;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23457}
458
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35459int16_t ACMGenericCodec::ResetEncoder() {
turaj@webrtc.org4c9b8192012-12-13 22:46:43460 WriteLockScoped lockCodec(codec_wrapper_lock_);
461 ReadLockScoped lockNetEq(*neteq_decode_lock_);
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51462 return ResetEncoderSafe();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23463}
464
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35465int16_t ACMGenericCodec::ResetEncoderSafe() {
turaj@webrtc.org4c9b8192012-12-13 22:46:43466 if (!encoder_exist_ || !encoder_initialized_) {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35467 // We don't reset if encoder doesn't exists or isn't initialized yet.
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51468 return 0;
469 }
470
turaj@webrtc.org4c9b8192012-12-13 22:46:43471 in_audio_ix_write_ = 0;
472 in_audio_ix_read_ = 0;
473 in_timestamp_ix_write_ = 0;
474 num_missed_samples_ = 0;
475 is_audio_buff_fresh_ = true;
476 memset(in_audio_, 0, AUDIO_BUFFER_SIZE_W16 * sizeof(int16_t));
477 memset(in_timestamp_, 0, TIMESTAMP_BUFFER_SIZE_W32 * sizeof(int32_t));
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51478
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35479 // Store DTX/VAD parameters.
turaj@webrtc.org4c9b8192012-12-13 22:46:43480 bool enable_vad = vad_enabled_;
481 bool enable_dtx = dtx_enabled_;
482 ACMVADMode mode = vad_mode_;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51483
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35484 // Reset the encoder.
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51485 if (InternalResetEncoder() < 0) {
turaj@webrtc.org4c9b8192012-12-13 22:46:43486 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51487 "ResetEncoderSafe: error in reset encoder");
488 return -1;
489 }
490
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35491 // Disable DTX & VAD to delete the states and have a fresh start.
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51492 DisableDTX();
493 DisableVAD();
494
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35495 // Set DTX/VAD.
tina.legrand@webrtc.org584b6882013-08-27 07:33:51496 int status = SetVADSafe(&enable_dtx, &enable_vad, &mode);
497 vad_enabled_ = enable_dtx;
498 dtx_enabled_ = enable_vad;
499 vad_mode_ = mode;
500 return status;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51501}
502
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35503int16_t ACMGenericCodec::InternalResetEncoder() {
504 // Call the codecs internal encoder initialization/reset function.
turaj@webrtc.org4c9b8192012-12-13 22:46:43505 return InternalInitEncoder(&encoder_params_);
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51506}
507
turaj@webrtc.org4c9b8192012-12-13 22:46:43508int16_t ACMGenericCodec::InitEncoder(WebRtcACMCodecParams* codec_params,
509 bool force_initialization) {
510 WriteLockScoped lockCodec(codec_wrapper_lock_);
511 ReadLockScoped lockNetEq(*neteq_decode_lock_);
512 return InitEncoderSafe(codec_params, force_initialization);
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51513}
514
turaj@webrtc.org4c9b8192012-12-13 22:46:43515int16_t ACMGenericCodec::InitEncoderSafe(WebRtcACMCodecParams* codec_params,
516 bool force_initialization) {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35517 // Check if we got a valid set of parameters.
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51518 int mirrorID;
turaj@webrtc.org4c9b8192012-12-13 22:46:43519 int codec_number = ACMCodecDB::CodecNumber(&(codec_params->codec_inst),
520 &mirrorID);
521 if (codec_number < 0) {
522 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51523 "InitEncoderSafe: error, codec number negative");
524 return -1;
525 }
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35526 // Check if the parameters are for this codec.
turaj@webrtc.org4c9b8192012-12-13 22:46:43527 if ((codec_id_ >= 0) && (codec_id_ != codec_number) &&
528 (codec_id_ != mirrorID)) {
529 // The current codec is not the same as the one given by codec_params.
530 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
531 "InitEncoderSafe: current codec is not the same as the one "
532 "given by codec_params");
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51533 return -1;
534 }
535
turaj@webrtc.org4c9b8192012-12-13 22:46:43536 if (!CanChangeEncodingParam(codec_params->codec_inst)) {
537 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51538 "InitEncoderSafe: cannot change encoding parameters");
539 return -1;
540 }
541
turaj@webrtc.org4c9b8192012-12-13 22:46:43542 if (encoder_initialized_ && !force_initialization) {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35543 // The encoder is already initialized, and we don't want to force
544 // initialization.
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51545 return 0;
546 }
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35547 int16_t status;
turaj@webrtc.org4c9b8192012-12-13 22:46:43548 if (!encoder_exist_) {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35549 // New encoder, start with creating.
turaj@webrtc.org4c9b8192012-12-13 22:46:43550 encoder_initialized_ = false;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51551 status = CreateEncoder();
552 if (status < 0) {
turaj@webrtc.org4c9b8192012-12-13 22:46:43553 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51554 "InitEncoderSafe: cannot create encoder");
555 return -1;
556 } else {
turaj@webrtc.org4c9b8192012-12-13 22:46:43557 encoder_exist_ = true;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51558 }
559 }
turaj@webrtc.org4c9b8192012-12-13 22:46:43560 frame_len_smpl_ = (codec_params->codec_inst).pacsize;
561 num_channels_ = codec_params->codec_inst.channels;
562 status = InternalInitEncoder(codec_params);
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51563 if (status < 0) {
turaj@webrtc.org4c9b8192012-12-13 22:46:43564 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51565 "InitEncoderSafe: error in init encoder");
turaj@webrtc.org4c9b8192012-12-13 22:46:43566 encoder_initialized_ = false;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51567 return -1;
568 } else {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35569 // Store encoder parameters.
turaj@webrtc.org4c9b8192012-12-13 22:46:43570 memcpy(&encoder_params_, codec_params, sizeof(WebRtcACMCodecParams));
571 encoder_initialized_ = true;
572 if (in_audio_ == NULL) {
573 in_audio_ = new int16_t[AUDIO_BUFFER_SIZE_W16];
574 if (in_audio_ == NULL) {
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51575 return -1;
576 }
turaj@webrtc.org4c9b8192012-12-13 22:46:43577 memset(in_audio_, 0, AUDIO_BUFFER_SIZE_W16 * sizeof(int16_t));
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51578 }
turaj@webrtc.org4c9b8192012-12-13 22:46:43579 if (in_timestamp_ == NULL) {
580 in_timestamp_ = new uint32_t[TIMESTAMP_BUFFER_SIZE_W32];
581 if (in_timestamp_ == NULL) {
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51582 return -1;
583 }
turaj@webrtc.org4c9b8192012-12-13 22:46:43584 memset(in_timestamp_, 0, sizeof(uint32_t) * TIMESTAMP_BUFFER_SIZE_W32);
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51585 }
turaj@webrtc.org4c9b8192012-12-13 22:46:43586 is_audio_buff_fresh_ = true;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51587 }
tina.legrand@webrtc.org584b6882013-08-27 07:33:51588 status = SetVADSafe(&codec_params->enable_dtx, &codec_params->enable_vad,
589 &codec_params->vad_mode);
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51590
591 return status;
592}
593
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35594// TODO(tlegrand): Remove the function CanChangeEncodingParam. Returns true
595// for all codecs.
turaj@webrtc.org4c9b8192012-12-13 22:46:43596bool ACMGenericCodec::CanChangeEncodingParam(CodecInst& /*codec_inst*/) {
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51597 return true;
598}
599
pbos@webrtc.orgdd1b19d2013-07-31 15:54:00600void ACMGenericCodec::CurrentRate(int32_t& /* rate_bps */) {
601 return;
602}
603
turaj@webrtc.org4c9b8192012-12-13 22:46:43604int16_t ACMGenericCodec::InitDecoder(WebRtcACMCodecParams* codec_params,
605 bool force_initialization) {
606 WriteLockScoped lockCodc(codec_wrapper_lock_);
607 WriteLockScoped lockNetEq(*neteq_decode_lock_);
608 return InitDecoderSafe(codec_params, force_initialization);
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51609}
610
turaj@webrtc.org4c9b8192012-12-13 22:46:43611int16_t ACMGenericCodec::InitDecoderSafe(WebRtcACMCodecParams* codec_params,
612 bool force_initialization) {
613 int mirror_id;
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35614 // Check if we got a valid set of parameters.
turaj@webrtc.org4c9b8192012-12-13 22:46:43615 int codec_number = ACMCodecDB::ReceiverCodecNumber(&codec_params->codec_inst,
616 &mirror_id);
617 if (codec_number < 0) {
618 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51619 "InitDecoderSafe: error, invalid codec number");
620 return -1;
621 }
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35622 // Check if the parameters are for this codec.
turaj@webrtc.org4c9b8192012-12-13 22:46:43623 if ((codec_id_ >= 0) && (codec_id_ != codec_number) &&
624 (codec_id_ != mirror_id)) {
625 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
626 "InitDecoderSafe: current codec is not the same as the one "
627 "given by codec_params");
628 // The current codec is not the same as the one given by codec_params.
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51629 return -1;
630 }
631
turaj@webrtc.org4c9b8192012-12-13 22:46:43632 if (decoder_initialized_ && !force_initialization) {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35633 // The decoder is already initialized, and we don't want to force
634 // initialization.
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51635 return 0;
636 }
637
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35638 int16_t status;
turaj@webrtc.org4c9b8192012-12-13 22:46:43639 if (!decoder_exist_) {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35640 // New decoder, start with creating.
turaj@webrtc.org4c9b8192012-12-13 22:46:43641 decoder_initialized_ = false;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51642 status = CreateDecoder();
643 if (status < 0) {
turaj@webrtc.org4c9b8192012-12-13 22:46:43644 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51645 "InitDecoderSafe: cannot create decoder");
646 return -1;
647 } else {
turaj@webrtc.org4c9b8192012-12-13 22:46:43648 decoder_exist_ = true;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51649 }
650 }
651
turaj@webrtc.org4c9b8192012-12-13 22:46:43652 status = InternalInitDecoder(codec_params);
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51653 if (status < 0) {
turaj@webrtc.org4c9b8192012-12-13 22:46:43654 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51655 "InitDecoderSafe: cannot init decoder");
turaj@webrtc.org4c9b8192012-12-13 22:46:43656 decoder_initialized_ = false;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51657 return -1;
658 } else {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35659 // Store decoder parameters.
turaj@webrtc.org4c9b8192012-12-13 22:46:43660 SaveDecoderParamSafe(codec_params);
661 decoder_initialized_ = true;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51662 }
663 return 0;
664}
665
turaj@webrtc.org4c9b8192012-12-13 22:46:43666int16_t ACMGenericCodec::ResetDecoder(int16_t payload_type) {
667 WriteLockScoped lockCodec(codec_wrapper_lock_);
668 WriteLockScoped lockNetEq(*neteq_decode_lock_);
669 return ResetDecoderSafe(payload_type);
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51670}
671
turaj@webrtc.org4c9b8192012-12-13 22:46:43672int16_t ACMGenericCodec::ResetDecoderSafe(int16_t payload_type) {
673 WebRtcACMCodecParams decoder_params;
674 if (!decoder_exist_ || !decoder_initialized_) {
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51675 return 0;
676 }
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35677 // Initialization of the decoder should work for all the codec. For codecs
678 // that needs to keep some states an overloading implementation of
679 // |DecoderParamsSafe| exists.
turaj@webrtc.org4c9b8192012-12-13 22:46:43680 DecoderParamsSafe(&decoder_params, static_cast<uint8_t>(payload_type));
681 return InternalInitDecoder(&decoder_params);
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51682}
683
684void ACMGenericCodec::ResetNoMissedSamples() {
turaj@webrtc.org4c9b8192012-12-13 22:46:43685 WriteLockScoped cs(codec_wrapper_lock_);
686 num_missed_samples_ = 0;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51687}
688
turaj@webrtc.org4c9b8192012-12-13 22:46:43689void ACMGenericCodec::IncreaseNoMissedSamples(const int16_t num_samples) {
690 num_missed_samples_ += num_samples;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23691}
692
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35693// Get the number of missed samples, this can be public.
694uint32_t ACMGenericCodec::NoMissedSamples() const {
turaj@webrtc.org4c9b8192012-12-13 22:46:43695 ReadLockScoped cs(codec_wrapper_lock_);
696 return num_missed_samples_;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23697}
698
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51699void ACMGenericCodec::DestructEncoder() {
turaj@webrtc.org4c9b8192012-12-13 22:46:43700 WriteLockScoped wl(codec_wrapper_lock_);
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51701
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35702 // Disable VAD and delete the instance.
turaj@webrtc.org4c9b8192012-12-13 22:46:43703 if (ptr_vad_inst_ != NULL) {
704 WebRtcVad_Free(ptr_vad_inst_);
705 ptr_vad_inst_ = NULL;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51706 }
turaj@webrtc.org4c9b8192012-12-13 22:46:43707 vad_enabled_ = false;
708 vad_mode_ = VADNormal;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51709
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35710 // Disable DTX and delete the instance.
turaj@webrtc.org4c9b8192012-12-13 22:46:43711 dtx_enabled_ = false;
712 if (ptr_dtx_inst_ != NULL) {
713 WebRtcCng_FreeEnc(ptr_dtx_inst_);
714 ptr_dtx_inst_ = NULL;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51715 }
turaj@webrtc.org4c9b8192012-12-13 22:46:43716 num_lpc_params_ = kNewCNGNumPLCParams;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51717
718 DestructEncoderSafe();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23719}
720
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51721void ACMGenericCodec::DestructDecoder() {
turaj@webrtc.org4c9b8192012-12-13 22:46:43722 WriteLockScoped wl(codec_wrapper_lock_);
723 decoder_params_.codec_inst.pltype = -1;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51724 DestructDecoderSafe();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23725}
726
turaj@webrtc.org4c9b8192012-12-13 22:46:43727int16_t ACMGenericCodec::SetBitRate(const int32_t bitrate_bps) {
728 WriteLockScoped wl(codec_wrapper_lock_);
729 return SetBitRateSafe(bitrate_bps);
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51730}
731
turaj@webrtc.org4c9b8192012-12-13 22:46:43732int16_t ACMGenericCodec::SetBitRateSafe(const int32_t bitrate_bps) {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35733 // If the codec can change the bit-rate this function is overloaded.
734 // Otherwise the only acceptable value is the one that is in the database.
turaj@webrtc.org4c9b8192012-12-13 22:46:43735 CodecInst codec_params;
736 if (ACMCodecDB::Codec(codec_id_, &codec_params) < 0) {
737 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51738 "SetBitRateSafe: error in ACMCodecDB::Codec");
739 return -1;
740 }
turaj@webrtc.org4c9b8192012-12-13 22:46:43741 if (codec_params.rate != bitrate_bps) {
742 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51743 "SetBitRateSafe: rate value is not acceptable");
744 return -1;
745 } else {
746 return 0;
747 }
748}
749
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35750// iSAC specific functions:
751int32_t ACMGenericCodec::GetEstimatedBandwidth() {
turaj@webrtc.org4c9b8192012-12-13 22:46:43752 WriteLockScoped wl(codec_wrapper_lock_);
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51753 return GetEstimatedBandwidthSafe();
754}
755
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35756int32_t ACMGenericCodec::GetEstimatedBandwidthSafe() {
757 // All codecs but iSAC will return -1.
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51758 return -1;
759}
760
turaj@webrtc.org4c9b8192012-12-13 22:46:43761int32_t ACMGenericCodec::SetEstimatedBandwidth(int32_t estimated_bandwidth) {
762 WriteLockScoped wl(codec_wrapper_lock_);
763 return SetEstimatedBandwidthSafe(estimated_bandwidth);
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51764}
765
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35766int32_t ACMGenericCodec::SetEstimatedBandwidthSafe(
turaj@webrtc.org4c9b8192012-12-13 22:46:43767 int32_t /*estimated_bandwidth*/) {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35768 // All codecs but iSAC will return -1.
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51769 return -1;
770}
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35771// End of iSAC specific functions.
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51772
turaj@webrtc.org4c9b8192012-12-13 22:46:43773int32_t ACMGenericCodec::GetRedPayload(uint8_t* red_payload,
774 int16_t* payload_bytes) {
775 WriteLockScoped wl(codec_wrapper_lock_);
776 return GetRedPayloadSafe(red_payload, payload_bytes);
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51777}
778
turaj@webrtc.org4c9b8192012-12-13 22:46:43779int32_t ACMGenericCodec::GetRedPayloadSafe(uint8_t* /* red_payload */,
780 int16_t* /* payload_bytes */) {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35781 return -1; // Do nothing by default.
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51782}
783
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35784int16_t ACMGenericCodec::CreateEncoder() {
785 int16_t status = 0;
turaj@webrtc.org4c9b8192012-12-13 22:46:43786 if (!encoder_exist_) {
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51787 status = InternalCreateEncoder();
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35788 // We just created the codec and obviously it is not initialized.
turaj@webrtc.org4c9b8192012-12-13 22:46:43789 encoder_initialized_ = false;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51790 }
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51791 if (status < 0) {
turaj@webrtc.org4c9b8192012-12-13 22:46:43792 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51793 "CreateEncoder: error in internal create encoder");
turaj@webrtc.org4c9b8192012-12-13 22:46:43794 encoder_exist_ = false;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51795 } else {
turaj@webrtc.org4c9b8192012-12-13 22:46:43796 encoder_exist_ = true;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51797 }
798 return status;
799}
800
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35801int16_t ACMGenericCodec::CreateDecoder() {
802 int16_t status = 0;
turaj@webrtc.org4c9b8192012-12-13 22:46:43803 if (!decoder_exist_) {
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51804 status = InternalCreateDecoder();
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35805 // Decoder just created and obviously it is not initialized.
turaj@webrtc.org4c9b8192012-12-13 22:46:43806 decoder_initialized_ = false;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51807 }
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51808 if (status < 0) {
turaj@webrtc.org4c9b8192012-12-13 22:46:43809 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51810 "CreateDecoder: error in internal create decoder");
turaj@webrtc.org4c9b8192012-12-13 22:46:43811 decoder_exist_ = false;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51812 } else {
turaj@webrtc.org4c9b8192012-12-13 22:46:43813 decoder_exist_ = true;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51814 }
815 return status;
816}
817
turaj@webrtc.org4c9b8192012-12-13 22:46:43818void ACMGenericCodec::DestructEncoderInst(void* ptr_inst) {
819 if (ptr_inst != NULL) {
820 WriteLockScoped lockCodec(codec_wrapper_lock_);
821 ReadLockScoped lockNetEq(*neteq_decode_lock_);
822 InternalDestructEncoderInst(ptr_inst);
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51823 }
824}
825
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35826// Get the current audio buffer including read and write states, and timestamps.
turaj@webrtc.org4c9b8192012-12-13 22:46:43827int16_t ACMGenericCodec::AudioBuffer(WebRtcACMAudioBuff& audio_buff) {
828 ReadLockScoped cs(codec_wrapper_lock_);
829 memcpy(audio_buff.in_audio, in_audio_,
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35830 AUDIO_BUFFER_SIZE_W16 * sizeof(int16_t));
turaj@webrtc.org4c9b8192012-12-13 22:46:43831 audio_buff.in_audio_ix_read = in_audio_ix_read_;
832 audio_buff.in_audio_ix_write = in_audio_ix_write_;
833 memcpy(audio_buff.in_timestamp, in_timestamp_,
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35834 TIMESTAMP_BUFFER_SIZE_W32 * sizeof(uint32_t));
turaj@webrtc.org4c9b8192012-12-13 22:46:43835 audio_buff.in_timestamp_ix_write = in_timestamp_ix_write_;
836 audio_buff.last_timestamp = last_timestamp_;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51837 return 0;
838}
839
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35840// Set the audio buffer.
turaj@webrtc.org4c9b8192012-12-13 22:46:43841int16_t ACMGenericCodec::SetAudioBuffer(WebRtcACMAudioBuff& audio_buff) {
842 WriteLockScoped cs(codec_wrapper_lock_);
843 memcpy(in_audio_, audio_buff.in_audio,
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35844 AUDIO_BUFFER_SIZE_W16 * sizeof(int16_t));
turaj@webrtc.org4c9b8192012-12-13 22:46:43845 in_audio_ix_read_ = audio_buff.in_audio_ix_read;
846 in_audio_ix_write_ = audio_buff.in_audio_ix_write;
847 memcpy(in_timestamp_, audio_buff.in_timestamp,
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35848 TIMESTAMP_BUFFER_SIZE_W32 * sizeof(uint32_t));
turaj@webrtc.org4c9b8192012-12-13 22:46:43849 in_timestamp_ix_write_ = audio_buff.in_timestamp_ix_write;
850 last_timestamp_ = audio_buff.last_timestamp;
851 is_audio_buff_fresh_ = false;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51852 return 0;
853}
854
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35855uint32_t ACMGenericCodec::LastEncodedTimestamp() const {
turaj@webrtc.org4c9b8192012-12-13 22:46:43856 ReadLockScoped cs(codec_wrapper_lock_);
857 return last_encoded_timestamp_;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51858}
859
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35860uint32_t ACMGenericCodec::EarliestTimestamp() const {
turaj@webrtc.org4c9b8192012-12-13 22:46:43861 ReadLockScoped cs(codec_wrapper_lock_);
862 return in_timestamp_[0];
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51863}
864
tina.legrand@webrtc.org584b6882013-08-27 07:33:51865int16_t ACMGenericCodec::SetVAD(bool* enable_dtx, bool* enable_vad,
866 ACMVADMode* mode) {
turaj@webrtc.org4c9b8192012-12-13 22:46:43867 WriteLockScoped cs(codec_wrapper_lock_);
868 return SetVADSafe(enable_dtx, enable_vad, mode);
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51869}
870
tina.legrand@webrtc.org584b6882013-08-27 07:33:51871int16_t ACMGenericCodec::SetVADSafe(bool* enable_dtx, bool* enable_vad,
872 ACMVADMode* mode) {
873 if (!STR_CASE_CMP(encoder_params_.codec_inst.plname, "OPUS") ||
874 encoder_params_.codec_inst.channels == 2 ) {
875 // VAD/DTX is not supported for Opus (even if sending mono), or other
876 // stereo codecs.
877 DisableDTX();
878 DisableVAD();
879 *enable_dtx = false;
880 *enable_vad = false;
881 return 0;
882 }
883
884 if (*enable_dtx) {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35885 // Make G729 AnnexB a special case.
turaj@webrtc.org4c9b8192012-12-13 22:46:43886 if (!STR_CASE_CMP(encoder_params_.codec_inst.plname, "G729")
887 && !has_internal_dtx_) {
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51888 if (ACMGenericCodec::EnableDTX() < 0) {
turaj@webrtc.org4c9b8192012-12-13 22:46:43889 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51890 "SetVADSafe: error in enable DTX");
tina.legrand@webrtc.org584b6882013-08-27 07:33:51891 *enable_dtx = false;
892 *enable_vad = vad_enabled_;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23893 return -1;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51894 }
895 } else {
896 if (EnableDTX() < 0) {
turaj@webrtc.org4c9b8192012-12-13 22:46:43897 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51898 "SetVADSafe: error in enable DTX");
tina.legrand@webrtc.org584b6882013-08-27 07:33:51899 *enable_dtx = false;
900 *enable_vad = vad_enabled_;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23901 return -1;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51902 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23903 }
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51904
tina.legrand@webrtc.org584b6882013-08-27 07:33:51905 // If codec does not have internal DTX (normal case) enabling DTX requires
906 // an active VAD. '*enable_dtx == true' overwrites VAD status.
907 // If codec has internal DTX, practically we don't need WebRtc VAD, however,
908 // we let the user to turn it on if they need call-backs on silence.
909 if (!has_internal_dtx_) {
910 // DTX is enabled, and VAD will be activated.
911 *enable_vad = true;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23912 }
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51913 } else {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35914 // Make G729 AnnexB a special case.
turaj@webrtc.org4c9b8192012-12-13 22:46:43915 if (!STR_CASE_CMP(encoder_params_.codec_inst.plname, "G729")
916 && !has_internal_dtx_) {
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51917 ACMGenericCodec::DisableDTX();
tina.legrand@webrtc.org584b6882013-08-27 07:33:51918 *enable_dtx = false;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51919 } else {
920 DisableDTX();
tina.legrand@webrtc.org584b6882013-08-27 07:33:51921 *enable_dtx = false;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51922 }
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51923 }
tina.legrand@webrtc.org584b6882013-08-27 07:33:51924
925 int16_t status = (*enable_vad) ? EnableVAD(*mode) : DisableVAD();
926 if (status < 0) {
927 // Failed to set VAD, disable DTX.
928 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
929 "SetVADSafe: error in enable VAD");
930 DisableDTX();
931 *enable_dtx = false;
932 *enable_vad = false;
933 }
934 return status;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23935}
936
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35937int16_t ACMGenericCodec::EnableDTX() {
turaj@webrtc.org4c9b8192012-12-13 22:46:43938 if (has_internal_dtx_) {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35939 // We should not be here if we have internal DTX this function should be
940 // overloaded by the derived class in this case.
andrew@webrtc.orgb015cbe2012-10-22 18:19:23941 return -1;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51942 }
turaj@webrtc.org4c9b8192012-12-13 22:46:43943 if (!dtx_enabled_) {
944 if (WebRtcCng_CreateEnc(&ptr_dtx_inst_) < 0) {
945 ptr_dtx_inst_ = NULL;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51946 return -1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23947 }
turaj@webrtc.org4c9b8192012-12-13 22:46:43948 uint16_t freq_hz;
949 EncoderSampFreq(freq_hz);
950 if (WebRtcCng_InitEnc(ptr_dtx_inst_, freq_hz, kCngSidIntervalMsec,
951 num_lpc_params_) < 0) {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35952 // Couldn't initialize, has to return -1, and free the memory.
turaj@webrtc.org4c9b8192012-12-13 22:46:43953 WebRtcCng_FreeEnc(ptr_dtx_inst_);
954 ptr_dtx_inst_ = NULL;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51955 return -1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23956 }
turaj@webrtc.org4c9b8192012-12-13 22:46:43957 dtx_enabled_ = true;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51958 }
959 return 0;
960}
961
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35962int16_t ACMGenericCodec::DisableDTX() {
turaj@webrtc.org4c9b8192012-12-13 22:46:43963 if (has_internal_dtx_) {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35964 // We should not be here if we have internal DTX this function should be
965 // overloaded by the derived class in this case.
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51966 return -1;
967 }
turaj@webrtc.org4c9b8192012-12-13 22:46:43968 if (ptr_dtx_inst_ != NULL) {
969 WebRtcCng_FreeEnc(ptr_dtx_inst_);
970 ptr_dtx_inst_ = NULL;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51971 }
turaj@webrtc.org4c9b8192012-12-13 22:46:43972 dtx_enabled_ = false;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51973 return 0;
974}
975
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35976int16_t ACMGenericCodec::EnableVAD(ACMVADMode mode) {
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51977 if ((mode < VADNormal) || (mode > VADVeryAggr)) {
turaj@webrtc.org4c9b8192012-12-13 22:46:43978 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51979 "EnableVAD: error in VAD mode range");
980 return -1;
981 }
982
turaj@webrtc.org4c9b8192012-12-13 22:46:43983 if (!vad_enabled_) {
984 if (WebRtcVad_Create(&ptr_vad_inst_) < 0) {
985 ptr_vad_inst_ = NULL;
986 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51987 "EnableVAD: error in create VAD");
988 return -1;
989 }
turaj@webrtc.org4c9b8192012-12-13 22:46:43990 if (WebRtcVad_Init(ptr_vad_inst_) < 0) {
991 WebRtcVad_Free(ptr_vad_inst_);
992 ptr_vad_inst_ = NULL;
993 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:51994 "EnableVAD: error in init VAD");
995 return -1;
996 }
997 }
998
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:35999 // Set the VAD mode to the given value.
turaj@webrtc.org4c9b8192012-12-13 22:46:431000 if (WebRtcVad_set_mode(ptr_vad_inst_, mode) < 0) {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:351001 // We failed to set the mode and we have to return -1. If we already have a
turaj@webrtc.org4c9b8192012-12-13 22:46:431002 // working VAD (vad_enabled_ == true) then we leave it to work. Otherwise,
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:351003 // the following will be executed.
turaj@webrtc.org4c9b8192012-12-13 22:46:431004 if (!vad_enabled_) {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:351005 // We just created the instance but cannot set the mode we have to free
1006 // the memory.
turaj@webrtc.org4c9b8192012-12-13 22:46:431007 WebRtcVad_Free(ptr_vad_inst_);
1008 ptr_vad_inst_ = NULL;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511009 }
turaj@webrtc.org4c9b8192012-12-13 22:46:431010 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceAudioCoding, unique_id_,
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511011 "EnableVAD: failed to set the VAD mode");
1012 return -1;
1013 }
turaj@webrtc.org4c9b8192012-12-13 22:46:431014 vad_mode_ = mode;
1015 vad_enabled_ = true;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511016 return 0;
1017}
1018
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:351019int16_t ACMGenericCodec::DisableVAD() {
turaj@webrtc.org4c9b8192012-12-13 22:46:431020 if (ptr_vad_inst_ != NULL) {
1021 WebRtcVad_Free(ptr_vad_inst_);
1022 ptr_vad_inst_ = NULL;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511023 }
turaj@webrtc.org4c9b8192012-12-13 22:46:431024 vad_enabled_ = false;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511025 return 0;
1026}
1027
turaj@webrtc.org4c9b8192012-12-13 22:46:431028int32_t ACMGenericCodec::ReplaceInternalDTX(const bool replace_internal_dtx) {
1029 WriteLockScoped cs(codec_wrapper_lock_);
1030 return ReplaceInternalDTXSafe(replace_internal_dtx);
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511031}
1032
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:351033int32_t ACMGenericCodec::ReplaceInternalDTXSafe(
turaj@webrtc.org4c9b8192012-12-13 22:46:431034 const bool /* replace_internal_dtx */) {
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511035 return -1;
1036}
1037
turaj@webrtc.org4c9b8192012-12-13 22:46:431038int32_t ACMGenericCodec::IsInternalDTXReplaced(bool* internal_dtx_replaced) {
1039 WriteLockScoped cs(codec_wrapper_lock_);
1040 return IsInternalDTXReplacedSafe(internal_dtx_replaced);
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511041}
1042
turaj@webrtc.org4c9b8192012-12-13 22:46:431043int32_t ACMGenericCodec::IsInternalDTXReplacedSafe(
1044 bool* internal_dtx_replaced) {
1045 *internal_dtx_replaced = false;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511046 return 0;
1047}
1048
turaj@webrtc.org4c9b8192012-12-13 22:46:431049int16_t ACMGenericCodec::ProcessFrameVADDTX(uint8_t* bitstream,
1050 int16_t* bitstream_len_byte,
1051 int16_t* samples_processed) {
1052 if (!vad_enabled_) {
1053 // VAD not enabled, set all |vad_lable_[]| to 1 (speech detected).
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:351054 for (int n = 0; n < MAX_FRAME_SIZE_10MSEC; n++) {
turaj@webrtc.org4c9b8192012-12-13 22:46:431055 vad_label_[n] = 1;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511056 }
turaj@webrtc.org4c9b8192012-12-13 22:46:431057 *samples_processed = 0;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511058 return 0;
1059 }
1060
turaj@webrtc.org4c9b8192012-12-13 22:46:431061 uint16_t freq_hz;
1062 EncoderSampFreq(freq_hz);
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511063
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:351064 // Calculate number of samples in 10 ms blocks, and number ms in one frame.
turaj@webrtc.org4c9b8192012-12-13 22:46:431065 int16_t samples_in_10ms = static_cast<int16_t>(freq_hz / 100);
1066 int32_t frame_len_ms = static_cast<int32_t>(frame_len_smpl_) * 1000 / freq_hz;
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:351067 int16_t status;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511068
1069 // Vector for storing maximum 30 ms of mono audio at 48 kHz.
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:351070 int16_t audio[1440];
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511071
1072 // Calculate number of VAD-blocks to process, and number of samples in each
1073 // block.
turaj@webrtc.org4c9b8192012-12-13 22:46:431074 int num_samples_to_process[2];
1075 if (frame_len_ms == 40) {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:351076 // 20 ms in each VAD block.
turaj@webrtc.org4c9b8192012-12-13 22:46:431077 num_samples_to_process[0] = num_samples_to_process[1] = 2 * samples_in_10ms;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511078 } else {
1079 // For 10-30 ms framesizes, second VAD block will be size zero ms,
1080 // for 50 and 60 ms first VAD block will be 30 ms.
turaj@webrtc.org4c9b8192012-12-13 22:46:431081 num_samples_to_process[0] =
1082 (frame_len_ms > 30) ? 3 * samples_in_10ms : frame_len_smpl_;
1083 num_samples_to_process[1] = frame_len_smpl_ - num_samples_to_process[0];
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511084 }
1085
turaj@webrtc.org4c9b8192012-12-13 22:46:431086 int offset = 0;
1087 int loops = (num_samples_to_process[1] > 0) ? 2 : 1;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511088 for (int i = 0; i < loops; i++) {
turaj@webrtc.org4c9b8192012-12-13 22:46:431089 // TODO(turajs): Do we need to care about VAD together with stereo?
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:351090 // If stereo, calculate mean of the two channels.
turaj@webrtc.org4c9b8192012-12-13 22:46:431091 if (num_channels_ == 2) {
1092 for (int j = 0; j < num_samples_to_process[i]; j++) {
1093 audio[j] = (in_audio_[(offset + j) * 2] +
1094 in_audio_[(offset + j) * 2 + 1]) / 2;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511095 }
turaj@webrtc.org4c9b8192012-12-13 22:46:431096 offset = num_samples_to_process[0];
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511097 } else {
turaj@webrtc.org4c9b8192012-12-13 22:46:431098 // Mono, copy data from in_audio_ to continue work on.
1099 memcpy(audio, in_audio_, sizeof(int16_t) * num_samples_to_process[i]);
andrew@webrtc.orgb015cbe2012-10-22 18:19:231100 }
1101
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:351102 // Call VAD.
turaj@webrtc.org4c9b8192012-12-13 22:46:431103 status = static_cast<int16_t>(WebRtcVad_Process(ptr_vad_inst_,
1104 static_cast<int>(freq_hz),
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:351105 audio,
turaj@webrtc.org4c9b8192012-12-13 22:46:431106 num_samples_to_process[i]));
1107 vad_label_[i] = status;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511108
1109 if (status < 0) {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:351110 // This will force that the data be removed from the buffer.
turaj@webrtc.org4c9b8192012-12-13 22:46:431111 *samples_processed += num_samples_to_process[i];
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511112 return -1;
1113 }
1114
1115 // If VAD decision non-active, update DTX. NOTE! We only do this if the
1116 // first part of a frame gets the VAD decision "inactive". Otherwise DTX
1117 // might say it is time to transmit SID frame, but we will encode the whole
1118 // frame, because the first part is active.
turaj@webrtc.org4c9b8192012-12-13 22:46:431119 *samples_processed = 0;
1120 if ((status == 0) && (i == 0) && dtx_enabled_ && !has_internal_dtx_) {
1121 int16_t bitstream_len;
1122 int num_10ms_frames = num_samples_to_process[i] / samples_in_10ms;
1123 *bitstream_len_byte = 0;
1124 for (int n = 0; n < num_10ms_frames; n++) {
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511125 // This block is (passive) && (vad enabled). If first CNG after
1126 // speech, force SID by setting last parameter to "1".
turaj@webrtc.org4c9b8192012-12-13 22:46:431127 status = WebRtcCng_Encode(ptr_dtx_inst_, &audio[n * samples_in_10ms],
1128 samples_in_10ms, bitstream, &bitstream_len,
1129 !prev_frame_cng_);
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511130 if (status < 0) {
1131 return -1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:231132 }
1133
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511134 // Update previous frame was CNG.
turaj@webrtc.org4c9b8192012-12-13 22:46:431135 prev_frame_cng_ = 1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:231136
turaj@webrtc.org4c9b8192012-12-13 22:46:431137 *samples_processed += samples_in_10ms * num_channels_;
andrew@webrtc.orgb015cbe2012-10-22 18:19:231138
turaj@webrtc.org4c9b8192012-12-13 22:46:431139 // |bitstream_len_byte| will only be > 0 once per 100 ms.
1140 *bitstream_len_byte += bitstream_len;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511141 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:231142
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:351143 // Check if all samples got processed by the DTX.
turaj@webrtc.org4c9b8192012-12-13 22:46:431144 if (*samples_processed != num_samples_to_process[i] * num_channels_) {
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511145 // Set to zero since something went wrong. Shouldn't happen.
turaj@webrtc.org4c9b8192012-12-13 22:46:431146 *samples_processed = 0;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511147 }
1148 } else {
1149 // Update previous frame was not CNG.
turaj@webrtc.org4c9b8192012-12-13 22:46:431150 prev_frame_cng_ = 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:231151 }
1152
turaj@webrtc.org4c9b8192012-12-13 22:46:431153 if (*samples_processed > 0) {
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511154 // The block contains inactive speech, and is processed by DTX.
1155 // Discontinue running VAD.
1156 break;
1157 }
1158 }
1159
1160 return status;
andrew@webrtc.orgb015cbe2012-10-22 18:19:231161}
1162
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:351163int16_t ACMGenericCodec::SamplesLeftToEncode() {
turaj@webrtc.org4c9b8192012-12-13 22:46:431164 ReadLockScoped rl(codec_wrapper_lock_);
1165 return (frame_len_smpl_ <= in_audio_ix_write_) ? 0 :
1166 (frame_len_smpl_ - in_audio_ix_write_);
andrew@webrtc.orgb015cbe2012-10-22 18:19:231167}
1168
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:351169void ACMGenericCodec::SetUniqueID(const uint32_t id) {
turaj@webrtc.org4c9b8192012-12-13 22:46:431170 unique_id_ = id;
andrew@webrtc.orgb015cbe2012-10-22 18:19:231171}
1172
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511173bool ACMGenericCodec::IsAudioBufferFresh() const {
turaj@webrtc.org4c9b8192012-12-13 22:46:431174 ReadLockScoped rl(codec_wrapper_lock_);
1175 return is_audio_buff_fresh_;
andrew@webrtc.orgb015cbe2012-10-22 18:19:231176}
1177
pbos@webrtc.orgdd1b19d2013-07-31 15:54:001178int16_t ACMGenericCodec::UpdateDecoderSampFreq(int16_t /* codec_id */) {
1179 return 0;
1180}
1181
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:351182// This function is replaced by codec specific functions for some codecs.
turaj@webrtc.org4c9b8192012-12-13 22:46:431183int16_t ACMGenericCodec::EncoderSampFreq(uint16_t& samp_freq_hz) {
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:351184 int32_t f;
turaj@webrtc.org4c9b8192012-12-13 22:46:431185 f = ACMCodecDB::CodecFreq(codec_id_);
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511186 if (f < 0) {
turaj@webrtc.org4c9b8192012-12-13 22:46:431187 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511188 "EncoderSampFreq: codec frequency is negative");
andrew@webrtc.orgb015cbe2012-10-22 18:19:231189 return -1;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511190 } else {
turaj@webrtc.org4c9b8192012-12-13 22:46:431191 samp_freq_hz = static_cast<uint16_t>(f);
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511192 return 0;
1193 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:231194}
1195
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:351196int32_t ACMGenericCodec::ConfigISACBandwidthEstimator(
turaj@webrtc.org4c9b8192012-12-13 22:46:431197 const uint8_t /* init_frame_size_msec */,
1198 const uint16_t /* init_rate_bit_per_sec */,
1199 const bool /* enforce_frame_size */) {
1200 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, unique_id_,
1201 "The send-codec is not iSAC, failed to config iSAC bandwidth "
1202 "estimator.");
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511203 return -1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:231204}
1205
turaj@webrtc.org4c9b8192012-12-13 22:46:431206int32_t ACMGenericCodec::SetISACMaxRate(
1207 const uint32_t /* max_rate_bit_per_sec */) {
1208 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, unique_id_,
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511209 "The send-codec is not iSAC, failed to set iSAC max rate.");
1210 return -1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:231211}
1212
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:351213int32_t ACMGenericCodec::SetISACMaxPayloadSize(
turaj@webrtc.org4c9b8192012-12-13 22:46:431214 const uint16_t /* max_payload_len_bytes */) {
1215 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, unique_id_,
1216 "The send-codec is not iSAC, failed to set iSAC max "
1217 "payload-size.");
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511218 return -1;
1219}
1220
1221void ACMGenericCodec::SaveDecoderParam(
turaj@webrtc.org4c9b8192012-12-13 22:46:431222 const WebRtcACMCodecParams* codec_params) {
1223 WriteLockScoped wl(codec_wrapper_lock_);
1224 SaveDecoderParamSafe(codec_params);
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511225}
1226
1227void ACMGenericCodec::SaveDecoderParamSafe(
turaj@webrtc.org4c9b8192012-12-13 22:46:431228 const WebRtcACMCodecParams* codec_params) {
1229 memcpy(&decoder_params_, codec_params, sizeof(WebRtcACMCodecParams));
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511230}
1231
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:351232int16_t ACMGenericCodec::UpdateEncoderSampFreq(
turaj@webrtc.org4c9b8192012-12-13 22:46:431233 uint16_t /* samp_freq_hz */) {
1234 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
1235 "It is asked for a change in smapling frequency while the "
1236 "current send-codec supports only one sampling rate.");
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511237 return -1;
1238}
1239
turaj@webrtc.org4c9b8192012-12-13 22:46:431240void ACMGenericCodec::SetIsMaster(bool is_master) {
1241 WriteLockScoped wl(codec_wrapper_lock_);
1242 is_master_ = is_master;
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511243}
1244
turaj@webrtc.org4c9b8192012-12-13 22:46:431245int16_t ACMGenericCodec::REDPayloadISAC(const int32_t /* isac_rate */,
1246 const int16_t /* isac_bw_estimate */,
tina.legrand@webrtc.org2bd7fc72012-11-13 14:09:351247 uint8_t* /* payload */,
turaj@webrtc.org4c9b8192012-12-13 22:46:431248 int16_t* /* payload_len_bytes */) {
1249 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511250 "Error: REDPayloadISAC is an iSAC specific function");
1251 return -1;
1252}
1253
pbos@webrtc.orgdd1b19d2013-07-31 15:54:001254bool ACMGenericCodec::IsTrueStereoCodec() { return false; }
1255
turaj@webrtc.orged0b4fb2013-09-13 23:06:591256} // namespace acm1
1257
tina.legrand@webrtc.orgc0cf1db2012-11-05 09:35:511258} // namespace webrtc