/*
* Copyright (c) 2008 Alexandre Ratchov <alex at caoua.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <string.h>
#include <sndio.h>
#include <ao/ao.h>
#include <ao/plugin.h>
static char *ao_sndio_options[] = {
"verbose",
"quiet",
"matrix",
"debug",
"dev",
"id"
};
ao_info ao_sndio_info = {
AO_TYPE_LIVE,
"sndio audio output",
"sndio",
"Alexandre Ratchov <alex at caoua.org>",
"Outputs to the sndio library",
AO_FMT_NATIVE,
30,
ao_sndio_options,
sizeof(ao_sndio_options)/sizeof(*ao_sndio_options)
};
typedef struct ao_sndio_internal
{
struct sio_hdl *hdl;
char *dev;
int id;
} ao_sndio_internal;
int ao_plugin_test()
{
struct sio_hdl *hdl;
hdl = sio_open(NULL, SIO_PLAY, 0);
if (hdl == NULL)
return 0;
sio_close(hdl);
return 1;
}
ao_info *ao_plugin_driver_info(void)
{
return &ao_sndio_info;
}
int ao_plugin_device_init(ao_device *device)
{
ao_sndio_internal *internal;
internal = (ao_sndio_internal *) calloc(1,sizeof(*internal));
internal->id=-1;
device->internal = internal;
device->output_matrix_order = AO_OUTPUT_MATRIX_FIXED;
return 1;
}
int ao_plugin_set_option(ao_device *device, const char *key, const char *value)
{
ao_sndio_internal *internal = (ao_sndio_internal *) device->internal;
if (!strcmp(key, "dev")) {
if (internal->dev)
free (internal->dev);
if(!value){
internal->dev=NULL;
}else{
if (!(internal->dev = strdup(value)))
return 0;
}
}
if (!strcmp(key, "id")) {
if(internal->dev)
free (internal->dev);
internal->dev=NULL;
internal->id=atoi(value);
}
return 1;
}
int ao_plugin_open(ao_device *device, ao_sample_format *format)
{
ao_sndio_internal *internal = (ao_sndio_internal *) device->internal;
struct sio_par par;
if(!internal->dev && internal->id>=0){
char buf[80];
sprintf(buf,"sun:%d",internal->id);
internal->dev = strdup(buf);
}
internal->hdl = sio_open(internal->dev, SIO_PLAY, 0);
if (internal->hdl == NULL)
return 0;
sio_initpar(&par);
par.sig = 1;
par.le = SIO_LE_NATIVE;
par.bits = format->bits;
par.rate = format->rate;
par.pchan = device->output_channels;
if (!sio_setpar(internal->hdl, &par))
return 0;
device->driver_byte_format = AO_FMT_NATIVE;
if (!sio_start(internal->hdl))
return 0;
if(!device->inter_matrix){
/* set up matrix such that users are warned about > stereo playback */
if(device->output_channels<=2)
device->inter_matrix=strdup("L,R");
//else no matrix, which results in a warning
}
return 1;
}
int ao_plugin_play(ao_device *device, const char *output_samples, uint_32 num_bytes)
{
ao_sndio_internal *internal = (ao_sndio_internal *) device->internal;
struct sio_hdl *hdl = internal->hdl;
if (!sio_write(hdl, output_samples, num_bytes))
return 0;
return 1;
}
int ao_plugin_close(ao_device *device)
{
ao_sndio_internal *internal = (ao_sndio_internal *) device->internal;
struct sio_hdl *hdl = internal->hdl;
if(hdl)
if (!sio_stop(hdl))
return 0;
return 1;
}
void ao_plugin_device_clear(ao_device *device)
{
ao_sndio_internal *internal = (ao_sndio_internal *) device->internal;
struct sio_hdl *hdl = internal->hdl;
if(hdl)
sio_close(hdl);
if(internal->dev)
free(internal->dev);
free(internal);
device->internal=NULL;
}