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