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