]> git.sesse.net Git - vlc/blobdiff - modules/audio_output/waveout.c
amem: defer set_volume() before setup()
[vlc] / modules / audio_output / waveout.c
index 4bb6831b7e79cc75b3ae872cff43efc551b421c8..de54f96b63d5d5ca8ea76bcbff8fd725a0ff5455 100644 (file)
@@ -1,23 +1,23 @@
 /*****************************************************************************
  * waveout.c : Windows waveOut plugin for vlc
  *****************************************************************************
- * Copyright (C) 2001-2009 the VideoLAN team
+ * Copyright (C) 2001-2009 VLC authors and VideoLAN
  * $Id$
  *
  * Authors: Gildas Bazin <gbazin@videolan.org>
  *          AndrĂ© Weber
  *
- * 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
- * the Free Software Foundation; either version 2 of the License, or
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
+ * You should have received a copy of the GNU Lesser General Public License
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 #endif
 
 #include <stdio.h>
+#include <math.h>
 #include <wchar.h>
 
 #define UNICODE
 #include <vlc_common.h>
 #include <vlc_plugin.h>
 #include <vlc_aout.h>
-#include <vlc_aout_intf.h>
 #include <vlc_charset.h> /* FromWide() */
 #include <vlc_atomic.h>
 
@@ -56,57 +56,28 @@ static void Play         ( audio_output_t *, block_t * );
  * notification_thread_t: waveOut event thread
  *****************************************************************************/
 /* local functions */
-static void Probe        ( audio_output_t * );
+static void Probe        ( audio_output_t *, const audio_sample_format_t * );
 static int OpenWaveOut   ( audio_output_t *, uint32_t,
                            int, int, int, int, bool );
 static int OpenWaveOutPCM( audio_output_t *, uint32_t,
                            vlc_fourcc_t*, int, int, int, bool );
 static int PlayWaveOut   ( audio_output_t *, HWAVEOUT, WAVEHDR *,
-                           aout_buffer_t *, bool );
+                           block_t *, bool );
 
 static void CALLBACK WaveOutCallback ( HWAVEOUT, UINT, DWORD_PTR, DWORD_PTR, DWORD_PTR );
 static void* WaveOutThread( void * );
 
-static int VolumeSet( audio_output_t *, float, bool );
+static int VolumeSet( audio_output_t *, float );
+static int MuteSet( audio_output_t *, bool );
 
 static int WaveOutClearDoneBuffers(aout_sys_t *p_sys);
 
-static int ReloadWaveoutDevices( vlc_object_t *, char const *,
-                                vlc_value_t, vlc_value_t, void * );
+static int ReloadWaveoutDevices( vlc_object_t *, const char *,
+                                 char ***, char *** );
 static uint32_t findDeviceID(char *);
 
 static const wchar_t device_name_fmt[] = L"%ls ($%x,$%x)";
 
-static const char *const ppsz_adev[] = { "wavemapper", };
-static const char *const ppsz_adev_text[] = { N_("Microsoft Soundmapper") };
-
-
-/*****************************************************************************
- * Module descriptor
- *****************************************************************************/
-#define DEVICE_TEXT N_("Select Audio Device")
-#define DEVICE_LONG N_("Select special Audio device, or let windows "\
-                       "decide (default), change needs VLC restart "\
-                       "to apply.")
-#define DEFAULT_AUDIO_DEVICE N_("Default Audio Device")
-
-vlc_module_begin ()
-    set_shortname( "WaveOut" )
-    set_description( N_("Win32 waveOut extension output") )
-    set_capability( "audio output", 50 )
-    set_category( CAT_AUDIO )
-    set_subcategory( SUBCAT_AUDIO_AOUT )
-
-    add_string( "waveout-audio-device", "wavemapper",
-                 DEVICE_TEXT, DEVICE_LONG, false )
-       change_string_list( ppsz_adev, ppsz_adev_text, ReloadWaveoutDevices )
-       change_action_add( ReloadWaveoutDevices, N_("Refresh list") )
-
-    add_bool( "waveout-float32", true, FLOAT_TEXT, FLOAT_LONGTEXT, true )
-
-    set_callbacks( Open, Close )
-vlc_module_end ()
-
 /*****************************************************************************
  * aout_sys_t: waveOut audio output method descriptor
  *****************************************************************************
@@ -139,35 +110,60 @@ struct aout_sys_t
 
     uint8_t *p_silence_buffer;              /* buffer we use to play silence */
 
