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.
27 #include <dmedia/audio.h>
29 #include "audio_out.h"
30 #include "audio_out_internal.h"
32 #include "libaf/af_format.h"
34 static const ao_info_t info
=
38 "Oliver Schoenbrunner",
45 static ALconfig ao_config
;
46 static ALport ao_port
;
47 static int sample_rate
;
48 static int queue_size
;
49 static int bytes_per_frame
;
52 * \param [in/out] format
55 * \return the closest matching SGI AL sample format
57 * \note width is set to required per-channel sample width
58 * format is updated to match the SGI AL sample format
60 static int fmt2sgial(int *format
, int *width
) {
61 int smpfmt
= AL_SAMPFMT_TWOSCOMP
;
63 /* SGI AL only supports float and signed integers in native
64 * endianness. If this is something else, we must rely on the audio
65 * filter to convert it to a compatible format. */
67 /* 24-bit audio is supported, but only with 32-bit alignment.
68 * mplayer's 24-bit format is packed, unfortunately.
69 * So we must upgrade 24-bit requests to 32 bits. Then we drop the
70 * lowest 8 bits during playback. */
76 *format
= AF_FORMAT_S8
;
79 case AF_FORMAT_U16_LE
:
80 case AF_FORMAT_U16_BE
:
81 case AF_FORMAT_S16_LE
:
82 case AF_FORMAT_S16_BE
:
83 *width
= AL_SAMPLE_16
;
84 *format
= AF_FORMAT_S16_NE
;
87 case AF_FORMAT_U24_LE
:
88 case AF_FORMAT_U24_BE
:
89 case AF_FORMAT_S24_LE
:
90 case AF_FORMAT_S24_BE
:
91 case AF_FORMAT_U32_LE
:
92 case AF_FORMAT_U32_BE
:
93 case AF_FORMAT_S32_LE
:
94 case AF_FORMAT_S32_BE
:
95 *width
= AL_SAMPLE_24
;
96 *format
= AF_FORMAT_S32_NE
;
99 case AF_FORMAT_FLOAT_LE
:
100 case AF_FORMAT_FLOAT_BE
:
102 *format
= AF_FORMAT_FLOAT_NE
;
103 smpfmt
= AL_SAMPFMT_FLOAT
;
107 *width
= AL_SAMPLE_16
;
108 *format
= AF_FORMAT_S16_NE
;
116 // to set/get/query special features/parameters
117 static int control(int cmd
, void *arg
){
119 mp_tmsg(MSGT_AO
, MSGL_INFO
, "[AO SGI] control.\n");
122 case AOCONTROL_QUERY_FORMAT
:
123 /* Do not reject any format: return the closest matching
124 * format if the request is not supported natively. */
128 return CONTROL_UNKNOWN
;
131 // open & setup audio device
132 // return: 1=success 0=fail
133 static int init(int rate
, int channels
, int format
, int flags
) {
135 int smpwidth
, smpfmt
;
136 int rv
= AL_DEFAULT_OUTPUT
;
138 smpfmt
= fmt2sgial(&format
, &smpwidth
);
140 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
));
142 { /* from /usr/share/src/dmedia/audio/setrate.c */
144 double frate
, realrate
;
148 rv
= alGetResourceByName(AL_SYSTEM
, ao_subdevice
, AL_OUTPUT_DEVICE_TYPE
);
150 mp_tmsg(MSGT_AO
, MSGL_ERR
, "[AO SGI] play: invalid device.\n");
157 x
[0].param
= AL_RATE
;
158 x
[0].value
.ll
= alDoubleToFixed(rate
);
159 x
[1].param
= AL_MASTER_CLOCK
;
160 x
[1].value
.i
= AL_CRYSTAL_MCLK_TYPE
;
162 if (alSetParams(rv
,x
, 2)<0) {
163 mp_tmsg(MSGT_AO
, MSGL_WARN
, "[AO SGI] init: setparams failed: %s\nCould not set desired samplerate.\n", alGetErrorString(oserror()));
166 if (x
[0].sizeOut
< 0) {
167 mp_tmsg(MSGT_AO
, MSGL_WARN
, "[AO SGI] init: AL_RATE was not accepted on the given resource.\n");
170 if (alGetParams(rv
,x
, 1)<0) {
171 mp_tmsg(MSGT_AO
, MSGL_WARN
, "[AO SGI] init: getparams failed: %s\n", alGetErrorString(oserror()));
174 realrate
= alFixedToDouble(x
[0].value
.ll
);
175 if (frate
!= realrate
) {
176 mp_tmsg(MSGT_AO
, MSGL_INFO
, "[AO SGI] init: samplerate is now %f (desired rate is %f)\n", realrate
, frate
);
178 sample_rate
= (int)realrate
;
181 bytes_per_frame
= channels
* smpwidth
;
183 ao_data
.samplerate
= sample_rate
;
184 ao_data
.channels
= channels
;
185 ao_data
.format
= format
;
186 ao_data
.bps
= sample_rate
* bytes_per_frame
;
187 ao_data
.buffersize
=131072;
188 ao_data
.outburst
= ao_data
.buffersize
/16;
190 ao_config
= alNewConfig();
193 mp_tmsg(MSGT_AO
, MSGL_ERR
, "[AO SGI] init: %s\n", alGetErrorString(oserror()));
197 if(alSetChannels(ao_config
, channels
) < 0 ||
198 alSetWidth(ao_config
, smpwidth
) < 0 ||
199 alSetSampFmt(ao_config
, smpfmt
) < 0 ||
200 alSetQueueSize(ao_config
, sample_rate
) < 0 ||
201 alSetDevice(ao_config
, rv
) < 0) {
202 mp_tmsg(MSGT_AO
, MSGL_ERR
, "[AO SGI] init: %s\n", alGetErrorString(oserror()));
206 ao_port
= alOpenPort("mplayer", "w", ao_config
);
209 mp_tmsg(MSGT_AO
, MSGL_ERR
, "[AO SGI] init: Unable to open audio channel: %s\n", alGetErrorString(oserror()));
213 // printf("ao_sgi, init: port %d config %d\n", ao_port, ao_config);
214 queue_size
= alGetQueueSize(ao_config
);
219 // close audio device
220 static void uninit(int immed
) {
222 /* TODO: samplerate should be set back to the value before mplayer was started! */
224 mp_tmsg(MSGT_AO
, MSGL_INFO
, "[AO SGI] uninit: ...\n");
227 alFreeConfig(ao_config
);
233 while(alGetFilled(ao_port
) > 0) sginap(1);
234 alClosePort(ao_port
);
240 // stop playing and empty buffers (for seeking/pause)
241 static void reset(void) {
243 mp_tmsg(MSGT_AO
, MSGL_INFO
, "[AO SGI] reset: ...\n");
245 alDiscardFrames(ao_port
, queue_size
);
248 // stop playing, keep buffers (for pause)
249 static void audio_pause(void) {
251 mp_tmsg(MSGT_AO
, MSGL_INFO
, "[AO SGI] audio_pause: ...\n");
255 // resume playing, after audio_pause()
256 static void audio_resume(void) {
258 mp_tmsg(MSGT_AO
, MSGL_INFO
, "[AO SGI] audio_resume: ...\n");
262 // return: how many bytes can be played without blocking
263 static int get_space(void) {
265 // printf("ao_sgi, get_space: (ao_outburst %d)\n", ao_data.outburst);
266 // printf("ao_sgi, get_space: alGetFillable [%d] \n", alGetFillable(ao_port));
268 return alGetFillable(ao_port
) * bytes_per_frame
;
273 // plays 'len' bytes of 'data'
274 // it should round it down to outburst*n
275 // return: number of bytes played
276 static int play(void* data
, int len
, int flags
) {
278 /* Always process data in quadword-aligned chunks (64-bits). */
279 const int plen
= len
/ (sizeof(uint64_t) * bytes_per_frame
);
280 const int framecount
= plen
* sizeof(uint64_t);
282 // printf("ao_sgi, play: len %d flags %d (%d %d)\n", len, flags, ao_port, ao_config);
283 // printf("channels %d\n", ao_data.channels);
285 if(ao_data
.format
== AF_FORMAT_S32_NE
) {
286 /* The zen of this is explained in fmt2sgial() */
287 int32_t *smpls
= data
;
288 const int32_t *smple
= smpls
+ (framecount
* ao_data
.channels
);
293 alWriteFrames(ao_port
, data
, framecount
);
295 return framecount
* bytes_per_frame
;
299 // return: delay in seconds between first and last sample in buffer
300 static float get_delay(void){
302 // printf("ao_sgi, get_delay: (ao_buffersize %d)\n", ao_buffersize);
304 // return (float)queue_size/((float)sample_rate);
305 const int outstanding
= alGetFilled(ao_port
);
306 return (float)((outstanding
< 0) ? queue_size
: outstanding
) /
307 ((float)sample_rate
);