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