This tutorial provides information on how to create a PNaCl application that uses pp::Audio and pp::URLLoader resources. The application can be tested with Samsung Smart TV Emulator 4.5 or directly on Samsung Smart TV with Native Client. You can also test it in the Google Chrome browser.

The pp::Audio interface in PNaCl enables usage of sounds in your applications.

There are 3 possible audio sources:

an audio file (for example in WAVE format)

a sound generated inside of application (i.e. sine wave)

a sound recorded into the memory by another part of application

All 3 types of sources can be joined to create more complex sounds.

This tutorial shows how to create a PNaCl application that reads data from a WAVE file and plays it on an audio output device, so that user can hear it. Also application manages mixing and playing simultaneously sounds from different files.

The pp::Audio provides a low-level audio stream handling. When resource is created, it gets PPB_Audio_Callback callback function, that gets called every time browser needs more data to play. Playback can be stopped or started.

The pp::URLLoader serves mainly for loading remote resources, but we can use it also for loading assets from widget directory. When doing this, you need to directly specify needed file path from your widget directory:

// set file to downloadurl_="./sounds/"+varMessage.AsString()+".wav";

Following figure shows how browser and PNaCl module communicate when loading requested file:

second, called when data was read, should be created as optional, because when data is available (here we don’t need to download it from remote point, so it is available) ReadResponseBody() may return read data synchronously.

When full file was read or an error occurred, fileReadCompleted() function is called. This function starts WAVE interpreting procedure.

Reading WAVE header

The Microsoft’s RIFF specification contains the WAVE file format. File starts with a header followed by a sequence of samples formatted according to data in the header. The standard WAVE file format is as follows:

Figure 8: WAVE format

From this format we will extract a header with fields of appropriate size:

Once sound is being played, browser continually sends request to fill audio buffer. PNaCl supports stereo sound. This means that we have to provide two samples (left and right) for every sample to play.

Mixing sounds is not supported by pp::Audio interface. To achieve multiple sounds plying simultaneously mixing technique has to be implemented by application. This tutorial provides simple mixer that sums up samples from all playing sounds. Volumes of the sounds are normalized according to number of playing sounds.

For mono sound we just rewrite one sample many times to output buffer.

// for mono sound each sample is passed to both channelsaudioDemoInstance->safeAdd(buff[i*2],(int16_t)instance.sampleData[instance.sampleDataOffset]*volume);audioDemoInstance->safeAdd(buff[i*2+1],(int16_t)instance.sampleData[instance.sampleDataOffset]*volume);instance.sampleDataOffset++;

For stereo sound each sample is used once.

// for stereo sound samples are written successively to all channelsaudioDemoInstance->safeAdd(buff[2*i],(int16_t)instance.sampleData[instance.sampleDataOffset]*volume);instance.sampleDataOffset++;audioDemoInstance->safeAdd(buff[2*i+1],(int16_t)instance.sampleData[instance.sampleDataOffset]*volume);instance.sampleDataOffset++;

Important

Always check before writing to buffer if its size is enough to write as much samples as required.

Thread and real-time issues

As audio callback function is called from background application thread. This brings several problems:

Data access

Data can be accessed from both audio and main application threads. However, locks should not be used, as attempting to acquire a lock may result in swapping out the thread and audio dropouts.

PPAPI and CRT (C Run-Time) library calls

Using some functions form PPAPI or CRT library, such as malloc, gettimeofday, mutex, critical sections also swaps out the callback function and shouldn’t be used inside of it.

Long computations

Another case when audio dropouts may occur is when callback computation time does not meet real-time conditions.

Summing up, you should program the callback function very carefully. Calling some functions or doing much time-consuming computations may result in hard to track down and debug audio dropouts.

Warning

StartPlayback() and StopPlayback() are asynchronous RPCs. That means, the playback may not be started or stopped immediately after calling these functions. If you need it to be precise with another application actions, you have to synchronize it manually.