Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

oss.c

00001 /*****************************************************************************
00002  * oss.c : OSS /dev/dsp module for vlc
00003  *****************************************************************************
00004  * Copyright (C) 2000-2002 the VideoLAN team
00005  * $Id: oss.c 11664 2005-07-09 06:17:09Z courmisch $
00006  *
00007  * Authors: Michel Kaempf <[email protected]>
00008  *          Sam Hocevar <[email protected]>
00009  *          Christophe Massiot <[email protected]>
00010  *
00011  * This program is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2 of the License, or
00014  * (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software
00023  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00024  *****************************************************************************/
00025 
00026 /*****************************************************************************
00027  * Preamble
00028  *****************************************************************************/
00029 #include <errno.h>                                                 /* ENOMEM */
00030 #include <fcntl.h>                                       /* open(), O_WRONLY */
00031 #include <sys/ioctl.h>                                            /* ioctl() */
00032 #include <string.h>                                            /* strerror() */
00033 #include <unistd.h>                                      /* write(), close() */
00034 #include <stdlib.h>                            /* calloc(), malloc(), free() */
00035 
00036 #include <vlc/vlc.h>
00037 
00038 #ifdef HAVE_ALLOCA_H
00039 #   include <alloca.h>
00040 #endif
00041 
00042 #include <vlc/aout.h>
00043 
00044 #include "aout_internal.h"
00045 
00046 /* SNDCTL_DSP_RESET, SNDCTL_DSP_SETFMT, SNDCTL_DSP_STEREO, SNDCTL_DSP_SPEED,
00047  * SNDCTL_DSP_GETOSPACE */
00048 #ifdef HAVE_SOUNDCARD_H
00049 #   include <soundcard.h>
00050 #elif defined( HAVE_SYS_SOUNDCARD_H )
00051 #   include <sys/soundcard.h>
00052 #elif defined( HAVE_MACHINE_SOUNDCARD_H )
00053 #   include <machine/soundcard.h>
00054 #endif
00055 
00056 /* Patches for ignorant OSS versions */
00057 #ifndef AFMT_AC3
00058 #   define AFMT_AC3     0x00000400        /* Dolby Digital AC3 */
00059 #endif
00060 
00061 #ifndef AFMT_S16_NE
00062 #   ifdef WORDS_BIGENDIAN
00063 #       define AFMT_S16_NE AFMT_S16_BE
00064 #   else
00065 #       define AFMT_S16_NE AFMT_S16_LE
00066 #   endif
00067 #endif
00068 
00069 /*****************************************************************************
00070  * aout_sys_t: OSS audio output method descriptor
00071  *****************************************************************************
00072  * This structure is part of the audio output thread descriptor.
00073  * It describes the DSP specific properties of an audio device.
00074  *****************************************************************************/
00075 struct aout_sys_t
00076 {
00077     int i_fd;
00078     int b_workaround_buggy_driver;
00079     int i_fragstotal;
00080     mtime_t max_buffer_duration;
00081 };
00082 
00083 /* This must be a power of 2. */
00084 #define FRAME_SIZE 1024
00085 #define FRAME_COUNT 4
00086 
00087 /*****************************************************************************
00088  * Local prototypes
00089  *****************************************************************************/
00090 static int  Open         ( vlc_object_t * );
00091 static void Close        ( vlc_object_t * );
00092 
00093 static void Play         ( aout_instance_t * );
00094 static int  OSSThread    ( aout_instance_t * );
00095 
00096 static mtime_t BufferDuration( aout_instance_t * p_aout );
00097 
00098 /*****************************************************************************
00099  * Module descriptor
00100  *****************************************************************************/
00101 #define BUGGY_TEXT N_("Try to work around buggy OSS drivers")
00102 #define BUGGY_LONGTEXT N_( \
00103     "Some buggy OSS drivers just don't like when their internal buffers " \
00104     "are completely filled (the sound gets heavily hashed). If you have one " \
00105     "of these drivers, then you need to enable this option." )
00106 
00107 vlc_module_begin();
00108     set_shortname( "OSS" );
00109     set_description( _("Linux OSS audio output") );
00110 
00111     set_category( CAT_AUDIO );
00112     set_subcategory( SUBCAT_AUDIO_AOUT );
00113     add_file( "dspdev", "/dev/dsp", aout_FindAndRestart,
00114               N_("OSS DSP device"), NULL, VLC_FALSE );
00115     add_bool( "oss-buggy", 0, NULL, BUGGY_TEXT, BUGGY_LONGTEXT, VLC_TRUE );
00116 
00117     set_capability( "audio output", 100 );
00118     add_shortcut( "oss" );
00119     set_callbacks( Open, Close );
00120 vlc_module_end();
00121 
00122 /*****************************************************************************
00123  * Probe: probe the audio device for available formats and channels
00124  *****************************************************************************/
00125 static void Probe( aout_instance_t * p_aout )
00126 {
00127     struct aout_sys_t * p_sys = p_aout->output.p_sys;
00128     vlc_value_t val, text;
00129     int i_format, i_nb_channels;
00130 
00131     var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
00132     text.psz_string = _("Audio Device");
00133     var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
00134 
00135     /* Test for multi-channel. */
00136 #ifdef SNDCTL_DSP_GETCHANNELMASK
00137     if ( aout_FormatNbChannels( &p_aout->output.output ) > 2 )
00138     {
00139         /* Check that the device supports this. */
00140 
00141         int i_chanmask;
00142 
00143         /* Reset all. */
00144         i_format = AFMT_S16_NE;
00145         if( ioctl( p_sys->i_fd, SNDCTL_DSP_RESET, NULL ) < 0 ||
00146             ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0 )
00147         {
00148             msg_Err( p_aout, "cannot reset OSS audio device" );
00149             var_Destroy( p_aout, "audio-device" );
00150             return;
00151         }
00152 
00153         if ( ioctl( p_sys->i_fd, SNDCTL_DSP_GETCHANNELMASK,
00154                     &i_chanmask ) == 0 )
00155         {
00156             if ( !(i_chanmask & DSP_BIND_FRONT) )
00157             {
00158                 msg_Err( p_aout, "No front channels ! (%x)",
00159                          i_chanmask );
00160                 return;
00161             }
00162 
00163             if ( (i_chanmask & (DSP_BIND_SURR | DSP_BIND_CENTER_LFE))
00164                   && (p_aout->output.output.i_physical_channels ==
00165                        (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
00166                          | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
00167                          | AOUT_CHAN_LFE)) )
00168             {
00169                 val.i_int = AOUT_VAR_5_1;
00170                 text.psz_string = N_("5.1");
00171                 var_Change( p_aout, "audio-device",
00172                             VLC_VAR_ADDCHOICE, &val, &text );
00173             }
00174 
00175             if ( (i_chanmask & DSP_BIND_SURR)
00176                   && (p_aout->output.output.i_physical_channels &
00177                        (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
00178                          | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT)) )
00179             {
00180                 val.i_int = AOUT_VAR_2F2R;
00181                 text.psz_string = N_("2 Front 2 Rear");
00182                 var_Change( p_aout, "audio-device",
00183                             VLC_VAR_ADDCHOICE, &val, &text );
00184             }
00185         }
00186     }
00187 #endif
00188 
00189     /* Reset all. */
00190     i_format = AFMT_S16_NE;
00191     if( ioctl( p_sys->i_fd, SNDCTL_DSP_RESET, NULL ) < 0 ||
00192         ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0 )
00193     {
00194         msg_Err( p_aout, "cannot reset OSS audio device" );
00195         var_Destroy( p_aout, "audio-device" );
00196         return;
00197     }
00198 
00199     /* Test for stereo. */
00200     i_nb_channels = 2;
00201     if( ioctl( p_sys->i_fd, SNDCTL_DSP_CHANNELS, &i_nb_channels ) >= 0
00202          && i_nb_channels == 2 )
00203     {
00204         val.i_int = AOUT_VAR_STEREO;
00205         text.psz_string = N_("Stereo");
00206         var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
00207     }
00208 
00209     /* Reset all. */
00210     i_format = AFMT_S16_NE;
00211     if( ioctl( p_sys->i_fd, SNDCTL_DSP_RESET, NULL ) < 0 ||
00212         ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0 )
00213     {
00214         msg_Err( p_aout, "cannot reset OSS audio device" );
00215         var_Destroy( p_aout, "audio-device" );
00216         return;
00217     }
00218 
00219     /* Test for mono. */
00220     i_nb_channels = 1;
00221     if( ioctl( p_sys->i_fd, SNDCTL_DSP_CHANNELS, &i_nb_channels ) >= 0
00222          && i_nb_channels == 1 )
00223     {
00224         val.i_int = AOUT_VAR_MONO;
00225         text.psz_string = N_("Mono");
00226         var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
00227         if ( p_aout->output.output.i_physical_channels == AOUT_CHAN_CENTER )
00228         {
00229             var_Set( p_aout, "audio-device", val );
00230         }
00231     }
00232 
00233     if( ioctl( p_sys->i_fd, SNDCTL_DSP_RESET, NULL ) < 0 )
00234     {
00235         msg_Err( p_aout, "cannot reset OSS audio device" );
00236         var_Destroy( p_aout, "audio-device" );
00237         return;
00238     }
00239 
00240     /* Test for spdif. */
00241     if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
00242     {
00243         i_format = AFMT_AC3;
00244 
00245         if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) >= 0
00246              && i_format == AFMT_AC3 )
00247         {
00248             val.i_int = AOUT_VAR_SPDIF;
00249             text.psz_string = N_("A/52 over S/PDIF");
00250             var_Change( p_aout, "audio-device",
00251                         VLC_VAR_ADDCHOICE, &val, &text );
00252             if( config_GetInt( p_aout, "spdif" ) )
00253                 var_Set( p_aout, "audio-device", val );
00254         }
00255         else if( config_GetInt( p_aout, "spdif" ) )
00256         {
00257             msg_Warn( p_aout, "s/pdif not supported by card" );
00258         }
00259     }
00260 
00261     var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart,
00262                      NULL );
00263 }
00264 
00265 /*****************************************************************************
00266  * Open: open the audio device (the digital sound processor)
00267  *****************************************************************************
00268  * This function opens the DSP as a usual non-blocking write-only file, and
00269  * modifies the p_aout->p_sys->i_fd with the file's descriptor.
00270  *****************************************************************************/
00271 static int Open( vlc_object_t *p_this )
00272 {
00273     aout_instance_t * p_aout = (aout_instance_t *)p_this;
00274     struct aout_sys_t * p_sys;
00275     char * psz_device;
00276     vlc_value_t val;
00277 
00278     /* Allocate structure */
00279     p_aout->output.p_sys = p_sys = malloc( sizeof( aout_sys_t ) );
00280     if( p_sys == NULL )
00281     {
00282         msg_Err( p_aout, "out of memory" );
00283         return VLC_ENOMEM;
00284     }
00285 
00286     /* Get device name */
00287     if( (psz_device = config_GetPsz( p_aout, "dspdev" )) == NULL )
00288     {
00289         msg_Err( p_aout, "no audio device specified (maybe /dev/dsp?)" );
00290         free( p_sys );
00291         return VLC_EGENERIC;
00292     }
00293 
00294     /* Open the sound device in non-blocking mode, because ALSA's OSS
00295      * emulation and some broken OSS drivers would make a blocking call
00296      * wait forever until the device is available. Since this breaks the
00297      * OSS spec, we immediately put it back to blocking mode if the
00298      * operation was successful. */
00299     p_sys->i_fd = open( psz_device, O_WRONLY | O_NDELAY );
00300     if( p_sys->i_fd < 0 )
00301     {
00302         msg_Err( p_aout, "cannot open audio device (%s)", psz_device );
00303         free( p_sys );
00304         return VLC_EGENERIC;
00305     }
00306 
00307     /* if the opening was ok, put the device back in blocking mode */
00308     fcntl( p_sys->i_fd, F_SETFL,
00309             fcntl( p_sys->i_fd, F_GETFL ) &~ FNDELAY );
00310 
00311     free( psz_device );
00312 
00313     p_aout->output.pf_play = Play;
00314 
00315     if ( var_Type( p_aout, "audio-device" ) == 0 )
00316     {
00317         Probe( p_aout );
00318     }
00319 
00320     if ( var_Get( p_aout, "audio-device", &val ) < 0 )
00321     {
00322         /* Probe() has failed. */
00323         free( p_sys );
00324         return VLC_EGENERIC;
00325     }
00326 
00327     if ( val.i_int == AOUT_VAR_SPDIF )
00328     {
00329         p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i');
00330     }
00331     else if ( val.i_int == AOUT_VAR_5_1 )
00332     {
00333         p_aout->output.output.i_format = AOUT_FMT_S16_NE;
00334         p_aout->output.output.i_physical_channels
00335             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
00336                | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
00337                | AOUT_CHAN_LFE;
00338     }
00339     else if ( val.i_int == AOUT_VAR_2F2R )
00340     {
00341         p_aout->output.output.i_format = AOUT_FMT_S16_NE;
00342         p_aout->output.output.i_physical_channels
00343             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
00344                | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
00345     }
00346     else if ( val.i_int == AOUT_VAR_STEREO )
00347     {
00348         p_aout->output.output.i_format = AOUT_FMT_S16_NE;
00349         p_aout->output.output.i_physical_channels
00350             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
00351     }
00352     else if ( val.i_int == AOUT_VAR_MONO )
00353     {
00354         p_aout->output.output.i_format = AOUT_FMT_S16_NE;
00355         p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
00356     }
00357     else
00358     {
00359         /* This should not happen ! */
00360         msg_Err( p_aout, "internal: can't find audio-device (%i)", val.i_int );
00361         free( p_sys );
00362         return VLC_EGENERIC;
00363     }
00364 
00365     val.b_bool = VLC_TRUE;
00366     var_Set( p_aout, "intf-change", val );
00367 
00368     /* Reset the DSP device */
00369     if( ioctl( p_sys->i_fd, SNDCTL_DSP_RESET, NULL ) < 0 )
00370     {
00371         msg_Err( p_aout, "cannot reset OSS audio device" );
00372         close( p_sys->i_fd );
00373         free( p_sys );
00374         return VLC_EGENERIC;
00375     }
00376 
00377     /* Set the output format */
00378     if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
00379     {
00380         int i_format = AFMT_AC3;
00381 
00382         if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0
00383              || i_format != AFMT_AC3 )
00384         {
00385             msg_Err( p_aout, "cannot reset OSS audio device" );
00386             close( p_sys->i_fd );
00387             free( p_sys );
00388             return VLC_EGENERIC;
00389         }
00390 
00391         p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i');
00392         p_aout->output.i_nb_samples = A52_FRAME_NB;
00393         p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
00394         p_aout->output.output.i_frame_length = A52_FRAME_NB;
00395 
00396         aout_VolumeNoneInit( p_aout );
00397     }
00398 
00399     if ( !AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
00400     {
00401         unsigned int i_format = AFMT_S16_NE;
00402         unsigned int i_frame_size, i_fragments;
00403         unsigned int i_rate;
00404         unsigned int i_nb_channels;
00405         audio_buf_info audio_buf;
00406 
00407         if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0 )
00408         {
00409             msg_Err( p_aout, "cannot set audio output format" );
00410             close( p_sys->i_fd );
00411             free( p_sys );
00412             return VLC_EGENERIC;
00413         }
00414 
00415         switch ( i_format )
00416         {
00417         case AFMT_U8:
00418             p_aout->output.output.i_format = VLC_FOURCC('u','8',' ',' ');
00419             break;
00420         case AFMT_S8:
00421             p_aout->output.output.i_format = VLC_FOURCC('s','8',' ',' ');
00422             break;
00423         case AFMT_U16_LE:
00424             p_aout->output.output.i_format = VLC_FOURCC('u','1','6','l');
00425             break;
00426         case AFMT_S16_LE:
00427             p_aout->output.output.i_format = VLC_FOURCC('s','1','6','l');
00428             break;
00429         case AFMT_U16_BE:
00430             p_aout->output.output.i_format = VLC_FOURCC('u','1','6','b');
00431             break;
00432         case AFMT_S16_BE:
00433             p_aout->output.output.i_format = VLC_FOURCC('s','1','6','b');
00434             break;
00435         default:
00436             msg_Err( p_aout, "OSS fell back to an unknown format (%d)",
00437                      i_format );
00438             close( p_sys->i_fd );
00439             free( p_sys );
00440             return VLC_EGENERIC;
00441         }
00442 
00443         i_nb_channels = aout_FormatNbChannels( &p_aout->output.output );
00444 
00445         /* Set the number of channels */
00446         if( ioctl( p_sys->i_fd, SNDCTL_DSP_CHANNELS, &i_nb_channels ) < 0 ||
00447             i_nb_channels != aout_FormatNbChannels( &p_aout->output.output ) )
00448         {
00449             msg_Err( p_aout, "cannot set number of audio channels (%s)",
00450                      aout_FormatPrintChannels( &p_aout->output.output) );
00451             close( p_sys->i_fd );
00452             free( p_sys );
00453             return VLC_EGENERIC;
00454         }
00455 
00456         /* Set the output rate */
00457         i_rate = p_aout->output.output.i_rate;
00458         if( ioctl( p_sys->i_fd, SNDCTL_DSP_SPEED, &i_rate ) < 0 )
00459         {
00460             msg_Err( p_aout, "cannot set audio output rate (%i)",
00461                              p_aout->output.output.i_rate );
00462             close( p_sys->i_fd );
00463             free( p_sys );
00464             return VLC_EGENERIC;
00465         }
00466 
00467         if( i_rate != p_aout->output.output.i_rate )
00468         {
00469             p_aout->output.output.i_rate = i_rate;
00470         }
00471 
00472         /* Set the fragment size */
00473         aout_FormatPrepare( &p_aout->output.output );
00474 
00475         /* i_fragment = xxxxyyyy where: xxxx        is fragtotal
00476          *                              1 << yyyy   is fragsize */
00477         i_fragments = 0;
00478         i_frame_size = FRAME_SIZE * p_aout->output.output.i_bytes_per_frame;
00479         while( i_frame_size >>= 1 )
00480         {
00481             ++i_fragments;
00482         }
00483         i_fragments |= FRAME_COUNT << 16;
00484         if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFRAGMENT, &i_fragments ) < 0 )
00485         {
00486             msg_Warn( p_aout, "cannot set fragment size (%.8x)", i_fragments );
00487         }
00488 
00489         if( ioctl( p_sys->i_fd, SNDCTL_DSP_GETOSPACE, &audio_buf ) < 0 )
00490         {
00491             msg_Err( p_aout, "cannot get fragment size" );
00492             close( p_sys->i_fd );
00493             free( p_sys );
00494             return VLC_EGENERIC;
00495         }
00496         else
00497         {
00498             /* Number of fragments actually allocated */
00499             p_aout->output.p_sys->i_fragstotal = audio_buf.fragstotal;
00500 
00501             /* Maximum duration the soundcard's buffer can hold */
00502             p_aout->output.p_sys->max_buffer_duration =
00503                 (mtime_t)audio_buf.fragstotal * audio_buf.fragsize * 1000000
00504                 / p_aout->output.output.i_bytes_per_frame
00505                 / p_aout->output.output.i_rate
00506                 * p_aout->output.output.i_frame_length;
00507 
00508             p_aout->output.i_nb_samples = audio_buf.fragsize /
00509                 p_aout->output.output.i_bytes_per_frame;
00510         }
00511 
00512         aout_VolumeSoftInit( p_aout );
00513     }
00514 
00515     p_aout->output.p_sys->b_workaround_buggy_driver =
00516         config_GetInt( p_aout, "oss-buggy" );
00517 
00518     /* Create OSS thread and wait for its readiness. */
00519     if( vlc_thread_create( p_aout, "aout", OSSThread,
00520                            VLC_THREAD_PRIORITY_OUTPUT, VLC_FALSE ) )
00521     {
00522         msg_Err( p_aout, "cannot create OSS thread (%s)", strerror(errno) );
00523         close( p_sys->i_fd );
00524         free( p_sys );
00525         return VLC_ETHREAD;
00526     }
00527 
00528     return VLC_SUCCESS;
00529 }
00530 
00531 /*****************************************************************************
00532  * Play: nothing to do
00533  *****************************************************************************/
00534 static void Play( aout_instance_t *p_aout )
00535 {
00536 }
00537 
00538 /*****************************************************************************
00539  * Close: close the DSP audio device
00540  *****************************************************************************/
00541 static void Close( vlc_object_t * p_this )
00542 {
00543     aout_instance_t *p_aout = (aout_instance_t *)p_this;
00544     struct aout_sys_t * p_sys = p_aout->output.p_sys;
00545 
00546     p_aout->b_die = VLC_TRUE;
00547     vlc_thread_join( p_aout );
00548     p_aout->b_die = VLC_FALSE;
00549 
00550     ioctl( p_sys->i_fd, SNDCTL_DSP_RESET, NULL );
00551     close( p_sys->i_fd );
00552 
00553     free( p_sys );
00554 }
00555 
00556 /*****************************************************************************
00557  * BufferDuration: buffer status query
00558  *****************************************************************************
00559  * This function returns the duration in microseconds of the current buffer.
00560  *****************************************************************************/
00561 static mtime_t BufferDuration( aout_instance_t * p_aout )
00562 {
00563     struct aout_sys_t * p_sys = p_aout->output.p_sys;
00564     audio_buf_info audio_buf;
00565     int i_bytes;
00566 
00567     /* Fill the audio_buf_info structure:
00568      * - fragstotal: total number of fragments allocated
00569      * - fragsize: size of a fragment in bytes
00570      * - bytes: available space in bytes (includes partially used fragments)
00571      * Note! 'bytes' could be more than fragments*fragsize */
00572     ioctl( p_sys->i_fd, SNDCTL_DSP_GETOSPACE, &audio_buf );
00573 
00574     /* calculate number of available fragments (not partially used ones) */
00575     i_bytes = (audio_buf.fragstotal * audio_buf.fragsize) - audio_buf.bytes;
00576 
00577     /* Return the fragment duration */
00578     return (mtime_t)i_bytes * 1000000
00579             / p_aout->output.output.i_bytes_per_frame
00580             / p_aout->output.output.i_rate
00581             * p_aout->output.output.i_frame_length;
00582 }
00583 
00584 /*****************************************************************************
00585  * OSSThread: asynchronous thread used to DMA the data to the device
00586  *****************************************************************************/
00587 static int OSSThread( aout_instance_t * p_aout )
00588 {
00589     struct aout_sys_t * p_sys = p_aout->output.p_sys;
00590     mtime_t next_date = 0;
00591 
00592     while ( !p_aout->b_die )
00593     {
00594         aout_buffer_t * p_buffer = NULL;
00595         int i_tmp, i_size;
00596         byte_t * p_bytes;
00597 
00598         if ( p_aout->output.output.i_format != VLC_FOURCC('s','p','d','i') )
00599         {
00600             mtime_t buffered = BufferDuration( p_aout );
00601 
00602             if( p_aout->output.p_sys->b_workaround_buggy_driver )
00603             {
00604 #define i_fragstotal p_aout->output.p_sys->i_fragstotal
00605                 /* Wait a bit - we don't want our buffer to be full */
00606                 if( buffered > (p_aout->output.p_sys->max_buffer_duration
00607                                 / i_fragstotal * (i_fragstotal - 1)) )
00608                 {
00609                     msleep((p_aout->output.p_sys->max_buffer_duration
00610                                 / i_fragstotal ));
00611                     buffered = BufferDuration( p_aout );
00612                 }
00613 #undef i_fragstotal
00614             }
00615 
00616             /* Next buffer will be played at mdate() + buffered */
00617             p_buffer = aout_OutputNextBuffer( p_aout, mdate() + buffered,
00618                                               VLC_FALSE );
00619 
00620             if( p_buffer == NULL &&
00621                 buffered > ( p_aout->output.p_sys->max_buffer_duration
00622                              / p_aout->output.p_sys->i_fragstotal ) )
00623             {
00624                 /* If we have at least a fragment full, then we can wait a
00625                  * little and retry to get a new audio buffer instead of
00626                  * playing a blank sample */
00627                 msleep( ( p_aout->output.p_sys->max_buffer_duration
00628                           / p_aout->output.p_sys->i_fragstotal / 2 ) );
00629                 continue;
00630             }
00631         }
00632         else
00633         {
00634             /* emu10k1 driver does not report Buffer Duration correctly in
00635              * passthrough mode so we have to cheat */
00636             if( !next_date )
00637             {
00638                 next_date = mdate();
00639             }
00640             else
00641             {
00642                 mtime_t delay = next_date - mdate();
00643                 if( delay > AOUT_PTS_TOLERANCE )
00644                 {
00645                     msleep( delay / 2 );
00646                 }
00647             }
00648 
00649             while( !p_aout->b_die && ! ( p_buffer =
00650                 aout_OutputNextBuffer( p_aout, next_date, VLC_TRUE ) ) )
00651             {
00652                 msleep( 1000 );
00653                 next_date = mdate();
00654             }
00655         }
00656 
00657         if ( p_buffer != NULL )
00658         {
00659             p_bytes = p_buffer->p_buffer;
00660             i_size = p_buffer->i_nb_bytes;
00661             /* This is theoretical ... we'll see next iteration whether
00662              * we're drifting */
00663             next_date += p_buffer->end_date - p_buffer->start_date;
00664         }
00665         else
00666         {
00667             i_size = FRAME_SIZE / p_aout->output.output.i_frame_length
00668                       * p_aout->output.output.i_bytes_per_frame;
00669             p_bytes = malloc( i_size );
00670             memset( p_bytes, 0, i_size );
00671             next_date = 0;
00672         }
00673 
00674         i_tmp = write( p_sys->i_fd, p_bytes, i_size );
00675 
00676         if( i_tmp < 0 )
00677         {
00678             msg_Err( p_aout, "write failed (%s)", strerror(errno) );
00679         }
00680 
00681         if ( p_buffer != NULL )
00682         {
00683             aout_BufferFree( p_buffer );
00684         }
00685         else
00686         {
00687             free( p_bytes );
00688         }
00689     }
00690 
00691     return VLC_SUCCESS;
00692 }

Generated on Tue Dec 20 10:14:28 2005 for vlc-0.8.4a by  doxygen 1.4.2