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
ACMG729(int16_t)29 ACMG729::ACMG729(int16_t /* codec_id */) : encoder_inst_ptr_(NULL) {}
30
~ACMG729()31 ACMG729::~ACMG729() { return; }
32
InternalEncode(uint8_t *,int16_t *)33 int16_t ACMG729::InternalEncode(uint8_t* /* bitstream */,
34 int16_t* /* bitstream_len_byte */) {
35 return -1;
36 }
37
EnableDTX()38 int16_t ACMG729::EnableDTX() { return -1; }
39
DisableDTX()40 int16_t ACMG729::DisableDTX() { return -1; }
41
ReplaceInternalDTXSafe(const bool)42 int32_t ACMG729::ReplaceInternalDTXSafe(const bool /*replace_internal_dtx */) {
43 return -1;
44 }
45
IsInternalDTXReplacedSafe(bool *)46 int32_t ACMG729::IsInternalDTXReplacedSafe(bool* /* internal_dtx_replaced */) {
47 return -1;
48 }
49
InternalInitEncoder(WebRtcACMCodecParams *)50 int16_t ACMG729::InternalInitEncoder(WebRtcACMCodecParams* /* codec_params */) {
51 return -1;
52 }
53
CreateInstance(void)54 ACMGenericCodec* ACMG729::CreateInstance(void) { return NULL; }
55
InternalCreateEncoder()56 int16_t ACMG729::InternalCreateEncoder() { return -1; }
57
DestructEncoderSafe()58 void ACMG729::DestructEncoderSafe() { return; }
59
InternalDestructEncoderInst(void *)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