1 // Copyright (c) 2012 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.
5 #include "ppapi/tests/test_audio.h"
9 #include "ppapi/c/ppb_audio_config.h"
10 #include "ppapi/c/ppb_audio.h"
11 #include "ppapi/cpp/module.h"
12 #include "ppapi/tests/testing_instance.h"
13 #include "ppapi/tests/test_utils.h"
15 #define ARRAYSIZE_UNSAFE(a) \
16 ((sizeof(a) / sizeof(*(a))) / \
17 static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
19 REGISTER_TEST_CASE(Audio
);
21 TestAudio::TestAudio(TestingInstance
* instance
)
23 audio_callback_method_(NULL
),
24 audio_callback_event_(instance
->pp_instance()),
26 audio_interface_(NULL
),
27 audio_interface_1_0_(NULL
),
28 audio_config_interface_(NULL
),
29 core_interface_(NULL
) {
32 TestAudio::~TestAudio() {
35 bool TestAudio::Init() {
36 audio_interface_
= static_cast<const PPB_Audio_1_1
*>(
37 pp::Module::Get()->GetBrowserInterface(PPB_AUDIO_INTERFACE_1_1
));
38 audio_interface_1_0_
= static_cast<const PPB_Audio_1_0
*>(
39 pp::Module::Get()->GetBrowserInterface(PPB_AUDIO_INTERFACE_1_0
));
40 audio_config_interface_
= static_cast<const PPB_AudioConfig
*>(
41 pp::Module::Get()->GetBrowserInterface(PPB_AUDIO_CONFIG_INTERFACE
));
42 core_interface_
= static_cast<const PPB_Core
*>(
43 pp::Module::Get()->GetBrowserInterface(PPB_CORE_INTERFACE
));
44 return audio_interface_
&& audio_interface_1_0_
&& audio_config_interface_
&&
48 void TestAudio::RunTests(const std::string
& filter
) {
49 RUN_TEST(Creation
, filter
);
50 RUN_TEST(DestroyNoStop
, filter
);
51 RUN_TEST(Failures
, filter
);
52 RUN_TEST(AudioCallback1
, filter
);
53 RUN_TEST(AudioCallback2
, filter
);
54 RUN_TEST(AudioCallback3
, filter
);
55 RUN_TEST(AudioCallback4
, filter
);
58 // Test creating audio resources for all guaranteed sample rates and various
60 std::string
TestAudio::TestCreation() {
61 static const PP_AudioSampleRate kSampleRates
[] = {
62 PP_AUDIOSAMPLERATE_44100
,
63 PP_AUDIOSAMPLERATE_48000
65 static const uint32_t kRequestFrameCounts
[] = {
66 PP_AUDIOMINSAMPLEFRAMECOUNT
,
67 PP_AUDIOMAXSAMPLEFRAMECOUNT
,
68 // Include some "okay-looking" frame counts; check their validity below.
69 PP_AUDIOSAMPLERATE_44100
/ 100, // 10ms @ 44.1kHz
70 PP_AUDIOSAMPLERATE_48000
/ 100, // 10ms @ 48kHz
71 2 * PP_AUDIOSAMPLERATE_44100
/ 100, // 20ms @ 44.1kHz
72 2 * PP_AUDIOSAMPLERATE_48000
/ 100, // 20ms @ 48kHz
77 PP_AudioSampleRate sample_rate
= audio_config_interface_
->RecommendSampleRate(
78 instance_
->pp_instance());
79 ASSERT_TRUE(sample_rate
== PP_AUDIOSAMPLERATE_NONE
||
80 sample_rate
== PP_AUDIOSAMPLERATE_44100
||
81 sample_rate
== PP_AUDIOSAMPLERATE_48000
);
82 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(kSampleRates
); i
++) {
83 PP_AudioSampleRate sample_rate
= kSampleRates
[i
];
85 for (size_t j
= 0; j
< ARRAYSIZE_UNSAFE(kRequestFrameCounts
); j
++) {
86 // Make a config, create the audio resource, and release the config.
87 uint32_t request_frame_count
= kRequestFrameCounts
[j
];
88 uint32_t frame_count
= audio_config_interface_
->RecommendSampleFrameCount(
89 instance_
->pp_instance(), sample_rate
, request_frame_count
);
90 PP_Resource ac
= audio_config_interface_
->CreateStereo16Bit(
91 instance_
->pp_instance(), sample_rate
, frame_count
);
93 PP_Resource audio
= audio_interface_
->Create(
94 instance_
->pp_instance(), ac
, AudioCallbackTrampoline
, this);
95 core_interface_
->ReleaseResource(ac
);
99 ASSERT_TRUE(audio_interface_
->IsAudio(audio
));
101 // Check that the config returned for |audio| matches what we gave it.
102 ac
= audio_interface_
->GetCurrentConfig(audio
);
104 ASSERT_TRUE(audio_config_interface_
->IsAudioConfig(ac
));
105 ASSERT_EQ(sample_rate
, audio_config_interface_
->GetSampleRate(ac
));
106 ASSERT_EQ(frame_count
, audio_config_interface_
->GetSampleFrameCount(ac
));
107 core_interface_
->ReleaseResource(ac
);
110 // Start and stop audio playback. The documentation indicates that
111 // |StartPlayback()| and |StopPlayback()| may fail, but gives no
112 // indication as to why ... so check that they succeed.
113 audio_callback_method_
= &TestAudio::AudioCallbackTrivial
;
114 ASSERT_TRUE(audio_interface_
->StartPlayback(audio
));
115 ASSERT_TRUE(audio_interface_
->StopPlayback(audio
));
116 audio_callback_method_
= NULL
;
118 core_interface_
->ReleaseResource(audio
);
125 // Test that releasing the resource without calling |StopPlayback()| "works".
126 std::string
TestAudio::TestDestroyNoStop() {
127 PP_Resource ac
= CreateAudioConfig(PP_AUDIOSAMPLERATE_44100
, 2048);
129 audio_callback_method_
= NULL
;
130 PP_Resource audio
= audio_interface_
->Create(
131 instance_
->pp_instance(), ac
, AudioCallbackTrampoline
, this);
132 core_interface_
->ReleaseResource(ac
);
136 ASSERT_TRUE(audio_interface_
->IsAudio(audio
));
138 // Start playback and release the resource.
139 audio_callback_method_
= &TestAudio::AudioCallbackTrivial
;
140 ASSERT_TRUE(audio_interface_
->StartPlayback(audio
));
141 core_interface_
->ReleaseResource(audio
);
142 audio_callback_method_
= NULL
;
147 std::string
TestAudio::TestFailures() {
148 // Test invalid parameters to |Create()|.
150 // We want a valid config for some of our tests of |Create()|.
151 PP_Resource ac
= CreateAudioConfig(PP_AUDIOSAMPLERATE_44100
, 2048);
154 // Failure cases should never lead to the callback being called.
155 audio_callback_method_
= NULL
;
157 // Invalid instance -> failure.
158 PP_Resource audio
= audio_interface_
->Create(
159 0, ac
, AudioCallbackTrampoline
, this);
162 // Invalid config -> failure.
163 audio
= audio_interface_
->Create(
164 instance_
->pp_instance(), 0, AudioCallbackTrampoline
, this);
167 // Null callback -> failure.
168 audio
= audio_interface_
->Create(
169 instance_
->pp_instance(), ac
, NULL
, NULL
);
172 core_interface_
->ReleaseResource(ac
);
175 // Test the other functions with an invalid audio resource.
176 ASSERT_FALSE(audio_interface_
->IsAudio(0));
177 ASSERT_EQ(0, audio_interface_
->GetCurrentConfig(0));
178 ASSERT_FALSE(audio_interface_
->StartPlayback(0));
179 ASSERT_FALSE(audio_interface_
->StopPlayback(0));
184 // NOTE: |TestAudioCallbackN| assumes that the audio callback is called at least
185 // once. If the audio stream does not start up correctly or is interrupted this
186 // may not be the case and these tests will fail. However, in order to properly
187 // test the audio callbacks, we must have a configuration where audio can
188 // successfully play, so we assume this is the case on bots.
190 // This test starts playback and verifies that:
191 // 1) the audio callback is actually called;
192 // 2) that |StopPlayback()| waits for the audio callback to finish.
193 std::string
TestAudio::TestAudioCallback1() {
194 PP_Resource ac
= CreateAudioConfig(PP_AUDIOSAMPLERATE_44100
, 1024);
196 audio_callback_method_
= NULL
;
197 PP_Resource audio
= audio_interface_
->Create(
198 instance_
->pp_instance(), ac
, AudioCallbackTrampoline
, this);
199 core_interface_
->ReleaseResource(ac
);
202 audio_callback_event_
.Reset();
205 audio_callback_method_
= &TestAudio::AudioCallbackTest
;
206 ASSERT_TRUE(audio_interface_
->StartPlayback(audio
));
208 // Wait for the audio callback to be called.
209 audio_callback_event_
.Wait();
210 ASSERT_TRUE(audio_interface_
->StopPlayback(audio
));
213 // If any more audio callbacks are generated, we should crash (which is good).
214 audio_callback_method_
= NULL
;
216 core_interface_
->ReleaseResource(audio
);
221 // This is the same as |TestAudioCallback1()|, except that instead of calling
222 // |StopPlayback()|, it just releases the resource.
223 std::string
TestAudio::TestAudioCallback2() {
224 PP_Resource ac
= CreateAudioConfig(PP_AUDIOSAMPLERATE_44100
, 1024);
226 audio_callback_method_
= NULL
;
227 PP_Resource audio
= audio_interface_
->Create(
228 instance_
->pp_instance(), ac
, AudioCallbackTrampoline
, this);
229 core_interface_
->ReleaseResource(ac
);
232 audio_callback_event_
.Reset();
235 audio_callback_method_
= &TestAudio::AudioCallbackTest
;
236 ASSERT_TRUE(audio_interface_
->StartPlayback(audio
));
238 // Wait for the audio callback to be called.
239 audio_callback_event_
.Wait();
241 core_interface_
->ReleaseResource(audio
);
245 // If any more audio callbacks are generated, we should crash (which is good).
246 audio_callback_method_
= NULL
;
251 // This is the same as |TestAudioCallback1()|, except that it attempts a second
252 // round of |StartPlayback| and |StopPlayback| to make sure the callback
253 // function still responds when using the same audio resource.
254 std::string
TestAudio::TestAudioCallback3() {
255 PP_Resource ac
= CreateAudioConfig(PP_AUDIOSAMPLERATE_44100
, 1024);
257 audio_callback_method_
= NULL
;
258 PP_Resource audio
= audio_interface_
->Create(
259 instance_
->pp_instance(), ac
, AudioCallbackTrampoline
, this);
260 core_interface_
->ReleaseResource(ac
);
263 audio_callback_event_
.Reset();
266 audio_callback_method_
= &TestAudio::AudioCallbackTest
;
267 ASSERT_TRUE(audio_interface_
->StartPlayback(audio
));
269 // Wait for the audio callback to be called.
270 audio_callback_event_
.Wait();
272 ASSERT_TRUE(audio_interface_
->StopPlayback(audio
));
274 // Repeat one more |StartPlayback| & |StopPlayback| cycle, and verify again
275 // that the callback function was invoked.
276 audio_callback_event_
.Reset();
277 ASSERT_TRUE(audio_interface_
->StartPlayback(audio
));
279 // Wait for the audio callback to be called.
280 audio_callback_event_
.Wait();
281 ASSERT_TRUE(audio_interface_
->StopPlayback(audio
));
284 // If any more audio callbacks are generated, we should crash (which is good).
285 audio_callback_method_
= NULL
;
287 core_interface_
->ReleaseResource(audio
);
292 // This is the same as |TestAudioCallback1()|, except that it uses
294 std::string
TestAudio::TestAudioCallback4() {
295 PP_Resource ac
= CreateAudioConfig(PP_AUDIOSAMPLERATE_44100
, 1024);
297 audio_callback_method_
= NULL
;
298 PP_Resource audio
= audio_interface_1_0_
->Create(
299 instance_
->pp_instance(), ac
, AudioCallbackTrampoline1_0
, this);
300 core_interface_
->ReleaseResource(ac
);
303 audio_callback_event_
.Reset();
306 audio_callback_method_
= &TestAudio::AudioCallbackTest
;
307 ASSERT_TRUE(audio_interface_1_0_
->StartPlayback(audio
));
309 // Wait for the audio callback to be called.
310 audio_callback_event_
.Wait();
311 ASSERT_TRUE(audio_interface_1_0_
->StopPlayback(audio
));
314 // If any more audio callbacks are generated, we should crash (which is good).
315 audio_callback_method_
= NULL
;
317 core_interface_
->ReleaseResource(audio
);
322 // TODO(raymes): Test that actually playback happens correctly, etc.
324 static void Crash() {
325 *static_cast<volatile unsigned*>(NULL
) = 0xdeadbeef;
329 void TestAudio::AudioCallbackTrampoline(void* sample_buffer
,
330 uint32_t buffer_size_in_bytes
,
331 PP_TimeDelta latency
,
333 TestAudio
* thiz
= static_cast<TestAudio
*>(user_data
);
335 // Crash if on the main thread.
336 if (thiz
->core_interface_
->IsMainThread())
339 AudioCallbackMethod method
= thiz
->audio_callback_method_
;
340 (thiz
->*method
)(sample_buffer
, buffer_size_in_bytes
, latency
);
344 void TestAudio::AudioCallbackTrampoline1_0(void* sample_buffer
,
345 uint32_t buffer_size_in_bytes
,
347 AudioCallbackTrampoline(sample_buffer
, buffer_size_in_bytes
, 0.0, user_data
);
350 void TestAudio::AudioCallbackTrivial(void* sample_buffer
,
351 uint32_t buffer_size_in_bytes
,
352 PP_TimeDelta latency
) {
356 memset(sample_buffer
, 0, buffer_size_in_bytes
);
359 void TestAudio::AudioCallbackTest(void* sample_buffer
,
360 uint32_t buffer_size_in_bytes
,
361 PP_TimeDelta latency
) {
362 if (test_done_
|| latency
< 0)
365 memset(sample_buffer
, 0, buffer_size_in_bytes
);
366 audio_callback_event_
.Signal();
369 PP_Resource
TestAudio::CreateAudioConfig(
370 PP_AudioSampleRate sample_rate
,
371 uint32_t requested_sample_frame_count
) {
372 uint32_t frame_count
= audio_config_interface_
->RecommendSampleFrameCount(
373 instance_
->pp_instance(), sample_rate
, requested_sample_frame_count
);
374 return audio_config_interface_
->CreateStereo16Bit(
375 instance_
->pp_instance(), sample_rate
, frame_count
);