Merge svn changes up to r30502
[mplayer/kovensky.git] / libao2 / ao_sgi.c
blob0973f302ab33a005ae50931eff6d16f160cf53e9
1 /*
2 * SGI/IRIX audio output driver
4 * copyright (c) 2001 oliver.schoenbrunner@jku.at
6 * This file is part of MPlayer.
8 * MPlayer is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * MPlayer is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <errno.h>
27 #include <dmedia/audio.h>
29 #include "audio_out.h"
30 #include "audio_out_internal.h"
31 #include "mp_msg.h"
32 #include "help_mp.h"
33 #include "libaf/af_format.h"
35 static const ao_info_t info =
37 "sgi audio output",
38 "sgi",
39 "Oliver Schoenbrunner",
43 LIBAO_EXTERN(sgi)
46 static ALconfig ao_config;
47 static ALport ao_port;
48 static int sample_rate;
49 static int queue_size;
50 static int bytes_per_frame;
52 /**
53 * \param [in/out] format
54 * \param [out] width
56 * \return the closest matching SGI AL sample format
58 * \note width is set to required per-channel sample width
59 * format is updated to match the SGI AL sample format
61 static int fmt2sgial(int *format, int *width) {
62 int smpfmt = AL_SAMPFMT_TWOSCOMP;
64 /* SGI AL only supports float and signed integers in native
65 * endianness. If this is something else, we must rely on the audio
66 * filter to convert it to a compatible format. */
68 /* 24-bit audio is supported, but only with 32-bit alignment.
69 * mplayer's 24-bit format is packed, unfortunately.
70 * So we must upgrade 24-bit requests to 32 bits. Then we drop the
71 * lowest 8 bits during playback. */
73 switch(*format) {
74 case AF_FORMAT_U8:
75 case AF_FORMAT_S8:
76 *width = AL_SAMPLE_8;
77 *format = AF_FORMAT_S8;
78 break;
80 case AF_FORMAT_U16_LE:
81 case AF_FORMAT_U16_BE:
82 case AF_FORMAT_S16_LE:
83 case AF_FORMAT_S16_BE:
84 *width = AL_SAMPLE_16;
85 *format = AF_FORMAT_S16_NE;
86 break;
88 case AF_FORMAT_U24_LE:
89 case AF_FORMAT_U24_BE:
90 case AF_FORMAT_S24_LE:
91 case AF_FORMAT_S24_BE:
92 case AF_FORMAT_U32_LE:
93 case AF_FORMAT_U32_BE:
94 case AF_FORMAT_S32_LE:
95 case AF_FORMAT_S32_BE:
96 *width = AL_SAMPLE_24;
97 *format = AF_FORMAT_S32_NE;
98 break;
100 case AF_FORMAT_FLOAT_LE:
101 case AF_FORMAT_FLOAT_BE:
102 *width = 4;
103 *format = AF_FORMAT_FLOAT_NE;
104 smpfmt = AL_SAMPFMT_FLOAT;
105 break;
107 default:
108 *width = AL_SAMPLE_16;
109 *format = AF_FORMAT_S16_NE;
110 break;
114 return smpfmt;
117 // to set/get/query special features/parameters
118 static int control(int cmd, void *arg){
120 mp_tmsg(MSGT_AO, MSGL_INFO, "[AO SGI] control.\n");
122 switch(cmd) {
123 case AOCONTROL_QUERY_FORMAT:
124 /* Do not reject any format: return the closest matching
125 * format if the request is not supported natively. */
126 return CONTROL_TRUE;
129 return CONTROL_UNKNOWN;
132 // open & setup audio device
133 // return: 1=success 0=fail
134 static int init(int rate, int channels, int format, int flags) {
136 int smpwidth, smpfmt;
137 int rv = AL_DEFAULT_OUTPUT;
139 smpfmt = fmt2sgial(&format, &smpwidth);
141 mp_tmsg(MSGT_AO, MSGL_INFO, "[AO SGI] init: Samplerate: %iHz Channels: %s Format %s\n", rate, (channels > 1) ? "Stereo" : "Mono", af_fmt2str_short(format));
143 { /* from /usr/share/src/dmedia/audio/setrate.c */
145 double frate, realrate;
146 ALpv x[2];
148 if(ao_subdevice) {
149 rv = alGetResourceByName(AL_SYSTEM, ao_subdevice, AL_OUTPUT_DEVICE_TYPE);
150 if (!rv) {
151 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO SGI] play: invalid device.\n");
152 return 0;
156 frate = rate;
158 x[0].param = AL_RATE;
159 x[0].value.ll = alDoubleToFixed(rate);
160 x[1].param = AL_MASTER_CLOCK;
161 x[1].value.i = AL_CRYSTAL_MCLK_TYPE;
163 if (alSetParams(rv,x, 2)<0) {
164 mp_tmsg(MSGT_AO, MSGL_WARN, "[AO SGI] init: setparams failed: %s\nCould not set desired samplerate.\n", alGetErrorString(oserror()));
167 if (x[0].sizeOut < 0) {
168 mp_tmsg(MSGT_AO, MSGL_WARN, "[AO SGI] init: AL_RATE was not accepted on the given resource.\n");
171 if (alGetParams(rv,x, 1)<0) {
172 mp_tmsg(MSGT_AO, MSGL_WARN, "[AO SGI] init: getparams failed: %s\n", alGetErrorString(oserror()));
175 realrate = alFixedToDouble(x[0].value.ll);
176 if (frate != realrate) {
177 mp_tmsg(MSGT_AO, MSGL_INFO, "[AO SGI] init: samplerate is now %f (desired rate is %f)\n", realrate, frate);
179 sample_rate = (int)realrate;
182 bytes_per_frame = channels * smpwidth;
184 ao_data.samplerate = sample_rate;
185 ao_data.channels = channels;
186 ao_data.format = format;
187 ao_data.bps = sample_rate * bytes_per_frame;
188 ao_data.buffersize=131072;
189 ao_data.outburst = ao_data.buffersize/16;
191 ao_config = alNewConfig();
193 if (!ao_config) {
194 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO SGI] init: %s\n", alGetErrorString(oserror()));
195 return 0;
198 if(alSetChannels(ao_config, channels) < 0 ||
199 alSetWidth(ao_config, smpwidth) < 0 ||
200 alSetSampFmt(ao_config, smpfmt) < 0 ||
201 alSetQueueSize(ao_config, sample_rate) < 0 ||
202 alSetDevice(ao_config, rv) < 0) {
203 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO SGI] init: %s\n", alGetErrorString(oserror()));
204 return 0;
207 ao_port = alOpenPort("mplayer", "w", ao_config);
209 if (!ao_port) {
210 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO SGI] init: Unable to open audio channel: %s\n", alGetErrorString(oserror()));
211 return 0;
214 // printf("ao_sgi, init: port %d config %d\n", ao_port, ao_config);
215 queue_size = alGetQueueSize(ao_config);
216 return 1;
220 // close audio device
221 static void uninit(int immed) {
223 /* TODO: samplerate should be set back to the value before mplayer was started! */
225 mp_tmsg(MSGT_AO, MSGL_INFO, "[AO SGI] uninit: ...\n");
227 if (ao_config) {
228 alFreeConfig(ao_config);
229 ao_config = NULL;
232 if (ao_port) {
233 if (!immed)
234 while(alGetFilled(ao_port) > 0) sginap(1);
235 alClosePort(ao_port);
236 ao_port = NULL;
241 // stop playing and empty buffers (for seeking/pause)
242 static void reset(void) {
244 mp_tmsg(MSGT_AO, MSGL_INFO, "[AO SGI] reset: ...\n");
246 alDiscardFrames(ao_port, queue_size);
249 // stop playing, keep buffers (for pause)
250 static void audio_pause(void) {
252 mp_tmsg(MSGT_AO, MSGL_INFO, "[AO SGI] audio_pause: ...\n");
256 // resume playing, after audio_pause()
257 static void audio_resume(void) {
259 mp_tmsg(MSGT_AO, MSGL_INFO, "[AO SGI] audio_resume: ...\n");
263 // return: how many bytes can be played without blocking
264 static int get_space(void) {
266 // printf("ao_sgi, get_space: (ao_outburst %d)\n", ao_data.outburst);
267 // printf("ao_sgi, get_space: alGetFillable [%d] \n", alGetFillable(ao_port));
269 return alGetFillable(ao_port) * bytes_per_frame;
274 // plays 'len' bytes of 'data'
275 // it should round it down to outburst*n
276 // return: number of bytes played
277 static int play(void* data, int len, int flags) {
279 /* Always process data in quadword-aligned chunks (64-bits). */
280 const int plen = len / (sizeof(uint64_t) * bytes_per_frame);
281 const int framecount = plen * sizeof(uint64_t);
283 // printf("ao_sgi, play: len %d flags %d (%d %d)\n", len, flags, ao_port, ao_config);
284 // printf("channels %d\n", ao_data.channels);
286 if(ao_data.format == AF_FORMAT_S32_NE) {
287 /* The zen of this is explained in fmt2sgial() */
288 int32_t *smpls = data;
289 const int32_t *smple = smpls + (framecount * ao_data.channels);
290 while(smpls < smple)
291 *smpls++ >>= 8;
294 alWriteFrames(ao_port, data, framecount);
296 return framecount * bytes_per_frame;
300 // return: delay in seconds between first and last sample in buffer
301 static float get_delay(void){
303 // printf("ao_sgi, get_delay: (ao_buffersize %d)\n", ao_buffersize);
305 // return (float)queue_size/((float)sample_rate);
306 const int outstanding = alGetFilled(ao_port);
307 return (float)((outstanding < 0) ? queue_size : outstanding) /
308 ((float)sample_rate);