Chromium Code Reviews| 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/opus/audio_encoder_opus.h" | 11 #include "webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h" |
| 12 | 12 |
| 13 #include <algorithm> | 13 #include <algorithm> |
| 14 | 14 |
| 15 #include "webrtc/base/checks.h" | 15 #include "webrtc/base/checks.h" |
| 16 #include "webrtc/base/safe_conversions.h" | 16 #include "webrtc/base/safe_conversions.h" |
| 17 #include "webrtc/common_types.h" | 17 #include "webrtc/common_types.h" |
| 18 #include "webrtc/modules/audio_coding/codecs/opus/opus_interface.h" | 18 #include "webrtc/modules/audio_coding/codecs/opus/opus_interface.h" |
| 19 #include "webrtc/modules/audio_coding/audio_network_adaptor/include/audio_networ k_adaptor.h" | |
| 19 | 20 |
| 20 namespace webrtc { | 21 namespace webrtc { |
| 21 | 22 |
| 22 namespace { | 23 namespace { |
| 23 | 24 |
| 24 const int kSampleRateHz = 48000; | 25 const int kSampleRateHz = 48000; |
| 25 const int kMinBitrateBps = 500; | 26 const int kMinBitrateBps = 500; |
| 26 const int kMaxBitrateBps = 512000; | 27 const int kMaxBitrateBps = 512000; |
| 27 | 28 |
| 28 AudioEncoderOpus::Config CreateConfig(const CodecInst& codec_inst) { | 29 AudioEncoderOpus::Config CreateConfig(const CodecInst& codec_inst) { |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 134 | 135 |
| 135 int AudioEncoderOpus::GetTargetBitrate() const { | 136 int AudioEncoderOpus::GetTargetBitrate() const { |
| 136 return config_.GetBitrateBps(); | 137 return config_.GetBitrateBps(); |
| 137 } | 138 } |
| 138 | 139 |
| 139 void AudioEncoderOpus::Reset() { | 140 void AudioEncoderOpus::Reset() { |
| 140 RTC_CHECK(RecreateEncoderInstance(config_)); | 141 RTC_CHECK(RecreateEncoderInstance(config_)); |
| 141 } | 142 } |
| 142 | 143 |
| 143 bool AudioEncoderOpus::SetFec(bool enable) { | 144 bool AudioEncoderOpus::SetFec(bool enable) { |
| 144 auto conf = config_; | 145 if (enable) { |
| 145 conf.fec_enabled = enable; | 146 RTC_CHECK_EQ(0, WebRtcOpus_EnableFec(inst_)); |
| 146 return RecreateEncoderInstance(conf); | 147 } else { |
| 148 RTC_CHECK_EQ(0, WebRtcOpus_DisableFec(inst_)); | |
| 149 } | |
| 150 config_.fec_enabled = enable; | |
| 151 return true; | |
| 147 } | 152 } |
| 148 | 153 |
| 149 bool AudioEncoderOpus::SetDtx(bool enable) { | 154 bool AudioEncoderOpus::SetDtx(bool enable) { |
| 150 auto conf = config_; | 155 if (enable) { |
| 151 conf.dtx_enabled = enable; | 156 RTC_CHECK_EQ(0, WebRtcOpus_EnableDtx(inst_)); |
| 152 return RecreateEncoderInstance(conf); | 157 } else { |
| 158 RTC_CHECK_EQ(0, WebRtcOpus_DisableDtx(inst_)); | |
| 159 } | |
| 160 config_.dtx_enabled = enable; | |
| 161 return true; | |
| 153 } | 162 } |
| 154 | 163 |
| 155 bool AudioEncoderOpus::GetDtx() const { | 164 bool AudioEncoderOpus::GetDtx() const { |
| 156 return config_.dtx_enabled; | 165 return config_.dtx_enabled; |
| 157 } | 166 } |
| 158 | 167 |
| 159 bool AudioEncoderOpus::SetApplication(Application application) { | 168 bool AudioEncoderOpus::SetApplication(Application application) { |
| 160 auto conf = config_; | 169 auto conf = config_; |
| 161 switch (application) { | 170 switch (application) { |
| 162 case Application::kSpeech: | 171 case Application::kSpeech: |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 185 } | 194 } |
| 186 } | 195 } |
| 187 | 196 |
| 188 void AudioEncoderOpus::SetTargetBitrate(int bits_per_second) { | 197 void AudioEncoderOpus::SetTargetBitrate(int bits_per_second) { |
| 189 config_.bitrate_bps = rtc::Optional<int>( | 198 config_.bitrate_bps = rtc::Optional<int>( |
| 190 std::max(std::min(bits_per_second, kMaxBitrateBps), kMinBitrateBps)); | 199 std::max(std::min(bits_per_second, kMaxBitrateBps), kMinBitrateBps)); |
| 191 RTC_DCHECK(config_.IsOk()); | 200 RTC_DCHECK(config_.IsOk()); |
| 192 RTC_CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, config_.GetBitrateBps())); | 201 RTC_CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, config_.GetBitrateBps())); |
| 193 } | 202 } |
| 194 | 203 |
| 204 void AudioEncoderOpus::OnReceivedUplinkBandwidth(int uplink_bandwidth_bps) { | |
| 205 if (!config_.audio_network_adaptor_enabled) | |
| 206 return; | |
| 207 RTC_DCHECK(audio_network_adaptor_); | |
| 208 audio_network_adaptor_->SetUplinkBandwidth(uplink_bandwidth_bps); | |
| 209 ApplyAudioNetworkAdaptor(); | |
| 210 } | |
| 211 | |
| 212 void AudioEncoderOpus::OnReceivedUplinkPacketLossFraction(float uplink_packet_lo ss_fraction) { | |
| 213 if (!config_.audio_network_adaptor_enabled) | |
| 214 return; | |
| 215 RTC_DCHECK(audio_network_adaptor_); | |
| 216 audio_network_adaptor_->SetUplinkPacketLossFraction(uplink_packet_loss_fractio n); | |
| 217 ApplyAudioNetworkAdaptor(); | |
| 218 } | |
| 219 | |
| 220 void AudioEncoderOpus::OnReceivedTargetAudioBitrate(int target_audio_bitrate_bps ) { | |
| 221 if (!config_.audio_network_adaptor_enabled) | |
| 222 return; | |
| 223 RTC_DCHECK(audio_network_adaptor_); | |
| 224 // audio_network_adaptor_->SetReceivedTargetAudioBitrate(uplink_bandwidth_bps); | |
| 225 ApplyAudioNetworkAdaptor(); | |
| 226 } | |
| 227 | |
| 228 void AudioEncoderOpus::OnReceivedRtt(int rtt_ms) { | |
| 229 if (!config_.audio_network_adaptor_enabled) | |
| 230 return; | |
| 231 RTC_DCHECK(audio_network_adaptor_); | |
| 232 // audio_network_adaptor_->SetRtt(rtt_ms); | |
| 233 ApplyAudioNetworkAdaptor(); | |
| 234 } | |
| 235 | |
| 195 AudioEncoder::EncodedInfo AudioEncoderOpus::EncodeImpl( | 236 AudioEncoder::EncodedInfo AudioEncoderOpus::EncodeImpl( |
| 196 uint32_t rtp_timestamp, | 237 uint32_t rtp_timestamp, |
| 197 rtc::ArrayView<const int16_t> audio, | 238 rtc::ArrayView<const int16_t> audio, |
| 198 rtc::Buffer* encoded) { | 239 rtc::Buffer* encoded) { |
| 199 | 240 |
| 200 if (input_buffer_.empty()) | 241 if (input_buffer_.empty()) |
| 201 first_timestamp_in_buffer_ = rtp_timestamp; | 242 first_timestamp_in_buffer_ = rtp_timestamp; |
| 202 | 243 |
| 203 input_buffer_.insert(input_buffer_.end(), audio.cbegin(), audio.cend()); | 244 input_buffer_.insert(input_buffer_.end(), audio.cbegin(), audio.cend()); |
| 204 if (input_buffer_.size() < | 245 if (input_buffer_.size() < |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 219 config_.num_channels), | 260 config_.num_channels), |
| 220 rtc::saturated_cast<int16_t>(max_encoded_bytes), | 261 rtc::saturated_cast<int16_t>(max_encoded_bytes), |
| 221 encoded.data()); | 262 encoded.data()); |
| 222 | 263 |
| 223 RTC_CHECK_GE(status, 0); // Fails only if fed invalid data. | 264 RTC_CHECK_GE(status, 0); // Fails only if fed invalid data. |
| 224 | 265 |
| 225 return static_cast<size_t>(status); | 266 return static_cast<size_t>(status); |
| 226 }); | 267 }); |
| 227 input_buffer_.clear(); | 268 input_buffer_.clear(); |
| 228 | 269 |
| 270 // Will use new packet size for next encoding. | |
| 271 config_.frame_size_ms = next_frame_size_ms_; | |
| 272 | |
| 229 info.encoded_timestamp = first_timestamp_in_buffer_; | 273 info.encoded_timestamp = first_timestamp_in_buffer_; |
| 230 info.payload_type = config_.payload_type; | 274 info.payload_type = config_.payload_type; |
| 231 info.send_even_if_empty = true; // Allows Opus to send empty packets. | 275 info.send_even_if_empty = true; // Allows Opus to send empty packets. |
| 232 info.speech = (info.encoded_bytes > 0); | 276 info.speech = (info.encoded_bytes > 0); |
| 233 info.encoder_type = CodecType::kOpus; | 277 info.encoder_type = CodecType::kOpus; |
| 234 return info; | 278 return info; |
| 235 } | 279 } |
| 236 | 280 |
| 237 size_t AudioEncoderOpus::Num10msFramesPerPacket() const { | 281 size_t AudioEncoderOpus::Num10msFramesPerPacket() const { |
| 238 return static_cast<size_t>(rtc::CheckedDivExact(config_.frame_size_ms, 10)); | 282 return static_cast<size_t>(rtc::CheckedDivExact(config_.frame_size_ms, 10)); |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 258 bool AudioEncoderOpus::RecreateEncoderInstance(const Config& config) { | 302 bool AudioEncoderOpus::RecreateEncoderInstance(const Config& config) { |
| 259 if (!config.IsOk()) | 303 if (!config.IsOk()) |
| 260 return false; | 304 return false; |
| 261 if (inst_) | 305 if (inst_) |
| 262 RTC_CHECK_EQ(0, WebRtcOpus_EncoderFree(inst_)); | 306 RTC_CHECK_EQ(0, WebRtcOpus_EncoderFree(inst_)); |
| 263 input_buffer_.clear(); | 307 input_buffer_.clear(); |
| 264 input_buffer_.reserve(Num10msFramesPerPacket() * SamplesPer10msFrame()); | 308 input_buffer_.reserve(Num10msFramesPerPacket() * SamplesPer10msFrame()); |
| 265 RTC_CHECK_EQ(0, WebRtcOpus_EncoderCreate(&inst_, config.num_channels, | 309 RTC_CHECK_EQ(0, WebRtcOpus_EncoderCreate(&inst_, config.num_channels, |
| 266 config.application)); | 310 config.application)); |
| 267 RTC_CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, config.GetBitrateBps())); | 311 RTC_CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, config.GetBitrateBps())); |
| 268 if (config.fec_enabled) { | 312 if (config.fec_enabled) { |
|
michaelt
2016/09/22 12:13:14
Use new function to set FEC and DTX
minyue-webrtc
2016/09/27 08:30:36
ok, will do
minyue-webrtc
2016/09/29 15:34:24
I gave it a second thought, and feel that it may n
| |
| 269 RTC_CHECK_EQ(0, WebRtcOpus_EnableFec(inst_)); | 313 RTC_CHECK_EQ(0, WebRtcOpus_EnableFec(inst_)); |
| 270 } else { | 314 } else { |
| 271 RTC_CHECK_EQ(0, WebRtcOpus_DisableFec(inst_)); | 315 RTC_CHECK_EQ(0, WebRtcOpus_DisableFec(inst_)); |
| 272 } | 316 } |
| 273 RTC_CHECK_EQ( | 317 RTC_CHECK_EQ( |
| 274 0, WebRtcOpus_SetMaxPlaybackRate(inst_, config.max_playback_rate_hz)); | 318 0, WebRtcOpus_SetMaxPlaybackRate(inst_, config.max_playback_rate_hz)); |
| 275 RTC_CHECK_EQ(0, WebRtcOpus_SetComplexity(inst_, config.complexity)); | 319 RTC_CHECK_EQ(0, WebRtcOpus_SetComplexity(inst_, config.complexity)); |
| 276 if (config.dtx_enabled) { | 320 if (config.dtx_enabled) { |
| 277 RTC_CHECK_EQ(0, WebRtcOpus_EnableDtx(inst_)); | 321 RTC_CHECK_EQ(0, WebRtcOpus_EnableDtx(inst_)); |
| 278 } else { | 322 } else { |
| 279 RTC_CHECK_EQ(0, WebRtcOpus_DisableDtx(inst_)); | 323 RTC_CHECK_EQ(0, WebRtcOpus_DisableDtx(inst_)); |
| 280 } | 324 } |
| 281 RTC_CHECK_EQ(0, | 325 RTC_CHECK_EQ(0, |
| 282 WebRtcOpus_SetPacketLossRate( | 326 WebRtcOpus_SetPacketLossRate( |
| 283 inst_, static_cast<int32_t>(packet_loss_rate_ * 100 + .5))); | 327 inst_, static_cast<int32_t>(packet_loss_rate_ * 100 + .5))); |
| 284 config_ = config; | 328 config_ = config; |
| 329 | |
| 330 num_channels_to_encode_ = 0; // Opus automatic mode. | |
|
michaelt
2016/09/22 12:13:14
I think we should create a enum class for num_chan
minyue-webrtc
2016/09/27 08:30:36
I think we should not use "0", since audio network
| |
| 331 next_frame_size_ms_ = config_.frame_size_ms; | |
| 332 if (config_.audio_network_adaptor_enabled) { | |
| 333 // TODO(minyue): Create AudioNetworkAdaptorImpl. | |
| 334 } | |
| 285 return true; | 335 return true; |
| 286 } | 336 } |
| 287 | 337 |
| 338 void AudioEncoderOpus::SetFrameLength(int frame_length_ms) { | |
| 339 next_frame_size_ms_ = frame_length_ms; | |
| 340 } | |
| 341 | |
| 342 void AudioEncoderOpus::SetNumChannelsToEncode(size_t num_channels_to_encode) { | |
| 343 RTC_DCHECK_GT(num_channels_to_encode, 0u); | |
| 344 RTC_DCHECK_LE(num_channels_to_encode, config_.num_channels); | |
| 345 | |
| 346 if (num_channels_to_encode_ == num_channels_to_encode) | |
| 347 return; | |
| 348 | |
| 349 // RTC_CHECK_EQ(0, WebRtcOpus_SetForceChannels(inst_, num_channels_to_encode)); | |
| 350 num_channels_to_encode_ = num_channels_to_encode; | |
| 351 } | |
| 352 | |
| 353 void AudioEncoderOpus::ApplyAudioNetworkAdaptor() { | |
| 354 auto config = audio_network_adaptor_->GetEncoderRuntimeConfig(); | |
| 355 | |
| 356 RTC_DCHECK(config.bitrate_bps && config.frame_length_ms && | |
| 357 config.uplink_packet_loss_fraction && config.enable_fec && | |
| 358 config.enable_dtx); | |
| 359 RTC_DCHECK(*config.frame_length_ms == 20 || *config.frame_length_ms == 60); | |
| 360 | |
| 361 SetTargetBitrate(*config.bitrate_bps); | |
| 362 SetFrameLength(*config.frame_length_ms); | |
| 363 SetFec(*config.enable_fec); | |
| 364 SetProjectedPacketLossRate(*config.uplink_packet_loss_fraction); | |
| 365 SetDtx(*config.enable_dtx); | |
| 366 SetNumChannelsToEncode(*config.num_channels); | |
| 367 } | |
| 368 | |
| 288 } // namespace webrtc | 369 } // namespace webrtc |
| OLD | NEW |