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