summaryrefslogtreecommitdiffstats
path: root/libao2/ao_sgi.c
diff options
context:
space:
mode:
authorreimar <reimar@b3059339-0415-0410-9bf9-f77b7e298cf2>2005-10-04 22:23:51 +0000
committerreimar <reimar@b3059339-0415-0410-9bf9-f77b7e298cf2>2005-10-04 22:23:51 +0000
commit42f543639619ab039645f1ade9f54cf3c755e902 (patch)
tree38b3b13231673f1a57f16b050a242bb2a40fc605 /libao2/ao_sgi.c
parent1e4a90cd2be1325218d91824fb6f96687f69dfec (diff)
downloadmpv-42f543639619ab039645f1ade9f54cf3c755e902.tar.bz2
mpv-42f543639619ab039645f1ade9f54cf3c755e902.tar.xz
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
Diffstat (limited to 'libao2/ao_sgi.c')
-rw-r--r--libao2/ao_sgi.c162
1 files changed, 133 insertions, 29 deletions
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 <stdio.h>
#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
#include <dmedia/audio.h>
#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);
}