More possible fixes for mesa-buffer mode.
[mplayer/glamo.git] / libao2 / ao_sgi.c
blob1ca52ee8e4a72264a0e41c5604e41c40b6afdd71
1 /*
2 ao_sgi - sgi/irix output plugin for MPlayer
4 22oct2001 oliver.schoenbrunner@jku.at
6 */
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <errno.h>
12 #include <dmedia/audio.h>
14 #include "audio_out.h"
15 #include "audio_out_internal.h"
16 #include "mp_msg.h"
17 #include "help_mp.h"
18 #include "libaf/af_format.h"
20 static ao_info_t info =
22 "sgi audio output",
23 "sgi",
24 "Oliver Schoenbrunner",
28 LIBAO_EXTERN(sgi)
31 static ALconfig ao_config;
32 static ALport ao_port;
33 static int sample_rate;
34 static int queue_size;
35 static int bytes_per_frame;
37 /**
38 * \param [in/out] format
39 * \param [out] width
41 * \return the closest matching SGI AL sample format
43 * \note width is set to required per-channel sample width
44 * format is updated to match the SGI AL sample format
46 static int fmt2sgial(int *format, int *width) {
47 int smpfmt = AL_SAMPFMT_TWOSCOMP;
49 /* SGI AL only supports float and signed integers in native
50 * endianness. If this is something else, we must rely on the audio
51 * filter to convert it to a compatible format. */
53 /* 24-bit audio is supported, but only with 32-bit alignment.
54 * mplayer's 24-bit format is packed, unfortunately.
55 * So we must upgrade 24-bit requests to 32 bits. Then we drop the
56 * lowest 8 bits during playback. */
58 switch(*format) {
59 case AF_FORMAT_U8:
60 case AF_FORMAT_S8:
61 *width = AL_SAMPLE_8;
62 *format = AF_FORMAT_S8;
63 break;
65 case AF_FORMAT_U16_LE:
66 case AF_FORMAT_U16_BE:
67 case AF_FORMAT_S16_LE:
68 case AF_FORMAT_S16_BE:
69 *width = AL_SAMPLE_16;
70 *format = AF_FORMAT_S16_NE;
71 break;
73 case AF_FORMAT_U24_LE:
74 case AF_FORMAT_U24_BE:
75 case AF_FORMAT_S24_LE:
76 case AF_FORMAT_S24_BE:
77 case AF_FORMAT_U32_LE:
78 case AF_FORMAT_U32_BE:
79 case AF_FORMAT_S32_LE:
80 case AF_FORMAT_S32_BE:
81 *width = AL_SAMPLE_24;
82 *format = AF_FORMAT_S32_NE;
83 break;
85 case AF_FORMAT_FLOAT_LE:
86 case AF_FORMAT_FLOAT_BE:
87 *width = 4;
88 *format = AF_FORMAT_FLOAT_NE;
89 smpfmt = AL_SAMPFMT_FLOAT;
90 break;
92 default:
93 *width = AL_SAMPLE_16;
94 *format = AF_FORMAT_S16_NE;
95 break;
99 return smpfmt;
102 // to set/get/query special features/parameters
103 static int control(int cmd, void *arg){
105 mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_SGI_INFO);
107 switch(cmd) {
108 case AOCONTROL_QUERY_FORMAT:
109 /* Do not reject any format: return the closest matching
110 * format if the request is not supported natively. */
111 return CONTROL_TRUE;
114 return CONTROL_UNKNOWN;
117 // open & setup audio device
118 // return: 1=success 0=fail
119 static int init(int rate, int channels, int format, int flags) {
121 int smpwidth, smpfmt;
122 int rv = AL_DEFAULT_OUTPUT;
124 smpfmt = fmt2sgial(&format, &smpwidth);
126 mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_SGI_InitInfo, rate, (channels > 1) ? "Stereo" : "Mono", af_fmt2str_short(format));
128 { /* from /usr/share/src/dmedia/audio/setrate.c */
130 double frate, realrate;
131 ALpv x[2];
133 if(ao_subdevice) {
134 rv = alGetResourceByName(AL_SYSTEM, ao_subdevice, AL_OUTPUT_DEVICE_TYPE);
135 if (!rv) {
136 mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_SGI_InvalidDevice);
137 return 0;
141 frate = rate;
143 x[0].param = AL_RATE;
144 x[0].value.ll = alDoubleToFixed(rate);
145 x[1].param = AL_MASTER_CLOCK;
146 x[1].value.i = AL_CRYSTAL_MCLK_TYPE;
148 if (alSetParams(rv,x, 2)<0) {
149 mp_msg(MSGT_AO, MSGL_WARN, MSGTR_AO_SGI_CantSetParms_Samplerate, alGetErrorString(oserror()));
152 if (x[0].sizeOut < 0) {
153 mp_msg(MSGT_AO, MSGL_WARN, MSGTR_AO_SGI_CantSetAlRate);
156 if (alGetParams(rv,x, 1)<0) {
157 mp_msg(MSGT_AO, MSGL_WARN, MSGTR_AO_SGI_CantGetParms, alGetErrorString(oserror()));
160 realrate = alFixedToDouble(x[0].value.ll);
161 if (frate != realrate) {
162 mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_SGI_SampleRateInfo, realrate, frate);
164 sample_rate = (int)realrate;
167 bytes_per_frame = channels * smpwidth;
169 ao_data.samplerate = sample_rate;
170 ao_data.channels = channels;
171 ao_data.format = format;
172 ao_data.bps = sample_rate * bytes_per_frame;
173 ao_data.buffersize=131072;
174 ao_data.outburst = ao_data.buffersize/16;
176 ao_config = alNewConfig();
178 if (!ao_config) {
179 mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_SGI_InitConfigError, alGetErrorString(oserror()));
180 return 0;
183 if(alSetChannels(ao_config, channels) < 0 ||
184 alSetWidth(ao_config, smpwidth) < 0 ||
185 alSetSampFmt(ao_config, smpfmt) < 0 ||
186 alSetQueueSize(ao_config, sample_rate) < 0 ||
187 alSetDevice(ao_config, rv) < 0) {
188 mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_SGI_InitConfigError, alGetErrorString(oserror()));
189 return 0;
192 ao_port = alOpenPort("mplayer", "w", ao_config);
194 if (!ao_port) {
195 mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_SGI_InitOpenAudioFailed, alGetErrorString(oserror()));
196 return 0;
199 // printf("ao_sgi, init: port %d config %d\n", ao_port, ao_config);
200 queue_size = alGetQueueSize(ao_config);
201 return 1;
205 // close audio device
206 static void uninit(int immed) {
208 /* TODO: samplerate should be set back to the value before mplayer was started! */
210 mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_SGI_Uninit);
212 if (ao_config) {
213 alFreeConfig(ao_config);
214 ao_config = NULL;
217 if (ao_port) {
218 if (!immed)
219 while(alGetFilled(ao_port) > 0) sginap(1);
220 alClosePort(ao_port);
221 ao_port = NULL;
226 // stop playing and empty buffers (for seeking/pause)
227 static void reset(void) {
229 mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_SGI_Reset);
231 alDiscardFrames(ao_port, queue_size);
234 // stop playing, keep buffers (for pause)
235 static void audio_pause(void) {
237 mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_SGI_PauseInfo);
241 // resume playing, after audio_pause()
242 static void audio_resume(void) {
244 mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_SGI_ResumeInfo);
248 // return: how many bytes can be played without blocking
249 static int get_space(void) {
251 // printf("ao_sgi, get_space: (ao_outburst %d)\n", ao_data.outburst);
252 // printf("ao_sgi, get_space: alGetFillable [%d] \n", alGetFillable(ao_port));
254 return alGetFillable(ao_port) * bytes_per_frame;
259 // plays 'len' bytes of 'data'
260 // it should round it down to outburst*n
261 // return: number of bytes played
262 static int play(void* data, int len, int flags) {
264 /* Always process data in quadword-aligned chunks (64-bits). */
265 const int plen = len / (sizeof(uint64_t) * bytes_per_frame);
266 const int framecount = plen * sizeof(uint64_t);
268 // printf("ao_sgi, play: len %d flags %d (%d %d)\n", len, flags, ao_port, ao_config);
269 // printf("channels %d\n", ao_data.channels);
271 if(ao_data.format == AF_FORMAT_S32_NE) {
272 /* The zen of this is explained in fmt2sgial() */
273 int32_t *smpls = data;
274 const int32_t *smple = smpls + (framecount * ao_data.channels);
275 while(smpls < smple)
276 *smpls++ >>= 8;
279 alWriteFrames(ao_port, data, framecount);
281 return framecount * bytes_per_frame;
285 // return: delay in seconds between first and last sample in buffer
286 static float get_delay(void){
288 // printf("ao_sgi, get_delay: (ao_buffersize %d)\n", ao_buffersize);
290 // return (float)queue_size/((float)sample_rate);
291 const int outstanding = alGetFilled(ao_port);
292 return (float)((outstanding < 0) ? queue_size : outstanding) /
293 ((float)sample_rate);