Home | History | Annotate | Download | only in acm2
      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