Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / ppapi / tests / test_audio.cc
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.
4
5 #include "ppapi/tests/test_audio.h"
6
7 #include <string.h>
8
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"
14
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
19
20 #define ARRAYSIZE_UNSAFE(a) \
21   ((sizeof(a) / sizeof(*(a))) / \
22    static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
23
24 #if defined(__native_client__)
25 namespace {
26
27 void GetNaClIrtPpapiHook(struct nacl_irt_ppapihook* hooks) {
28   nacl_interface_query(NACL_IRT_PPAPIHOOK_v0_1, hooks, sizeof(*hooks));
29 }
30
31 struct PP_ThreadFunctions g_thread_funcs = {};
32
33 void ThreadFunctionsGetter(const struct PP_ThreadFunctions* thread_funcs) {
34   g_thread_funcs = *thread_funcs;
35 }
36
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;
42
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);
48 }
49
50 int CountingThreadJoin(uintptr_t tid) {
51   ++g_num_thread_join_called;
52   return g_thread_funcs.thread_join(tid);
53 }
54
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);
62 }
63
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);
71
72   // Here g_thread_funcs stores the thread functions.
73   // Inject the CountingThreadCreate.
74   PP_ThreadFunctions thread_functions = {
75     CountingThreadCreate,
76     CountingThreadJoin,
77   };
78   GetNaClIrtPpapiHook(&hooks);
79   hooks.ppapi_register_thread_creator(&thread_functions);
80 }
81
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);
90   }
91 };
92
93 }  // namespace
94 #endif  // __native_client__
95
96 REGISTER_TEST_CASE(Audio);
97
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) {
107 }
108
109 TestAudio::~TestAudio() {
110 }
111
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_;
123 }
124
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);
133
134 #if defined(__native_client__)
135   RUN_TEST(AudioThreadCreatorIsRequired, filter);
136   RUN_TEST(AudioThreadCreatorIsCalled, filter);
137 #endif
138 }
139
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
146   };
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
158   };
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];
166
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;
179
180       ASSERT_TRUE(audio);
181       ASSERT_TRUE(audio_interface_->IsAudio(audio));
182
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;
191
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;
199
200       core_interface_->ReleaseResource(audio);
201     }
202   }
203
204   PASS();
205 }
206
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;
216
217   ASSERT_TRUE(audio);
218   ASSERT_TRUE(audio_interface_->IsAudio(audio));
219
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;
225
226   PASS();
227 }
228
229 std::string TestAudio::TestFailures() {
230   // Test invalid parameters to |Create()|.
231
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);
235
236   // Failure cases should never lead to the callback being called.
237   audio_callback_method_ = NULL;
238
239   // Invalid instance -> failure.
240   PP_Resource audio = audio_interface_->Create(
241       0, ac, AudioCallbackTrampoline, this);
242   ASSERT_EQ(0, audio);
243
244   // Invalid config -> failure.
245   audio = audio_interface_->Create(
246       instance_->pp_instance(), 0, AudioCallbackTrampoline, this);
247   ASSERT_EQ(0, audio);
248
249   // Null callback -> failure.
250   audio = audio_interface_->Create(
251       instance_->pp_instance(), ac, NULL, NULL);
252   ASSERT_EQ(0, audio);
253
254   core_interface_->ReleaseResource(ac);
255   ac = 0;
256
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));
262
263   PASS();
264 }
265
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.
271
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;
283
284   audio_callback_event_.Reset();
285   test_done_ = false;
286
287   audio_callback_method_ = &TestAudio::AudioCallbackTest;
288   ASSERT_TRUE(audio_interface_->StartPlayback(audio));
289
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;
294
295   // If any more audio callbacks are generated, we should crash (which is good).
296   audio_callback_method_ = NULL;
297
298   core_interface_->ReleaseResource(audio);
299
300   PASS();
301 }
302
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;
313
314   audio_callback_event_.Reset();
315   test_done_ = false;
316
317   audio_callback_method_ = &TestAudio::AudioCallbackTest;
318   ASSERT_TRUE(audio_interface_->StartPlayback(audio));
319
320   // Wait for the audio callback to be called.
321   audio_callback_event_.Wait();
322
323   core_interface_->ReleaseResource(audio);
324
325   test_done_ = true;
326
327   // If any more audio callbacks are generated, we should crash (which is good).
328   audio_callback_method_ = NULL;
329
330   PASS();
331 }
332
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;
344
345   audio_callback_event_.Reset();
346   test_done_ = false;
347
348   audio_callback_method_ = &TestAudio::AudioCallbackTest;
349   ASSERT_TRUE(audio_interface_->StartPlayback(audio));
350
351   // Wait for the audio callback to be called.
352   audio_callback_event_.Wait();
353
354   ASSERT_TRUE(audio_interface_->StopPlayback(audio));
355
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));
360
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;
365
366   // If any more audio callbacks are generated, we should crash (which is good).
367   audio_callback_method_ = NULL;
368
369   core_interface_->ReleaseResource(audio);
370
371   PASS();
372 }
373
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;
384
385   audio_callback_event_.Reset();
386   test_done_ = false;
387
388   audio_callback_method_ = &TestAudio::AudioCallbackTest;
389   ASSERT_TRUE(audio_interface_1_0_->StartPlayback(audio));
390
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;
395
396   // If any more audio callbacks are generated, we should crash (which is good).
397   audio_callback_method_ = NULL;
398
399   core_interface_->ReleaseResource(audio);
400
401   PASS();
402 }
403
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;
413
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();
417
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;
425
426   // StartPlayback() fails, because no thread creating function
427   // is available.
428   ASSERT_FALSE(audio_interface_->StartPlayback(audio));
429
430   // If any more audio callbacks are generated,
431   // we should crash (which is good).
432   audio_callback_method_ = NULL;
433
434   core_interface_->ReleaseResource(audio);
435
436   PASS();
437 }
438
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;
445
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();
451
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;
459
460   audio_callback_event_.Reset();
461   test_done_ = false;
462
463   audio_callback_method_ = &TestAudio::AudioCallbackTest;
464   ASSERT_TRUE(audio_interface_->StartPlayback(audio));
465
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);
471
472   ASSERT_TRUE(audio_interface_->StopPlayback(audio));
473
474   test_done_ = true;
475
476   // Here, the injected thread_join is called.
477   ASSERT_EQ(1, g_num_thread_join_called);
478
479   // If any more audio callbacks are generated,
480   // we should crash (which is good).
481   audio_callback_method_ = NULL;
482
483   core_interface_->ReleaseResource(audio);
484
485   PASS();
486 }
487 #endif
488
489 // TODO(raymes): Test that actually playback happens correctly, etc.
490
491 static void Crash() {
492   *static_cast<volatile unsigned*>(NULL) = 0xdeadbeef;
493 }
494
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);
501
502   // Crash if on the main thread.
503   if (thiz->core_interface_->IsMainThread())
504     Crash();
505
506   AudioCallbackMethod method = thiz->audio_callback_method_;
507   (thiz->*method)(sample_buffer, buffer_size_in_bytes, latency);
508 }
509
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);
515 }
516
517 void TestAudio::AudioCallbackTrivial(void* sample_buffer,
518                                      uint32_t buffer_size_in_bytes,
519                                      PP_TimeDelta latency) {
520   if (latency < 0)
521     Crash();
522
523   memset(sample_buffer, 0, buffer_size_in_bytes);
524 }
525
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();
531
532   memset(sample_buffer, 0, buffer_size_in_bytes);
533   audio_callback_event_.Signal();
534 }
535
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);
543 }