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