1 /*
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
11 #include "webrtc/modules/audio_coding/main/acm2/acm_speex.h"
12
13 #ifdef WEBRTC_CODEC_SPEEX
14 // NOTE! Speex is not included in the open-source package. Modify this file or
15 // your codec API to match the function calls and names of used Speex API file.
16 #include "webrtc/modules/audio_coding/main/codecs/speex/interface/speex_interface.h"
17 #include "webrtc/modules/audio_coding/main/acm2/acm_codec_database.h"
18 #include "webrtc/modules/audio_coding/main/acm2/acm_common_defs.h"
19 #include "webrtc/system_wrappers/interface/trace.h"
20 #endif
21
22 namespace webrtc {
23
24 namespace acm2 {
25
26 #ifndef WEBRTC_CODEC_SPEEX
ACMSPEEX(int16_t)27 ACMSPEEX::ACMSPEEX(int16_t /* codec_id */)
28 : encoder_inst_ptr_(NULL),
29 compl_mode_(0),
30 vbr_enabled_(false),
31 encoding_rate_(-1),
32 sampling_frequency_(-1),
33 samples_in_20ms_audio_(-1) {
34 return;
35 }
36
~ACMSPEEX()37 ACMSPEEX::~ACMSPEEX() { return; }
38
InternalEncode(uint8_t *,int16_t *)39 int16_t ACMSPEEX::InternalEncode(uint8_t* /* bitstream */,
40 int16_t* /* bitstream_len_byte */) {
41 return -1;
42 }
43
EnableDTX()44 int16_t ACMSPEEX::EnableDTX() { return -1; }
45
DisableDTX()46 int16_t ACMSPEEX::DisableDTX() { return -1; }
47
InternalInitEncoder(WebRtcACMCodecParams *)48 int16_t ACMSPEEX::InternalInitEncoder(
49 WebRtcACMCodecParams* /* codec_params */) {
50 return -1;
51 }
52
CreateInstance(void)53 ACMGenericCodec* ACMSPEEX::CreateInstance(void) { return NULL; }
54
InternalCreateEncoder()55 int16_t ACMSPEEX::InternalCreateEncoder() { return -1; }
56
DestructEncoderSafe()57 void ACMSPEEX::DestructEncoderSafe() { return; }
58
SetBitRateSafe(const int32_t)59 int16_t ACMSPEEX::SetBitRateSafe(const int32_t /* rate */) { return -1; }
60
InternalDestructEncoderInst(void *)61 void ACMSPEEX::InternalDestructEncoderInst(void* /* ptr_inst */) { return; }
62
63 #ifdef UNUSEDSPEEX
EnableVBR()64 int16_t ACMSPEEX::EnableVBR() { return -1; }
65
DisableVBR()66 int16_t ACMSPEEX::DisableVBR() { return -1; }
67
SetComplMode(int16_t mode)68 int16_t ACMSPEEX::SetComplMode(int16_t mode) { return -1; }
69 #endif
70
71 #else //===================== Actual Implementation =======================
72
73 ACMSPEEX::ACMSPEEX(int16_t codec_id) : encoder_inst_ptr_(NULL) {
74 codec_id_ = codec_id;
75
76 // Set sampling frequency, frame size and rate Speex
77 if (codec_id_ == ACMCodecDB::kSPEEX8) {
78 sampling_frequency_ = 8000;
79 samples_in_20ms_audio_ = 160;
80 encoding_rate_ = 11000;
81 } else if (codec_id_ == ACMCodecDB::kSPEEX16) {
82 sampling_frequency_ = 16000;
83 samples_in_20ms_audio_ = 320;
84 encoding_rate_ = 22000;
85 } else {
86 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
87 "Wrong codec id for Speex.");
88
89 sampling_frequency_ = -1;
90 samples_in_20ms_audio_ = -1;
91 encoding_rate_ = -1;
92 }
93
94 has_internal_dtx_ = true;
95 dtx_enabled_ = false;
96 vbr_enabled_ = false;
97 compl_mode_ = 3; // default complexity value
98
99 return;
100 }
101
102 ACMSPEEX::~ACMSPEEX() {
103 if (encoder_inst_ptr_ != NULL) {
104 WebRtcSpeex_FreeEnc(encoder_inst_ptr_);
105 encoder_inst_ptr_ = NULL;
106 }
107 return;
108 }
109
110 int16_t ACMSPEEX::InternalEncode(uint8_t* bitstream,
111 int16_t* bitstream_len_byte) {
112 int16_t status;
113 int16_t num_encoded_samples = 0;
114 int16_t n = 0;
115
116 while (num_encoded_samples < frame_len_smpl_) {
117 status = WebRtcSpeex_Encode(
118 encoder_inst_ptr_, &in_audio_[in_audio_ix_read_], encoding_rate_);
119
120 // increment the read index this tell the caller that how far
121 // we have gone forward in reading the audio buffer
122 in_audio_ix_read_ += samples_in_20ms_audio_;
123 num_encoded_samples += samples_in_20ms_audio_;
124
125 if (status < 0) {
126 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
127 "Error in Speex encoder");
128 return status;
129 }
130
131 // Update VAD, if internal DTX is used
132 if (has_internal_dtx_ && dtx_enabled_) {
133 vad_label_[n++] = status;
134 vad_label_[n++] = status;
135 }
136
137 if (status == 0) {
138 // This frame is detected as inactive. We need send whatever
139 // encoded so far.
140 *bitstream_len_byte = WebRtcSpeex_GetBitstream(
141 encoder_inst_ptr_, reinterpret_cast<int16_t*>(bitstream));
142 return *bitstream_len_byte;
143 }
144 }
145
146 *bitstream_len_byte = WebRtcSpeex_GetBitstream(
147 encoder_inst_ptr_, reinterpret_cast<int16_t*>(bitstream));
148 return *bitstream_len_byte;
149 }
150
151 int16_t ACMSPEEX::EnableDTX() {
152 if (dtx_enabled_) {
153 return 0;
154 } else if (encoder_exist_) { // check if encoder exist
155 // enable DTX
156 if (WebRtcSpeex_EncoderInit(encoder_inst_ptr_, vbr_enabled_ ? 1 : 0,
157 compl_mode_, 1) < 0) {
158 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
159 "Cannot enable DTX for Speex");
160 return -1;
161 }
162 dtx_enabled_ = true;
163 return 0;
164 } else {
165 return -1;
166 }
167
168 return 0;
169 }
170
171 int16_t ACMSPEEX::DisableDTX() {
172 if (!dtx_enabled_) {
173 return 0;
174 } else if (encoder_exist_) { // check if encoder exist
175 // disable DTX
176 if (WebRtcSpeex_EncoderInit(encoder_inst_ptr_, (vbr_enabled_ ? 1 : 0),
177 compl_mode_, 0) < 0) {
178 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
179 "Cannot disable DTX for Speex");
180 return -1;
181 }
182 dtx_enabled_ = false;
183 return 0;
184 } else {
185 // encoder doesn't exists, therefore disabling is harmless
186 return 0;
187 }
188
189 return 0;
190 }
191
192 int16_t ACMSPEEX::InternalInitEncoder(WebRtcACMCodecParams* codec_params) {
193 // sanity check
194 if (encoder_inst_ptr_ == NULL) {
195 WEBRTC_TRACE(webrtc::kTraceError,
196 webrtc::kTraceAudioCoding,
197 unique_id_,
198 "Cannot initialize Speex encoder, instance does not exist");
199 return -1;
200 }
201
202 int16_t status = SetBitRateSafe((codec_params->codecInstant).rate);
203 status += (WebRtcSpeex_EncoderInit(encoder_inst_ptr_,
204 vbr_enabled_,
205 compl_mode_,
206 ((codec_params->enable_dtx) ? 1 : 0)) < 0)
207 ? -1
208 : 0;
209
210 if (status >= 0) {
211 return 0;
212 } else {
213 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
214 "Error in initialization of Speex encoder");
215 return -1;
216 }
217 }
218
219 ACMGenericCodec* ACMSPEEX::CreateInstance(void) { return NULL; }
220
221 int16_t ACMSPEEX::InternalCreateEncoder() {
222 return WebRtcSpeex_CreateEnc(&encoder_inst_ptr_, sampling_frequency_);
223 }
224
225 void ACMSPEEX::DestructEncoderSafe() {
226 if (encoder_inst_ptr_ != NULL) {
227 WebRtcSpeex_FreeEnc(encoder_inst_ptr_);
228 encoder_inst_ptr_ = NULL;
229 }
230 // there is no encoder set the following
231 encoder_exist_ = false;
232 encoder_initialized_ = false;
233 encoding_rate_ = 0;
234 }
235
236 int16_t ACMSPEEX::SetBitRateSafe(const int32_t rate) {
237 // Check if changed rate
238 if (rate == encoding_rate_) {
239 return 0;
240 } else if (rate > 2000) {
241 encoding_rate_ = rate;
242 encoder_params_.codecInstant.rate = rate;
243 } else {
244 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
245 "Unsupported encoding rate for Speex");
246
247 return -1;
248 }
249
250 return 0;
251 }
252
253 void ACMSPEEX::InternalDestructEncoderInst(void* ptr_inst) {
254 if (ptr_inst != NULL) {
255 WebRtcSpeex_FreeEnc(static_cast<SPEEX_encinst_t_*>(ptr_inst));
256 }
257 return;
258 }
259
260 #ifdef UNUSEDSPEEX
261
262 // This API is currently not in use. If requested to be able to enable/disable
263 // VBR an ACM API need to be added.
264 int16_t ACMSPEEX::EnableVBR() {
265 if (vbr_enabled_) {
266 return 0;
267 } else if (encoder_exist_) { // check if encoder exist
268 // enable Variable Bit Rate (VBR)
269 if (WebRtcSpeex_EncoderInit(encoder_inst_ptr_, 1, compl_mode_,
270 (dtx_enabled_ ? 1 : 0)) < 0) {
271 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
272 "Cannot enable VBR mode for Speex");
273
274 return -1;
275 }
276 vbr_enabled_ = true;
277 return 0;
278 } else {
279 return -1;
280 }
281 }
282
283 // This API is currently not in use. If requested to be able to enable/disable
284 // VBR an ACM API need to be added.
285 int16_t ACMSPEEX::DisableVBR() {
286 if (!vbr_enabled_) {
287 return 0;
288 } else if (encoder_exist_) { // check if encoder exist
289 // disable DTX
290 if (WebRtcSpeex_EncoderInit(encoder_inst_ptr_, 0, compl_mode_,
291 (dtx_enabled_ ? 1 : 0)) < 0) {
292 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
293 "Cannot disable DTX for Speex");
294
295 return -1;
296 }
297 vbr_enabled_ = false;
298 return 0;
299 } else {
300 // encoder doesn't exists, therefore disabling is harmless
301 return 0;
302 }
303 }
304
305 // This API is currently not in use. If requested to be able to set complexity
306 // an ACM API need to be added.
307 int16_t ACMSPEEX::SetComplMode(int16_t mode) {
308 // Check if new mode
309 if (mode == compl_mode_) {
310 return 0;
311 } else if (encoder_exist_) { // check if encoder exist
312 // Set new mode
313 if (WebRtcSpeex_EncoderInit(encoder_inst_ptr_, 0, mode,
314 (dtx_enabled_ ? 1 : 0)) < 0) {
315 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
316 "Error in complexity mode for Speex");
317 return -1;
318 }
319 compl_mode_ = mode;
320 return 0;
321 } else {
322 // encoder doesn't exists, therefore disabling is harmless
323 return 0;
324 }
325 }
326
327 #endif
328
329 #endif
330
331 } // namespace acm2
332
333 } // namespace webrtc
334