]> git.sesse.net Git - vlc/blob - modules/audio_output/oss.c
A bit of headers cleanup
[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 <string.h>                                            /* strerror() */
33 #include <unistd.h>                                      /* write(), close() */
34 #include <stdlib.h>                            /* calloc(), malloc(), free() */
35
36 #include <vlc/vlc.h>
37
38 #ifdef HAVE_ALLOCA_H
39 #   include <alloca.h>
40 #endif
41
42 #include <vlc_aout.h>
43
44 /* SNDCTL_DSP_RESET, SNDCTL_DSP_SETFMT, SNDCTL_DSP_STEREO, SNDCTL_DSP_SPEED,
45  * SNDCTL_DSP_GETOSPACE */
46 #ifdef HAVE_SOUNDCARD_H
47 #   include <soundcard.h>
48 #elif defined( HAVE_SYS_SOUNDCARD_H )
49 #   include <sys/soundcard.h>
50 #elif defined( HAVE_MACHINE_SOUNDCARD_H )
51 #   include <machine/soundcard.h>
52 #endif
53
54 /* Patches for ignorant OSS versions */
55 #ifndef AFMT_AC3
56 #   define AFMT_AC3     0x00000400        /* Dolby Digital AC3 */
57 #endif
58
59 #ifndef AFMT_S16_NE
60 #   ifdef WORDS_BIGENDIAN
61 #       define AFMT_S16_NE AFMT_S16_BE
62 #   else
63 #       define AFMT_S16_NE AFMT_S16_LE
64 #   endif
65 #endif
66
67 /*****************************************************************************
68  * aout_sys_t: OSS audio output method descriptor
69  *****************************************************************************
70  * This structure is part of the audio output thread descriptor.
71  * It describes the DSP specific properties of an audio device.
72  *****************************************************************************/
73 struct aout_sys_t
74 {
75     int i_fd;
76     int b_workaround_buggy_driver;
77     int i_fragstotal;
78     mtime_t max_buffer_duration;
79 };
80
81 /* This must be a power of 2. */
82 #define FRAME_SIZE 1024
83 #define FRAME_COUNT 4
84
85 /*****************************************************************************
86  * Local prototypes
87  *****************************************************************************/
88 static int  Open         ( vlc_object_t * );
89 static void Close        ( vlc_object_t * );
90
91 static void Play         ( aout_instance_t * );
92 static int  OSSThread    ( aout_instance_t * );
93
94 static mtime_t BufferDuration( aout_instance_t * p_aout );
95
96 /*****************************************************************************
97  * Module descriptor
98  *****************************************************************************/
99 #define BUGGY_TEXT N_("Try to work around buggy OSS drivers")
100 #define BUGGY_LONGTEXT N_( \
101     "Some buggy OSS drivers just don't like when their internal buffers " \
102     "are completely filled (the sound gets heavily hashed). If you have one " \
103     "of these drivers, then you need to enable this option." )
104
105 vlc_module_begin();
106     set_shortname( "OSS" );
107     set_description( _("Linux OSS audio output") );
108
109     set_category( CAT_AUDIO );
110     set_subcategory( SUBCAT_AUDIO_AOUT );
111     add_file( "dspdev", "/dev/dsp", aout_FindAndRestart,
112               N_("OSS DSP device"), NULL, VLC_FALSE );
113     add_bool( "oss-buggy", 0, NULL, BUGGY_TEXT, BUGGY_LONGTEXT, VLC_TRUE );
114
115     set_capability( "audio output", 100 );
116     add_shortcut( "oss" );
117     set_callbacks( Open, Close );
118 vlc_module_end();
119
120 /*****************************************************************************
121  * Probe: probe the audio device for available formats and channels
122  *****************************************************************************/
123 static void Probe( aout_instance_t * p_aout )
124 {
125     struct aout_sys_t * p_sys = p_aout->output.p_sys;
126     vlc_value_t val, text;
127     int i_format, i_nb_channels;
128
129     var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
130     text.psz_string = _("Audio Device");
131     var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
132
133     /* Test for multi-channel. */
134 #ifdef SNDCTL_DSP_GETCHANNELMASK
135     if ( aout_FormatNbChannels( &p_aout->output.output ) > 2 )
136     {
137         /* Check that the device supports this. */
138
139         int i_chanmask;
140
141         /* Reset all. */
142         i_format = AFMT_S16_NE;
143         if( ioctl( p_sys->i_fd, SNDCTL_DSP_RESET, NULL ) < 0 ||
144             ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0 )
145         {
146             msg_Err( p_aout, "cannot reset OSS audio device" );
147             var_Destroy( p_aout, "audio-device" );
148             return;
149         }
150
151         if ( ioctl( p_sys->i_fd, SNDCTL_DSP_GETCHANNELMASK,
152                     &i_chanmask ) == 0 )
153         {
154             if ( !(i_chanmask & DSP_BIND_FRONT) )
155             {
156                 msg_Err( p_aout, "no front channels! (%x)",
157                          i_chanmask );
158                 return;
159             }
160
161             if ( (i_chanmask & (DSP_BIND_SURR | DSP_BIND_CENTER_LFE))
162                   && (p_aout->output.output.i_physical_channels ==
163                        (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
164                          | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
165                          | AOUT_CHAN_LFE)) )
166             {
167                 val.i_int = AOUT_VAR_5_1;
168                 text.psz_string = "5.1";
169                 var_Change( p_aout, "audio-device",
170                             VLC_VAR_ADDCHOICE, &val, &text );
171             }
172
173             if ( (i_chanmask & DSP_BIND_SURR)
174                   && (p_aout->output.output.i_physical_channels &
175                        (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
176                          | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT)) )
177             {
178                 val.i_int = AOUT_VAR_2F2R;
179                 text.psz_string = N_("2 Front 2 Rear");
180                 var_Change( p_aout, "audio-device",
181                             VLC_VAR_ADDCHOICE, &val, &text );
182             }
183         }
184     }
185 #endif
186
187     /* Reset all. */
188     i_format = AFMT_S16_NE;
189     if( ioctl( p_sys->i_fd, SNDCTL_DSP_RESET, NULL ) < 0 ||
190         ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0 )
191     {
192         msg_Err( p_aout, "cannot reset OSS audio device" );
193         var_Destroy( p_aout, "audio-device" );
194         return;
195     }
196
197     /* Test for stereo. */
198     i_nb_channels = 2;
199     if( ioctl( p_sys->i_fd, SNDCTL_DSP_CHANNELS, &i_nb_channels ) >= 0
200          && i_nb_channels == 2 )
201     {
202         val.i_int = AOUT_VAR_STEREO;
203         text.psz_string = N_("Stereo");
204         var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
205     }
206
207     /* Reset all. */
208     i_format = AFMT_S16_NE;
209     if( ioctl( p_sys->i_fd, SNDCTL_DSP_RESET, NULL ) < 0 ||
210         ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0 )
211     {
212         msg_Err( p_aout, "cannot reset OSS audio device" );
213         var_Destroy( p_aout, "audio-device" );
214         return;
215     }
216
217     /* Test for mono. */
218     i_nb_channels = 1;
219     if( ioctl( p_sys->i_fd, SNDCTL_DSP_CHANNELS, &i_nb_channels ) >= 0
220          && i_nb_channels == 1 )
221     {
222         val.i_int = AOUT_VAR_MONO;
223         text.psz_string = N_("Mono");
224         var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
225         if ( p_aout->output.output.i_physical_channels == AOUT_CHAN_CENTER )
226         {
227             var_Set( p_aout, "audio-device", val );
228         }
229     }
230
231     if( ioctl( p_sys->i_fd, SNDCTL_DSP_RESET, NULL ) < 0 )
232     {
233         msg_Err( p_aout, "cannot reset OSS audio device" );
234         var_Destroy( p_aout, "audio-device" );
235         return;
236     }
237
238     /* Test for spdif. */
239     if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
240     {
241         i_format = AFMT_AC3;
242
243         if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) >= 0
244              && i_format == AFMT_AC3 )
245         {
246             val.i_int = AOUT_VAR_SPDIF;
247             text.psz_string = N_("A/52 over S/PDIF");
248             var_Change( p_aout, "audio-device",
249                         VLC_VAR_ADDCHOICE, &val, &text );
250             if( config_GetInt( p_aout, "spdif" ) )
251                 var_Set( p_aout, "audio-device", val );
252         }
253         else if( config_GetInt( p_aout, "spdif" ) )
254         {
255             msg_Warn( p_aout, "S/PDIF not supported by card" );
256         }
257     }
258
259     var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart,
260                      NULL );
261 }
262
263 /*****************************************************************************
264  * Open: open the audio device (the digital sound processor)
265  *****************************************************************************
266  * This function opens the DSP as a usual non-blocking write-only file, and
267  * modifies the p_aout->p_sys->i_fd with the file's descriptor.
268  *****************************************************************************/
269 static int Open( vlc_object_t *p_this )
270 {
271     aout_instance_t * p_aout = (aout_instance_t *)p_this;
272     struct aout_sys_t * p_sys;
273     char * psz_device;
274     vlc_value_t val;
275
276     /* Allocate structure */
277     p_aout->output.p_sys = p_sys = malloc( sizeof( aout_sys_t ) );
278     if( p_sys == NULL )
279     {
280         msg_Err( p_aout, "out of memory" );
281         return VLC_ENOMEM;
282     }
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 = VLC_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_fragments = 0;
476         i_frame_size = FRAME_SIZE * p_aout->output.output.i_bytes_per_frame;
477         while( i_frame_size >>= 1 )
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, VLC_FALSE ) )
519     {
520         msg_Err( p_aout, "cannot create OSS thread (%s)", strerror(errno) );
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 }
535
536 /*****************************************************************************
537  * Close: close the DSP audio device
538  *****************************************************************************/
539 static void Close( vlc_object_t * p_this )
540 {
541     aout_instance_t *p_aout = (aout_instance_t *)p_this;
542     struct aout_sys_t * p_sys = p_aout->output.p_sys;
543
544     p_aout->b_die = VLC_TRUE;
545     vlc_thread_join( p_aout );
546     p_aout->b_die = VLC_FALSE;
547
548     ioctl( p_sys->i_fd, SNDCTL_DSP_RESET, NULL );
549     close( p_sys->i_fd );
550
551     free( p_sys );
552 }
553
554 /*****************************************************************************
555  * BufferDuration: buffer status query
556  *****************************************************************************
557  * This function returns the duration in microseconds of the current buffer.
558  *****************************************************************************/
559 static mtime_t BufferDuration( aout_instance_t * p_aout )
560 {
561     struct aout_sys_t * p_sys = p_aout->output.p_sys;
562     audio_buf_info audio_buf;
563     int i_bytes;
564
565     /* Fill the audio_buf_info structure:
566      * - fragstotal: total number of fragments allocated
567      * - fragsize: size of a fragment in bytes
568      * - bytes: available space in bytes (includes partially used fragments)
569      * Note! 'bytes' could be more than fragments*fragsize */
570     ioctl( p_sys->i_fd, SNDCTL_DSP_GETOSPACE, &audio_buf );
571
572     /* calculate number of available fragments (not partially used ones) */
573     i_bytes = (audio_buf.fragstotal * audio_buf.fragsize) - audio_buf.bytes;
574
575     /* Return the fragment duration */
576     return (mtime_t)i_bytes * 1000000
577             / p_aout->output.output.i_bytes_per_frame
578             / p_aout->output.output.i_rate
579             * p_aout->output.output.i_frame_length;
580 }
581
582 /*****************************************************************************
583  * OSSThread: asynchronous thread used to DMA the data to the device
584  *****************************************************************************/
585 static int OSSThread( aout_instance_t * p_aout )
586 {
587     struct aout_sys_t * p_sys = p_aout->output.p_sys;
588     mtime_t next_date = 0;
589
590     while ( !p_aout->b_die )
591     {
592         aout_buffer_t * p_buffer = NULL;
593         int i_tmp, i_size;
594         byte_t * p_bytes;
595
596         if ( p_aout->output.output.i_format != VLC_FOURCC('s','p','d','i') )
597         {
598             mtime_t buffered = BufferDuration( p_aout );
599
600             if( p_aout->output.p_sys->b_workaround_buggy_driver )
601             {
602 #define i_fragstotal p_aout->output.p_sys->i_fragstotal
603                 /* Wait a bit - we don't want our buffer to be full */
604                 if( buffered > (p_aout->output.p_sys->max_buffer_duration
605                                 / i_fragstotal * (i_fragstotal - 1)) )
606                 {
607                     msleep((p_aout->output.p_sys->max_buffer_duration
608                                 / i_fragstotal ));
609                     buffered = BufferDuration( p_aout );
610                 }
611 #undef i_fragstotal
612             }
613
614             /* Next buffer will be played at mdate() + buffered */
615             p_buffer = aout_OutputNextBuffer( p_aout, mdate() + buffered,
616                                               VLC_FALSE );
617
618             if( p_buffer == NULL &&
619                 buffered > ( p_aout->output.p_sys->max_buffer_duration
620                              / p_aout->output.p_sys->i_fragstotal ) )
621             {
622                 /* If we have at least a fragment full, then we can wait a
623                  * little and retry to get a new audio buffer instead of
624                  * playing a blank sample */
625                 msleep( ( p_aout->output.p_sys->max_buffer_duration
626                           / p_aout->output.p_sys->i_fragstotal / 2 ) );
627                 continue;
628             }
629         }
630         else
631         {
632             /* emu10k1 driver does not report Buffer Duration correctly in
633              * passthrough mode so we have to cheat */
634             if( !next_date )
635             {
636                 next_date = mdate();
637             }
638             else
639             {
640                 mtime_t delay = next_date - mdate();
641                 if( delay > AOUT_PTS_TOLERANCE )
642                 {
643                     msleep( delay / 2 );
644                 }
645             }
646
647             while( !p_aout->b_die && ! ( p_buffer =
648                 aout_OutputNextBuffer( p_aout, next_date, VLC_TRUE ) ) )
649             {
650                 msleep( 1000 );
651                 next_date = mdate();
652             }
653         }
654
655         if ( p_buffer != NULL )
656         {
657             p_bytes = p_buffer->p_buffer;
658             i_size = p_buffer->i_nb_bytes;
659             /* This is theoretical ... we'll see next iteration whether
660              * we're drifting */
661             next_date += p_buffer->end_date - p_buffer->start_date;
662         }
663         else
664         {
665             i_size = FRAME_SIZE / p_aout->output.output.i_frame_length
666                       * p_aout->output.output.i_bytes_per_frame;
667             p_bytes = malloc( i_size );
668             memset( p_bytes, 0, i_size );
669             next_date = 0;
670         }
671
672         i_tmp = write( p_sys->i_fd, p_bytes, i_size );
673
674         if( i_tmp < 0 )
675         {
676             msg_Err( p_aout, "write failed (%s)", strerror(errno) );
677         }
678
679         if ( p_buffer != NULL )
680         {
681             aout_BufferFree( p_buffer );
682         }
683         else
684         {
685             free( p_bytes );
686         }
687     }
688
689     return VLC_SUCCESS;
690 }