| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 #include "webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng.h" | 11 #include "webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng.h" |
| 12 | 12 |
| 13 #include <algorithm> | 13 #include <algorithm> |
| 14 #include <memory> | 14 #include <memory> |
| 15 #include <limits> | 15 #include <limits> |
| 16 #include <utility> | 16 #include <utility> |
| 17 | 17 |
| 18 namespace webrtc { | 18 namespace webrtc { |
| 19 | 19 |
| 20 namespace { | 20 namespace { |
| 21 | 21 |
| 22 const int kMaxFrameSizeMs = 60; | 22 const int kMaxFrameSizeMs = 60; |
| 23 | 23 |
| 24 std::unique_ptr<CNG_enc_inst, CngInstDeleter> CreateCngInst( | |
| 25 int sample_rate_hz, | |
| 26 int sid_frame_interval_ms, | |
| 27 int num_cng_coefficients) { | |
| 28 CNG_enc_inst* ci; | |
| 29 RTC_CHECK_EQ(0, WebRtcCng_CreateEnc(&ci)); | |
| 30 std::unique_ptr<CNG_enc_inst, CngInstDeleter> cng_inst(ci); | |
| 31 RTC_CHECK_EQ(0, | |
| 32 WebRtcCng_InitEnc(cng_inst.get(), sample_rate_hz, | |
| 33 sid_frame_interval_ms, num_cng_coefficients)); | |
| 34 return cng_inst; | |
| 35 } | |
| 36 | |
| 37 } // namespace | 24 } // namespace |
| 38 | 25 |
| 39 AudioEncoderCng::Config::Config() = default; | 26 AudioEncoderCng::Config::Config() = default; |
| 40 AudioEncoderCng::Config::Config(Config&&) = default; | 27 AudioEncoderCng::Config::Config(Config&&) = default; |
| 41 AudioEncoderCng::Config::~Config() = default; | 28 AudioEncoderCng::Config::~Config() = default; |
| 42 | 29 |
| 43 bool AudioEncoderCng::Config::IsOk() const { | 30 bool AudioEncoderCng::Config::IsOk() const { |
| 44 if (num_channels != 1) | 31 if (num_channels != 1) |
| 45 return false; | 32 return false; |
| 46 if (!speech_encoder) | 33 if (!speech_encoder) |
| (...skipping 11 matching lines...) Expand all Loading... |
| 58 | 45 |
| 59 AudioEncoderCng::AudioEncoderCng(Config&& config) | 46 AudioEncoderCng::AudioEncoderCng(Config&& config) |
| 60 : speech_encoder_( | 47 : speech_encoder_( |
| 61 ([&] { RTC_CHECK(config.IsOk()) << "Invalid configuration."; }(), | 48 ([&] { RTC_CHECK(config.IsOk()) << "Invalid configuration."; }(), |
| 62 std::move(config.speech_encoder))), | 49 std::move(config.speech_encoder))), |
| 63 cng_payload_type_(config.payload_type), | 50 cng_payload_type_(config.payload_type), |
| 64 num_cng_coefficients_(config.num_cng_coefficients), | 51 num_cng_coefficients_(config.num_cng_coefficients), |
| 65 sid_frame_interval_ms_(config.sid_frame_interval_ms), | 52 sid_frame_interval_ms_(config.sid_frame_interval_ms), |
| 66 last_frame_active_(true), | 53 last_frame_active_(true), |
| 67 vad_(config.vad ? std::unique_ptr<Vad>(config.vad) | 54 vad_(config.vad ? std::unique_ptr<Vad>(config.vad) |
| 68 : CreateVad(config.vad_mode)) { | 55 : CreateVad(config.vad_mode)), |
| 69 cng_inst_ = CreateCngInst(SampleRateHz(), sid_frame_interval_ms_, | 56 cng_encoder_(new ComfortNoiseEncoder(SampleRateHz(), |
| 70 num_cng_coefficients_); | 57 sid_frame_interval_ms_, |
| 58 num_cng_coefficients_)) { |
| 71 } | 59 } |
| 72 | 60 |
| 73 AudioEncoderCng::~AudioEncoderCng() = default; | 61 AudioEncoderCng::~AudioEncoderCng() = default; |
| 74 | 62 |
| 75 int AudioEncoderCng::SampleRateHz() const { | 63 int AudioEncoderCng::SampleRateHz() const { |
| 76 return speech_encoder_->SampleRateHz(); | 64 return speech_encoder_->SampleRateHz(); |
| 77 } | 65 } |
| 78 | 66 |
| 79 size_t AudioEncoderCng::NumChannels() const { | 67 size_t AudioEncoderCng::NumChannels() const { |
| 80 return 1; | 68 return 1; |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 163 rtp_timestamps_.begin() + frames_to_encode); | 151 rtp_timestamps_.begin() + frames_to_encode); |
| 164 return info; | 152 return info; |
| 165 } | 153 } |
| 166 | 154 |
| 167 void AudioEncoderCng::Reset() { | 155 void AudioEncoderCng::Reset() { |
| 168 speech_encoder_->Reset(); | 156 speech_encoder_->Reset(); |
| 169 speech_buffer_.clear(); | 157 speech_buffer_.clear(); |
| 170 rtp_timestamps_.clear(); | 158 rtp_timestamps_.clear(); |
| 171 last_frame_active_ = true; | 159 last_frame_active_ = true; |
| 172 vad_->Reset(); | 160 vad_->Reset(); |
| 173 cng_inst_ = CreateCngInst(SampleRateHz(), sid_frame_interval_ms_, | 161 cng_encoder_.reset( |
| 174 num_cng_coefficients_); | 162 new ComfortNoiseEncoder(SampleRateHz(), sid_frame_interval_ms_, |
| 163 num_cng_coefficients_)); |
| 175 } | 164 } |
| 176 | 165 |
| 177 bool AudioEncoderCng::SetFec(bool enable) { | 166 bool AudioEncoderCng::SetFec(bool enable) { |
| 178 return speech_encoder_->SetFec(enable); | 167 return speech_encoder_->SetFec(enable); |
| 179 } | 168 } |
| 180 | 169 |
| 181 bool AudioEncoderCng::SetDtx(bool enable) { | 170 bool AudioEncoderCng::SetDtx(bool enable) { |
| 182 return speech_encoder_->SetDtx(enable); | 171 return speech_encoder_->SetDtx(enable); |
| 183 } | 172 } |
| 184 | 173 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 197 void AudioEncoderCng::SetTargetBitrate(int bits_per_second) { | 186 void AudioEncoderCng::SetTargetBitrate(int bits_per_second) { |
| 198 speech_encoder_->SetTargetBitrate(bits_per_second); | 187 speech_encoder_->SetTargetBitrate(bits_per_second); |
| 199 } | 188 } |
| 200 | 189 |
| 201 AudioEncoder::EncodedInfo AudioEncoderCng::EncodePassive( | 190 AudioEncoder::EncodedInfo AudioEncoderCng::EncodePassive( |
| 202 size_t frames_to_encode, | 191 size_t frames_to_encode, |
| 203 rtc::Buffer* encoded) { | 192 rtc::Buffer* encoded) { |
| 204 bool force_sid = last_frame_active_; | 193 bool force_sid = last_frame_active_; |
| 205 bool output_produced = false; | 194 bool output_produced = false; |
| 206 const size_t samples_per_10ms_frame = SamplesPer10msFrame(); | 195 const size_t samples_per_10ms_frame = SamplesPer10msFrame(); |
| 207 const size_t bytes_to_encode = frames_to_encode * samples_per_10ms_frame; | |
| 208 AudioEncoder::EncodedInfo info; | 196 AudioEncoder::EncodedInfo info; |
| 209 | 197 |
| 210 encoded->AppendData(bytes_to_encode, [&] (rtc::ArrayView<uint8_t> encoded) { | 198 for (size_t i = 0; i < frames_to_encode; ++i) { |
| 211 for (size_t i = 0; i < frames_to_encode; ++i) { | 199 // It's important not to pass &info.encoded_bytes directly to |
| 212 // It's important not to pass &info.encoded_bytes directly to | 200 // WebRtcCng_Encode(), since later loop iterations may return zero in |
| 213 // WebRtcCng_Encode(), since later loop iterations may return zero in | 201 // that value, in which case we don't want to overwrite any value from |
| 214 // that value, in which case we don't want to overwrite any value from | 202 // an earlier iteration. |
| 215 // an earlier iteration. | 203 size_t encoded_bytes_tmp = |
| 216 size_t encoded_bytes_tmp = 0; | 204 cng_encoder_->Encode( |
| 217 RTC_CHECK_GE( | 205 rtc::ArrayView<const int16_t>( |
| 218 WebRtcCng_Encode(cng_inst_.get(), | 206 &speech_buffer_[i * samples_per_10ms_frame], |
| 219 &speech_buffer_[i * samples_per_10ms_frame], | 207 samples_per_10ms_frame), |
| 220 samples_per_10ms_frame, encoded.data(), | 208 force_sid, encoded); |
| 221 &encoded_bytes_tmp, force_sid), | |
| 222 0); | |
| 223 if (encoded_bytes_tmp > 0) { | |
| 224 RTC_CHECK(!output_produced); | |
| 225 info.encoded_bytes = encoded_bytes_tmp; | |
| 226 output_produced = true; | |
| 227 force_sid = false; | |
| 228 } | |
| 229 } | |
| 230 | 209 |
| 231 return info.encoded_bytes; | 210 if (encoded_bytes_tmp > 0) { |
| 232 }); | 211 RTC_CHECK(!output_produced); |
| 212 info.encoded_bytes = encoded_bytes_tmp; |
| 213 output_produced = true; |
| 214 force_sid = false; |
| 215 } |
| 216 } |
| 233 | 217 |
| 234 info.encoded_timestamp = rtp_timestamps_.front(); | 218 info.encoded_timestamp = rtp_timestamps_.front(); |
| 235 info.payload_type = cng_payload_type_; | 219 info.payload_type = cng_payload_type_; |
| 236 info.send_even_if_empty = true; | 220 info.send_even_if_empty = true; |
| 237 info.speech = false; | 221 info.speech = false; |
| 238 return info; | 222 return info; |
| 239 } | 223 } |
| 240 | 224 |
| 241 AudioEncoder::EncodedInfo AudioEncoderCng::EncodeActive( | 225 AudioEncoder::EncodedInfo AudioEncoderCng::EncodeActive( |
| 242 size_t frames_to_encode, | 226 size_t frames_to_encode, |
| (...skipping 15 matching lines...) Expand all Loading... |
| 258 } | 242 } |
| 259 } | 243 } |
| 260 return info; | 244 return info; |
| 261 } | 245 } |
| 262 | 246 |
| 263 size_t AudioEncoderCng::SamplesPer10msFrame() const { | 247 size_t AudioEncoderCng::SamplesPer10msFrame() const { |
| 264 return rtc::CheckedDivExact(10 * SampleRateHz(), 1000); | 248 return rtc::CheckedDivExact(10 * SampleRateHz(), 1000); |
| 265 } | 249 } |
| 266 | 250 |
| 267 } // namespace webrtc | 251 } // namespace webrtc |
| OLD | NEW |