1 {{+bindTo:partials.standard_nacl_article}}
4 <span id=
"devguide-coding-audio"></span><h1 id=
"audio"><span id=
"devguide-coding-audio"></span>Audio
</h1>
5 <div class=
"contents local" id=
"contents" style=
"display: none">
7 <li><a class=
"reference internal" href=
"#reference-information" id=
"id1">Reference information
</a></li>
8 <li><a class=
"reference internal" href=
"#about-the-pepper-audio-api" id=
"id2">About the Pepper audio API
</a></li>
9 <li><a class=
"reference internal" href=
"#digital-audio-concepts" id=
"id3">Digital audio concepts
</a></li>
10 <li><a class=
"reference internal" href=
"#setting-up-the-module" id=
"id4">Setting up the module
</a></li>
11 <li><p class=
"first"><a class=
"reference internal" href=
"#creating-an-audio-configuration-resource" id=
"id5">Creating an audio configuration resource
</a></p>
12 <ul class=
"small-gap">
13 <li><a class=
"reference internal" href=
"#resources" id=
"id6">Resources
</a></li>
14 <li><a class=
"reference internal" href=
"#sample-frame-count" id=
"id7">Sample frame count
</a></li>
15 <li><a class=
"reference internal" href=
"#supported-audio-configurations" id=
"id8">Supported audio configurations
</a></li>
18 <li><a class=
"reference internal" href=
"#creating-an-audio-resource" id=
"id9">Creating an audio resource
</a></li>
19 <li><p class=
"first"><a class=
"reference internal" href=
"#implementing-a-callback-function" id=
"id10">Implementing a callback function
</a></p>
20 <ul class=
"small-gap">
21 <li><a class=
"reference internal" href=
"#application-threads-and-real-time-requirements" id=
"id11">Application threads and real-time requirements
</a></li>
24 <li><a class=
"reference internal" href=
"#starting-and-stopping-playback" id=
"id12">Starting and stopping playback
</a></li>
27 </div><p>This section describes how to use the Pepper audio API to play an audio
28 stream. The Pepper audio API provides a low-level means of playing a stream of
29 audio samples generated by a Native Client module. The API generally works as
30 follows: A Native Client module creates an audio resource that represents an
31 audio stream, and tells the browser to start or stop playing the audio
32 resource. The browser calls a function in the Native Client module to fill a
33 buffer with audio samples every time it needs data to play from the audio
35 <p>The code examples in this section describe a simple Native Client module that
36 generates audio samples using a sine wave with a frequency of
440 Hz. The module
37 starts playing the audio samples as soon as it is loaded into the browser. For a
38 slightly more sophisticated example, see the
<code>audio
</code> example (source code in
39 the SDK directory
<code>examples/api/audio
</code>), which lets users specify a frequency
40 for the sine wave and click buttons to start and stop audio playback.
</p>
41 <h2 id=
"reference-information">Reference information
</h2>
42 <p>For reference information related to the Pepper audio API, see the following
44 <ul class=
"small-gap">
45 <li><a class=
"reference external" href=
"/native-client/pepper_stable/cpp/classpp_1_1_audio_config">pp::AudioConfig class
</a></li>
46 <li><a class=
"reference external" href=
"/native-client/pepper_stable/cpp/classpp_1_1_audio">pp::Audio class
</a></li>
47 <li><a class=
"reference external" href=
"/native-client/pepper_cpp/audio__config_8h">audio_config.h
</a></li>
48 <li><a class=
"reference external" href=
"/native-client/pepper_stable/cpp/audio_8h">audio.h
</a></li>
49 <li><a class=
"reference external" href=
"/native-client/pepper_stable/c/group___enums#gaee750c350655f2fb0fe04c04029e0ff8">PP_AudioSampleRate
</a></li>
51 <h2 id=
"about-the-pepper-audio-api">About the Pepper audio API
</h2>
52 <p>The Pepper audio API lets Native Client modules play audio streams in a
53 browser. To play an audio stream, a module generates audio samples and writes
54 them into a buffer. The browser reads the audio samples from the buffer and
55 plays them using an audio device on the client computer.
</p>
56 <img alt=
"/native-client/images/pepper-audio-buffer.png" src=
"/native-client/images/pepper-audio-buffer.png" />
57 <p>This mechanism is simple but low-level. If you want to play plain sound files in
58 a web application, you may want to consider higher-level alternatives such as
59 using the HTML
<code><audio
></code> tag, JavaScript, or the new
<a class=
"reference external" href=
"http://chromium.googlecode.com/svn/trunk/samples/audio/index.html">Web Audio API
</a>.
</p>
60 <p>The Pepper audio API is a good option for playing audio data if you want to do
61 audio processing in your web application. You might use the audio API, for
62 example, if you want to apply audio effects to sounds, synthesize your own
63 sounds, or do any other type of CPU-intensive processing of audio
64 samples. Another likely use case is gaming applications: you might use a gaming
65 library to process audio data, and then simply use the audio API to output the
67 <p>The Pepper audio API is straightforward to use:
</p>
68 <ol class=
"arabic simple">
69 <li>Your module creates an audio configuration resource and an audio resource.
</li>
70 <li>Your module implements a callback function that fills an audio buffer with
72 <li>Your module invokes the StartPlayback and StopPlayback methods of the audio
73 resource (e.g., when certain events occur).
</li>
74 <li>The browser invokes your callback function whenever it needs audio data to
75 play. Your callback function can generate the audio data in a number of
76 ways
—e.g., it can generate new data, or it can copy pre-mixed data into the
79 <p>This basic interaction is illustrated below, and described in detail in the
80 sections that follow.
</p>
81 <img alt=
"/native-client/images/pepper-audio-api.png" src=
"/native-client/images/pepper-audio-api.png" />
82 <h2 id=
"digital-audio-concepts">Digital audio concepts
</h2>
83 <p>Before you use the Pepper audio API, it
’s helpful to understand a few concepts
84 that are fundamental to how digital audio is recorded and played back:
</p>
87 <dd>the number of times an input sound source is sampled per second;
88 correspondingly, the number of samples that are played back per second
</dd>
90 <dd>the number of bits used to represent a sample
</dd>
92 <dd>the number of input sources recorded in each sampling interval;
93 correspondingly, the number of outputs that are played back simultaneously
94 (typically using different speakers)
</dd>
96 <p>The higher the sample rate and bit depth used to record a sound wave, the more
97 accurately the sound wave can be reproduced, since it will have been sampled
98 more frequently and stored using a higher level of quantization. Common sampling
99 rates include
44,
100 Hz (
44,
100 samples/second, the sample rate used on CDs),
100 and
48,
000 Hz (the sample rate used on DVDs and Digital Audio Tapes). A common
101 bit depth is
16 bits per sample, and a common number of channels is
2 (left and
102 right channels for stereo sound).
</p>
103 <p id=
"pepper-audio-configurations">The Pepper audio API currently lets Native Client modules play audio streams
104 with the following configurations:
</p>
105 <ul class=
"small-gap">
106 <li><strong>sample rate
</strong>:
44,
100 Hz or
48,
000 Hz
</li>
107 <li><strong>bit depth
</strong>:
16</li>
108 <li><strong>channels
</strong>:
2 (stereo)
</li>
110 <h2 id=
"setting-up-the-module">Setting up the module
</h2>
111 <p>The code examples below describe a simple Native Client module that generates
112 audio samples using a sine wave with a frequency of
440 Hz. The module starts
113 playing the audio samples as soon as it is loaded into the browser.
</p>
114 <p>The Native Client module is set up by implementing subclasses of the
115 <code>pp::Module
</code> and
<code>pp::Instance
</code> classes, as normal.
</p>
116 <pre class=
"prettyprint">
117 class SineSynthInstance : public pp::Instance {
119 explicit SineSynthInstance(PP_Instance instance);
120 virtual ~SineSynthInstance() {}
122 // Called by the browser once the NaCl module is loaded and ready to
123 // initialize. Creates a Pepper audio context and initializes it. Returns
124 // true on success. Returning false causes the NaCl module to be deleted
125 // and no other functions to be called.
126 virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]);
129 // Function called by the browser when it needs more audio samples.
130 static void SineWaveCallback(void* samples,
131 uint32_t buffer_size,
141 class SineSynthModule : public pp::Module {
143 SineSynthModule() : pp::Module() {}
144 ~SineSynthModule() {}
146 // Create and return a SineSynthInstance object.
147 virtual pp::Instance* CreateInstance(PP_Instance instance) {
148 return new SineSynthInstance(instance);
152 <h2 id=
"creating-an-audio-configuration-resource">Creating an audio configuration resource
</h2>
153 <h3 id=
"resources">Resources
</h3>
154 <p>Before the module can play an audio stream, it must create two resources: an
155 audio configuration resource and an audio resource. Resources are handles to
156 objects that the browser provides to module instances. An audio resource is an
157 object that represents the state of an audio stream, including whether the
158 stream is paused or being played back, and which callback function to invoke
159 when the samples in the stream
’s buffer run out. An audio configuration resource
160 is an object that stores configuration data for an audio resource, including the
161 sampling frequency of the audio samples, and the number of samples that the
162 callback function must provide when the browser invokes it.
</p>
163 <h3 id=
"sample-frame-count">Sample frame count
</h3>
164 <p>Prior to creating an audio configuration resource, the module should call
165 <code>RecommendSampleFrameCount
</code> to obtain a
<em>sample frame count
</em> from the
166 browser. The sample frame count is the number of samples that the callback
167 function must provide per channel each time the browser invokes the callback
168 function. For example, if the sample frame count is
4096 for a stereo audio
169 stream, the callback function must provide a
8192 samples (
4096 for the left
170 channel and
4096 for the right channel).
</p>
171 <p>The module can request a specific sample frame count, but the browser may return
172 a different sample frame count depending on the capabilities of the client
173 device. At present,
<code>RecommendSampleFrameCount
</code> simply bound-checks the
174 requested sample frame count (see
<code>include/ppapi/c/ppb_audio_config.h
</code> for the
175 minimum and maximum sample frame counts, currently
64 and
32768). In the future,
176 <code>RecommendSampleFrameCount
</code> may perform a more sophisticated calculation,
177 particularly if there is an intrinsic buffer size for the client device.
</p>
178 <p>Selecting a sample frame count for an audio stream involves a tradeoff between
179 latency and CPU usage. If you want your module to have short audio latency so
180 that it can rapidly change what
’s playing in the audio stream, you should
181 request a small sample frame count. That could be useful in gaming applications,
182 for example, where sounds have to change frequently in response to game
183 action. However, a small sample frame count results in higher CPU usage, since
184 the browser must invoke the callback function frequently to refill the audio
185 buffer. Conversely, a large sample frame count results in higher latency but
186 lower CPU usage. You should request a large sample frame count if your module
187 will play long, uninterrupted audio segments.
</p>
188 <h3 id=
"supported-audio-configurations">Supported audio configurations
</h3>
189 <p>After the module obtains a sample frame count, it can create an audio
190 configuration resource. Currently the Pepper audio API supports audio streams
191 with the configuration settings shown
<a class=
"reference internal" href=
"#pepper-audio-configurations"><em>above
</em></a>.
192 C++ modules can create a configuration resource by instantiating a
193 <code>pp::AudioConfig
</code> object. Check
<code>audio_config.h
</code> for the latest
194 configurations that are supported.
</p>
195 <pre class=
"prettyprint">
196 bool SineSynthInstance::Init(uint32_t argc,
198 const char* argv[]) {
200 // Ask the browser/device for an appropriate sample frame count size.
201 sample_frame_count_ =
202 pp::AudioConfig::RecommendSampleFrameCount(PP_AUDIOSAMPLERATE_44100,
205 // Create an audio configuration resource.
206 pp::AudioConfig audio_config = pp::AudioConfig(this,
207 PP_AUDIOSAMPLERATE_44100,
208 sample_frame_count_);
210 // Create an audio resource.
211 audio_ = pp::Audio(this,
216 // Start playback when the module instance is initialized.
217 return audio_.StartPlayback();
220 <h2 id=
"creating-an-audio-resource">Creating an audio resource
</h2>
221 <p>Once the module has created an audio configuration resource, it can create an
222 audio resource. To do so, it instantiates a
<code>pp::Audio
</code> object, passing in a
223 pointer to the module instance, the audio configuration resource, a callback
224 function, and a pointer to user data (data that is used in the callback
225 function). See the example above.
</p>
226 <h2 id=
"implementing-a-callback-function">Implementing a callback function
</h2>
227 <p>The browser calls the callback function associated with an audio resource every
228 time it needs more samples to play. The callback function can generate new
229 samples (e.g., by applying sound effects), or copy pre-mixed samples into the
230 audio buffer. The example below generates new samples by computing values of a
232 <p>The last parameter passed to the callback function is generic user data that the
233 function can use in processing samples. In the example below, the user data is a
234 pointer to the module instance, which includes member variables
235 <code>sample_frame_count_
</code> (the sample frame count obtained from the browser) and
236 <code>theta_
</code> (the last angle that was used to compute a sine value in the previous
237 callback; this lets the function generate a smooth sine wave by starting at that
238 angle plus a small delta).
</p>
239 <pre class=
"prettyprint">
240 class SineSynthInstance : public pp::Instance {
245 static void SineWaveCallback(void* samples,
246 uint32_t buffer_size,
249 // The user data in this example is a pointer to the module instance.
250 SineSynthInstance* sine_synth_instance =
251 reinterpret_cast
<SineSynthInstance*
>(data);
253 // Delta by which to increase theta_ for each sample.
254 const double delta = kTwoPi * kFrequency / PP_AUDIOSAMPLERATE_44100;
255 // Amount by which to scale up the computed sine value.
256 const int16_t max_int16 = std::numeric_limits
<int16_t
>::max();
258 int16_t* buff = reinterpret_cast
<int16_t*
>(samples);
260 // Make sure we can't write outside the buffer.
261 assert(buffer_size
>= (sizeof(*buff) * kChannels *
262 sine_synth_instance-
>sample_frame_count_));
264 for (size_t sample_i =
0;
265 sample_i
< sine_synth_instance-
>sample_frame_count_;
266 ++sample_i, sine_synth_instance-
>theta_ += delta) {
268 // Keep theta_ from going beyond
2*Pi.
269 if (sine_synth_instance-
>theta_
> kTwoPi) {
270 sine_synth_instance-
>theta_ -= kTwoPi;
273 // Compute the sine value for the current theta_, scale it up,
274 // and write it into the buffer once for each channel.
275 double sin_value(std::sin(sine_synth_instance-
>theta_));
276 int16_t scaled_value = static_cast
<int16_t
>(sin_value * max_int16);
277 for (size_t channel =
0; channel
< kChannels; ++channel) {
278 *buff++ = scaled_value;
286 <h3 id=
"application-threads-and-real-time-requirements">Application threads and real-time requirements
</h3>
287 <p>The callback function runs in a background application thread. This allows audio
288 processing to continue even when the application is busy doing something
289 else. If the main application thread and the callback thread access the same
290 data, you may be tempted to use a lock to control access to that data. You
291 should avoid the use of locks in the callback thread, however, as attempting to
292 acquire a lock may cause the thread to get swapped out, resulting in audio
294 <p>In general, you must program the callback thread carefully, as the Pepper audio
295 API is a very low level API that needs to meet hard real-time requirements. If
296 the callback thread spends too much time processing, it can easily miss the
297 real-time deadline, resulting in audio dropouts. One way the callback thread can
298 miss the deadline is by taking too much time doing computation. Another way the
299 callback thread can miss the deadline is by executing a function call that swaps
300 out the callback thread. Unfortunately, such function calls include just about
301 all C Run-Time (CRT) library calls and Pepper API calls. The callback thread
302 should therefore avoid calls to malloc, gettimeofday, mutex, condvars, critical
303 sections, and so forth; any such calls could attempt to take a lock and swap out
304 the callback thread, which would be disastrous for audio playback. Similarly,
305 the callback thread should avoid Pepper API calls. Audio dropouts due to thread
306 swapping can be very rare and very hard to track down and debug
—it
’s best to
307 avoid making system/Pepper calls in the first place. In short, the audio
308 (callback) thread should use
“lock-free
” techniques and avoid making CRT library
310 <p>One other issue to be aware of is that the
<code>StartPlayback
</code> function (discussed
311 below) is an asynchronous RPC; i.e., it does not block. That means that the
312 callback function may not be called immediately after the call to
313 <code>StartPlayback
</code>. If it
’s important to synchronize the callback thread with
314 another thread so that the audio stream starts playing simultaneously with
315 another action in your application, you must handle such synchronization
317 <h2 id=
"starting-and-stopping-playback">Starting and stopping playback
</h2>
318 <p>To start and stop audio playback, the module simply reacts to JavaScript
320 <pre class=
"prettyprint">
321 const char* const kPlaySoundId =
"playSound
";
322 const char* const kStopSoundId =
"stopSound
";
324 void SineSynthInstance::HandleMessage(const pp::Var
& var_message) {
325 if (!var_message.is_string()) {
328 std::string message = var_message.AsString();
329 if (message == kPlaySoundId) {
330 audio_.StartPlayback();
331 } else if (message == kStopSoundId) {
332 audio_.StopPlayback();
340 {{/partials.standard_nacl_article}}