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