• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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