]> git.sesse.net Git - vlc/blob - modules/audio_output/oss.c
* modules/audio_output/alsa.c: Fixed mono files output (thanks bozo !),
[vlc] / modules / audio_output / oss.c
1 /*****************************************************************************
2  * oss.c : OSS /dev/dsp module for vlc
3  *****************************************************************************
4  * Copyright (C) 2000-2002 VideoLAN
5  * $Id: oss.c,v 1.51 2003/02/10 17:43:21 massiot Exp $
6  *
7  * Authors: Michel Kaempf <maxx@via.ecp.fr>
8  *          Samuel 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., 59 Temple Place - Suite 330, Boston, MA  02111, 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 #include "aout_internal.h"
45
46 /* SNDCTL_DSP_RESET, SNDCTL_DSP_SETFMT, SNDCTL_DSP_STEREO, SNDCTL_DSP_SPEED,
47  * SNDCTL_DSP_GETOSPACE */
48 #ifdef HAVE_SOUNDCARD_H
49 #   include <soundcard.h>
50 #elif defined( HAVE_SYS_SOUNDCARD_H )
51 #   include <sys/soundcard.h>
52 #elif defined( HAVE_MACHINE_SOUNDCARD_H )
53 #   include <machine/soundcard.h>
54 #endif
55
56 /* Patches for ignorant OSS versions */
57 #ifndef AFMT_AC3
58 #   define AFMT_AC3     0x00000400      /* Dolby Digital AC3 */
59 #endif
60
61 #ifndef AFMT_S16_NE
62 #   ifdef WORDS_BIGENDIAN
63 #       define AFMT_S16_NE AFMT_S16_BE
64 #   else
65 #       define AFMT_S16_NE AFMT_S16_LE
66 #   endif
67 #endif
68
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 4
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 #define SPDIF_TEXT N_("try to use S/PDIF output")
109 #define SPDIF_LONGTEXT N_( \
110     "Sometimes we attempt to use the S/PDIF output, even if nothing is " \
111     "connected to it. Un-checking this option disables this behaviour, " \
112     "and permanently selects analog PCM output." )
113
114 vlc_module_begin();
115     add_category_hint( N_("OSS"), NULL );
116     add_file( "dspdev", "/dev/dsp", aout_FindAndRestart,
117               N_("OSS dsp device"), NULL );
118     add_bool( "oss-buggy", 0, NULL, BUGGY_TEXT, BUGGY_LONGTEXT );
119     add_bool( "spdif", 1, NULL, SPDIF_TEXT, SPDIF_LONGTEXT );
120     set_description( _("Linux OSS /dev/dsp module") );
121     set_capability( "audio output", 100 );
122     add_shortcut( "oss" );
123     set_callbacks( Open, Close );
124 vlc_module_end();
125
126 /*****************************************************************************
127  * Probe: probe the audio device for available formats and channels
128  *****************************************************************************/
129 static void Probe( aout_instance_t * p_aout )
130 {
131     struct aout_sys_t * p_sys = p_aout->output.p_sys;
132     vlc_value_t val;
133     int i_format, i_nb_channels;
134
135     var_Create( p_aout, "audio-device", VLC_VAR_STRING | VLC_VAR_HASCHOICE );
136
137     if( ioctl( p_sys->i_fd, SNDCTL_DSP_RESET, NULL ) < 0 )
138     {
139         msg_Err( p_aout, "cannot reset OSS audio device" );
140         var_Destroy( p_aout, "audio-device" );
141         return;
142     }
143
144     if ( config_GetInt( p_aout, "spdif" )
145           && AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
146     {
147         i_format = AFMT_AC3;
148
149         if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) >= 0
150              && i_format == AFMT_AC3 )
151         {
152             val.psz_string = N_("A/52 over S/PDIF");
153             var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val );
154         }
155     }
156
157     /* Go to PCM mode. */
158     i_format = AFMT_S16_NE;
159     if( ioctl( p_sys->i_fd, SNDCTL_DSP_RESET, NULL ) < 0 ||
160         ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0 )
161     {
162         return;
163     }
164
165 #ifdef SNDCTL_DSP_GETCHANNELMASK
166     if ( aout_FormatNbChannels( &p_aout->output.output ) > 2 )
167     {
168         /* Check that the device supports this. */
169
170         int i_chanmask;
171         if ( ioctl( p_sys->i_fd, SNDCTL_DSP_GETCHANNELMASK,
172                     &i_chanmask ) == 0 )
173         {
174             if ( !(i_chanmask & DSP_BIND_FRONT) )
175             {
176                 msg_Err( p_aout, "No front channels ! (%x)",
177                          i_chanmask );
178                 return;
179             }
180
181             if ( (i_chanmask & (DSP_BIND_SURR | DSP_BIND_CENTER_LFE))
182                   && (p_aout->output.output.i_physical_channels ==
183                        (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
184                          | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
185                          | AOUT_CHAN_LFE)) )
186             {
187                 val.psz_string = N_("5.1");
188                 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val );
189             }
190
191             if ( (i_chanmask & DSP_BIND_SURR)
192                   && (p_aout->output.output.i_physical_channels &
193                        (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
194                          | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT)) )
195             {
196                 val.psz_string = N_("2 Front 2 Rear");
197                 var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val );
198             }
199         }
200     }
201 #endif
202
203     /* Test for stereo. */
204     i_nb_channels = 2;
205     if( ioctl( p_sys->i_fd, SNDCTL_DSP_CHANNELS, &i_nb_channels ) >= 0
206          && i_nb_channels == 2 )
207     {
208         val.psz_string = N_("Stereo");
209         var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val );
210     }
211
212     /* Reset all. */
213     i_format = AFMT_S16_NE;
214     if( ioctl( p_sys->i_fd, SNDCTL_DSP_RESET, NULL ) < 0 ||
215         ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0 )
216     {
217         msg_Err( p_aout, "cannot reset OSS audio device" );
218         var_Destroy( p_aout, "audio-device" );
219         return;
220     }
221
222     /* Test for mono. */
223     i_nb_channels = 1;
224     if( ioctl( p_sys->i_fd, SNDCTL_DSP_CHANNELS, &i_nb_channels ) >= 0
225          && i_nb_channels == 1 )
226     {
227         val.psz_string = N_("Mono");
228         var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val );
229         if ( p_aout->output.output.i_physical_channels == AOUT_CHAN_CENTER )
230         {
231             var_Set( p_aout, "audio-device", val );
232         }
233     }
234
235
236     var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart,
237                      NULL );
238 }
239
240 /*****************************************************************************
241  * Open: open the audio device (the digital sound processor)
242  *****************************************************************************
243  * This function opens the dsp as a usual non-blocking write-only file, and
244  * modifies the p_aout->p_sys->i_fd with the file's descriptor.
245  *****************************************************************************/
246 static int Open( vlc_object_t *p_this )
247 {
248     aout_instance_t * p_aout = (aout_instance_t *)p_this;
249     struct aout_sys_t * p_sys;
250     char * psz_device;
251     vlc_value_t val;
252
253     /* Allocate structure */
254     p_aout->output.p_sys = p_sys = malloc( sizeof( aout_sys_t ) );
255     if( p_sys == NULL )
256     {
257         msg_Err( p_aout, "out of memory" );
258         return VLC_ENOMEM;
259     }
260
261     /* Get device name */
262     if( (psz_device = config_GetPsz( p_aout, "dspdev" )) == NULL )
263     {
264         msg_Err( p_aout, "no audio device given (maybe /dev/dsp ?)" );
265         free( p_sys );
266         return VLC_EGENERIC;
267     }
268
269     /* Open the sound device */
270     p_sys->i_fd = open( psz_device, O_WRONLY | O_NDELAY );
271     if( p_sys->i_fd < 0 )
272     {
273         msg_Err( p_aout, "cannot open audio device (%s)", psz_device );
274         free( p_sys );
275         return VLC_EGENERIC;
276     }
277
278     /* if the opening was ok, put the device back in blocking mode */
279     fcntl( p_sys->i_fd, F_SETFL,
280             fcntl( p_sys->i_fd, F_GETFL ) &~ FNDELAY );
281
282     free( psz_device );
283
284     p_aout->output.pf_play = Play;
285
286     if ( var_Type( p_aout, "audio-device" ) == 0 )
287     {
288         Probe( p_aout );
289     }
290
291     if ( var_Get( p_aout, "audio-device", &val ) < 0 )
292     {
293         /* Probe() has failed. */
294         free( p_sys );
295         return VLC_EGENERIC;
296     }
297
298     if ( !strcmp( val.psz_string, N_("A/52 over S/PDIF") ) )
299     {
300         p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i');
301     }
302     else if ( !strcmp( val.psz_string, N_("5.1") ) )
303     {
304         p_aout->output.output.i_format = AOUT_FMT_S16_NE;
305         p_aout->output.output.i_physical_channels
306             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
307                | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARLEFT
308                | AOUT_CHAN_LFE;
309     }
310     else if ( !strcmp( val.psz_string, N_("2 Front 2 Rear") ) )
311     {
312         p_aout->output.output.i_format = AOUT_FMT_S16_NE;
313         p_aout->output.output.i_physical_channels
314             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
315                | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARLEFT;
316     }
317     else if ( !strcmp( val.psz_string, N_("Stereo") ) )
318     {
319         p_aout->output.output.i_format = AOUT_FMT_S16_NE;
320         p_aout->output.output.i_physical_channels
321             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
322     }
323     else if ( !strcmp( val.psz_string, N_("Mono") ) )
324     {
325         p_aout->output.output.i_format = AOUT_FMT_S16_NE;
326         p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
327     }
328     else
329     {
330         /* This should not happen ! */
331         msg_Err( p_aout, "internal: can't find audio-device (%s)",
332                  val.psz_string );
333         free( p_sys );
334         free( val.psz_string );
335         return VLC_EGENERIC;
336     }
337     free( val.psz_string );
338
339     val.b_bool = VLC_TRUE;
340     var_Set( p_aout, "intf-change", val );
341
342     /* Reset the DSP device */
343     if( ioctl( p_sys->i_fd, SNDCTL_DSP_RESET, NULL ) < 0 )
344     {
345         msg_Err( p_aout, "cannot reset OSS audio device" );
346         close( p_sys->i_fd );
347         free( p_sys );
348         return VLC_EGENERIC;
349     }
350
351     /* Set the output format */
352     if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
353     {
354         int i_format = AFMT_AC3;
355
356         if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0
357              || i_format != AFMT_AC3 )
358         {
359             msg_Err( p_aout, "cannot reset OSS audio device" );
360             close( p_sys->i_fd );
361             free( p_sys );
362             return VLC_EGENERIC;
363         }
364
365         p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i');
366         p_aout->output.i_nb_samples = A52_FRAME_NB;
367         p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
368         p_aout->output.output.i_frame_length = A52_FRAME_NB;
369
370         aout_VolumeNoneInit( p_aout );
371     }
372
373     if ( !AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
374     {
375         unsigned int i_format = AFMT_S16_NE;
376         unsigned int i_frame_size, i_fragments;
377         unsigned int i_rate;
378         unsigned int i_nb_channels;
379         audio_buf_info audio_buf;
380
381         if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0 )
382         {
383             msg_Err( p_aout, "cannot set audio output format" );
384             close( p_sys->i_fd );
385             free( p_sys );
386             return VLC_EGENERIC;
387         }
388
389         switch ( i_format )
390         {
391         case AFMT_U8:
392             p_aout->output.output.i_format = VLC_FOURCC('u','8',' ',' ');
393             break;
394         case AFMT_S8:
395             p_aout->output.output.i_format = VLC_FOURCC('s','8',' ',' ');
396             break;
397         case AFMT_U16_LE:
398             p_aout->output.output.i_format = VLC_FOURCC('u','1','6','l');
399             break;
400         case AFMT_S16_LE:
401             p_aout->output.output.i_format = VLC_FOURCC('s','1','6','l');
402             break;
403         case AFMT_U16_BE:
404             p_aout->output.output.i_format = VLC_FOURCC('u','1','6','b');
405             break;
406         case AFMT_S16_BE:
407             p_aout->output.output.i_format = VLC_FOURCC('s','1','6','b');
408             break;
409         default:
410             msg_Err( p_aout, "OSS fell back to an unknown format (%d)",
411                      i_format );
412             close( p_sys->i_fd );
413             free( p_sys );
414             return VLC_EGENERIC;
415         }
416
417         i_nb_channels = aout_FormatNbChannels( &p_aout->output.output );
418
419         /* Set the number of channels */
420         if( ioctl( p_sys->i_fd, SNDCTL_DSP_CHANNELS, &i_nb_channels ) < 0 ||
421             i_nb_channels != aout_FormatNbChannels( &p_aout->output.output ) )
422         {
423             msg_Err( p_aout, "cannot set number of audio channels (%s)",
424                      aout_FormatPrintChannels( &p_aout->output.output) );
425             close( p_sys->i_fd );
426             free( p_sys );
427             return VLC_EGENERIC;
428         }
429
430         /* Set the output rate */
431         i_rate = p_aout->output.output.i_rate;
432         if( ioctl( p_sys->i_fd, SNDCTL_DSP_SPEED, &i_rate ) < 0 )
433         {
434             msg_Err( p_aout, "cannot set audio output rate (%i)",
435                              p_aout->output.output.i_rate );
436             close( p_sys->i_fd );
437             free( p_sys );
438             return VLC_EGENERIC;
439         }
440
441         if( i_rate != p_aout->output.output.i_rate )
442         {
443             p_aout->output.output.i_rate = i_rate;
444         }
445
446         /* Set the fragment size */
447         aout_FormatPrepare( &p_aout->output.output );
448
449         /* i_fragment = xxxxyyyy where: xxxx        is fragtotal
450          *                              1 << yyyy   is fragsize */
451         i_fragments = 0;
452         i_frame_size = FRAME_SIZE * p_aout->output.output.i_bytes_per_frame;
453         while( i_frame_size >>= 1 )
454         {
455             ++i_fragments;
456         }
457         i_fragments |= FRAME_COUNT << 16;
458         if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFRAGMENT, &i_fragments ) < 0 )
459         {
460             msg_Warn( p_aout, "cannot set fragment size (%.8x)", i_fragments );
461         }
462
463         if( ioctl( p_sys->i_fd, SNDCTL_DSP_GETOSPACE, &audio_buf ) < 0 )
464         {
465             msg_Err( p_aout, "cannot get fragment size" );
466             close( p_sys->i_fd );
467             free( p_sys );
468             return VLC_EGENERIC;
469         }
470         else
471         {
472             /* Number of fragments actually allocated */
473             p_aout->output.p_sys->i_fragstotal = audio_buf.fragstotal;
474
475             /* Maximum duration the soundcard's buffer can hold */
476             p_aout->output.p_sys->max_buffer_duration =
477                 (mtime_t)audio_buf.fragstotal * audio_buf.fragsize * 1000000
478                 / p_aout->output.output.i_bytes_per_frame
479                 / p_aout->output.output.i_rate
480                 * p_aout->output.output.i_frame_length;
481
482             p_aout->output.i_nb_samples = audio_buf.fragsize /
483                 p_aout->output.output.i_bytes_per_frame;
484         }
485
486         aout_VolumeSoftInit( p_aout );
487     }
488
489     p_aout->output.p_sys->b_workaround_buggy_driver =
490         config_GetInt( p_aout, "oss-buggy" );
491
492     /* Create OSS thread and wait for its readiness. */
493     if( vlc_thread_create( p_aout, "aout", OSSThread,
494                            VLC_THREAD_PRIORITY_OUTPUT, VLC_FALSE ) )
495     {
496         msg_Err( p_aout, "cannot create OSS thread (%s)", strerror(errno) );
497         close( p_sys->i_fd );
498         free( p_sys );
499         return VLC_ETHREAD;
500     }
501
502     return VLC_SUCCESS;
503 }
504
505 /*****************************************************************************
506  * Play: nothing to do
507  *****************************************************************************/
508 static void Play( aout_instance_t *p_aout )
509 {
510 }
511
512 /*****************************************************************************
513  * Close: close the dsp audio device
514  *****************************************************************************/
515 static void Close( vlc_object_t * p_this )
516 {
517     aout_instance_t *p_aout = (aout_instance_t *)p_this;
518     struct aout_sys_t * p_sys = p_aout->output.p_sys;
519
520     p_aout->b_die = VLC_TRUE;
521     vlc_thread_join( p_aout );
522     p_aout->b_die = VLC_FALSE;
523
524     ioctl( p_sys->i_fd, SNDCTL_DSP_RESET, NULL );
525     close( p_sys->i_fd );
526
527     free( p_sys );
528 }
529
530 /*****************************************************************************
531  * BufferDuration: buffer status query
532  *****************************************************************************
533  * This function returns the duration in microseconds of the current buffer.
534  *****************************************************************************/
535 static mtime_t BufferDuration( aout_instance_t * p_aout )
536 {
537     struct aout_sys_t * p_sys = p_aout->output.p_sys;
538     audio_buf_info audio_buf;
539     int i_bytes;
540
541     /* Fill the audio_buf_info structure:
542      * - fragstotal: total number of fragments allocated
543      * - fragsize: size of a fragment in bytes
544      * - bytes: available space in bytes (includes partially used fragments)
545      * Note! 'bytes' could be more than fragments*fragsize */
546     ioctl( p_sys->i_fd, SNDCTL_DSP_GETOSPACE, &audio_buf );
547
548     /* calculate number of available fragments (not partially used ones) */
549     i_bytes = (audio_buf.fragstotal * audio_buf.fragsize) - audio_buf.bytes;
550
551     /* Return the fragment duration */
552     return (mtime_t)i_bytes * 1000000
553             / p_aout->output.output.i_bytes_per_frame
554             / p_aout->output.output.i_rate
555             * p_aout->output.output.i_frame_length;
556 }
557
558 /*****************************************************************************
559  * OSSThread: asynchronous thread used to DMA the data to the device
560  *****************************************************************************/
561 static int OSSThread( aout_instance_t * p_aout )
562 {
563     struct aout_sys_t * p_sys = p_aout->output.p_sys;
564     mtime_t next_date = 0;
565
566     while ( !p_aout->b_die )
567     {
568         aout_buffer_t * p_buffer = NULL;
569         int i_tmp, i_size;
570         byte_t * p_bytes;
571
572         if ( p_aout->output.output.i_format != VLC_FOURCC('s','p','d','i') )
573         {
574             mtime_t buffered = BufferDuration( p_aout );
575
576             if( p_aout->output.p_sys->b_workaround_buggy_driver )
577             {
578 #define i_fragstotal p_aout->output.p_sys->i_fragstotal
579                 /* Wait a bit - we don't want our buffer to be full */
580                 if( buffered > (p_aout->output.p_sys->max_buffer_duration
581                                 / i_fragstotal * (i_fragstotal - 1)) )
582                 {
583                     msleep((p_aout->output.p_sys->max_buffer_duration
584                                 / i_fragstotal ));
585                     buffered = BufferDuration( p_aout );
586                 }
587 #undef i_fragstotal
588             }
589
590             /* Next buffer will be played at mdate() + buffered */
591             p_buffer = aout_OutputNextBuffer( p_aout, mdate() + buffered,
592                                               VLC_FALSE );
593
594             if( p_buffer == NULL &&
595                 buffered > ( p_aout->output.p_sys->max_buffer_duration
596                              / p_aout->output.p_sys->i_fragstotal ) )
597             {
598                 /* If we have at least a fragment full, then we can wait a
599                  * little and retry to get a new audio buffer instead of
600                  * playing a blank sample */
601                 msleep( ( p_aout->output.p_sys->max_buffer_duration
602                           / p_aout->output.p_sys->i_fragstotal / 2 ) );
603                 continue;
604             }
605         }
606         else
607         {
608             /* emu10k1 driver does not report Buffer Duration correctly in
609              * passthrough mode so we have to cheat */
610             if( !next_date )
611             {
612                 next_date = mdate();
613             }
614             else
615             {
616                 mtime_t delay = next_date - mdate();
617                 if( delay > AOUT_PTS_TOLERANCE )
618                 {
619                     msleep( delay / 2 );
620                 }
621             }
622
623             while( !p_aout->b_die && ! ( p_buffer =
624                 aout_OutputNextBuffer( p_aout, next_date, VLC_TRUE ) ) )
625             {
626                 msleep( 1000 );
627                 next_date = mdate();
628             }
629         }
630
631         if ( p_buffer != NULL )
632         {
633             p_bytes = p_buffer->p_buffer;
634             i_size = p_buffer->i_nb_bytes;
635             /* This is theoretical ... we'll see next iteration whether
636              * we're drifting */
637             next_date += p_buffer->end_date - p_buffer->start_date;
638         }
639         else
640         {
641             i_size = FRAME_SIZE / p_aout->output.output.i_frame_length
642                       * p_aout->output.output.i_bytes_per_frame;
643             p_bytes = malloc( i_size );
644             memset( p_bytes, 0, i_size );
645             next_date = 0;
646         }
647
648         i_tmp = write( p_sys->i_fd, p_bytes, i_size );
649
650         if( i_tmp < 0 )
651         {
652             msg_Err( p_aout, "write failed (%s)", strerror(errno) );
653         }
654
655         if ( p_buffer != NULL )
656         {
657             aout_BufferFree( p_buffer );
658         }
659         else
660         {
661             free( p_bytes );
662         }
663     }
664
665     return VLC_SUCCESS;
666 }