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 #if defined(__native_client__)
16 #include "native_client/src/untrusted/irt/irt.h"
17 #include "ppapi/native_client/src/untrusted/irt_stub/thread_creator.h"
20 #define ARRAYSIZE_UNSAFE(a) \
21 ((sizeof(a) / sizeof(*(a))) / \
22 static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
24 #if defined(__native_client__)
27 void GetNaClIrtPpapiHook(struct nacl_irt_ppapihook
* hooks
) {
28 nacl_interface_query(NACL_IRT_PPAPIHOOK_v0_1
, hooks
, sizeof(*hooks
));
31 struct PP_ThreadFunctions g_thread_funcs
= {};
33 void ThreadFunctionsGetter(const struct PP_ThreadFunctions
* thread_funcs
) {
34 g_thread_funcs
= *thread_funcs
;
37 // In order to check if the thread_create is called, CountingThreadCreate()
38 // increments this variable. Callers can check if the function is actually
39 // called by looking at this value.
40 int g_num_thread_create_called
= 0;
41 int g_num_thread_join_called
= 0;
43 int CountingThreadCreate(uintptr_t* tid
,
44 void (*func
)(void* thread_argument
),
45 void* thread_argument
) {
46 ++g_num_thread_create_called
;
47 return g_thread_funcs
.thread_create(tid
, func
, thread_argument
);
50 int CountingThreadJoin(uintptr_t tid
) {
51 ++g_num_thread_join_called
;
52 return g_thread_funcs
.thread_join(tid
);
55 // Sets NULL for PP_ThreadFunctions to emulate the situation that
56 // ppapi_register_thread_creator() is not yet called.
57 void SetNullThreadFunctions() {
58 nacl_irt_ppapihook hooks
;
59 GetNaClIrtPpapiHook(&hooks
);
60 PP_ThreadFunctions thread_functions
= {};
61 hooks
.ppapi_register_thread_creator(&thread_functions
);
64 void InjectCountingThreadFunctions() {
65 // First of all, we extract the system default thread functions.
66 // Internally, __nacl_register_thread_creator calls
67 // hooks.ppapi_register_thread_creator with default PP_ThreadFunctions
68 // instance. ThreadFunctionGetter stores it to g_thread_funcs.
69 nacl_irt_ppapihook hooks
= { NULL
, ThreadFunctionsGetter
};
70 __nacl_register_thread_creator(&hooks
);
72 // Here g_thread_funcs stores the thread functions.
73 // Inject the CountingThreadCreate.
74 PP_ThreadFunctions thread_functions
= {
78 GetNaClIrtPpapiHook(&hooks
);
79 hooks
.ppapi_register_thread_creator(&thread_functions
);
82 // Resets the PP_ThreadFunctions on exit from the scope.
83 class ScopedThreadFunctionsResetter
{
85 ScopedThreadFunctionsResetter() {}
86 ~ScopedThreadFunctionsResetter() {
87 nacl_irt_ppapihook hooks
;
88 GetNaClIrtPpapiHook(&hooks
);
89 __nacl_register_thread_creator(&hooks
);
94 #endif // __native_client__
96 REGISTER_TEST_CASE(Audio
);
98 TestAudio::TestAudio(TestingInstance
* instance
)
100 audio_callback_method_(NULL
),
101 audio_callback_event_(instance
->pp_instance()),
103 audio_interface_(NULL
),
104 audio_interface_1_0_(NULL
),
105 audio_config_interface_(NULL
),
106 core_interface_(NULL
) {
109 TestAudio::~TestAudio() {
112 bool TestAudio::Init() {
113 audio_interface_
= static_cast<const PPB_Audio_1_1
*>(
114 pp::Module::Get()->GetBrowserInterface(PPB_AUDIO_INTERFACE_1_1
));
115 audio_interface_1_0_
= static_cast<const PPB_Audio_1_0
*>(
116 pp::Module::Get()->GetBrowserInterface(PPB_AUDIO_INTERFACE_1_0
));
117 audio_config_interface_
= static_cast<const PPB_AudioConfig
*>(
118 pp::Module::Get()->GetBrowserInterface(PPB_AUDIO_CONFIG_INTERFACE
));
119 core_interface_
= static_cast<const PPB_Core
*>(
120 pp::Module::Get()->GetBrowserInterface(PPB_CORE_INTERFACE
));
121 return audio_interface_
&& audio_interface_1_0_
&& audio_config_interface_
&&
125 void TestAudio::RunTests(const std::string
& filter
) {
126 RUN_TEST(Creation
, filter
);
127 RUN_TEST(DestroyNoStop
, filter
);
128 RUN_TEST(Failures
, filter
);
129 RUN_TEST(AudioCallback1
, filter
);
130 RUN_TEST(AudioCallback2
, filter
);
131 RUN_TEST(AudioCallback3
, filter
);
132 RUN_TEST(AudioCallback4
, filter
);
134 #if defined(__native_client__)
135 RUN_TEST(AudioThreadCreatorIsRequired
, filter
);
136 RUN_TEST(AudioThreadCreatorIsCalled
, filter
);
140 // Test creating audio resources for all guaranteed sample rates and various
142 std::string
TestAudio::TestCreation() {
143 static const PP_AudioSampleRate kSampleRates
[] = {
144 PP_AUDIOSAMPLERATE_44100
,
145 PP_AUDIOSAMPLERATE_48000
147 static const uint32_t kRequestFrameCounts
[] = {
148 PP_AUDIOMINSAMPLEFRAMECOUNT
,
149 PP_AUDIOMAXSAMPLEFRAMECOUNT
,
150 // Include some "okay-looking" frame counts; check their validity below.
151 PP_AUDIOSAMPLERATE_44100
/ 100, // 10ms @ 44.1kHz
152 PP_AUDIOSAMPLERATE_48000
/ 100, // 10ms @ 48kHz
153 2 * PP_AUDIOSAMPLERATE_44100
/ 100, // 20ms @ 44.1kHz
154 2 * PP_AUDIOSAMPLERATE_48000
/ 100, // 20ms @ 48kHz
159 PP_AudioSampleRate sample_rate
= audio_config_interface_
->RecommendSampleRate(
160 instance_
->pp_instance());
161 ASSERT_TRUE(sample_rate
== PP_AUDIOSAMPLERATE_NONE
||
162 sample_rate
== PP_AUDIOSAMPLERATE_44100
||
163 sample_rate
== PP_AUDIOSAMPLERATE_48000
);
164 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(kSampleRates
); i
++) {
165 PP_AudioSampleRate sample_rate
= kSampleRates
[i
];
167 for (size_t j
= 0; j
< ARRAYSIZE_UNSAFE(kRequestFrameCounts
); j
++) {
168 // Make a config, create the audio resource, and release the config.
169 uint32_t request_frame_count
= kRequestFrameCounts
[j
];
170 uint32_t frame_count
= audio_config_interface_
->RecommendSampleFrameCount(
171 instance_
->pp_instance(), sample_rate
, request_frame_count
);
172 PP_Resource ac
= audio_config_interface_
->CreateStereo16Bit(
173 instance_
->pp_instance(), sample_rate
, frame_count
);
175 PP_Resource audio
= audio_interface_
->Create(
176 instance_
->pp_instance(), ac
, AudioCallbackTrampoline
, this);
177 core_interface_
->ReleaseResource(ac
);
181 ASSERT_TRUE(audio_interface_
->IsAudio(audio
));
183 // Check that the config returned for |audio| matches what we gave it.
184 ac
= audio_interface_
->GetCurrentConfig(audio
);
186 ASSERT_TRUE(audio_config_interface_
->IsAudioConfig(ac
));
187 ASSERT_EQ(sample_rate
, audio_config_interface_
->GetSampleRate(ac
));
188 ASSERT_EQ(frame_count
, audio_config_interface_
->GetSampleFrameCount(ac
));
189 core_interface_
->ReleaseResource(ac
);
192 // Start and stop audio playback. The documentation indicates that
193 // |StartPlayback()| and |StopPlayback()| may fail, but gives no
194 // indication as to why ... so check that they succeed.
195 audio_callback_method_
= &TestAudio::AudioCallbackTrivial
;
196 ASSERT_TRUE(audio_interface_
->StartPlayback(audio
));
197 ASSERT_TRUE(audio_interface_
->StopPlayback(audio
));
198 audio_callback_method_
= NULL
;
200 core_interface_
->ReleaseResource(audio
);
207 // Test that releasing the resource without calling |StopPlayback()| "works".
208 std::string
TestAudio::TestDestroyNoStop() {
209 PP_Resource ac
= CreateAudioConfig(PP_AUDIOSAMPLERATE_44100
, 2048);
211 audio_callback_method_
= NULL
;
212 PP_Resource audio
= audio_interface_
->Create(
213 instance_
->pp_instance(), ac
, AudioCallbackTrampoline
, this);
214 core_interface_
->ReleaseResource(ac
);
218 ASSERT_TRUE(audio_interface_
->IsAudio(audio
));
220 // Start playback and release the resource.
221 audio_callback_method_
= &TestAudio::AudioCallbackTrivial
;
222 ASSERT_TRUE(audio_interface_
->StartPlayback(audio
));
223 core_interface_
->ReleaseResource(audio
);
224 audio_callback_method_
= NULL
;
229 std::string
TestAudio::TestFailures() {
230 // Test invalid parameters to |Create()|.
232 // We want a valid config for some of our tests of |Create()|.
233 PP_Resource ac
= CreateAudioConfig(PP_AUDIOSAMPLERATE_44100
, 2048);
236 // Failure cases should never lead to the callback being called.
237 audio_callback_method_
= NULL
;
239 // Invalid instance -> failure.
240 PP_Resource audio
= audio_interface_
->Create(
241 0, ac
, AudioCallbackTrampoline
, this);
244 // Invalid config -> failure.
245 audio
= audio_interface_
->Create(
246 instance_
->pp_instance(), 0, AudioCallbackTrampoline
, this);
249 // Null callback -> failure.
250 audio
= audio_interface_
->Create(
251 instance_
->pp_instance(), ac
, NULL
, NULL
);
254 core_interface_
->ReleaseResource(ac
);
257 // Test the other functions with an invalid audio resource.
258 ASSERT_FALSE(audio_interface_
->IsAudio(0));
259 ASSERT_EQ(0, audio_interface_
->GetCurrentConfig(0));
260 ASSERT_FALSE(audio_interface_
->StartPlayback(0));
261 ASSERT_FALSE(audio_interface_
->StopPlayback(0));
266 // NOTE: |TestAudioCallbackN| assumes that the audio callback is called at least
267 // once. If the audio stream does not start up correctly or is interrupted this
268 // may not be the case and these tests will fail. However, in order to properly
269 // test the audio callbacks, we must have a configuration where audio can
270 // successfully play, so we assume this is the case on bots.
272 // This test starts playback and verifies that:
273 // 1) the audio callback is actually called;
274 // 2) that |StopPlayback()| waits for the audio callback to finish.
275 std::string
TestAudio::TestAudioCallback1() {
276 PP_Resource ac
= CreateAudioConfig(PP_AUDIOSAMPLERATE_44100
, 1024);
278 audio_callback_method_
= NULL
;
279 PP_Resource audio
= audio_interface_
->Create(
280 instance_
->pp_instance(), ac
, AudioCallbackTrampoline
, this);
281 core_interface_
->ReleaseResource(ac
);
284 audio_callback_event_
.Reset();
287 audio_callback_method_
= &TestAudio::AudioCallbackTest
;
288 ASSERT_TRUE(audio_interface_
->StartPlayback(audio
));
290 // Wait for the audio callback to be called.
291 audio_callback_event_
.Wait();
292 ASSERT_TRUE(audio_interface_
->StopPlayback(audio
));
295 // If any more audio callbacks are generated, we should crash (which is good).
296 audio_callback_method_
= NULL
;
298 core_interface_
->ReleaseResource(audio
);
303 // This is the same as |TestAudioCallback1()|, except that instead of calling
304 // |StopPlayback()|, it just releases the resource.
305 std::string
TestAudio::TestAudioCallback2() {
306 PP_Resource ac
= CreateAudioConfig(PP_AUDIOSAMPLERATE_44100
, 1024);
308 audio_callback_method_
= NULL
;
309 PP_Resource audio
= audio_interface_
->Create(
310 instance_
->pp_instance(), ac
, AudioCallbackTrampoline
, this);
311 core_interface_
->ReleaseResource(ac
);
314 audio_callback_event_
.Reset();
317 audio_callback_method_
= &TestAudio::AudioCallbackTest
;
318 ASSERT_TRUE(audio_interface_
->StartPlayback(audio
));
320 // Wait for the audio callback to be called.
321 audio_callback_event_
.Wait();
323 core_interface_
->ReleaseResource(audio
);
327 // If any more audio callbacks are generated, we should crash (which is good).
328 audio_callback_method_
= NULL
;
333 // This is the same as |TestAudioCallback1()|, except that it attempts a second
334 // round of |StartPlayback| and |StopPlayback| to make sure the callback
335 // function still responds when using the same audio resource.
336 std::string
TestAudio::TestAudioCallback3() {
337 PP_Resource ac
= CreateAudioConfig(PP_AUDIOSAMPLERATE_44100
, 1024);
339 audio_callback_method_
= NULL
;
340 PP_Resource audio
= audio_interface_
->Create(
341 instance_
->pp_instance(), ac
, AudioCallbackTrampoline
, this);
342 core_interface_
->ReleaseResource(ac
);
345 audio_callback_event_
.Reset();
348 audio_callback_method_
= &TestAudio::AudioCallbackTest
;
349 ASSERT_TRUE(audio_interface_
->StartPlayback(audio
));
351 // Wait for the audio callback to be called.
352 audio_callback_event_
.Wait();
354 ASSERT_TRUE(audio_interface_
->StopPlayback(audio
));
356 // Repeat one more |StartPlayback| & |StopPlayback| cycle, and verify again
357 // that the callback function was invoked.
358 audio_callback_event_
.Reset();
359 ASSERT_TRUE(audio_interface_
->StartPlayback(audio
));
361 // Wait for the audio callback to be called.
362 audio_callback_event_
.Wait();
363 ASSERT_TRUE(audio_interface_
->StopPlayback(audio
));
366 // If any more audio callbacks are generated, we should crash (which is good).
367 audio_callback_method_
= NULL
;
369 core_interface_
->ReleaseResource(audio
);
374 // This is the same as |TestAudioCallback1()|, except that it uses
376 std::string
TestAudio::TestAudioCallback4() {
377 PP_Resource ac
= CreateAudioConfig(PP_AUDIOSAMPLERATE_44100
, 1024);
379 audio_callback_method_
= NULL
;
380 PP_Resource audio
= audio_interface_1_0_
->Create(
381 instance_
->pp_instance(), ac
, AudioCallbackTrampoline1_0
, this);
382 core_interface_
->ReleaseResource(ac
);
385 audio_callback_event_
.Reset();
388 audio_callback_method_
= &TestAudio::AudioCallbackTest
;
389 ASSERT_TRUE(audio_interface_1_0_
->StartPlayback(audio
));
391 // Wait for the audio callback to be called.
392 audio_callback_event_
.Wait();
393 ASSERT_TRUE(audio_interface_1_0_
->StopPlayback(audio
));
396 // If any more audio callbacks are generated, we should crash (which is good).
397 audio_callback_method_
= NULL
;
399 core_interface_
->ReleaseResource(audio
);
404 #if defined(__native_client__)
405 // Tests the behavior of the thread_create functions.
406 // For PPB_Audio_Shared to work properly, the user code must call
407 // ppapi_register_thread_creator(). This test checks the error handling for the
408 // case when user code doesn't call ppapi_register_thread_creator().
409 std::string
TestAudio::TestAudioThreadCreatorIsRequired() {
410 // We'll inject some thread functions in this test case.
411 // Reset them at the end of this case.
412 ScopedThreadFunctionsResetter thread_resetter
;
414 // Set the thread functions to NULLs to emulate the situation where
415 // ppapi_register_thread_creator() is not called by user code.
416 SetNullThreadFunctions();
418 PP_Resource ac
= CreateAudioConfig(PP_AUDIOSAMPLERATE_44100
, 1024);
420 audio_callback_method_
= NULL
;
421 PP_Resource audio
= audio_interface_
->Create(
422 instance_
->pp_instance(), ac
, AudioCallbackTrampoline
, this);
423 core_interface_
->ReleaseResource(ac
);
426 // StartPlayback() fails, because no thread creating function
428 ASSERT_FALSE(audio_interface_
->StartPlayback(audio
));
430 // If any more audio callbacks are generated,
431 // we should crash (which is good).
432 audio_callback_method_
= NULL
;
434 core_interface_
->ReleaseResource(audio
);
439 // Tests whether the thread functions passed from the user code are actually
441 std::string
TestAudio::TestAudioThreadCreatorIsCalled() {
442 // We'll inject some thread functions in this test case.
443 // Reset them at the end of this case.
444 ScopedThreadFunctionsResetter thread_resetter
;
446 // Inject the thread counting function. In the injected function,
447 // when called, g_num_thread_create_called is incremented.
448 g_num_thread_create_called
= 0;
449 g_num_thread_join_called
= 0;
450 InjectCountingThreadFunctions();
452 PP_Resource ac
= CreateAudioConfig(PP_AUDIOSAMPLERATE_44100
, 1024);
454 audio_callback_method_
= NULL
;
455 PP_Resource audio
= audio_interface_
->Create(
456 instance_
->pp_instance(), ac
, AudioCallbackTrampoline
, this);
457 core_interface_
->ReleaseResource(ac
);
460 audio_callback_event_
.Reset();
463 audio_callback_method_
= &TestAudio::AudioCallbackTest
;
464 ASSERT_TRUE(audio_interface_
->StartPlayback(audio
));
466 // Wait for the audio callback to be called.
467 audio_callback_event_
.Wait();
468 // Here, the injected thread_create is called, but thread_join is not yet.
469 ASSERT_EQ(1, g_num_thread_create_called
);
470 ASSERT_EQ(0, g_num_thread_join_called
);
472 ASSERT_TRUE(audio_interface_
->StopPlayback(audio
));
476 // Here, the injected thread_join is called.
477 ASSERT_EQ(1, g_num_thread_join_called
);
479 // If any more audio callbacks are generated,
480 // we should crash (which is good).
481 audio_callback_method_
= NULL
;
483 core_interface_
->ReleaseResource(audio
);
489 // TODO(raymes): Test that actually playback happens correctly, etc.
491 static void Crash() {
492 *static_cast<volatile unsigned*>(NULL
) = 0xdeadbeef;
496 void TestAudio::AudioCallbackTrampoline(void* sample_buffer
,
497 uint32_t buffer_size_in_bytes
,
498 PP_TimeDelta latency
,
500 TestAudio
* thiz
= static_cast<TestAudio
*>(user_data
);
502 // Crash if on the main thread.
503 if (thiz
->core_interface_
->IsMainThread())
506 AudioCallbackMethod method
= thiz
->audio_callback_method_
;
507 (thiz
->*method
)(sample_buffer
, buffer_size_in_bytes
, latency
);
511 void TestAudio::AudioCallbackTrampoline1_0(void* sample_buffer
,
512 uint32_t buffer_size_in_bytes
,
514 AudioCallbackTrampoline(sample_buffer
, buffer_size_in_bytes
, 0.0, user_data
);
517 void TestAudio::AudioCallbackTrivial(void* sample_buffer
,
518 uint32_t buffer_size_in_bytes
,
519 PP_TimeDelta latency
) {
523 memset(sample_buffer
, 0, buffer_size_in_bytes
);
526 void TestAudio::AudioCallbackTest(void* sample_buffer
,
527 uint32_t buffer_size_in_bytes
,
528 PP_TimeDelta latency
) {
529 if (test_done_
|| latency
< 0)
532 memset(sample_buffer
, 0, buffer_size_in_bytes
);
533 audio_callback_event_
.Signal();
536 PP_Resource
TestAudio::CreateAudioConfig(
537 PP_AudioSampleRate sample_rate
,
538 uint32_t requested_sample_frame_count
) {
539 uint32_t frame_count
= audio_config_interface_
->RecommendSampleFrameCount(
540 instance_
->pp_instance(), sample_rate
, requested_sample_frame_count
);
541 return audio_config_interface_
->CreateStereo16Bit(
542 instance_
->pp_instance(), sample_rate
, frame_count
);