| 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 23 matching lines...) Expand all  Loading... | 
| 34   return config; | 34   return config; | 
| 35 } | 35 } | 
| 36 | 36 | 
| 37 // Optimize the loss rate to configure Opus. Basically, optimized loss rate is | 37 // Optimize the loss rate to configure Opus. Basically, optimized loss rate is | 
| 38 // the input loss rate rounded down to various levels, because a robustly good | 38 // the input loss rate rounded down to various levels, because a robustly good | 
| 39 // audio quality is achieved by lowering the packet loss down. | 39 // audio quality is achieved by lowering the packet loss down. | 
| 40 // Additionally, to prevent toggling, margins are used, i.e., when jumping to | 40 // Additionally, to prevent toggling, margins are used, i.e., when jumping to | 
| 41 // a loss rate from below, a higher threshold is used than jumping to the same | 41 // a loss rate from below, a higher threshold is used than jumping to the same | 
| 42 // level from above. | 42 // level from above. | 
| 43 double OptimizePacketLossRate(double new_loss_rate, double old_loss_rate) { | 43 double OptimizePacketLossRate(double new_loss_rate, double old_loss_rate) { | 
| 44   DCHECK_GE(new_loss_rate, 0.0); | 44   RTC_DCHECK_GE(new_loss_rate, 0.0); | 
| 45   DCHECK_LE(new_loss_rate, 1.0); | 45   RTC_DCHECK_LE(new_loss_rate, 1.0); | 
| 46   DCHECK_GE(old_loss_rate, 0.0); | 46   RTC_DCHECK_GE(old_loss_rate, 0.0); | 
| 47   DCHECK_LE(old_loss_rate, 1.0); | 47   RTC_DCHECK_LE(old_loss_rate, 1.0); | 
| 48   const double kPacketLossRate20 = 0.20; | 48   const double kPacketLossRate20 = 0.20; | 
| 49   const double kPacketLossRate10 = 0.10; | 49   const double kPacketLossRate10 = 0.10; | 
| 50   const double kPacketLossRate5 = 0.05; | 50   const double kPacketLossRate5 = 0.05; | 
| 51   const double kPacketLossRate1 = 0.01; | 51   const double kPacketLossRate1 = 0.01; | 
| 52   const double kLossRate20Margin = 0.02; | 52   const double kLossRate20Margin = 0.02; | 
| 53   const double kLossRate10Margin = 0.01; | 53   const double kLossRate10Margin = 0.01; | 
| 54   const double kLossRate5Margin = 0.01; | 54   const double kLossRate5Margin = 0.01; | 
| 55   if (new_loss_rate >= | 55   if (new_loss_rate >= | 
| 56       kPacketLossRate20 + | 56       kPacketLossRate20 + | 
| 57           kLossRate20Margin * | 57           kLossRate20Margin * | 
| (...skipping 25 matching lines...) Expand all  Loading... | 
| 83     return false; | 83     return false; | 
| 84   if (bitrate_bps < kMinBitrateBps || bitrate_bps > kMaxBitrateBps) | 84   if (bitrate_bps < kMinBitrateBps || bitrate_bps > kMaxBitrateBps) | 
| 85     return false; | 85     return false; | 
| 86   if (complexity < 0 || complexity > 10) | 86   if (complexity < 0 || complexity > 10) | 
| 87     return false; | 87     return false; | 
| 88   return true; | 88   return true; | 
| 89 } | 89 } | 
| 90 | 90 | 
| 91 AudioEncoderOpus::AudioEncoderOpus(const Config& config) | 91 AudioEncoderOpus::AudioEncoderOpus(const Config& config) | 
| 92     : packet_loss_rate_(0.0), inst_(nullptr) { | 92     : packet_loss_rate_(0.0), inst_(nullptr) { | 
| 93   CHECK(RecreateEncoderInstance(config)); | 93   RTC_CHECK(RecreateEncoderInstance(config)); | 
| 94 } | 94 } | 
| 95 | 95 | 
| 96 AudioEncoderOpus::AudioEncoderOpus(const CodecInst& codec_inst) | 96 AudioEncoderOpus::AudioEncoderOpus(const CodecInst& codec_inst) | 
| 97     : AudioEncoderOpus(CreateConfig(codec_inst)) {} | 97     : AudioEncoderOpus(CreateConfig(codec_inst)) {} | 
| 98 | 98 | 
| 99 AudioEncoderOpus::~AudioEncoderOpus() { | 99 AudioEncoderOpus::~AudioEncoderOpus() { | 
| 100   CHECK_EQ(0, WebRtcOpus_EncoderFree(inst_)); | 100   RTC_CHECK_EQ(0, WebRtcOpus_EncoderFree(inst_)); | 
| 101 } | 101 } | 
| 102 | 102 | 
| 103 size_t AudioEncoderOpus::MaxEncodedBytes() const { | 103 size_t AudioEncoderOpus::MaxEncodedBytes() const { | 
| 104   // Calculate the number of bytes we expect the encoder to produce, | 104   // Calculate the number of bytes we expect the encoder to produce, | 
| 105   // then multiply by two to give a wide margin for error. | 105   // then multiply by two to give a wide margin for error. | 
| 106   const size_t bytes_per_millisecond = | 106   const size_t bytes_per_millisecond = | 
| 107       static_cast<size_t>(config_.bitrate_bps / (1000 * 8) + 1); | 107       static_cast<size_t>(config_.bitrate_bps / (1000 * 8) + 1); | 
| 108   const size_t approx_encoded_bytes = | 108   const size_t approx_encoded_bytes = | 
| 109       Num10msFramesPerPacket() * 10 * bytes_per_millisecond; | 109       Num10msFramesPerPacket() * 10 * bytes_per_millisecond; | 
| 110   return 2 * approx_encoded_bytes; | 110   return 2 * approx_encoded_bytes; | 
| (...skipping 25 matching lines...) Expand all  Loading... | 
| 136     size_t max_encoded_bytes, | 136     size_t max_encoded_bytes, | 
| 137     uint8_t* encoded) { | 137     uint8_t* encoded) { | 
| 138   if (input_buffer_.empty()) | 138   if (input_buffer_.empty()) | 
| 139     first_timestamp_in_buffer_ = rtp_timestamp; | 139     first_timestamp_in_buffer_ = rtp_timestamp; | 
| 140   input_buffer_.insert(input_buffer_.end(), audio, | 140   input_buffer_.insert(input_buffer_.end(), audio, | 
| 141                        audio + SamplesPer10msFrame()); | 141                        audio + SamplesPer10msFrame()); | 
| 142   if (input_buffer_.size() < | 142   if (input_buffer_.size() < | 
| 143       (static_cast<size_t>(Num10msFramesPerPacket()) * SamplesPer10msFrame())) { | 143       (static_cast<size_t>(Num10msFramesPerPacket()) * SamplesPer10msFrame())) { | 
| 144     return EncodedInfo(); | 144     return EncodedInfo(); | 
| 145   } | 145   } | 
| 146   CHECK_EQ(input_buffer_.size(), static_cast<size_t>(Num10msFramesPerPacket()) * | 146   RTC_CHECK_EQ( | 
| 147                                      SamplesPer10msFrame()); | 147       input_buffer_.size(), | 
|  | 148       static_cast<size_t>(Num10msFramesPerPacket()) * SamplesPer10msFrame()); | 
| 148   int status = WebRtcOpus_Encode( | 149   int status = WebRtcOpus_Encode( | 
| 149       inst_, &input_buffer_[0], | 150       inst_, &input_buffer_[0], | 
| 150       rtc::CheckedDivExact(input_buffer_.size(), | 151       rtc::CheckedDivExact(input_buffer_.size(), | 
| 151                            static_cast<size_t>(config_.num_channels)), | 152                            static_cast<size_t>(config_.num_channels)), | 
| 152       rtc::saturated_cast<int16_t>(max_encoded_bytes), encoded); | 153       rtc::saturated_cast<int16_t>(max_encoded_bytes), encoded); | 
| 153   CHECK_GE(status, 0);  // Fails only if fed invalid data. | 154   RTC_CHECK_GE(status, 0);  // Fails only if fed invalid data. | 
| 154   input_buffer_.clear(); | 155   input_buffer_.clear(); | 
| 155   EncodedInfo info; | 156   EncodedInfo info; | 
| 156   info.encoded_bytes = static_cast<size_t>(status); | 157   info.encoded_bytes = static_cast<size_t>(status); | 
| 157   info.encoded_timestamp = first_timestamp_in_buffer_; | 158   info.encoded_timestamp = first_timestamp_in_buffer_; | 
| 158   info.payload_type = config_.payload_type; | 159   info.payload_type = config_.payload_type; | 
| 159   info.send_even_if_empty = true;  // Allows Opus to send empty packets. | 160   info.send_even_if_empty = true;  // Allows Opus to send empty packets. | 
| 160   info.speech = (status > 0); | 161   info.speech = (status > 0); | 
| 161   return info; | 162   return info; | 
| 162 } | 163 } | 
| 163 | 164 | 
| 164 void AudioEncoderOpus::Reset() { | 165 void AudioEncoderOpus::Reset() { | 
| 165   CHECK(RecreateEncoderInstance(config_)); | 166   RTC_CHECK(RecreateEncoderInstance(config_)); | 
| 166 } | 167 } | 
| 167 | 168 | 
| 168 bool AudioEncoderOpus::SetFec(bool enable) { | 169 bool AudioEncoderOpus::SetFec(bool enable) { | 
| 169   auto conf = config_; | 170   auto conf = config_; | 
| 170   conf.fec_enabled = enable; | 171   conf.fec_enabled = enable; | 
| 171   return RecreateEncoderInstance(conf); | 172   return RecreateEncoderInstance(conf); | 
| 172 } | 173 } | 
| 173 | 174 | 
| 174 bool AudioEncoderOpus::SetDtx(bool enable) { | 175 bool AudioEncoderOpus::SetDtx(bool enable) { | 
| 175   auto conf = config_; | 176   auto conf = config_; | 
| (...skipping 10 matching lines...) Expand all  Loading... | 
| 186     case Application::kAudio: | 187     case Application::kAudio: | 
| 187       conf.application = AudioEncoderOpus::kAudio; | 188       conf.application = AudioEncoderOpus::kAudio; | 
| 188       break; | 189       break; | 
| 189   } | 190   } | 
| 190   return RecreateEncoderInstance(conf); | 191   return RecreateEncoderInstance(conf); | 
| 191 } | 192 } | 
| 192 | 193 | 
| 193 void AudioEncoderOpus::SetMaxPlaybackRate(int frequency_hz) { | 194 void AudioEncoderOpus::SetMaxPlaybackRate(int frequency_hz) { | 
| 194   auto conf = config_; | 195   auto conf = config_; | 
| 195   conf.max_playback_rate_hz = frequency_hz; | 196   conf.max_playback_rate_hz = frequency_hz; | 
| 196   CHECK(RecreateEncoderInstance(conf)); | 197   RTC_CHECK(RecreateEncoderInstance(conf)); | 
| 197 } | 198 } | 
| 198 | 199 | 
| 199 void AudioEncoderOpus::SetProjectedPacketLossRate(double fraction) { | 200 void AudioEncoderOpus::SetProjectedPacketLossRate(double fraction) { | 
| 200   double opt_loss_rate = OptimizePacketLossRate(fraction, packet_loss_rate_); | 201   double opt_loss_rate = OptimizePacketLossRate(fraction, packet_loss_rate_); | 
| 201   if (packet_loss_rate_ != opt_loss_rate) { | 202   if (packet_loss_rate_ != opt_loss_rate) { | 
| 202     packet_loss_rate_ = opt_loss_rate; | 203     packet_loss_rate_ = opt_loss_rate; | 
| 203     CHECK_EQ(0, WebRtcOpus_SetPacketLossRate( | 204     RTC_CHECK_EQ( | 
| 204                     inst_, static_cast<int32_t>(packet_loss_rate_ * 100 + .5))); | 205         0, WebRtcOpus_SetPacketLossRate( | 
|  | 206                inst_, static_cast<int32_t>(packet_loss_rate_ * 100 + .5))); | 
| 205   } | 207   } | 
| 206 } | 208 } | 
| 207 | 209 | 
| 208 void AudioEncoderOpus::SetTargetBitrate(int bits_per_second) { | 210 void AudioEncoderOpus::SetTargetBitrate(int bits_per_second) { | 
| 209   config_.bitrate_bps = | 211   config_.bitrate_bps = | 
| 210       std::max(std::min(bits_per_second, kMaxBitrateBps), kMinBitrateBps); | 212       std::max(std::min(bits_per_second, kMaxBitrateBps), kMinBitrateBps); | 
| 211   DCHECK(config_.IsOk()); | 213   RTC_DCHECK(config_.IsOk()); | 
| 212   CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, config_.bitrate_bps)); | 214   RTC_CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, config_.bitrate_bps)); | 
| 213 } | 215 } | 
| 214 | 216 | 
| 215 int AudioEncoderOpus::Num10msFramesPerPacket() const { | 217 int AudioEncoderOpus::Num10msFramesPerPacket() const { | 
| 216   return rtc::CheckedDivExact(config_.frame_size_ms, 10); | 218   return rtc::CheckedDivExact(config_.frame_size_ms, 10); | 
| 217 } | 219 } | 
| 218 | 220 | 
| 219 int AudioEncoderOpus::SamplesPer10msFrame() const { | 221 int AudioEncoderOpus::SamplesPer10msFrame() const { | 
| 220   return rtc::CheckedDivExact(kSampleRateHz, 100) * config_.num_channels; | 222   return rtc::CheckedDivExact(kSampleRateHz, 100) * config_.num_channels; | 
| 221 } | 223 } | 
| 222 | 224 | 
| 223 // If the given config is OK, recreate the Opus encoder instance with those | 225 // If the given config is OK, recreate the Opus encoder instance with those | 
| 224 // settings, save the config, and return true. Otherwise, do nothing and return | 226 // settings, save the config, and return true. Otherwise, do nothing and return | 
| 225 // false. | 227 // false. | 
| 226 bool AudioEncoderOpus::RecreateEncoderInstance(const Config& config) { | 228 bool AudioEncoderOpus::RecreateEncoderInstance(const Config& config) { | 
| 227   if (!config.IsOk()) | 229   if (!config.IsOk()) | 
| 228     return false; | 230     return false; | 
| 229   if (inst_) | 231   if (inst_) | 
| 230     CHECK_EQ(0, WebRtcOpus_EncoderFree(inst_)); | 232     RTC_CHECK_EQ(0, WebRtcOpus_EncoderFree(inst_)); | 
| 231   input_buffer_.clear(); | 233   input_buffer_.clear(); | 
| 232   input_buffer_.reserve(Num10msFramesPerPacket() * SamplesPer10msFrame()); | 234   input_buffer_.reserve(Num10msFramesPerPacket() * SamplesPer10msFrame()); | 
| 233   CHECK_EQ(0, WebRtcOpus_EncoderCreate(&inst_, config.num_channels, | 235   RTC_CHECK_EQ(0, WebRtcOpus_EncoderCreate(&inst_, config.num_channels, | 
| 234                                        config.application)); | 236                                            config.application)); | 
| 235   CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, config.bitrate_bps)); | 237   RTC_CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, config.bitrate_bps)); | 
| 236   if (config.fec_enabled) { | 238   if (config.fec_enabled) { | 
| 237     CHECK_EQ(0, WebRtcOpus_EnableFec(inst_)); | 239     RTC_CHECK_EQ(0, WebRtcOpus_EnableFec(inst_)); | 
| 238   } else { | 240   } else { | 
| 239     CHECK_EQ(0, WebRtcOpus_DisableFec(inst_)); | 241     RTC_CHECK_EQ(0, WebRtcOpus_DisableFec(inst_)); | 
| 240   } | 242   } | 
| 241   CHECK_EQ(0, | 243   RTC_CHECK_EQ( | 
| 242            WebRtcOpus_SetMaxPlaybackRate(inst_, config.max_playback_rate_hz)); | 244       0, WebRtcOpus_SetMaxPlaybackRate(inst_, config.max_playback_rate_hz)); | 
| 243   CHECK_EQ(0, WebRtcOpus_SetComplexity(inst_, config.complexity)); | 245   RTC_CHECK_EQ(0, WebRtcOpus_SetComplexity(inst_, config.complexity)); | 
| 244   if (config.dtx_enabled) { | 246   if (config.dtx_enabled) { | 
| 245     CHECK_EQ(0, WebRtcOpus_EnableDtx(inst_)); | 247     RTC_CHECK_EQ(0, WebRtcOpus_EnableDtx(inst_)); | 
| 246   } else { | 248   } else { | 
| 247     CHECK_EQ(0, WebRtcOpus_DisableDtx(inst_)); | 249     RTC_CHECK_EQ(0, WebRtcOpus_DisableDtx(inst_)); | 
| 248   } | 250   } | 
| 249   CHECK_EQ(0, WebRtcOpus_SetPacketLossRate( | 251   RTC_CHECK_EQ(0, | 
| 250                   inst_, static_cast<int32_t>(packet_loss_rate_ * 100 + .5))); | 252                WebRtcOpus_SetPacketLossRate( | 
|  | 253                    inst_, static_cast<int32_t>(packet_loss_rate_ * 100 + .5))); | 
| 251   config_ = config; | 254   config_ = config; | 
| 252   return true; | 255   return true; | 
| 253 } | 256 } | 
| 254 | 257 | 
| 255 }  // namespace webrtc | 258 }  // namespace webrtc | 
| OLD | NEW | 
|---|