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.
5 #include "ppapi/tests/test_audio.h"
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"
15 #define ARRAYSIZE_UNSAFE(a) \
16 ((sizeof(a) / sizeof(*(a))) / \
17 static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
19 REGISTER_TEST_CASE(Audio
);
21 const int32_t kMagicValue
= 12345;
23 TestAudio::TestAudio(TestingInstance
* instance
)
25 audio_callback_method_(NULL
),
26 audio_callback_event_(instance
->pp_instance()),
30 TestAudio::~TestAudio() {
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_
;
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
);
52 // Test creating audio resources for all guaranteed sample rates and various
54 std::string
TestAudio::TestCreation() {
55 static const PP_AudioSampleRate kSampleRates
[] = {
56 PP_AUDIOSAMPLERATE_44100
,
57 PP_AUDIOSAMPLERATE_48000
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
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
];
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
);
87 PP_Resource audio
= audio_interface_
->Create(
88 instance_
->pp_instance(), ac
, AudioCallbackTrampoline
, this);
89 core_interface_
->ReleaseResource(ac
);
93 ASSERT_TRUE(audio_interface_
->IsAudio(audio
));
95 // Check that the config returned for |audio| matches what we gave it.
96 ac
= audio_interface_
->GetCurrentConfig(audio
);
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
);
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
;
112 core_interface_
->ReleaseResource(audio
);
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;
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
);
129 audio_callback_method_
= NULL
;
130 PP_Resource audio
= audio_interface_
->Create(
131 instance_
->pp_instance(), ac
, AudioCallbackTrampoline
, this);
132 core_interface_
->ReleaseResource(ac
);
136 ASSERT_TRUE(audio_interface_
->IsAudio(audio
));
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
;
147 std::string
TestAudio::TestFailures() {
148 const PP_AudioSampleRate kSampleRate
= PP_AUDIOSAMPLERATE_44100
;
149 const uint32_t kRequestFrameCount
= 2048;
151 // Test invalid parameters to |Create()|.
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
);
160 // Failure cases should never lead to the callback being called.
161 audio_callback_method_
= NULL
;
163 // Invalid instance -> failure.
164 PP_Resource audio
= audio_interface_
->Create(
165 0, ac
, AudioCallbackTrampoline
, this);
168 // Invalid config -> failure.
169 audio
= audio_interface_
->Create(
170 instance_
->pp_instance(), 0, AudioCallbackTrampoline
, this);
173 // Null callback -> failure.
174 audio
= audio_interface_
->Create(
175 instance_
->pp_instance(), ac
, NULL
, NULL
);
178 core_interface_
->ReleaseResource(ac
);
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));
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
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;
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
);
209 audio_callback_method_
= NULL
;
210 PP_Resource audio
= audio_interface_
->Create(
211 instance_
->pp_instance(), ac
, AudioCallbackTrampoline
, this);
212 core_interface_
->ReleaseResource(ac
);
215 audio_callback_event_
.Reset();
218 audio_callback_method_
= &TestAudio::AudioCallbackTest
;
219 ASSERT_TRUE(audio_interface_
->StartPlayback(audio
));
221 // Wait for the audio callback to be called.
222 audio_callback_event_
.Wait();
223 ASSERT_TRUE(audio_interface_
->StopPlayback(audio
));
226 // If any more audio callbacks are generated, we should crash (which is good).
227 audio_callback_method_
= NULL
;
229 core_interface_
->ReleaseResource(audio
);
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;
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
);
245 audio_callback_method_
= NULL
;
246 PP_Resource audio
= audio_interface_
->Create(
247 instance_
->pp_instance(), ac
, AudioCallbackTrampoline
, this);
248 core_interface_
->ReleaseResource(ac
);
251 audio_callback_event_
.Reset();
253 callback_fired_
= false;
255 audio_callback_method_
= &TestAudio::AudioCallbackTest
;
256 ASSERT_TRUE(audio_interface_
->StartPlayback(audio
));
258 // Wait for the audio callback to be called.
259 audio_callback_event_
.Wait();
261 core_interface_
->ReleaseResource(audio
);
265 // If any more audio callbacks are generated, we should crash (which is good).
266 audio_callback_method_
= NULL
;
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;
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
);
283 audio_callback_method_
= NULL
;
284 PP_Resource audio
= audio_interface_
->Create(
285 instance_
->pp_instance(), ac
, AudioCallbackTrampoline
, this);
286 core_interface_
->ReleaseResource(ac
);
289 audio_callback_event_
.Reset();
291 callback_fired_
= false;
293 audio_callback_method_
= &TestAudio::AudioCallbackTest
;
294 ASSERT_TRUE(audio_interface_
->StartPlayback(audio
));
296 // Wait for the audio callback to be called.
297 audio_callback_event_
.Wait();
299 ASSERT_TRUE(audio_interface_
->StopPlayback(audio
));
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
));
306 // Wait for the audio callback to be called.
307 audio_callback_event_
.Wait();
308 ASSERT_TRUE(audio_interface_
->StopPlayback(audio
));
311 // If any more audio callbacks are generated, we should crash (which is good).
312 audio_callback_method_
= NULL
;
314 core_interface_
->ReleaseResource(audio
);
320 // TODO(raymes): Test that actually playback happens correctly, etc.
322 static void Crash() {
323 *static_cast<volatile unsigned*>(NULL
) = 0xdeadbeef;
327 void TestAudio::AudioCallbackTrampoline(void* sample_buffer
,
328 uint32_t buffer_size_in_bytes
,
330 TestAudio
* thiz
= static_cast<TestAudio
*>(user_data
);
332 // Crash if on the main thread.
333 if (thiz
->core_interface_
->IsMainThread())
336 AudioCallbackMethod method
= thiz
->audio_callback_method_
;
337 (thiz
->*method
)(sample_buffer
, buffer_size_in_bytes
);
340 void TestAudio::AudioCallbackTrivial(void* sample_buffer
,
341 uint32_t buffer_size_in_bytes
) {
342 memset(sample_buffer
, 0, buffer_size_in_bytes
);
345 void TestAudio::AudioCallbackTest(void* sample_buffer
,
346 uint32_t buffer_size_in_bytes
) {
350 memset(sample_buffer
, 0, buffer_size_in_bytes
);
351 audio_callback_event_
.Signal();