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_opus.h" 12 13 #ifdef WEBRTC_CODEC_OPUS 14 #include "webrtc/modules/audio_coding/codecs/opus/interface/opus_interface.h" 15 #include "webrtc/modules/audio_coding/main/acm2/acm_codec_database.h" 16 #include "webrtc/modules/audio_coding/main/acm2/acm_common_defs.h" 17 #include "webrtc/system_wrappers/interface/trace.h" 18 #endif 19 20 namespace webrtc { 21 22 namespace acm2 { 23 24 #ifndef WEBRTC_CODEC_OPUS 25 26 ACMOpus::ACMOpus(int16_t /* codec_id */) 27 : encoder_inst_ptr_(NULL), 28 sample_freq_(0), 29 bitrate_(0), 30 channels_(1) { 31 return; 32 } 33 34 ACMOpus::~ACMOpus() { 35 return; 36 } 37 38 int16_t ACMOpus::InternalEncode(uint8_t* /* bitstream */, 39 int16_t* /* bitstream_len_byte */) { 40 return -1; 41 } 42 43 int16_t ACMOpus::InternalInitEncoder(WebRtcACMCodecParams* /* codec_params */) { 44 return -1; 45 } 46 47 ACMGenericCodec* ACMOpus::CreateInstance(void) { 48 return NULL; 49 } 50 51 int16_t ACMOpus::InternalCreateEncoder() { 52 return -1; 53 } 54 55 void ACMOpus::DestructEncoderSafe() { 56 return; 57 } 58 59 void ACMOpus::InternalDestructEncoderInst(void* /* ptr_inst */) { 60 return; 61 } 62 63 int16_t ACMOpus::SetBitRateSafe(const int32_t /*rate*/) { 64 return -1; 65 } 66 67 #else //===================== Actual Implementation ======================= 68 69 ACMOpus::ACMOpus(int16_t codec_id) 70 : encoder_inst_ptr_(NULL), 71 sample_freq_(32000), // Default sampling frequency. 72 bitrate_(20000), // Default bit-rate. 73 channels_(1) { // Default mono 74 codec_id_ = codec_id; 75 // Opus has internal DTX, but we dont use it for now. 76 has_internal_dtx_ = false; 77 78 has_internal_fec_ = true; 79 80 if (codec_id_ != ACMCodecDB::kOpus) { 81 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_, 82 "Wrong codec id for Opus."); 83 sample_freq_ = -1; 84 bitrate_ = -1; 85 } 86 return; 87 } 88 89 ACMOpus::~ACMOpus() { 90 if (encoder_inst_ptr_ != NULL) { 91 WebRtcOpus_EncoderFree(encoder_inst_ptr_); 92 encoder_inst_ptr_ = NULL; 93 } 94 } 95 96 int16_t ACMOpus::InternalEncode(uint8_t* bitstream, 97 int16_t* bitstream_len_byte) { 98 // Call Encoder. 99 *bitstream_len_byte = WebRtcOpus_Encode(encoder_inst_ptr_, 100 &in_audio_[in_audio_ix_read_], 101 frame_len_smpl_, 102 MAX_PAYLOAD_SIZE_BYTE, bitstream); 103 // Check for error reported from encoder. 104 if (*bitstream_len_byte < 0) { 105 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_, 106 "InternalEncode: Encode error for Opus"); 107 *bitstream_len_byte = 0; 108 return -1; 109 } 110 111 // Increment the read index. This tells the caller how far 112 // we have gone forward in reading the audio buffer. 113 in_audio_ix_read_ += frame_len_smpl_ * channels_; 114 115 return *bitstream_len_byte; 116 } 117 118 int16_t ACMOpus::InternalInitEncoder(WebRtcACMCodecParams* codec_params) { 119 int16_t ret; 120 if (encoder_inst_ptr_ != NULL) { 121 WebRtcOpus_EncoderFree(encoder_inst_ptr_); 122 encoder_inst_ptr_ = NULL; 123 } 124 ret = WebRtcOpus_EncoderCreate(&encoder_inst_ptr_, 125 codec_params->codec_inst.channels); 126 // Store number of channels. 127 channels_ = codec_params->codec_inst.channels; 128 129 if (ret < 0) { 130 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_, 131 "Encoder creation failed for Opus"); 132 return ret; 133 } 134 ret = WebRtcOpus_SetBitRate(encoder_inst_ptr_, 135 codec_params->codec_inst.rate); 136 if (ret < 0) { 137 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_, 138 "Setting initial bitrate failed for Opus"); 139 return ret; 140 } 141 142 // Store bitrate. 143 bitrate_ = codec_params->codec_inst.rate; 144 145 // TODO(tlegrand): Remove this code when we have proper APIs to set the 146 // complexity at a higher level. 147 #if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) || defined(WEBRTC_ARCH_ARM) 148 // If we are on Android, iOS and/or ARM, use a lower complexity setting as 149 // default, to save encoder complexity. 150 const int kOpusComplexity5 = 5; 151 WebRtcOpus_SetComplexity(encoder_inst_ptr_, kOpusComplexity5); 152 if (ret < 0) { 153 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_, 154 "Setting complexity failed for Opus"); 155 return ret; 156 } 157 #endif 158 159 return 0; 160 } 161 162 ACMGenericCodec* ACMOpus::CreateInstance(void) { 163 return NULL; 164 } 165 166 int16_t ACMOpus::InternalCreateEncoder() { 167 // Real encoder will be created in InternalInitEncoder. 168 return 0; 169 } 170 171 void ACMOpus::DestructEncoderSafe() { 172 if (encoder_inst_ptr_) { 173 WebRtcOpus_EncoderFree(encoder_inst_ptr_); 174 encoder_inst_ptr_ = NULL; 175 } 176 } 177 178 void ACMOpus::InternalDestructEncoderInst(void* ptr_inst) { 179 if (ptr_inst != NULL) { 180 WebRtcOpus_EncoderFree(static_cast<OpusEncInst*>(ptr_inst)); 181 } 182 return; 183 } 184 185 int16_t ACMOpus::SetBitRateSafe(const int32_t rate) { 186 if (rate < 6000 || rate > 510000) { 187 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_, 188 "SetBitRateSafe: Invalid rate Opus"); 189 return -1; 190 } 191 192 bitrate_ = rate; 193 194 // Ask the encoder for the new rate. 195 if (WebRtcOpus_SetBitRate(encoder_inst_ptr_, bitrate_) >= 0) { 196 encoder_params_.codec_inst.rate = bitrate_; 197 return 0; 198 } 199 200 return -1; 201 } 202 203 int ACMOpus::SetFEC(bool enable_fec) { 204 // Ask the encoder to enable FEC. 205 if (enable_fec) { 206 if (WebRtcOpus_EnableFec(encoder_inst_ptr_) == 0) { 207 fec_enabled_ = true; 208 return 0; 209 } 210 } else { 211 if (WebRtcOpus_DisableFec(encoder_inst_ptr_) == 0) { 212 fec_enabled_ = false; 213 return 0; 214 } 215 } 216 return -1; 217 } 218 219 int ACMOpus::SetPacketLossRate(int loss_rate) { 220 // Ask the encoder to change the target packet loss rate. 221 if (WebRtcOpus_SetPacketLossRate(encoder_inst_ptr_, loss_rate) == 0) { 222 packet_loss_rate_ = loss_rate; 223 return 0; 224 } 225 return -1; 226 } 227 228 #endif // WEBRTC_CODEC_OPUS 229 230 } // namespace acm2 231 232 } // namespace webrtc 233