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