-    bool b_chan_reorder;              /* do we need channel reordering */
-    int pi_chan_table[AOUT_CHAN_MAX];
+    union {
+        float volume;
+        float soft_gain;
+    };
+    union {
+        bool mute;
+        bool soft_mute;
+    };
+
+    uint8_t chans_to_reorder;              /* do we need channel reordering */
+    uint8_t chan_table[AOUT_CHAN_MAX];
 };
 
+#include "volume.h"
+
 /*****************************************************************************
- * Open: open the audio device
- *****************************************************************************
- * This function opens and setups Win32 waveOut
+ * Module descriptor
  *****************************************************************************/
-static int Open( vlc_object_t *p_this )
-{
-    audio_output_t *p_aout = (audio_output_t *)p_this;
-    vlc_value_t val;
+#define DEVICE_TEXT N_("Select Audio Device")
+#define DEVICE_LONG N_("Select special Audio device, or let windows "\
+                       "decide (default), change needs VLC restart "\
+                       "to apply.")
+#define DEFAULT_AUDIO_DEVICE N_("Default Audio Device")
 
-    /* Allocate structure */
-    p_aout->sys = malloc( sizeof( aout_sys_t ) );
+vlc_module_begin ()
+    set_shortname( "WaveOut" )
+    set_description( N_("Win32 waveOut extension output") )
+    set_capability( "audio output", 50 )
+    set_category( CAT_AUDIO )
+    set_subcategory( SUBCAT_AUDIO_AOUT )
 
-    if( p_aout->sys == NULL )
-        return VLC_ENOMEM;
+    add_string( "waveout-audio-device", "wavemapper",
+                 DEVICE_TEXT, DEVICE_LONG, false )
+       change_string_cb( ReloadWaveoutDevices )
+    add_sw_gain( )
 
-    p_aout->pf_play = Play;
-    p_aout->pf_pause = aout_PacketPause;
-    p_aout->pf_flush = aout_PacketFlush;
+    add_bool( "waveout-float32", true, FLOAT_TEXT, FLOAT_LONGTEXT, true )
 
