Home | History | Annotate | Download | only in tests
      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 }
    544