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

Side by Side Diff: native_client_sdk/src/doc/devguide/coding/audio.rst

Issue 24446002: Port Pepper Audio API from the devsite. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Remove SDK gallery refs and () instances Created 7 years, 2 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
« no previous file with comments | « no previous file | native_client_sdk/src/doc/images/pepper-audio-api.png » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 .. _devguide-coding-audio: 1 .. _devguide-coding-audio:
2 2
3 ##### 3 #####
4 Audio 4 Audio
5 ##### 5 #####
6 6
7 fooooooooooooooooooooo 7 .. contents::
8 8 :local:
9 :backlinks: none
10 :depth: 2
11
12 This chapter describes how to use the Pepper audio API to play an audio
13 stream. The Pepper audio API provides a low-level means of playing a stream of
14 audio samples generated by a Native Client module. The API generally works as
15 follows: A Native Client module creates an audio resource that represents an
16 audio stream, and tells the browser to start or stop playing the audio
17 resource. The browser calls a function in the Native Client module to fill a
18 buffer with audio samples every time it needs data to play from the audio
19 stream.
20
21 The code examples in this chapter describe a simple Native Client module that
22 generates audio samples using a sine wave with a frequency of 440 Hz. The module
23 starts playing the audio samples as soon as it is loaded into the browser. For a
24 slightly more sophisticated example, see the ``audio`` example (source code in
25 the SDK directory ``examples/api/audio``), which lets users specify a frequency
26 for the sine wave and click buttons to start and stop audio playback.
27
28 Reference information
29 =====================
30
31 For reference information related to the Pepper audio API, see the following
32 documentation:
33
34 * `pp::AudioConfig class
35 <https://developers.google.com/native-client/peppercpp/classpp_1_1_audio_confi g>`_
36
37 * `pp::Audio class
38 <https://developers.google.com/native-client/peppercpp/classpp_1_1_audio>`_
39
40 * `audio_config.h
41 <https://developers.google.com/native-client/peppercpp/audio__config_8h>`_
42
43 * `audio.h <https://developers.google.com/native-client/peppercpp/audio_8h>`_
44
45 * `PP_AudioSampleRate
46 <https://developers.google.com/native-client/pepperc/group___enums.html#gaee75 0c350655f2fb0fe04c04029e0ff8>`_
47
48 About the Pepper audio API
49 ==========================
50
51 The Pepper audio API lets Native Client modules play audio streams in a
52 browser. To play an audio stream, a module generates audio samples and writes
53 them into a buffer. The browser reads the audio samples from the buffer and
54 plays them using an audio device on the client computer.
55
56 .. image:: /images/pepper-audio-buffer.png
57
58 This mechanism is simple but low-level. If you want to play plain sound files in
59 a web application, you may want to consider higher-level alternatives such as
60 using the HTML ``<audio>`` tag, JavaScript, or the new `Web Audio API
61 <http://chromium.googlecode.com/svn/trunk/samples/audio/index.html>`_.
binji 2013/10/02 07:00:42 We also include ogg/vorbis/openAL in the SDK now,
Jim Stichnoth 2013/10/17 21:57:36 I don't really have enough knowledge to add someth
binji 2013/10/17 21:59:54 OK, we can leave it out for now.
62
63 The Pepper audio API is a good option for playing audio data if you want to do
64 audio processing in your web application. You might use the audio API, for
65 example, if you want to apply audio effects to sounds, synthesize your own
66 sounds, or do any other type of CPU-intensive processing of audio
67 samples. Another likely use case is gaming applications: you might use a gaming
68 library to process audio data, and then simply use the audio API to output the
69 processed data.
70
71 The Pepper audio API is straightforward to use:
72
73 #. Your module creates an audio configuration resource and an audio resource.
74
75 #. Your module implements a callback function that fills an audio buffer with
76 data.
77
78 #. Your module invokes the StartPlayback and StopPlayback methods of the audio
79 resource (e.g., when certain events occur).
80
81 #. The browser invokes your callback function whenever it needs audio data to
82 play. Your callback function can generate the audio data in a number of
83 ways---e.g., it can generate new data, or it can copy pre-mixed data into the
84 audio buffer.
85
86 This basic interaction is illustrated below, and described in detail in the
87 sections that follow.
88
89 .. image:: /images/pepper-audio-api.png
90
91 Digital audio concepts
92 ======================
93
94 Before you use the Pepper audio API, it's helpful to understand a few concepts
95 that are fundamental to how digital audio is recorded and played back:
96
97 sample rate
98 the number of times an input sound source is sampled per second;
99 correspondingly, the number of samples that are played back per second
100
101 bit depth
102 the number of bits used to represent a sample
103
104 channels
105 the number of input sources recorded in each sampling interval;
106 correspondingly, the number of outputs that are played back simultaneously
107 (typically using different speakers)
108
109 The higher the sample rate and bit depth used to record a sound wave, the more
110 accurately the sound wave can be reproduced, since it will have been sampled
111 more frequently and stored using a higher level of quantization. Common sampling
112 rates include 44,100 Hz (44,100 samples/second, the sample rate used on CDs),
113 and 48,000 Hz (the sample rate used on DVDs and Digital Audio Tapes). A common
114 bit depth is 16 bits per sample, and a common number of channels is 2 (left and
115 right channels for stereo sound).
116
117 The Pepper audio API currently lets Native Client modules play audio streams
118 with the following configurations:
119
120 * **sample rate**: 44,100 Hz or 48,000 Hz
121 * **bit depth**: 16
122 * **channels**: 2 (stereo)
123
124 Setting up the module
125 =====================
126
127 The code examples below describe a simple Native Client module that generates
128 audio samples using a sine wave with a frequency of 440 Hz. The module starts
129 playing the audio samples as soon as it is loaded into the browser.
130
131 The Native Client module is set up by implementing subclasses of the
132 ``pp::Module`` and ``pp::Instance`` classes, as normal.
binji 2013/10/02 07:00:42 None of the other documents (aside from the tutori
Jim Stichnoth 2013/10/17 21:57:36 I trimmed the example back a bunch.
133
134 .. naclcode::
135
136 #include <cassert>
137 #include <cmath>
138 #include <limits>
139 #include "ppapi/cpp/audio.h"
140 #include "ppapi/cpp/instance.h"
141 #include "ppapi/cpp/module.h"
142
143 namespace {
144 // Constants used to generate a sine wave.
145 const double kFrequency = 440.0;
146 const double kTwoPi = 2.0 * 3.141592653589;
147
148 // Constants used to create an audio configuration resource.
149 // The sample count we will request from the browser.
150 const uint32_t kSampleFrameCount = 4096u;
151 // The number of channels in the audio stream (only supporting stereo audio
152 // for now).
153 const uint32_t kChannels = 2u;
154 } // namespace
155
156 namespace sine_synth {
157 // The Instance class. One of these exists for each instance of your NaCl
158 // module on the web page. The browser will ask the Module object to create
159 // a new Instance for each occurrence of the <embed> tag that has these
160 // attributes:
161 // type="application/x-nacl"
162 // src="sine_synth.nmf"
163 class SineSynthInstance : public pp::Instance {
164 public:
165 explicit SineSynthInstance(PP_Instance instance)
166 : pp::Instance(instance),
167 theta_(0),
168 sample_frame_count_(kSampleFrameCount) {}
169 virtual ~SineSynthInstance() {}
170
171 // Called by the browser once the NaCl module is loaded and ready to
172 // initialize. Creates a Pepper audio context and initializes it. Returns
173 // true on success. Returning false causes the NaCl module to be deleted
174 // and no other functions to be called.
175 virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]);
176
177 private:
178 // Function called by the browser when it needs more audio samples.
179 static void SineWaveCallback(void* samples,
180 uint32_t buffer_size,
181 void* data) {
182 ...
183 }
184
185 // Audio resource.
186 pp::Audio audio_;
187
188 // The last parameter sent to the sin function. Used to prevent sine wave
189 // skips on buffer boundaries.
190 double theta_;
191
192 // The count of sample frames per channel in an audio buffer.
193 uint32_t sample_frame_count_;
194
195 };
196
197 // The Module class. The browser calls the CreateInstance() method to create
198 // an instance of your NaCl module on the web page. The browser creates a new
199 // instance for each <embed> tag with type="application/x-nacl".
200 class SineSynthModule : public pp::Module {
201 public:
202 SineSynthModule() : pp::Module() {}
203 ~SineSynthModule() {}
204
205 // Create and return a SineSynthInstance object.
206 virtual pp::Instance* CreateInstance(PP_Instance instance) {
207 return new SineSynthInstance(instance);
208 }
209 };
210
211 } // namespace sine_synth
212
213 // Factory function called by the browser when the module is first loaded.
214 // The browser keeps a singleton of this module. It calls the
215 // CreateInstance() method on the object you return to make instances. There
216 // is one instance per <embed> tag on the page. This is the main binding
217 // point for your NaCl module with the browser.
218 namespace pp {
219 Module* CreateModule() {
220 return new sine_synth::SineSynthModule();
221 }
222
223 Creating an audio configuration resource
224 ========================================
225
226 Resources
227 ---------
228
229 Before the module can play an audio stream, it must create two resources: an
230 audio configuration resource and an audio resource. Resources are handles to
231 objects that the browser provides to module instances. An audio resource is an
232 object that represents the state of an audio stream, including whether the
233 stream is paused or being played back, and which callback function to invoke
234 when the samples in the stream's buffer run out. An audio configuration resource
235 is an object that stores configuration data for an audio resource, including the
236 sampling frequency of the audio samples, and the number of samples that the
237 callback function must provide when the browser invokes it.
238
239 Sample frame count
240 ------------------
241
242 Prior to creating an audio configuration resource, the module should call
243 ``RecommendSampleFrameCount`` to obtain a *sample frame count* from the
244 browser. The sample frame count is the number of samples that the callback
245 function must provide per channel each time the browser invokes the callback
246 function. For example, if the sample frame count is 4096 for a stereo audio
247 stream, the callback function must provide a 8192 samples (4096 for the left
248 channel and 4096 for the right channel).
249
250 The module can request a specific sample frame count, but the browser may return
251 a different sample frame count depending on the capabilities of the client
252 device. At present, ``RecommendSampleFrameCount`` simply bound-checks the
253 requested sample frame count (see
254 ``toolchain/platform/x86_64-nacl/include/ppapi/c/ppb_audio_config.h`` for the
binji 2013/10/02 07:00:42 this location is ``include/ppapi/c/ppb_audio_confi
Jim Stichnoth 2013/10/17 21:57:36 Done.
255 minimum and maximum sample frame counts, currently 64 and 32768). In the future,
256 ``RecommendSampleFrameCount`` may perform a more sophisticated calculation,
257 particularly if there is an intrinsic buffer size for the client device.
258
259 Selecting a sample frame count for an audio stream involves a tradeoff between
260 latency and CPU usage. If you want your module to have short audio latency so
261 that it can rapidly change what's playing in the audio stream, you should
262 request a small sample frame count. That could be useful in gaming applications,
263 for example, where sounds have to change frequently in response to game
264 action. However, a small sample frame count results in higher CPU usage, since
265 the browser must invoke the callback function frequently to refill the audio
266 buffer. Conversely, a large sample frame count results in higher latency but
267 lower CPU usage. You should request a large sample frame count if your module
268 will play long, uninterrupted audio segments.
269
270 Supported audio configurations
271 ------------------------------
272
273 After the module obtains a sample frame count, it can create an audio
274 configuration resource. Currently the Pepper audio API supports audio streams
275 with the following configuration settings:
276
277 * sample rate: 44,100 Hz or 48,000 Hz
binji 2013/10/02 07:00:42 There is a duplicated table above. Should we remov
Jim Stichnoth 2013/10/17 21:57:36 Done.
278 * bit depth: 16
279 * channels: 2
280
281 C++ modules can create a configuration resource by instantiating a
282 ``pp::AudioConfig`` object. Check ``audio_config.h`` for the latest
283 configurations that are supported.
284
285 .. naclcode::
286
287 bool SineSynthInstance::Init(uint32_t argc,
binji 2013/10/02 07:00:42 This has changed slightly, but maybe it's better t
288 const char* argn[],
289 const char* argv[]) {
290
291 // Ask the browser/device for an appropriate sample frame count size.
292 sample_frame_count_ =
293 pp::AudioConfig::RecommendSampleFrameCount(PP_AUDIOSAMPLERATE_44100,
294 kSampleFrameCount);
295
296 // Create an audio configuration resource.
297 pp::AudioConfig audio_config = pp::AudioConfig(this,
298 PP_AUDIOSAMPLERATE_44100,
299 sample_frame_count_);
300
301 // Create an audio resource.
302 audio_ = pp::Audio(this,
303 audio_config,
304 SineWaveCallback,
305 this);
306
307 // Start playback when the module instance is initialized.
308 return audio_.StartPlayback();
309 }
310
311 Creating an audio resource
312 ==========================
313
314 Once the module has created an audio configuration resource, it can create an
315 audio resource. To do so, it instantiates a ``pp::Audio`` object, passing in a
316 pointer to the module instance, the audio configuration resource, a callback
317 function, and a pointer to user data (data that is used in the callback
318 function).
319
320 .. naclcode::
binji 2013/10/02 07:00:42 This is a duplicate of the above code. Remove one?
Jim Stichnoth 2013/10/17 21:57:36 Done.
321
322 bool SineSynthInstance::Init(uint32_t argc,
323 const char* argn[],
324 const char* argv[]) {
325
326 // Ask the browser/device for an appropriate sample frame count size.
327 sample_frame_count_ =
328 pp::AudioConfig::RecommendSampleFrameCount(PP_AUDIOSAMPLERATE_44100,
329 kSampleFrameCount);
330
331 // Create an audio configuration resource.
332 pp::AudioConfig audio_config = pp::AudioConfig(this,
333 PP_AUDIOSAMPLERATE_44100,
334 sample_frame_count_);
335
336 // Create an audio resource.
337 audio_ = pp::Audio(this,
338 audio_config,
339 SineWaveCallback,
340 this);
341
342 // Start playback when the module instance is initialized.
343 return audio_.StartPlayback();
344 }
345
346 Implementing a callback function
347 ================================
348
349 The browser calls the callback function associated with an audio resource every
350 time it needs more samples to play. The callback function can generate new
351 samples (e.g., by applying sound effects), or copy pre-mixed samples into the
352 audio buffer. The example below generates new samples by computing values of a
353 sine wave.
354
355 The last parameter passed to the callback function is generic user data that the
356 function can use in processing samples. In the example below, the user data is a
357 pointer to the module instance, which includes member variables
358 ``sample_frame_count_`` (the sample frame count obtained from the browser) and
359 ``theta_`` (the last angle that was used to compute a sine value in the previous
360 callback; this lets the function generate a smooth sine wave by starting at that
361 angle plus a small delta).
362
363 .. naclcode::
364
365 class SineSynthInstance : public pp::Instance {
366 public:
367 ...
368
369 private:
370 static void SineWaveCallback(void* samples,
371 uint32_t buffer_size,
372 void* data) {
373
374 // The user data in this example is a pointer to the module instance.
375 SineSynthInstance* sine_synth_instance =
376 reinterpret_cast<SineSynthInstance*>(data);
binji 2013/10/02 07:00:42 hmm, these reinterpret_casts should really be stat
377
378 // Delta by which to increase theta_ for each sample.
379 const double delta = kTwoPi * kFrequency / PP_AUDIOSAMPLERATE_44100;
380 // Amount by which to scale up the computed sine value.
381 const int16_t max_int16 = std::numeric_limits<int16_t>::max();
382
383 int16_t* buff = reinterpret_cast<int16_t*>(samples);
384
385 // Make sure we can't write outside the buffer.
386 assert(buffer_size >= (sizeof(*buff) * kChannels *
387 sine_synth_instance->sample_frame_count_));
388
389 for (size_t sample_i = 0;
390 sample_i < sine_synth_instance->sample_frame_count_;
391 ++sample_i, sine_synth_instance->theta_ += delta) {
392
393 // Keep theta_ from going beyond 2*Pi.
394 if (sine_synth_instance->theta_ > kTwoPi) {
395 sine_synth_instance->theta_ -= kTwoPi;
396 }
397
398 // Compute the sine value for the current theta_, scale it up,
399 // and write it into the buffer once for each channel.
400 double sin_value(std::sin(sine_synth_instance->theta_));
401 int16_t scaled_value = static_cast<int16_t>(sin_value * max_int16);
402 for (size_t channel = 0; channel < kChannels; ++channel) {
403 *buff++ = scaled_value;
404 }
binji 2013/10/02 07:00:42 This code is basically the same as the example. I
405 }
406 }
407
408 ...
409 };
410
411 Application threads and real-time requirements
412 ----------------------------------------------
413
414 The callback function runs in a background application thread. This allows audio
415 processing to continue even when the application is busy doing something
416 else. If the main application thread and the callback thread access the same
417 data, you may be tempted to use a lock to control access to that data. You
418 should avoid the use of locks in the callback thread, however, as attempting to
419 acquire a lock may cause the thread to get swapped out, resulting in audio
420 dropouts.
421
422 In general, you must program the callback thread carefully, as the Pepper audio
423 API is a very low level API that needs to meet hard real-time requirements. If
424 the callback thread spends too much time processing, it can easily miss the
425 real-time deadline, resulting in audio dropouts. One way the callback thread can
426 miss the deadline is by taking too much time doing computation. Another way the
427 callback thread can miss the deadline is by executing a function call that swaps
428 out the callback thread. Unfortunately, such function calls include just about
429 all C Run-Time (CRT) library calls and Pepper API calls. The callback thread
430 should therefore avoid calls to malloc, gettimeofday, mutex, condvars, critical
431 sections, and so forth; any such calls could attempt to take a lock and swap out
432 the callback thread, which would be disastrous for audio playback. Similarly,
433 the callback thread should avoid Pepper API calls. Audio dropouts due to thread
434 swapping can be very rare and very hard to track down and debug---it's best to
435 avoid making system/Pepper calls in the first place. In short, the audio
436 (callback) thread should use "lock-free" techniques and avoid making CRT library
437 calls.
438
439 One other issue to be aware of is that the ``StartPlayback`` function (discussed
440 below) is an asynchronous RPC; i.e., it does not block. That means that the
441 callback function may not be called immediately after the call to
442 ``StartPlayback``. If it's important to synchronize the callback thread with
443 another thread so that the audio stream starts playing simultaneously with
444 another action in your application, you must handle such synchronization
445 manually.
446
447 Starting and stopping playback
448 ==============================
449
450 To start and stop audio playback, the module simply calls the ``StartPlayback``
451 and ``StopPlayback`` methods of the ``Audio`` object. In the example below, the
452 module calls ``StartPlayback`` when the module instance is created; a more
binji 2013/10/02 07:00:42 This is no longer true, the StartPlayback/StopPlay
Jim Stichnoth 2013/10/17 21:57:36 Done.
453 realistic use would be for a module to start playback in response to user input.
454
455 .. naclcode::
456
457 bool SineSynthInstance::Init(uint32_t argc,
458 const char* argn[],
459 const char* argv[]) {
460
461 // Ask the browser/device for an appropriate sample frame count size.
462 sample_frame_count_ =
463 pp::AudioConfig::RecommendSampleFrameCount(PP_AUDIOSAMPLERATE_44100,
464 kSampleFrameCount);
465
466 // Create an audio configuration resource.
467 pp::AudioConfig audio_config = pp::AudioConfig(this,
468 PP_AUDIOSAMPLERATE_44100,
469 sample_frame_count_);
470
471 // Create an audio resource.
472 audio_ = pp::Audio(this,
473 audio_config,
474 SineWaveCallback,
475 this);
476
477 // Start playback when the module instance is initialized.
478 return audio_.StartPlayback();
479 }
OLDNEW
« no previous file with comments | « no previous file | native_client_sdk/src/doc/images/pepper-audio-api.png » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698