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/command_line.h"
6#include "base/logging.h"
7#include "content/public/common/content_switches.h"
8#include "content/renderer/media/mock_media_constraint_factory.h"
9#include "content/renderer/media/webrtc/webrtc_local_audio_track_adapter.h"
10#include "content/renderer/media/webrtc_audio_capturer.h"
11#include "content/renderer/media/webrtc_local_audio_track.h"
12#include "media/audio/audio_parameters.h"
13#include "media/base/audio_bus.h"
14#include "testing/gmock/include/gmock/gmock.h"
15#include "testing/gtest/include/gtest/gtest.h"
16#include "third_party/WebKit/public/platform/WebMediaConstraints.h"
17
18using ::testing::_;
19using ::testing::AtLeast;
20
21namespace content {
22
23namespace {
24
25class MockCapturerSource : public media::AudioCapturerSource {
26 public:
27  MockCapturerSource() {}
28  MOCK_METHOD3(Initialize, void(const media::AudioParameters& params,
29                                CaptureCallback* callback,
30                                int session_id));
31  MOCK_METHOD0(Start, void());
32  MOCK_METHOD0(Stop, void());
33  MOCK_METHOD1(SetVolume, void(double volume));
34  MOCK_METHOD1(SetAutomaticGainControl, void(bool enable));
35
36 protected:
37  virtual ~MockCapturerSource() {}
38};
39
40class MockPeerConnectionAudioSink : public PeerConnectionAudioSink {
41 public:
42  MockPeerConnectionAudioSink() {}
43  ~MockPeerConnectionAudioSink() {}
44  virtual int OnData(const int16* audio_data, int sample_rate,
45                     int number_of_channels, int number_of_frames,
46                     const std::vector<int>& channels,
47                     int audio_delay_milliseconds, int current_volume,
48                     bool need_audio_processing, bool key_pressed) OVERRIDE {
49    EXPECT_EQ(sample_rate, params_.sample_rate());
50    EXPECT_EQ(number_of_channels, params_.channels());
51    EXPECT_EQ(number_of_frames, params_.frames_per_buffer());
52    OnDataCallback(audio_data, channels, audio_delay_milliseconds,
53                   current_volume, need_audio_processing, key_pressed);
54    return 0;
55  }
56  MOCK_METHOD6(OnDataCallback, void(const int16* audio_data,
57                                    const std::vector<int>& channels,
58                                    int audio_delay_milliseconds,
59                                    int current_volume,
60                                    bool need_audio_processing,
61                                    bool key_pressed));
62  virtual void OnSetFormat(const media::AudioParameters& params) OVERRIDE {
63    params_ = params;
64    FormatIsSet();
65  }
66  MOCK_METHOD0(FormatIsSet, void());
67
68 private:
69  media::AudioParameters params_;
70};
71
72}  // namespace
73
74class WebRtcAudioCapturerTest : public testing::Test {
75 protected:
76  WebRtcAudioCapturerTest()
77#if defined(OS_ANDROID)
78      : params_(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
79                media::CHANNEL_LAYOUT_STEREO, 48000, 16, 960) {
80    // Android works with a buffer size bigger than 20ms.
81#else
82      : params_(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
83                media::CHANNEL_LAYOUT_STEREO, 48000, 16, 128) {
84#endif
85  }
86
87  void DisableAudioTrackProcessing() {
88    CommandLine::ForCurrentProcess()->AppendSwitch(
89        switches::kDisableAudioTrackProcessing);
90  }
91
92  void VerifyAudioParams(const blink::WebMediaConstraints& constraints,
93                         bool need_audio_processing) {
94    capturer_ = WebRtcAudioCapturer::CreateCapturer(
95        -1, StreamDeviceInfo(MEDIA_DEVICE_AUDIO_CAPTURE,
96                             "", "", params_.sample_rate(),
97                             params_.channel_layout(),
98                             params_.frames_per_buffer()),
99        constraints, NULL, NULL);
100    capturer_source_ = new MockCapturerSource();
101    EXPECT_CALL(*capturer_source_.get(), Initialize(_, capturer_.get(), -1));
102    EXPECT_CALL(*capturer_source_.get(), SetAutomaticGainControl(true));
103    EXPECT_CALL(*capturer_source_.get(), Start());
104    capturer_->SetCapturerSourceForTesting(capturer_source_, params_);
105
106    scoped_refptr<WebRtcLocalAudioTrackAdapter> adapter(
107        WebRtcLocalAudioTrackAdapter::Create(std::string(), NULL));
108    track_.reset(new WebRtcLocalAudioTrack(adapter.get(), capturer_, NULL));
109    track_->Start();
110
111    // Connect a mock sink to the track.
112    scoped_ptr<MockPeerConnectionAudioSink> sink(
113        new MockPeerConnectionAudioSink());
114    track_->AddSink(sink.get());
115
116    int delay_ms = 65;
117    bool key_pressed = true;
118    double volume = 0.9;
119
120    // MaxVolume() in WebRtcAudioCapturer is hard-coded to return 255, we add
121    // 0.5 to do the correct truncation like the production code does.
122    int expected_volume_value = volume * capturer_->MaxVolume() + 0.5;
123    scoped_ptr<media::AudioBus> audio_bus = media::AudioBus::Create(params_);
124    audio_bus->Zero();
125
126    media::AudioCapturerSource::CaptureCallback* callback =
127        static_cast<media::AudioCapturerSource::CaptureCallback*>(
128            capturer_.get());
129
130    // Verify the sink is getting the correct values.
131    EXPECT_CALL(*sink, FormatIsSet());
132    EXPECT_CALL(*sink,
133                OnDataCallback(_, _, delay_ms, expected_volume_value,
134                               need_audio_processing, key_pressed))
135        .Times(AtLeast(1));
136    callback->Capture(audio_bus.get(), delay_ms, volume, key_pressed);
137
138    // Verify the cached values in the capturer fits what we expect.
139    base::TimeDelta cached_delay;
140    int cached_volume = !expected_volume_value;
141    bool cached_key_pressed = !key_pressed;
142    capturer_->GetAudioProcessingParams(&cached_delay, &cached_volume,
143                                        &cached_key_pressed);
144    EXPECT_EQ(cached_delay.InMilliseconds(), delay_ms);
145    EXPECT_EQ(cached_volume, expected_volume_value);
146    EXPECT_EQ(cached_key_pressed, key_pressed);
147
148    track_->RemoveSink(sink.get());
149    EXPECT_CALL(*capturer_source_.get(), Stop());
150    capturer_->Stop();
151  }
152
153  media::AudioParameters params_;
154  scoped_refptr<MockCapturerSource> capturer_source_;
155  scoped_refptr<WebRtcAudioCapturer> capturer_;
156  scoped_ptr<WebRtcLocalAudioTrack> track_;
157};
158
159// Pass the delay value, volume and key_pressed info via capture callback, and
160// those values should be correctly stored and passed to the track.
161TEST_F(WebRtcAudioCapturerTest, VerifyAudioParamsWithoutAudioProcessing) {
162  DisableAudioTrackProcessing();
163  // Use constraints with default settings.
164  MockMediaConstraintFactory constraint_factory;
165  VerifyAudioParams(constraint_factory.CreateWebMediaConstraints(), true);
166}
167
168TEST_F(WebRtcAudioCapturerTest, VerifyAudioParamsWithAudioProcessing) {
169  // Turn off the default constraints to verify that the sink will get packets
170  // with a buffer size smaller than 10ms.
171  MockMediaConstraintFactory constraint_factory;
172  constraint_factory.DisableDefaultAudioConstraints();
173  VerifyAudioParams(constraint_factory.CreateWebMediaConstraints(), false);
174}
175
176TEST_F(WebRtcAudioCapturerTest, FailToCreateCapturerWithWrongConstraints) {
177  MockMediaConstraintFactory constraint_factory;
178  const std::string dummy_constraint = "dummy";
179  constraint_factory.AddMandatory(dummy_constraint, true);
180
181  scoped_refptr<WebRtcAudioCapturer> capturer(
182      WebRtcAudioCapturer::CreateCapturer(
183          0, StreamDeviceInfo(MEDIA_DEVICE_AUDIO_CAPTURE,
184                               "", "", params_.sample_rate(),
185                               params_.channel_layout(),
186                               params_.frames_per_buffer()),
187          constraint_factory.CreateWebMediaConstraints(), NULL, NULL)
188  );
189  EXPECT_TRUE(capturer.get() == NULL);
190}
191
192
193}  // namespace content
194