|
Packit |
c32a2d |
/*
|
|
Packit |
c32a2d |
sgi: audio output on SGI boxen
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
copyright ?-2013 by the mpg123 project - free software under the terms of the LGPL 2.1
|
|
Packit |
c32a2d |
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
|
Packit |
c32a2d |
initially written (as it seems) by Thomas Woerner
|
|
Packit |
c32a2d |
*/
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#include "out123_int.h"
|
|
Packit |
c32a2d |
#include <fcntl.h>
|
|
Packit |
c32a2d |
#include <dmedia/audio.h>
|
|
Packit |
c32a2d |
#include "errno.h"
|
|
Packit |
c32a2d |
#include "debug.h"
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static int set_rate(out123_handle *ao, ALconfig config)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
int dev = alGetDevice(config);
|
|
Packit |
c32a2d |
ALpv params[1];
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Make sure the device is OK */
|
|
Packit |
c32a2d |
if(dev < 0)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
error1("set_rate: %s", alGetErrorString(oserror()));
|
|
Packit |
c32a2d |
return -1;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
if(ao->rate > 0)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
params[0].param = AL_RATE;
|
|
Packit |
c32a2d |
params[0].value.ll = alDoubleToFixed((double)ao->rate);
|
|
Packit |
c32a2d |
if(alSetParams(dev, params, 1) < 0)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
error1("set_rate: %s", alGetErrorString(oserror()));
|
|
Packit |
c32a2d |
return -1;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
return 0;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static int set_channels(out123_handle *ao, ALconfig config)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
int ret;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if(ao->channels == 2)
|
|
Packit |
c32a2d |
ret = alSetChannels(config, AL_STEREO);
|
|
Packit |
c32a2d |
else
|
|
Packit |
c32a2d |
ret = alSetChannels(config, AL_MONO);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if(ret < 0)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
error1("set_channels : %s", alGetErrorString(oserror()));
|
|
Packit |
c32a2d |
return -1;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
return 0;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static int set_format(out123_handle *ao, ALconfig config)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(ao->format == MPG123_ENC_FLOAT_32)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(alSetSampFmt(config, AL_SAMPFMT_FLOAT) < 0)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
error1("SetSampFmt: %s", alGetErrorString(oserror()));
|
|
Packit |
c32a2d |
return -1;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
} else
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(alSetSampFmt(config, AL_SAMPFMT_TWOSCOMP) < 0)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
error1("SetSampFmt: %s", alGetErrorString(oserror()));
|
|
Packit |
c32a2d |
return -1;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
if(alSetWidth(config, AL_SAMPLE_16) < 0)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
error1("SetWidth: %s", alGetErrorString(oserror()));
|
|
Packit |
c32a2d |
return -1;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
return 0;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static int open_sgi(out123_handle *ao)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
int current_dev;
|
|
Packit |
c32a2d |
ALport port = NULL;
|
|
Packit |
c32a2d |
ALconfig config = alNewConfig();
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
ao->userptr = NULL;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Test for correct completion */
|
|
Packit |
c32a2d |
if(config == 0)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
error1("open_sgi: %s", alGetErrorString(oserror()));
|
|
Packit |
c32a2d |
return -1;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Setup output device to specified device name. If there is no device name
|
|
Packit |
c32a2d |
specified in ao structure, use the default for output */
|
|
Packit |
c32a2d |
if((ao->device) != NULL)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
current_dev = alGetResourceByName(AL_SYSTEM, ao->device, AL_OUTPUT_DEVICE_TYPE);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
debug2("Dev: %s %i", ao->device, current_dev);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if(!current_dev)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
int i, numOut;
|
|
Packit |
c32a2d |
char devname[32];
|
|
Packit |
c32a2d |
ALpv pv[1];
|
|
Packit |
c32a2d |
ALvalue *alvalues;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
error2("Invalid audio resource: %s (%s)", ao->device, alGetErrorString(oserror()));
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if((numOut= alQueryValues(AL_SYSTEM,AL_DEFAULT_OUTPUT,0,0,0,0))>=0)
|
|
Packit |
c32a2d |
fprintf(stderr, "There are %d output devices on this system.\n", numOut);
|
|
Packit |
c32a2d |
else
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
fprintf(stderr, "Can't find output devices. alQueryValues failed: %s\n", alGetErrorString(oserror()));
|
|
Packit |
c32a2d |
goto open_sgi_bad;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
alvalues = malloc(sizeof(ALvalue) * numOut);
|
|
Packit |
c32a2d |
i = alQueryValues(AL_SYSTEM, AL_DEFAULT_OUTPUT, alvalues, numOut, pv, 0);
|
|
Packit |
c32a2d |
if(i == -1)
|
|
Packit |
c32a2d |
error1("alQueryValues: %s", alGetErrorString(oserror()));
|
|
Packit |
c32a2d |
else
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
for(i=0; i < numOut; i++)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
pv[0].param = AL_NAME;
|
|
Packit |
c32a2d |
pv[0].value.ptr = devname;
|
|
Packit |
c32a2d |
pv[0].sizeIn = 32;
|
|
Packit |
c32a2d |
alGetParams(alvalues[i].i, pv, 1);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
fprintf(stderr, "%i: %s\n", i, devname);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
free(alvalues);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
goto open_sgi_bad;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if(alSetDevice(config, current_dev) < 0)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
error1("open: alSetDevice : %s",alGetErrorString(oserror()));
|
|
Packit |
c32a2d |
goto open_sgi_bad;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
} else
|
|
Packit |
c32a2d |
current_dev = AL_DEFAULT_OUTPUT;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Set the device */
|
|
Packit |
c32a2d |
if(alSetDevice(config, current_dev) < 0)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
error1("open_sgi: %s", alGetErrorString(oserror()));
|
|
Packit |
c32a2d |
goto open_sgi_bad;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Set port parameters */
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if(alSetQueueSize(config, 131069) < 0)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
error1("open_sgi: setting audio buffer failed: %s", alGetErrorString(oserror()));
|
|
Packit |
c32a2d |
goto open_sgi_bad;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if( set_format(ao, config) < 0
|
|
Packit |
c32a2d |
|| set_rate(ao, config) < 0
|
|
Packit |
c32a2d |
|| set_channels(ao, config) < 0 )
|
|
Packit |
c32a2d |
goto open_sgi_bad;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Open the audio port */
|
|
Packit |
c32a2d |
port = alOpenPort("mpg123-VSC", "w", config);
|
|
Packit |
c32a2d |
if(port == NULL)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
error1("Unable to open audio channel: %s", alGetErrorString(oserror()));
|
|
Packit |
c32a2d |
goto open_sgi_bad;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
ao->userptr = (void*)port;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
alFreeConfig(config);
|
|
Packit |
c32a2d |
return 1;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
open_sgi_bad:
|
|
Packit |
c32a2d |
/* clean up and return error */
|
|
Packit |
c32a2d |
alFreeConfig(config);
|
|
Packit |
c32a2d |
return -1;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static int get_formats_sgi(out123_handle *ao)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
return MPG123_ENC_SIGNED_16|MPG123_ENC_FLOAT_32;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static int write_sgi(out123_handle *ao, unsigned char *buf, int len)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
int length = len;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if(!ao || !ao->userptr) return -1;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
ALport port = (ALport)ao->userptr;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if(ao->channels == 2) length >>= 2;
|
|
Packit |
c32a2d |
else length >>= 1;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if(ao->format == MPG123_ENC_FLOAT_32) length >>=1;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Not much error checking ... */
|
|
Packit |
c32a2d |
alWriteFrames(port, buf, length);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
return len;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static int close_sgi(out123_handle *ao)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(!ao || !ao->userptr) return -1;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
ALport port = (ALport)ao->userptr;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if(port)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
/* play all remaining samples */
|
|
Packit |
c32a2d |
while(alGetFilled(port) > 0) sginap(1);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
alClosePort(port);
|
|
Packit |
c32a2d |
ao->userptr=NULL;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
return 0;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static void flush_sgi(out123_handle *ao)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
ALport port = (ALport)ao->userptr;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if(port) alDiscardFrames(port, alGetFilled(port));
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static int init_sgi(out123_handle* ao)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(ao == NULL) return -1;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Set callbacks */
|
|
Packit |
c32a2d |
ao->open = open_sgi;
|
|
Packit |
c32a2d |
ao->flush = flush_sgi;
|
|
Packit |
c32a2d |
ao->write = write_sgi;
|
|
Packit |
c32a2d |
ao->get_formats = get_formats_sgi;
|
|
Packit |
c32a2d |
ao->close = close_sgi;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Success */
|
|
Packit |
c32a2d |
return 0;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/*
|
|
Packit |
c32a2d |
Module information data structure
|
|
Packit |
c32a2d |
*/
|
|
Packit |
c32a2d |
mpg123_module_t mpg123_output_module_info =
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
/* api_version */ MPG123_MODULE_API_VERSION,
|
|
Packit |
c32a2d |
/* name */ "sgi",
|
|
Packit |
c32a2d |
/* description */ "Audio output for SGI.",
|
|
Packit |
c32a2d |
/* revision */ "$Rev:$",
|
|
Packit |
c32a2d |
/* handle */ NULL,
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* init_output */ init_sgi,
|
|
Packit |
c32a2d |
};
|