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