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