| Index: native_client_sdk/src/doc/_developer.chrome.com_generated/devguide/coding/audio.html
|
| diff --git a/native_client_sdk/src/doc/_developer.chrome.com_generated/devguide/coding/audio.html b/native_client_sdk/src/doc/_developer.chrome.com_generated/devguide/coding/audio.html
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..a4b65bbbd53e571af453142f358057a41119eb79
|
| --- /dev/null
|
| +++ b/native_client_sdk/src/doc/_developer.chrome.com_generated/devguide/coding/audio.html
|
| @@ -0,0 +1,352 @@
|
| +{{+bindTo:partials.standard_nacl_article}}
|
| +
|
| +<section id="audio">
|
| +<span id="devguide-coding-audio"></span><h1 id="audio"><span id="devguide-coding-audio"></span>Audio</h1>
|
| +<div class="contents local topic" id="contents">
|
| +<ul class="small-gap">
|
| +<li><a class="reference internal" href="#reference-information" id="id1">Reference information</a></li>
|
| +<li><a class="reference internal" href="#about-the-pepper-audio-api" id="id2">About the Pepper audio API</a></li>
|
| +<li><a class="reference internal" href="#digital-audio-concepts" id="id3">Digital audio concepts</a></li>
|
| +<li><a class="reference internal" href="#setting-up-the-module" id="id4">Setting up the module</a></li>
|
| +<li><p class="first"><a class="reference internal" href="#creating-an-audio-configuration-resource" id="id5">Creating an audio configuration resource</a></p>
|
| +<ul class="small-gap">
|
| +<li><a class="reference internal" href="#resources" id="id6">Resources</a></li>
|
| +<li><a class="reference internal" href="#sample-frame-count" id="id7">Sample frame count</a></li>
|
| +<li><a class="reference internal" href="#supported-audio-configurations" id="id8">Supported audio configurations</a></li>
|
| +</ul>
|
| +</li>
|
| +<li><a class="reference internal" href="#creating-an-audio-resource" id="id9">Creating an audio resource</a></li>
|
| +<li><p class="first"><a class="reference internal" href="#implementing-a-callback-function" id="id10">Implementing a callback function</a></p>
|
| +<ul class="small-gap">
|
| +<li><a class="reference internal" href="#application-threads-and-real-time-requirements" id="id11">Application threads and real-time requirements</a></li>
|
| +</ul>
|
| +</li>
|
| +<li><a class="reference internal" href="#starting-and-stopping-playback" id="id12">Starting and stopping playback</a></li>
|
| +</ul>
|
| +</div>
|
| +<p>This chapter describes how to use the Pepper audio API to play an audio
|
| +stream. The Pepper audio API provides a low-level means of playing a stream of
|
| +audio samples generated by a Native Client module. The API generally works as
|
| +follows: A Native Client module creates an audio resource that represents an
|
| +audio stream, and tells the browser to start or stop playing the audio
|
| +resource. The browser calls a function in the Native Client module to fill a
|
| +buffer with audio samples every time it needs data to play from the audio
|
| +stream.</p>
|
| +<p>The code examples in this chapter describe a simple Native Client module that
|
| +generates audio samples using a sine wave with a frequency of 440 Hz. The module
|
| +starts playing the audio samples as soon as it is loaded into the browser. For a
|
| +slightly more sophisticated example, see the <code>audio</code> example (source code in
|
| +the SDK directory <code>examples/api/audio</code>), which lets users specify a frequency
|
| +for the sine wave and click buttons to start and stop audio playback.</p>
|
| +<section id="reference-information">
|
| +<h2 id="reference-information">Reference information</h2>
|
| +<p>For reference information related to the Pepper audio API, see the following
|
| +documentation:</p>
|
| +<ul class="small-gap">
|
| +<li><a class="reference external" href="https://developers.google.com/native-client/peppercpp/classpp_1_1_audio_config">pp::AudioConfig class</a></li>
|
| +<li><a class="reference external" href="https://developers.google.com/native-client/peppercpp/classpp_1_1_audio">pp::Audio class</a></li>
|
| +<li><a class="reference external" href="https://developers.google.com/native-client/peppercpp/audio__config_8h">audio_config.h</a></li>
|
| +<li><a class="reference external" href="https://developers.google.com/native-client/peppercpp/audio_8h">audio.h</a></li>
|
| +<li><a class="reference external" href="https://developers.google.com/native-client/pepperc/group___enums.html#gaee750c350655f2fb0fe04c04029e0ff8">PP_AudioSampleRate</a></li>
|
| +</ul>
|
| +</section><section id="about-the-pepper-audio-api">
|
| +<h2 id="about-the-pepper-audio-api">About the Pepper audio API</h2>
|
| +<p>The Pepper audio API lets Native Client modules play audio streams in a
|
| +browser. To play an audio stream, a module generates audio samples and writes
|
| +them into a buffer. The browser reads the audio samples from the buffer and
|
| +plays them using an audio device on the client computer.</p>
|
| +<img alt="/native-client/images/pepper-audio-buffer.png" src="/native-client/images/pepper-audio-buffer.png" />
|
| +<p>This mechanism is simple but low-level. If you want to play plain sound files in
|
| +a web application, you may want to consider higher-level alternatives such as
|
| +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>
|
| +<p>The Pepper audio API is a good option for playing audio data if you want to do
|
| +audio processing in your web application. You might use the audio API, for
|
| +example, if you want to apply audio effects to sounds, synthesize your own
|
| +sounds, or do any other type of CPU-intensive processing of audio
|
| +samples. Another likely use case is gaming applications: you might use a gaming
|
| +library to process audio data, and then simply use the audio API to output the
|
| +processed data.</p>
|
| +<p>The Pepper audio API is straightforward to use:</p>
|
| +<ol class="arabic simple">
|
| +<li>Your module creates an audio configuration resource and an audio resource.</li>
|
| +<li>Your module implements a callback function that fills an audio buffer with
|
| +data.</li>
|
| +<li>Your module invokes the StartPlayback and StopPlayback methods of the audio
|
| +resource (e.g., when certain events occur).</li>
|
| +<li>The browser invokes your callback function whenever it needs audio data to
|
| +play. Your callback function can generate the audio data in a number of
|
| +ways—e.g., it can generate new data, or it can copy pre-mixed data into the
|
| +audio buffer.</li>
|
| +</ol>
|
| +<p>This basic interaction is illustrated below, and described in detail in the
|
| +sections that follow.</p>
|
| +<img alt="/native-client/images/pepper-audio-api.png" src="/native-client/images/pepper-audio-api.png" />
|
| +</section><section id="digital-audio-concepts">
|
| +<h2 id="digital-audio-concepts">Digital audio concepts</h2>
|
| +<p>Before you use the Pepper audio API, it’s helpful to understand a few concepts
|
| +that are fundamental to how digital audio is recorded and played back:</p>
|
| +<dl class="docutils">
|
| +<dt>sample rate</dt>
|
| +<dd>the number of times an input sound source is sampled per second;
|
| +correspondingly, the number of samples that are played back per second</dd>
|
| +<dt>bit depth</dt>
|
| +<dd>the number of bits used to represent a sample</dd>
|
| +<dt>channels</dt>
|
| +<dd>the number of input sources recorded in each sampling interval;
|
| +correspondingly, the number of outputs that are played back simultaneously
|
| +(typically using different speakers)</dd>
|
| +</dl>
|
| +<p>The higher the sample rate and bit depth used to record a sound wave, the more
|
| +accurately the sound wave can be reproduced, since it will have been sampled
|
| +more frequently and stored using a higher level of quantization. Common sampling
|
| +rates include 44,100 Hz (44,100 samples/second, the sample rate used on CDs),
|
| +and 48,000 Hz (the sample rate used on DVDs and Digital Audio Tapes). A common
|
| +bit depth is 16 bits per sample, and a common number of channels is 2 (left and
|
| +right channels for stereo sound).</p>
|
| +<p id="pepper-audio-configurations">The Pepper audio API currently lets Native Client modules play audio streams
|
| +with the following configurations:</p>
|
| +<ul class="small-gap">
|
| +<li><strong>sample rate</strong>: 44,100 Hz or 48,000 Hz</li>
|
| +<li><strong>bit depth</strong>: 16</li>
|
| +<li><strong>channels</strong>: 2 (stereo)</li>
|
| +</ul>
|
| +</section><section id="setting-up-the-module">
|
| +<h2 id="setting-up-the-module">Setting up the module</h2>
|
| +<p>The code examples below describe a simple Native Client module that generates
|
| +audio samples using a sine wave with a frequency of 440 Hz. The module starts
|
| +playing the audio samples as soon as it is loaded into the browser.</p>
|
| +<p>The Native Client module is set up by implementing subclasses of the
|
| +<code>pp::Module</code> and <code>pp::Instance</code> classes, as normal.</p>
|
| +<pre class="prettyprint">
|
| +class SineSynthInstance : public pp::Instance {
|
| + public:
|
| + explicit SineSynthInstance(PP_Instance instance);
|
| + virtual ~SineSynthInstance() {}
|
| +
|
| + // Called by the browser once the NaCl module is loaded and ready to
|
| + // initialize. Creates a Pepper audio context and initializes it. Returns
|
| + // true on success. Returning false causes the NaCl module to be deleted
|
| + // and no other functions to be called.
|
| + virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]);
|
| +
|
| + private:
|
| + // Function called by the browser when it needs more audio samples.
|
| + static void SineWaveCallback(void* samples,
|
| + uint32_t buffer_size,
|
| + void* data);
|
| +
|
| + // Audio resource.
|
| + pp::Audio audio_;
|
| +
|
| + ...
|
| +
|
| +};
|
| +
|
| +class SineSynthModule : public pp::Module {
|
| + public:
|
| + SineSynthModule() : pp::Module() {}
|
| + ~SineSynthModule() {}
|
| +
|
| + // Create and return a SineSynthInstance object.
|
| + virtual pp::Instance* CreateInstance(PP_Instance instance) {
|
| + return new SineSynthInstance(instance);
|
| + }
|
| +};
|
| +</pre>
|
| +</section><section id="creating-an-audio-configuration-resource">
|
| +<h2 id="creating-an-audio-configuration-resource">Creating an audio configuration resource</h2>
|
| +<section id="resources">
|
| +<h3 id="resources">Resources</h3>
|
| +<p>Before the module can play an audio stream, it must create two resources: an
|
| +audio configuration resource and an audio resource. Resources are handles to
|
| +objects that the browser provides to module instances. An audio resource is an
|
| +object that represents the state of an audio stream, including whether the
|
| +stream is paused or being played back, and which callback function to invoke
|
| +when the samples in the stream’s buffer run out. An audio configuration resource
|
| +is an object that stores configuration data for an audio resource, including the
|
| +sampling frequency of the audio samples, and the number of samples that the
|
| +callback function must provide when the browser invokes it.</p>
|
| +</section><section id="sample-frame-count">
|
| +<h3 id="sample-frame-count">Sample frame count</h3>
|
| +<p>Prior to creating an audio configuration resource, the module should call
|
| +<code>RecommendSampleFrameCount</code> to obtain a <em>sample frame count</em> from the
|
| +browser. The sample frame count is the number of samples that the callback
|
| +function must provide per channel each time the browser invokes the callback
|
| +function. For example, if the sample frame count is 4096 for a stereo audio
|
| +stream, the callback function must provide a 8192 samples (4096 for the left
|
| +channel and 4096 for the right channel).</p>
|
| +<p>The module can request a specific sample frame count, but the browser may return
|
| +a different sample frame count depending on the capabilities of the client
|
| +device. At present, <code>RecommendSampleFrameCount</code> simply bound-checks the
|
| +requested sample frame count (see <code>include/ppapi/c/ppb_audio_config.h</code> for the
|
| +minimum and maximum sample frame counts, currently 64 and 32768). In the future,
|
| +<code>RecommendSampleFrameCount</code> may perform a more sophisticated calculation,
|
| +particularly if there is an intrinsic buffer size for the client device.</p>
|
| +<p>Selecting a sample frame count for an audio stream involves a tradeoff between
|
| +latency and CPU usage. If you want your module to have short audio latency so
|
| +that it can rapidly change what’s playing in the audio stream, you should
|
| +request a small sample frame count. That could be useful in gaming applications,
|
| +for example, where sounds have to change frequently in response to game
|
| +action. However, a small sample frame count results in higher CPU usage, since
|
| +the browser must invoke the callback function frequently to refill the audio
|
| +buffer. Conversely, a large sample frame count results in higher latency but
|
| +lower CPU usage. You should request a large sample frame count if your module
|
| +will play long, uninterrupted audio segments.</p>
|
| +</section><section id="supported-audio-configurations">
|
| +<h3 id="supported-audio-configurations">Supported audio configurations</h3>
|
| +<p>After the module obtains a sample frame count, it can create an audio
|
| +configuration resource. Currently the Pepper audio API supports audio streams
|
| +with the configuration settings shown <a class="reference internal" href="#pepper-audio-configurations"><em>above</em></a>.
|
| +C++ modules can create a configuration resource by instantiating a
|
| +<code>pp::AudioConfig</code> object. Check <code>audio_config.h</code> for the latest
|
| +configurations that are supported.</p>
|
| +<pre class="prettyprint">
|
| +bool SineSynthInstance::Init(uint32_t argc,
|
| + const char* argn[],
|
| + const char* argv[]) {
|
| +
|
| + // Ask the browser/device for an appropriate sample frame count size.
|
| + sample_frame_count_ =
|
| + pp::AudioConfig::RecommendSampleFrameCount(PP_AUDIOSAMPLERATE_44100,
|
| + kSampleFrameCount);
|
| +
|
| + // Create an audio configuration resource.
|
| + pp::AudioConfig audio_config = pp::AudioConfig(this,
|
| + PP_AUDIOSAMPLERATE_44100,
|
| + sample_frame_count_);
|
| +
|
| + // Create an audio resource.
|
| + audio_ = pp::Audio(this,
|
| + audio_config,
|
| + SineWaveCallback,
|
| + this);
|
| +
|
| + // Start playback when the module instance is initialized.
|
| + return audio_.StartPlayback();
|
| +}
|
| +</pre>
|
| +</section></section><section id="creating-an-audio-resource">
|
| +<h2 id="creating-an-audio-resource">Creating an audio resource</h2>
|
| +<p>Once the module has created an audio configuration resource, it can create an
|
| +audio resource. To do so, it instantiates a <code>pp::Audio</code> object, passing in a
|
| +pointer to the module instance, the audio configuration resource, a callback
|
| +function, and a pointer to user data (data that is used in the callback
|
| +function). See the example above.</p>
|
| +</section><section id="implementing-a-callback-function">
|
| +<h2 id="implementing-a-callback-function">Implementing a callback function</h2>
|
| +<p>The browser calls the callback function associated with an audio resource every
|
| +time it needs more samples to play. The callback function can generate new
|
| +samples (e.g., by applying sound effects), or copy pre-mixed samples into the
|
| +audio buffer. The example below generates new samples by computing values of a
|
| +sine wave.</p>
|
| +<p>The last parameter passed to the callback function is generic user data that the
|
| +function can use in processing samples. In the example below, the user data is a
|
| +pointer to the module instance, which includes member variables
|
| +<code>sample_frame_count_</code> (the sample frame count obtained from the browser) and
|
| +<code>theta_</code> (the last angle that was used to compute a sine value in the previous
|
| +callback; this lets the function generate a smooth sine wave by starting at that
|
| +angle plus a small delta).</p>
|
| +<pre class="prettyprint">
|
| +class SineSynthInstance : public pp::Instance {
|
| + public:
|
| + ...
|
| +
|
| + private:
|
| + static void SineWaveCallback(void* samples,
|
| + uint32_t buffer_size,
|
| + void* data) {
|
| +
|
| + // The user data in this example is a pointer to the module instance.
|
| + SineSynthInstance* sine_synth_instance =
|
| + reinterpret_cast<SineSynthInstance*>(data);
|
| +
|
| + // Delta by which to increase theta_ for each sample.
|
| + const double delta = kTwoPi * kFrequency / PP_AUDIOSAMPLERATE_44100;
|
| + // Amount by which to scale up the computed sine value.
|
| + const int16_t max_int16 = std::numeric_limits<int16_t>::max();
|
| +
|
| + int16_t* buff = reinterpret_cast<int16_t*>(samples);
|
| +
|
| + // Make sure we can't write outside the buffer.
|
| + assert(buffer_size >= (sizeof(*buff) * kChannels *
|
| + sine_synth_instance->sample_frame_count_));
|
| +
|
| + for (size_t sample_i = 0;
|
| + sample_i < sine_synth_instance->sample_frame_count_;
|
| + ++sample_i, sine_synth_instance->theta_ += delta) {
|
| +
|
| + // Keep theta_ from going beyond 2*Pi.
|
| + if (sine_synth_instance->theta_ > kTwoPi) {
|
| + sine_synth_instance->theta_ -= kTwoPi;
|
| + }
|
| +
|
| + // Compute the sine value for the current theta_, scale it up,
|
| + // and write it into the buffer once for each channel.
|
| + double sin_value(std::sin(sine_synth_instance->theta_));
|
| + int16_t scaled_value = static_cast<int16_t>(sin_value * max_int16);
|
| + for (size_t channel = 0; channel < kChannels; ++channel) {
|
| + *buff++ = scaled_value;
|
| + }
|
| + }
|
| + }
|
| +
|
| + ...
|
| +};
|
| +</pre>
|
| +<section id="application-threads-and-real-time-requirements">
|
| +<h3 id="application-threads-and-real-time-requirements">Application threads and real-time requirements</h3>
|
| +<p>The callback function runs in a background application thread. This allows audio
|
| +processing to continue even when the application is busy doing something
|
| +else. If the main application thread and the callback thread access the same
|
| +data, you may be tempted to use a lock to control access to that data. You
|
| +should avoid the use of locks in the callback thread, however, as attempting to
|
| +acquire a lock may cause the thread to get swapped out, resulting in audio
|
| +dropouts.</p>
|
| +<p>In general, you must program the callback thread carefully, as the Pepper audio
|
| +API is a very low level API that needs to meet hard real-time requirements. If
|
| +the callback thread spends too much time processing, it can easily miss the
|
| +real-time deadline, resulting in audio dropouts. One way the callback thread can
|
| +miss the deadline is by taking too much time doing computation. Another way the
|
| +callback thread can miss the deadline is by executing a function call that swaps
|
| +out the callback thread. Unfortunately, such function calls include just about
|
| +all C Run-Time (CRT) library calls and Pepper API calls. The callback thread
|
| +should therefore avoid calls to malloc, gettimeofday, mutex, condvars, critical
|
| +sections, and so forth; any such calls could attempt to take a lock and swap out
|
| +the callback thread, which would be disastrous for audio playback. Similarly,
|
| +the callback thread should avoid Pepper API calls. Audio dropouts due to thread
|
| +swapping can be very rare and very hard to track down and debug—it’s best to
|
| +avoid making system/Pepper calls in the first place. In short, the audio
|
| +(callback) thread should use “lock-free” techniques and avoid making CRT library
|
| +calls.</p>
|
| +<p>One other issue to be aware of is that the <code>StartPlayback</code> function (discussed
|
| +below) is an asynchronous RPC; i.e., it does not block. That means that the
|
| +callback function may not be called immediately after the call to
|
| +<code>StartPlayback</code>. If it’s important to synchronize the callback thread with
|
| +another thread so that the audio stream starts playing simultaneously with
|
| +another action in your application, you must handle such synchronization
|
| +manually.</p>
|
| +</section></section><section id="starting-and-stopping-playback">
|
| +<h2 id="starting-and-stopping-playback">Starting and stopping playback</h2>
|
| +<p>To start and stop audio playback, the module simply reacts to JavaScript
|
| +messages.</p>
|
| +<pre class="prettyprint">
|
| +const char* const kPlaySoundId = "playSound";
|
| +const char* const kStopSoundId = "stopSound";
|
| +
|
| +void SineSynthInstance::HandleMessage(const pp::Var& var_message) {
|
| + if (!var_message.is_string()) {
|
| + return;
|
| + }
|
| + std::string message = var_message.AsString();
|
| + if (message == kPlaySoundId) {
|
| + audio_.StartPlayback();
|
| + } else if (message == kStopSoundId) {
|
| + audio_.StopPlayback();
|
| + } else if (...) {
|
| + ...
|
| + }
|
| +}
|
| +</pre>
|
| +</section></section>
|
| +
|
| +{{/partials.standard_nacl_article}}
|
|
|