Drive: Add BatchableRequest subclass.
[chromium-blink-merge.git] / ppapi / tests / test_audio.cc
blob1c1c9b594afd7a62ca5cff52d01971cd4890d7f3
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"
7 #include <string.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"
18 #endif
20 #define ARRAYSIZE_UNSAFE(a) \
21 ((sizeof(a) / sizeof(*(a))) / \
22 static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
24 #if defined(__native_client__)
25 namespace {
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 = {
75 CountingThreadCreate,
76 CountingThreadJoin,
78 GetNaClIrtPpapiHook(&hooks);
79 hooks.ppapi_register_thread_creator(&thread_functions);
82 // Resets the PP_ThreadFunctions on exit from the scope.
83 class ScopedThreadFunctionsResetter {
84 public:
85 ScopedThreadFunctionsResetter() {}
86 ~ScopedThreadFunctionsResetter() {
87 nacl_irt_ppapihook hooks;
88 GetNaClIrtPpapiHook(&hooks);
89 __nacl_register_thread_creator(&hooks);
93 } // namespace
94 #endif // __native_client__
96 REGISTER_TEST_CASE(Audio);
98 TestAudio::TestAudio(TestingInstance* instance)
99 : TestCase(instance),
100 audio_callback_method_(NULL),
101 audio_callback_event_(instance->pp_instance()),
102 test_done_(false),
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_ &&
122 core_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);
137 #endif
140 // Test creating audio resources for all guaranteed sample rates and various
141 // frame counts.
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
155 1024,
156 2048,
157 4096
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);
174 ASSERT_TRUE(ac);
175 PP_Resource audio = audio_interface_->Create(
176 instance_->pp_instance(), ac, AudioCallbackTrampoline, this);
177 core_interface_->ReleaseResource(ac);
178 ac = 0;
180 ASSERT_TRUE(audio);
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);
185 ASSERT_TRUE(ac);
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);
190 ac = 0;
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);
204 PASS();
207 // Test that releasing the resource without calling |StopPlayback()| "works".
208 std::string TestAudio::TestDestroyNoStop() {
209 PP_Resource ac = CreateAudioConfig(PP_AUDIOSAMPLERATE_44100, 2048);
210 ASSERT_TRUE(ac);
211 audio_callback_method_ = NULL;
212 PP_Resource audio = audio_interface_->Create(
213 instance_->pp_instance(), ac, AudioCallbackTrampoline, this);
214 core_interface_->ReleaseResource(ac);
215 ac = 0;
217 ASSERT_TRUE(audio);
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;
226 PASS();
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);
234 ASSERT_TRUE(ac);
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);
242 ASSERT_EQ(0, audio);
244 // Invalid config -> failure.
245 audio = audio_interface_->Create(
246 instance_->pp_instance(), 0, AudioCallbackTrampoline, this);
247 ASSERT_EQ(0, audio);
249 // Null callback -> failure.
250 audio = audio_interface_->Create(
251 instance_->pp_instance(), ac, NULL, NULL);
252 ASSERT_EQ(0, audio);
254 core_interface_->ReleaseResource(ac);
255 ac = 0;
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));
263 PASS();
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);
277 ASSERT_TRUE(ac);
278 audio_callback_method_ = NULL;
279 PP_Resource audio = audio_interface_->Create(
280 instance_->pp_instance(), ac, AudioCallbackTrampoline, this);
281 core_interface_->ReleaseResource(ac);
282 ac = 0;
284 audio_callback_event_.Reset();
285 test_done_ = false;
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));
293 test_done_ = true;
295 // If any more audio callbacks are generated, we should crash (which is good).
296 audio_callback_method_ = NULL;
298 core_interface_->ReleaseResource(audio);
300 PASS();
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);
307 ASSERT_TRUE(ac);
308 audio_callback_method_ = NULL;
309 PP_Resource audio = audio_interface_->Create(
310 instance_->pp_instance(), ac, AudioCallbackTrampoline, this);
311 core_interface_->ReleaseResource(ac);
312 ac = 0;
314 audio_callback_event_.Reset();
315 test_done_ = false;
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);
325 test_done_ = true;
327 // If any more audio callbacks are generated, we should crash (which is good).
328 audio_callback_method_ = NULL;
330 PASS();
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);
338 ASSERT_TRUE(ac);
339 audio_callback_method_ = NULL;
340 PP_Resource audio = audio_interface_->Create(
341 instance_->pp_instance(), ac, AudioCallbackTrampoline, this);
342 core_interface_->ReleaseResource(ac);
343 ac = 0;
345 audio_callback_event_.Reset();
346 test_done_ = false;
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));
364 test_done_ = true;
366 // If any more audio callbacks are generated, we should crash (which is good).
367 audio_callback_method_ = NULL;
369 core_interface_->ReleaseResource(audio);
371 PASS();
374 // This is the same as |TestAudioCallback1()|, except that it uses
375 // PPB_Audio_1_0.
376 std::string TestAudio::TestAudioCallback4() {
377 PP_Resource ac = CreateAudioConfig(PP_AUDIOSAMPLERATE_44100, 1024);
378 ASSERT_TRUE(ac);
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);
383 ac = 0;
385 audio_callback_event_.Reset();
386 test_done_ = false;
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));
394 test_done_ = true;
396 // If any more audio callbacks are generated, we should crash (which is good).
397 audio_callback_method_ = NULL;
399 core_interface_->ReleaseResource(audio);
401 PASS();
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);
419 ASSERT_TRUE(ac);
420 audio_callback_method_ = NULL;
421 PP_Resource audio = audio_interface_->Create(
422 instance_->pp_instance(), ac, AudioCallbackTrampoline, this);
423 core_interface_->ReleaseResource(ac);
424 ac = 0;
426 // StartPlayback() fails, because no thread creating function
427 // is available.
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);
436 PASS();
439 // Tests whether the thread functions passed from the user code are actually
440 // called.
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);
453 ASSERT_TRUE(ac);
454 audio_callback_method_ = NULL;
455 PP_Resource audio = audio_interface_->Create(
456 instance_->pp_instance(), ac, AudioCallbackTrampoline, this);
457 core_interface_->ReleaseResource(ac);
458 ac = 0;
460 audio_callback_event_.Reset();
461 test_done_ = false;
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));
474 test_done_ = true;
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);
485 PASS();
487 #endif
489 // TODO(raymes): Test that actually playback happens correctly, etc.
491 static void Crash() {
492 *static_cast<volatile unsigned*>(NULL) = 0xdeadbeef;
495 // static
496 void TestAudio::AudioCallbackTrampoline(void* sample_buffer,
497 uint32_t buffer_size_in_bytes,
498 PP_TimeDelta latency,
499 void* user_data) {
500 TestAudio* thiz = static_cast<TestAudio*>(user_data);
502 // Crash if on the main thread.
503 if (thiz->core_interface_->IsMainThread())
504 Crash();
506 AudioCallbackMethod method = thiz->audio_callback_method_;
507 (thiz->*method)(sample_buffer, buffer_size_in_bytes, latency);
510 // static
511 void TestAudio::AudioCallbackTrampoline1_0(void* sample_buffer,
512 uint32_t buffer_size_in_bytes,
513 void* user_data) {
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) {
520 if (latency < 0)
521 Crash();
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)
530 Crash();
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);