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 #define ARRAYSIZE_UNSAFE(a) \
     16   ((sizeof(a) / sizeof(*(a))) / \
     17    static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
     18 
     19 REGISTER_TEST_CASE(Audio);
     20 
     21 TestAudio::TestAudio(TestingInstance* instance)
     22     : TestCase(instance),
     23       audio_callback_method_(NULL),
     24       audio_callback_event_(instance->pp_instance()),
     25       test_done_(false),
     26       audio_interface_(NULL),
     27       audio_interface_1_0_(NULL),
     28       audio_config_interface_(NULL),
     29       core_interface_(NULL) {
     30 }
     31 
     32 TestAudio::~TestAudio() {
     33 }
     34 
     35 bool TestAudio::Init() {
     36   audio_interface_ = static_cast<const PPB_Audio_1_1*>(
     37       pp::Module::Get()->GetBrowserInterface(PPB_AUDIO_INTERFACE_1_1));
     38   audio_interface_1_0_ = static_cast<const PPB_Audio_1_0*>(
     39       pp::Module::Get()->GetBrowserInterface(PPB_AUDIO_INTERFACE_1_0));
     40   audio_config_interface_ = static_cast<const PPB_AudioConfig*>(
     41       pp::Module::Get()->GetBrowserInterface(PPB_AUDIO_CONFIG_INTERFACE));
     42   core_interface_ = static_cast<const PPB_Core*>(
     43       pp::Module::Get()->GetBrowserInterface(PPB_CORE_INTERFACE));
     44   return audio_interface_ && audio_interface_1_0_ && audio_config_interface_ &&
     45          core_interface_;
     46 }
     47 
     48 void TestAudio::RunTests(const std::string& filter) {
     49   RUN_TEST(Creation, filter);
     50   RUN_TEST(DestroyNoStop, filter);
     51   RUN_TEST(Failures, filter);
     52   RUN_TEST(AudioCallback1, filter);
     53   RUN_TEST(AudioCallback2, filter);
     54   RUN_TEST(AudioCallback3, filter);
     55   RUN_TEST(AudioCallback4, filter);
     56 }
     57 
     58 // Test creating audio resources for all guaranteed sample rates and various
     59 // frame counts.
     60 std::string TestAudio::TestCreation() {
     61   static const PP_AudioSampleRate kSampleRates[] = {
     62     PP_AUDIOSAMPLERATE_44100,
     63     PP_AUDIOSAMPLERATE_48000
     64   };
     65   static const uint32_t kRequestFrameCounts[] = {
     66     PP_AUDIOMINSAMPLEFRAMECOUNT,
     67     PP_AUDIOMAXSAMPLEFRAMECOUNT,
     68     // Include some "okay-looking" frame counts; check their validity below.
     69     PP_AUDIOSAMPLERATE_44100 / 100,  // 10ms @ 44.1kHz
     70     PP_AUDIOSAMPLERATE_48000 / 100,  // 10ms @ 48kHz
     71     2 * PP_AUDIOSAMPLERATE_44100 / 100,  // 20ms @ 44.1kHz
     72     2 * PP_AUDIOSAMPLERATE_48000 / 100,  // 20ms @ 48kHz
     73     1024,
     74     2048,
     75     4096
     76   };
     77   PP_AudioSampleRate sample_rate = audio_config_interface_->RecommendSampleRate(
     78       instance_->pp_instance());
     79   ASSERT_TRUE(sample_rate == PP_AUDIOSAMPLERATE_NONE ||
     80               sample_rate == PP_AUDIOSAMPLERATE_44100 ||
     81               sample_rate == PP_AUDIOSAMPLERATE_48000);
     82   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kSampleRates); i++) {
     83     PP_AudioSampleRate sample_rate = kSampleRates[i];
     84 
     85     for (size_t j = 0; j < ARRAYSIZE_UNSAFE(kRequestFrameCounts); j++) {
     86       // Make a config, create the audio resource, and release the config.
     87       uint32_t request_frame_count = kRequestFrameCounts[j];
     88       uint32_t frame_count = audio_config_interface_->RecommendSampleFrameCount(
     89           instance_->pp_instance(), sample_rate, request_frame_count);
     90       PP_Resource ac = audio_config_interface_->CreateStereo16Bit(
     91           instance_->pp_instance(), sample_rate, frame_count);
     92       ASSERT_TRUE(ac);
     93       PP_Resource audio = audio_interface_->Create(
     94           instance_->pp_instance(), ac, AudioCallbackTrampoline, this);
     95       core_interface_->ReleaseResource(ac);
     96       ac = 0;
     97 
     98       ASSERT_TRUE(audio);
     99       ASSERT_TRUE(audio_interface_->IsAudio(audio));
    100 
    101       // Check that the config returned for |audio| matches what we gave it.
    102       ac = audio_interface_->GetCurrentConfig(audio);
    103       ASSERT_TRUE(ac);
    104       ASSERT_TRUE(audio_config_interface_->IsAudioConfig(ac));
    105       ASSERT_EQ(sample_rate, audio_config_interface_->GetSampleRate(ac));
    106       ASSERT_EQ(frame_count, audio_config_interface_->GetSampleFrameCount(ac));
    107       core_interface_->ReleaseResource(ac);
    108       ac = 0;
    109 
    110       // Start and stop audio playback. The documentation indicates that
    111       // |StartPlayback()| and |StopPlayback()| may fail, but gives no
    112       // indication as to why ... so check that they succeed.
    113       audio_callback_method_ = &TestAudio::AudioCallbackTrivial;
    114       ASSERT_TRUE(audio_interface_->StartPlayback(audio));
    115       ASSERT_TRUE(audio_interface_->StopPlayback(audio));
    116       audio_callback_method_ = NULL;
    117 
    118       core_interface_->ReleaseResource(audio);
    119     }
    120   }
    121 
    122   PASS();
    123 }
    124 
    125 // Test that releasing the resource without calling |StopPlayback()| "works".
    126 std::string TestAudio::TestDestroyNoStop() {
    127   PP_Resource ac = CreateAudioConfig(PP_AUDIOSAMPLERATE_44100, 2048);
    128   ASSERT_TRUE(ac);
    129   audio_callback_method_ = NULL;
    130   PP_Resource audio = audio_interface_->Create(
    131       instance_->pp_instance(), ac, AudioCallbackTrampoline, this);
    132   core_interface_->ReleaseResource(ac);
    133   ac = 0;
    134 
    135   ASSERT_TRUE(audio);
    136   ASSERT_TRUE(audio_interface_->IsAudio(audio));
    137 
    138   // Start playback and release the resource.
    139   audio_callback_method_ = &TestAudio::AudioCallbackTrivial;
    140   ASSERT_TRUE(audio_interface_->StartPlayback(audio));
    141   core_interface_->ReleaseResource(audio);
    142   audio_callback_method_ = NULL;
    143 
    144   PASS();
    145 }
    146 
    147 std::string TestAudio::TestFailures() {
    148   // Test invalid parameters to |Create()|.
    149 
    150   // We want a valid config for some of our tests of |Create()|.
    151   PP_Resource ac = CreateAudioConfig(PP_AUDIOSAMPLERATE_44100, 2048);
    152   ASSERT_TRUE(ac);
    153 
    154   // Failure cases should never lead to the callback being called.
    155   audio_callback_method_ = NULL;
    156 
    157   // Invalid instance -> failure.
    158   PP_Resource audio = audio_interface_->Create(
    159       0, ac, AudioCallbackTrampoline, this);
    160   ASSERT_EQ(0, audio);
    161 
    162   // Invalid config -> failure.
    163   audio = audio_interface_->Create(
    164       instance_->pp_instance(), 0, AudioCallbackTrampoline, this);
    165   ASSERT_EQ(0, audio);
    166 
    167   // Null callback -> failure.
    168   audio = audio_interface_->Create(
    169       instance_->pp_instance(), ac, NULL, NULL);
    170   ASSERT_EQ(0, audio);
    171 
    172   core_interface_->ReleaseResource(ac);
    173   ac = 0;
    174 
    175   // Test the other functions with an invalid audio resource.
    176   ASSERT_FALSE(audio_interface_->IsAudio(0));
    177   ASSERT_EQ(0, audio_interface_->GetCurrentConfig(0));
    178   ASSERT_FALSE(audio_interface_->StartPlayback(0));
    179   ASSERT_FALSE(audio_interface_->StopPlayback(0));
    180 
    181   PASS();
    182 }
    183 
    184 // NOTE: |TestAudioCallbackN| assumes that the audio callback is called at least
    185 // once. If the audio stream does not start up correctly or is interrupted this
    186 // may not be the case and these tests will fail. However, in order to properly
    187 // test the audio callbacks, we must have a configuration where audio can
    188 // successfully play, so we assume this is the case on bots.
    189 
    190 // This test starts playback and verifies that:
    191 //  1) the audio callback is actually called;
    192 //  2) that |StopPlayback()| waits for the audio callback to finish.
    193 std::string TestAudio::TestAudioCallback1() {
    194   PP_Resource ac = CreateAudioConfig(PP_AUDIOSAMPLERATE_44100, 1024);
    195   ASSERT_TRUE(ac);
    196   audio_callback_method_ = NULL;
    197   PP_Resource audio = audio_interface_->Create(
    198       instance_->pp_instance(), ac, AudioCallbackTrampoline, this);
    199   core_interface_->ReleaseResource(ac);
    200   ac = 0;
    201 
    202   audio_callback_event_.Reset();
    203   test_done_ = false;
    204 
    205   audio_callback_method_ = &TestAudio::AudioCallbackTest;
    206   ASSERT_TRUE(audio_interface_->StartPlayback(audio));
    207 
    208   // Wait for the audio callback to be called.
    209   audio_callback_event_.Wait();
    210   ASSERT_TRUE(audio_interface_->StopPlayback(audio));
    211   test_done_ = true;
    212 
    213   // If any more audio callbacks are generated, we should crash (which is good).
    214   audio_callback_method_ = NULL;
    215 
    216   core_interface_->ReleaseResource(audio);
    217 
    218   PASS();
    219 }
    220 
    221 // This is the same as |TestAudioCallback1()|, except that instead of calling
    222 // |StopPlayback()|, it just releases the resource.
    223 std::string TestAudio::TestAudioCallback2() {
    224   PP_Resource ac = CreateAudioConfig(PP_AUDIOSAMPLERATE_44100, 1024);
    225   ASSERT_TRUE(ac);
    226   audio_callback_method_ = NULL;
    227   PP_Resource audio = audio_interface_->Create(
    228       instance_->pp_instance(), ac, AudioCallbackTrampoline, this);
    229   core_interface_->ReleaseResource(ac);
    230   ac = 0;
    231 
    232   audio_callback_event_.Reset();
    233   test_done_ = false;
    234 
    235   audio_callback_method_ = &TestAudio::AudioCallbackTest;
    236   ASSERT_TRUE(audio_interface_->StartPlayback(audio));
    237 
    238   // Wait for the audio callback to be called.
    239   audio_callback_event_.Wait();
    240 
    241   core_interface_->ReleaseResource(audio);
    242 
    243   test_done_ = true;
    244 
    245   // If any more audio callbacks are generated, we should crash (which is good).
    246   audio_callback_method_ = NULL;
    247 
    248   PASS();
    249 }
    250 
    251 // This is the same as |TestAudioCallback1()|, except that it attempts a second
    252 // round of |StartPlayback| and |StopPlayback| to make sure the callback
    253 // function still responds when using the same audio resource.
    254 std::string TestAudio::TestAudioCallback3() {
    255   PP_Resource ac = CreateAudioConfig(PP_AUDIOSAMPLERATE_44100, 1024);
    256   ASSERT_TRUE(ac);
    257   audio_callback_method_ = NULL;
    258   PP_Resource audio = audio_interface_->Create(
    259       instance_->pp_instance(), ac, AudioCallbackTrampoline, this);
    260   core_interface_->ReleaseResource(ac);
    261   ac = 0;
    262 
    263   audio_callback_event_.Reset();
    264   test_done_ = false;
    265 
    266   audio_callback_method_ = &TestAudio::AudioCallbackTest;
    267   ASSERT_TRUE(audio_interface_->StartPlayback(audio));
    268 
    269   // Wait for the audio callback to be called.
    270   audio_callback_event_.Wait();
    271 
    272   ASSERT_TRUE(audio_interface_->StopPlayback(audio));
    273 
    274   // Repeat one more |StartPlayback| & |StopPlayback| cycle, and verify again
    275   // that the callback function was invoked.
    276   audio_callback_event_.Reset();
    277   ASSERT_TRUE(audio_interface_->StartPlayback(audio));
    278 
    279   // Wait for the audio callback to be called.
    280   audio_callback_event_.Wait();
    281   ASSERT_TRUE(audio_interface_->StopPlayback(audio));
    282   test_done_ = true;
    283 
    284   // If any more audio callbacks are generated, we should crash (which is good).
    285   audio_callback_method_ = NULL;
    286 
    287   core_interface_->ReleaseResource(audio);
    288 
    289   PASS();
    290 }
    291 
    292 // This is the same as |TestAudioCallback1()|, except that it uses
    293 // PPB_Audio_1_0.
    294 std::string TestAudio::TestAudioCallback4() {
    295   PP_Resource ac = CreateAudioConfig(PP_AUDIOSAMPLERATE_44100, 1024);
    296   ASSERT_TRUE(ac);
    297   audio_callback_method_ = NULL;
    298   PP_Resource audio = audio_interface_1_0_->Create(
    299       instance_->pp_instance(), ac, AudioCallbackTrampoline1_0, this);
    300   core_interface_->ReleaseResource(ac);
    301   ac = 0;
    302 
    303   audio_callback_event_.Reset();
    304   test_done_ = false;
    305 
    306   audio_callback_method_ = &TestAudio::AudioCallbackTest;
    307   ASSERT_TRUE(audio_interface_1_0_->StartPlayback(audio));
    308 
    309   // Wait for the audio callback to be called.
    310   audio_callback_event_.Wait();
    311   ASSERT_TRUE(audio_interface_1_0_->StopPlayback(audio));
    312   test_done_ = true;
    313 
    314   // If any more audio callbacks are generated, we should crash (which is good).
    315   audio_callback_method_ = NULL;
    316 
    317   core_interface_->ReleaseResource(audio);
    318 
    319   PASS();
    320 }
    321 
    322 // TODO(raymes): Test that actually playback happens correctly, etc.
    323 
    324 static void Crash() {
    325   *static_cast<volatile unsigned*>(NULL) = 0xdeadbeef;
    326 }
    327 
    328 // static
    329 void TestAudio::AudioCallbackTrampoline(void* sample_buffer,
    330                                         uint32_t buffer_size_in_bytes,
    331                                         PP_TimeDelta latency,
    332                                         void* user_data) {
    333   TestAudio* thiz = static_cast<TestAudio*>(user_data);
    334 
    335   // Crash if on the main thread.
    336   if (thiz->core_interface_->IsMainThread())
    337     Crash();
    338 
    339   AudioCallbackMethod method = thiz->audio_callback_method_;
    340   (thiz->*method)(sample_buffer, buffer_size_in_bytes, latency);
    341 }
    342 
    343 // static
    344 void TestAudio::AudioCallbackTrampoline1_0(void* sample_buffer,
    345                                            uint32_t buffer_size_in_bytes,
    346                                            void* user_data) {
    347   AudioCallbackTrampoline(sample_buffer, buffer_size_in_bytes, 0.0, user_data);
    348 }
    349 
    350 void TestAudio::AudioCallbackTrivial(void* sample_buffer,
    351                                      uint32_t buffer_size_in_bytes,
    352                                      PP_TimeDelta latency) {
    353   if (latency < 0)
    354     Crash();
    355 
    356   memset(sample_buffer, 0, buffer_size_in_bytes);
    357 }
    358 
    359 void TestAudio::AudioCallbackTest(void* sample_buffer,
    360                                   uint32_t buffer_size_in_bytes,
    361                                   PP_TimeDelta latency) {
    362   if (test_done_ || latency < 0)
    363     Crash();
    364 
    365   memset(sample_buffer, 0, buffer_size_in_bytes);
    366   audio_callback_event_.Signal();
    367 }
    368 
    369 PP_Resource TestAudio::CreateAudioConfig(
    370     PP_AudioSampleRate sample_rate,
    371     uint32_t requested_sample_frame_count) {
    372   uint32_t frame_count = audio_config_interface_->RecommendSampleFrameCount(
    373       instance_->pp_instance(), sample_rate, requested_sample_frame_count);
    374   return audio_config_interface_->CreateStereo16Bit(
    375       instance_->pp_instance(), sample_rate, frame_count);
    376 }
    377