Home | History | Annotate | Download | only in media
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/logging.h"
      6 #include "content/renderer/media/rtc_media_constraints.h"
      7 #include "content/renderer/media/webrtc_audio_capturer.h"
      8 #include "content/renderer/media/webrtc_local_audio_track.h"
      9 #include "media/audio/audio_parameters.h"
     10 #include "media/base/audio_bus.h"
     11 #include "testing/gmock/include/gmock/gmock.h"
     12 #include "testing/gtest/include/gtest/gtest.h"
     13 
     14 using ::testing::_;
     15 using ::testing::AtLeast;
     16 
     17 namespace content {
     18 
     19 namespace {
     20 
     21 // TODO(xians): Consolidate the similar methods in different unittests into
     22 // one.
     23 void ApplyFixedAudioConstraints(RTCMediaConstraints* constraints) {
     24   // Constant constraint keys which enables default audio constraints on
     25   // mediastreams with audio.
     26   struct {
     27     const char* key;
     28     const char* value;
     29   } static const kDefaultAudioConstraints[] = {
     30     { webrtc::MediaConstraintsInterface::kEchoCancellation,
     31       webrtc::MediaConstraintsInterface::kValueTrue },
     32   #if defined(OS_CHROMEOS) || defined(OS_MACOSX)
     33     // Enable the extended filter mode AEC on platforms with known echo issues.
     34     { webrtc::MediaConstraintsInterface::kExperimentalEchoCancellation,
     35       webrtc::MediaConstraintsInterface::kValueTrue },
     36   #endif
     37     { webrtc::MediaConstraintsInterface::kAutoGainControl,
     38       webrtc::MediaConstraintsInterface::kValueTrue },
     39     { webrtc::MediaConstraintsInterface::kExperimentalAutoGainControl,
     40       webrtc::MediaConstraintsInterface::kValueTrue },
     41     { webrtc::MediaConstraintsInterface::kNoiseSuppression,
     42       webrtc::MediaConstraintsInterface::kValueTrue },
     43     { webrtc::MediaConstraintsInterface::kHighpassFilter,
     44       webrtc::MediaConstraintsInterface::kValueTrue },
     45   };
     46 
     47   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kDefaultAudioConstraints); ++i) {
     48     constraints->AddMandatory(kDefaultAudioConstraints[i].key,
     49                               kDefaultAudioConstraints[i].value, false);
     50   }
     51 }
     52 
     53 class MockCapturerSource : public media::AudioCapturerSource {
     54  public:
     55   MockCapturerSource() {}
     56   MOCK_METHOD3(Initialize, void(const media::AudioParameters& params,
     57                                 CaptureCallback* callback,
     58                                 int session_id));
     59   MOCK_METHOD0(Start, void());
     60   MOCK_METHOD0(Stop, void());
     61   MOCK_METHOD1(SetVolume, void(double volume));
     62   MOCK_METHOD1(SetAutomaticGainControl, void(bool enable));
     63 
     64  protected:
     65   virtual ~MockCapturerSource() {}
     66 };
     67 
     68 class MockPeerConnectionAudioSink : public PeerConnectionAudioSink {
     69  public:
     70   MockPeerConnectionAudioSink() {}
     71   ~MockPeerConnectionAudioSink() {}
     72   MOCK_METHOD9(OnData, int(const int16* audio_data,
     73                            int sample_rate,
     74                            int number_of_channels,
     75                            int number_of_frames,
     76                            const std::vector<int>& channels,
     77                            int audio_delay_milliseconds,
     78                            int current_volume,
     79                            bool need_audio_processing,
     80                            bool key_pressed));
     81   MOCK_METHOD1(OnSetFormat, void(const media::AudioParameters& params));
     82 };
     83 
     84 }  // namespace
     85 
     86 class WebRtcAudioCapturerTest : public testing::Test {
     87  protected:
     88   WebRtcAudioCapturerTest()
     89 #if defined(OS_ANDROID)
     90       : params_(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
     91                 media::CHANNEL_LAYOUT_STEREO, 48000, 16, 960) {
     92     // Android works with a buffer size bigger than 20ms.
     93 #else
     94       : params_(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
     95                 media::CHANNEL_LAYOUT_STEREO, 48000, 16, 128) {
     96 #endif
     97     capturer_ = WebRtcAudioCapturer::CreateCapturer();
     98     capturer_->Initialize(-1, params_.channel_layout(), params_.sample_rate(),
     99                           params_.frames_per_buffer(), 0, std::string(), 0, 0,
    100                           params_.effects());
    101     capturer_source_ = new MockCapturerSource();
    102     EXPECT_CALL(*capturer_source_.get(), Initialize(_, capturer_.get(), 0));
    103     capturer_->SetCapturerSource(capturer_source_,
    104                                  params_.channel_layout(),
    105                                  params_.sample_rate(),
    106                                  params_.effects());
    107 
    108     EXPECT_CALL(*capturer_source_.get(), SetAutomaticGainControl(true));
    109     EXPECT_CALL(*capturer_source_.get(), Start());
    110     RTCMediaConstraints constraints;
    111     ApplyFixedAudioConstraints(&constraints);
    112     track_ = WebRtcLocalAudioTrack::Create(std::string(), capturer_, NULL,
    113                                            NULL, &constraints);
    114     static_cast<WebRtcLocalAudioSourceProvider*>(
    115         track_->audio_source_provider())->SetSinkParamsForTesting(params_);
    116     track_->Start();
    117     EXPECT_TRUE(track_->enabled());
    118   }
    119 
    120   media::AudioParameters params_;
    121   scoped_refptr<MockCapturerSource> capturer_source_;
    122   scoped_refptr<WebRtcAudioCapturer> capturer_;
    123   scoped_refptr<WebRtcLocalAudioTrack> track_;
    124 };
    125 
    126 // Pass the delay value, vollume and key_pressed info via capture callback, and
    127 // those values should be correctly stored and passed to the track.
    128 TEST_F(WebRtcAudioCapturerTest, VerifyAudioParams) {
    129   // Connect a mock sink to the track.
    130   scoped_ptr<MockPeerConnectionAudioSink> sink(
    131       new MockPeerConnectionAudioSink());
    132   track_->AddSink(sink.get());
    133 
    134   int delay_ms = 65;
    135   bool key_pressed = true;
    136   double volume = 0.9;
    137   // MaxVolume() in WebRtcAudioCapturer is hard-coded to return 255, we add 0.5
    138   // to do the correct truncation as how the production code does.
    139   int expected_volume_value = volume * capturer_->MaxVolume() + 0.5;
    140   scoped_ptr<media::AudioBus> audio_bus = media::AudioBus::Create(params_);
    141   audio_bus->Zero();
    142 #if defined(OS_ANDROID)
    143   const int expected_buffer_size = params_.sample_rate() / 100;
    144 #else
    145   const int expected_buffer_size = params_.frames_per_buffer();
    146 #endif
    147   bool expected_need_audio_processing = true;
    148   media::AudioCapturerSource::CaptureCallback* callback =
    149       static_cast<media::AudioCapturerSource::CaptureCallback*>(capturer_);
    150   // Verify the sink is getting the correct values.
    151   EXPECT_CALL(*sink, OnSetFormat(_));
    152   EXPECT_CALL(*sink,
    153               OnData(_, params_.sample_rate(), params_.channels(),
    154                      expected_buffer_size, _, delay_ms,
    155                      expected_volume_value, expected_need_audio_processing,
    156                      key_pressed)).Times(AtLeast(1));
    157   callback->Capture(audio_bus.get(), delay_ms, volume, key_pressed);
    158 
    159   // Verify the cached values in the capturer fits what we expect.
    160   base::TimeDelta cached_delay;
    161   int cached_volume = !expected_volume_value;
    162   bool cached_key_pressed = !key_pressed;
    163   capturer_->GetAudioProcessingParams(&cached_delay, &cached_volume,
    164                                       &cached_key_pressed);
    165   EXPECT_EQ(cached_delay.InMilliseconds(), delay_ms);
    166   EXPECT_EQ(cached_volume, expected_volume_value);
    167   EXPECT_EQ(cached_key_pressed, key_pressed);
    168 
    169   track_->RemoveSink(sink.get());
    170   EXPECT_CALL(*capturer_source_.get(), Stop());
    171   capturer_->Stop();
    172 }
    173 
    174 }  // namespace content
    175