1 /*
2 * Copyright (c) 2014 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/codecs/cng/audio_encoder_cng.h"
12
13 #include <algorithm>
14 #include <limits>
15
16 namespace webrtc {
17
18 namespace {
19
20 const int kMaxFrameSizeMs = 60;
21
CreateCngInst(int sample_rate_hz,int sid_frame_interval_ms,int num_cng_coefficients)22 rtc::scoped_ptr<CNG_enc_inst, CngInstDeleter> CreateCngInst(
23 int sample_rate_hz,
24 int sid_frame_interval_ms,
25 int num_cng_coefficients) {
26 rtc::scoped_ptr<CNG_enc_inst, CngInstDeleter> cng_inst;
27 RTC_CHECK_EQ(0, WebRtcCng_CreateEnc(cng_inst.accept()));
28 RTC_CHECK_EQ(0,
29 WebRtcCng_InitEnc(cng_inst.get(), sample_rate_hz,
30 sid_frame_interval_ms, num_cng_coefficients));
31 return cng_inst;
32 }
33
34 } // namespace
35
IsOk() const36 bool AudioEncoderCng::Config::IsOk() const {
37 if (num_channels != 1)
38 return false;
39 if (!speech_encoder)
40 return false;
41 if (num_channels != speech_encoder->NumChannels())
42 return false;
43 if (sid_frame_interval_ms <
44 static_cast<int>(speech_encoder->Max10MsFramesInAPacket() * 10))
45 return false;
46 if (num_cng_coefficients > WEBRTC_CNG_MAX_LPC_ORDER ||
47 num_cng_coefficients <= 0)
48 return false;
49 return true;
50 }
51
AudioEncoderCng(const Config & config)52 AudioEncoderCng::AudioEncoderCng(const Config& config)
53 : speech_encoder_(config.speech_encoder),
54 cng_payload_type_(config.payload_type),
55 num_cng_coefficients_(config.num_cng_coefficients),
56 sid_frame_interval_ms_(config.sid_frame_interval_ms),
57 last_frame_active_(true),
58 vad_(config.vad ? rtc_make_scoped_ptr(config.vad)
59 : CreateVad(config.vad_mode)) {
60 RTC_CHECK(config.IsOk()) << "Invalid configuration.";
61 cng_inst_ = CreateCngInst(SampleRateHz(), sid_frame_interval_ms_,
62 num_cng_coefficients_);
63 }
64
65 AudioEncoderCng::~AudioEncoderCng() = default;
66
MaxEncodedBytes() const67 size_t AudioEncoderCng::MaxEncodedBytes() const {
68 const size_t max_encoded_bytes_active = speech_encoder_->MaxEncodedBytes();
69 const size_t max_encoded_bytes_passive =
70 rtc::CheckedDivExact(kMaxFrameSizeMs, 10) * SamplesPer10msFrame();
71 return std::max(max_encoded_bytes_active, max_encoded_bytes_passive);
72 }
73
SampleRateHz() const74 int AudioEncoderCng::SampleRateHz() const {
75 return speech_encoder_->SampleRateHz();
76 }
77
NumChannels() const78 size_t AudioEncoderCng::NumChannels() const {
79 return 1;
80 }
81
RtpTimestampRateHz() const82 int AudioEncoderCng::RtpTimestampRateHz() const {
83 return speech_encoder_->RtpTimestampRateHz();
84 }
85
Num10MsFramesInNextPacket() const86 size_t AudioEncoderCng::Num10MsFramesInNextPacket() const {
87 return speech_encoder_->Num10MsFramesInNextPacket();
88 }
89
Max10MsFramesInAPacket() const90 size_t AudioEncoderCng::Max10MsFramesInAPacket() const {
91 return speech_encoder_->Max10MsFramesInAPacket();
92 }
93
GetTargetBitrate() const94 int AudioEncoderCng::GetTargetBitrate() const {
95 return speech_encoder_->GetTargetBitrate();
96 }
97
EncodeInternal(uint32_t rtp_timestamp,rtc::ArrayView<const int16_t> audio,size_t max_encoded_bytes,uint8_t * encoded)98 AudioEncoder::EncodedInfo AudioEncoderCng::EncodeInternal(
99 uint32_t rtp_timestamp,
100 rtc::ArrayView<const int16_t> audio,
101 size_t max_encoded_bytes,
102 uint8_t* encoded) {
103 RTC_CHECK_GE(max_encoded_bytes,
104 static_cast<size_t>(num_cng_coefficients_ + 1));
105 const size_t samples_per_10ms_frame = SamplesPer10msFrame();
106 RTC_CHECK_EQ(speech_buffer_.size(),
107 rtp_timestamps_.size() * samples_per_10ms_frame);
108 rtp_timestamps_.push_back(rtp_timestamp);
109 RTC_DCHECK_EQ(samples_per_10ms_frame, audio.size());
110 speech_buffer_.insert(speech_buffer_.end(), audio.cbegin(), audio.cend());
111 const size_t frames_to_encode = speech_encoder_->Num10MsFramesInNextPacket();
112 if (rtp_timestamps_.size() < frames_to_encode) {
113 return EncodedInfo();
114 }
115 RTC_CHECK_LE(static_cast<int>(frames_to_encode * 10), kMaxFrameSizeMs)
116 << "Frame size cannot be larger than " << kMaxFrameSizeMs
117 << " ms when using VAD/CNG.";
118
119 // Group several 10 ms blocks per VAD call. Call VAD once or twice using the
120 // following split sizes:
121 // 10 ms = 10 + 0 ms; 20 ms = 20 + 0 ms; 30 ms = 30 + 0 ms;
122 // 40 ms = 20 + 20 ms; 50 ms = 30 + 20 ms; 60 ms = 30 + 30 ms.
123 size_t blocks_in_first_vad_call =
124 (frames_to_encode > 3 ? 3 : frames_to_encode);
125 if (frames_to_encode == 4)
126 blocks_in_first_vad_call = 2;
127 RTC_CHECK_GE(frames_to_encode, blocks_in_first_vad_call);
128 const size_t blocks_in_second_vad_call =
129 frames_to_encode - blocks_in_first_vad_call;
130
131 // Check if all of the buffer is passive speech. Start with checking the first
132 // block.
133 Vad::Activity activity = vad_->VoiceActivity(
134 &speech_buffer_[0], samples_per_10ms_frame * blocks_in_first_vad_call,
135 SampleRateHz());
136 if (activity == Vad::kPassive && blocks_in_second_vad_call > 0) {
137 // Only check the second block if the first was passive.
138 activity = vad_->VoiceActivity(
139 &speech_buffer_[samples_per_10ms_frame * blocks_in_first_vad_call],
140 samples_per_10ms_frame * blocks_in_second_vad_call, SampleRateHz());
141 }
142
143 EncodedInfo info;
144 switch (activity) {
145 case Vad::kPassive: {
146 info = EncodePassive(frames_to_encode, max_encoded_bytes, encoded);
147 last_frame_active_ = false;
148 break;
149 }
150 case Vad::kActive: {
151 info = EncodeActive(frames_to_encode, max_encoded_bytes, encoded);
152 last_frame_active_ = true;
153 break;
154 }
155 case Vad::kError: {
156 FATAL(); // Fails only if fed invalid data.
157 break;
158 }
159 }
160
161 speech_buffer_.erase(
162 speech_buffer_.begin(),
163 speech_buffer_.begin() + frames_to_encode * samples_per_10ms_frame);
164 rtp_timestamps_.erase(rtp_timestamps_.begin(),
165 rtp_timestamps_.begin() + frames_to_encode);
166 return info;
167 }
168
Reset()169 void AudioEncoderCng::Reset() {
170 speech_encoder_->Reset();
171 speech_buffer_.clear();
172 rtp_timestamps_.clear();
173 last_frame_active_ = true;
174 vad_->Reset();
175 cng_inst_ = CreateCngInst(SampleRateHz(), sid_frame_interval_ms_,
176 num_cng_coefficients_);
177 }
178
SetFec(bool enable)179 bool AudioEncoderCng::SetFec(bool enable) {
180 return speech_encoder_->SetFec(enable);
181 }
182
SetDtx(bool enable)183 bool AudioEncoderCng::SetDtx(bool enable) {
184 return speech_encoder_->SetDtx(enable);
185 }
186
SetApplication(Application application)187 bool AudioEncoderCng::SetApplication(Application application) {
188 return speech_encoder_->SetApplication(application);
189 }
190
SetMaxPlaybackRate(int frequency_hz)191 void AudioEncoderCng::SetMaxPlaybackRate(int frequency_hz) {
192 speech_encoder_->SetMaxPlaybackRate(frequency_hz);
193 }
194
SetProjectedPacketLossRate(double fraction)195 void AudioEncoderCng::SetProjectedPacketLossRate(double fraction) {
196 speech_encoder_->SetProjectedPacketLossRate(fraction);
197 }
198
SetTargetBitrate(int bits_per_second)199 void AudioEncoderCng::SetTargetBitrate(int bits_per_second) {
200 speech_encoder_->SetTargetBitrate(bits_per_second);
201 }
202
EncodePassive(size_t frames_to_encode,size_t max_encoded_bytes,uint8_t * encoded)203 AudioEncoder::EncodedInfo AudioEncoderCng::EncodePassive(
204 size_t frames_to_encode,
205 size_t max_encoded_bytes,
206 uint8_t* encoded) {
207 bool force_sid = last_frame_active_;
208 bool output_produced = false;
209 const size_t samples_per_10ms_frame = SamplesPer10msFrame();
210 RTC_CHECK_GE(max_encoded_bytes, frames_to_encode * samples_per_10ms_frame);
211 AudioEncoder::EncodedInfo info;
212 for (size_t i = 0; i < frames_to_encode; ++i) {
213 // It's important not to pass &info.encoded_bytes directly to
214 // WebRtcCng_Encode(), since later loop iterations may return zero in that
215 // value, in which case we don't want to overwrite any value from an earlier
216 // iteration.
217 size_t encoded_bytes_tmp = 0;
218 RTC_CHECK_GE(WebRtcCng_Encode(cng_inst_.get(),
219 &speech_buffer_[i * samples_per_10ms_frame],
220 samples_per_10ms_frame, 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 info.encoded_timestamp = rtp_timestamps_.front();
231 info.payload_type = cng_payload_type_;
232 info.send_even_if_empty = true;
233 info.speech = false;
234 return info;
235 }
236
EncodeActive(size_t frames_to_encode,size_t max_encoded_bytes,uint8_t * encoded)237 AudioEncoder::EncodedInfo AudioEncoderCng::EncodeActive(
238 size_t frames_to_encode,
239 size_t max_encoded_bytes,
240 uint8_t* encoded) {
241 const size_t samples_per_10ms_frame = SamplesPer10msFrame();
242 AudioEncoder::EncodedInfo info;
243 for (size_t i = 0; i < frames_to_encode; ++i) {
244 info =
245 speech_encoder_->Encode(rtp_timestamps_.front(),
246 rtc::ArrayView<const int16_t>(
247 &speech_buffer_[i * samples_per_10ms_frame],
248 samples_per_10ms_frame),
249 max_encoded_bytes, encoded);
250 if (i + 1 == frames_to_encode) {
251 RTC_CHECK_GT(info.encoded_bytes, 0u) << "Encoder didn't deliver data.";
252 } else {
253 RTC_CHECK_EQ(info.encoded_bytes, 0u)
254 << "Encoder delivered data too early.";
255 }
256 }
257 return info;
258 }
259
SamplesPer10msFrame() const260 size_t AudioEncoderCng::SamplesPer10msFrame() const {
261 return rtc::CheckedDivExact(10 * SampleRateHz(), 1000);
262 }
263
264 } // namespace webrtc
265