1 /*
2 * OSS audio output driver
3 *
4 * This file is part of MPlayer.
5 *
6 * MPlayer is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * MPlayer is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23
24 #include <sys/ioctl.h>
25 #include <unistd.h>
26 #include <sys/time.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <errno.h>
31 #include <string.h>
32
33 #include "config.h"
34 #include "libavutil/avstring.h"
35 #include "mp_msg.h"
36 #include "mixer.h"
37 #include "help_mp.h"
38
39 #ifdef HAVE_SYS_SOUNDCARD_H
40 #include <sys/soundcard.h>
41 #else
42 #ifdef HAVE_SOUNDCARD_H
43 #include <soundcard.h>
44 #endif
45 #endif
46
47 #include "libaf/af_format.h"
48
49 #include "audio_out.h"
50 #include "audio_out_internal.h"
51
52 static const ao_info_t info =
53 {
54 "OSS/ioctl audio output",
55 "oss",
56 "A'rpi",
57 ""
58 };
59
60 static int volume = -1;
61
62 /* Support for >2 output channels added 2001-11-25 - Steve Davies <steve@daviesfam.org> */
63
LIBAO_EXTERN(oss)64 LIBAO_EXTERN(oss)
65
66 static int format2oss(int format)
67 {
68 switch(format)
69 {
70 case AF_FORMAT_U8: return AFMT_U8;
71 case AF_FORMAT_S8: return AFMT_S8;
72 case AF_FORMAT_U16_LE: return AFMT_U16_LE;
73 case AF_FORMAT_U16_BE: return AFMT_U16_BE;
74 case AF_FORMAT_S16_LE: return AFMT_S16_LE;
75 case AF_FORMAT_S16_BE: return AFMT_S16_BE;
76 #ifdef AFMT_S24_PACKED
77 case AF_FORMAT_S24_LE: return AFMT_S24_PACKED;
78 #elif defined(__FreeBSD__) && defined(AFMT_S24_LE)
79 case AF_FORMAT_U24_LE: return AFMT_U24_LE;
80 case AF_FORMAT_U24_BE: return AFMT_U24_BE;
81 case AF_FORMAT_S24_LE: return AFMT_S24_LE;
82 case AF_FORMAT_S24_BE: return AFMT_S24_BE;
83 #endif
84 #ifdef AFMT_U32_LE
85 case AF_FORMAT_U32_LE: return AFMT_U32_LE;
86 #endif
87 #ifdef AFMT_U32_BE
88 case AF_FORMAT_U32_BE: return AFMT_U32_BE;
89 #endif
90 #ifdef AFMT_S32_LE
91 case AF_FORMAT_S32_LE: return AFMT_S32_LE;
92 #endif
93 #ifdef AFMT_S32_BE
94 case AF_FORMAT_S32_BE: return AFMT_S32_BE;
95 #endif
96 #ifdef AFMT_FLOAT
97 case AF_FORMAT_FLOAT_NE: return AFMT_FLOAT;
98 #endif
99 // SPECIALS
100 case AF_FORMAT_MU_LAW: return AFMT_MU_LAW;
101 case AF_FORMAT_A_LAW: return AFMT_A_LAW;
102 case AF_FORMAT_IMA_ADPCM: return AFMT_IMA_ADPCM;
103 #ifdef AFMT_MPEG
104 case AF_FORMAT_MPEG2: return AFMT_MPEG;
105 #endif
106 #ifdef AFMT_AC3
107 case AF_FORMAT_AC3_NE: return AFMT_AC3;
108 #endif
109 }
110 mp_msg(MSGT_AO, MSGL_V, "OSS: Unknown/not supported internal format: %s\n", af_fmt2str_short(format));
111 return -1;
112 }
113
oss2format(int format)114 static int oss2format(int format)
115 {
116 switch(format)
117 {
118 case AFMT_U8: return AF_FORMAT_U8;
119 case AFMT_S8: return AF_FORMAT_S8;
120 case AFMT_U16_LE: return AF_FORMAT_U16_LE;
121 case AFMT_U16_BE: return AF_FORMAT_U16_BE;
122 case AFMT_S16_LE: return AF_FORMAT_S16_LE;
123 case AFMT_S16_BE: return AF_FORMAT_S16_BE;
124 #ifdef AFMT_S24_PACKED
125 case AFMT_S24_PACKED: return AF_FORMAT_S24_LE;
126 #elif defined(__FreeBSD__) && defined(AFMT_S24_LE)
127 case AFMT_U24_LE: return AF_FORMAT_U24_LE;
128 case AFMT_U24_BE: return AF_FORMAT_U24_BE;
129 case AFMT_S24_LE: return AF_FORMAT_S24_LE;
130 case AFMT_S24_BE: return AF_FORMAT_S24_BE;
131 #endif
132 #ifdef AFMT_U32_LE
133 case AFMT_U32_LE: return AF_FORMAT_U32_LE;
134 #endif
135 #ifdef AFMT_U32_BE
136 case AFMT_U32_BE: return AF_FORMAT_U32_BE;
137 #endif
138 #ifdef AFMT_S32_LE
139 case AFMT_S32_LE: return AF_FORMAT_S32_LE;
140 #endif
141 #ifdef AFMT_S32_BE
142 case AFMT_S32_BE: return AF_FORMAT_S32_BE;
143 #endif
144 #ifdef AFMT_FLOAT
145 case AFMT_FLOAT: return AF_FORMAT_FLOAT_NE;
146 #endif
147 // SPECIALS
148 case AFMT_MU_LAW: return AF_FORMAT_MU_LAW;
149 case AFMT_A_LAW: return AF_FORMAT_A_LAW;
150 case AFMT_IMA_ADPCM: return AF_FORMAT_IMA_ADPCM;
151 #ifdef AFMT_MPEG
152 case AFMT_MPEG: return AF_FORMAT_MPEG2;
153 #endif
154 #ifdef AFMT_AC3
155 case AFMT_AC3: return AF_FORMAT_AC3_NE;
156 #endif
157 }
158 mp_msg(MSGT_GLOBAL,MSGL_ERR,MSGTR_AO_OSS_UnknownUnsupportedFormat, format);
159 return -1;
160 }
161
162 static char *dsp=PATH_DEV_DSP;
163 static audio_buf_info zz;
164 static int audio_fd=-1;
165 static int prepause_space;
166
167 static const char *oss_mixer_device = PATH_DEV_MIXER;
168 static int oss_mixer_channel = SOUND_MIXER_PCM;
169
170 // to set/get/query special features/parameters
control(int cmd,void * arg)171 static int control(int cmd,void *arg){
172 switch(cmd){
173 case AOCONTROL_SET_DEVICE:
174 dsp=(char*)arg;
175 return CONTROL_OK;
176 case AOCONTROL_GET_DEVICE:
177 *(char**)arg=dsp;
178 return CONTROL_OK;
179 #ifdef SNDCTL_DSP_GETFMTS
180 case AOCONTROL_QUERY_FORMAT:
181 {
182 int format;
183 if (!ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &format))
184 if ((unsigned int)format & (unsigned long)arg)
185 return CONTROL_TRUE;
186 return CONTROL_FALSE;
187 }
188 #endif
189 case AOCONTROL_GET_VOLUME:
190 case AOCONTROL_SET_VOLUME:
191 {
192 ao_control_vol_t *vol = (ao_control_vol_t *)arg;
193 int fd, v, devs;
194
195 if(AF_FORMAT_IS_AC3(ao_data.format))
196 return CONTROL_TRUE;
197
198 if ((fd = open(oss_mixer_device, O_RDONLY)) != -1)
199 {
200 if (ioctl(fd, SOUND_MIXER_READ_DEVMASK, &devs) == -1)
201 return CONTROL_ERROR;
202 if (devs & (1 << oss_mixer_channel))
203 {
204 if (cmd == AOCONTROL_GET_VOLUME)
205 {
206 if (ioctl(fd, MIXER_READ(oss_mixer_channel), &v) == -1)
207 return CONTROL_ERROR;
208 vol->right = (v & 0xFF00) >> 8;
209 vol->left = v & 0x00FF;
210 }
211 else
212 {
213 v = ((int)vol->right << 8) | (int)vol->left;
214 if (ioctl(fd, MIXER_WRITE(oss_mixer_channel), &v) == -1)
215 return CONTROL_ERROR;
216 }
217 }
218 else
219 {
220 close(fd);
221 return CONTROL_ERROR;
222 }
223 close(fd);
224 return CONTROL_OK;
225 }
226 }
227 return CONTROL_ERROR;
228 }
229 return CONTROL_UNKNOWN;
230 }
231
setfragment(int audio_fd)232 static void setfragment(int audio_fd)
233 {
234 int buffer_bytes = ao_data.channels * ao_data.samplerate;
235 int block_size = 0;
236
237 switch (ao_data.format & AF_FORMAT_BITS_MASK) {
238 case AF_FORMAT_8BIT:
239 break;
240 case AF_FORMAT_16BIT:
241 buffer_bytes *= 2;
242 break;
243 case AF_FORMAT_24BIT:
244 buffer_bytes *= 3;
245 break;
246 case AF_FORMAT_32BIT:
247 buffer_bytes *= 4;
248 break;
249 }
250 buffer_bytes *= 0.050;
251
252 if(ioctl(audio_fd, SNDCTL_DSP_GETBLKSIZE, &block_size)==0){
253 int setfrag;
254 /* make block size power of two */
255 while (block_size & (block_size - 1))
256 block_size += block_size & ~(block_size - 1);
257 /* set number of fragments */
258 setfrag = ((buffer_bytes + block_size - 1) / block_size) << 16;
259 /* need at least double buffering */
260 if (setfrag < (2 << 16))
261 setfrag = (2 << 16);
262 /* set block size in power of two */
263 while (block_size) {
264 setfrag++;
265 block_size /= 2;
266 }
267 /* try to set a total buffer of 50ms */
268 if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &setfrag)==-1){
269 mp_msg(MSGT_AO,MSGL_V,"audio_setup: setfragment %d failed\n", setfrag);
270 }
271 }
272 }
273
274 // open & setup audio device
275 // return: 1=success 0=fail
init(int rate,int channels,int format,int flags)276 static int init(int rate,int channels,int format,int flags){
277 char *mixer_channels [SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
278 int oss_format;
279 char *mdev = mixer_device, *mchan = mixer_channel;
280
281 mp_msg(MSGT_AO,MSGL_V,"ao2: %d Hz %d chans %s\n",rate,channels,
282 af_fmt2str_short(format));
283
284 if (ao_subdevice) {
285 char *m,*c;
286 m = strchr(ao_subdevice,':');
287 if(m) {
288 c = strchr(m+1,':');
289 if(c) {
290 mchan = c+1;
291 c[0] = '\0';
292 }
293 mdev = m+1;
294 m[0] = '\0';
295 }
296 dsp = ao_subdevice;
297 }
298
299 if(mdev)
300 oss_mixer_device=mdev;
301 else
302 oss_mixer_device=PATH_DEV_MIXER;
303
304 if(mchan){
305 int fd, devs, i;
306
307 if ((fd = open(oss_mixer_device, O_RDONLY)) == -1){
308 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_OSS_CantOpenMixer,
309 oss_mixer_device, strerror(errno));
310 }else{
311 if (ioctl(fd, SOUND_MIXER_READ_DEVMASK, &devs) == -1)
312 devs = 0;
313 close(fd);
314
315 for (i=0; i<SOUND_MIXER_NRDEVICES; i++){
316 if(!av_strcasecmp(mixer_channels[i], mchan)){
317 if(!(devs & (1 << i))){
318 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_OSS_ChanNotFound,mchan);
319 i = SOUND_MIXER_NRDEVICES+1;
320 break;
321 }
322 oss_mixer_channel = i;
323 break;
324 }
325 }
326 if(i==SOUND_MIXER_NRDEVICES){
327 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_OSS_ChanNotFound,mchan);
328 }
329 }
330 } else
331 oss_mixer_channel = SOUND_MIXER_PCM;
332
333 mp_msg(MSGT_AO,MSGL_V,"audio_setup: using '%s' dsp device\n", dsp);
334 mp_msg(MSGT_AO,MSGL_V,"audio_setup: using '%s' mixer device\n", oss_mixer_device);
335 mp_msg(MSGT_AO,MSGL_V,"audio_setup: using '%s' mixer device\n", mixer_channels[oss_mixer_channel]);
336
337 #ifdef __linux__
338 audio_fd=open(dsp, O_WRONLY | O_NONBLOCK);
339 #else
340 audio_fd=open(dsp, O_WRONLY);
341 #endif
342 if(audio_fd<0){
343 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_OSS_CantOpenDev, dsp, strerror(errno));
344 return 0;
345 }
346
347 #ifdef __linux__
348 /* Remove the non-blocking flag */
349 if(fcntl(audio_fd, F_SETFL, 0) < 0) {
350 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_OSS_CantMakeFd, strerror(errno));
351 return 0;
352 }
353 #endif
354
355 #if defined(FD_CLOEXEC) && defined(F_SETFD)
356 fcntl(audio_fd, F_SETFD, FD_CLOEXEC);
357 #endif
358
359 if(AF_FORMAT_IS_AC3(format)) {
360 ao_data.samplerate=rate;
361 if (ioctl (audio_fd, SNDCTL_DSP_SPEED, &ao_data.samplerate) == -1)
362 mp_msg(MSGT_AO,MSGL_WARN, "OSS: Failed setting AC3 sample-rate %i %s\n", rate, strerror(errno));
363 }
364
365 ac3_retry:
366 if (AF_FORMAT_IS_AC3(format))
367 format = AF_FORMAT_AC3_NE;
368 ao_data.format=format;
369 oss_format=format2oss(format);
370 if (oss_format == -1) {
371 #if HAVE_BIGENDIAN
372 oss_format=AFMT_S16_BE;
373 #else
374 oss_format=AFMT_S16_LE;
375 #endif
376 format=AF_FORMAT_S16_NE;
377 }
378 if( ioctl(audio_fd, SNDCTL_DSP_SETFMT, &oss_format)<0 ||
379 oss_format != format2oss(format)) {
380 mp_msg(MSGT_AO,MSGL_WARN, MSGTR_AO_OSS_CantSet, dsp,
381 af_fmt2str_short(format), af_fmt2str_short(AF_FORMAT_S16_NE) );
382 format=AF_FORMAT_S16_NE;
383 goto ac3_retry;
384 }
385 #if 0
386 if(oss_format!=format2oss(format))
387 mp_msg(MSGT_AO,MSGL_WARN,"WARNING! Your soundcard does NOT support %s sample format! Broken audio or bad playback speed are possible! Try with '-af format'\n",audio_out_format_name(format));
388 #endif
389
390 ao_data.format = oss2format(oss_format);
391 if (ao_data.format == -1) return 0;
392
393 mp_msg(MSGT_AO,MSGL_V,"audio_setup: sample format: %s (requested: %s)\n",
394 af_fmt2str_short(ao_data.format), af_fmt2str_short(format));
395
396 ao_data.channels = channels;
397 if(!AF_FORMAT_IS_AC3(format)) {
398 // We only use SNDCTL_DSP_CHANNELS for >2 channels, in case some drivers don't have it
399 if (ao_data.channels > 2) {
400 if ( ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &ao_data.channels) == -1 ||
401 ao_data.channels != channels ) {
402 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_OSS_CantSetChans, channels);
403 return 0;
404 }
405 }
406 else {
407 int c = ao_data.channels-1;
408 if (ioctl (audio_fd, SNDCTL_DSP_STEREO, &c) == -1) {
409 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_OSS_CantSetChans, ao_data.channels);
410 return 0;
411 }
412 ao_data.channels=c+1;
413 }
414 mp_msg(MSGT_AO,MSGL_V,"audio_setup: using %d channels (requested: %d)\n", ao_data.channels, channels);
415 // set rate
416 ao_data.samplerate=rate;
417 if (ioctl (audio_fd, SNDCTL_DSP_SPEED, &ao_data.samplerate) == -1)
418 mp_msg(MSGT_AO,MSGL_WARN, "OSS: Failed setting sample-rate %i %s\n", rate, strerror(errno));
419 mp_msg(MSGT_AO,MSGL_V,"audio_setup: using %d Hz samplerate (requested: %d)\n",ao_data.samplerate,rate);
420 }
421 setfragment(audio_fd);
422
423 if(ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &zz)==-1){
424 int r=0;
425 mp_msg(MSGT_AO,MSGL_WARN,MSGTR_AO_OSS_CantUseGetospace);
426 if(ioctl(audio_fd, SNDCTL_DSP_GETBLKSIZE, &r)==-1){
427 mp_msg(MSGT_AO,MSGL_V,"audio_setup: %d bytes/frag (config.h)\n",ao_data.outburst);
428 } else {
429 ao_data.outburst=r;
430 mp_msg(MSGT_AO,MSGL_V,"audio_setup: %d bytes/frag (GETBLKSIZE)\n",ao_data.outburst);
431 }
432 } else {
433 mp_msg(MSGT_AO,MSGL_V,"audio_setup: frags: %3d/%d (%d bytes/frag) free: %6d\n",
434 zz.fragments, zz.fragstotal, zz.fragsize, zz.bytes);
435 if(ao_data.buffersize==-1) ao_data.buffersize=zz.bytes;
436 ao_data.outburst=zz.fragsize;
437 }
438
439 if(ao_data.buffersize==-1){
440 // Measuring buffer size:
441 void* data;
442 ao_data.buffersize=0;
443 #ifdef HAVE_AUDIO_SELECT
444 data=malloc(ao_data.outburst); memset(data,0,ao_data.outburst);
445 while(ao_data.buffersize<0x40000){
446 fd_set rfds;
447 struct timeval tv;
448 FD_ZERO(&rfds); FD_SET(audio_fd,&rfds);
449 tv.tv_sec=0; tv.tv_usec = 0;
450 if(!select(audio_fd+1, NULL, &rfds, NULL, &tv)) break;
451 write(audio_fd,data,ao_data.outburst);
452 ao_data.buffersize+=ao_data.outburst;
453 }
454 free(data);
455 if(ao_data.buffersize==0){
456 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_OSS_CantUseSelect);
457 return 0;
458 }
459 #endif
460 }
461
462 ao_data.bps=ao_data.channels;
463 switch (ao_data.format & AF_FORMAT_BITS_MASK) {
464 case AF_FORMAT_8BIT:
465 break;
466 case AF_FORMAT_16BIT:
467 ao_data.bps*=2;
468 break;
469 case AF_FORMAT_24BIT:
470 ao_data.bps*=3;
471 break;
472 case AF_FORMAT_32BIT:
473 ao_data.bps*=4;
474 break;
475 }
476
477 ao_data.outburst-=ao_data.outburst % ao_data.bps; // round down
478 ao_data.bps*=ao_data.samplerate;
479
480 return 1;
481 }
482
483 // close audio device
uninit(int immed)484 static void uninit(int immed){
485 if(audio_fd == -1) return;
486 #ifdef SNDCTL_DSP_SYNC
487 // to get the buffer played
488 if (!immed)
489 ioctl(audio_fd, SNDCTL_DSP_SYNC, NULL);
490 #endif
491 #ifdef SNDCTL_DSP_RESET
492 if (immed)
493 ioctl(audio_fd, SNDCTL_DSP_RESET, NULL);
494 #endif
495 close(audio_fd);
496 audio_fd = -1;
497 }
498
savevol(void)499 static void savevol(void){
500 int fd;
501 if (volume < 0) {
502 if ((fd = open(oss_mixer_device, O_RDONLY)) >= 0) {
503 ioctl(fd, MIXER_READ(oss_mixer_channel), &volume);
504 close(fd);
505 }
506 }
507 }
508
restorevol(void)509 static void restorevol(void){
510 int fd;
511 if ((fd = open(oss_mixer_device, O_RDONLY)) >= 0) {
512 ioctl(fd, MIXER_WRITE(oss_mixer_channel), &volume);
513 close(fd);
514 }
515 volume = -1;
516 }
517
518 // stop playing and empty buffers (for seeking/pause)
reset(void)519 static void reset(void){
520 int fail = 0;
521 int oss_format;
522 savevol();
523 uninit(1);
524 audio_fd=open(dsp, O_WRONLY);
525 if(audio_fd < 0){
526 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_OSS_CantReopen, strerror(errno));
527 return;
528 }
529
530 #if defined(FD_CLOEXEC) && defined(F_SETFD)
531 fcntl(audio_fd, F_SETFD, FD_CLOEXEC);
532 #endif
533
534 ioctl (audio_fd, SNDCTL_DSP_SPEED, &ao_data.samplerate);
535 oss_format = format2oss(ao_data.format);
536 if(AF_FORMAT_IS_AC3(ao_data.format))
537 fail |= ioctl (audio_fd, SNDCTL_DSP_SPEED, &ao_data.samplerate) == -1;
538 fail |= ioctl (audio_fd, SNDCTL_DSP_SETFMT, &oss_format) == -1;
539 if(!AF_FORMAT_IS_AC3(ao_data.format)) {
540 if (ao_data.channels > 2)
541 fail |= ioctl (audio_fd, SNDCTL_DSP_CHANNELS, &ao_data.channels) == -1;
542 else {
543 int c = ao_data.channels-1;
544 fail |= ioctl (audio_fd, SNDCTL_DSP_STEREO, &c) == -1;
545 }
546 fail |= ioctl (audio_fd, SNDCTL_DSP_SPEED, &ao_data.samplerate) == -1;
547 }
548 if (fail)
549 mp_msg(MSGT_AO,MSGL_WARN, "OSS: Reset failed\n");
550 setfragment(audio_fd);
551 restorevol();
552 }
553
554 // stop playing, keep buffers (for pause)
audio_pause(void)555 static void audio_pause(void)
556 {
557 savevol();
558 prepause_space = get_space();
559 uninit(1);
560 }
561
562 // resume playing, after audio_pause()
audio_resume(void)563 static void audio_resume(void)
564 {
565 reset();
566 mp_ao_resume_refill(&audio_out_oss, prepause_space);
567 }
568
569
570 // return: how many bytes can be played without blocking
get_space(void)571 static int get_space(void){
572 int playsize=ao_data.outburst;
573
574 #ifdef SNDCTL_DSP_GETOSPACE
575 if(ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &zz)!=-1){
576 // calculate exact buffer space:
577 playsize = zz.fragments*zz.fragsize;
578 if (playsize > MAX_OUTBURST)
579 playsize = (MAX_OUTBURST / zz.fragsize) * zz.fragsize;
580 return playsize;
581 }
582 #endif
583
584 // check buffer
585 #ifdef HAVE_AUDIO_SELECT
586 { fd_set rfds;
587 struct timeval tv;
588 FD_ZERO(&rfds);
589 FD_SET(audio_fd, &rfds);
590 tv.tv_sec = 0;
591 tv.tv_usec = 0;
592 if(!select(audio_fd+1, NULL, &rfds, NULL, &tv)) return 0; // not block!
593 }
594 #endif
595
596 return ao_data.outburst;
597 }
598
599 // plays 'len' bytes of 'data'
600 // it should round it down to outburst*n
601 // return: number of bytes played
play(void * data,int len,int flags)602 static int play(void* data,int len,int flags){
603 if(len==0)
604 return len;
605 if(len>ao_data.outburst || !(flags & AOPLAY_FINAL_CHUNK)) {
606 len/=ao_data.outburst;
607 len*=ao_data.outburst;
608 }
609 len=write(audio_fd,data,len);
610 return len;
611 }
612
613 static int audio_delay_method=2;
614
615 // return: delay in seconds between first and last sample in buffer
get_delay(void)616 static float get_delay(void){
617 /* Calculate how many bytes/second is sent out */
618 if(audio_delay_method==2){
619 #ifdef SNDCTL_DSP_GETODELAY
620 int r=0;
621 if(ioctl(audio_fd, SNDCTL_DSP_GETODELAY, &r)!=-1)
622 return ((float)r)/(float)ao_data.bps;
623 #endif
624 audio_delay_method=1; // fallback if not supported
625 }
626 if(audio_delay_method==1){
627 // SNDCTL_DSP_GETOSPACE
628 if(ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &zz)!=-1)
629 return ((float)(ao_data.buffersize-zz.bytes))/(float)ao_data.bps;
630 audio_delay_method=0; // fallback if not supported
631 }
632 return ((float)ao_data.buffersize)/(float)ao_data.bps;
633 }
634