-    /*
-     initialize/update Device selection List
-    */
-    ReloadWaveoutDevices( p_this, "waveout-audio-device", val, val, NULL);
+    set_callbacks( Open, Close )
+vlc_module_end ()
+
+/*****************************************************************************
+ * Opens the audio device
+ *****************************************************************************
+ * This function opens and setups Win32 waveOut
+ *****************************************************************************/
+static int Start( audio_output_t *p_aout, audio_sample_format_t *restrict fmt )
+{
+    vlc_value_t val;
 
+    p_aout->time_get = aout_PacketTimeGet;
+    p_aout->play = Play;
+    p_aout->pause = NULL;
+    p_aout->flush = aout_PacketFlush;
 
     /*
       check for configured audio device!
@@ -208,7 +204,7 @@ static int Open( vlc_object_t *p_this )
 
     if( var_Type( p_aout, "audio-device" ) == 0 )
     {
-        Probe( p_aout );
+        Probe( p_aout, fmt );
     }
 
     if( var_Get( p_aout, "audio-device", &val ) < 0 )
@@ -223,14 +219,11 @@ static int Open( vlc_object_t *p_this )
     /* Open the device */
     if( val.i_int == AOUT_VAR_SPDIF )
     {
-        p_aout->format.i_format = VLC_CODEC_SPDIFL;
-
-        if( OpenWaveOut( p_aout,
-                         p_aout->sys->i_wave_device_id,
-                         VLC_CODEC_SPDIFL,
-                         p_aout->format.i_physical_channels,
-                         aout_FormatNbChannels( &p_aout->format ),
-                         p_aout->format.i_rate, false )
+        fmt->i_format = VLC_CODEC_SPDIFL;
+
+        if( OpenWaveOut( p_aout, p_aout->sys->i_wave_device_id,
+                         VLC_CODEC_SPDIFL, fmt->i_physical_channels,
+                         aout_FormatNbChannels( fmt ), fmt->i_rate, false )
             != VLC_SUCCESS )
         {
             msg_Err( p_aout, "cannot open waveout audio device" );
@@ -239,13 +232,11 @@ static int Open( vlc_object_t *p_this )
         }
 
         /* Calculate the frame size in bytes */
-        p_aout->format.i_bytes_per_frame = AOUT_SPDIF_SIZE;
-        p_aout->format.i_frame_length = A52_FRAME_NB;
-        p_aout->sys->i_buffer_size =
-            p_aout->format.i_bytes_per_frame;
+        fmt->i_bytes_per_frame = AOUT_SPDIF_SIZE;
+        fmt->i_frame_length = A52_FRAME_NB;
+        p_aout->sys->i_buffer_size = fmt->i_bytes_per_frame;
 
-        aout_PacketInit( p_aout, &p_aout->sys->packet, A52_FRAME_NB );
-        aout_VolumeNoneInit( p_aout );
+        aout_PacketInit( p_aout, &p_aout->sys->packet, A52_FRAME_NB, fmt );
     }
     else
     {
@@ -254,30 +245,26 @@ static int Open( vlc_object_t *p_this )
         switch( val.i_int )
         {
         case AOUT_VAR_5_1:
-            p_aout->format.i_physical_channels
+            fmt->i_physical_channels
                     = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
                       | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
                       | AOUT_CHAN_LFE;
             break;
         case AOUT_VAR_2F2R:
-            p_aout->format.i_physical_channels
+            fmt->i_physical_channels
                     = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
                       | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
             break;
         case AOUT_VAR_MONO:
-            p_aout->format.i_physical_channels = AOUT_CHAN_CENTER;
+            fmt->i_physical_channels = AOUT_CHAN_CENTER;
             break;
         default:
-            p_aout->format.i_physical_channels
-                    = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
+            fmt->i_physical_channels = AOUT_CHANS_STEREO;
         }
 
-        if( OpenWaveOutPCM( p_aout,
-                            p_aout->sys->i_wave_device_id,
-                            &p_aout->format.i_format,
-                            p_aout->format.i_physical_channels,
-                            aout_FormatNbChannels( &p_aout->format ),
-                            p_aout->format.i_rate, false )
+        if( OpenWaveOutPCM( p_aout, p_aout->sys->i_wave_device_id,
+                            &fmt->i_format, fmt->i_physical_channels,
+                            aout_FormatNbChannels( fmt ), fmt->i_rate, false )
             != VLC_SUCCESS )
         {
             msg_Err( p_aout, "cannot open waveout audio device" );
@@ -286,22 +273,25 @@ static int Open( vlc_object_t *p_this )
         }
 
         /* Calculate the frame size in bytes */
-        aout_FormatPrepare( &p_aout->format );
-        p_aout->sys->i_buffer_size = FRAME_SIZE *
-            p_aout->format.i_bytes_per_frame;
+        aout_FormatPrepare( fmt );
+        p_aout->sys->i_buffer_size = FRAME_SIZE * fmt->i_bytes_per_frame;
 
-        aout_PacketInit( p_aout, &p_aout->sys->packet, FRAME_SIZE );
+        aout_PacketInit( p_aout, &p_aout->sys->packet, FRAME_SIZE, fmt );
 
         /* Check for hardware volume support */
         if( waveOutGetDevCaps( (UINT_PTR)p_aout->sys->h_waveout,
                                &wocaps, sizeof(wocaps) ) == MMSYSERR_NOERROR
          && (wocaps.dwSupport & WAVECAPS_VOLUME) )
-            aout_VolumeHardInit( p_aout, VolumeSet, false /* ?? */ );
+        {   /* FIXME: this needs to be moved to Open() */
+            p_aout->volume_set = VolumeSet;
+            p_aout->mute_set = MuteSet;
+            p_aout->sys->volume = 0xffff.fp0;
+            p_aout->sys->mute = false;
+        }
         else
-            aout_VolumeSoftInit( p_aout );
+            aout_SoftVolumeInit( p_aout );
     }
 
-
     waveOutReset( p_aout->sys->h_waveout );
 
     /* Allocate silence buffer */
@@ -352,7 +342,7 @@ static int Open( vlc_object_t *p_this )
 /*****************************************************************************
  * Probe: probe the audio device for available formats and channels
  *****************************************************************************/
-static void Probe( audio_output_t * p_aout )
+static void Probe( audio_output_t * p_aout, const audio_sample_format_t *fmt )
 {
     vlc_value_t val, text;
     vlc_fourcc_t i_format;
@@ -366,13 +356,11 @@ static void Probe( audio_output_t * p_aout )
     i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
                           AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
                           AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
-    if( p_aout->format.i_physical_channels == i_physical_channels )
+    if( fmt->i_physical_channels == i_physical_channels )
     {
-        if( OpenWaveOutPCM( p_aout,
-                            p_aout->sys->i_wave_device_id,
-                            &i_format,
-                            i_physical_channels, 6,
-                            p_aout->format.i_rate, true )
+        if( OpenWaveOutPCM( p_aout, p_aout->sys->i_wave_device_id,
+                            &i_format, i_physical_channels, 6,
+                            fmt->i_rate, true )
             == VLC_SUCCESS )
         {
             val.i_int = AOUT_VAR_5_1;
@@ -386,14 +374,12 @@ static void Probe( audio_output_t * p_aout )
     /* Test for 2 Front 2 Rear support */
     i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
                           AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
-    if( ( p_aout->format.i_physical_channels & i_physical_channels )
+    if( ( fmt->i_physical_channels & i_physical_channels )
         == i_physical_channels )
     {
-        if( OpenWaveOutPCM( p_aout,
-                            p_aout->sys->i_wave_device_id,
-                            &i_format,
-                            i_physical_channels, 4,
-                            p_aout->format.i_rate, true )
+        if( OpenWaveOutPCM( p_aout,p_aout->sys->i_wave_device_id,
+                            &i_format, i_physical_channels, 4,
+                            fmt->i_rate, true )
             == VLC_SUCCESS )
         {
             val.i_int = AOUT_VAR_2F2R;
@@ -406,11 +392,9 @@ static void Probe( audio_output_t * p_aout )
 
     /* Test for stereo support */
     i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
-    if( OpenWaveOutPCM( p_aout,
-                        p_aout->sys->i_wave_device_id,
-                        &i_format,
-                        i_physical_channels, 2,
-                        p_aout->format.i_rate, true )
+    if( OpenWaveOutPCM( p_aout, p_aout->sys->i_wave_device_id,
+                        &i_format,i_physical_channels, 2,
+                        fmt->i_rate, true )
         == VLC_SUCCESS )
     {
         val.i_int = AOUT_VAR_STEREO;
@@ -421,11 +405,8 @@ static void Probe( audio_output_t * p_aout )
 
     /* Test for mono support */
     i_physical_channels = AOUT_CHAN_CENTER;
-    if( OpenWaveOutPCM( p_aout,
-                        p_aout->sys->i_wave_device_id,
-                        &i_format,
-                        i_physical_channels, 1,
-                        p_aout->format.i_rate, true )
+    if( OpenWaveOutPCM( p_aout, p_aout->sys->i_wave_device_id,
+                        &i_format, i_physical_channels, 1, fmt->i_rate, true )
         == VLC_SUCCESS )
     {
         val.i_int = AOUT_VAR_MONO;
@@ -435,14 +416,11 @@ static void Probe( audio_output_t * p_aout )
     }
 
     /* Test for SPDIF support */
-    if ( AOUT_FMT_SPDIF( &p_aout->format ) )
+    if ( AOUT_FMT_SPDIF( fmt ) )
     {
-        if( OpenWaveOut( p_aout,
-                         p_aout->sys->i_wave_device_id,
-                         VLC_CODEC_SPDIFL,
-                         p_aout->format.i_physical_channels,
-                         aout_FormatNbChannels( &p_aout->format ),
-                         p_aout->format.i_rate, true )
+        if( OpenWaveOut( p_aout, p_aout->sys->i_wave_device_id,
+                         VLC_CODEC_SPDIFL, fmt->i_physical_channels,
+                         aout_FormatNbChannels( fmt ), fmt->i_rate, true )
             == VLC_SUCCESS )
         {
             msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
@@ -464,7 +442,6 @@ static void Probe( audio_output_t * p_aout )
     }
 
     var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
-    var_TriggerCallback( p_aout, "intf-change" );
 }
 
 /*****************************************************************************
@@ -496,9 +473,8 @@ static void Play( audio_output_t *_p_aout, block_t *block )
 /*****************************************************************************
  * Close: close the audio device
  *****************************************************************************/
-static void Close( vlc_object_t *p_this )
+static void Stop( audio_output_t *p_aout )
 {
-    audio_output_t *p_aout = (audio_output_t *)p_this;
     aout_sys_t *p_sys = p_aout->sys;
 
     /* Before calling waveOutClose we must reset the device */
@@ -567,7 +543,6 @@ static void Close( vlc_object_t *p_this )
 
     free( p_sys->p_silence_buffer );
     aout_PacketDestroy( p_aout );
-    free( p_sys );
 }
 
 /*****************************************************************************
@@ -584,11 +559,9 @@ static int OpenWaveOut( audio_output_t *p_aout, uint32_t i_device_id, int i_form
 #define waveformat p_aout->sys->waveformat
 
     waveformat.dwChannelMask = 0;
-    for( unsigned i = 0; i < sizeof(pi_channels_src)/sizeof(uint32_t); i++ )
-    {
-        if( i_channels & pi_channels_src[i] )
+    for( unsigned i = 0; pi_vlc_chan_order_wg4[i]; i++ )
+        if( i_channels & pi_vlc_chan_order_wg4[i] )
             waveformat.dwChannelMask |= pi_channels_in[i];
-    }
 
     switch( i_format )
     {
@@ -684,15 +657,12 @@ static int OpenWaveOut( audio_output_t *p_aout, uint32_t i_device_id, int i_form
         return VLC_EGENERIC;
     }
 
-    p_aout->sys->b_chan_reorder =
+    p_aout->sys->chans_to_reorder =
         aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
-                                  waveformat.dwChannelMask, i_nb_channels,
-                                  p_aout->sys->pi_chan_table );
-
-    if( p_aout->sys->b_chan_reorder )
-    {
+                                  waveformat.dwChannelMask,
+                                  p_aout->sys->chan_table );
+    if( p_aout->sys->chans_to_reorder )
         msg_Dbg( p_aout, "channel reordering needed" );
-    }
 
     return VLC_SUCCESS;
 
@@ -737,8 +707,7 @@ static int OpenWaveOutPCM( audio_output_t *p_aout, uint32_t i_device_id,
  * PlayWaveOut: play a buffer through the WaveOut device
  *****************************************************************************/
 static int PlayWaveOut( audio_output_t *p_aout, HWAVEOUT h_waveout,
-                        WAVEHDR *p_waveheader, aout_buffer_t *p_buffer,
-                        bool b_spdif)
+                        WAVEHDR *p_waveheader, block_t *p_buffer, bool b_spdif)
 {
     MMRESULT result;
 
@@ -754,7 +723,7 @@ static int PlayWaveOut( audio_output_t *p_aout, HWAVEOUT h_waveout,
         */
         if(b_spdif)
         {
-           vlc_memcpy( p_aout->sys->p_silence_buffer,
+           memcpy( p_aout->sys->p_silence_buffer,
                        p_buffer->p_buffer,
                        p_aout->sys->i_buffer_size );
            p_aout->sys->i_repeat_counter = 2;
@@ -766,7 +735,7 @@ static int PlayWaveOut( audio_output_t *p_aout, HWAVEOUT h_waveout,
            p_aout->sys->i_repeat_counter--;
            if(!p_aout->sys->i_repeat_counter)
            {
-               vlc_memset( p_aout->sys->p_silence_buffer,
+               memset( p_aout->sys->p_silence_buffer,
                            0x00, p_aout->sys->i_buffer_size );
            }
         }
@@ -827,7 +796,7 @@ static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
 
 
 /****************************************************************************
- * WaveOutClearDoneBuffers: Clear all done marked buffers, and free aout_bufer
+ * WaveOutClearDoneBuffers: Clear all done marked buffers, and free buffer
  ****************************************************************************
  * return value is the number of still playing buffers in the queue
  ****************************************************************************/
@@ -841,14 +810,14 @@ static int WaveOutClearDoneBuffers(aout_sys_t *p_sys)
         if( (p_waveheader[i].dwFlags & WHDR_DONE) &&
             p_waveheader[i].dwUser )
         {
-            aout_buffer_t *p_buffer =
-                    (aout_buffer_t *)(p_waveheader[i].dwUser);
+            block_t *p_buffer =
+                    (block_t *)(p_waveheader[i].dwUser);
             /* 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( p_buffer );
+                block_Release( p_buffer );
 
             p_waveheader[i].dwUser = 0;
         }
@@ -873,7 +842,7 @@ static void* WaveOutThread( void *data )
 {
     audio_output_t *p_aout = data;
     aout_sys_t *p_sys = p_aout->sys;
-    aout_buffer_t *p_buffer = NULL;
+    block_t *p_buffer = NULL;
     WAVEHDR *p_waveheader = p_sys->waveheader;
     int i, i_queued_frames;
     bool b_sleek;
@@ -881,7 +850,7 @@ static void* WaveOutThread( void *data )
     int canc = vlc_savecancel ();
 
     /* We don't want any resampling when using S/PDIF */
-    b_sleek = p_aout->format.i_format == VLC_CODEC_SPDIFL;
+    b_sleek = p_sys->packet.format.i_format == VLC_CODEC_SPDIFL;
 
     // wait for first call to "play()"
     while( !p_sys->start_date && !vlc_atomic_get(&p_aout->sys->abort) )
@@ -952,12 +921,12 @@ static void* WaveOutThread( void *data )
                 }
 
                 /* Do the channel reordering */
-                if( p_buffer && p_sys->b_chan_reorder )
+                if( p_buffer && p_sys->chans_to_reorder )
                 {
                     aout_ChannelReorder( p_buffer->p_buffer,
                         p_buffer->i_buffer,
                         p_sys->waveformat.Format.nChannels,
-                        p_sys->pi_chan_table,
+                        p_sys->chan_table,
                         p_sys->waveformat.Format.wBitsPerSample );
                 }
 
@@ -993,65 +962,54 @@ static void* WaveOutThread( void *data )
     return NULL;
 }
 
-static int VolumeSet( audio_output_t * p_aout, float volume, bool mute )
+static int VolumeSet( audio_output_t *aout, float volume )
 {
-    if( mute )
-        volume = 0.;
+    aout_sys_t *sys = aout->sys;
+    const HWAVEOUT hwo = sys->h_waveout;
+    const float full = 0xffff.fp0;
 
-    unsigned long i_waveout_vol = volume
-        * (0xFFFF * AOUT_VOLUME_DEFAULT / AOUT_VOLUME_MAX);
+    volume *= full;
+    if( volume >= full )
+        return -1;
 
-    if( i_waveout_vol <= 0xFFFF )
-        i_waveout_vol |= i_waveout_vol << 16;
-    else
-        i_waveout_vol = 0xFFFFFFFF;
+    sys->volume = volume;
+    if( sys->mute )
+        return 0;
 
-#ifdef UNDER_CE
-    waveOutSetVolume( 0, i_waveout_vol );
-#else
-    waveOutSetVolume( p_aout->sys->h_waveout, i_waveout_vol );
-#endif
+    uint16_t vol = lroundf(volume);
+    waveOutSetVolume( hwo, vol | (vol << 16) );
     return 0;
 }
 
+static int MuteSet( audio_output_t * p_aout, bool mute )
+{
+    aout_sys_t *sys = p_aout->sys;
+    const HWAVEOUT hwo = sys->h_waveout;
+    uint16_t vol = mute ? 0 : lroundf(sys->volume);
+
+    sys->mute = mute;
+    waveOutSetVolume( hwo, vol | (vol << 16) );
+    return 0;
+}
 
 /*
   reload the configuration drop down list, of the Audio Devices
 */
 static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
-                                 vlc_value_t newval, vlc_value_t oldval, void *data )
+                                 char ***values, char ***descs )
 {
-    VLC_UNUSED( newval ); VLC_UNUSED( oldval ); VLC_UNUSED( data );
-
-    module_config_t *p_item = config_FindConfig( p_this, psz_name );
-    if( !p_item ) return VLC_SUCCESS;
+    int n = 0, nb_devices = waveOutGetNumDevs();
 
-    /* Clear-up the current list */
-    if( p_item->i_list )
-    {
-        int i;
-
-        /* Keep the first entry */
-        for( i = 1; i < p_item->i_list; i++ )
-        {
-            free((char *)(p_item->ppsz_list[i]) );
-            free((char *)(p_item->ppsz_list_text[i]) );
-        }
-        /* TODO: Remove when no more needed */
-        p_item->ppsz_list[i] = NULL;
-        p_item->ppsz_list_text[i] = NULL;
-    }
-    p_item->i_list = 1;
+    VLC_UNUSED( p_this); VLC_UNUSED( psz_name );
 
-    int wave_devices = waveOutGetNumDevs();
+    *values = xmalloc( (nb_devices + 1) * sizeof(char *) );
+    *descs = xmalloc( (nb_devices + 1) * sizeof(char *) );
 
-    p_item->ppsz_list = xrealloc( p_item->ppsz_list,
-                          (wave_devices+2) * sizeof(char *) );
-    p_item->ppsz_list_text = xrealloc( p_item->ppsz_list_text,
-                          (wave_devices+2) * sizeof(char *) );
+    (*values)[n] = strdup( "wavemapper" );
+    (*descs)[n] = strdup( _("Microsoft Soundmapper") );
+    n++;
 
-    int j=1;
-    for(int i=0; i<wave_devices; i++)
+    for(int i = 0; i < nb_devices; i++)
     {
         WAVEOUTCAPS caps;
         wchar_t dev_name[MAXPNAMELEN+32];
@@ -1061,16 +1019,13 @@ static int ReloadWaveoutDevices( vlc_object_t *p_this, char const *psz_name,
             continue;
 
         _snwprintf(dev_name, MAXPNAMELEN + 32, device_name_fmt,
-                 caps.szPname, caps.wMid, caps.wPid);
-        p_item->ppsz_list[j] = FromWide( dev_name );
-        p_item->ppsz_list_text[j] = FromWide( dev_name );
-        p_item->i_list++;
-        j++;
+                   caps.szPname, caps.wMid, caps.wPid);
+        (*values)[n] = FromWide( dev_name );
+        (*descs)[n] = strdup( (*values)[n] );
+        n++;
     }
-    p_item->ppsz_list[j] = NULL;
-    p_item->ppsz_list_text[j] = NULL;
 
-    return VLC_SUCCESS;
+    return n;
 }
 
 /*
@@ -1108,3 +1063,25 @@ static uint32_t findDeviceID(char *psz_device_name)
 
     return WAVE_MAPPER;
 }
+
+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;
+    /* FIXME: volume handlers */
+    return VLC_SUCCESS;
+}
+
+static void Close(vlc_object_t *obj)
+{
+    audio_output_t *aout = (audio_output_t *)obj;
+    aout_sys_t *sys = aout->sys;
+
+    free(sys);
+}