One of the reasons it took me so long to implement OpenSL support for libpd is that I was dreading the complexity of OpenSL. I tried reading the documentation more than once, but my eyes glazed over every time. Fortunately, Victor Lazzarini came along and posted a great tutorial on streaming audio with OpenSL.
Now that I had some sample code that took care of the setup, configuration, and cleanup of OpenSL objects, it was straightforward to revise it for my purposes. The main change I made was to equip OpenSL with a simple, callback-driven API inspired by the JACK audio connection kit, much like the Java-based API that I put together when I first started working on Pd for Android.
In order to use this library, you need to implement an audio processing callback that reads a buffer of input samples and writes a buffer of output samples. The exact signature looks like this:
typedef void (*opensl_process_t)(void *context, int sRate, int bufFrames, int inChans, const short *inBuf, int outChans, short *outBuf);
In addition to the input and output buffers, the parameters include the sample rate, buffer size in frames, and the number of input and output channels, as well as a pointer that may be used to store additional context information between callbacks.
Once the processing callback is in place, you can open an OpenSL I/O stream by specifying the desired sample rate, channel configuration, buffer size, and processing callback:
OPENSL_STREAM *opensl_open(int sRate, int inChans, int outChans, int bufFrames, opensl_process_t proc, void *context);
The context pointer can be
NULL if the callback needs no additional information. The return value will be an opaque pointer representing the OpenSL I/O stream on success, or
NULL on failure.
(By the way, I should point out that there is no such thing as an OpenSL I/O stream. Much like Android’s Java API, OpenSL has objects for either input or output, but not both. One of the purposes of this API is to tie them together to create a reasonable illusion of duplex audio.)
Now that you have an OpenSL stream, you can start and pause it with the following pair of functions, whose return values are zero on success:
int opensl_start(OPENSL_STREAM *p);
int opensl_pause(OPENSL_STREAM *p);
When you’re done with the stream, you should close it in order to release the resources that it takes up:
void opensl_close(OPENSL_STREAM *p);
After you’ve closed the stream, the pointer is no longer valid.
That’s all there is to it. I hope that this API will be useful beyond its original purpose, and that it will lower the barrier to entry for OpenSL development. The code is available from the opensl branch of Pd for Android: https://github.com/libpd/libpd/tree/opensl/jni