| Index: webrtc/modules/audio_mixer/audio_mixer_impl_unittest.cc
 | 
| diff --git a/webrtc/modules/audio_mixer/audio_mixer_impl_unittest.cc b/webrtc/modules/audio_mixer/audio_mixer_impl_unittest.cc
 | 
| index e90dac1e70e9839f032da4db4f91b8eb0d002686..f651fe978315fa01dbcad9ab0f0dc873a3129c2d 100644
 | 
| --- a/webrtc/modules/audio_mixer/audio_mixer_impl_unittest.cc
 | 
| +++ b/webrtc/modules/audio_mixer/audio_mixer_impl_unittest.cc
 | 
| @@ -12,10 +12,13 @@
 | 
|  
 | 
|  #include <limits>
 | 
|  #include <memory>
 | 
| +#include <sstream>
 | 
| +#include <string>
 | 
|  #include <utility>
 | 
|  
 | 
|  #include "webrtc/api/audio/audio_mixer.h"
 | 
|  #include "webrtc/base/bind.h"
 | 
| +#include "webrtc/base/checks.h"
 | 
|  #include "webrtc/base/thread.h"
 | 
|  #include "webrtc/modules/audio_mixer/audio_mixer_impl.h"
 | 
|  #include "webrtc/modules/audio_mixer/default_output_rate_calculator.h"
 | 
| @@ -46,6 +49,16 @@ void ResetFrame(AudioFrame* frame) {
 | 
|    frame->speech_type_ = AudioFrame::kNormalSpeech;
 | 
|  }
 | 
|  
 | 
| +std::string ProduceDebugText(int sample_rate_hz,
 | 
| +                             int number_of_channels,
 | 
| +                             int number_of_sources) {
 | 
| +  std::ostringstream ss;
 | 
| +  ss << "Sample rate: " << sample_rate_hz << " ";
 | 
| +  ss << "Number of channels: " << number_of_channels << " ";
 | 
| +  ss << "Number of sources: " << number_of_sources;
 | 
| +  return ss.str();
 | 
| +}
 | 
| +
 | 
|  AudioFrame frame_for_mixing;
 | 
|  
 | 
|  }  // namespace
 | 
| @@ -78,7 +91,8 @@ class MockMixerAudioSource : public AudioMixer::Source {
 | 
|                                          AudioFrame* audio_frame) {
 | 
|      audio_frame->CopyFrom(fake_frame_);
 | 
|      audio_frame->sample_rate_hz_ = sample_rate_hz;
 | 
| -    audio_frame->samples_per_channel_ = sample_rate_hz / 100;
 | 
| +    audio_frame->samples_per_channel_ =
 | 
| +        rtc::CheckedDivExact(sample_rate_hz, 100);
 | 
|      return fake_info();
 | 
|    }
 | 
|  
 | 
