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 |
(...skipping 15 matching lines...) Expand all Loading... | |
26 const int kMaxBitrateBps = 512000; | 26 const int kMaxBitrateBps = 512000; |
27 | 27 |
28 AudioEncoderOpus::Config CreateConfig(const CodecInst& codec_inst) { | 28 AudioEncoderOpus::Config CreateConfig(const CodecInst& codec_inst) { |
29 AudioEncoderOpus::Config config; | 29 AudioEncoderOpus::Config config; |
30 config.frame_size_ms = rtc::CheckedDivExact(codec_inst.pacsize, 48); | 30 config.frame_size_ms = rtc::CheckedDivExact(codec_inst.pacsize, 48); |
31 config.num_channels = codec_inst.channels; | 31 config.num_channels = codec_inst.channels; |
32 config.bitrate_bps = rtc::Optional<int>(codec_inst.rate); | 32 config.bitrate_bps = rtc::Optional<int>(codec_inst.rate); |
33 config.payload_type = codec_inst.pltype; | 33 config.payload_type = codec_inst.pltype; |
34 config.application = config.num_channels == 1 ? AudioEncoderOpus::kVoip | 34 config.application = config.num_channels == 1 ? AudioEncoderOpus::kVoip |
35 : AudioEncoderOpus::kAudio; | 35 : AudioEncoderOpus::kAudio; |
36 config.audio_network_adaptor_enabled = false; | |
36 return config; | 37 return config; |
37 } | 38 } |
38 | 39 |
39 // Optimize the loss rate to configure Opus. Basically, optimized loss rate is | 40 // Optimize the loss rate to configure Opus. Basically, optimized loss rate is |
40 // the input loss rate rounded down to various levels, because a robustly good | 41 // the input loss rate rounded down to various levels, because a robustly good |
41 // audio quality is achieved by lowering the packet loss down. | 42 // audio quality is achieved by lowering the packet loss down. |
42 // Additionally, to prevent toggling, margins are used, i.e., when jumping to | 43 // Additionally, to prevent toggling, margins are used, i.e., when jumping to |
43 // a loss rate from below, a higher threshold is used than jumping to the same | 44 // a loss rate from below, a higher threshold is used than jumping to the same |
44 // level from above. | 45 // level from above. |
45 double OptimizePacketLossRate(double new_loss_rate, double old_loss_rate) { | 46 double OptimizePacketLossRate(double new_loss_rate, double old_loss_rate) { |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
97 } | 98 } |
98 | 99 |
99 int AudioEncoderOpus::Config::GetBitrateBps() const { | 100 int AudioEncoderOpus::Config::GetBitrateBps() const { |
100 RTC_DCHECK(IsOk()); | 101 RTC_DCHECK(IsOk()); |
101 if (bitrate_bps) | 102 if (bitrate_bps) |
102 return *bitrate_bps; // Explicitly set value. | 103 return *bitrate_bps; // Explicitly set value. |
103 else | 104 else |
104 return num_channels == 1 ? 32000 : 64000; // Default value. | 105 return num_channels == 1 ? 32000 : 64000; // Default value. |
105 } | 106 } |
106 | 107 |
107 AudioEncoderOpus::AudioEncoderOpus(const Config& config) | 108 AudioEncoderOpus::AudioEncoderOpus( |
108 : packet_loss_rate_(0.0), inst_(nullptr) { | 109 const Config& config, |
110 std::unique_ptr<AudioNetworkAdaptor> audio_network_adaptor) | |
111 : packet_loss_rate_(0.0), | |
112 inst_(nullptr), | |
113 audio_network_adaptor_(std::move(audio_network_adaptor)) { | |
109 RTC_CHECK(RecreateEncoderInstance(config)); | 114 RTC_CHECK(RecreateEncoderInstance(config)); |
110 } | 115 } |
111 | 116 |
112 AudioEncoderOpus::AudioEncoderOpus(const CodecInst& codec_inst) | 117 AudioEncoderOpus::AudioEncoderOpus(const CodecInst& codec_inst) |
113 : AudioEncoderOpus(CreateConfig(codec_inst)) {} | 118 : AudioEncoderOpus(CreateConfig(codec_inst), nullptr) {} |
114 | 119 |
115 AudioEncoderOpus::~AudioEncoderOpus() { | 120 AudioEncoderOpus::~AudioEncoderOpus() { |
116 RTC_CHECK_EQ(0, WebRtcOpus_EncoderFree(inst_)); | 121 RTC_CHECK_EQ(0, WebRtcOpus_EncoderFree(inst_)); |
117 } | 122 } |
118 | 123 |
119 int AudioEncoderOpus::SampleRateHz() const { | 124 int AudioEncoderOpus::SampleRateHz() const { |
120 return kSampleRateHz; | 125 return kSampleRateHz; |
121 } | 126 } |
122 | 127 |
123 size_t AudioEncoderOpus::NumChannels() const { | 128 size_t AudioEncoderOpus::NumChannels() const { |
(...skipping 10 matching lines...) Expand all Loading... | |
134 | 139 |
135 int AudioEncoderOpus::GetTargetBitrate() const { | 140 int AudioEncoderOpus::GetTargetBitrate() const { |
136 return config_.GetBitrateBps(); | 141 return config_.GetBitrateBps(); |
137 } | 142 } |
138 | 143 |
139 void AudioEncoderOpus::Reset() { | 144 void AudioEncoderOpus::Reset() { |
140 RTC_CHECK(RecreateEncoderInstance(config_)); | 145 RTC_CHECK(RecreateEncoderInstance(config_)); |
141 } | 146 } |
142 | 147 |
143 bool AudioEncoderOpus::SetFec(bool enable) { | 148 bool AudioEncoderOpus::SetFec(bool enable) { |
144 auto conf = config_; | 149 if (enable) { |
145 conf.fec_enabled = enable; | 150 RTC_CHECK_EQ(0, WebRtcOpus_EnableFec(inst_)); |
146 return RecreateEncoderInstance(conf); | 151 } else { |
152 RTC_CHECK_EQ(0, WebRtcOpus_DisableFec(inst_)); | |
153 } | |
154 config_.fec_enabled = enable; | |
155 return true; | |
147 } | 156 } |
148 | 157 |
149 bool AudioEncoderOpus::SetDtx(bool enable) { | 158 bool AudioEncoderOpus::SetDtx(bool enable) { |
150 auto conf = config_; | 159 if (enable) { |
151 conf.dtx_enabled = enable; | 160 RTC_CHECK_EQ(0, WebRtcOpus_EnableDtx(inst_)); |
152 return RecreateEncoderInstance(conf); | 161 } else { |
162 RTC_CHECK_EQ(0, WebRtcOpus_DisableDtx(inst_)); | |
163 } | |
164 config_.dtx_enabled = enable; | |
165 return true; | |
153 } | 166 } |
154 | 167 |
155 bool AudioEncoderOpus::GetDtx() const { | 168 bool AudioEncoderOpus::GetDtx() const { |
156 return config_.dtx_enabled; | 169 return config_.dtx_enabled; |
157 } | 170 } |
158 | 171 |
159 bool AudioEncoderOpus::SetApplication(Application application) { | 172 bool AudioEncoderOpus::SetApplication(Application application) { |
160 auto conf = config_; | 173 auto conf = config_; |
161 switch (application) { | 174 switch (application) { |
162 case Application::kSpeech: | 175 case Application::kSpeech: |
(...skipping 22 matching lines...) Expand all Loading... | |
185 } | 198 } |
186 } | 199 } |
187 | 200 |
188 void AudioEncoderOpus::SetTargetBitrate(int bits_per_second) { | 201 void AudioEncoderOpus::SetTargetBitrate(int bits_per_second) { |
189 config_.bitrate_bps = rtc::Optional<int>( | 202 config_.bitrate_bps = rtc::Optional<int>( |
190 std::max(std::min(bits_per_second, kMaxBitrateBps), kMinBitrateBps)); | 203 std::max(std::min(bits_per_second, kMaxBitrateBps), kMinBitrateBps)); |
191 RTC_DCHECK(config_.IsOk()); | 204 RTC_DCHECK(config_.IsOk()); |
192 RTC_CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, config_.GetBitrateBps())); | 205 RTC_CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, config_.GetBitrateBps())); |
193 } | 206 } |
194 | 207 |
208 bool AudioEncoderOpus::SetAudioNetworkAdaptor(bool enable) { | |
209 if (config_.audio_network_adaptor_enabled == enable) | |
210 return true; | |
211 config_.audio_network_adaptor_enabled = enable; | |
212 if (config_.audio_network_adaptor_enabled) { | |
213 // TODO(minyue): Create AudioNetworkAdaptorImpl. | |
214 } else { | |
215 audio_network_adaptor_.reset(nullptr); | |
216 } | |
217 return true; | |
218 } | |
kwiberg-webrtc
2016/09/27 09:35:54
Hmm. I don't quite understand in what circumstance
minyue-webrtc
2016/09/27 16:02:33
My intention is to make it hook up in similar mann
| |
219 | |
220 void AudioEncoderOpus::OnReceivedUplinkBandwidth(int uplink_bandwidth_bps) { | |
221 if (!config_.audio_network_adaptor_enabled) | |
222 return; | |
223 RTC_DCHECK(audio_network_adaptor_); | |
224 audio_network_adaptor_->SetUplinkBandwidth(uplink_bandwidth_bps); | |
225 ApplyAudioNetworkAdaptor(); | |
226 } | |
227 | |
228 void AudioEncoderOpus::OnReceivedUplinkPacketLossFraction( | |
229 float uplink_packet_loss_fraction) { | |
230 if (!config_.audio_network_adaptor_enabled) | |
231 return; | |
232 RTC_DCHECK(audio_network_adaptor_); | |
233 audio_network_adaptor_->SetUplinkPacketLossFraction( | |
234 uplink_packet_loss_fraction); | |
235 ApplyAudioNetworkAdaptor(); | |
236 } | |
237 | |
238 void AudioEncoderOpus::OnReceivedTargetAudioBitrate( | |
239 int target_audio_bitrate_bps) { | |
240 if (!config_.audio_network_adaptor_enabled) | |
241 return; | |
242 RTC_DCHECK(audio_network_adaptor_); | |
243 audio_network_adaptor_->SetTargetAudioBitrate(target_audio_bitrate_bps); | |
244 ApplyAudioNetworkAdaptor(); | |
245 } | |
246 | |
247 void AudioEncoderOpus::OnReceivedRtt(int rtt_ms) { | |
248 if (!config_.audio_network_adaptor_enabled) | |
249 return; | |
250 RTC_DCHECK(audio_network_adaptor_); | |
251 audio_network_adaptor_->SetRtt(rtt_ms); | |
252 ApplyAudioNetworkAdaptor(); | |
253 } | |
254 | |
255 void AudioEncoderOpus::SetReceiverFrameLengthRange(int min_frame_length_ms, | |
256 int max_frame_length_ms) { | |
257 if (!config_.audio_network_adaptor_enabled) | |
258 return; | |
259 RTC_DCHECK(audio_network_adaptor_); | |
260 audio_network_adaptor_->SetReceiverFrameLengthRange(min_frame_length_ms, | |
261 max_frame_length_ms); | |
262 ApplyAudioNetworkAdaptor(); | |
263 } | |
264 | |
195 AudioEncoder::EncodedInfo AudioEncoderOpus::EncodeImpl( | 265 AudioEncoder::EncodedInfo AudioEncoderOpus::EncodeImpl( |
196 uint32_t rtp_timestamp, | 266 uint32_t rtp_timestamp, |
197 rtc::ArrayView<const int16_t> audio, | 267 rtc::ArrayView<const int16_t> audio, |
198 rtc::Buffer* encoded) { | 268 rtc::Buffer* encoded) { |
199 | 269 |
200 if (input_buffer_.empty()) | 270 if (input_buffer_.empty()) |
201 first_timestamp_in_buffer_ = rtp_timestamp; | 271 first_timestamp_in_buffer_ = rtp_timestamp; |
202 | 272 |
203 input_buffer_.insert(input_buffer_.end(), audio.cbegin(), audio.cend()); | 273 input_buffer_.insert(input_buffer_.end(), audio.cbegin(), audio.cend()); |
204 if (input_buffer_.size() < | 274 if (input_buffer_.size() < |
(...skipping 14 matching lines...) Expand all Loading... | |
219 config_.num_channels), | 289 config_.num_channels), |
220 rtc::saturated_cast<int16_t>(max_encoded_bytes), | 290 rtc::saturated_cast<int16_t>(max_encoded_bytes), |
221 encoded.data()); | 291 encoded.data()); |
222 | 292 |
223 RTC_CHECK_GE(status, 0); // Fails only if fed invalid data. | 293 RTC_CHECK_GE(status, 0); // Fails only if fed invalid data. |
224 | 294 |
225 return static_cast<size_t>(status); | 295 return static_cast<size_t>(status); |
226 }); | 296 }); |
227 input_buffer_.clear(); | 297 input_buffer_.clear(); |
228 | 298 |
299 // Will use new packet size for next encoding. | |
300 config_.frame_size_ms = next_frame_size_ms_; | |
301 | |
229 info.encoded_timestamp = first_timestamp_in_buffer_; | 302 info.encoded_timestamp = first_timestamp_in_buffer_; |
230 info.payload_type = config_.payload_type; | 303 info.payload_type = config_.payload_type; |
231 info.send_even_if_empty = true; // Allows Opus to send empty packets. | 304 info.send_even_if_empty = true; // Allows Opus to send empty packets. |
232 info.speech = (info.encoded_bytes > 0); | 305 info.speech = (info.encoded_bytes > 0); |
233 info.encoder_type = CodecType::kOpus; | 306 info.encoder_type = CodecType::kOpus; |
234 return info; | 307 return info; |
235 } | 308 } |
236 | 309 |
237 size_t AudioEncoderOpus::Num10msFramesPerPacket() const { | 310 size_t AudioEncoderOpus::Num10msFramesPerPacket() const { |
238 return static_cast<size_t>(rtc::CheckedDivExact(config_.frame_size_ms, 10)); | 311 return static_cast<size_t>(rtc::CheckedDivExact(config_.frame_size_ms, 10)); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
275 RTC_CHECK_EQ(0, WebRtcOpus_SetComplexity(inst_, config.complexity)); | 348 RTC_CHECK_EQ(0, WebRtcOpus_SetComplexity(inst_, config.complexity)); |
276 if (config.dtx_enabled) { | 349 if (config.dtx_enabled) { |
277 RTC_CHECK_EQ(0, WebRtcOpus_EnableDtx(inst_)); | 350 RTC_CHECK_EQ(0, WebRtcOpus_EnableDtx(inst_)); |
278 } else { | 351 } else { |
279 RTC_CHECK_EQ(0, WebRtcOpus_DisableDtx(inst_)); | 352 RTC_CHECK_EQ(0, WebRtcOpus_DisableDtx(inst_)); |
280 } | 353 } |
281 RTC_CHECK_EQ(0, | 354 RTC_CHECK_EQ(0, |
282 WebRtcOpus_SetPacketLossRate( | 355 WebRtcOpus_SetPacketLossRate( |
283 inst_, static_cast<int32_t>(packet_loss_rate_ * 100 + .5))); | 356 inst_, static_cast<int32_t>(packet_loss_rate_ * 100 + .5))); |
284 config_ = config; | 357 config_ = config; |
358 | |
359 num_channels_to_encode_ = 0; // Opus automatic mode. | |
360 next_frame_size_ms_ = config_.frame_size_ms; | |
285 return true; | 361 return true; |
286 } | 362 } |
287 | 363 |
364 void AudioEncoderOpus::SetFrameLength(int frame_length_ms) { | |
365 next_frame_size_ms_ = frame_length_ms; | |
366 } | |
367 | |
368 void AudioEncoderOpus::SetNumChannelsToEncode(size_t num_channels_to_encode) { | |
369 RTC_DCHECK_GT(num_channels_to_encode, 0u); | |
370 RTC_DCHECK_LE(num_channels_to_encode, config_.num_channels); | |
371 | |
372 if (num_channels_to_encode_ == num_channels_to_encode) | |
373 return; | |
374 | |
375 // RTC_CHECK_EQ(0, WebRtcOpus_SetForceChannels(inst_, | |
376 // num_channels_to_encode)); | |
kwiberg-webrtc
2016/09/27 09:35:54
Remove commented-out code.
minyue-webrtc
2016/09/27 16:02:33
Yes, we can do it now. Since WebRtcOpus_SetForceCh
| |
377 num_channels_to_encode_ = num_channels_to_encode; | |
378 } | |
379 | |
380 void AudioEncoderOpus::ApplyAudioNetworkAdaptor() { | |
kwiberg-webrtc
2016/09/27 09:35:55
"ApplyAudioNetworkAdaptorConfig"?
minyue-webrtc
2016/09/27 16:02:33
I think ApplyAudioNetworkAdaptor may be better sin
| |
381 auto config = audio_network_adaptor_->GetEncoderRuntimeConfig(); | |
382 | |
383 RTC_DCHECK(config.bitrate_bps && config.frame_length_ms && | |
384 config.uplink_packet_loss_fraction && config.enable_fec && | |
385 config.enable_dtx && config.num_channels); | |
kwiberg-webrtc
2016/09/27 09:35:54
It's often better to split things like this up int
minyue-webrtc
2016/09/27 16:02:33
ok. will change in next patch set.
| |
386 RTC_DCHECK(*config.frame_length_ms == 20 || *config.frame_length_ms == 60); | |
387 | |
388 SetTargetBitrate(*config.bitrate_bps); | |
389 SetFrameLength(*config.frame_length_ms); | |
390 SetFec(*config.enable_fec); | |
391 SetProjectedPacketLossRate(*config.uplink_packet_loss_fraction); | |
392 SetDtx(*config.enable_dtx); | |
393 SetNumChannelsToEncode(*config.num_channels); | |
394 } | |
395 | |
288 } // namespace webrtc | 396 } // namespace webrtc |
OLD | NEW |