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_g729.h"
     12 
     13 #ifdef WEBRTC_CODEC_G729
     14 // NOTE! G.729 is not included in the open-source package. Modify this file
     15 // or your codec API to match the function calls and names of used G.729 API
     16 // file.
     17 #include "webrtc/modules/audio_coding/main/codecs/g729/interface/g729_interface.h"
     18 #include "webrtc/modules/audio_coding/main/acm2/acm_common_defs.h"
     19 #include "webrtc/modules/audio_coding/main/acm2/acm_receiver.h"
     20 #include "webrtc/system_wrappers/interface/trace.h"
     21 #endif
     22 
     23 namespace webrtc {
     24 
     25 namespace acm2 {
     26 
     27 #ifndef WEBRTC_CODEC_G729
     28 
     29 ACMG729::ACMG729(int16_t /* codec_id */) : encoder_inst_ptr_(NULL) {}
     30 
     31 ACMG729::~ACMG729() { return; }
     32 
     33 int16_t ACMG729::InternalEncode(uint8_t* /* bitstream */,
     34                                 int16_t* /* bitstream_len_byte */) {
     35   return -1;
     36 }
     37 
     38 int16_t ACMG729::EnableDTX() { return -1; }
     39 
     40 int16_t ACMG729::DisableDTX() { return -1; }
     41 
     42 int32_t ACMG729::ReplaceInternalDTXSafe(const bool /*replace_internal_dtx */) {
     43   return -1;
     44 }
     45 
     46 int32_t ACMG729::IsInternalDTXReplacedSafe(bool* /* internal_dtx_replaced */) {
     47   return -1;
     48 }
     49 
     50 int16_t ACMG729::InternalInitEncoder(WebRtcACMCodecParams* /* codec_params */) {
     51   return -1;
     52 }
     53 
     54 ACMGenericCodec* ACMG729::CreateInstance(void) { return NULL; }
     55 
     56 int16_t ACMG729::InternalCreateEncoder() { return -1; }
     57 
     58 void ACMG729::DestructEncoderSafe() { return; }
     59 
     60 void ACMG729::InternalDestructEncoderInst(void* /* ptr_inst */) { return; }
     61 
     62 #else  //===================== Actual Implementation =======================
     63 ACMG729::ACMG729(int16_t codec_id)
     64     : codec_id_(codec_id),
     65       has_internal_dtx_(),
     66       encoder_inst_ptr_(NULL) {}
     67 
     68 ACMG729::~ACMG729() {
     69   if (encoder_inst_ptr_ != NULL) {
     70     // Delete encoder memory
     71     WebRtcG729_FreeEnc(encoder_inst_ptr_);
     72     encoder_inst_ptr_ = NULL;
     73   }
     74   return;
     75 }
     76 
     77 int16_t ACMG729::InternalEncode(uint8_t* bitstream,
     78                                 int16_t* bitstream_len_byte) {
     79   // Initialize before entering the loop
     80   int16_t num_encoded_samples = 0;
     81   int16_t tmp_len_byte = 0;
     82   int16_t vad_decision = 0;
     83   *bitstream_len_byte = 0;
     84   while (num_encoded_samples < frame_len_smpl_) {
     85     // Call G.729 encoder with pointer to encoder memory, input
     86     // audio, number of samples and bitsream
     87     tmp_len_byte = WebRtcG729_Encode(
     88         encoder_inst_ptr_, &in_audio_[in_audio_ix_read_], 80,
     89         reinterpret_cast<int16_t*>(&(bitstream[*bitstream_len_byte])));
     90 
     91     // increment the read index this tell the caller that how far
     92     // we have gone forward in reading the audio buffer
     93     in_audio_ix_read_ += 80;
     94 
     95     // sanity check
     96     if (tmp_len_byte < 0) {
     97       // error has happened
     98       *bitstream_len_byte = 0;
     99       return -1;
    100     }
    101 
    102     // increment number of written bytes
    103     *bitstream_len_byte += tmp_len_byte;
    104     switch (tmp_len_byte) {
    105       case 0: {
    106         if (0 == num_encoded_samples) {
    107           // this is the first 10 ms in this packet and there is
    108           // no data generated, perhaps DTX is enabled and the
    109           // codec is not generating any bit-stream for this 10 ms.
    110           // we do not continue encoding this frame.
    111           return 0;
    112         }
    113         break;
    114       }
    115       case 2: {
    116         // check if G.729 internal DTX is enabled
    117         if (has_internal_dtx_ && dtx_enabled_) {
    118           vad_decision = 0;
    119           for (int16_t n = 0; n < MAX_FRAME_SIZE_10MSEC; n++) {
    120             vad_label_[n] = vad_decision;
    121           }
    122         }
    123         // we got a SID and have to send out this packet no matter
    124         // how much audio we have encoded
    125         return *bitstream_len_byte;
    126       }
    127       case 10: {
    128         vad_decision = 1;
    129         // this is a valid length just continue encoding
    130         break;
    131       }
    132       default: {
    133         return -1;
    134       }
    135     }
    136 
    137     // update number of encoded samples
    138     num_encoded_samples += 80;
    139   }
    140 
    141   // update VAD decision vector
    142   if (has_internal_dtx_ && !vad_decision && dtx_enabled_) {
    143     for (int16_t n = 0; n < MAX_FRAME_SIZE_10MSEC; n++) {
    144       vad_label_[n] = vad_decision;
    145     }
    146   }
    147 
    148   // done encoding, return number of encoded bytes
    149   return *bitstream_len_byte;
    150 }
    151 
    152 int16_t ACMG729::EnableDTX() {
    153   if (dtx_enabled_) {
    154     // DTX already enabled, do nothing
    155     return 0;
    156   } else if (encoder_exist_) {
    157     // Re-init the G.729 encoder to turn on DTX
    158     if (WebRtcG729_EncoderInit(encoder_inst_ptr_, 1) < 0) {
    159       return -1;
    160     }
    161     dtx_enabled_ = true;
    162     return 0;
    163   } else {
    164     return -1;
    165   }
    166 }
    167 
    168 int16_t ACMG729::DisableDTX() {
    169   if (!dtx_enabled_) {
    170     // DTX already dissabled, do nothing
    171     return 0;
    172   } else if (encoder_exist_) {
    173     // Re-init the G.729 decoder to turn off DTX
    174     if (WebRtcG729_EncoderInit(encoder_inst_ptr_, 0) < 0) {
    175       return -1;
    176     }
    177     dtx_enabled_ = false;
    178     return 0;
    179   } else {
    180     // encoder doesn't exists, therefore disabling is harmless
    181     return 0;
    182   }
    183 }
    184 
    185 int32_t ACMG729::ReplaceInternalDTXSafe(const bool replace_internal_dtx) {
    186   // This function is used to disable the G.729 built in DTX and use an
    187   // external instead.
    188 
    189   if (replace_internal_dtx == has_internal_dtx_) {
    190     // Make sure we keep the DTX/VAD setting if possible
    191     bool old_enable_dtx = dtx_enabled_;
    192     bool old_enable_vad = vad_enabled_;
    193     ACMVADMode old_mode = vad_mode_;
    194     if (replace_internal_dtx) {
    195       // Disable internal DTX before enabling external DTX
    196       DisableDTX();
    197     } else {
    198       // Disable external DTX before enabling internal
    199       ACMGenericCodec::DisableDTX();
    200     }
    201     has_internal_dtx_ = !replace_internal_dtx;
    202     int16_t status = SetVADSafe(old_enable_dtx, old_enable_vad, old_mode);
    203     // Check if VAD status has changed from inactive to active, or if error was
    204     // reported
    205     if (status == 1) {
    206       vad_enabled_ = true;
    207       return status;
    208     } else if (status < 0) {
    209       has_internal_dtx_ = replace_internal_dtx;
    210       return -1;
    211     }
    212   }
    213   return 0;
    214 }
    215 
    216 int32_t ACMG729::IsInternalDTXReplacedSafe(bool* internal_dtx_replaced) {
    217   // Get status of wether DTX is replaced or not
    218   *internal_dtx_replaced = !has_internal_dtx_;
    219   return 0;
    220 }
    221 
    222 int16_t ACMG729::InternalInitEncoder(WebRtcACMCodecParams* codec_params) {
    223   // Init G.729 encoder
    224   return WebRtcG729_EncoderInit(encoder_inst_ptr_,
    225                                 ((codec_params->enable_dtx) ? 1 : 0));
    226 }
    227 
    228 ACMGenericCodec* ACMG729::CreateInstance(void) {
    229   // Function not used
    230   return NULL;
    231 }
    232 
    233 int16_t ACMG729::InternalCreateEncoder() {
    234   // Create encoder memory
    235   return WebRtcG729_CreateEnc(&encoder_inst_ptr_);
    236 }
    237 
    238 void ACMG729::DestructEncoderSafe() {
    239   // Free encoder memory
    240   encoder_exist_ = false;
    241   encoder_initialized_ = false;
    242   if (encoder_inst_ptr_ != NULL) {
    243     WebRtcG729_FreeEnc(encoder_inst_ptr_);
    244     encoder_inst_ptr_ = NULL;
    245   }
    246 }
    247 
    248 void ACMG729::InternalDestructEncoderInst(void* ptr_inst) {
    249   if (ptr_inst != NULL) {
    250     WebRtcG729_FreeEnc(static_cast<G729_encinst_t_*>(ptr_inst));
    251   }
    252   return;
    253 }
    254 
    255 #endif
    256 
    257 }  // namespace acm2
    258 
    259 }  // namespace webrtc
    260