]> git.sesse.net Git - vlc/blob - modules/audio_output/oss.c
Fixed AFMT_AC3 and AFMT_S16_NE handling.
[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.50 2003/02/06 15:14:41 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         return VLC_EGENERIC;
335     }
336     free( val.psz_string );
337
338     val.b_bool = VLC_TRUE;
339     var_Set( p_aout, "intf-change", val );
340
341     /* Reset the DSP device */
342     if( ioctl( p_sys->i_fd, SNDCTL_DSP_RESET, NULL ) < 0 )
343     {
344         msg_Err( p_aout, "cannot reset OSS audio device" );
345         close( p_sys->i_fd );
346         free( p_sys );
347         return VLC_EGENERIC;
348     }
349
350     /* Set the output format */
351     if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
352     {
353         int i_format = AFMT_AC3;
354
355         if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0
356              || i_format != AFMT_AC3 )
357         {
358             msg_Err( p_aout, "cannot reset OSS audio device" );
359             close( p_sys->i_fd );
360             free( p_sys );
361             return VLC_EGENERIC;
362         }
363
364         p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i');
365         p_aout->output.i_nb_samples = A52_FRAME_NB;
366         p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
367         p_aout->output.output.i_frame_length = A52_FRAME_NB;
368
369         aout_VolumeNoneInit( p_aout );
370     }
371
372     if ( !AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
373     {
374         unsigned int i_format = AFMT_S16_NE;
375         unsigned int i_frame_size, i_fragments;
376         unsigned int i_rate;
377         unsigned int i_nb_channels;
378         audio_buf_info audio_buf;
379
380         if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0 )
381         {
382             msg_Err( p_aout, "cannot set audio output format" );
383             close( p_sys->i_fd );
384             free( p_sys );
385             return VLC_EGENERIC;
386         }
387
388         switch ( i_format )
389         {
390         case AFMT_U8:
391             p_aout->output.output.i_format = VLC_FOURCC('u','8',' ',' ');
392             break;
393         case AFMT_S8:
394             p_aout->output.output.i_format = VLC_FOURCC('s','8',' ',' ');
395             break;
396         case AFMT_U16_LE:
397             p_aout->output.output.i_format = VLC_FOURCC('u','1','6','l');
398             break;
399         case AFMT_S16_LE:
400             p_aout->output.output.i_format = VLC_FOURCC('s','1','6','l');
401             break;
402         case AFMT_U16_BE:
403             p_aout->output.output.i_format = VLC_FOURCC('u','1','6','b');
404             break;
405         case AFMT_S16_BE:
406             p_aout->output.output.i_format = VLC_FOURCC('s','1','6','b');
407             break;
408         default:
409             msg_Err( p_aout, "OSS fell back to an unknown format (%d)",
410                      i_format );
411             close( p_sys->i_fd );
412             free( p_sys );
413             return VLC_EGENERIC;
414         }
415
416         i_nb_channels = aout_FormatNbChannels( &p_aout->output.output );
417
418         /* Set the number of channels */
419         if( ioctl( p_sys->i_fd, SNDCTL_DSP_CHANNELS, &i_nb_channels ) < 0 ||
420             i_nb_channels != aout_FormatNbChannels( &p_aout->output.output ) )
421         {
422             msg_Err( p_aout, "cannot set number of audio channels (%s)",
423                      aout_FormatPrintChannels( &p_aout->output.output) );
424             close( p_sys->i_fd );
425             free( p_sys );
426             return VLC_EGENERIC;
427         }
428
429         /* Set the output rate */
430         i_rate = p_aout->output.output.i_rate;
431         if( ioctl( p_sys->i_fd, SNDCTL_DSP_SPEED, &i_rate ) < 0 )
432         {
433             msg_Err( p_aout, "cannot set audio output rate (%i)",
434                              p_aout->output.output.i_rate );
435             close( p_sys->i_fd );
436             free( p_sys );
437             return VLC_EGENERIC;
438         }
439
440         if( i_rate != p_aout->output.output.i_rate )
441         {
442             p_aout->output.output.i_rate = i_rate;
443         }
444
445         /* Set the fragment size */
446         aout_FormatPrepare( &p_aout->output.output );
447
448         /* i_fragment = xxxxyyyy where: xxxx        is fragtotal
449          *                              1 << yyyy   is fragsize */
450         i_fragments = 0;
451         i_frame_size = FRAME_SIZE * p_aout->output.output.i_bytes_per_frame;
452         while( i_frame_size >>= 1 )
453         {
454             ++i_fragments;
455         }
456         i_fragments |= FRAME_COUNT << 16;
457         if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFRAGMENT, &i_fragments ) < 0 )
458         {
459             msg_Warn( p_aout, "cannot set fragment size (%.8x)", i_fragments );
460         }
461
462         if( ioctl( p_sys->i_fd, SNDCTL_DSP_GETOSPACE, &audio_buf ) < 0 )
463         {
464             msg_Err( p_aout, "cannot get fragment size" );
465             close( p_sys->i_fd );
466             free( p_sys );
467             return VLC_EGENERIC;
468         }
469         else
470         {
471             /* Number of fragments actually allocated */
472             p_aout->output.p_sys->i_fragstotal = audio_buf.fragstotal;
473
474             /* Maximum duration the soundcard's buffer can hold */
475             p_aout->output.p_sys->max_buffer_duration =
476                 (mtime_t)audio_buf.fragstotal * audio_buf.fragsize * 1000000
477                 / p_aout->output.output.i_bytes_per_frame
478                 / p_aout->output.output.i_rate
479                 * p_aout->output.output.i_frame_length;
480
481             p_aout->output.i_nb_samples = audio_buf.fragsize /
482                 p_aout->output.output.i_bytes_per_frame;
483         }
484
485         aout_VolumeSoftInit( p_aout );
486     }
487
488     p_aout->output.p_sys->b_workaround_buggy_driver =
489         config_GetInt( p_aout, "oss-buggy" );
490
491     /* Create OSS thread and wait for its readiness. */
492     if( vlc_thread_create( p_aout, "aout", OSSThread,
493                            VLC_THREAD_PRIORITY_OUTPUT, VLC_FALSE ) )
494     {
495         msg_Err( p_aout, "cannot create OSS thread (%s)", strerror(errno) );
496         close( p_sys->i_fd );
497         free( p_sys );
498         return VLC_ETHREAD;
499     }
500
501     return VLC_SUCCESS;
502 }
503
504 /*****************************************************************************
505  * Play: nothing to do
506  *****************************************************************************/
507 static void Play( aout_instance_t *p_aout )
508 {
509 }
510
511 /*****************************************************************************
512  * Close: close the dsp audio device
513  *****************************************************************************/
514 static void Close( vlc_object_t * p_this )
515 {
516     aout_instance_t *p_aout = (aout_instance_t *)p_this;
517     struct aout_sys_t * p_sys = p_aout->output.p_sys;
518
519     p_aout->b_die = VLC_TRUE;
520     vlc_thread_join( p_aout );
521     p_aout->b_die = VLC_FALSE;
522
523     ioctl( p_sys->i_fd, SNDCTL_DSP_RESET, NULL );
524     close( p_sys->i_fd );
525
526     free( p_sys );
527 }
528
529 /*****************************************************************************
530  * BufferDuration: buffer status query
531  *****************************************************************************
532  * This function returns the duration in microseconds of the current buffer.
533  *****************************************************************************/
534 static mtime_t BufferDuration( aout_instance_t * p_aout )
535 {
536     struct aout_sys_t * p_sys = p_aout->output.p_sys;
537     audio_buf_info audio_buf;
538     int i_bytes;
539
540     /* Fill the audio_buf_info structure:
541      * - fragstotal: total number of fragments allocated
542      * - fragsize: size of a fragment in bytes
543      * - bytes: available space in bytes (includes partially used fragments)
544      * Note! 'bytes' could be more than fragments*fragsize */
545     ioctl( p_sys->i_fd, SNDCTL_DSP_GETOSPACE, &audio_buf );
546
547     /* calculate number of available fragments (not partially used ones) */
548     i_bytes = (audio_buf.fragstotal * audio_buf.fragsize) - audio_buf.bytes;
549
550     /* Return the fragment duration */
551     return (mtime_t)i_bytes * 1000000
552             / p_aout->output.output.i_bytes_per_frame
553             / p_aout->output.output.i_rate
554             * p_aout->output.output.i_frame_length;
555 }
556
557 /*****************************************************************************
558  * OSSThread: asynchronous thread used to DMA the data to the device
559  *****************************************************************************/
560 static int OSSThread( aout_instance_t * p_aout )
561 {
562     struct aout_sys_t * p_sys = p_aout->output.p_sys;
563     mtime_t next_date = 0;
564
565     while ( !p_aout->b_die )
566     {
567         aout_buffer_t * p_buffer = NULL;
568         int i_tmp, i_size;
569         byte_t * p_bytes;
570
571         if ( p_aout->output.output.i_format != VLC_FOURCC('s','p','d','i') )
572         {
573             mtime_t buffered = BufferDuration( p_aout );
574
575             if( p_aout->output.p_sys->b_workaround_buggy_driver )
576             {
577 #define i_fragstotal p_aout->output.p_sys->i_fragstotal
578                 /* Wait a bit - we don't want our buffer to be full */
579                 if( buffered > (p_aout->output.p_sys->max_buffer_duration
580                                 / i_fragstotal * (i_fragstotal - 1)) )
581                 {
582                     msleep((p_aout->output.p_sys->max_buffer_duration
583                                 / i_fragstotal ));
584                     buffered = BufferDuration( p_aout );
585                 }
586 #undef i_fragstotal
587             }
588
589             /* Next buffer will be played at mdate() + buffered */
590             p_buffer = aout_OutputNextBuffer( p_aout, mdate() + buffered,
591                                               VLC_FALSE );
592
593             if( p_buffer == NULL &&
594                 buffered > ( p_aout->output.p_sys->max_buffer_duration
595                              / p_aout->output.p_sys->i_fragstotal ) )
596             {
597                 /* If we have at least a fragment full, then we can wait a
598                  * little and retry to get a new audio buffer instead of
599                  * playing a blank sample */
600                 msleep( ( p_aout->output.p_sys->max_buffer_duration
601                           / p_aout->output.p_sys->i_fragstotal / 2 ) );
602                 continue;
603             }
604         }
605         else
606         {
607             /* emu10k1 driver does not report Buffer Duration correctly in
608              * passthrough mode so we have to cheat */
609             if( !next_date )
610             {
611                 next_date = mdate();
612             }
613             else
614             {
615                 mtime_t delay = next_date - mdate();
616                 if( delay > AOUT_PTS_TOLERANCE )
617                 {
618                     msleep( delay / 2 );
619                 }
620             }
621
622             while( !p_aout->b_die && ! ( p_buffer =
623                 aout_OutputNextBuffer( p_aout, next_date, VLC_TRUE ) ) )
624             {
625                 msleep( 1000 );
626                 next_date = mdate();
627             }
628         }
629
630         if ( p_buffer != NULL )
631         {
632             p_bytes = p_buffer->p_buffer;
633             i_size = p_buffer->i_nb_bytes;
634             /* This is theoretical ... we'll see next iteration whether
635              * we're drifting */
636             next_date += p_buffer->end_date - p_buffer->start_date;
637         }
638         else
639         {
640             i_size = FRAME_SIZE / p_aout->output.output.i_frame_length
641                       * p_aout->output.output.i_bytes_per_frame;
642             p_bytes = malloc( i_size );
643             memset( p_bytes, 0, i_size );
644             next_date = 0;
645         }
646
647         i_tmp = write( p_sys->i_fd, p_bytes, i_size );
648
649         if( i_tmp < 0 )
650         {
651             msg_Err( p_aout, "write failed (%s)", strerror(errno) );
652         }
653
654         if ( p_buffer != NULL )
655         {
656             aout_BufferFree( p_buffer );
657         }
658         else
659         {
660             free( p_bytes );
661         }
662     }
663
664     return VLC_SUCCESS;
665 }