• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/message_loop/message_loop.h"
6 #include "base/run_loop.h"
7 #include "content/renderer/media/webaudiosourceprovider_impl.h"
8 #include "media/audio/audio_parameters.h"
9 #include "media/base/fake_audio_render_callback.h"
10 #include "media/base/mock_audio_renderer_sink.h"
11 #include "testing/gmock/include/gmock/gmock.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "third_party/WebKit/public/platform/WebAudioSourceProviderClient.h"
14 
15 namespace content {
16 
17 namespace {
18 const float kTestVolume = 0.25;
19 }  // namespace
20 
21 class WebAudioSourceProviderImplTest
22     : public testing::Test,
23       public blink::WebAudioSourceProviderClient {
24  public:
WebAudioSourceProviderImplTest()25   WebAudioSourceProviderImplTest()
26       : params_(media::AudioParameters::AUDIO_PCM_LINEAR,
27                 media::CHANNEL_LAYOUT_STEREO, 48000, 16, 64),
28         fake_callback_(0.1),
29         mock_sink_(new media::MockAudioRendererSink()),
30         wasp_impl_(new WebAudioSourceProviderImpl(mock_sink_)) {
31   }
32 
~WebAudioSourceProviderImplTest()33   virtual ~WebAudioSourceProviderImplTest() {}
34 
CallAllSinkMethodsAndVerify(bool verify)35   void CallAllSinkMethodsAndVerify(bool verify) {
36     testing::InSequence s;
37 
38     EXPECT_CALL(*mock_sink_.get(), Start()).Times(verify);
39     wasp_impl_->Start();
40 
41     EXPECT_CALL(*mock_sink_.get(), Play()).Times(verify);
42     wasp_impl_->Play();
43 
44     EXPECT_CALL(*mock_sink_.get(), Pause()).Times(verify);
45     wasp_impl_->Pause();
46 
47     EXPECT_CALL(*mock_sink_.get(), SetVolume(kTestVolume)).Times(verify);
48     wasp_impl_->SetVolume(kTestVolume);
49 
50     EXPECT_CALL(*mock_sink_.get(), Stop()).Times(verify);
51     wasp_impl_->Stop();
52 
53     testing::Mock::VerifyAndClear(mock_sink_.get());
54   }
55 
SetClient(blink::WebAudioSourceProviderClient * client)56   void SetClient(blink::WebAudioSourceProviderClient* client) {
57     testing::InSequence s;
58 
59     if (client) {
60       EXPECT_CALL(*mock_sink_.get(), Stop());
61       EXPECT_CALL(*this, setFormat(params_.channels(), params_.sample_rate()));
62     }
63     wasp_impl_->setClient(client);
64     base::RunLoop().RunUntilIdle();
65 
66     testing::Mock::VerifyAndClear(mock_sink_.get());
67     testing::Mock::VerifyAndClear(this);
68   }
69 
CompareBusses(const media::AudioBus * bus1,const media::AudioBus * bus2)70   bool CompareBusses(const media::AudioBus* bus1, const media::AudioBus* bus2) {
71     EXPECT_EQ(bus1->channels(), bus2->channels());
72     EXPECT_EQ(bus1->frames(), bus2->frames());
73     for (int ch = 0; ch < bus1->channels(); ++ch) {
74       if (memcmp(bus1->channel(ch), bus2->channel(ch),
75                  sizeof(*bus1->channel(ch)) * bus1->frames()) != 0) {
76         return false;
77       }
78     }
79     return true;
80   }
81 
82   // blink::WebAudioSourceProviderClient implementation.
83   MOCK_METHOD2(setFormat, void(size_t numberOfChannels, float sampleRate));
84 
85  protected:
86   media::AudioParameters params_;
87   media::FakeAudioRenderCallback fake_callback_;
88   scoped_refptr<media::MockAudioRendererSink> mock_sink_;
89   scoped_refptr<WebAudioSourceProviderImpl> wasp_impl_;
90   base::MessageLoop message_loop_;
91 
92   DISALLOW_COPY_AND_ASSIGN(WebAudioSourceProviderImplTest);
93 };
94 
TEST_F(WebAudioSourceProviderImplTest,SetClientBeforeInitialize)95 TEST_F(WebAudioSourceProviderImplTest, SetClientBeforeInitialize) {
96   // setClient() with a NULL client should do nothing if no client is set.
97   wasp_impl_->setClient(NULL);
98 
99   EXPECT_CALL(*mock_sink_.get(), Stop());
100   wasp_impl_->setClient(this);
101   base::RunLoop().RunUntilIdle();
102 
103   // When Initialize() is called after setClient(), the params should propagate
104   // to the client via setFormat() during the call.
105   EXPECT_CALL(*this, setFormat(params_.channels(), params_.sample_rate()));
106   wasp_impl_->Initialize(params_, &fake_callback_);
107   base::RunLoop().RunUntilIdle();
108 
109   // setClient() with the same client should do nothing.
110   wasp_impl_->setClient(this);
111   base::RunLoop().RunUntilIdle();
112 }
113 
114 // Verify AudioRendererSink functionality w/ and w/o a client.
TEST_F(WebAudioSourceProviderImplTest,SinkMethods)115 TEST_F(WebAudioSourceProviderImplTest, SinkMethods) {
116   wasp_impl_->Initialize(params_, &fake_callback_);
117   ASSERT_EQ(mock_sink_->callback(), &fake_callback_);
118 
119   // Without a client all WASP calls should fall through to the underlying sink.
120   CallAllSinkMethodsAndVerify(true);
121 
122   // With a client no calls should reach the Stop()'d sink.  Also, setClient()
123   // should propagate the params provided during Initialize() at call time.
124   SetClient(this);
125   CallAllSinkMethodsAndVerify(false);
126 
127   // Removing the client should cause WASP to revert to the underlying sink.
128   EXPECT_CALL(*mock_sink_.get(), SetVolume(kTestVolume));
129   SetClient(NULL);
130   CallAllSinkMethodsAndVerify(true);
131 }
132 
133 // Verify underlying sink state is restored after client removal.
TEST_F(WebAudioSourceProviderImplTest,SinkStateRestored)134 TEST_F(WebAudioSourceProviderImplTest, SinkStateRestored) {
135   wasp_impl_->Initialize(params_, &fake_callback_);
136 
137   // Verify state set before the client is set propagates back afterward.
138   EXPECT_CALL(*mock_sink_.get(), Start());
139   wasp_impl_->Start();
140   SetClient(this);
141 
142   EXPECT_CALL(*mock_sink_.get(), SetVolume(1.0));
143   EXPECT_CALL(*mock_sink_.get(), Start());
144   SetClient(NULL);
145 
146   // Verify state set while the client was attached propagates back afterward.
147   SetClient(this);
148   wasp_impl_->Play();
149   wasp_impl_->SetVolume(kTestVolume);
150 
151   EXPECT_CALL(*mock_sink_.get(), SetVolume(kTestVolume));
152   EXPECT_CALL(*mock_sink_.get(), Start());
153   EXPECT_CALL(*mock_sink_.get(), Play());
154   SetClient(NULL);
155 }
156 
157 // Test the AudioRendererSink state machine and its effects on provideInput().
TEST_F(WebAudioSourceProviderImplTest,ProvideInput)158 TEST_F(WebAudioSourceProviderImplTest, ProvideInput) {
159   scoped_ptr<media::AudioBus> bus1 = media::AudioBus::Create(params_);
160   scoped_ptr<media::AudioBus> bus2 = media::AudioBus::Create(params_);
161 
162   // Point the WebVector into memory owned by |bus1|.
163   blink::WebVector<float*> audio_data(static_cast<size_t>(bus1->channels()));
164   for (size_t i = 0; i < audio_data.size(); ++i)
165     audio_data[i] = bus1->channel(i);
166 
167   // Verify provideInput() works before Initialize() and returns silence.
168   bus1->channel(0)[0] = 1;
169   bus2->Zero();
170   wasp_impl_->provideInput(audio_data, params_.frames_per_buffer());
171   ASSERT_TRUE(CompareBusses(bus1.get(), bus2.get()));
172 
173   wasp_impl_->Initialize(params_, &fake_callback_);
174   SetClient(this);
175 
176   // Verify provideInput() is muted prior to Start() and no calls to the render
177   // callback have occurred.
178   bus1->channel(0)[0] = 1;
179   bus2->Zero();
180   wasp_impl_->provideInput(audio_data, params_.frames_per_buffer());
181   ASSERT_TRUE(CompareBusses(bus1.get(), bus2.get()));
182   ASSERT_EQ(fake_callback_.last_audio_delay_milliseconds(), -1);
183 
184   wasp_impl_->Start();
185 
186   // Ditto for Play().
187   bus1->channel(0)[0] = 1;
188   wasp_impl_->provideInput(audio_data, params_.frames_per_buffer());
189   ASSERT_TRUE(CompareBusses(bus1.get(), bus2.get()));
190   ASSERT_EQ(fake_callback_.last_audio_delay_milliseconds(), -1);
191 
192   wasp_impl_->Play();
193 
194   // Now we should get real audio data.
195   wasp_impl_->provideInput(audio_data, params_.frames_per_buffer());
196   ASSERT_FALSE(CompareBusses(bus1.get(), bus2.get()));
197 
198   // Ensure volume adjustment is working.
199   fake_callback_.reset();
200   fake_callback_.Render(bus2.get(), 0);
201   bus2->Scale(kTestVolume);
202 
203   fake_callback_.reset();
204   wasp_impl_->SetVolume(kTestVolume);
205   wasp_impl_->provideInput(audio_data, params_.frames_per_buffer());
206   ASSERT_TRUE(CompareBusses(bus1.get(), bus2.get()));
207 
208   // Pause should return to silence.
209   wasp_impl_->Pause();
210   bus1->channel(0)[0] = 1;
211   bus2->Zero();
212   wasp_impl_->provideInput(audio_data, params_.frames_per_buffer());
213   ASSERT_TRUE(CompareBusses(bus1.get(), bus2.get()));
214 
215   // Ensure if a renderer properly fill silence for partial Render() calls by
216   // configuring the fake callback to return half the data.  After these calls
217   // bus1 is full of junk data, and bus2 is partially filled.
218   wasp_impl_->SetVolume(1);
219   fake_callback_.Render(bus1.get(), 0);
220   fake_callback_.reset();
221   fake_callback_.Render(bus2.get(), 0);
222   bus2->ZeroFramesPartial(bus2->frames() / 2,
223                           bus2->frames() - bus2->frames() / 2);
224   fake_callback_.reset();
225   fake_callback_.set_half_fill(true);
226   wasp_impl_->Play();
227 
228   // Play should return real audio data again, but the last half should be zero.
229   wasp_impl_->provideInput(audio_data, params_.frames_per_buffer());
230   ASSERT_TRUE(CompareBusses(bus1.get(), bus2.get()));
231 
232   // Stop() should return silence.
233   wasp_impl_->Stop();
234   bus1->channel(0)[0] = 1;
235   bus2->Zero();
236   wasp_impl_->provideInput(audio_data, params_.frames_per_buffer());
237   ASSERT_TRUE(CompareBusses(bus1.get(), bus2.get()));
238 }
239 
240 }  // namespace content
241