X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Faudio_output%2Fwaveout.c;h=c1bf8a0c5c0a367166199e877f9e4a7b8dbba63b;hb=eb47e072b2bd1ffa5506c099698525b0a64f92fb;hp=5f8666bc59cf0a4feaccaf6a6cf0ee7f30289874;hpb=8e2410ecb5693126ab6f0a5cc9e78ace96e0560f;p=vlc diff --git a/modules/audio_output/waveout.c b/modules/audio_output/waveout.c index 5f8666bc59..c1bf8a0c5c 100644 --- a/modules/audio_output/waveout.c +++ b/modules/audio_output/waveout.c @@ -2,9 +2,9 @@ * waveout.c : Windows waveOut plugin for vlc ***************************************************************************** * Copyright (C) 2001 VideoLAN - * $Id: waveout.c,v 1.23 2003/04/08 21:26:22 gbazin Exp $ + * $Id$ * - * Authors: Gildas Bazin + * Authors: Gildas Bazin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,8 +34,8 @@ #include #include -#define FRAME_SIZE 1024 /* The size is in samples, not in bytes */ -#define FRAMES_NUM 4 +#define FRAME_SIZE 4096 /* The size is in samples, not in bytes */ +#define FRAMES_NUM 8 /***************************************************************************** * Useful macros @@ -92,10 +92,9 @@ typedef struct { } WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE; #endif -#include -DEFINE_GUID( __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, WAVE_FORMAT_IEEE_FLOAT, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 ); -DEFINE_GUID( __KSDATAFORMAT_SUBTYPE_PCM, WAVE_FORMAT_PCM, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 ); -DEFINE_GUID( __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF, WAVE_FORMAT_DOLBY_AC3_SPDIF, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 ); +static const GUID __KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {WAVE_FORMAT_IEEE_FLOAT, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; +static const GUID __KSDATAFORMAT_SUBTYPE_PCM = {WAVE_FORMAT_PCM, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; +static const GUID __KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF = {WAVE_FORMAT_DOLBY_AC3_SPDIF, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; /***************************************************************************** * Local prototypes @@ -104,25 +103,45 @@ static int Open ( vlc_object_t * ); static void Close ( vlc_object_t * ); static void Play ( aout_instance_t * ); +/***************************************************************************** + * notification_thread_t: waveOut event thread + *****************************************************************************/ +typedef struct notification_thread_t +{ + VLC_COMMON_MEMBERS + aout_instance_t *p_aout; + +} notification_thread_t; + /* local functions */ static void Probe ( aout_instance_t * ); static int OpenWaveOut ( aout_instance_t *, int, int, int, int, vlc_bool_t ); static int OpenWaveOutPCM( aout_instance_t *, int*, int, int, int, vlc_bool_t ); -static void CheckReordering( aout_instance_t *, int ); static int PlayWaveOut ( aout_instance_t *, HWAVEOUT, WAVEHDR *, aout_buffer_t * ); static void CALLBACK WaveOutCallback ( HWAVEOUT, UINT, DWORD, DWORD, DWORD ); +static void WaveOutThread( notification_thread_t * ); -static void InterleaveFloat32( float *, int *, int ); -static void InterleaveS16( int16_t *, int *, int ); +static int VolumeInfos( aout_instance_t *, audio_volume_t * ); +static int VolumeGet( aout_instance_t *, audio_volume_t * ); +static int VolumeSet( aout_instance_t *, audio_volume_t ); /***************************************************************************** * Module descriptor *****************************************************************************/ +#define FLOAT_TEXT N_("Use float32 output") +#define FLOAT_LONGTEXT N_( \ + "The option allows you to enable or disable the high-quality float32 " \ + "audio output mode (which is not well supported by some soundcards)." ) + vlc_module_begin(); + set_shortname( "WaveOut" ); set_description( _("Win32 waveOut extension output") ); set_capability( "audio output", 50 ); + set_category( CAT_AUDIO ); + set_subcategory( SUBCAT_AUDIO_AOUT ); + add_bool( "waveout-float32", 1, 0, FLOAT_TEXT, FLOAT_LONGTEXT, VLC_TRUE ); set_callbacks( Open, Close ); vlc_module_end(); @@ -140,26 +159,32 @@ struct aout_sys_t WAVEHDR waveheader[FRAMES_NUM]; + notification_thread_t *p_notif; /* WaveOutThread id */ + HANDLE event; + int i_buffer_size; byte_t *p_silence_buffer; /* buffer we use to play silence */ vlc_bool_t b_chan_reorder; /* do we need channel reordering */ - int *pi_chan_table; + int pi_chan_table[AOUT_CHAN_MAX]; }; -static const uint32_t pi_channels_in[] = +static const uint32_t pi_channels_src[] = { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, + AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT, AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, - AOUT_CHAN_CENTER, AOUT_CHAN_LFE }; + AOUT_CHAN_CENTER, AOUT_CHAN_LFE, 0 }; +static const uint32_t pi_channels_in[] = + { SPEAKER_FRONT_LEFT, SPEAKER_FRONT_RIGHT, + SPEAKER_SIDE_LEFT, SPEAKER_SIDE_RIGHT, + SPEAKER_BACK_LEFT, SPEAKER_BACK_RIGHT, + SPEAKER_FRONT_CENTER, SPEAKER_LOW_FREQUENCY, 0 }; static const uint32_t pi_channels_out[] = { SPEAKER_FRONT_LEFT, SPEAKER_FRONT_RIGHT, + SPEAKER_FRONT_CENTER, SPEAKER_LOW_FREQUENCY, SPEAKER_BACK_LEFT, SPEAKER_BACK_RIGHT, - SPEAKER_FRONT_CENTER, SPEAKER_LOW_FREQUENCY }; -static const uint32_t pi_channels_ordered[] = - { SPEAKER_FRONT_LEFT, SPEAKER_FRONT_RIGHT, SPEAKER_FRONT_CENTER, - SPEAKER_LOW_FREQUENCY, - SPEAKER_BACK_LEFT, SPEAKER_BACK_RIGHT }; + SPEAKER_SIDE_LEFT, SPEAKER_SIDE_RIGHT, 0 }; /***************************************************************************** * Open: open the audio device @@ -182,7 +207,6 @@ static int Open( vlc_object_t *p_this ) } p_aout->output.pf_play = Play; - p_aout->output.p_sys->pi_chan_table = NULL; p_aout->b_die = VLC_FALSE; if( var_Type( p_aout, "audio-device" ) == 0 ) @@ -197,11 +221,12 @@ static int Open( vlc_object_t *p_this ) return VLC_EGENERIC; } + var_Create( p_aout, "waveout-float32", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); + /* Open the device */ - if( !strcmp( val.psz_string, N_("A/52 over S/PDIF") ) ) + if( val.i_int == AOUT_VAR_SPDIF ) { p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i'); - free( val.psz_string ); if( OpenWaveOut( p_aout, VLC_FOURCC('s','p','d','i'), p_aout->output.output.i_physical_channels, @@ -225,20 +250,20 @@ static int Open( vlc_object_t *p_this ) } else { - if( !strcmp( val.psz_string, N_("5.1") ) ) + if( val.i_int == AOUT_VAR_5_1 ) { p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE; } - else if( !strcmp( val.psz_string, N_("2 Front 2 Rear") ) ) + else if( val.i_int == AOUT_VAR_2F2R ) { p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT; } - else if( !strcmp( val.psz_string, "Mono" ) ) + else if( val.i_int == AOUT_VAR_MONO ) { p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER; } @@ -247,7 +272,6 @@ static int Open( vlc_object_t *p_this ) p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; } - free( val.psz_string ); if( OpenWaveOutPCM( p_aout, &p_aout->output.output.i_format, p_aout->output.output.i_physical_channels, @@ -267,6 +291,10 @@ static int Open( vlc_object_t *p_this ) p_aout->output.output.i_bytes_per_frame; aout_VolumeSoftInit( p_aout ); + + p_aout->output.pf_volume_infos = VolumeInfos; + p_aout->output.pf_volume_get = VolumeGet; + p_aout->output.pf_volume_set = VolumeSet; } @@ -286,11 +314,26 @@ static int Open( vlc_object_t *p_this ) memset( p_aout->output.p_sys->p_silence_buffer, 0, p_aout->output.p_sys->i_buffer_size ); + /* Now we need to setup our waveOut play notification structure */ + p_aout->output.p_sys->p_notif = + vlc_object_create( p_aout, sizeof(notification_thread_t) ); + p_aout->output.p_sys->p_notif->p_aout = p_aout; + p_aout->output.p_sys->event = CreateEvent( NULL, FALSE, FALSE, NULL ); + + /* Then launch the notification thread */ + if( vlc_thread_create( p_aout->output.p_sys->p_notif, + "waveOut Notification Thread", WaveOutThread, + VLC_THREAD_PRIORITY_HIGHEST, VLC_FALSE ) ) + { + msg_Err( p_aout, "cannot create WaveOutThread" ); + } + /* We need to kick off the playback in order to have the callback properly * working */ for( i = 0; i < FRAMES_NUM; i++ ) { p_aout->output.p_sys->waveheader[i].dwFlags = WHDR_DONE; + p_aout->output.p_sys->waveheader[i].dwUser = 0; } PlayWaveOut( p_aout, p_aout->output.p_sys->h_waveout, &p_aout->output.p_sys->waveheader[0], NULL ); @@ -303,11 +346,13 @@ static int Open( vlc_object_t *p_this ) *****************************************************************************/ static void Probe( aout_instance_t * p_aout ) { - vlc_value_t val; + vlc_value_t val, text; int i_format; unsigned int i_physical_channels; - var_Create( p_aout, "audio-device", VLC_VAR_STRING | VLC_VAR_HASCHOICE ); + var_Create( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE ); + text.psz_string = _("Audio Device"); + var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL ); /* Test for 5.1 support */ i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | @@ -320,8 +365,10 @@ static void Probe( aout_instance_t * p_aout ) p_aout->output.output.i_rate, VLC_TRUE ) == VLC_SUCCESS ) { - val.psz_string = N_("5.1"); - var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val ); + val.i_int = AOUT_VAR_5_1; + text.psz_string = N_("5.1"); + var_Change( p_aout, "audio-device", + VLC_VAR_ADDCHOICE, &val, &text ); msg_Dbg( p_aout, "device supports 5.1 channels" ); } } @@ -337,8 +384,10 @@ static void Probe( aout_instance_t * p_aout ) p_aout->output.output.i_rate, VLC_TRUE ) == VLC_SUCCESS ) { - val.psz_string = N_("2 Front 2 Rear"); - var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val ); + val.i_int = AOUT_VAR_2F2R; + text.psz_string = N_("2 Front 2 Rear"); + var_Change( p_aout, "audio-device", + VLC_VAR_ADDCHOICE, &val, &text ); msg_Dbg( p_aout, "device supports 4 channels" ); } } @@ -350,9 +399,9 @@ static void Probe( aout_instance_t * p_aout ) p_aout->output.output.i_rate, VLC_TRUE ) == VLC_SUCCESS ) { - val.psz_string = N_("Stereo"); - var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val ); - var_Set( p_aout, "audio-device", val ); + val.i_int = AOUT_VAR_STEREO; + text.psz_string = N_("Stereo"); + var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text ); msg_Dbg( p_aout, "device supports 2 channels" ); } @@ -363,8 +412,9 @@ static void Probe( aout_instance_t * p_aout ) p_aout->output.output.i_rate, VLC_TRUE ) == VLC_SUCCESS ) { - val.psz_string = N_("Mono"); - var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val ); + val.i_int = AOUT_VAR_MONO; + text.psz_string = N_("Mono"); + var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text ); msg_Dbg( p_aout, "device supports 1 channel" ); } @@ -378,13 +428,23 @@ static void Probe( aout_instance_t * p_aout ) == VLC_SUCCESS ) { msg_Dbg( p_aout, "device supports A/52 over S/PDIF" ); - val.psz_string = N_("A/52 over S/PDIF"); - var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val ); + val.i_int = AOUT_VAR_SPDIF; + text.psz_string = N_("A/52 over S/PDIF"); + var_Change( p_aout, "audio-device", + VLC_VAR_ADDCHOICE, &val, &text ); if( config_GetInt( p_aout, "spdif" ) ) var_Set( p_aout, "audio-device", val ); } } + var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL ); + if( val.i_int <= 0 ) + { + /* Probe() has failed. */ + var_Destroy( p_aout, "audio-device" ); + return; + } + var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL ); val.b_bool = VLC_TRUE; @@ -397,7 +457,7 @@ static void Probe( aout_instance_t * p_aout ) * This doesn't actually play the buffer. This just stores the buffer so it * can be played by the callback thread. *****************************************************************************/ -static void Play( aout_instance_t *p_aout ) +static void Play( aout_instance_t *_p_aout ) { } @@ -407,40 +467,27 @@ 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; + aout_sys_t *p_sys = p_aout->output.p_sys; /* Before calling waveOutClose we must reset the device */ p_aout->b_die = VLC_TRUE; - /* Wait for the waveout buffers to be freed */ - while( VLC_TRUE ) - { - int i; - vlc_bool_t b_not_done = VLC_FALSE; - - for( i = 0; i < FRAMES_NUM; i++ ) - { - if( !(p_aout->output.p_sys->waveheader[i].dwFlags & WHDR_DONE) ) - b_not_done = VLC_TRUE; - } - - if( !b_not_done ) - break; + waveOutReset( p_sys->h_waveout ); - msleep( 1000 ); - } - - waveOutReset( p_aout->output.p_sys->h_waveout ); + /* wake up the audio thread */ + SetEvent( p_sys->event ); + vlc_thread_join( p_sys->p_notif ); + vlc_object_destroy( p_sys->p_notif ); + CloseHandle( p_sys->event ); /* Close the device */ - if( waveOutClose( p_aout->output.p_sys->h_waveout ) != MMSYSERR_NOERROR ) + if( waveOutClose( p_sys->h_waveout ) != MMSYSERR_NOERROR ) { msg_Err( p_aout, "waveOutClose failed" ); } - free( p_aout->output.p_sys->p_silence_buffer ); - if( p_aout->output.p_sys->pi_chan_table ) - free( p_aout->output.p_sys->pi_chan_table ); - free( p_aout->output.p_sys ); + free( p_sys->p_silence_buffer ); + free( p_sys ); } /***************************************************************************** @@ -458,10 +505,10 @@ static int OpenWaveOut( aout_instance_t *p_aout, int i_format, #define waveformat p_aout->output.p_sys->waveformat waveformat.dwChannelMask = 0; - for( i = 0; i < sizeof(pi_channels_in)/sizeof(uint32_t); i++ ) + for( i = 0; i < sizeof(pi_channels_src)/sizeof(uint32_t); i++ ) { - if( i_channels & pi_channels_in[i] ) - waveformat.dwChannelMask |= pi_channels_out[i]; + if( i_channels & pi_channels_src[i] ) + waveformat.dwChannelMask |= pi_channels_in[i]; } switch( i_format ) @@ -534,7 +581,15 @@ static int OpenWaveOut( aout_instance_t *p_aout, int i_format, return VLC_EGENERIC; } - CheckReordering( p_aout, i_nb_channels ); + p_aout->output.p_sys->b_chan_reorder = + aout_CheckChannelReorder( pi_channels_in, pi_channels_out, + waveformat.dwChannelMask, i_nb_channels, + p_aout->output.p_sys->pi_chan_table ); + + if( p_aout->output.p_sys->b_chan_reorder ) + { + msg_Dbg( p_aout, "channel reordering needed" ); + } return VLC_SUCCESS; @@ -549,8 +604,12 @@ static int OpenWaveOutPCM( aout_instance_t *p_aout, int *i_format, int i_channels, int i_nb_channels, int i_rate, vlc_bool_t b_probe ) { - if( OpenWaveOut( p_aout, VLC_FOURCC('f','l','3','2'), - i_channels, i_nb_channels, i_rate, b_probe ) + vlc_value_t val; + + var_Get( p_aout, "waveout-float32", &val ); + + if( !val.b_bool || OpenWaveOut( p_aout, VLC_FOURCC('f','l','3','2'), + i_channels, i_nb_channels, i_rate, b_probe ) != VLC_SUCCESS ) { if ( OpenWaveOut( p_aout, VLC_FOURCC('s','1','6','l'), @@ -572,63 +631,6 @@ static int OpenWaveOutPCM( aout_instance_t *p_aout, int *i_format, } } -/***************************************************************************** - * CheckReordering: Check if we need to do some channel re-ordering (the ac3 - * channel order is different from the one chosen by - * Microsoft). - *****************************************************************************/ -static void CheckReordering( aout_instance_t *p_aout, int i_nb_channels ) -{ - int i, j, k, l; - -#define waveformat p_aout->output.p_sys->waveformat -#define pi_chan_table p_aout->output.p_sys->pi_chan_table - - p_aout->output.p_sys->b_chan_reorder = VLC_FALSE; - - pi_chan_table = malloc( i_nb_channels * sizeof(int) ); - if( !pi_chan_table ) - { - return; - } - - for( i = 0, j = 0; - i < (int)(sizeof(pi_channels_out)/sizeof(uint32_t)); i++ ) - { - if( waveformat.dwChannelMask & pi_channels_out[i] ) - { - for( k = 0, l = 0; - pi_channels_out[i] != pi_channels_ordered[k]; k++ ) - { - if( waveformat.dwChannelMask & pi_channels_ordered[k] ) - { - l++; - } - } - - pi_chan_table[j] = l; - - j++; - } - } - - for( i = 0; i < i_nb_channels; i++ ) - { - if( pi_chan_table[i] != i ) - { - p_aout->output.p_sys->b_chan_reorder = VLC_TRUE; - } - } - - if( p_aout->output.p_sys->b_chan_reorder ) - { - msg_Dbg( p_aout, "channel reordering needed" ); - } - -#undef pi_chan_table -#undef waveformat -} - /***************************************************************************** * PlayWaveOut: play a buffer through the WaveOut device *****************************************************************************/ @@ -644,7 +646,7 @@ static int PlayWaveOut( aout_instance_t *p_aout, HWAVEOUT h_waveout, /* Use silence buffer instead */ p_waveheader->lpData = p_aout->output.p_sys->p_silence_buffer; - p_waveheader->dwUser = (DWORD_PTR)p_buffer; + p_waveheader->dwUser = p_buffer ? (DWORD_PTR)p_buffer : (DWORD_PTR)1; p_waveheader->dwBufferLength = p_aout->output.p_sys->i_buffer_size; p_waveheader->dwFlags = 0; @@ -674,23 +676,12 @@ static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg, DWORD dwParam1, DWORD dwParam2 ) { aout_instance_t *p_aout = (aout_instance_t *)_p_aout; - WAVEHDR *p_waveheader = (WAVEHDR *)dwParam1; - aout_buffer_t *p_buffer = NULL; - vlc_bool_t b_sleek; int i, i_queued_frames = 0; if( uMsg != WOM_DONE ) return; - /* Unprepare and free the buffer which has just been played */ - waveOutUnprepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) ); - if( p_waveheader->dwUser ) - aout_BufferFree( (aout_buffer_t *)p_waveheader->dwUser ); - if( p_aout->b_die ) return; - /* We don't want any resampling when using S/PDIF */ - b_sleek = p_aout->output.output.i_format == VLC_FOURCC('s','p','d','i'); - /* Find out the current latency */ for( i = 0; i < FRAMES_NUM; i++ ) { @@ -701,81 +692,122 @@ static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg, } } - /* Try to fill in as many frame buffers as possible */ - for( i = 0; i < FRAMES_NUM; i++ ) + /* Don't wake up the thread too much */ + if( i_queued_frames < FRAMES_NUM / 2 ) + SetEvent( p_aout->output.p_sys->event ); +} + +/***************************************************************************** + * WaveOutThread: this thread will capture play notification events. + ***************************************************************************** + * We use this thread to feed new audio samples to the sound card because + * we are not authorized to use waveOutWrite() directly in the waveout + * callback. + *****************************************************************************/ +static void WaveOutThread( notification_thread_t *p_notif ) +{ + aout_instance_t *p_aout = p_notif->p_aout; + aout_sys_t *p_sys = p_aout->output.p_sys; + aout_buffer_t *p_buffer = NULL; + WAVEHDR *p_waveheader = p_sys->waveheader; + int i, i_queued_frames; + vlc_bool_t b_sleek; + + /* We don't want any resampling when using S/PDIF */ + b_sleek = p_aout->output.output.i_format == VLC_FOURCC('s','p','d','i'); + + while( 1 ) { - /* Check if frame buf is available */ - if( p_aout->output.p_sys->waveheader[i].dwFlags & WHDR_DONE ) - { - /* Take into account the latency */ - p_buffer = aout_OutputNextBuffer( p_aout, - mdate() + 1000000 * i_queued_frames / - p_aout->output.output.i_rate * p_aout->output.i_nb_samples, - b_sleek ); + WaitForSingleObject( p_sys->event, INFINITE ); - if( !p_buffer && i_queued_frames ) + /* Cleanup and find out the current latency */ + i_queued_frames = 0; + for( i = 0; i < FRAMES_NUM; i++ ) + { + if( (p_waveheader[i].dwFlags & WHDR_DONE) && + p_waveheader[i].dwUser ) { - /* We aren't late so no need to play a blank sample */ - return; + /* Unprepare and free the buffers which has just been played */ + waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i], + sizeof(WAVEHDR) ); + + if( p_waveheader[i].dwUser != 1 ) + aout_BufferFree( (aout_buffer_t *)p_waveheader[i].dwUser ); + + p_waveheader[i].dwUser = 0; } - /* Do the channel reordering here */ - if( p_buffer && p_aout->output.p_sys->b_chan_reorder ) + /* Check if frame buf is available */ + if( !(p_waveheader[i].dwFlags & WHDR_DONE) ) { - if( p_aout->output.output.i_format == - VLC_FOURCC('s','1','6','l') ) - InterleaveS16( (int16_t *)p_buffer->p_buffer, - p_aout->output.p_sys->pi_chan_table, - aout_FormatNbChannels( &p_aout->output.output ) ); - else - InterleaveFloat32( (float *)p_buffer->p_buffer, - p_aout->output.p_sys->pi_chan_table, - aout_FormatNbChannels( &p_aout->output.output ) ); + i_queued_frames++; } + } - PlayWaveOut( p_aout, h_waveout, - &p_aout->output.p_sys->waveheader[i] , p_buffer ); + if( p_aout->b_die ) return; - i_queued_frames++; + /* Try to fill in as many frame buffers as possible */ + for( i = 0; i < FRAMES_NUM; i++ ) + { + /* Check if frame buf is available */ + if( p_waveheader[i].dwFlags & WHDR_DONE ) + { + /* Take into account the latency */ + p_buffer = aout_OutputNextBuffer( p_aout, + mdate() + 1000000 * i_queued_frames / + p_aout->output.output.i_rate * p_aout->output.i_nb_samples, + b_sleek ); + + if( !p_buffer && i_queued_frames ) + { + /* We aren't late so no need to play a blank sample */ + break; + } + + /* Do the channel reordering */ + if( p_buffer && p_sys->b_chan_reorder ) + { + aout_ChannelReorder( p_buffer->p_buffer, + p_buffer->i_nb_bytes, + p_sys->waveformat.Format.nChannels, + p_sys->pi_chan_table, + p_sys->waveformat.Format.wBitsPerSample ); + } + + PlayWaveOut( p_aout, p_sys->h_waveout, + &p_waveheader[i], p_buffer ); + + i_queued_frames++; + } } } } -/***************************************************************************** - * InterleaveFloat32/S16: change the channel order to the Microsoft one. - *****************************************************************************/ -static void InterleaveFloat32( float *p_buf, int *pi_chan_table, - int i_nb_channels ) +static int VolumeInfos( aout_instance_t * p_aout, audio_volume_t * pi_soft ) { - int i, j; - float p_tmp[10]; + *pi_soft = AOUT_VOLUME_MAX / 2; + return 0; +} - for( i = 0; i < FRAME_SIZE; i++ ) - { - for( j = 0; j < i_nb_channels; j++ ) - { - p_tmp[pi_chan_table[j]] = p_buf[i*i_nb_channels + j]; - } +static int VolumeGet( aout_instance_t * p_aout, audio_volume_t * pi_volume ) +{ + aout_sys_t *p_sys = p_aout->output.p_sys; + DWORD i_waveout_vol; - memcpy( &p_buf[i*i_nb_channels], p_tmp, - i_nb_channels * sizeof(float) ); - } + waveOutGetVolume( p_sys->h_waveout, &i_waveout_vol ); + i_waveout_vol &= 0xFFFF; + *pi_volume = p_aout->output.i_volume = + i_waveout_vol * AOUT_VOLUME_MAX / 2 / 0xFFFF; + return 0; } -static void InterleaveS16( int16_t *p_buf, int *pi_chan_table, - int i_nb_channels ) +static int VolumeSet( aout_instance_t * p_aout, audio_volume_t i_volume ) { - int i, j; - int16_t p_tmp[10]; - - for( i = 0; i < FRAME_SIZE; i++ ) - { - for( j = 0; j < i_nb_channels; j++ ) - { - p_tmp[pi_chan_table[j]] = p_buf[i*i_nb_channels + j]; - } + aout_sys_t *p_sys = p_aout->output.p_sys; + unsigned long i_waveout_vol = i_volume * 0xFFFF * 2 / AOUT_VOLUME_MAX; + i_waveout_vol |= (i_waveout_vol << 16); - memcpy( &p_buf[i*i_nb_channels], p_tmp, - i_nb_channels * sizeof(int16_t) ); - } + waveOutSetVolume( p_sys->h_waveout, i_waveout_vol ); + p_aout->output.i_volume = i_volume; + return 0; }