| 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/interface/audio_encoder_opus.h
     " |   11 #include "webrtc/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h
     " | 
|   12  |   12  | 
|   13 #include "webrtc/base/checks.h" |   13 #include "webrtc/base/checks.h" | 
 |   14 #include "webrtc/base/safe_conversions.h" | 
|   14 #include "webrtc/common_types.h" |   15 #include "webrtc/common_types.h" | 
|   15 #include "webrtc/modules/audio_coding/codecs/opus/interface/opus_interface.h" |   16 #include "webrtc/modules/audio_coding/codecs/opus/interface/opus_interface.h" | 
|   16  |   17  | 
|   17 namespace webrtc { |   18 namespace webrtc { | 
|   18  |   19  | 
|   19 namespace { |   20 namespace { | 
|   20  |   21  | 
 |   22 const int kSampleRateHz = 48000; | 
|   21 const int kMinBitrateBps = 500; |   23 const int kMinBitrateBps = 500; | 
|   22 const int kMaxBitrateBps = 512000; |   24 const int kMaxBitrateBps = 512000; | 
|   23  |   25  | 
|   24 // TODO(tlegrand): Remove this code when we have proper APIs to set the |   26 AudioEncoderOpus::Config CreateConfig(const CodecInst& codec_inst) { | 
|   25 // complexity at a higher level. |   27   AudioEncoderOpus::Config config; | 
|   26 #if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) || defined(WEBRTC_ARCH_ARM) |   28   config.frame_size_ms = rtc::CheckedDivExact(codec_inst.pacsize, 48); | 
|   27 // If we are on Android, iOS and/or ARM, use a lower complexity setting as |   29   config.num_channels = codec_inst.channels; | 
|   28 // default, to save encoder complexity. |   30   config.bitrate_bps = codec_inst.rate; | 
|   29 const int kDefaultComplexity = 5; |   31   config.payload_type = codec_inst.pltype; | 
|   30 #else |   32   config.application = config.num_channels == 1 ? AudioEncoderOpus::kVoip | 
|   31 const int kDefaultComplexity = 9; |   33                                                 : AudioEncoderOpus::kAudio; | 
|   32 #endif |   34   return config; | 
 |   35 } | 
|   33  |   36  | 
|   34 // We always encode at 48 kHz. |   37 // Optimize the loss rate to configure Opus. Basically, optimized loss rate is | 
|   35 const int kSampleRateHz = 48000; |   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. | 
 |   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 | 
 |   42 // level from above. | 
 |   43 double OptimizePacketLossRate(double new_loss_rate, double old_loss_rate) { | 
 |   44   DCHECK_GE(new_loss_rate, 0.0); | 
 |   45   DCHECK_LE(new_loss_rate, 1.0); | 
 |   46   DCHECK_GE(old_loss_rate, 0.0); | 
 |   47   DCHECK_LE(old_loss_rate, 1.0); | 
 |   48   const double kPacketLossRate20 = 0.20; | 
 |   49   const double kPacketLossRate10 = 0.10; | 
 |   50   const double kPacketLossRate5 = 0.05; | 
 |   51   const double kPacketLossRate1 = 0.01; | 
 |   52   const double kLossRate20Margin = 0.02; | 
 |   53   const double kLossRate10Margin = 0.01; | 
 |   54   const double kLossRate5Margin = 0.01; | 
 |   55   if (new_loss_rate >= | 
 |   56       kPacketLossRate20 + | 
 |   57           kLossRate20Margin * | 
 |   58               (kPacketLossRate20 - old_loss_rate > 0 ? 1 : -1)) { | 
 |   59     return kPacketLossRate20; | 
 |   60   } else if (new_loss_rate >= | 
 |   61              kPacketLossRate10 + | 
 |   62                  kLossRate10Margin * | 
 |   63                      (kPacketLossRate10 - old_loss_rate > 0 ? 1 : -1)) { | 
 |   64     return kPacketLossRate10; | 
 |   65   } else if (new_loss_rate >= | 
 |   66              kPacketLossRate5 + | 
 |   67                  kLossRate5Margin * | 
 |   68                      (kPacketLossRate5 - old_loss_rate > 0 ? 1 : -1)) { | 
 |   69     return kPacketLossRate5; | 
 |   70   } else if (new_loss_rate >= kPacketLossRate1) { | 
 |   71     return kPacketLossRate1; | 
 |   72   } else { | 
 |   73     return 0.0; | 
 |   74   } | 
 |   75 } | 
|   36  |   76  | 
|   37 }  // namespace |   77 }  // namespace | 
|   38  |   78  | 
|   39 AudioEncoderOpus::Config::Config() |  | 
|   40     : frame_size_ms(20), |  | 
|   41       num_channels(1), |  | 
|   42       payload_type(120), |  | 
|   43       application(kVoip), |  | 
|   44       bitrate_bps(64000), |  | 
|   45       fec_enabled(false), |  | 
|   46       max_playback_rate_hz(48000), |  | 
|   47       complexity(kDefaultComplexity), |  | 
|   48       dtx_enabled(false) { |  | 
|   49 } |  | 
|   50  |  | 
|   51 bool AudioEncoderOpus::Config::IsOk() const { |   79 bool AudioEncoderOpus::Config::IsOk() const { | 
|   52   if (frame_size_ms <= 0 || frame_size_ms % 10 != 0) |   80   if (frame_size_ms <= 0 || frame_size_ms % 10 != 0) | 
|   53     return false; |   81     return false; | 
|   54   if (num_channels != 1 && num_channels != 2) |   82   if (num_channels != 1 && num_channels != 2) | 
|   55     return false; |   83     return false; | 
|   56   if (bitrate_bps < kMinBitrateBps || bitrate_bps > kMaxBitrateBps) |   84   if (bitrate_bps < kMinBitrateBps || bitrate_bps > kMaxBitrateBps) | 
|   57     return false; |   85     return false; | 
|   58   if (complexity < 0 || complexity > 10) |   86   if (complexity < 0 || complexity > 10) | 
|   59     return false; |   87     return false; | 
|   60   return true; |   88   return true; | 
|   61 } |   89 } | 
|   62  |   90  | 
|   63 AudioEncoderOpus::AudioEncoderOpus(const Config& config) |   91 AudioEncoderOpus::AudioEncoderOpus(const Config& config) | 
|   64     : num_10ms_frames_per_packet_( |   92     : packet_loss_rate_(0.0), inst_(nullptr) { | 
|   65           static_cast<size_t>(rtc::CheckedDivExact(config.frame_size_ms, 10))), |   93   CHECK(RecreateEncoderInstance(config)); | 
|   66       num_channels_(config.num_channels), |  | 
|   67       payload_type_(config.payload_type), |  | 
|   68       application_(config.application), |  | 
|   69       dtx_enabled_(config.dtx_enabled), |  | 
|   70       samples_per_10ms_frame_(static_cast<size_t>( |  | 
|   71           rtc::CheckedDivExact(kSampleRateHz, 100) * num_channels_)), |  | 
|   72       packet_loss_rate_(0.0) { |  | 
|   73   CHECK(config.IsOk()); |  | 
|   74   input_buffer_.reserve(num_10ms_frames_per_packet_ * samples_per_10ms_frame_); |  | 
|   75   CHECK_EQ(0, WebRtcOpus_EncoderCreate(&inst_, num_channels_, application_)); |  | 
|   76   SetTargetBitrate(config.bitrate_bps); |  | 
|   77   if (config.fec_enabled) { |  | 
|   78     CHECK_EQ(0, WebRtcOpus_EnableFec(inst_)); |  | 
|   79   } else { |  | 
|   80     CHECK_EQ(0, WebRtcOpus_DisableFec(inst_)); |  | 
|   81   } |  | 
|   82   CHECK_EQ(0, |  | 
|   83            WebRtcOpus_SetMaxPlaybackRate(inst_, config.max_playback_rate_hz)); |  | 
|   84   CHECK_EQ(0, WebRtcOpus_SetComplexity(inst_, config.complexity)); |  | 
|   85   if (config.dtx_enabled) { |  | 
|   86     CHECK_EQ(0, WebRtcOpus_EnableDtx(inst_)); |  | 
|   87   } else { |  | 
|   88     CHECK_EQ(0, WebRtcOpus_DisableDtx(inst_)); |  | 
|   89   } |  | 
|   90 } |   94 } | 
|   91  |   95  | 
 |   96 AudioEncoderOpus::AudioEncoderOpus(const CodecInst& codec_inst) | 
 |   97     : AudioEncoderOpus(CreateConfig(codec_inst)) {} | 
 |   98  | 
|   92 AudioEncoderOpus::~AudioEncoderOpus() { |   99 AudioEncoderOpus::~AudioEncoderOpus() { | 
|   93   CHECK_EQ(0, WebRtcOpus_EncoderFree(inst_)); |  100   CHECK_EQ(0, WebRtcOpus_EncoderFree(inst_)); | 
|   94 } |  101 } | 
|   95  |  102  | 
 |  103 size_t AudioEncoderOpus::MaxEncodedBytes() const { | 
 |  104   // Calculate the number of bytes we expect the encoder to produce, | 
 |  105   // then multiply by two to give a wide margin for error. | 
 |  106   const size_t bytes_per_millisecond = | 
 |  107       static_cast<size_t>(config_.bitrate_bps / (1000 * 8) + 1); | 
 |  108   const size_t approx_encoded_bytes = | 
 |  109       Num10msFramesPerPacket() * 10 * bytes_per_millisecond; | 
 |  110   return 2 * approx_encoded_bytes; | 
 |  111 } | 
 |  112  | 
|   96 int AudioEncoderOpus::SampleRateHz() const { |  113 int AudioEncoderOpus::SampleRateHz() const { | 
|   97   return kSampleRateHz; |  114   return kSampleRateHz; | 
|   98 } |  115 } | 
|   99  |  116  | 
|  100 int AudioEncoderOpus::NumChannels() const { |  117 int AudioEncoderOpus::NumChannels() const { | 
|  101   return num_channels_; |  118   return config_.num_channels; | 
|  102 } |  | 
|  103  |  | 
|  104 size_t AudioEncoderOpus::MaxEncodedBytes() const { |  | 
|  105   // Calculate the number of bytes we expect the encoder to produce, |  | 
|  106   // then multiply by two to give a wide margin for error. |  | 
|  107   size_t bytes_per_millisecond = |  | 
|  108       static_cast<size_t>(bitrate_bps_ / (1000 * 8) + 1); |  | 
|  109   size_t approx_encoded_bytes = |  | 
|  110       num_10ms_frames_per_packet_ * 10 * bytes_per_millisecond; |  | 
|  111   return 2 * approx_encoded_bytes; |  | 
|  112 } |  119 } | 
|  113  |  120  | 
|  114 size_t AudioEncoderOpus::Num10MsFramesInNextPacket() const { |  121 size_t AudioEncoderOpus::Num10MsFramesInNextPacket() const { | 
|  115   return num_10ms_frames_per_packet_; |  122   return Num10msFramesPerPacket(); | 
|  116 } |  123 } | 
|  117  |  124  | 
|  118 size_t AudioEncoderOpus::Max10MsFramesInAPacket() const { |  125 size_t AudioEncoderOpus::Max10MsFramesInAPacket() const { | 
|  119   return num_10ms_frames_per_packet_; |  126   return Num10msFramesPerPacket(); | 
|  120 } |  127 } | 
|  121  |  128  | 
|  122 int AudioEncoderOpus::GetTargetBitrate() const { |  129 int AudioEncoderOpus::GetTargetBitrate() const { | 
|  123   return bitrate_bps_; |  130   return config_.bitrate_bps; | 
|  124 } |  | 
|  125  |  | 
|  126 void AudioEncoderOpus::SetTargetBitrate(int bits_per_second) { |  | 
|  127   bitrate_bps_ = std::max(std::min(bits_per_second, kMaxBitrateBps), |  | 
|  128                           kMinBitrateBps); |  | 
|  129   CHECK_EQ(WebRtcOpus_SetBitRate(inst_, bitrate_bps_), 0); |  | 
|  130 } |  | 
|  131  |  | 
|  132 void AudioEncoderOpus::SetProjectedPacketLossRate(double fraction) { |  | 
|  133   DCHECK_GE(fraction, 0.0); |  | 
|  134   DCHECK_LE(fraction, 1.0); |  | 
|  135   // Optimize the loss rate to configure Opus. Basically, optimized loss rate is |  | 
|  136   // the input loss rate rounded down to various levels, because a robustly good |  | 
|  137   // audio quality is achieved by lowering the packet loss down. |  | 
|  138   // Additionally, to prevent toggling, margins are used, i.e., when jumping to |  | 
|  139   // a loss rate from below, a higher threshold is used than jumping to the same |  | 
|  140   // level from above. |  | 
|  141   const double kPacketLossRate20 = 0.20; |  | 
|  142   const double kPacketLossRate10 = 0.10; |  | 
|  143   const double kPacketLossRate5 = 0.05; |  | 
|  144   const double kPacketLossRate1 = 0.01; |  | 
|  145   const double kLossRate20Margin = 0.02; |  | 
|  146   const double kLossRate10Margin = 0.01; |  | 
|  147   const double kLossRate5Margin = 0.01; |  | 
|  148   double opt_loss_rate; |  | 
|  149   if (fraction >= |  | 
|  150       kPacketLossRate20 + |  | 
|  151           kLossRate20Margin * |  | 
|  152               (kPacketLossRate20 - packet_loss_rate_ > 0 ? 1 : -1)) { |  | 
|  153     opt_loss_rate = kPacketLossRate20; |  | 
|  154   } else if (fraction >= |  | 
|  155              kPacketLossRate10 + |  | 
|  156                  kLossRate10Margin * |  | 
|  157                      (kPacketLossRate10 - packet_loss_rate_ > 0 ? 1 : -1)) { |  | 
|  158     opt_loss_rate = kPacketLossRate10; |  | 
|  159   } else if (fraction >= |  | 
|  160              kPacketLossRate5 + |  | 
|  161                  kLossRate5Margin * |  | 
|  162                      (kPacketLossRate5 - packet_loss_rate_ > 0 ? 1 : -1)) { |  | 
|  163     opt_loss_rate = kPacketLossRate5; |  | 
|  164   } else if (fraction >= kPacketLossRate1) { |  | 
|  165     opt_loss_rate = kPacketLossRate1; |  | 
|  166   } else { |  | 
|  167     opt_loss_rate = 0; |  | 
|  168   } |  | 
|  169  |  | 
|  170   if (packet_loss_rate_ != opt_loss_rate) { |  | 
|  171     // Ask the encoder to change the target packet loss rate. |  | 
|  172     CHECK_EQ(WebRtcOpus_SetPacketLossRate( |  | 
|  173                  inst_, static_cast<int32_t>(opt_loss_rate * 100 + .5)), |  | 
|  174              0); |  | 
|  175     packet_loss_rate_ = opt_loss_rate; |  | 
|  176   } |  | 
|  177 } |  131 } | 
|  178  |  132  | 
|  179 AudioEncoder::EncodedInfo AudioEncoderOpus::EncodeInternal( |  133 AudioEncoder::EncodedInfo AudioEncoderOpus::EncodeInternal( | 
|  180     uint32_t rtp_timestamp, |  134     uint32_t rtp_timestamp, | 
|  181     const int16_t* audio, |  135     const int16_t* audio, | 
|  182     size_t max_encoded_bytes, |  136     size_t max_encoded_bytes, | 
|  183     uint8_t* encoded) { |  137     uint8_t* encoded) { | 
|  184   if (input_buffer_.empty()) |  138   if (input_buffer_.empty()) | 
|  185     first_timestamp_in_buffer_ = rtp_timestamp; |  139     first_timestamp_in_buffer_ = rtp_timestamp; | 
|  186   input_buffer_.insert(input_buffer_.end(), audio, |  140   input_buffer_.insert(input_buffer_.end(), audio, | 
|  187                        audio + samples_per_10ms_frame_); |  141                        audio + SamplesPer10msFrame()); | 
|  188   if (input_buffer_.size() < |  142   if (input_buffer_.size() < | 
|  189       (num_10ms_frames_per_packet_ * samples_per_10ms_frame_)) { |  143       (static_cast<size_t>(Num10msFramesPerPacket()) * SamplesPer10msFrame())) { | 
|  190     return EncodedInfo(); |  144     return EncodedInfo(); | 
|  191   } |  145   } | 
|  192   CHECK_EQ(input_buffer_.size(), |  146   CHECK_EQ(input_buffer_.size(), static_cast<size_t>(Num10msFramesPerPacket()) * | 
|  193            num_10ms_frames_per_packet_ * samples_per_10ms_frame_); |  147                                      SamplesPer10msFrame()); | 
|  194   int status = WebRtcOpus_Encode( |  148   int status = WebRtcOpus_Encode( | 
|  195       inst_, &input_buffer_[0], |  149       inst_, &input_buffer_[0], | 
|  196       rtc::CheckedDivExact(input_buffer_.size(), |  150       rtc::CheckedDivExact(input_buffer_.size(), | 
|  197                            static_cast<size_t>(num_channels_)), |  151                            static_cast<size_t>(config_.num_channels)), | 
|  198       max_encoded_bytes, encoded); |  152       rtc::saturated_cast<int16_t>(max_encoded_bytes), encoded); | 
|  199   CHECK_GE(status, 0);  // Fails only if fed invalid data. |  153   CHECK_GE(status, 0);  // Fails only if fed invalid data. | 
|  200   input_buffer_.clear(); |  154   input_buffer_.clear(); | 
|  201   EncodedInfo info; |  155   EncodedInfo info; | 
|  202   info.encoded_bytes = static_cast<size_t>(status); |  156   info.encoded_bytes = static_cast<size_t>(status); | 
|  203   info.encoded_timestamp = first_timestamp_in_buffer_; |  157   info.encoded_timestamp = first_timestamp_in_buffer_; | 
|  204   info.payload_type = payload_type_; |  158   info.payload_type = config_.payload_type; | 
|  205   info.send_even_if_empty = true;  // Allows Opus to send empty packets. |  159   info.send_even_if_empty = true;  // Allows Opus to send empty packets. | 
|  206   info.speech = (status > 0); |  160   info.speech = (status > 0); | 
|  207   return info; |  161   return info; | 
|  208 } |  162 } | 
|  209  |  163  | 
|  210 namespace { |  164 void AudioEncoderOpus::Reset() { | 
|  211 AudioEncoderOpus::Config CreateConfig(const CodecInst& codec_inst) { |  165   CHECK(RecreateEncoderInstance(config_)); | 
|  212   AudioEncoderOpus::Config config; |  | 
|  213   config.frame_size_ms = rtc::CheckedDivExact(codec_inst.pacsize, 48); |  | 
|  214   config.num_channels = codec_inst.channels; |  | 
|  215   config.bitrate_bps = codec_inst.rate; |  | 
|  216   config.payload_type = codec_inst.pltype; |  | 
|  217   config.application = (config.num_channels == 1 ? AudioEncoderOpus::kVoip |  | 
|  218                                                  : AudioEncoderOpus::kAudio); |  | 
|  219   return config; |  | 
|  220 } |  | 
|  221 }  // namespace |  | 
|  222  |  | 
|  223 AudioEncoderMutableOpus::AudioEncoderMutableOpus(const CodecInst& codec_inst) |  | 
|  224     : AudioEncoderMutableImpl<AudioEncoderOpus>(CreateConfig(codec_inst)) { |  | 
|  225 } |  166 } | 
|  226  |  167  | 
|  227 bool AudioEncoderMutableOpus::SetFec(bool enable) { |  168 bool AudioEncoderOpus::SetFec(bool enable) { | 
|  228   auto conf = config(); |  169   auto conf = config_; | 
|  229   conf.fec_enabled = enable; |  170   conf.fec_enabled = enable; | 
|  230   return Reconstruct(conf); |  171   return RecreateEncoderInstance(conf); | 
|  231 } |  172 } | 
|  232  |  173  | 
|  233 bool AudioEncoderMutableOpus::SetDtx(bool enable) { |  174 bool AudioEncoderOpus::SetDtx(bool enable) { | 
|  234   auto conf = config(); |  175   auto conf = config_; | 
|  235   conf.dtx_enabled = enable; |  176   conf.dtx_enabled = enable; | 
|  236   return Reconstruct(conf); |  177   return RecreateEncoderInstance(conf); | 
|  237 } |  178 } | 
|  238  |  179  | 
|  239 bool AudioEncoderMutableOpus::SetApplication(Application application) { |  180 bool AudioEncoderOpus::SetApplication(Application application) { | 
|  240   auto conf = config(); |  181   auto conf = config_; | 
|  241   switch (application) { |  182   switch (application) { | 
|  242     case kApplicationSpeech: |  183     case Application::kSpeech: | 
|  243       conf.application = AudioEncoderOpus::kVoip; |  184       conf.application = AudioEncoderOpus::kVoip; | 
|  244       break; |  185       break; | 
|  245     case kApplicationAudio: |  186     case Application::kAudio: | 
|  246       conf.application = AudioEncoderOpus::kAudio; |  187       conf.application = AudioEncoderOpus::kAudio; | 
|  247       break; |  188       break; | 
|  248   } |  189   } | 
|  249   return Reconstruct(conf); |  190   return RecreateEncoderInstance(conf); | 
|  250 } |  191 } | 
|  251  |  192  | 
|  252 bool AudioEncoderMutableOpus::SetMaxPlaybackRate(int frequency_hz) { |  193 bool AudioEncoderOpus::SetMaxPlaybackRate(int frequency_hz) { | 
|  253   auto conf = config(); |  194   auto conf = config_; | 
|  254   conf.max_playback_rate_hz = frequency_hz; |  195   conf.max_playback_rate_hz = frequency_hz; | 
|  255   return Reconstruct(conf); |  196   return RecreateEncoderInstance(conf); | 
 |  197 } | 
 |  198  | 
 |  199 void AudioEncoderOpus::SetProjectedPacketLossRate(double fraction) { | 
 |  200   double opt_loss_rate = OptimizePacketLossRate(fraction, packet_loss_rate_); | 
 |  201   if (packet_loss_rate_ != opt_loss_rate) { | 
 |  202     packet_loss_rate_ = opt_loss_rate; | 
 |  203     CHECK_EQ(0, WebRtcOpus_SetPacketLossRate( | 
 |  204                     inst_, static_cast<int32_t>(packet_loss_rate_ * 100 + .5))); | 
 |  205   } | 
 |  206 } | 
 |  207  | 
 |  208 void AudioEncoderOpus::SetTargetBitrate(int bits_per_second) { | 
 |  209   config_.bitrate_bps = | 
 |  210       std::max(std::min(bits_per_second, kMaxBitrateBps), kMinBitrateBps); | 
 |  211   DCHECK(config_.IsOk()); | 
 |  212   CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, config_.bitrate_bps)); | 
 |  213 } | 
 |  214  | 
 |  215 int AudioEncoderOpus::Num10msFramesPerPacket() const { | 
 |  216   return rtc::CheckedDivExact(config_.frame_size_ms, 10); | 
 |  217 } | 
 |  218  | 
 |  219 int AudioEncoderOpus::SamplesPer10msFrame() const { | 
 |  220   return rtc::CheckedDivExact(kSampleRateHz, 100) * config_.num_channels; | 
 |  221 } | 
 |  222  | 
 |  223 // 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 | 
 |  225 // false. | 
 |  226 bool AudioEncoderOpus::RecreateEncoderInstance(const Config& config) { | 
 |  227   if (!config.IsOk()) | 
 |  228     return false; | 
 |  229   if (inst_) | 
 |  230     CHECK_EQ(0, WebRtcOpus_EncoderFree(inst_)); | 
 |  231   input_buffer_.clear(); | 
 |  232   input_buffer_.reserve(Num10msFramesPerPacket() * SamplesPer10msFrame()); | 
 |  233   CHECK_EQ(0, WebRtcOpus_EncoderCreate(&inst_, config.num_channels, | 
 |  234                                        config.application)); | 
 |  235   CHECK_EQ(0, WebRtcOpus_SetBitRate(inst_, config.bitrate_bps)); | 
 |  236   if (config.fec_enabled) { | 
 |  237     CHECK_EQ(0, WebRtcOpus_EnableFec(inst_)); | 
 |  238   } else { | 
 |  239     CHECK_EQ(0, WebRtcOpus_DisableFec(inst_)); | 
 |  240   } | 
 |  241   CHECK_EQ(0, | 
 |  242            WebRtcOpus_SetMaxPlaybackRate(inst_, config.max_playback_rate_hz)); | 
 |  243   CHECK_EQ(0, WebRtcOpus_SetComplexity(inst_, config.complexity)); | 
 |  244   if (config.dtx_enabled) { | 
 |  245     CHECK_EQ(0, WebRtcOpus_EnableDtx(inst_)); | 
 |  246   } else { | 
 |  247     CHECK_EQ(0, WebRtcOpus_DisableDtx(inst_)); | 
 |  248   } | 
 |  249   CHECK_EQ(0, WebRtcOpus_SetPacketLossRate( | 
 |  250                   inst_, static_cast<int32_t>(packet_loss_rate_ * 100 + .5))); | 
 |  251   config_ = config; | 
 |  252   return true; | 
|  256 } |  253 } | 
|  257  |  254  | 
|  258 }  // namespace webrtc |  255 }  // namespace webrtc | 
| OLD | NEW |