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