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

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