| @@ -89,7 +103,7 @@ class MockMixerAudioSource : public AudioMixer::Source {
 | 
|  class CustomRateCalculator : public OutputRateCalculator {
 | 
|   public:
 | 
|    explicit CustomRateCalculator(int rate) : rate_(rate) {}
 | 
| -  int CalculateOutputRate(const std::vector<int>& preferred_rates) {
 | 
| +  int CalculateOutputRate(const std::vector<int>& preferred_rates) override {
 | 
|      return rate_;
 | 
|    }
 | 
|  
 | 
| @@ -103,19 +117,19 @@ void MixAndCompare(
 | 
|      const std::vector<AudioFrame>& frames,
 | 
|      const std::vector<AudioMixer::Source::AudioFrameInfo>& frame_info,
 | 
|      const std::vector<bool>& expected_status) {
 | 
| -  int num_audio_sources = frames.size();
 | 
| +  const size_t num_audio_sources = frames.size();
 | 
|    RTC_DCHECK(frames.size() == frame_info.size());
 | 
|    RTC_DCHECK(frame_info.size() == expected_status.size());
 | 
|  
 | 
|    const auto mixer = AudioMixerImpl::Create();
 | 
|    std::vector<MockMixerAudioSource> participants(num_audio_sources);
 | 
|  
 | 
| -  for (int i = 0; i < num_audio_sources; i++) {
 | 
| +  for (size_t i = 0; i < num_audio_sources; ++i) {
 | 
|      participants[i].fake_frame()->CopyFrom(frames[i]);
 | 
|      participants[i].set_fake_info(frame_info[i]);
 | 
|    }
 | 
|  
 | 
| -  for (int i = 0; i < num_audio_sources; i++) {
 | 
| +  for (size_t i = 0; i < num_audio_sources; ++i) {
 | 
|      EXPECT_TRUE(mixer->AddSource(&participants[i]));
 | 
|      EXPECT_CALL(participants[i], GetAudioFrameWithInfo(kDefaultSampleRateHz, _))
 | 
|          .Times(Exactly(1));
 | 
| @@ -123,7 +137,7 @@ void MixAndCompare(
 | 
|  
 | 
|    mixer->Mix(1, &frame_for_mixing);
 | 
|  
 | 
| -  for (int i = 0; i < num_audio_sources; i++) {
 | 
| +  for (size_t i = 0; i < num_audio_sources; ++i) {
 | 
|      EXPECT_EQ(expected_status[i],
 | 
|                mixer->GetAudioSourceMixabilityStatusForTest(&participants[i]))
 | 
|          << "Mixed status of AudioSource #" << i << " wrong.";
 | 
| @@ -191,11 +205,11 @@ TEST(AudioMixer, FrameNotModifiedForSingleParticipant) {
 | 
|    MockMixerAudioSource participant;
 | 
|  
 | 
|    ResetFrame(participant.fake_frame());
 | 
| -  const int n_samples = participant.fake_frame()->samples_per_channel_;
 | 
| +  const size_t n_samples = participant.fake_frame()->samples_per_channel_;
 | 
|  
 | 
|    // Modify the frame so that it's not zero.
 | 
| -  for (int j = 0; j < n_samples; j++) {
 | 
| -    participant.fake_frame()->data_[j] = j;
 | 
| +  for (size_t j = 0; j < n_samples; ++j) {
 | 
| +    participant.fake_frame()->data_[j] = static_cast<int16_t>(j);
 | 
|    }
 | 
|  
 | 
|    EXPECT_TRUE(mixer->AddSource(&participant));
 | 
| @@ -203,7 +217,7 @@ TEST(AudioMixer, FrameNotModifiedForSingleParticipant) {
 | 
|  
 | 
|    AudioFrame audio_frame;
 | 
|    // Two mix iteration to compare after the ramp-up step.
 | 
| -  for (int i = 0; i < 2; i++) {
 | 
| +  for (int i = 0; i < 2; ++i) {
 | 
|      mixer->Mix(1,  // number of channels
 | 
|                 &audio_frame);
 | 
|    }
 | 
| @@ -310,7 +324,7 @@ TEST(AudioMixer, RampedOutSourcesShouldNotBeMarkedMixed) {
 | 
|    const auto mixer = AudioMixerImpl::Create();
 | 
|    MockMixerAudioSource participants[kAudioSources];
 | 
|  
 | 
| -  for (int i = 0; i < kAudioSources; i++) {
 | 
| +  for (int i = 0; i < kAudioSources; ++i) {
 | 
|      ResetFrame(participants[i].fake_frame());
 | 
|      // Set the participant audio energy to increase with the index
 | 
|      // |i|.
 | 
| @@ -318,7 +332,7 @@ TEST(AudioMixer, RampedOutSourcesShouldNotBeMarkedMixed) {
 | 
|    }
 | 
|  
 | 
|    // Add all participants but the loudest for mixing.
 | 
| -  for (int i = 0; i < kAudioSources - 1; i++) {
 | 
| +  for (int i = 0; i < kAudioSources - 1; ++i) {
 | 
|      EXPECT_TRUE(mixer->AddSource(&participants[i]));
 | 
|      EXPECT_CALL(participants[i], GetAudioFrameWithInfo(kDefaultSampleRateHz, _))
 | 
|          .Times(Exactly(1));
 | 
| @@ -328,14 +342,14 @@ TEST(AudioMixer, RampedOutSourcesShouldNotBeMarkedMixed) {
 | 
|    mixer->Mix(1, &frame_for_mixing);
 | 
|  
 | 
|    // All participants but the loudest should have been mixed.
 | 
| -  for (int i = 0; i < kAudioSources - 1; i++) {
 | 
| +  for (int i = 0; i < kAudioSources - 1; ++i) {
 | 
|      EXPECT_TRUE(mixer->GetAudioSourceMixabilityStatusForTest(&participants[i]))
 | 
|          << "Mixed status of AudioSource #" << i << " wrong.";
 | 
|    }
 | 
|  
 | 
|    // Add new participant with higher energy.
 | 
|    EXPECT_TRUE(mixer->AddSource(&participants[kAudioSources - 1]));
 | 
| -  for (int i = 0; i < kAudioSources; i++) {
 | 
| +  for (int i = 0; i < kAudioSources; ++i) {
 | 
|      EXPECT_CALL(participants[i], GetAudioFrameWithInfo(kDefaultSampleRateHz, _))
 | 
|          .Times(Exactly(1));
 | 
|    }
 | 
| @@ -347,7 +361,7 @@ TEST(AudioMixer, RampedOutSourcesShouldNotBeMarkedMixed) {
 | 
|        << "Mixed status of AudioSource #0 wrong.";
 | 
|  
 | 
|    // The loudest participants should have been mixed.
 | 
| -  for (int i = 1; i < kAudioSources; i++) {
 | 
| +  for (int i = 1; i < kAudioSources; ++i) {
 | 
|      EXPECT_EQ(true,
 | 
|                mixer->GetAudioSourceMixabilityStatusForTest(&participants[i]))
 | 
|          << "Mixed status of AudioSource #" << i << " wrong.";
 | 
| @@ -456,9 +470,10 @@ TEST(AudioMixer, UnmutedShouldMixBeforeLoud) {
 | 
|  
 | 
|  TEST(AudioMixer, MixingRateShouldBeDecidedByRateCalculator) {
 | 
|    constexpr int kOutputRate = 22000;
 | 
| -  const auto mixer = AudioMixerImpl::CreateWithOutputRateCalculator(
 | 
| +  const auto mixer = AudioMixerImpl::CreateWithOutputRateCalculatorAndLimiter(
 | 
|        std::unique_ptr<OutputRateCalculator>(
 | 
| -          new CustomRateCalculator(kOutputRate)));
 | 
| +          new CustomRateCalculator(kOutputRate)),
 | 
| +      true);
 | 
|    MockMixerAudioSource audio_source;
 | 
|    mixer->AddSource(&audio_source);
 | 
|    ResetFrame(audio_source.fake_frame());
 | 
| @@ -471,12 +486,48 @@ TEST(AudioMixer, MixingRateShouldBeDecidedByRateCalculator) {
 | 
|  
 | 
|  TEST(AudioMixer, ZeroSourceRateShouldBeDecidedByRateCalculator) {
 | 
|    constexpr int kOutputRate = 8000;
 | 
| -  const auto mixer = AudioMixerImpl::CreateWithOutputRateCalculator(
 | 
| +  const auto mixer = AudioMixerImpl::CreateWithOutputRateCalculatorAndLimiter(
 | 
|        std::unique_ptr<OutputRateCalculator>(
 | 
| -          new CustomRateCalculator(kOutputRate)));
 | 
| +          new CustomRateCalculator(kOutputRate)),
 | 
| +      true);
 | 
|  
 | 
|    mixer->Mix(1, &frame_for_mixing);
 | 
|  
 | 
|    EXPECT_EQ(kOutputRate, frame_for_mixing.sample_rate_hz_);
 | 
|  }
 | 
| +
 | 
| +TEST(AudioMixer, NoLimiterBasicApiCalls) {
 | 
| +  const auto mixer = AudioMixerImpl::CreateWithOutputRateCalculatorAndLimiter(
 | 
| +      std::unique_ptr<OutputRateCalculator>(new DefaultOutputRateCalculator()),
 | 
| +      false);
 | 
| +  mixer->Mix(1, &frame_for_mixing);
 | 
| +}
 | 
| +
 | 
| +TEST(AudioMixer, AnyRateIsPossibleWithNoLimiter) {
 | 
| +  // No APM limiter means no AudioProcessing::NativeRate restriction
 | 
| +  // on mixing rate. The rate has to be divisible by 100 since we use
 | 
| +  // 10 ms frames, though.
 | 
| +  for (const auto rate : {8000, 20000, 24000, 32000, 44100}) {
 | 
| +    for (const size_t number_of_channels : {1, 2}) {
 | 
| +      for (const auto number_of_sources : {0, 1, 2, 3, 4}) {
 | 
| +        SCOPED_TRACE(
 | 
| +            ProduceDebugText(rate, number_of_sources, number_of_sources));
 | 
| +        const auto mixer =
 | 
| +            AudioMixerImpl::CreateWithOutputRateCalculatorAndLimiter(
 | 
| +                std::unique_ptr<OutputRateCalculator>(
 | 
| +                    new CustomRateCalculator(rate)),
 | 
| +                false);
 | 
| +
 | 
| +        std::vector<MockMixerAudioSource> sources(number_of_sources);
 | 
| +        for (auto& source : sources) {
 | 
| +          mixer->AddSource(&source);
 | 
| +        }
 | 
| +
 | 
| +        mixer->Mix(number_of_channels, &frame_for_mixing);
 | 
| +        EXPECT_EQ(rate, frame_for_mixing.sample_rate_hz_);
 | 
| +        EXPECT_EQ(number_of_channels, frame_for_mixing.num_channels_);
 | 
| +      }
 | 
| +    }
 | 
| +  }
 | 
| +}
 | 
|  }  // namespace webrtc
 | 
| 
 |