oss.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:23k
源码类别:

多媒体

开发平台:

MultiPlatform

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