test_audio.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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 19REGISTER_TEST_CASE(Audio); 20 21const int32_t kMagicValue = 12345; 22 23TestAudio::TestAudio(TestingInstance* instance) 24 : TestCase(instance), 25 audio_callback_method_(NULL), 26 test_callback_(), 27 test_done_(false) { 28} 29 30TestAudio::~TestAudio() { 31} 32 33bool 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 43void 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. 54std::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". 120std::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 147std::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. 200std::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 // |AudioCallbackTest()| calls |test_callback_|, sleeps a bit, then sets 216 // |test_done_|. 217 TestCompletionCallback test_callback(instance_->pp_instance()); 218 test_callback_ = static_cast<pp::CompletionCallback>( 219 test_callback).pp_completion_callback(); 220 test_done_ = false; 221 callback_fired_ = false; 222 223 audio_callback_method_ = &TestAudio::AudioCallbackTest; 224 ASSERT_TRUE(audio_interface_->StartPlayback(audio)); 225 226 // Wait for the audio callback to be called. 227 test_callback.WaitForResult(); 228 ASSERT_EQ(kMagicValue, test_callback.result()); 229 230 ASSERT_TRUE(audio_interface_->StopPlayback(audio)); 231 232 // |StopPlayback()| should wait for the audio callback to finish. 233 ASSERT_TRUE(callback_fired_); 234 test_done_ = true; 235 236 // If any more audio callbacks are generated, we should crash (which is good). 237 audio_callback_method_ = NULL; 238 test_callback_ = PP_CompletionCallback(); 239 240 core_interface_->ReleaseResource(audio); 241 242 PASS(); 243} 244 245// This is the same as |TestAudioCallback1()|, except that instead of calling 246// |StopPlayback()|, it just releases the resource. 247std::string TestAudio::TestAudioCallback2() { 248 const PP_AudioSampleRate kSampleRate = PP_AUDIOSAMPLERATE_44100; 249 const uint32_t kRequestFrameCount = 1024; 250 251 uint32_t frame_count = audio_config_interface_->RecommendSampleFrameCount( 252 instance_->pp_instance(), kSampleRate, kRequestFrameCount); 253 PP_Resource ac = audio_config_interface_->CreateStereo16Bit( 254 instance_->pp_instance(), kSampleRate, frame_count); 255 ASSERT_TRUE(ac); 256 audio_callback_method_ = NULL; 257 PP_Resource audio = audio_interface_->Create( 258 instance_->pp_instance(), ac, AudioCallbackTrampoline, this); 259 core_interface_->ReleaseResource(ac); 260 ac = 0; 261 262 // |AudioCallbackTest()| calls |test_callback_|, sleeps a bit, then sets 263 // |test_done_|. 264 TestCompletionCallback test_callback(instance_->pp_instance()); 265 test_callback_ = static_cast<pp::CompletionCallback>( 266 test_callback).pp_completion_callback(); 267 test_done_ = false; 268 callback_fired_ = false; 269 270 audio_callback_method_ = &TestAudio::AudioCallbackTest; 271 ASSERT_TRUE(audio_interface_->StartPlayback(audio)); 272 273 // Wait for the audio callback to be called. 274 test_callback.WaitForResult(); 275 ASSERT_EQ(kMagicValue, test_callback.result()); 276 277 core_interface_->ReleaseResource(audio); 278 279 // The final release should wait for the audio callback to finish. 280 ASSERT_TRUE(callback_fired_); 281 test_done_ = true; 282 283 // If any more audio callbacks are generated, we should crash (which is good). 284 audio_callback_method_ = NULL; 285 test_callback_ = PP_CompletionCallback(); 286 287 PASS(); 288} 289 290// This is the same as |TestAudioCallback1()|, except that it attempts a second 291// round of |StartPlayback| and |StopPlayback| to make sure the callback 292// function still responds when using the same audio resource. 293std::string TestAudio::TestAudioCallback3() { 294 const PP_AudioSampleRate kSampleRate = PP_AUDIOSAMPLERATE_44100; 295 const uint32_t kRequestFrameCount = 1024; 296 297 uint32_t frame_count = audio_config_interface_->RecommendSampleFrameCount( 298 instance_->pp_instance(), kSampleRate, kRequestFrameCount); 299 PP_Resource ac = audio_config_interface_->CreateStereo16Bit( 300 instance_->pp_instance(), kSampleRate, frame_count); 301 ASSERT_TRUE(ac); 302 audio_callback_method_ = NULL; 303 PP_Resource audio = audio_interface_->Create( 304 instance_->pp_instance(), ac, AudioCallbackTrampoline, this); 305 core_interface_->ReleaseResource(ac); 306 ac = 0; 307 308 // |AudioCallbackTest()| calls |test_callback_|, sleeps a bit, then sets 309 // |test_done_|. 310 TestCompletionCallback test_callback_1(instance_->pp_instance()); 311 test_callback_ = static_cast<pp::CompletionCallback>( 312 test_callback_1).pp_completion_callback(); 313 test_done_ = false; 314 callback_fired_ = false; 315 316 audio_callback_method_ = &TestAudio::AudioCallbackTest; 317 ASSERT_TRUE(audio_interface_->StartPlayback(audio)); 318 319 // Wait for the audio callback to be called. 320 test_callback_1.WaitForResult(); 321 ASSERT_EQ(kMagicValue, test_callback_1.result()); 322 323 ASSERT_TRUE(audio_interface_->StopPlayback(audio)); 324 325 // |StopPlayback()| should wait for the audio callback to finish. 326 ASSERT_TRUE(callback_fired_); 327 328 TestCompletionCallback test_callback_2(instance_->pp_instance()); 329 test_callback_ = static_cast<pp::CompletionCallback>( 330 test_callback_2).pp_completion_callback(); 331 332 // Repeat one more |StartPlayback| & |StopPlayback| cycle, and verify again 333 // that the callback function was invoked. 334 callback_fired_ = false; 335 ASSERT_TRUE(audio_interface_->StartPlayback(audio)); 336 337 // Wait for the audio callback to be called. 338 test_callback_2.WaitForResult(); 339 ASSERT_EQ(kMagicValue, test_callback_2.result()); 340 341 ASSERT_TRUE(audio_interface_->StopPlayback(audio)); 342 343 // |StopPlayback()| should wait for the audio callback to finish. 344 ASSERT_TRUE(callback_fired_); 345 346 test_done_ = true; 347 348 // If any more audio callbacks are generated, we should crash (which is good). 349 audio_callback_method_ = NULL; 350 test_callback_ = PP_CompletionCallback(); 351 352 core_interface_->ReleaseResource(audio); 353 354 PASS(); 355} 356 357 358// TODO(raymes): Test that actually playback happens correctly, etc. 359 360static void Crash() { 361 *static_cast<volatile unsigned*>(NULL) = 0xdeadbeef; 362} 363 364// static 365void TestAudio::AudioCallbackTrampoline(void* sample_buffer, 366 uint32_t buffer_size_in_bytes, 367 void* user_data) { 368 TestAudio* thiz = static_cast<TestAudio*>(user_data); 369 370 // Crash if not on the main thread. 371 if (thiz->core_interface_->IsMainThread()) 372 Crash(); 373 374 AudioCallbackMethod method = thiz->audio_callback_method_; 375 (thiz->*method)(sample_buffer, buffer_size_in_bytes); 376} 377 378void TestAudio::AudioCallbackTrivial(void* sample_buffer, 379 uint32_t buffer_size_in_bytes) { 380 memset(sample_buffer, 0, buffer_size_in_bytes); 381} 382 383void TestAudio::AudioCallbackTest(void* sample_buffer, 384 uint32_t buffer_size_in_bytes) { 385 if (test_done_) 386 Crash(); 387 388 if (!callback_fired_) { 389 memset(sample_buffer, 0, buffer_size_in_bytes); 390 core_interface_->CallOnMainThread(0, test_callback_, kMagicValue); 391 callback_fired_ = true; 392 } 393} 394