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.
ApplyFixedAudioConstraints(RTCMediaConstraints * constraints)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:
MockCapturerSource()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:
~MockCapturerSource()65 virtual ~MockCapturerSource() {}
66 };
67
68 class MockPeerConnectionAudioSink : public PeerConnectionAudioSink {
69 public:
MockPeerConnectionAudioSink()70 MockPeerConnectionAudioSink() {}
~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:
WebRtcAudioCapturerTest()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.
TEST_F(WebRtcAudioCapturerTest,VerifyAudioParams)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