Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(171)

Side by Side Diff: ppapi/native_client/tests/ppapi_example_audio/audio.cc

Issue 7740013: Cloning a bunch of stuff from the native_client repository at r6528 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 9 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Native Client 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
6 #include <nacl/nacl_log.h>
7
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12
13 #include <cmath>
14 #include <limits>
15 #include <string>
16 #include <nacl/nacl_inttypes.h>
17
18 #include "native_client/src/shared/ppapi_proxy/utility.h"
19 #include "ppapi/c/pp_bool.h"
20 #include "ppapi/c/pp_errors.h"
21 #include "ppapi/c/ppb_audio.h"
22 #include "ppapi/c/ppb_audio_config.h"
23 #include "ppapi/cpp/audio.h"
24 #include "ppapi/cpp/audio_config.h"
25 #include "ppapi/cpp/completion_callback.h"
26 #include "ppapi/cpp/instance.h"
27 #include "ppapi/cpp/module.h"
28 #include "ppapi/cpp/var.h"
29
30
31 // Most of this example is borrowed from ppapi/examples/audio/audio.cc
32
33 // Separate left and right frequency to make sure we didn't swap L & R.
34 // Sounds pretty horrible, though...
35 const double kDefaultFrequencyLeft = 400.0;
36 const double kDefaultFrequencyRight = 1000.0;
37 const uint32_t kDefaultDuration = 10000;
38
39 // This sample frequency is guaranteed to work.
40 const PP_AudioSampleRate kSampleFrequency = PP_AUDIOSAMPLERATE_44100;
41 // Buffer size in units of sample frames.
42 // 4096 is a conservative size that should avoid underruns on most systems.
43 const uint32_t kSampleFrameCount = 4096;
44
45 const double kPi = 3.141592653589;
46 const double kTwoPi = 2.0 * kPi;
47
48 void LogFailure(const char* msg) {
49 NaClLog(LOG_ERROR, "\n*** FAILURE **** example: %s", msg);
50 }
51
52 class MyInstance : public pp::Instance {
53 private:
54 void ParseArgs(uint32_t argc, const char* argn[], const char* argv[]) {
55 NaClLog(1, "example: parsing %d args\n", static_cast<int>(argc));
56 for (uint32_t i = 0; i < argc; ++i) {
57 NaClLog(1, "example: arg %d: [%s] [%s]\n",
58 static_cast<int>(i), argn[i], argv[i]);
59 const std::string tag = argn[i];
60 if (tag == "frequency_l") frequency_l_ = strtod(argv[i], 0);
61 if (tag == "frequency_r") frequency_r_ = strtod(argv[i], 0);
62 if (tag == "amplitude_l") amplitude_l_ = strtod(argv[i], 0);
63 if (tag == "amplitude_r") amplitude_r_ = strtod(argv[i], 0);
64 if (tag == "duration_msec") duration_msec_ = strtod(argv[i], 0);
65 if (tag == "basic_tests") basic_tests_ = (0 != atoi(argv[i]));
66 if (tag == "stress_tests") stress_tests_ = (0 != atoi(argv[i]));
67 if (tag == "headless") headless_ = (0 != atoi(argv[i]));
68 // ignore other tags
69 }
70 }
71
72 public:
73 explicit MyInstance(PP_Instance instance)
74 : pp::Instance(instance),
75 config_(NULL),
76 audio_(NULL),
77 audio_wave_l_(0.0),
78 audio_wave_r_(0.0),
79 frequency_l_(kDefaultFrequencyLeft),
80 frequency_r_(kDefaultFrequencyRight),
81 amplitude_l_(1.0),
82 amplitude_r_(1.0),
83 headless_(false),
84 basic_tests_(false),
85 stress_tests_(false),
86 duration_msec_(kDefaultDuration),
87 obtained_sample_frame_count_(0),
88 callback_count_(0) {}
89
90 virtual void HandleMessage(const pp::Var& message) {
91 NaClLog(1, "example: received HandleMessage\n");
92 if (message.is_string()) {
93 if (message.AsString() == "StartPlayback") {
94 StartOutput();
95 }
96 }
97 }
98
99 void StartOutput() {
100 bool audio_start_playback = audio_->StartPlayback();
101 CHECK(true == audio_start_playback);
102 NaClLog(1, "example: frequencies are %f %f\n", frequency_l_, frequency_r_);
103 NaClLog(1, "example: amplitudes are %f %f\n", amplitude_l_, amplitude_r_);
104 NaClLog(1, "example: Scheduling StopOutput on main thread in %"
105 NACL_PRIu32"msec\n", duration_msec_);
106 // Schedule a callback in duration_msec_ to stop audio output
107 pp::CompletionCallback cc(StopOutput, this);
108 pp::Module::Get()->core()->CallOnMainThread(duration_msec_, cc, PP_OK);
109 }
110
111 static void StopOutput(void* user_data, int32_t err) {
112 MyInstance* instance = static_cast<MyInstance*>(user_data);
113
114 const int kMaxResult = 256;
115 char result[kMaxResult];
116 NaClLog(1, "example: StopOutput() invoked on main thread\n");
117 if (PP_OK == err) {
118 if (instance->audio_->StopPlayback()) {
119 // In headless mode, the build bots may not have an audio driver, in
120 // which case the callback won't be invoked.
121 // TODO(nfullagar): Other ways to determine if machine has audio
122 // capabilities. Currently PPAPI returns a valid resource regardless.
123 if ((instance->callback_count_ >= 2) || instance->headless_) {
124 snprintf(result, kMaxResult, "StopOutput:PASSED");
125 } else {
126 snprintf(result, kMaxResult, "StopOutput:FAILED - too "
127 "few callbacks (only %d callbacks detected)",
128 static_cast<int>(instance->callback_count_));
129 }
130 }
131 } else {
132 snprintf(result, kMaxResult,
133 "StopOutput: FAILED - returned err is %d", static_cast<int>(err));
134 }
135 // Release audio & config instance.
136 delete instance->audio_;
137 delete instance->config_;
138 instance->audio_ = NULL;
139 instance->config_ = NULL;
140 // At this point the test has finished, report result.
141 pp::Var message(result);
142 instance->PostMessage(message);
143 }
144
145 // To enable basic tests, use basic_tests="1" in the embed tag.
146 void BasicTests() {
147 // Verify obtained_sample_frame_count isn't out of range.
148 CHECK(obtained_sample_frame_count_ >= PP_AUDIOMINSAMPLEFRAMECOUNT);
149 CHECK(obtained_sample_frame_count_ <= PP_AUDIOMAXSAMPLEFRAMECOUNT);
150 // Do some sanity checks below; verify c & cpp interfaces agree.
151 // Note: This is test code and is not normally needed for an application.
152 PPB_GetInterface get_browser_interface =
153 pp::Module::Get()->get_browser_interface();
154 const struct PPB_AudioConfig* audio_config_interface =
155 static_cast<const struct PPB_AudioConfig*>(
156 get_browser_interface(PPB_AUDIO_CONFIG_INTERFACE));
157 const struct PPB_Audio* audio_interface =
158 static_cast<const struct PPB_Audio*>(
159 get_browser_interface(PPB_AUDIO_INTERFACE));
160 PP_Resource audio_config_resource = config_->pp_resource();
161 PP_Resource audio_resource = audio_->pp_resource();
162 NaClLog(1, "example: audio config resource: %"NACL_PRId32"\n",
163 audio_config_resource);
164 NaClLog(1, "example: audio resource: %"NACL_PRId32"\n", audio_resource);
165 CHECK(PP_TRUE == audio_config_interface->
166 IsAudioConfig(audio_config_resource));
167 CHECK(PP_TRUE == audio_interface->IsAudio(audio_resource));
168 CHECK(PP_FALSE == audio_config_interface->IsAudioConfig(audio_resource));
169 CHECK(PP_FALSE == audio_interface->IsAudio(audio_config_resource));
170 CHECK(audio_interface->GetCurrentConfig(audio_resource) ==
171 audio_config_resource);
172 CHECK(0 == audio_interface->GetCurrentConfig(audio_config_resource));
173 CHECK(audio_config_interface->GetSampleRate(audio_config_resource) ==
174 config_->sample_rate());
175 CHECK(audio_config_interface->GetSampleFrameCount(audio_config_resource) ==
176 config_->sample_frame_count());
177 CHECK(audio_->config().pp_resource() == audio_config_resource);
178 }
179
180 // To enable stress tests, use stress_tests="1" in the embed tag.
181 void StressTests() {
182 // Attempt to create many audio devices, then immediately shut them down.
183 // Chrome may generate some warnings on the console, but should not crash.
184 const int kNumManyAudio = 1000;
185 pp::Audio* many_audio[kNumManyAudio];
186 for (int i = 0; i < kNumManyAudio; ++i)
187 many_audio[i] = new pp::Audio(this, *config_, SilenceCallback, this);
188 for (int i = 0; i < kNumManyAudio; ++i)
189 CHECK(true == many_audio[i]->StartPlayback());
190 for (int i = 0; i < kNumManyAudio; ++i)
191 delete many_audio[i];
192 }
193
194 void TestSuite() {
195 if (basic_tests_)
196 BasicTests();
197 if (stress_tests_)
198 StressTests();
199 }
200
201 virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) {
202 ParseArgs(argc, argn, argv);
203 obtained_sample_frame_count_ = pp::AudioConfig::RecommendSampleFrameCount(
204 kSampleFrequency, kSampleFrameCount);
205 config_ = new
206 pp::AudioConfig(this, kSampleFrequency, obtained_sample_frame_count_);
207 CHECK(NULL != config_);
208 audio_ = new pp::Audio(this, *config_, SineWaveCallback, this);
209 CHECK(NULL != audio_);
210 // Run through test suite before attempting real playback.
211 TestSuite();
212 return true;
213 }
214
215 private:
216 static void SineWaveCallback(void* samples, uint32_t num_bytes, void* thiz) {
217 MyInstance* instance = reinterpret_cast<MyInstance*>(thiz);
218 const double delta_l = kTwoPi * instance->frequency_l_ / kSampleFrequency;
219 const double delta_r = kTwoPi * instance->frequency_r_ / kSampleFrequency;
220
221 // Verify num_bytes and obtained_sample_frame_count match up.
222 const int kNumChannelsForStereo = 2;
223 const int kSizeOfSample = sizeof(int16_t);
224 const size_t single_sample = kNumChannelsForStereo * kSizeOfSample;
225
226 // CHECK inside callback is only for testing purposes.
227 CHECK(instance->obtained_sample_frame_count_ * single_sample == num_bytes);
228
229 // Use per channel audio wave value to avoid clicks on buffer boundries.
230 double wave_l = instance->audio_wave_l_;
231 double wave_r = instance->audio_wave_r_;
232 const int16_t max_int16 = std::numeric_limits<int16_t>::max();
233 int16_t* buf = reinterpret_cast<int16_t*>(samples);
234 for (size_t i = 0; i < instance->obtained_sample_frame_count_; ++i) {
235 const double l = sin(wave_l) * instance->amplitude_l_ * max_int16;
236 const double r = sin(wave_r) * instance->amplitude_r_ * max_int16;
237 *buf++ = static_cast<int16_t>(l);
238 *buf++ = static_cast<int16_t>(r);
239 // Add delta, keep within -kTwoPi..kTwoPi to preserve precision.
240 wave_l += delta_l;
241 if (wave_l > kTwoPi)
242 wave_l -= kTwoPi * 2.0;
243 wave_r += delta_r;
244 if (wave_r > kTwoPi)
245 wave_r -= kTwoPi * 2.0;
246 }
247 // Store current value to use as starting point for next callback.
248 instance->audio_wave_l_ = wave_l;
249 instance->audio_wave_r_ = wave_r;
250
251 ++instance->callback_count_;
252 }
253
254 static void SilenceCallback(void* samples, uint32_t num_bytes, void* thiz) {
255 memset(samples, 0, num_bytes);
256 }
257
258 // Audio config resource. Allocated in Init().
259 pp::AudioConfig* config_;
260
261 // Audio resource. Allocated in Init().
262 pp::Audio* audio_;
263
264 // Current audio wave position, used to prevent sine wave skips
265 // on buffer boundaries.
266 double audio_wave_l_;
267 double audio_wave_r_;
268
269 double frequency_l_;
270 double frequency_r_;
271
272 double amplitude_l_;
273 double amplitude_r_;
274
275 bool headless_;
276
277 bool basic_tests_;
278 bool stress_tests_;
279
280 uint32_t duration_msec_;
281 uint32_t obtained_sample_frame_count_;
282
283 int callback_count_;
284 };
285
286 class MyModule : public pp::Module {
287 public:
288 // Override CreateInstance to create your customized Instance object.
289 virtual pp::Instance* CreateInstance(PP_Instance instance) {
290 return new MyInstance(instance);
291 }
292 };
293
294 namespace pp {
295
296 // Factory function for your specialization of the Module object.
297 Module* CreateModule() {
298 NaClLogModuleInit();
299 return new MyModule();
300 }
301
302 } // namespace pp
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698