From 42f543639619ab039645f1ade9f54cf3c755e902 Mon Sep 17 00:00:00 2001 From: reimar Date: Tue, 4 Oct 2005 22:23:51 +0000 Subject: General bug fixes, like missing includes, formats that were incorrectly claimed to be supported etc. Patch by dega (dega quickclic net) git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@16668 b3059339-0415-0410-9bf9-f77b7e298cf2 --- libao2/ao_sgi.c | 162 ++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 133 insertions(+), 29 deletions(-) (limited to 'libao2/ao_sgi.c') diff --git a/libao2/ao_sgi.c b/libao2/ao_sgi.c index e41e77f2b0..e7ef5c675d 100644 --- a/libao2/ao_sgi.c +++ b/libao2/ao_sgi.c @@ -7,12 +7,15 @@ #include #include +#include +#include #include #include "audio_out.h" #include "audio_out_internal.h" #include "mp_msg.h" #include "help_mp.h" +#include "libaf/af_format.h" static ao_info_t info = { @@ -29,32 +32,110 @@ static ALconfig ao_config; static ALport ao_port; static int sample_rate; static int queue_size; +static int bytes_per_frame; + +/** + * \param [in/out] format + * \param [out] width + * + * \return the closest matching SGI AL sample format + * + * \note width is set to required per-channel sample width + * format is updated to match the SGI AL sample format + */ +static int fmt2sgial(int *format, int *width) { + int smpfmt = AL_SAMPFMT_TWOSCOMP; + + /* SGI AL only supports float and signed integers in native + * endianess. If this is something else, we must rely on the audio + * filter to convert it to a compatible format. */ + + /* 24-bit audio is supported, but only with 32-bit alignment. + * mplayer's 24-bit format is packed, unfortunately. + * So we must upgrade 24-bit requests to 32 bits. Then we drop the + * lowest 8 bits during playback. */ + + switch(*format) { + case AF_FORMAT_U8: + case AF_FORMAT_S8: + *width = AL_SAMPLE_8; + *format = AF_FORMAT_S8; + break; + + case AF_FORMAT_U16_LE: + case AF_FORMAT_U16_BE: + case AF_FORMAT_S16_LE: + case AF_FORMAT_S16_BE: + *width = AL_SAMPLE_16; + *format = AF_FORMAT_S16_NE; + break; + + case AF_FORMAT_U24_LE: + case AF_FORMAT_U24_BE: + case AF_FORMAT_S24_LE: + case AF_FORMAT_S24_BE: + case AF_FORMAT_U32_LE: + case AF_FORMAT_U32_BE: + case AF_FORMAT_S32_LE: + case AF_FORMAT_S32_BE: + *width = AL_SAMPLE_24; + *format = AF_FORMAT_S32_NE; + break; + + case AF_FORMAT_FLOAT_LE: + case AF_FORMAT_FLOAT_BE: + *width = 4; + *format = AF_FORMAT_FLOAT_NE; + smpfmt = AL_SAMPFMT_FLOAT; + break; + + default: + *width = AL_SAMPLE_16; + *format = AF_FORMAT_S16_NE; + break; + + } + + return smpfmt; +} // to set/get/query special features/parameters static int control(int cmd, void *arg){ mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_SGI_INFO); - return -1; + switch(cmd) { + case AOCONTROL_QUERY_FORMAT: + /* Do not reject any format: return the closest matching + * format if the request is not supported natively. */ + return CONTROL_TRUE; + } + + return CONTROL_UNKNOWN; } // open & setup audio device // return: 1=success 0=fail static int init(int rate, int channels, int format, int flags) { + int smpwidth, smpfmt; + int rv = AL_DEFAULT_OUTPUT; + + smpfmt = fmt2sgial(&format, &smpwidth); + mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_SGI_InitInfo, rate, (channels > 1) ? "Stereo" : "Mono", af_fmt2str_short(format)); { /* from /usr/share/src/dmedia/audio/setrate.c */ - int fd; - int rv; - double frate; + double frate, realrate; ALpv x[2]; - rv = alGetResourceByName(AL_SYSTEM, "out.analog", AL_DEVICE_TYPE); - if (!rv) { - mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_SGI_InvalidDevice); - return 0; + if(ao_subdevice) { + rv = alGetResourceByName(AL_SYSTEM, ao_subdevice, AL_OUTPUT_DEVICE_TYPE); + if (!rv) { + mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_SGI_InvalidDevice); + return 0; + } } frate = rate; @@ -76,15 +157,21 @@ static int init(int rate, int channels, int format, int flags) { mp_msg(MSGT_AO, MSGL_WARN, MSGTR_AO_SGI_CantGetParms, alGetErrorString(oserror())); } - if (frate != alFixedToDouble(x[0].value.ll)) { - mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_SGI_SampleRateInfo, alFixedToDouble(x[0].value.ll), frate); + realrate = alFixedToDouble(x[0].value.ll); + if (frate != realrate) { + mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_SGI_SampleRateInfo, realrate, frate); } - sample_rate = (int)frate; + sample_rate = (int)realrate; } + bytes_per_frame = channels * smpwidth; + + ao_data.samplerate = sample_rate; + ao_data.channels = channels; + ao_data.format = format; + ao_data.bps = sample_rate * bytes_per_frame; ao_data.buffersize=131072; ao_data.outburst = ao_data.buffersize/16; - ao_data.channels = channels; ao_config = alNewConfig(); @@ -93,14 +180,11 @@ static int init(int rate, int channels, int format, int flags) { return 0; } - if(channels == 2) alSetChannels(ao_config, AL_STEREO); - else alSetChannels(ao_config, AL_MONO); - - alSetWidth(ao_config, AL_SAMPLE_16); - alSetSampFmt(ao_config, AL_SAMPFMT_TWOSCOMP); - alSetQueueSize(ao_config, 48000); - - if (alSetDevice(ao_config, AL_DEFAULT_OUTPUT) < 0) { + if(alSetChannels(ao_config, channels) < 0 || + alSetWidth(ao_config, smpwidth) < 0 || + alSetSampFmt(ao_config, smpfmt) < 0 || + alSetQueueSize(ao_config, sample_rate) < 0 || + alSetDevice(ao_config, rv) < 0) { mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_SGI_InitConfigError, alGetErrorString(oserror())); return 0; } @@ -125,11 +209,16 @@ static void uninit(int immed) { mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_SGI_Uninit); + if (ao_config) { + alFreeConfig(ao_config); + ao_config = NULL; + } + if (ao_port) { if (!immed) while(alGetFilled(ao_port) > 0) sginap(1); alClosePort(ao_port); - alFreeConfig(ao_config); + ao_port = NULL; } } @@ -139,6 +228,7 @@ static void reset() { mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_SGI_Reset); + alDiscardFrames(ao_port, queue_size); } // stop playing, keep buffers (for pause) @@ -158,10 +248,10 @@ static void audio_resume() { // return: how many bytes can be played without blocking static int get_space() { - // printf("ao_sgi, get_space: (ao_outburst %d)\n", ao_outburst); + // printf("ao_sgi, get_space: (ao_outburst %d)\n", ao_data.outburst); // printf("ao_sgi, get_space: alGetFillable [%d] \n", alGetFillable(ao_port)); - return alGetFillable(ao_port)*(2*ao_data.channels); + return alGetFillable(ao_port) * bytes_per_frame; } @@ -171,12 +261,24 @@ static int get_space() { // return: number of bytes played static int play(void* data, int len, int flags) { + /* Always process data in quadword-aligned chunks (64-bits). */ + const int plen = len / (sizeof(uint64_t) * bytes_per_frame); + const int framecount = plen * sizeof(uint64_t); + // printf("ao_sgi, play: len %d flags %d (%d %d)\n", len, flags, ao_port, ao_config); - // printf("channels %d\n", ao_channels); + // printf("channels %d\n", ao_data.channels); + + if(ao_data.format == AF_FORMAT_S32_NE) { + /* The zen of this is explained in fmt2sgial() */ + int32_t *smpls = data; + const int32_t *smple = smpls + (framecount * ao_data.channels); + while(smpls < smple) + *smpls++ >>= 8; + } - alWriteFrames(ao_port, data, len/(2*ao_data.channels)); - - return len; + alWriteFrames(ao_port, data, framecount); + + return framecount * bytes_per_frame; } @@ -185,8 +287,10 @@ static float get_delay(){ // printf("ao_sgi, get_delay: (ao_buffersize %d)\n", ao_buffersize); - //return 0; - return (float)queue_size/((float)sample_rate); + // return (float)queue_size/((float)sample_rate); + const int outstanding = alGetFilled(ao_port); + return (float)((outstanding < 0) ? queue_size : outstanding) / + ((float)sample_rate); } -- cgit v1.2.3