• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GetNaClIrtPpapiHook(struct nacl_irt_ppapihook * hooks)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 
ThreadFunctionsGetter(const struct PP_ThreadFunctions * thread_funcs)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 
CountingThreadCreate(uintptr_t * tid,void (* func)(void * thread_argument),void * thread_argument)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 
CountingThreadJoin(uintptr_t tid)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.
SetNullThreadFunctions()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 
InjectCountingThreadFunctions()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:
ScopedThreadFunctionsResetter()85   ScopedThreadFunctionsResetter() {}
~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 
TestAudio(TestingInstance * instance)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 
~TestAudio()109 TestAudio::~TestAudio() {
110 }
111 
Init()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 
RunTests(const std::string & filter)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.
TestCreation()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".
TestDestroyNoStop()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 
TestFailures()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.
TestAudioCallback1()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.
TestAudioCallback2()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.
TestAudioCallback3()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.
TestAudioCallback4()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().
TestAudioThreadCreatorIsRequired()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.
TestAudioThreadCreatorIsCalled()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 
Crash()491 static void Crash() {
492   *static_cast<volatile unsigned*>(NULL) = 0xdeadbeef;
493 }
494 
495 // static
AudioCallbackTrampoline(void * sample_buffer,uint32_t buffer_size_in_bytes,PP_TimeDelta latency,void * user_data)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
AudioCallbackTrampoline1_0(void * sample_buffer,uint32_t buffer_size_in_bytes,void * user_data)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 
AudioCallbackTrivial(void * sample_buffer,uint32_t buffer_size_in_bytes,PP_TimeDelta latency)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 
AudioCallbackTest(void * sample_buffer,uint32_t buffer_size_in_bytes,PP_TimeDelta latency)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 
CreateAudioConfig(PP_AudioSampleRate sample_rate,uint32_t requested_sample_frame_count)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 }
544