OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <stddef.h> | 5 #include <stddef.h> |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/macros.h" | 8 #include "base/macros.h" |
9 #include "base/message_loop/message_loop.h" | 9 #include "base/message_loop/message_loop.h" |
10 #include "base/run_loop.h" | 10 #include "base/run_loop.h" |
11 #include "media/base/audio_parameters.h" | 11 #include "media/base/audio_parameters.h" |
12 #include "media/base/fake_audio_render_callback.h" | 12 #include "media/base/fake_audio_render_callback.h" |
13 #include "media/base/media_log.h" | |
13 #include "media/base/mock_audio_renderer_sink.h" | 14 #include "media/base/mock_audio_renderer_sink.h" |
14 #include "media/blink/webaudiosourceprovider_impl.h" | 15 #include "media/blink/webaudiosourceprovider_impl.h" |
15 #include "testing/gmock/include/gmock/gmock.h" | 16 #include "testing/gmock/include/gmock/gmock.h" |
16 #include "testing/gtest/include/gtest/gtest.h" | 17 #include "testing/gtest/include/gtest/gtest.h" |
17 #include "third_party/WebKit/public/platform/WebAudioSourceProviderClient.h" | 18 #include "third_party/WebKit/public/platform/WebAudioSourceProviderClient.h" |
18 | 19 |
19 using ::testing::_; | 20 using ::testing::_; |
20 | 21 |
21 namespace media { | 22 namespace media { |
22 | 23 |
23 namespace { | 24 namespace { |
24 const float kTestVolume = 0.25; | 25 const float kTestVolume = 0.25; |
26 | |
27 class WebAudioSourceProviderImplUnderTest : public WebAudioSourceProviderImpl { | |
28 public: | |
29 WebAudioSourceProviderImplUnderTest( | |
30 const scoped_refptr<SwitchableAudioRendererSink>& sink) | |
DaleCurtis
2016/12/02 18:28:57
non const& for new code.
o1ka
2016/12/05 09:54:13
Done.
| |
31 : WebAudioSourceProviderImpl(sink, new MediaLog()), | |
32 fallback_sink_(new MockAudioRendererSink()) {} | |
33 | |
34 MockAudioRendererSink* fallback_sink() { return fallback_sink_.get(); } | |
35 | |
36 protected: | |
37 scoped_refptr<SwitchableAudioRendererSink> CreateFallbackSink() override { | |
38 return fallback_sink_; | |
39 } | |
40 | |
41 private: | |
42 ~WebAudioSourceProviderImplUnderTest() override = default; | |
43 scoped_refptr<MockAudioRendererSink> fallback_sink_; | |
44 }; | |
DaleCurtis
2016/12/02 18:28:57
DISALLOW_COPY_AND_ASSIGN?
o1ka
2016/12/05 09:54:13
Done.
| |
45 | |
46 enum WaspSinkStatus { WASP_SINK_OK = 0, WASP_SINK_ERROR, WASP_SINK_NULL }; | |
DaleCurtis
2016/12/02 18:28:57
I prefer enum class these days (no = 0), but up to
o1ka
2016/12/05 09:54:13
Done.
| |
47 | |
48 scoped_refptr<MockAudioRendererSink> CreateWaspMockSink(WaspSinkStatus status) { | |
49 if (status == WASP_SINK_NULL) | |
50 return nullptr; | |
51 return new MockAudioRendererSink((status == WASP_SINK_OK) | |
DaleCurtis
2016/12/02 18:28:57
No uneccesary parens.
o1ka
2016/12/05 09:54:13
Done.
| |
52 ? OUTPUT_DEVICE_STATUS_OK | |
53 : OUTPUT_DEVICE_STATUS_ERROR_INTERNAL); | |
54 } | |
55 | |
25 } // namespace | 56 } // namespace |
26 | 57 |
27 class WebAudioSourceProviderImplTest | 58 class WebAudioSourceProviderImplTest |
28 : public testing::Test, | 59 : public testing::TestWithParam<WaspSinkStatus>, |
29 public blink::WebAudioSourceProviderClient { | 60 public blink::WebAudioSourceProviderClient { |
30 public: | 61 public: |
31 WebAudioSourceProviderImplTest() | 62 WebAudioSourceProviderImplTest() |
32 : params_(AudioParameters::AUDIO_PCM_LINEAR, | 63 : params_(AudioParameters::AUDIO_PCM_LINEAR, |
33 CHANNEL_LAYOUT_STEREO, 48000, 16, 64), | 64 CHANNEL_LAYOUT_STEREO, |
65 48000, | |
66 16, | |
67 64), | |
34 fake_callback_(0.1), | 68 fake_callback_(0.1), |
35 mock_sink_(new MockAudioRendererSink()), | 69 mock_sink_(CreateWaspMockSink(GetParam())), |
36 wasp_impl_(new WebAudioSourceProviderImpl(mock_sink_)) { | 70 wasp_impl_(new WebAudioSourceProviderImplUnderTest(mock_sink_)), |
37 } | 71 expected_sink_((GetParam() == WASP_SINK_OK) |
DaleCurtis
2016/12/02 18:28:57
Drop unnecessary parens.
o1ka
2016/12/05 09:54:13
Done.
| |
72 ? mock_sink_.get() | |
73 : wasp_impl_->fallback_sink()) {} | |
38 | 74 |
39 virtual ~WebAudioSourceProviderImplTest() {} | 75 virtual ~WebAudioSourceProviderImplTest() {} |
40 | 76 |
41 void CallAllSinkMethodsAndVerify(bool verify) { | 77 void CallAllSinkMethodsAndVerify(bool verify) { |
42 testing::InSequence s; | 78 testing::InSequence s; |
43 | 79 |
44 EXPECT_CALL(*mock_sink_.get(), Start()).Times(verify); | 80 EXPECT_CALL(*expected_sink_, Start()).Times(verify); |
45 wasp_impl_->Start(); | 81 wasp_impl_->Start(); |
46 | 82 |
47 EXPECT_CALL(*mock_sink_.get(), Play()).Times(verify); | 83 EXPECT_CALL(*expected_sink_, Play()).Times(verify); |
48 wasp_impl_->Play(); | 84 wasp_impl_->Play(); |
49 | 85 |
50 EXPECT_CALL(*mock_sink_.get(), Pause()).Times(verify); | 86 EXPECT_CALL(*expected_sink_, Pause()).Times(verify); |
51 wasp_impl_->Pause(); | 87 wasp_impl_->Pause(); |
52 | 88 |
53 EXPECT_CALL(*mock_sink_.get(), SetVolume(kTestVolume)).Times(verify); | 89 EXPECT_CALL(*expected_sink_, SetVolume(kTestVolume)).Times(verify); |
54 wasp_impl_->SetVolume(kTestVolume); | 90 wasp_impl_->SetVolume(kTestVolume); |
55 | 91 |
56 EXPECT_CALL(*mock_sink_.get(), Stop()).Times(verify); | 92 EXPECT_CALL(*expected_sink_, Stop()).Times(verify); |
57 wasp_impl_->Stop(); | 93 wasp_impl_->Stop(); |
58 | 94 |
59 testing::Mock::VerifyAndClear(mock_sink_.get()); | 95 testing::Mock::VerifyAndClear(mock_sink_.get()); |
60 } | 96 } |
61 | 97 |
62 void SetClient(blink::WebAudioSourceProviderClient* client) { | 98 void SetClient(blink::WebAudioSourceProviderClient* client) { |
63 testing::InSequence s; | 99 testing::InSequence s; |
64 | 100 |
65 if (client) { | 101 if (client) { |
66 EXPECT_CALL(*mock_sink_.get(), Stop()); | 102 EXPECT_CALL(*expected_sink_, Stop()); |
67 EXPECT_CALL(*this, setFormat(params_.channels(), params_.sample_rate())); | 103 EXPECT_CALL(*this, setFormat(params_.channels(), params_.sample_rate())); |
68 } | 104 } |
69 wasp_impl_->setClient(client); | 105 wasp_impl_->setClient(client); |
70 base::RunLoop().RunUntilIdle(); | 106 base::RunLoop().RunUntilIdle(); |
71 | 107 |
72 testing::Mock::VerifyAndClear(mock_sink_.get()); | 108 testing::Mock::VerifyAndClear(mock_sink_.get()); |
109 testing::Mock::VerifyAndClear(wasp_impl_->fallback_sink()); | |
73 testing::Mock::VerifyAndClear(this); | 110 testing::Mock::VerifyAndClear(this); |
74 } | 111 } |
75 | 112 |
76 bool CompareBusses(const AudioBus* bus1, const AudioBus* bus2) { | 113 bool CompareBusses(const AudioBus* bus1, const AudioBus* bus2) { |
77 EXPECT_EQ(bus1->channels(), bus2->channels()); | 114 EXPECT_EQ(bus1->channels(), bus2->channels()); |
78 EXPECT_EQ(bus1->frames(), bus2->frames()); | 115 EXPECT_EQ(bus1->frames(), bus2->frames()); |
79 for (int ch = 0; ch < bus1->channels(); ++ch) { | 116 for (int ch = 0; ch < bus1->channels(); ++ch) { |
80 if (memcmp(bus1->channel(ch), bus2->channel(ch), | 117 if (memcmp(bus1->channel(ch), bus2->channel(ch), |
81 sizeof(*bus1->channel(ch)) * bus1->frames()) != 0) { | 118 sizeof(*bus1->channel(ch)) * bus1->frames()) != 0) { |
82 return false; | 119 return false; |
(...skipping 11 matching lines...) Expand all Loading... | |
94 void OnAudioBus(std::unique_ptr<AudioBus> bus, | 131 void OnAudioBus(std::unique_ptr<AudioBus> bus, |
95 uint32_t frames_delayed, | 132 uint32_t frames_delayed, |
96 int sample_rate) { | 133 int sample_rate) { |
97 DoCopyAudioCB(bus.get(), frames_delayed, sample_rate); | 134 DoCopyAudioCB(bus.get(), frames_delayed, sample_rate); |
98 } | 135 } |
99 | 136 |
100 int Render(AudioBus* audio_bus) { | 137 int Render(AudioBus* audio_bus) { |
101 return wasp_impl_->RenderForTesting(audio_bus); | 138 return wasp_impl_->RenderForTesting(audio_bus); |
102 } | 139 } |
103 | 140 |
141 void ExpectUnhealthySinkToStop() { | |
142 if (GetParam() == WASP_SINK_ERROR) { | |
DaleCurtis
2016/12/02 18:28:57
Don't need {} for single line if, but up to you.
o1ka
2016/12/05 09:54:13
Done.
| |
143 EXPECT_CALL(*mock_sink_.get(), Stop()); | |
144 } | |
145 } | |
146 | |
104 protected: | 147 protected: |
105 AudioParameters params_; | 148 AudioParameters params_; |
106 FakeAudioRenderCallback fake_callback_; | 149 FakeAudioRenderCallback fake_callback_; |
107 scoped_refptr<MockAudioRendererSink> mock_sink_; | 150 scoped_refptr<MockAudioRendererSink> mock_sink_; |
108 scoped_refptr<WebAudioSourceProviderImpl> wasp_impl_; | 151 scoped_refptr<WebAudioSourceProviderImplUnderTest> wasp_impl_; |
152 MockAudioRendererSink* expected_sink_; | |
109 base::MessageLoop message_loop_; | 153 base::MessageLoop message_loop_; |
110 | 154 |
111 DISALLOW_COPY_AND_ASSIGN(WebAudioSourceProviderImplTest); | 155 DISALLOW_COPY_AND_ASSIGN(WebAudioSourceProviderImplTest); |
112 }; | 156 }; |
113 | 157 |
114 TEST_F(WebAudioSourceProviderImplTest, SetClientBeforeInitialize) { | 158 TEST_P(WebAudioSourceProviderImplTest, SetClientBeforeInitialize) { |
115 // setClient() with a NULL client should do nothing if no client is set. | 159 // setClient() with a NULL client should do nothing if no client is set. |
116 wasp_impl_->setClient(NULL); | 160 wasp_impl_->setClient(NULL); |
117 | 161 |
118 EXPECT_CALL(*mock_sink_.get(), Stop()); | 162 // If |mock_sink_| is not null, it should be stopped during setClient(this). |
163 // If it is unhealthy, it should also be stopped during fallback in | |
164 // Initialize(). | |
165 if (mock_sink_) | |
166 EXPECT_CALL(*mock_sink_.get(), Stop()).Times(2 + GetParam()); | |
167 | |
119 wasp_impl_->setClient(this); | 168 wasp_impl_->setClient(this); |
120 base::RunLoop().RunUntilIdle(); | 169 base::RunLoop().RunUntilIdle(); |
121 | 170 |
171 if (mock_sink_) | |
172 EXPECT_CALL(*mock_sink_.get(), SetVolume(1)).Times(1); | |
173 wasp_impl_->setClient(NULL); | |
174 base::RunLoop().RunUntilIdle(); | |
175 | |
176 wasp_impl_->setClient(this); | |
177 base::RunLoop().RunUntilIdle(); | |
178 | |
122 // When Initialize() is called after setClient(), the params should propagate | 179 // When Initialize() is called after setClient(), the params should propagate |
123 // to the client via setFormat() during the call. | 180 // to the client via setFormat() during the call. |
124 EXPECT_CALL(*this, setFormat(params_.channels(), params_.sample_rate())); | 181 EXPECT_CALL(*this, setFormat(params_.channels(), params_.sample_rate())); |
125 wasp_impl_->Initialize(params_, &fake_callback_); | 182 wasp_impl_->Initialize(params_, &fake_callback_); |
126 base::RunLoop().RunUntilIdle(); | 183 base::RunLoop().RunUntilIdle(); |
127 | 184 |
128 // setClient() with the same client should do nothing. | 185 // setClient() with the same client should do nothing. |
129 wasp_impl_->setClient(this); | 186 wasp_impl_->setClient(this); |
130 base::RunLoop().RunUntilIdle(); | 187 base::RunLoop().RunUntilIdle(); |
131 } | 188 } |
132 | 189 |
133 // Verify AudioRendererSink functionality w/ and w/o a client. | 190 // Verify AudioRendererSink functionality w/ and w/o a client. |
134 TEST_F(WebAudioSourceProviderImplTest, SinkMethods) { | 191 TEST_P(WebAudioSourceProviderImplTest, SinkMethods) { |
192 ExpectUnhealthySinkToStop(); | |
135 wasp_impl_->Initialize(params_, &fake_callback_); | 193 wasp_impl_->Initialize(params_, &fake_callback_); |
136 | 194 |
137 // Without a client all WASP calls should fall through to the underlying sink. | 195 // Without a client all WASP calls should fall through to the underlying sink. |
138 CallAllSinkMethodsAndVerify(true); | 196 CallAllSinkMethodsAndVerify(true); |
139 | 197 |
140 // With a client no calls should reach the Stop()'d sink. Also, setClient() | 198 // With a client no calls should reach the Stop()'d sink. Also, setClient() |
141 // should propagate the params provided during Initialize() at call time. | 199 // should propagate the params provided during Initialize() at call time. |
142 SetClient(this); | 200 SetClient(this); |
143 CallAllSinkMethodsAndVerify(false); | 201 CallAllSinkMethodsAndVerify(false); |
144 | 202 |
145 // Removing the client should cause WASP to revert to the underlying sink. | 203 // Removing the client should cause WASP to revert to the underlying sink. |
146 EXPECT_CALL(*mock_sink_.get(), SetVolume(kTestVolume)); | 204 EXPECT_CALL(*expected_sink_, SetVolume(kTestVolume)); |
147 SetClient(NULL); | 205 SetClient(NULL); |
148 CallAllSinkMethodsAndVerify(true); | 206 CallAllSinkMethodsAndVerify(true); |
149 } | 207 } |
150 | 208 |
151 // Verify underlying sink state is restored after client removal. | 209 // Verify underlying sink state is restored after client removal. |
152 TEST_F(WebAudioSourceProviderImplTest, SinkStateRestored) { | 210 TEST_P(WebAudioSourceProviderImplTest, SinkStateRestored) { |
211 ExpectUnhealthySinkToStop(); | |
153 wasp_impl_->Initialize(params_, &fake_callback_); | 212 wasp_impl_->Initialize(params_, &fake_callback_); |
154 | 213 |
155 // Verify state set before the client is set propagates back afterward. | 214 // Verify state set before the client is set propagates back afterward. |
156 EXPECT_CALL(*mock_sink_.get(), Start()); | 215 EXPECT_CALL(*expected_sink_, Start()); |
157 wasp_impl_->Start(); | 216 wasp_impl_->Start(); |
158 SetClient(this); | 217 SetClient(this); |
159 | 218 |
160 EXPECT_CALL(*mock_sink_.get(), SetVolume(1.0)); | 219 EXPECT_CALL(*expected_sink_, SetVolume(1.0)); |
161 EXPECT_CALL(*mock_sink_.get(), Start()); | 220 EXPECT_CALL(*expected_sink_, Start()); |
162 SetClient(NULL); | 221 SetClient(NULL); |
163 | 222 |
164 // Verify state set while the client was attached propagates back afterward. | 223 // Verify state set while the client was attached propagates back afterward. |
165 SetClient(this); | 224 SetClient(this); |
166 wasp_impl_->Play(); | 225 wasp_impl_->Play(); |
167 wasp_impl_->SetVolume(kTestVolume); | 226 wasp_impl_->SetVolume(kTestVolume); |
168 | 227 |
169 EXPECT_CALL(*mock_sink_.get(), SetVolume(kTestVolume)); | 228 EXPECT_CALL(*expected_sink_, SetVolume(kTestVolume)); |
170 EXPECT_CALL(*mock_sink_.get(), Start()); | 229 EXPECT_CALL(*expected_sink_, Start()); |
171 EXPECT_CALL(*mock_sink_.get(), Play()); | 230 EXPECT_CALL(*expected_sink_, Play()); |
172 SetClient(NULL); | 231 SetClient(NULL); |
173 } | 232 } |
174 | 233 |
175 // Test the AudioRendererSink state machine and its effects on provideInput(). | 234 // Test the AudioRendererSink state machine and its effects on provideInput(). |
176 TEST_F(WebAudioSourceProviderImplTest, ProvideInput) { | 235 TEST_P(WebAudioSourceProviderImplTest, ProvideInput) { |
236 ExpectUnhealthySinkToStop(); | |
177 std::unique_ptr<AudioBus> bus1 = AudioBus::Create(params_); | 237 std::unique_ptr<AudioBus> bus1 = AudioBus::Create(params_); |
178 std::unique_ptr<AudioBus> bus2 = AudioBus::Create(params_); | 238 std::unique_ptr<AudioBus> bus2 = AudioBus::Create(params_); |
179 | 239 |
180 // Point the WebVector into memory owned by |bus1|. | 240 // Point the WebVector into memory owned by |bus1|. |
181 blink::WebVector<float*> audio_data(static_cast<size_t>(bus1->channels())); | 241 blink::WebVector<float*> audio_data(static_cast<size_t>(bus1->channels())); |
182 for (size_t i = 0; i < audio_data.size(); ++i) | 242 for (size_t i = 0; i < audio_data.size(); ++i) |
183 audio_data[i] = bus1->channel(static_cast<int>(i)); | 243 audio_data[i] = bus1->channel(static_cast<int>(i)); |
184 | 244 |
185 // Verify provideInput() works before Initialize() and returns silence. | 245 // Verify provideInput() works before Initialize() and returns silence. |
186 bus1->channel(0)[0] = 1; | 246 bus1->channel(0)[0] = 1; |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
252 | 312 |
253 // Stop() should return silence. | 313 // Stop() should return silence. |
254 wasp_impl_->Stop(); | 314 wasp_impl_->Stop(); |
255 bus1->channel(0)[0] = 1; | 315 bus1->channel(0)[0] = 1; |
256 bus2->Zero(); | 316 bus2->Zero(); |
257 wasp_impl_->provideInput(audio_data, params_.frames_per_buffer()); | 317 wasp_impl_->provideInput(audio_data, params_.frames_per_buffer()); |
258 ASSERT_TRUE(CompareBusses(bus1.get(), bus2.get())); | 318 ASSERT_TRUE(CompareBusses(bus1.get(), bus2.get())); |
259 } | 319 } |
260 | 320 |
261 // Verify CopyAudioCB is called if registered. | 321 // Verify CopyAudioCB is called if registered. |
262 TEST_F(WebAudioSourceProviderImplTest, CopyAudioCB) { | 322 TEST_P(WebAudioSourceProviderImplTest, CopyAudioCB) { |
323 ExpectUnhealthySinkToStop(); | |
324 | |
263 testing::InSequence s; | 325 testing::InSequence s; |
264 wasp_impl_->Initialize(params_, &fake_callback_); | 326 wasp_impl_->Initialize(params_, &fake_callback_); |
265 wasp_impl_->SetCopyAudioCallback(base::Bind( | 327 wasp_impl_->SetCopyAudioCallback(base::Bind( |
266 &WebAudioSourceProviderImplTest::OnAudioBus, base::Unretained(this))); | 328 &WebAudioSourceProviderImplTest::OnAudioBus, base::Unretained(this))); |
267 | 329 |
268 const std::unique_ptr<AudioBus> bus1 = AudioBus::Create(params_); | 330 const std::unique_ptr<AudioBus> bus1 = AudioBus::Create(params_); |
269 EXPECT_CALL(*this, DoCopyAudioCB(_, 0, params_.sample_rate())).Times(1); | 331 EXPECT_CALL(*this, DoCopyAudioCB(_, 0, params_.sample_rate())).Times(1); |
270 Render(bus1.get()); | 332 Render(bus1.get()); |
271 | 333 |
272 wasp_impl_->ClearCopyAudioCallback(); | 334 wasp_impl_->ClearCopyAudioCallback(); |
273 EXPECT_CALL(*this, DoCopyAudioCB(_, _, _)).Times(0); | 335 EXPECT_CALL(*this, DoCopyAudioCB(_, _, _)).Times(0); |
274 Render(bus1.get()); | 336 Render(bus1.get()); |
275 | 337 |
276 testing::Mock::VerifyAndClear(mock_sink_.get()); | 338 testing::Mock::VerifyAndClear(mock_sink_.get()); |
277 } | 339 } |
278 | 340 |
341 INSTANTIATE_TEST_CASE_P( | |
342 /* prefix intentionally left blank due to only one parameterization */, | |
343 WebAudioSourceProviderImplTest, | |
344 testing::Values(WASP_SINK_OK, WASP_SINK_ERROR, WASP_SINK_NULL)); | |
345 | |
279 } // namespace media | 346 } // namespace media |
OLD | NEW |