2 ao_sgi - sgi/irix output plugin for MPlayer
4 22oct2001 oliver.schoenbrunner@jku.at
12 #include <dmedia/audio.h>
14 #include "audio_out.h"
15 #include "audio_out_internal.h"
18 #include "libaf/af_format.h"
20 static ao_info_t info
=
24 "Oliver Schoenbrunner",
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
;
38 * \param [in/out] format
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. */
62 *format
= AF_FORMAT_S8
;
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
;
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
;
85 case AF_FORMAT_FLOAT_LE
:
86 case AF_FORMAT_FLOAT_BE
:
88 *format
= AF_FORMAT_FLOAT_NE
;
89 smpfmt
= AL_SAMPFMT_FLOAT
;
93 *width
= AL_SAMPLE_16
;
94 *format
= AF_FORMAT_S16_NE
;
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
);
108 case AOCONTROL_QUERY_FORMAT
:
109 /* Do not reject any format: return the closest matching
110 * format if the request is not supported natively. */
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
;
134 rv
= alGetResourceByName(AL_SYSTEM
, ao_subdevice
, AL_OUTPUT_DEVICE_TYPE
);
136 mp_msg(MSGT_AO
, MSGL_ERR
, MSGTR_AO_SGI_InvalidDevice
);
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();
179 mp_msg(MSGT_AO
, MSGL_ERR
, MSGTR_AO_SGI_InitConfigError
, alGetErrorString(oserror()));
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()));
192 ao_port
= alOpenPort("mplayer", "w", ao_config
);
195 mp_msg(MSGT_AO
, MSGL_ERR
, MSGTR_AO_SGI_InitOpenAudioFailed
, alGetErrorString(oserror()));
199 // printf("ao_sgi, init: port %d config %d\n", ao_port, ao_config);
200 queue_size
= alGetQueueSize(ao_config
);
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
);
213 alFreeConfig(ao_config
);
219 while(alGetFilled(ao_port
) > 0) sginap(1);
220 alClosePort(ao_port
);
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
);
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
);