]> git.sesse.net Git - vlc/blob - modules/audio_output/oss.c
db1e28e63ec12d0672ee0cfd0f40d85dc1ea35c8
[vlc] / modules / audio_output / oss.c
1 /*****************************************************************************
2  * oss.c : OSS /dev/dsp module for vlc
3  *****************************************************************************
4  * Copyright (C) 2000-2002 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Michel Kaempf <maxx@via.ecp.fr>
8  *          Sam Hocevar <sam@zoy.org>
9  *          Christophe Massiot <massiot@via.ecp.fr>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include <errno.h>                                                 /* ENOMEM */
30 #include <fcntl.h>                                       /* open(), O_WRONLY */
31 #include <sys/ioctl.h>                                            /* ioctl() */
32 #include <unistd.h>                                      /* write(), close() */
33
34 #ifdef HAVE_CONFIG_H
35 # include "config.h"
36 #endif
37
38 #include <vlc_common.h>
39 #include <vlc_plugin.h>
40
41 #ifdef HAVE_ALLOCA_H
42 #   include <alloca.h>
43 #endif
44
45 #include <vlc_aout.h>
46
47 /* SNDCTL_DSP_RESET, SNDCTL_DSP_SETFMT, SNDCTL_DSP_STEREO, SNDCTL_DSP_SPEED,
48  * SNDCTL_DSP_GETOSPACE */
49 #ifdef HAVE_SOUNDCARD_H
50 #   include <soundcard.h>
51 #elif defined( HAVE_SYS_SOUNDCARD_H )
52 #   include <sys/soundcard.h>
53 #elif defined( HAVE_MACHINE_SOUNDCARD_H )
54 #   include <machine/soundcard.h>
55 #endif
56
57 /* Patches for ignorant OSS versions */
58 #ifndef AFMT_AC3
59 #   define AFMT_AC3     0x00000400        /* Dolby Digital AC3 */
60 #endif
61
62 #ifndef AFMT_S16_NE
63 #   ifdef WORDS_BIGENDIAN
64 #       define AFMT_S16_NE AFMT_S16_BE
65 #   else
66 #       define AFMT_S16_NE AFMT_S16_LE
67 #   endif
68 #endif
69
70 /*****************************************************************************
71  * aout_sys_t: OSS audio output method descriptor
72  *****************************************************************************
73  * This structure is part of the audio output thread descriptor.
74  * It describes the DSP specific properties of an audio device.
75  *****************************************************************************/
76 struct aout_sys_t
77 {
78     int i_fd;
79     int b_workaround_buggy_driver;
80     int i_fragstotal;
81     mtime_t max_buffer_duration;
82 };
83
84 /* This must be a power of 2. */
85 #define FRAME_SIZE 1024
86 #define FRAME_COUNT 32
87
88 /*****************************************************************************
89  * Local prototypes
90  *****************************************************************************/
91 static int  Open         ( vlc_object_t * );
92 static void Close        ( vlc_object_t * );
93
94 static void Play         ( aout_instance_t * );
95 static int  OSSThread    ( aout_instance_t * );
96
97 static mtime_t BufferDuration( aout_instance_t * p_aout );
98
99 /*****************************************************************************
100  * Module descriptor
101  *****************************************************************************/
102 #define BUGGY_TEXT N_("Try to work around buggy OSS drivers")
103 #define BUGGY_LONGTEXT N_( \
104     "Some buggy OSS drivers just don't like when their internal buffers " \
105     "are completely filled (the sound gets heavily hashed). If you have one " \
106     "of these drivers, then you need to enable this option." )
107
108 vlc_module_begin();
109     set_shortname( "OSS" );
110     set_description( N_("UNIX OSS audio output") );
111
112     set_category( CAT_AUDIO );
113     set_subcategory( SUBCAT_AUDIO_AOUT );
114     add_file( "dspdev", "/dev/dsp", aout_FindAndRestart,
115               N_("OSS DSP device"), NULL, false );
116     add_bool( "oss-buggy", 0, NULL, BUGGY_TEXT, BUGGY_LONGTEXT, true );
117
118     set_capability( "audio output", 100 );
119     add_shortcut( "oss" );
120     set_callbacks( Open, Close );
121 vlc_module_end();
122
123 /*****************************************************************************
124  * Probe: probe the audio device for available formats and channels
125  *****************************************************************************/
126 static void Probe( aout_instance_t * p_aout )
127 {
128     struct aout_sys_t * p_sys = p_aout->output.p_sys;
129     vlc_value_t val, text;
130     int i_format, i_nb_channels;
131
132     var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
133     text.psz_string = _("Audio Device");
134     var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
135
136     /* Test for multi-channel. */
137 #ifdef SNDCTL_DSP_GETCHANNELMASK
138     if ( aout_FormatNbChannels( &p_aout->output.output ) > 2 )
139     {
140         /* Check that the device supports this. */
141
142         int i_chanmask;
143
144         /* Reset all. */
145         i_format = AFMT_S16_NE;
146         if( ioctl( p_sys->i_fd, SNDCTL_DSP_RESET, NULL ) < 0 ||
147             ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0 )
148         {
149             msg_Err( p_aout, "cannot reset OSS audio device" );
150             var_Destroy( p_aout, "audio-device" );
151             return;
152         }
153
154         if ( ioctl( p_sys->i_fd, SNDCTL_DSP_GETCHANNELMASK,
155                     &i_chanmask ) == 0 )
156         {
157             if ( !(i_chanmask & DSP_BIND_FRONT) )
158             {
159                 msg_Err( p_aout, "no front channels! (%x)",
160                          i_chanmask );
161                 return;
162             }
163
164             if ( (i_chanmask & (DSP_BIND_SURR | DSP_BIND_CENTER_LFE))
165                   && (p_aout->output.output.i_physical_channels ==
166                        (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
167                          | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
168                          | AOUT_CHAN_LFE)) )
169             {
170                 val.i_int = AOUT_VAR_5_1;
171                 text.psz_string = "5.1";
172                 var_Change( p_aout, "audio-device",
173                             VLC_VAR_ADDCHOICE, &val, &text );
174             }
175
176             if ( (i_chanmask & DSP_BIND_SURR)
177                   && (p_aout->output.output.i_physical_channels &
178                        (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
179                          | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT)) )
180             {
181                 val.i_int = AOUT_VAR_2F2R;
182                 text.psz_string = N_("2 Front 2 Rear");
183                 var_Change( p_aout, "audio-device",
184                             VLC_VAR_ADDCHOICE, &val, &text );
185             }
186         }
187     }
188 #endif
189
190     /* Reset all. */
191     i_format = AFMT_S16_NE;
192     if( ioctl( p_sys->i_fd, SNDCTL_DSP_RESET, NULL ) < 0 ||
193         ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0 )
194     {
195         msg_Err( p_aout, "cannot reset OSS audio device" );
196         var_Destroy( p_aout, "audio-device" );
197         return;
198     }
199
200     /* Test for stereo. */
201     i_nb_channels = 2;
202     if( ioctl( p_sys->i_fd, SNDCTL_DSP_CHANNELS, &i_nb_channels ) >= 0
203          && i_nb_channels == 2 )
204     {
205         val.i_int = AOUT_VAR_STEREO;
206         text.psz_string = N_("Stereo");
207         var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
208     }
209
210     /* Reset all. */
211     i_format = AFMT_S16_NE;
212     if( ioctl( p_sys->i_fd, SNDCTL_DSP_RESET, NULL ) < 0 ||
213         ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0 )
214     {
215         msg_Err( p_aout, "cannot reset OSS audio device" );
216         var_Destroy( p_aout, "audio-device" );
217         return;
218     }
219
220     /* Test for mono. */
221     i_nb_channels = 1;
222     if( ioctl( p_sys->i_fd, SNDCTL_DSP_CHANNELS, &i_nb_channels ) >= 0
223          && i_nb_channels == 1 )
224     {
225         val.i_int = AOUT_VAR_MONO;
226         text.psz_string = N_("Mono");
227         var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
228         if ( p_aout->output.output.i_physical_channels == AOUT_CHAN_CENTER )
229         {
230             var_Set( p_aout, "audio-device", val );
231         }
232     }
233
234     if( ioctl( p_sys->i_fd, SNDCTL_DSP_RESET, NULL ) < 0 )
235     {
236         msg_Err( p_aout, "cannot reset OSS audio device" );
237         var_Destroy( p_aout, "audio-device" );
238         return;
239     }
240
241     /* Test for spdif. */
242     if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
243     {
244         i_format = AFMT_AC3;
245
246         if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) >= 0
247              && i_format == AFMT_AC3 )
248         {
249             val.i_int = AOUT_VAR_SPDIF;
250             text.psz_string = N_("A/52 over S/PDIF");
251             var_Change( p_aout, "audio-device",
252                         VLC_VAR_ADDCHOICE, &val, &text );
253             if( config_GetInt( p_aout, "spdif" ) )
254                 var_Set( p_aout, "audio-device", val );
255         }
256         else if( config_GetInt( p_aout, "spdif" ) )
257         {
258             msg_Warn( p_aout, "S/PDIF not supported by card" );
259         }
260     }
261
262     var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart,
263                      NULL );
264 }
265
266 /*****************************************************************************
267  * Open: open the audio device (the digital sound processor)
268  *****************************************************************************
269  * This function opens the DSP as a usual non-blocking write-only file, and
270  * modifies the p_aout->p_sys->i_fd with the file's descriptor.
271  *****************************************************************************/
272 static int Open( vlc_object_t *p_this )
273 {
274     aout_instance_t * p_aout = (aout_instance_t *)p_this;
275     struct aout_sys_t * p_sys;
276     char * psz_device;
277     vlc_value_t val;
278
279     /* Allocate structure */
280     p_aout->output.p_sys = p_sys = malloc( sizeof( aout_sys_t ) );
281     if( p_sys == NULL )
282         return VLC_ENOMEM;
283
284     /* Get device name */
285     if( (psz_device = config_GetPsz( p_aout, "dspdev" )) == NULL )
286     {
287         msg_Err( p_aout, "no audio device specified (maybe /dev/dsp?)" );
288         free( p_sys );
289         return VLC_EGENERIC;
290     }
291
292     /* Open the sound device in non-blocking mode, because ALSA's OSS
293      * emulation and some broken OSS drivers would make a blocking call
294      * wait forever until the device is available. Since this breaks the
295      * OSS spec, we immediately put it back to blocking mode if the
296      * operation was successful. */
297     p_sys->i_fd = open( psz_device, O_WRONLY | O_NDELAY );
298     if( p_sys->i_fd < 0 )
299     {
300         msg_Err( p_aout, "cannot open audio device (%s)", psz_device );
301         free( p_sys );
302         return VLC_EGENERIC;
303     }
304
305     /* if the opening was ok, put the device back in blocking mode */
306     fcntl( p_sys->i_fd, F_SETFL,
307             fcntl( p_sys->i_fd, F_GETFL ) &~ FNDELAY );
308
309     free( psz_device );
310
311     p_aout->output.pf_play = Play;
312
313     if ( var_Type( p_aout, "audio-device" ) == 0 )
314     {
315         Probe( p_aout );
316     }
317
318     if ( var_Get( p_aout, "audio-device", &val ) < 0 )
319     {
320         /* Probe() has failed. */
321         free( p_sys );
322         return VLC_EGENERIC;
323     }
324
325     if ( val.i_int == AOUT_VAR_SPDIF )
326     {
327         p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i');
328     }
329     else if ( val.i_int == AOUT_VAR_5_1 )
330     {
331         p_aout->output.output.i_format = AOUT_FMT_S16_NE;
332         p_aout->output.output.i_physical_channels
333             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
334                | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
335                | AOUT_CHAN_LFE;
336     }
337     else if ( val.i_int == AOUT_VAR_2F2R )
338     {
339         p_aout->output.output.i_format = AOUT_FMT_S16_NE;
340         p_aout->output.output.i_physical_channels
341             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
342                | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
343     }
344     else if ( val.i_int == AOUT_VAR_STEREO )
345     {
346         p_aout->output.output.i_format = AOUT_FMT_S16_NE;
347         p_aout->output.output.i_physical_channels
348             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
349     }
350     else if ( val.i_int == AOUT_VAR_MONO )
351     {
352         p_aout->output.output.i_format = AOUT_FMT_S16_NE;
353         p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
354     }
355     else
356     {
357         /* This should not happen ! */
358         msg_Err( p_aout, "internal: can't find audio-device (%i)", val.i_int );
359         free( p_sys );
360         return VLC_EGENERIC;
361     }
362
363     val.b_bool = true;
364     var_Set( p_aout, "intf-change", val );
365
366     /* Reset the DSP device */
367     if( ioctl( p_sys->i_fd, SNDCTL_DSP_RESET, NULL ) < 0 )
368     {
369         msg_Err( p_aout, "cannot reset OSS audio device" );
370         close( p_sys->i_fd );
371         free( p_sys );
372         return VLC_EGENERIC;
373     }
374
375     /* Set the output format */
376     if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
377     {
378         int i_format = AFMT_AC3;
379
380         if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0
381              || i_format != AFMT_AC3 )
382         {
383             msg_Err( p_aout, "cannot reset OSS audio device" );
384             close( p_sys->i_fd );
385             free( p_sys );
386             return VLC_EGENERIC;
387         }
388
389         p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i');
390         p_aout->output.i_nb_samples = A52_FRAME_NB;
391         p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
392         p_aout->output.output.i_frame_length = A52_FRAME_NB;
393
394         aout_VolumeNoneInit( p_aout );
395     }
396
397     if ( !AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
398     {
399         unsigned int i_format = AFMT_S16_NE;
400         unsigned int i_frame_size, i_fragments;
401         unsigned int i_rate;
402         unsigned int i_nb_channels;
403         audio_buf_info audio_buf;
404
405         if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0 )
406         {
407             msg_Err( p_aout, "cannot set audio output format" );
408             close( p_sys->i_fd );
409             free( p_sys );
410             return VLC_EGENERIC;
411         }
412
413         switch ( i_format )
414         {
415         case AFMT_U8:
416             p_aout->output.output.i_format = VLC_FOURCC('u','8',' ',' ');
417             break;
418         case AFMT_S8:
419             p_aout->output.output.i_format = VLC_FOURCC('s','8',' ',' ');
420             break;
421         case AFMT_U16_LE:
422             p_aout->output.output.i_format = VLC_FOURCC('u','1','6','l');
423             break;
424         case AFMT_S16_LE:
425             p_aout->output.output.i_format = VLC_FOURCC('s','1','6','l');
426             break;
427         case AFMT_U16_BE:
428             p_aout->output.output.i_format = VLC_FOURCC('u','1','6','b');
429             break;
430         case AFMT_S16_BE:
431             p_aout->output.output.i_format = VLC_FOURCC('s','1','6','b');
432             break;
433         default:
434             msg_Err( p_aout, "OSS fell back to an unknown format (%d)",
435                      i_format );
436             close( p_sys->i_fd );
437             free( p_sys );
438             return VLC_EGENERIC;
439         }
440
441         i_nb_channels = aout_FormatNbChannels( &p_aout->output.output );
442
443         /* Set the number of channels */
444         if( ioctl( p_sys->i_fd, SNDCTL_DSP_CHANNELS, &i_nb_channels ) < 0 ||
445             i_nb_channels != aout_FormatNbChannels( &p_aout->output.output ) )
446         {
447             msg_Err( p_aout, "cannot set number of audio channels (%s)",
448                      aout_FormatPrintChannels( &p_aout->output.output) );
449             close( p_sys->i_fd );
450             free( p_sys );
451             return VLC_EGENERIC;
452         }
453
454         /* Set the output rate */
455         i_rate = p_aout->output.output.i_rate;
456         if( ioctl( p_sys->i_fd, SNDCTL_DSP_SPEED, &i_rate ) < 0 )
457         {
458             msg_Err( p_aout, "cannot set audio output rate (%i)",
459                              p_aout->output.output.i_rate );
460             close( p_sys->i_fd );
461             free( p_sys );
462             return VLC_EGENERIC;
463         }
464
465         if( i_rate != p_aout->output.output.i_rate )
466         {
467             p_aout->output.output.i_rate = i_rate;
468         }
469
470         /* Set the fragment size */
471         aout_FormatPrepare( &p_aout->output.output );
472
473         /* i_fragment = xxxxyyyy where: xxxx        is fragtotal
474          *                              1 << yyyy   is fragsize */
475         i_frame_size = ((uint64_t)p_aout->output.output.i_bytes_per_frame * p_aout->output.output.i_rate * 65536) / (48000 * 2 * 2) / FRAME_COUNT;
476         i_fragments = 4;
477         while( i_fragments < 12 && (1U << i_fragments) < i_frame_size )
478         {
479             ++i_fragments;
480         }
481         i_fragments |= FRAME_COUNT << 16;
482         if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFRAGMENT, &i_fragments ) < 0 )
483         {
484             msg_Warn( p_aout, "cannot set fragment size (%.8x)", i_fragments );
485         }
486
487         if( ioctl( p_sys->i_fd, SNDCTL_DSP_GETOSPACE, &audio_buf ) < 0 )
488         {
489             msg_Err( p_aout, "cannot get fragment size" );
490             close( p_sys->i_fd );
491             free( p_sys );
492             return VLC_EGENERIC;
493         }
494         else
495         {
496             /* Number of fragments actually allocated */
497             p_aout->output.p_sys->i_fragstotal = audio_buf.fragstotal;
498
499             /* Maximum duration the soundcard's buffer can hold */
500             p_aout->output.p_sys->max_buffer_duration =
501                 (mtime_t)audio_buf.fragstotal * audio_buf.fragsize * 1000000
502                 / p_aout->output.output.i_bytes_per_frame
503                 / p_aout->output.output.i_rate
504                 * p_aout->output.output.i_frame_length;
505
506             p_aout->output.i_nb_samples = audio_buf.fragsize /
507                 p_aout->output.output.i_bytes_per_frame;
508         }
509
510         aout_VolumeSoftInit( p_aout );
511     }
512
513     p_aout->output.p_sys->b_workaround_buggy_driver =
514         config_GetInt( p_aout, "oss-buggy" );
515
516     /* Create OSS thread and wait for its readiness. */
517     if( vlc_thread_create( p_aout, "aout", OSSThread,
518                            VLC_THREAD_PRIORITY_OUTPUT, false ) )
519     {
520         msg_Err( p_aout, "cannot create OSS thread (%m)" );
521         close( p_sys->i_fd );
522         free( p_sys );
523         return VLC_ETHREAD;
524     }
525
526     return VLC_SUCCESS;
527 }
528
529 /*****************************************************************************
530  * Play: nothing to do
531  *****************************************************************************/
532 static void Play( aout_instance_t *p_aout )
533 {
534     VLC_UNUSED(p_aout);
535 }
536
537 /*****************************************************************************
538  * Close: close the DSP audio device
539  *****************************************************************************/
540 static void Close( vlc_object_t * p_this )
541 {
542     aout_instance_t *p_aout = (aout_instance_t *)p_this;
543     struct aout_sys_t * p_sys = p_aout->output.p_sys;
544
545     vlc_object_kill( p_aout );
546     vlc_thread_join( p_aout );
547     p_aout->b_die = false;
548
549     ioctl( p_sys->i_fd, SNDCTL_DSP_RESET, NULL );
550     close( p_sys->i_fd );
551
552     free( p_sys );
553 }
554
555 /*****************************************************************************
556  * BufferDuration: buffer status query
557  *****************************************************************************
558  * This function returns the duration in microseconds of the current buffer.
559  *****************************************************************************/
560 static mtime_t BufferDuration( aout_instance_t * p_aout )
561 {
562     struct aout_sys_t * p_sys = p_aout->output.p_sys;
563     audio_buf_info audio_buf;
564     int i_bytes;
565
566     /* Fill the audio_buf_info structure:
567      * - fragstotal: total number of fragments allocated
568      * - fragsize: size of a fragment in bytes
569      * - bytes: available space in bytes (includes partially used fragments)
570      * Note! 'bytes' could be more than fragments*fragsize */
571     ioctl( p_sys->i_fd, SNDCTL_DSP_GETOSPACE, &audio_buf );
572
573     /* calculate number of available fragments (not partially used ones) */
574     i_bytes = (audio_buf.fragstotal * audio_buf.fragsize) - audio_buf.bytes;
575
576     /* Return the fragment duration */
577     return (mtime_t)i_bytes * 1000000
578             / p_aout->output.output.i_bytes_per_frame
579             / p_aout->output.output.i_rate
580             * p_aout->output.output.i_frame_length;
581 }
582
583 /*****************************************************************************
584  * OSSThread: asynchronous thread used to DMA the data to the device
585  *****************************************************************************/
586 static int OSSThread( aout_instance_t * p_aout )
587 {
588     struct aout_sys_t * p_sys = p_aout->output.p_sys;
589     mtime_t next_date = 0;
590
591     while ( !p_aout->b_die )
592     {
593         aout_buffer_t * p_buffer = NULL;
594         int i_tmp, i_size;
595         uint8_t * p_bytes;
596
597         if ( p_aout->output.output.i_format != VLC_FOURCC('s','p','d','i') )
598         {
599             mtime_t buffered = BufferDuration( p_aout );
600
601             if( p_aout->output.p_sys->b_workaround_buggy_driver )
602             {
603 #define i_fragstotal p_aout->output.p_sys->i_fragstotal
604                 /* Wait a bit - we don't want our buffer to be full */
605                 if( buffered > (p_aout->output.p_sys->max_buffer_duration
606                                 / i_fragstotal * (i_fragstotal - 1)) )
607                 {
608                     msleep((p_aout->output.p_sys->max_buffer_duration
609                                 / i_fragstotal ));
610                     buffered = BufferDuration( p_aout );
611                 }
612 #undef i_fragstotal
613             }
614
615             /* Next buffer will be played at mdate() + buffered */
616             p_buffer = aout_OutputNextBuffer( p_aout, mdate() + buffered,
617                                               false );
618
619             if( p_buffer == NULL &&
620                 buffered > ( p_aout->output.p_sys->max_buffer_duration
621                              / p_aout->output.p_sys->i_fragstotal ) )
622             {
623                 /* If we have at least a fragment full, then we can wait a
624                  * little and retry to get a new audio buffer instead of
625                  * playing a blank sample */
626                 msleep( ( p_aout->output.p_sys->max_buffer_duration
627                           / p_aout->output.p_sys->i_fragstotal / 2 ) );
628                 continue;
629             }
630         }
631         else
632         {
633             /* emu10k1 driver does not report Buffer Duration correctly in
634              * passthrough mode so we have to cheat */
635             if( !next_date )
636             {
637                 next_date = mdate();
638             }
639             else
640             {
641                 mtime_t delay = next_date - mdate();
642                 if( delay > AOUT_PTS_TOLERANCE )
643                 {
644                     msleep( delay / 2 );
645                 }
646             }
647
648             while( !p_aout->b_die && ! ( p_buffer =
649                 aout_OutputNextBuffer( p_aout, next_date, true ) ) )
650             {
651                 msleep( 1000 );
652                 next_date = mdate();
653             }
654         }
655
656         if ( p_buffer != NULL )
657         {
658             p_bytes = p_buffer->p_buffer;
659             i_size = p_buffer->i_nb_bytes;
660             /* This is theoretical ... we'll see next iteration whether
661              * we're drifting */
662             next_date += p_buffer->end_date - p_buffer->start_date;
663         }
664         else
665         {
666             i_size = FRAME_SIZE / p_aout->output.output.i_frame_length
667                       * p_aout->output.output.i_bytes_per_frame;
668             p_bytes = malloc( i_size );
669             memset( p_bytes, 0, i_size );
670             next_date = 0;
671         }
672
673         i_tmp = write( p_sys->i_fd, p_bytes, i_size );
674
675         if( i_tmp < 0 )
676         {
677             msg_Err( p_aout, "write failed (%m)" );
678         }
679
680         if ( p_buffer != NULL )
681         {
682             aout_BufferFree( p_buffer );
683         }
684         else
685         {
686             free( p_bytes );
687         }
688     }
689
690     return VLC_SUCCESS;
691 }