+
+static int Open(vlc_object_t *obj)
+{
+ audio_output_t *aout = (audio_output_t *)obj;
+ aout_sys_t *sys = malloc(sizeof (*sys));
+
+ if (unlikely(sys == NULL))
+ return VLC_ENOMEM;
+ aout->sys = sys;
+ aout->start = Start;
+ aout->stop = Stop;
+ aout->volume_set = WaveoutVolumeSet;
+ aout->mute_set = WaveoutMuteSet;
+
+ sys->f_volume = var_InheritFloat(aout, "waveout-volume");
+ sys->b_mute = var_InheritBool(aout, "mute");
+
+ aout_MuteReport(aout, sys->b_mute);
+ aout_VolumeReport(aout, sys->f_volume );
+
+ if( vlc_timer_create( &sys->volume_poll_timer,
+ WaveoutPollVolume, aout ) )
+ {
+ msg_Err( aout, "Couldn't create volume polling timer" );
+ free( sys );
+ return VLC_ENOMEM;
+ }
+
+ vlc_mutex_init( &sys->lock );
+ vlc_cond_init( &sys->cond );
+
+ return VLC_SUCCESS;
+}
+
+static void Close(vlc_object_t *obj)
+{
+ audio_output_t *aout = (audio_output_t *)obj;
+ aout_sys_t *sys = aout->sys;
+
+ vlc_timer_destroy( sys->volume_poll_timer );
+
+ vlc_cond_destroy( &sys->cond );
+ vlc_mutex_destroy( &sys->lock );
+
+ free(sys);
+}
+
+static int WaveOutTimeGet(audio_output_t * p_aout, mtime_t *delay)
+{
+ MMTIME mmtime;
+ mmtime.wType = TIME_SAMPLES;
+
+ if( !p_aout->sys->i_frames )
+ return -1;
+
+ if( waveOutGetPosition( p_aout->sys->h_waveout, &mmtime, sizeof(MMTIME) )
+ != MMSYSERR_NOERROR )
+ {
+ msg_Err( p_aout, "waveOutGetPosition failed");
+ return -1;
+ }
+
+ mtime_t i_pos = (mtime_t) mmtime.u.sample * CLOCK_FREQ / p_aout->sys->i_rate;
+ *delay = p_aout->sys->i_played_length - i_pos;
+ return 0;
+}
+
+static void WaveOutFlush( audio_output_t *p_aout, bool wait)
+{
+ MMRESULT res;
+ if( !wait )
+ {
+ res = waveOutReset( p_aout->sys->h_waveout );
+ p_aout->sys->i_played_length = 0;
+ if( res != MMSYSERR_NOERROR )
+ msg_Err( p_aout, "waveOutReset failed");
+ }
+ else
+ {
+ vlc_mutex_lock( &p_aout->sys->lock );
+ while( p_aout->sys->i_frames )
+ {
+ vlc_cond_wait( &p_aout->sys->cond, &p_aout->sys-> lock );
+ }
+ vlc_mutex_unlock( &p_aout->sys->lock );
+ }
+}
+
+static void WaveOutPause( audio_output_t * p_aout, bool pause, mtime_t date)
+{
+ MMRESULT res;
+ (void) date;
+ if(pause)
+ {
+ vlc_timer_schedule( p_aout->sys->volume_poll_timer, false, 1, 200000 );
+ res = waveOutPause( p_aout->sys->h_waveout );
+ if( res != MMSYSERR_NOERROR )
+ {
+ msg_Err( p_aout, "waveOutPause failed (0x%x)", res);
+ return;
+ }
+ }
+ else
+ {
+ vlc_timer_schedule( p_aout->sys->volume_poll_timer, false, 0, 0 );
+ res = waveOutRestart( p_aout->sys->h_waveout );
+ if( res != MMSYSERR_NOERROR )
+ {
+ msg_Err( p_aout, "waveOutRestart failed (0x%x)", res);
+ return;
+ }
+ }
+}
+
+static int WaveoutVolumeSet( audio_output_t *p_aout, float volume )
+{
+ aout_sys_t *sys = p_aout->sys;
+
+ if( sys->b_soft )
+ {
+ float gain = volume * volume * volume;
+ if ( !sys->b_mute && aout_GainRequest( p_aout, gain ) )
+ return -1;
+ }
+ else
+ {
+ const HWAVEOUT hwo = sys->h_waveout;
+
+ uint32_t vol = lroundf( volume * 0x7fff.fp0 );
+
+ if( !sys->b_mute )
+ {
+ if( vol > 0xffff )
+ {
+ vol = 0xffff;
+ volume = 2.0f;
+ }
+
+ MMRESULT r = waveOutSetVolume( hwo, vol | ( vol << 16 ) );
+ if( r != MMSYSERR_NOERROR )
+ {
+ msg_Err( p_aout, "waveOutSetVolume failed (%u)", r );
+ return -1;
+ }
+ }
+ }
+
+ vlc_mutex_lock(&p_aout->sys->lock);
+ sys->f_volume = volume;
+
+ if( var_InheritBool( p_aout, "volume-save" ) )
+ config_PutFloat( p_aout, "waveout-volume", volume );
+
+ aout_VolumeReport( p_aout, volume );
+ vlc_mutex_unlock(&p_aout->sys->lock);
+
+ return 0;
+}
+
+static int WaveoutMuteSet( audio_output_t * p_aout, bool mute )
+{
+ aout_sys_t *sys = p_aout->sys;
+
+ if( sys->b_soft )
+ {
+ float gain = sys->f_volume * sys->f_volume * sys->f_volume;
+ if ( aout_GainRequest( p_aout, mute ? 0.f : gain ) )
+ return -1;
+ }
+ else
+ {
+
+ const HWAVEOUT hwo = sys->h_waveout;
+ uint32_t vol = mute ? 0 : lroundf( sys->f_volume * 0x7fff.fp0 );
+
+ if( vol > 0xffff )
+ vol = 0xffff;
+
+ MMRESULT r = waveOutSetVolume( hwo, vol | ( vol << 16 ) );
+ if( r != MMSYSERR_NOERROR )
+ {
+ msg_Err( p_aout, "waveOutSetVolume failed (%u)", r );
+ return -1;
+ }
+ }
+
+ vlc_mutex_lock(&p_aout->sys->lock);
+ sys->b_mute = mute;
+ aout_MuteReport( p_aout, mute );
+ vlc_mutex_unlock(&p_aout->sys->lock);
+
+ return 0;
+}
+
+static void WaveoutPollVolume( void * aout )
+{
+ audio_output_t * p_aout = (audio_output_t *) aout;
+ uint32_t vol;
+
+ MMRESULT r = waveOutGetVolume( p_aout->sys->h_waveout, (LPDWORD) &vol );
+
+ if( r != MMSYSERR_NOERROR )
+ {
+ msg_Err( p_aout, "waveOutGetVolume failed (%u)", r );
+ return;
+ }
+
+ float volume = (float) ( vol & UINT32_C( 0xffff ) );
+ volume /= 0x7fff.fp0;
+
+ vlc_mutex_lock(&p_aout->sys->lock);
+ if( !p_aout->sys->b_mute && volume != p_aout->sys->f_volume )
+ {
+ p_aout->sys->f_volume = volume;
+
+ if( var_InheritBool( p_aout, "volume-save" ) )
+ config_PutFloat( p_aout, "waveout-volume", volume );
+
+ aout_VolumeReport( p_aout, volume );
+ }
+ vlc_mutex_unlock(&p_aout->sys->lock);
+
+ return;
+}