X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Faudio_output%2Foss.c;h=d201df56516a32037f27351f8893d2211a569458;hb=33166ad97a418e9bdc0972901cab51e6aa437dd3;hp=42a22203462d370b1923246bede0a4da1afd03b3;hpb=db5fedc62315cfc0f93c0bb1fff76f53627142b8;p=vlc diff --git a/modules/audio_output/oss.c b/modules/audio_output/oss.c index 42a2220346..d201df5651 100644 --- a/modules/audio_output/oss.c +++ b/modules/audio_output/oss.c @@ -1,7 +1,7 @@ /***************************************************************************** * oss.c : OSS /dev/dsp module for vlc ***************************************************************************** - * Copyright (C) 2000-2002 VideoLAN + * Copyright (C) 2000-2002 the VideoLAN team * $Id$ * * Authors: Michel Kaempf @@ -20,28 +20,26 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ /***************************************************************************** * Preamble *****************************************************************************/ -#include /* ENOMEM */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + #include /* open(), O_WRONLY */ #include /* ioctl() */ -#include /* strerror() */ #include /* write(), close() */ -#include /* calloc(), malloc(), free() */ - -#include -#ifdef HAVE_ALLOCA_H -# include -#endif - -#include +#include +#include +#include -#include "aout_internal.h" +#include /* SNDCTL_DSP_RESET, SNDCTL_DSP_SETFMT, SNDCTL_DSP_STEREO, SNDCTL_DSP_SPEED, * SNDCTL_DSP_GETOSPACE */ @@ -49,8 +47,6 @@ # include #elif defined( HAVE_SYS_SOUNDCARD_H ) # include -#elif defined( HAVE_MACHINE_SOUNDCARD_H ) -# include #endif /* Patches for ignorant OSS versions */ @@ -74,15 +70,16 @@ *****************************************************************************/ struct aout_sys_t { + aout_packet_t packet; int i_fd; - int b_workaround_buggy_driver; int i_fragstotal; mtime_t max_buffer_duration; + vlc_thread_t thread; }; /* This must be a power of 2. */ #define FRAME_SIZE 1024 -#define FRAME_COUNT 4 +#define FRAME_COUNT 32 /***************************************************************************** * Local prototypes @@ -90,41 +87,34 @@ struct aout_sys_t static int Open ( vlc_object_t * ); static void Close ( vlc_object_t * ); -static void Play ( aout_instance_t * ); -static int OSSThread ( aout_instance_t * ); +static void Play ( audio_output_t *, block_t * ); +static void* OSSThread ( void * ); -static mtime_t BufferDuration( aout_instance_t * p_aout ); +static mtime_t BufferDuration( audio_output_t * p_aout ); /***************************************************************************** * Module descriptor *****************************************************************************/ -#define BUGGY_TEXT N_("Try to work around buggy OSS drivers") -#define BUGGY_LONGTEXT N_( \ - "Some buggy OSS drivers just don't like when their internal buffers " \ - "are completely filled (the sound gets heavily hashed). If you have one " \ - "of these drivers, then you need to enable this option." ) - -vlc_module_begin(); - set_shortname( "OSS" ); - set_description( _("Linux OSS audio output") ); - - set_category( CAT_AUDIO ); - set_subcategory( SUBCAT_AUDIO_AOUT ); - add_file( "dspdev", "/dev/dsp", aout_FindAndRestart, - N_("OSS DSP device"), NULL, VLC_FALSE ); - add_bool( "oss-buggy", 0, NULL, BUGGY_TEXT, BUGGY_LONGTEXT, VLC_TRUE ); - - set_capability( "audio output", 100 ); - add_shortcut( "oss" ); - set_callbacks( Open, Close ); -vlc_module_end(); +vlc_module_begin () + set_shortname( "OSS" ) + set_description( N_("Open Sound System") ) + + set_category( CAT_AUDIO ) + set_subcategory( SUBCAT_AUDIO_AOUT ) + add_loadfile( "oss-audio-device", "/dev/dsp", + N_("OSS DSP device"), NULL, false ) + + set_capability( "audio output", 100 ) + add_shortcut( "oss" ) + set_callbacks( Open, Close ) +vlc_module_end () /***************************************************************************** * Probe: probe the audio device for available formats and channels *****************************************************************************/ -static void Probe( aout_instance_t * p_aout ) +static void Probe( audio_output_t * p_aout ) { - struct aout_sys_t * p_sys = p_aout->output.p_sys; + struct aout_sys_t * p_sys = p_aout->sys; vlc_value_t val, text; int i_format, i_nb_channels; @@ -134,7 +124,7 @@ static void Probe( aout_instance_t * p_aout ) /* Test for multi-channel. */ #ifdef SNDCTL_DSP_GETCHANNELMASK - if ( aout_FormatNbChannels( &p_aout->output.output ) > 2 ) + if ( aout_FormatNbChannels( &p_aout->format ) > 2 ) { /* Check that the device supports this. */ @@ -155,30 +145,30 @@ static void Probe( aout_instance_t * p_aout ) { if ( !(i_chanmask & DSP_BIND_FRONT) ) { - msg_Err( p_aout, "No front channels ! (%x)", + msg_Err( p_aout, "no front channels! (%x)", i_chanmask ); return; } if ( (i_chanmask & (DSP_BIND_SURR | DSP_BIND_CENTER_LFE)) - && (p_aout->output.output.i_physical_channels == + && (p_aout->format.i_physical_channels == (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE)) ) { val.i_int = AOUT_VAR_5_1; - text.psz_string = N_("5.1"); + text.psz_string = (char*) "5.1"; var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text ); } if ( (i_chanmask & DSP_BIND_SURR) - && (p_aout->output.output.i_physical_channels & + && (p_aout->format.i_physical_channels & (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT)) ) { val.i_int = AOUT_VAR_2F2R; - text.psz_string = N_("2 Front 2 Rear"); + text.psz_string = _("2 Front 2 Rear"); var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text ); } @@ -202,7 +192,7 @@ static void Probe( aout_instance_t * p_aout ) && i_nb_channels == 2 ) { val.i_int = AOUT_VAR_STEREO; - text.psz_string = N_("Stereo"); + text.psz_string = _("Stereo"); var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text ); } @@ -222,9 +212,9 @@ static void Probe( aout_instance_t * p_aout ) && i_nb_channels == 1 ) { val.i_int = AOUT_VAR_MONO; - text.psz_string = N_("Mono"); + text.psz_string = _("Mono"); var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text ); - if ( p_aout->output.output.i_physical_channels == AOUT_CHAN_CENTER ) + if ( p_aout->format.i_physical_channels == AOUT_CHAN_CENTER ) { var_Set( p_aout, "audio-device", val ); } @@ -238,7 +228,7 @@ static void Probe( aout_instance_t * p_aout ) } /* Test for spdif. */ - if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) ) + if ( AOUT_FMT_SPDIF( &p_aout->format ) ) { i_format = AFMT_AC3; @@ -246,20 +236,17 @@ static void Probe( aout_instance_t * p_aout ) && i_format == AFMT_AC3 ) { val.i_int = AOUT_VAR_SPDIF; - text.psz_string = N_("A/52 over S/PDIF"); + text.psz_string = _("A/52 over S/PDIF"); var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text ); - if( config_GetInt( p_aout, "spdif" ) ) + if( var_InheritBool( p_aout, "spdif" ) ) var_Set( p_aout, "audio-device", val ); } - else if( config_GetInt( p_aout, "spdif" ) ) + else if( var_InheritBool( p_aout, "spdif" ) ) { - msg_Warn( p_aout, "s/pdif not supported by card" ); + msg_Warn( p_aout, "S/PDIF not supported by card" ); } } - - var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, - NULL ); } /***************************************************************************** @@ -270,21 +257,18 @@ static void Probe( aout_instance_t * p_aout ) *****************************************************************************/ static int Open( vlc_object_t *p_this ) { - aout_instance_t * p_aout = (aout_instance_t *)p_this; + audio_output_t * p_aout = (audio_output_t *)p_this; struct aout_sys_t * p_sys; char * psz_device; vlc_value_t val; /* Allocate structure */ - p_aout->output.p_sys = p_sys = malloc( sizeof( aout_sys_t ) ); + p_aout->sys = p_sys = malloc( sizeof( aout_sys_t ) ); if( p_sys == NULL ) - { - msg_Err( p_aout, "out of memory" ); return VLC_ENOMEM; - } /* Get device name */ - if( (psz_device = config_GetPsz( p_aout, "dspdev" )) == NULL ) + if( (psz_device = var_InheritString( p_aout, "oss-audio-device" )) == NULL ) { msg_Err( p_aout, "no audio device specified (maybe /dev/dsp?)" ); free( p_sys ); @@ -296,10 +280,11 @@ static int Open( vlc_object_t *p_this ) * wait forever until the device is available. Since this breaks the * OSS spec, we immediately put it back to blocking mode if the * operation was successful. */ - p_sys->i_fd = open( psz_device, O_WRONLY | O_NDELAY ); + p_sys->i_fd = vlc_open( psz_device, O_WRONLY | O_NDELAY ); if( p_sys->i_fd < 0 ) { msg_Err( p_aout, "cannot open audio device (%s)", psz_device ); + free( psz_device ); free( p_sys ); return VLC_EGENERIC; } @@ -310,72 +295,67 @@ static int Open( vlc_object_t *p_this ) free( psz_device ); - p_aout->output.pf_play = Play; + p_aout->pf_play = aout_PacketPlay; + p_aout->pf_pause = aout_PacketPause; + p_aout->pf_flush = aout_PacketFlush; if ( var_Type( p_aout, "audio-device" ) == 0 ) - { Probe( p_aout ); - } + var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL ); if ( var_Get( p_aout, "audio-device", &val ) < 0 ) - { /* Probe() has failed. */ - free( p_sys ); - return VLC_EGENERIC; - } + goto error; if ( val.i_int == AOUT_VAR_SPDIF ) { - p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i'); + p_aout->format.i_format = VLC_CODEC_SPDIFL; } else if ( val.i_int == AOUT_VAR_5_1 ) { - p_aout->output.output.i_format = AOUT_FMT_S16_NE; - p_aout->output.output.i_physical_channels + p_aout->format.i_format = VLC_CODEC_S16N; + p_aout->format.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE; } else if ( val.i_int == AOUT_VAR_2F2R ) { - p_aout->output.output.i_format = AOUT_FMT_S16_NE; - p_aout->output.output.i_physical_channels + p_aout->format.i_format = VLC_CODEC_S16N; + p_aout->format.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT; } else if ( val.i_int == AOUT_VAR_STEREO ) { - p_aout->output.output.i_format = AOUT_FMT_S16_NE; - p_aout->output.output.i_physical_channels + p_aout->format.i_format = VLC_CODEC_S16N; + p_aout->format.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; } else if ( val.i_int == AOUT_VAR_MONO ) { - p_aout->output.output.i_format = AOUT_FMT_S16_NE; - p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER; + p_aout->format.i_format = VLC_CODEC_S16N; + p_aout->format.i_physical_channels = AOUT_CHAN_CENTER; } else { /* This should not happen ! */ - msg_Err( p_aout, "internal: can't find audio-device (%i)", val.i_int ); - free( p_sys ); - return VLC_EGENERIC; + msg_Err( p_aout, "internal: can't find audio-device (%"PRId64")", + val.i_int ); + goto error; } - val.b_bool = VLC_TRUE; - var_Set( p_aout, "intf-change", val ); + var_TriggerCallback( p_aout, "intf-change" ); /* Reset the DSP device */ if( ioctl( p_sys->i_fd, SNDCTL_DSP_RESET, NULL ) < 0 ) { msg_Err( p_aout, "cannot reset OSS audio device" ); - close( p_sys->i_fd ); - free( p_sys ); - return VLC_EGENERIC; + goto error; } /* Set the output format */ - if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) ) + if ( AOUT_FMT_SPDIF( &p_aout->format ) ) { int i_format = AFMT_AC3; @@ -383,20 +363,17 @@ static int Open( vlc_object_t *p_this ) || i_format != AFMT_AC3 ) { msg_Err( p_aout, "cannot reset OSS audio device" ); - close( p_sys->i_fd ); - free( p_sys ); - return VLC_EGENERIC; + goto error; } - p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i'); - p_aout->output.i_nb_samples = A52_FRAME_NB; - p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE; - p_aout->output.output.i_frame_length = A52_FRAME_NB; + p_aout->format.i_format = VLC_CODEC_SPDIFL; + p_aout->format.i_bytes_per_frame = AOUT_SPDIF_SIZE; + p_aout->format.i_frame_length = A52_FRAME_NB; + aout_PacketInit( p_aout, &p_sys->packet, A52_FRAME_NB ); aout_VolumeNoneInit( p_aout ); } - - if ( !AOUT_FMT_NON_LINEAR( &p_aout->output.output ) ) + else { unsigned int i_format = AFMT_S16_NE; unsigned int i_frame_size, i_fragments; @@ -407,76 +384,68 @@ static int Open( vlc_object_t *p_this ) if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0 ) { msg_Err( p_aout, "cannot set audio output format" ); - close( p_sys->i_fd ); - free( p_sys ); - return VLC_EGENERIC; + goto error; } switch ( i_format ) { case AFMT_U8: - p_aout->output.output.i_format = VLC_FOURCC('u','8',' ',' '); + p_aout->format.i_format = VLC_CODEC_U8; break; case AFMT_S8: - p_aout->output.output.i_format = VLC_FOURCC('s','8',' ',' '); + p_aout->format.i_format = VLC_CODEC_S8; break; case AFMT_U16_LE: - p_aout->output.output.i_format = VLC_FOURCC('u','1','6','l'); + p_aout->format.i_format = VLC_CODEC_U16L; break; case AFMT_S16_LE: - p_aout->output.output.i_format = VLC_FOURCC('s','1','6','l'); + p_aout->format.i_format = VLC_CODEC_S16L; break; case AFMT_U16_BE: - p_aout->output.output.i_format = VLC_FOURCC('u','1','6','b'); + p_aout->format.i_format = VLC_CODEC_U16B; break; case AFMT_S16_BE: - p_aout->output.output.i_format = VLC_FOURCC('s','1','6','b'); + p_aout->format.i_format = VLC_CODEC_S16B; break; default: msg_Err( p_aout, "OSS fell back to an unknown format (%d)", i_format ); - close( p_sys->i_fd ); - free( p_sys ); - return VLC_EGENERIC; + goto error; } - i_nb_channels = aout_FormatNbChannels( &p_aout->output.output ); + i_nb_channels = aout_FormatNbChannels( &p_aout->format ); /* Set the number of channels */ if( ioctl( p_sys->i_fd, SNDCTL_DSP_CHANNELS, &i_nb_channels ) < 0 || - i_nb_channels != aout_FormatNbChannels( &p_aout->output.output ) ) + i_nb_channels != aout_FormatNbChannels( &p_aout->format ) ) { msg_Err( p_aout, "cannot set number of audio channels (%s)", - aout_FormatPrintChannels( &p_aout->output.output) ); - close( p_sys->i_fd ); - free( p_sys ); - return VLC_EGENERIC; + aout_FormatPrintChannels( &p_aout->format) ); + goto error; } /* Set the output rate */ - i_rate = p_aout->output.output.i_rate; + i_rate = p_aout->format.i_rate; if( ioctl( p_sys->i_fd, SNDCTL_DSP_SPEED, &i_rate ) < 0 ) { msg_Err( p_aout, "cannot set audio output rate (%i)", - p_aout->output.output.i_rate ); - close( p_sys->i_fd ); - free( p_sys ); - return VLC_EGENERIC; + p_aout->format.i_rate ); + goto error; } - if( i_rate != p_aout->output.output.i_rate ) + if( i_rate != p_aout->format.i_rate ) { - p_aout->output.output.i_rate = i_rate; + p_aout->format.i_rate = i_rate; } /* Set the fragment size */ - aout_FormatPrepare( &p_aout->output.output ); + aout_FormatPrepare( &p_aout->format ); /* i_fragment = xxxxyyyy where: xxxx is fragtotal * 1 << yyyy is fragsize */ - i_fragments = 0; - i_frame_size = FRAME_SIZE * p_aout->output.output.i_bytes_per_frame; - while( i_frame_size >>= 1 ) + i_frame_size = ((uint64_t)p_aout->format.i_bytes_per_frame * p_aout->format.i_rate * 65536) / (48000 * 2 * 2) / FRAME_COUNT; + i_fragments = 4; + while( i_fragments < 12 && (1U << i_fragments) < i_frame_size ) { ++i_fragments; } @@ -489,50 +458,40 @@ static int Open( vlc_object_t *p_this ) if( ioctl( p_sys->i_fd, SNDCTL_DSP_GETOSPACE, &audio_buf ) < 0 ) { msg_Err( p_aout, "cannot get fragment size" ); - close( p_sys->i_fd ); - free( p_sys ); - return VLC_EGENERIC; + goto error; } - else - { - /* Number of fragments actually allocated */ - p_aout->output.p_sys->i_fragstotal = audio_buf.fragstotal; - /* Maximum duration the soundcard's buffer can hold */ - p_aout->output.p_sys->max_buffer_duration = - (mtime_t)audio_buf.fragstotal * audio_buf.fragsize * 1000000 - / p_aout->output.output.i_bytes_per_frame - / p_aout->output.output.i_rate - * p_aout->output.output.i_frame_length; + /* Number of fragments actually allocated */ + p_aout->sys->i_fragstotal = audio_buf.fragstotal; - p_aout->output.i_nb_samples = audio_buf.fragsize / - p_aout->output.output.i_bytes_per_frame; - } + /* Maximum duration the soundcard's buffer can hold */ + p_aout->sys->max_buffer_duration = + (mtime_t)audio_buf.fragstotal * audio_buf.fragsize * 1000000 + / p_aout->format.i_bytes_per_frame + / p_aout->format.i_rate + * p_aout->format.i_frame_length; + aout_PacketInit( p_aout, &p_sys->packet, + audio_buf.fragsize/p_aout->format.i_bytes_per_frame ); aout_VolumeSoftInit( p_aout ); } - p_aout->output.p_sys->b_workaround_buggy_driver = - config_GetInt( p_aout, "oss-buggy" ); - /* Create OSS thread and wait for its readiness. */ - if( vlc_thread_create( p_aout, "aout", OSSThread, - VLC_THREAD_PRIORITY_OUTPUT, VLC_FALSE ) ) + if( vlc_clone( &p_sys->thread, OSSThread, p_aout, + VLC_THREAD_PRIORITY_OUTPUT ) ) { - msg_Err( p_aout, "cannot create OSS thread (%s)", strerror(errno) ); - close( p_sys->i_fd ); - free( p_sys ); - return VLC_ETHREAD; + msg_Err( p_aout, "cannot create OSS thread (%m)" ); + aout_PacketDestroy( p_aout ); + goto error; } return VLC_SUCCESS; -} -/***************************************************************************** - * Play: nothing to do - *****************************************************************************/ -static void Play( aout_instance_t *p_aout ) -{ +error: + var_DelCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL ); + close( p_sys->i_fd ); + free( p_sys ); + return VLC_EGENERIC; } /***************************************************************************** @@ -540,16 +499,18 @@ static void Play( aout_instance_t *p_aout ) *****************************************************************************/ static void Close( vlc_object_t * p_this ) { - aout_instance_t *p_aout = (aout_instance_t *)p_this; - struct aout_sys_t * p_sys = p_aout->output.p_sys; + audio_output_t *p_aout = (audio_output_t *)p_this; + struct aout_sys_t * p_sys = p_aout->sys; - p_aout->b_die = VLC_TRUE; - vlc_thread_join( p_aout ); - p_aout->b_die = VLC_FALSE; + vlc_cancel( p_sys->thread ); + vlc_join( p_sys->thread, NULL ); + p_aout->b_die = false; + var_DelCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL ); ioctl( p_sys->i_fd, SNDCTL_DSP_RESET, NULL ); close( p_sys->i_fd ); + aout_PacketDestroy( p_aout ); free( p_sys ); } @@ -558,79 +519,89 @@ static void Close( vlc_object_t * p_this ) ***************************************************************************** * This function returns the duration in microseconds of the current buffer. *****************************************************************************/ -static mtime_t BufferDuration( aout_instance_t * p_aout ) +static mtime_t BufferDuration( audio_output_t * p_aout ) { - struct aout_sys_t * p_sys = p_aout->output.p_sys; + struct aout_sys_t * p_sys = p_aout->sys; audio_buf_info audio_buf; int i_bytes; - /* Fill the audio_buf_info structure: - * - fragstotal: total number of fragments allocated - * - fragsize: size of a fragment in bytes - * - bytes: available space in bytes (includes partially used fragments) - * Note! 'bytes' could be more than fragments*fragsize */ - ioctl( p_sys->i_fd, SNDCTL_DSP_GETOSPACE, &audio_buf ); +#ifdef SNDCTL_DSP_GETODELAY + if ( ioctl( p_sys->i_fd, SNDCTL_DSP_GETODELAY, &i_bytes ) < 0 ) +#endif + { + /* Fall back to GETOSPACE and approximate latency. */ - /* calculate number of available fragments (not partially used ones) */ - i_bytes = (audio_buf.fragstotal * audio_buf.fragsize) - audio_buf.bytes; + /* Fill the audio_buf_info structure: + * - fragstotal: total number of fragments allocated + * - fragsize: size of a fragment in bytes + * - bytes: available space in bytes (includes partially used fragments) + * Note! 'bytes' could be more than fragments*fragsize */ + ioctl( p_sys->i_fd, SNDCTL_DSP_GETOSPACE, &audio_buf ); + + /* calculate number of available fragments (not partially used ones) */ + i_bytes = (audio_buf.fragstotal * audio_buf.fragsize) - audio_buf.bytes; + } /* Return the fragment duration */ return (mtime_t)i_bytes * 1000000 - / p_aout->output.output.i_bytes_per_frame - / p_aout->output.output.i_rate - * p_aout->output.output.i_frame_length; + / p_aout->format.i_bytes_per_frame + / p_aout->format.i_rate + * p_aout->format.i_frame_length; +} + +typedef struct +{ + aout_buffer_t *p_buffer; + void *p_bytes; +} oss_thread_ctx_t; + +static void OSSThreadCleanup( void *data ) +{ + oss_thread_ctx_t *p_ctx = data; + if( p_ctx->p_buffer ) + aout_BufferFree( p_ctx->p_buffer ); + else + free( p_ctx->p_bytes ); } /***************************************************************************** * OSSThread: asynchronous thread used to DMA the data to the device *****************************************************************************/ -static int OSSThread( aout_instance_t * p_aout ) +static void* OSSThread( void *obj ) { - struct aout_sys_t * p_sys = p_aout->output.p_sys; + audio_output_t * p_aout = (audio_output_t*)obj; + struct aout_sys_t * p_sys = p_aout->sys; mtime_t next_date = 0; - while ( !p_aout->b_die ) + for( ;; ) { aout_buffer_t * p_buffer = NULL; - int i_tmp, i_size; - byte_t * p_bytes; - if ( p_aout->output.output.i_format != VLC_FOURCC('s','p','d','i') ) + int canc = vlc_savecancel (); + if ( p_aout->format.i_format != VLC_CODEC_SPDIFL ) { mtime_t buffered = BufferDuration( p_aout ); - if( p_aout->output.p_sys->b_workaround_buggy_driver ) - { -#define i_fragstotal p_aout->output.p_sys->i_fragstotal - /* Wait a bit - we don't want our buffer to be full */ - if( buffered > (p_aout->output.p_sys->max_buffer_duration - / i_fragstotal * (i_fragstotal - 1)) ) - { - msleep((p_aout->output.p_sys->max_buffer_duration - / i_fragstotal )); - buffered = BufferDuration( p_aout ); - } -#undef i_fragstotal - } - /* Next buffer will be played at mdate() + buffered */ - p_buffer = aout_OutputNextBuffer( p_aout, mdate() + buffered, - VLC_FALSE ); + p_buffer = aout_PacketNext( p_aout, mdate() + buffered ); if( p_buffer == NULL && - buffered > ( p_aout->output.p_sys->max_buffer_duration - / p_aout->output.p_sys->i_fragstotal ) ) + buffered > ( p_aout->sys->max_buffer_duration + / p_aout->sys->i_fragstotal ) ) { + vlc_restorecancel (canc); /* If we have at least a fragment full, then we can wait a * little and retry to get a new audio buffer instead of * playing a blank sample */ - msleep( ( p_aout->output.p_sys->max_buffer_duration - / p_aout->output.p_sys->i_fragstotal / 2 ) ); + msleep( ( p_aout->sys->max_buffer_duration + / p_aout->sys->i_fragstotal / 2 ) ); continue; } } else { + vlc_restorecancel (canc); + /* emu10k1 driver does not report Buffer Duration correctly in * passthrough mode so we have to cheat */ if( !next_date ) @@ -640,53 +611,60 @@ static int OSSThread( aout_instance_t * p_aout ) else { mtime_t delay = next_date - mdate(); - if( delay > AOUT_PTS_TOLERANCE ) + if( delay > AOUT_MAX_PTS_ADVANCE ) { msleep( delay / 2 ); } } - while( !p_aout->b_die && ! ( p_buffer = - aout_OutputNextBuffer( p_aout, next_date, VLC_TRUE ) ) ) + for( ;; ) { - msleep( 1000 ); + canc = vlc_savecancel (); + p_buffer = aout_PacketNext( p_aout, next_date ); + if ( p_buffer ) + break; + vlc_restorecancel (canc); + + msleep( VLC_HARD_MIN_SLEEP ); next_date = mdate(); } } + uint8_t * p_bytes; + int i_size; if ( p_buffer != NULL ) { p_bytes = p_buffer->p_buffer; - i_size = p_buffer->i_nb_bytes; + i_size = p_buffer->i_buffer; /* This is theoretical ... we'll see next iteration whether * we're drifting */ - next_date += p_buffer->end_date - p_buffer->start_date; + next_date += p_buffer->i_length; } else { - i_size = FRAME_SIZE / p_aout->output.output.i_frame_length - * p_aout->output.output.i_bytes_per_frame; + i_size = FRAME_SIZE / p_aout->format.i_frame_length + * p_aout->format.i_bytes_per_frame; p_bytes = malloc( i_size ); memset( p_bytes, 0, i_size ); next_date = 0; } - i_tmp = write( p_sys->i_fd, p_bytes, i_size ); + oss_thread_ctx_t ctx = { + .p_buffer = p_buffer, + .p_bytes = p_bytes, + }; - if( i_tmp < 0 ) - { - msg_Err( p_aout, "write failed (%s)", strerror(errno) ); - } + vlc_cleanup_push( OSSThreadCleanup, &ctx ); + vlc_restorecancel( canc ); - if ( p_buffer != NULL ) - { - aout_BufferFree( p_buffer ); - } - else + int i_tmp = write( p_sys->i_fd, p_bytes, i_size ); + + if( i_tmp < 0 ) { - free( p_bytes ); + msg_Err( p_aout, "write failed (%m)" ); } + vlc_cleanup_run(); } - return VLC_SUCCESS; + return NULL; }