libao documentation | libao version 1.1.0 - 20110221

# libao Plugin Writer's Overview

Plugins are drivers that are loaded dynamically when libao is first initialized by the client application. Drivers that are operating system dependent, like the `oss` and `sun` drivers, or that depend on external libraries, like the `esd` driver, must be implemented as plugins in order to keep binary packagers happy. There are also statically linked drivers, which are written in a nearly identical way, but won't be covered here. In nearly all cases, a dynamically loadable plugin is the preferred way to write a driver, and the required way if the driver depends upon any external libraries.

## Life Cycle

The life cycle of a plugin is:

- When libao is first initialized, it loads all of the plugins from disk.
- Libao then tests each plugin to see if can be used as the default driver.
- When the user opens a device, libao will:
  - Call ao_plugin_device_init() to allow the plugin to allocate and initialize any private data structures it will use.
  - Call ao_plugin_set_option() for each parameter passed to the library by the client application.
  - Call ao_plugin_open.html to open the device for playback.
- Each time the client app calls ao_play(), the library will reorder the byte format (little-endian vs. big-endian) and rearrange input channels to match the format requested by the plugin. The library will then call ao_plugin_play() for the block of audio data.
- When the client app closes the audio device, the library calls ao_plugin_close() to close the device, followed by a call to ao_plugin_device_clear() to deallocate the private data structures.
- When the library is shutdown, the plugin will be unloaded from memory.

In case of errors, ao_plugin_device_clear() will always be called if ao_plugin_device_init() executed successfully. Similarly, ao_plugin_close() will always be called if ao_plugin_open() executed successfully.

## Creating a New Plugin

In order to write a new plugin, follow these steps:

- Decide upon a new short name for your plugin. It should be less than 8 characters and contain only alphanumeric characters (underscores are okay, but discouraged).
- Make a new directory in the src/plugins directory with the short name of your plugin.
- Study the contents of one of the other plugin directories. The Sun driver is a good example of a driver that uses system devices for output, and the ALSA driver is a good example of a plugin that uses an external library. Rename the source file to ao_shortname.c, where "shortname" is the short name of your plugin.
- Create an ao_info structure.
- Implement the all of the methods defined in the plugin API.
- Create src/plugins/shortname/Makefile.am ("shortname" is as described above) and edit the files configure.ac and src/plugins/Makefile.am. There should be a an configure option to disable your plugin. Look at the existing configure.ac file for examples of how to do this.
- Test it thoroughly! :)
- Send a tarball of the src/plugin/shortname directory (only this directory, please!) and a cvs diff -u of the changes you have made to the vorbis-dev list and we'll take a look at it for inclusion.

## API Implementation Tips

- Remember to close any devices/connections you openned in ao_plugin_test().
- Although you should try to allocate all of your data structures in ao_plugin_device_init(), there are cases where you won't be able to allocate memory until ao_plugin_open() is called. That is acceptable, but the rule is that you must deallocate memory in ao_plugin_close() that was allocated in ao_plugin_open() and deallocate memory in ao_plugin_device_clear() that was allocated in ao_plugin_device_init().
- Don't forget to set device->driver_byte_format in ao_plugin_open() to the byte ordering your plugin needs. The libao core will reorder the bytes for you if it necessary.
- Depending on the driver, a channel mapping may be very easy, tricky, or impossible. If the audio backend uses a fixed numbering for its channels (not necessarily a fixed order), your new driver can simply set an `output_matrix` and `output_matrix_ordering` in ao_plugin_device_init() and not need to worry about much else. Libao will automatically permute channels, as well has hand over the needed mapping information in a form that can usually be submitted directly to the audio backend during device configuration. Examples of drivers that do this are WAV, ALSA and PULSE.
- Some drivers can't perform channel mapping determination until they see the input sample format in ao_plugin_open(). Such a driver supports channel mapping by setting the overall `output_matrix_ordering` in ao_plugin_device_init() and then setting the `inter_matrix` field in ao_plugin_open(). One driver that works this way is the Roar plugin.
- The number of channels to be sent to the hardware is not the number of channels declared in the sample format; use the device->output_channels field instead. The number of channels an application submits to libao is not necessarily the same as the number of channels libao sends to the plugin to play.
- Read the driver documentation to see what priority you should set for your plugin in the ao_info structure.

copyright © 2001-2003 Stan Seibert, 2010-2011 Monty | xiph.org monty@xiph.org
libao documentation | libao version 1.1.0 - 20110221