* modules/video_output/directx/aout.c: adapted the directx audio plugin to aout3.
authorGildas Bazin <gbazin@videolan.org>
Sat, 10 Aug 2002 18:17:06 +0000 (18:17 +0000)
committerGildas Bazin <gbazin@videolan.org>
Sat, 10 Aug 2002 18:17:06 +0000 (18:17 +0000)
* modules/audio_output/waveout.c: adapted the waveout audio plugin to aout3 and
decreased its score so the directx plugin is selected by default.
* configure.in: re-enabled the waveout plugin

It's really amazing how much aout3 simplifies these plugins :)

configure.in
modules/audio_output/waveout.c
modules/video_output/directx/aout.c

index a9b5fd7..09ae663 100644 (file)
@@ -1473,7 +1473,7 @@ AC_ARG_ENABLE(waveout,
   [  --enable-waveout        Win32 waveOut module (default enabled on Win32)])
 if test "x${enable_waveout}" != "xno" -a "x${SYS}" = "xmingw32"
   then
-    #PLUGINS="${PLUGINS} audio_output/waveout"
+    PLUGINS="${PLUGINS} audio_output/waveout"
     waveout_LDFLAGS="-lwinmm"
 fi
 
index 7d61fff..552f1b2 100644 (file)
@@ -2,7 +2,7 @@
  * waveout.c : Windows waveOut plugin for vlc
  *****************************************************************************
  * Copyright (C) 2001 VideoLAN
- * $Id: waveout.c,v 1.1 2002/08/07 21:36:55 massiot Exp $
+ * $Id: waveout.c,v 1.2 2002/08/10 18:17:06 gbazin Exp $
  *
  * Authors: Gildas Bazin <gbazin@netcourrier.com>
  *      
 
 #include <vlc/vlc.h>
 #include <vlc/aout.h>
+#include "aout_internal.h"
 
 #include <mmsystem.h>
 
+#define FRAME_SIZE 2048              /* The size is in samples, not in bytes */
+
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
 static int  Open         ( vlc_object_t * );             
 static void Close        ( vlc_object_t * );                   
 
-static int  SetFormat    ( aout_thread_t * );  
-static int  GetBufInfo   ( aout_thread_t *, int );
-static void Play         ( aout_thread_t *, byte_t *, int );
+static int  SetFormat    ( aout_instance_t * );  
+static void Play         ( aout_instance_t *, aout_buffer_t * );
 
 /* local functions */
-static int     OpenWaveOutDevice( aout_thread_t *p_aout );
+static int OpenWaveOut   ( aout_instance_t *p_aout, int i_format,
+                           int i_channels, int i_rate );
+static int PlayWaveOut   ( aout_instance_t *, HWAVEOUT, WAVEHDR *,
+                           aout_buffer_t * );
+static void CALLBACK WaveOutCallback ( HWAVEOUT h_waveout, UINT uMsg,
+                                       DWORD _p_aout,
+                                       DWORD dwParam1, DWORD dwParam2 );
 
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
 vlc_module_begin();
     set_description( _("Win32 waveOut extension module") ); 
-    set_capability( "audio output", 250 );
+    set_capability( "audio output", 50 );
     set_callbacks( Open, Close );
 vlc_module_end();
 
@@ -63,20 +71,17 @@ vlc_module_end();
  * This structure is part of the audio output thread descriptor.
  * It describes the waveOut specific properties of an audio device.
  *****************************************************************************/
-
-#define NUMBUF 3           /* We use triple buffering to be on the safe side */
-
 struct aout_sys_t
 {
     HWAVEOUT h_waveout;                        /* handle to waveout instance */
 
-    WAVEFORMATEX waveformat;                                 /* Audio format */
+    WAVEFORMATEX waveformat;                                 /* audio format */
 
-    WAVEHDR waveheader[NUMBUF];
+    WAVEHDR waveheader[2];
 
-    int i_current_buffer;
+    int i_buffer_size;
 
-    DWORD dw_counter;              /* Number of bytes played since beginning */
+    byte_t *p_silence_buffer;               /* buffer we use to play silence */
 };
 
 /*****************************************************************************
@@ -86,29 +91,35 @@ struct aout_sys_t
  *****************************************************************************/
 static int Open( vlc_object_t *p_this )
 {   
-    aout_thread_t *p_aout = (aout_thread_t *)p_this;
-    int i;
+    aout_instance_t *p_aout = (aout_instance_t *)p_this;
 
     /* Allocate structure */
-    p_aout->p_sys = malloc( sizeof( aout_sys_t ) );
+    p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) );
 
-    if( p_aout->p_sys == NULL )
+    if( p_aout->output.p_sys == NULL )
     {
         msg_Err( p_aout, "out of memory" );
-        return( 1 );
+        return 1;
     }
 
-    p_aout->pf_setformat = SetFormat;
-    p_aout->pf_getbufinfo = GetBufInfo;
-    p_aout->pf_play = Play;
-
-    /* Initialize some variables */
-    p_aout->p_sys->i_current_buffer = 0;
-    for( i=0; i<NUMBUF; i++)
-        p_aout->p_sys->waveheader[i].lpData = malloc( 1 );
+    p_aout->output.pf_setformat = SetFormat;
+    p_aout->output.pf_play = Play;
 
-    return OpenWaveOutDevice( p_aout );
+    /* calculate the frame size in bytes */
+    p_aout->output.p_sys->i_buffer_size = FRAME_SIZE * sizeof(s16)
+                                  * p_aout->output.p_sys->waveformat.nChannels;
+    /* Allocate silence buffer */
+    p_aout->output.p_sys->p_silence_buffer =
+        calloc( p_aout->output.p_sys->i_buffer_size, 1 );
+    if( p_aout->output.p_sys->p_silence_buffer == NULL )
+    {
+        msg_Err( p_aout, "out of memory" );
+        return 1;
+    }
 
+    /* We need to open the device with default values to be sure it is
+     * available */
+    return OpenWaveOut( p_aout, WAVE_FORMAT_PCM, 2, 44100 );
 }
 
 /*****************************************************************************
@@ -118,108 +129,66 @@ static int Open( vlc_object_t *p_this )
  * For this we need to close the current device and create another
  * one with the desired format.
  *****************************************************************************/
-static int SetFormat( aout_thread_t *p_aout )
+static int SetFormat( aout_instance_t *p_aout )
 {
     msg_Dbg( p_aout, "SetFormat" );
 
-    /* Check if the format has changed */
+    waveOutReset( p_aout->output.p_sys->h_waveout );
 
-    if( (p_aout->p_sys->waveformat.nChannels != p_aout->i_channels) ||
-        (p_aout->p_sys->waveformat.nSamplesPerSec != p_aout->i_rate) )
-    {
-        /* Before calling waveOutClose we must reset the device */
-        waveOutReset( p_aout->p_sys->h_waveout );
+    p_aout->output.output.i_format = AOUT_FMT_S16_NE;
+    p_aout->output.i_nb_samples = FRAME_SIZE;
 
-        if( waveOutClose( p_aout->p_sys->h_waveout ) != MMSYSERR_NOERROR )
+    /* Check if the format has changed */
+    if( (p_aout->output.p_sys->waveformat.nChannels !=
+             p_aout->output.output.i_channels) ||
+        (p_aout->output.p_sys->waveformat.nSamplesPerSec !=
+             p_aout->output.output.i_rate) )
+    {
+        if( waveOutClose( p_aout->output.p_sys->h_waveout ) !=
+                MMSYSERR_NOERROR )
         {
             msg_Err( p_aout, "waveOutClose failed" );
         }
 
-        return OpenWaveOutDevice( p_aout );
-    }
-
-    return 0;
-}
+        /* calculate the frame size in bytes */
+        p_aout->output.p_sys->i_buffer_size = FRAME_SIZE * sizeof(s16)
+                                            * p_aout->output.output.i_channels;
 
-/*****************************************************************************
- * GetBufInfo: buffer status query
- *****************************************************************************
- * returns the number of bytes in the audio buffer that have not yet been
- * sent to the sound device.
- *****************************************************************************/
-static int GetBufInfo( aout_thread_t *p_aout, int i_buffer_limit )
-{
-    MMTIME mmtime;
+        /* take care of silence buffer */
+        free( p_aout->output.p_sys->p_silence_buffer );
+        p_aout->output.p_sys->p_silence_buffer =
+            calloc( p_aout->output.p_sys->i_buffer_size, 1 );
+        if( p_aout->output.p_sys->p_silence_buffer == NULL )
+        {
+            msg_Err( p_aout, "out of memory" );
+            return 1;
+        }
 
-    mmtime.wType = TIME_BYTES;
-    if( (waveOutGetPosition(p_aout->p_sys->h_waveout, &mmtime, sizeof(MMTIME)))
-        != MMSYSERR_NOERROR || (mmtime.wType != TIME_BYTES) )
-    {
-        msg_Warn( p_aout, "waveOutGetPosition failed" );
-        return i_buffer_limit;
+        if( OpenWaveOut( p_aout, WAVE_FORMAT_PCM,
+                         p_aout->output.output.i_channels,
+                         p_aout->output.output.i_rate ) )
+            return 1;
     }
 
+    /* We need to kick off the playback in order to have the callback properly
+     * working */
+    PlayWaveOut( p_aout, p_aout->output.p_sys->h_waveout,
+                 &p_aout->output.p_sys->waveheader[0], NULL );
+    PlayWaveOut( p_aout, p_aout->output.p_sys->h_waveout,
+                 &p_aout->output.p_sys->waveheader[1], NULL );
 
-#if 0
-    msg_Dbg( p_aout, "GetBufInfo: %i",
-                      p_aout->p_sys->dw_counter - mmtime.u.cb );
-#endif
-
-    return (p_aout->p_sys->dw_counter - mmtime.u.cb);
+    return 0;
 }
 
 /*****************************************************************************
  * Play: play a sound buffer
  *****************************************************************************
- * This function writes a buffer of i_length bytes
+ * 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_thread_t *p_aout, byte_t *p_buffer, int i_size )
+static void Play( aout_instance_t *p_aout, aout_buffer_t *p_buffer )
 {
-    MMRESULT result;
-    int current_buffer = p_aout->p_sys->i_current_buffer;
-
-    p_aout->p_sys->i_current_buffer = (current_buffer + 1) % NUMBUF;
-
-    /* Unprepare the old buffer */
-    waveOutUnprepareHeader( p_aout->p_sys->h_waveout,
-                            &p_aout->p_sys->waveheader[current_buffer],
-                            sizeof(WAVEHDR) );
-
-    /* Prepare the buffer */
-    p_aout->p_sys->waveheader[current_buffer].lpData =
-        realloc( p_aout->p_sys->waveheader[current_buffer].lpData, i_size );
-    if( !p_aout->p_sys->waveheader[current_buffer].lpData )
-    {
-        msg_Err( p_aout, "could not allocate buffer" );
-        return;
-    }
-    p_aout->p_sys->waveheader[current_buffer].dwBufferLength = i_size;
-    p_aout->p_sys->waveheader[current_buffer].dwFlags = 0;
-
-    result = waveOutPrepareHeader( p_aout->p_sys->h_waveout,
-                                   &p_aout->p_sys->waveheader[current_buffer],
-                                   sizeof(WAVEHDR) );
-    if( result != MMSYSERR_NOERROR )
-    {
-        msg_Err( p_aout, "waveOutPrepareHeader failed" );
-        return;
-    }
-
-    /* Send the buffer the waveOut queue */
-    p_aout->p_vlc->pf_memcpy( p_aout->p_sys->waveheader[current_buffer].lpData,
-                              p_buffer, i_size );
-    result = waveOutWrite( p_aout->p_sys->h_waveout,
-                           &p_aout->p_sys->waveheader[current_buffer],
-                           sizeof(WAVEHDR) );
-    if( result != MMSYSERR_NOERROR )
-    {
-        msg_Err( p_aout, "waveOutWrite failed" );
-        return;
-    }
-
-    /* keep track of number of bytes played */
-    p_aout->p_sys->dw_counter += i_size;
-
+    aout_FifoPush( p_aout, &p_aout->output.fifo, p_buffer );
 }
 
 /*****************************************************************************
@@ -227,60 +196,122 @@ static void Play( aout_thread_t *p_aout, byte_t *p_buffer, int i_size )
  *****************************************************************************/
 static void Close( vlc_object_t *p_this )
 {       
-    aout_thread_t *p_aout = (aout_thread_t *)p_this;
-    int i;
+    aout_instance_t *p_aout = (aout_instance_t *)p_this;
 
     /* Before calling waveOutClose we must reset the device */
-    waveOutReset( p_aout->p_sys->h_waveout );
+    waveOutReset( p_aout->output.p_sys->h_waveout );
 
     /* Close the device */
-    if( waveOutClose( p_aout->p_sys->h_waveout ) != MMSYSERR_NOERROR )
+    if( waveOutClose( p_aout->output.p_sys->h_waveout ) != MMSYSERR_NOERROR )
     {
         msg_Err( p_aout, "waveOutClose failed" );
     }
 
-    /* Deallocate memory */
-    for( i=0; i<NUMBUF; i++ )
-        free( p_aout->p_sys->waveheader[i].lpData );
+    /* Free silence buffer */
+    free( p_aout->output.p_sys->p_silence_buffer );
 
-    if( p_aout->p_sys != NULL )
+    if( p_aout->output.p_sys != NULL )
     { 
-        free( p_aout->p_sys );
-        p_aout->p_sys = NULL;
+        free( p_aout->output.p_sys );
+        p_aout->output.p_sys = NULL;
     }
 }
 
 /*****************************************************************************
- * OpenWaveOutDevice: open the sound device
+ * OpenWaveOut: open the waveout sound device
  ****************************************************************************/
-static int OpenWaveOutDevice( aout_thread_t *p_aout )
+static int OpenWaveOut( aout_instance_t *p_aout, int i_format,
+                        int i_channels, int i_rate )
 {
     MMRESULT result;
 
-    /* initialize played bytes counter */
-    p_aout->p_sys->dw_counter = 0;
-
     /* Set sound format */
-    p_aout->p_sys->waveformat.wFormatTag       = WAVE_FORMAT_PCM;
-    p_aout->p_sys->waveformat.nChannels        = p_aout->i_channels;
-    p_aout->p_sys->waveformat.nSamplesPerSec   = p_aout->i_rate;
-    p_aout->p_sys->waveformat.wBitsPerSample   = 16;
-    p_aout->p_sys->waveformat.nBlockAlign      =
-        p_aout->p_sys->waveformat.wBitsPerSample / 8 * p_aout->i_channels;
-    p_aout->p_sys->waveformat.nAvgBytesPerSec  =
-        p_aout->p_sys->waveformat.nSamplesPerSec *
-            p_aout->p_sys->waveformat.nBlockAlign;
-
+    p_aout->output.p_sys->waveformat.wFormatTag = i_format;
+    p_aout->output.p_sys->waveformat.nChannels = i_channels;
+    p_aout->output.p_sys->waveformat.nSamplesPerSec = i_rate;
+    p_aout->output.p_sys->waveformat.wBitsPerSample = 16;
+    p_aout->output.p_sys->waveformat.nBlockAlign =
+        p_aout->output.p_sys->waveformat.wBitsPerSample / 8 * i_channels;
+    p_aout->output.p_sys->waveformat.nAvgBytesPerSec  =
+        p_aout->output.p_sys->waveformat.nSamplesPerSec *
+            p_aout->output.p_sys->waveformat.nBlockAlign;
 
     /* Open the device */
-    result = waveOutOpen( &p_aout->p_sys->h_waveout, WAVE_MAPPER,
-                          &p_aout->p_sys->waveformat,
-                          0 /*callback*/, 0 /*callback data*/, CALLBACK_NULL );
+    result = waveOutOpen( &p_aout->output.p_sys->h_waveout, WAVE_MAPPER,
+                          &p_aout->output.p_sys->waveformat,
+                          (DWORD_PTR)WaveOutCallback, (DWORD_PTR)p_aout,
+                          CALLBACK_FUNCTION );
+    if( result == WAVERR_BADFORMAT )
+    {
+        msg_Err( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
+        return( 1 );
+    }
     if( result != MMSYSERR_NOERROR )
     {
         msg_Err( p_aout, "waveOutOpen failed" );
-        return( 1 );
+        return 1;
+    }
+
+    return 0;
+}
+
+/*****************************************************************************
+ * PlayWaveOut: play a buffer through the WaveOut device
+ *****************************************************************************/
+static int PlayWaveOut( aout_instance_t *p_aout, HWAVEOUT h_waveout,
+                        WAVEHDR *p_waveheader, aout_buffer_t *p_buffer )
+{
+    MMRESULT result;
+
+    /* Prepare the buffer */
+    if( p_buffer != NULL )
+        p_waveheader->lpData = p_buffer->p_buffer;
+    else
+        /* Use silence buffer instead */
+        p_waveheader->lpData = p_aout->output.p_sys->p_silence_buffer;
+
+    p_waveheader->dwUser = (DWORD_PTR)p_buffer;
+    p_waveheader->dwBufferLength = p_aout->output.p_sys->i_buffer_size;
+    p_waveheader->dwFlags = 0;
+
+    result = waveOutPrepareHeader( h_waveout, p_waveheader, sizeof(WAVEHDR) );
+    if( result != MMSYSERR_NOERROR )
+    {
+        msg_Err( p_aout, "waveOutPrepareHeader failed" );
+        return 1;
+    }
+
+    /* Send the buffer to the waveOut queue */
+    result = waveOutWrite( h_waveout, p_waveheader, sizeof(WAVEHDR) );
+    if( result != MMSYSERR_NOERROR )
+    {
+        msg_Err( p_aout, "waveOutWrite failed" );
+        return 1;
     }
 
-    return( 0 );
+    return 0;
+}
+
+/*****************************************************************************
+ * WaveOutCallback: what to do once WaveOut has played its sound samples
+ *****************************************************************************/
+static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
+                                      DWORD _p_aout,
+                                      DWORD dwParam1, DWORD dwParam2 )
+{
+    aout_instance_t * p_aout = (aout_instance_t *)_p_aout;
+    WAVEHDR *p_waveheader = (WAVEHDR *)dwParam1;
+    aout_buffer_t * p_buffer;
+
+    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 );
+
+    /* FIXME : take into account WaveOut latency instead of mdate() */
+    p_buffer = aout_OutputNextBuffer( p_aout, mdate() );
+
+    PlayWaveOut( p_aout, h_waveout, p_waveheader, p_buffer );
 }
index 84cc2ab..dc6301f 100644 (file)
@@ -2,7 +2,7 @@
  * aout.c: Windows DirectX audio output method
  *****************************************************************************
  * Copyright (C) 2001 VideoLAN
- * $Id: aout.c,v 1.1 2002/08/04 17:23:43 sam Exp $
+ * $Id: aout.c,v 1.2 2002/08/10 18:17:06 gbazin Exp $
  *
  * Authors: Gildas Bazin <gbazin@netcourrier.com>
  *
 
 #include <vlc/vlc.h>
 #include <vlc/aout.h>
+#include "aout_internal.h"
 
 #include <mmsystem.h>
 #include <dsound.h>
 
+#define FRAME_SIZE 2048              /* The size is in samples, not in bytes */
+
 /*****************************************************************************
  * DirectSound GUIDs.
  * Defining them here allows us to get rid of the dxguid library during
@@ -51,8 +54,9 @@ typedef struct notification_thread_t
 {
     VLC_COMMON_MEMBERS
 
-    aout_thread_t * p_aout;
+    aout_instance_t * p_aout;
     DSBPOSITIONNOTIFY p_events[2];               /* play notification events */
+    int i_buffer_size;                         /* Size in bytes of one frame */
 
 } notification_thread_t;
 
@@ -78,29 +82,27 @@ struct aout_sys_t
 
     HINSTANCE           hdsound_dll;      /* handle of the opened dsound dll */
 
-    long l_buffer_size;                       /* secondary sound buffer size */
-    long l_write_position;             /* next write position for the buffer */
-
-    volatile vlc_bool_t b_buffer_underflown;   /* buffer underflow detection */
-    volatile long l_data_played_from_beginning;   /* for underflow detection */
-    volatile long l_data_written_from_beginning;  /* for underflow detection */
-
     vlc_mutex_t buffer_lock;                            /* audio buffer lock */
 
     notification_thread_t * p_notif;                 /* DirectSoundThread id */
+
 };
 
+/*****************************************************************************
+ * Prototypes.
+ *****************************************************************************/
+void E_(CloseAudio) ( vlc_object_t *p_this );
+
 /*****************************************************************************
  * Local prototypes.
  *****************************************************************************/
-static int     SetFormat   ( aout_thread_t * );
-static int     GetBufInfo  ( aout_thread_t *, int );
-static void    Play        ( aout_thread_t *, byte_t *, int );
+static int  SetFormat ( aout_instance_t * );
+static void Play      ( aout_instance_t *, aout_buffer_t * );
 
 /* local functions */
-static int  DirectxCreateSecondaryBuffer ( aout_thread_t * );
-static void DirectxDestroySecondaryBuffer( aout_thread_t * );
-static int  DirectxInitDSound            ( aout_thread_t * );
+static int  DirectxCreateSecondaryBuffer ( aout_instance_t * );
+static void DirectxDestroySecondaryBuffer( aout_instance_t * );
+static int  DirectxInitDSound            ( aout_instance_t * );
 static void DirectSoundThread            ( notification_thread_t * );
 
 /*****************************************************************************
@@ -110,39 +112,36 @@ static void DirectSoundThread            ( notification_thread_t * );
  *****************************************************************************/
 int E_(OpenAudio) ( vlc_object_t *p_this )
 {
-    aout_thread_t * p_aout = (aout_thread_t *)p_this;
+    aout_instance_t * p_aout = (aout_instance_t *)p_this;
     HRESULT dsresult;
     DSBUFFERDESC dsbuffer_desc;
 
     msg_Dbg( p_aout, "Open" );
 
    /* Allocate structure */
-    p_aout->p_sys = malloc( sizeof( aout_sys_t ) );
-
-    if( p_aout->p_sys == NULL )
+    p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) );
+    if( p_aout->output.p_sys == NULL )
     {
         msg_Err( p_aout, "out of memory" );
-        return( 1 );
+        return 1;
     }
 
     /* Initialize some variables */
-    p_aout->p_sys->p_dsobject = NULL;
-    p_aout->p_sys->p_dsbuffer_primary = NULL;
-    p_aout->p_sys->p_dsbuffer = NULL;
-    p_aout->p_sys->p_dsnotify = NULL;
-    p_aout->p_sys->l_data_written_from_beginning = 0;
-    p_aout->p_sys->l_data_played_from_beginning = 0;
-    vlc_mutex_init( p_aout, &p_aout->p_sys->buffer_lock );
-
-    p_aout->pf_setformat = SetFormat;
-    p_aout->pf_getbufinfo = GetBufInfo;
-    p_aout->pf_play = Play;
+    p_aout->output.p_sys->p_dsobject = NULL;
+    p_aout->output.p_sys->p_dsbuffer_primary = NULL;
+    p_aout->output.p_sys->p_dsbuffer = NULL;
+    p_aout->output.p_sys->p_dsnotify = NULL;
+    p_aout->output.p_sys->p_notif = NULL;
+    vlc_mutex_init( p_aout, &p_aout->output.p_sys->buffer_lock );
+
+    p_aout->output.pf_setformat = SetFormat;
+    p_aout->output.pf_play = Play;
 
     /* Initialise DirectSound */
     if( DirectxInitDSound( p_aout ) )
     {
-        msg_Warn( p_aout, "cannot initialize DirectSound" );
-        return( 1 );
+        msg_Err( p_aout, "cannot initialize DirectSound" );
+        goto error;
     }
 
     /* Obtain (not create) Direct Sound primary buffer */
@@ -150,43 +149,45 @@ int E_(OpenAudio) ( vlc_object_t *p_this )
     dsbuffer_desc.dwSize = sizeof(DSBUFFERDESC);
     dsbuffer_desc.dwFlags = DSBCAPS_PRIMARYBUFFER;
     msg_Warn( p_aout, "create direct sound primary buffer" );
-    dsresult = IDirectSound_CreateSoundBuffer(p_aout->p_sys->p_dsobject,
-                                            &dsbuffer_desc,
-                                            &p_aout->p_sys->p_dsbuffer_primary,
-                                            NULL);
+    dsresult = IDirectSound_CreateSoundBuffer(p_aout->output.p_sys->p_dsobject,
+                                     &dsbuffer_desc,
+                                     &p_aout->output.p_sys->p_dsbuffer_primary,
+                                     NULL);
     if( dsresult != DS_OK )
     {
-        msg_Warn( p_aout, "cannot create direct sound primary buffer" );
-        IDirectSound_Release( p_aout->p_sys->p_dsobject );
-        p_aout->p_sys->p_dsobject = NULL;
-        p_aout->p_sys->p_dsbuffer_primary = NULL;
-        return( 1 );
+        msg_Err( p_aout, "cannot create direct sound primary buffer" );
+        goto error;
     }
 
 
     /* Now we need to setup DirectSound play notification */
+    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;
 
     /* first we need to create the notification events */
-    p_aout->p_sys->p_notif->p_events[0].hEventNotify =
+    p_aout->output.p_sys->p_notif->p_events[0].hEventNotify =
         CreateEvent( NULL, FALSE, FALSE, NULL );
-    p_aout->p_sys->p_notif->p_events[1].hEventNotify =
+    p_aout->output.p_sys->p_notif->p_events[1].hEventNotify =
         CreateEvent( NULL, FALSE, FALSE, NULL );
 
     /* then launch the notification thread */
     msg_Dbg( p_aout, "creating DirectSoundThread" );
-    p_aout->p_sys->p_notif =
-                vlc_object_create( p_aout, sizeof(notification_thread_t) );
-    p_aout->p_sys->p_notif->p_aout = p_aout;
-    if( vlc_thread_create( p_aout->p_sys->p_notif,
-                    "DirectSound Notification Thread", DirectSoundThread, 1 ) )
+    if( vlc_thread_create( p_aout->output.p_sys->p_notif,
+                           "DirectSound Notification Thread",
+                           DirectSoundThread, 1 ) )
     {
         msg_Err( p_aout, "cannot create DirectSoundThread" );
-        /* Let's go on anyway */
+        goto error;
     }
 
-    vlc_object_attach( p_aout->p_sys->p_notif, p_aout );
+    vlc_object_attach( p_aout->output.p_sys->p_notif, p_aout );
+
+    return 0;
 
-    return( 0 );
+ error:
+    E_(CloseAudio)( VLC_OBJECT(p_aout) );
+    return 1;
 }
 
 /*****************************************************************************
@@ -196,223 +197,60 @@ int E_(OpenAudio) ( vlc_object_t *p_this )
  * For this we need to close the current secondary buffer and create another
  * one with the desired format.
  *****************************************************************************/
-static int SetFormat( aout_thread_t *p_aout )
+static int SetFormat( aout_instance_t *p_aout )
 {
-    HRESULT       dsresult;
-    WAVEFORMATEX  *p_waveformat;
-    unsigned long i_size_struct;
+    HRESULT dsresult;
 
     msg_Dbg( p_aout, "SetFormat" );
-
-    /* Set the format of Direct Sound primary buffer */
-
-    /* first we need to know the current format */
-    dsresult = IDirectSoundBuffer_GetFormat( p_aout->p_sys->p_dsbuffer_primary,
-                                             NULL, 0, &i_size_struct );
-    if( dsresult == DS_OK )
-    {
-        p_waveformat = malloc( i_size_struct );
-        dsresult = IDirectSoundBuffer_GetFormat(
-                                             p_aout->p_sys->p_dsbuffer_primary,
-                                             p_waveformat, i_size_struct,
-                                             NULL );
-    }
-
-    if( dsresult == DS_OK )
-    {
-        /* Here we'll change the format */
-        p_waveformat->nChannels        = 2; 
-        p_waveformat->nSamplesPerSec   = (p_aout->i_rate < 44100) ? 44100
-                                             : p_aout->i_rate; 
-        p_waveformat->wBitsPerSample   = 16; 
-        p_waveformat->nBlockAlign      = p_waveformat->wBitsPerSample / 8 *
-                                             p_waveformat->nChannels;
-        p_waveformat->nAvgBytesPerSec  = p_waveformat->nSamplesPerSec *
-                                             p_waveformat->nBlockAlign;
-
-        dsresult = IDirectSoundBuffer_SetFormat(
-                                             p_aout->p_sys->p_dsbuffer_primary,
-                                             p_waveformat );
-    }
-    else msg_Warn( p_aout, "cannot get primary buffer format" );
-
-    if( dsresult != DS_OK )
-        msg_Warn( p_aout, "cannot set primary buffer format" );
-
-
-    /* Now we need to take care of Direct Sound secondary buffer */
-
-    vlc_mutex_lock( &p_aout->p_sys->buffer_lock );
+    vlc_mutex_lock( &p_aout->output.p_sys->buffer_lock );
 
     /* first release the current secondary buffer */
     DirectxDestroySecondaryBuffer( p_aout );
 
+    /* calculate the frame size in bytes */
+    p_aout->output.p_sys->p_notif->i_buffer_size = FRAME_SIZE * sizeof(s16)
+                                            * p_aout->output.output.i_channels;
+
     /* then create a new secondary buffer */
     if( DirectxCreateSecondaryBuffer( p_aout ) )
     {
-        msg_Warn( p_aout, "cannot create buffer" );
-        vlc_mutex_unlock( &p_aout->p_sys->buffer_lock );
-        return( 1 );
-    }
-
-    vlc_mutex_unlock( &p_aout->p_sys->buffer_lock );
-
-    return( 0 );
-}
-
-/*****************************************************************************
- * GetBufInfo: buffer status query
- *****************************************************************************
- * returns the number of bytes in the audio buffer that have not yet been
- * sent to the sound device.
- *****************************************************************************/
-static int GetBufInfo( aout_thread_t *p_aout, int i_buffer_limit )
-{
-    long l_play_position, l_notused, l_result;
-    HRESULT dsresult;
-
-    if( p_aout->p_sys->b_buffer_underflown )
-    {
-        msg_Warn( p_aout, "GetBufInfo underflow" );
-        return( i_buffer_limit );
+        msg_Err( p_aout, "cannot create buffer" );
+        vlc_mutex_unlock( &p_aout->output.p_sys->buffer_lock );
+        return 1;
     }
 
-    dsresult = IDirectSoundBuffer_GetCurrentPosition(p_aout->p_sys->p_dsbuffer,
-                                                 &l_play_position, &l_notused);
-    if( dsresult != DS_OK )
-    {
-        msg_Warn( p_aout, "GetBufInfo cannot get current pos" );
-        return( i_buffer_limit );
-    }
+    vlc_mutex_unlock( &p_aout->output.p_sys->buffer_lock );
 
-    l_result = (p_aout->p_sys->l_write_position >= l_play_position) ?
-      (p_aout->p_sys->l_write_position - l_play_position)
-               : (p_aout->p_sys->l_buffer_size - l_play_position
-                  + p_aout->p_sys->l_write_position);
-
-#if 0
-    msg_Dbg( p_aout, "GetBufInfo: %i", i_result);
-#endif
-    return l_result;
-}
-
-/*****************************************************************************
- * Play: play a sound buffer
- *****************************************************************************
- * This function writes a buffer of i_length bytes
- * Don't forget that DirectSound buffers are circular buffers.
- *****************************************************************************/
-static void Play( aout_thread_t *p_aout, byte_t *buffer, int i_size )
-{
-    VOID            *p_write_position, *p_start_buffer;
-    long            l_bytes1, l_bytes2, l_play_position;
-    HRESULT         dsresult;
-
-    /* protect buffer access (because of DirectSoundThread) */
-    vlc_mutex_lock( &p_aout->p_sys->buffer_lock );
-
-    if( p_aout->p_sys->b_buffer_underflown )
-    {
-        /*  there has been an underflow so we need to play the new sample
-         *  as soon as possible. This is why we query the play position */
-        dsresult = IDirectSoundBuffer_GetCurrentPosition(
-                                            p_aout->p_sys->p_dsbuffer,
-                                            &l_play_position,
-                                            &p_aout->p_sys->l_write_position );
-        if( dsresult != DS_OK )
-        {
-            msg_Warn( p_aout, "cannot get buffer position" );
-            p_aout->p_sys->l_write_position = 0; 
-        }
-
-        msg_Warn( p_aout, "Play underflow" );
-        /* reinitialise the underflow detection counters */
-        p_aout->p_sys->b_buffer_underflown = 0;
-        p_aout->p_sys->l_data_written_from_beginning = 0;
-
-#define WRITE_P  p_aout->p_sys->l_write_position
-#define PLAY_P   l_play_position
-#define BUF_SIZE p_aout->p_sys->l_buffer_size
-        p_aout->p_sys->l_data_played_from_beginning = -(WRITE_P %(BUF_SIZE/2));
-        if( PLAY_P < BUF_SIZE/2 && WRITE_P > BUF_SIZE/2 )
-        {
-            p_aout->p_sys->l_data_played_from_beginning -= (BUF_SIZE/2);
-        }
-        if( PLAY_P > BUF_SIZE/2 && WRITE_P < BUF_SIZE/2 )
-        {
-            p_aout->p_sys->l_data_played_from_beginning -= (BUF_SIZE/2);
-        }        
-#undef WRITE_P
-#undef PLAY_P
-#undef BUF_SIZE
-    }
-
-    /* Before copying anything, we have to lock the buffer */
-    dsresult = IDirectSoundBuffer_Lock( p_aout->p_sys->p_dsbuffer,
-                   p_aout->p_sys->l_write_position,  /* Offset of lock start */
-                   i_size,                        /* Number of bytes to lock */
-                   &p_write_position,               /* Address of lock start */
-                   &l_bytes1,    /* Count of bytes locked before wrap around */
-                   &p_start_buffer,        /* Buffer adress (if wrap around) */
-                   &l_bytes2,            /* Count of bytes after wrap around */
-                   0);                                              /* Flags */
-    if( dsresult == DSERR_BUFFERLOST )
-    {
-        IDirectSoundBuffer_Restore( p_aout->p_sys->p_dsbuffer );
-        dsresult = IDirectSoundBuffer_Lock( p_aout->p_sys->p_dsbuffer,
-                                            p_aout->p_sys->l_write_position,
-                                            i_size,
-                                            &p_write_position,
-                                            &l_bytes1,
-                                            &p_start_buffer,
-                                            &l_bytes2,
-                                            0);
-
-    }
-    if( dsresult != DS_OK )
-    {
-        msg_Warn( p_aout, "Play cannot lock buffer" );
-        vlc_mutex_unlock( &p_aout->p_sys->buffer_lock );
-        return;
-    }
-
-    /* Now do the actual memcpy (two memcpy because the buffer is circular) */
-    memcpy( p_write_position, buffer, l_bytes1 );
-    if( p_start_buffer != NULL )
-    {
-        memcpy( p_start_buffer, buffer + l_bytes1, l_bytes2 );
-    }
-
-    /* Now the data has been copied, unlock the buffer */
-    IDirectSoundBuffer_Unlock( p_aout->p_sys->p_dsbuffer, 
-            p_write_position, l_bytes1, p_start_buffer, l_bytes2 );
-
-    /* Update the write position index of the buffer*/
-    p_aout->p_sys->l_write_position += i_size;
-    p_aout->p_sys->l_write_position %= p_aout->p_sys->l_buffer_size;
-    p_aout->p_sys->l_data_written_from_beginning += i_size;
-
-    vlc_mutex_unlock( &p_aout->p_sys->buffer_lock );
-
-    /* The play function has no effect if the buffer is already playing */
-    dsresult = IDirectSoundBuffer_Play( p_aout->p_sys->p_dsbuffer,
+    /* start playing the buffer */
+    dsresult = IDirectSoundBuffer_Play( p_aout->output.p_sys->p_dsbuffer,
                                         0,                         /* Unused */
                                         0,                         /* Unused */
                                         DSBPLAY_LOOPING );          /* Flags */
     if( dsresult == DSERR_BUFFERLOST )
     {
-        IDirectSoundBuffer_Restore( p_aout->p_sys->p_dsbuffer );
-        dsresult = IDirectSoundBuffer_Play( p_aout->p_sys->p_dsbuffer,
+        IDirectSoundBuffer_Restore( p_aout->output.p_sys->p_dsbuffer );
+        dsresult = IDirectSoundBuffer_Play( p_aout->output.p_sys->p_dsbuffer,
                                             0,                     /* Unused */
                                             0,                     /* Unused */
                                             DSBPLAY_LOOPING );      /* Flags */
     }
     if( dsresult != DS_OK )
     {
-        msg_Warn( p_aout, "Play cannot play buffer" );
-        return;
+        msg_Warn( p_aout, "cannot play buffer" );
     }
 
+    return 0;
+}
+
+/*****************************************************************************
+ * Play: play a sound buffer
+ *****************************************************************************
+ * 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, aout_buffer_t *p_buffer )
+{
+    aout_FifoPush( p_aout, &p_aout->output.fifo, p_buffer );
 }
 
 /*****************************************************************************
@@ -420,85 +258,74 @@ static void Play( aout_thread_t *p_aout, byte_t *buffer, int i_size )
  *****************************************************************************/
 void E_(CloseAudio) ( vlc_object_t *p_this )
 {
-    aout_thread_t * p_aout = (aout_thread_t *)p_this;
+    aout_instance_t * p_aout = (aout_instance_t *)p_this;
 
     msg_Dbg( p_aout, "Close" );
 
     /* kill the position notification thread, if any */
-    vlc_object_detach_all( p_aout->p_sys->p_notif );
-    if( p_aout->p_sys->p_notif->b_thread )
+    if( p_aout->output.p_sys->p_notif )
     {
-        p_aout->p_sys->p_notif->b_die = 1;
-        vlc_thread_join( p_aout->p_sys->p_notif );
+        vlc_object_detach_all( p_aout->output.p_sys->p_notif );
+        if( p_aout->output.p_sys->p_notif->b_thread )
+        {
+            p_aout->output.p_sys->p_notif->b_die = 1;
+            vlc_thread_join( p_aout->output.p_sys->p_notif );
+        }
+        vlc_object_destroy( p_aout->output.p_sys->p_notif );
     }
-    vlc_object_destroy( p_aout->p_sys->p_notif );
 
     /* release the secondary buffer */
     DirectxDestroySecondaryBuffer( p_aout );
 
     /* then release the primary buffer */
-    if( p_aout->p_sys->p_dsbuffer_primary != NULL )
-    {
-        IDirectSoundBuffer_Release( p_aout->p_sys->p_dsbuffer_primary );
-        p_aout->p_sys->p_dsbuffer_primary = NULL;
-    }  
+    if( p_aout->output.p_sys->p_dsbuffer_primary )
+        IDirectSoundBuffer_Release( p_aout->output.p_sys->p_dsbuffer_primary );
 
     /* finally release the DirectSound object */
-    if( p_aout->p_sys->p_dsobject != NULL )
-    {
-        IDirectSound_Release( p_aout->p_sys->p_dsobject );
-        p_aout->p_sys->p_dsobject = NULL;
-    }  
+    if( p_aout->output.p_sys->p_dsobject )
+        IDirectSound_Release( p_aout->output.p_sys->p_dsobject );
     
     /* free DSOUND.DLL */
-    if( p_aout->p_sys->hdsound_dll != NULL )
-    {
-       FreeLibrary( p_aout->p_sys->hdsound_dll );
-       p_aout->p_sys->hdsound_dll = NULL;
-    }
+    if( p_aout->output.p_sys->hdsound_dll )
+       FreeLibrary( p_aout->output.p_sys->hdsound_dll );
 
     /* Close the Output. */
-    if ( p_aout->p_sys != NULL )
+    if ( p_aout->output.p_sys  )
     { 
-        free( p_aout->p_sys );
-        p_aout->p_sys = NULL;
+        free( p_aout->output.p_sys );
+        p_aout->output.p_sys = NULL;
     }
 }
 
 /*****************************************************************************
- * DirectxInitDSound
- *****************************************************************************
+ * DirectxInitDSound: handle all the gory details of DirectSound initialisation
  *****************************************************************************/
-static int DirectxInitDSound( aout_thread_t *p_aout )
+static int DirectxInitDSound( aout_instance_t *p_aout )
 {
     HRESULT (WINAPI *OurDirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN);
 
-    p_aout->p_sys->hdsound_dll = LoadLibrary("DSOUND.DLL");
-    if( p_aout->p_sys->hdsound_dll == NULL )
+    p_aout->output.p_sys->hdsound_dll = LoadLibrary("DSOUND.DLL");
+    if( p_aout->output.p_sys->hdsound_dll == NULL )
     {
-      msg_Warn( p_aout, "cannot open DSOUND.DLL" );
-      return( 1 );
+        msg_Warn( p_aout, "cannot open DSOUND.DLL" );
+        goto error;
     }
 
-    OurDirectSoundCreate = (void *)GetProcAddress( p_aout->p_sys->hdsound_dll,
-                                                   "DirectSoundCreate" );
-
+    OurDirectSoundCreate = (void *)GetProcAddress(
+                                           p_aout->output.p_sys->hdsound_dll,
+                                           "DirectSoundCreate" );
     if( OurDirectSoundCreate == NULL )
     {
-      msg_Warn( p_aout, "GetProcAddress FAILED" );
-      FreeLibrary( p_aout->p_sys->hdsound_dll );
-      p_aout->p_sys->hdsound_dll = NULL;
-      return( 1 );
+        msg_Warn( p_aout, "GetProcAddress FAILED" );
+        goto error;
     }
 
     /* Create the direct sound object */
-    if( OurDirectSoundCreate(NULL, &p_aout->p_sys->p_dsobject, NULL) != DS_OK )
+    if( OurDirectSoundCreate( NULL, &p_aout->output.p_sys->p_dsobject, NULL )
+        != DS_OK )
     {
         msg_Warn( p_aout, "cannot create a direct sound device" );
-        p_aout->p_sys->p_dsobject = NULL;
-        FreeLibrary( p_aout->p_sys->hdsound_dll );
-        p_aout->p_sys->hdsound_dll = NULL;
-        return( 1 );
+        goto error;
     }
 
     /* Set DirectSound Cooperative level, ie what control we want over Windows
@@ -511,14 +338,24 @@ static int DirectxInitDSound( aout_thread_t *p_aout )
      * sound without any video, and so what window handle should we use ???
      * The hack for now is to use the Desktop window handle - it seems to be
      * working */
-    if( IDirectSound_SetCooperativeLevel(p_aout->p_sys->p_dsobject,
-                                         GetDesktopWindow(),
-                                         DSSCL_EXCLUSIVE) )
+    if( IDirectSound_SetCooperativeLevel( p_aout->output.p_sys->p_dsobject,
+                                          GetDesktopWindow(),
+                                          DSSCL_EXCLUSIVE) )
     {
         msg_Warn( p_aout, "cannot set direct sound cooperative level" );
     }
 
-    return( 0 );
+    return 0;
+
+ error:
+    p_aout->output.p_sys->p_dsobject = NULL;
+    if( p_aout->output.p_sys->hdsound_dll )
+    {
+        FreeLibrary( p_aout->output.p_sys->hdsound_dll );
+        p_aout->output.p_sys->hdsound_dll = NULL;
+    }
+    return 1;
+
 }
 
 /*****************************************************************************
@@ -533,7 +370,7 @@ static int DirectxInitDSound( aout_thread_t *p_aout )
  * Once you create a secondary buffer, you cannot change its format anymore so
  * you have to release the current and create another one.
  *****************************************************************************/
-static int DirectxCreateSecondaryBuffer( aout_thread_t *p_aout )
+static int DirectxCreateSecondaryBuffer( aout_instance_t *p_aout )
 {
     WAVEFORMATEX         waveformat;
     DSBUFFERDESC         dsbdesc;
@@ -542,8 +379,8 @@ static int DirectxCreateSecondaryBuffer( aout_thread_t *p_aout )
     /* First set the buffer format */
     memset(&waveformat, 0, sizeof(WAVEFORMATEX)); 
     waveformat.wFormatTag      = WAVE_FORMAT_PCM; 
-    waveformat.nChannels       = p_aout->i_channels; 
-    waveformat.nSamplesPerSec  = p_aout->i_rate; 
+    waveformat.nChannels       = p_aout->output.output.i_channels;
+    waveformat.nSamplesPerSec  = p_aout->output.output.i_rate; 
     waveformat.wBitsPerSample  = 16; 
     waveformat.nBlockAlign     = waveformat.wBitsPerSample / 8 *
                                  waveformat.nChannels;
@@ -556,104 +393,108 @@ static int DirectxCreateSecondaryBuffer( aout_thread_t *p_aout )
     dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2/* Better position accuracy */
                     | DSBCAPS_CTRLPOSITIONNOTIFY     /* We need notification */
                     | DSBCAPS_GLOBALFOCUS;      /* Allows background playing */
-    dsbdesc.dwBufferBytes = waveformat.nAvgBytesPerSec * 2;  /* 2 sec buffer */
+    dsbdesc.dwBufferBytes = FRAME_SIZE * 2 /* frames*/ *      /* buffer size */
+                            sizeof(s16) * p_aout->output.output.i_channels;
     dsbdesc.lpwfxFormat = &waveformat; 
  
-    if( IDirectSound_CreateSoundBuffer( p_aout->p_sys->p_dsobject,
+    if( IDirectSound_CreateSoundBuffer( p_aout->output.p_sys->p_dsobject,
                                         &dsbdesc,
-                                        &p_aout->p_sys->p_dsbuffer,
+                                        &p_aout->output.p_sys->p_dsbuffer,
                                         NULL) != DS_OK )
     {
         msg_Warn( p_aout, "cannot create direct sound secondary buffer" );
-        p_aout->p_sys->p_dsbuffer = NULL;
-        return( 1 );
+        goto error;
     }
 
     /* backup the size of the secondary sound buffer */
     memset(&dsbcaps, 0, sizeof(DSBCAPS)); 
     dsbcaps.dwSize = sizeof(DSBCAPS);
-    IDirectSoundBuffer_GetCaps( p_aout->p_sys->p_dsbuffer, &dsbcaps  );
-    p_aout->p_sys->l_buffer_size = dsbcaps.dwBufferBytes;
-    p_aout->p_sys->l_write_position = 0;
+    IDirectSoundBuffer_GetCaps( p_aout->output.p_sys->p_dsbuffer, &dsbcaps  );
 
     msg_Dbg( p_aout, "DirectxCreateSecondaryBuffer: %li",
-                     p_aout->p_sys->l_buffer_size );
+             dsbcaps.dwBufferBytes );
 
     /* Now the secondary buffer is created, we need to setup its position
      * notification */
-    p_aout->p_sys->p_notif->p_events[0].dwOffset = 0;    /* notif position */
-    p_aout->p_sys->p_notif->p_events[1].dwOffset = dsbcaps.dwBufferBytes / 2;
+    p_aout->output.p_sys->p_notif->p_events[0].dwOffset = 0;
+    p_aout->output.p_sys->p_notif->p_events[1].dwOffset =
+        p_aout->output.p_sys->p_notif->i_buffer_size;
 
     /* Get the IDirectSoundNotify interface */
-    if FAILED( IDirectSoundBuffer_QueryInterface( p_aout->p_sys->p_dsbuffer,
-                                                  &IID_IDirectSoundNotify,
-                                       (LPVOID *)&p_aout->p_sys->p_dsnotify ) )
+    if FAILED( IDirectSoundBuffer_QueryInterface(
+                                p_aout->output.p_sys->p_dsbuffer,
+                                &IID_IDirectSoundNotify,
+                                (LPVOID *)&p_aout->output.p_sys->p_dsnotify ) )
     {
         msg_Warn( p_aout, "cannot get Notify interface" );
-        /* Go on anyway */
-        p_aout->p_sys->p_dsnotify = NULL;
-        return( 0 );
+        goto error;
     }
         
     if FAILED( IDirectSoundNotify_SetNotificationPositions(
-                                        p_aout->p_sys->p_dsnotify,
-                                        2,
-                                        p_aout->p_sys->p_notif->p_events ) )
+                                    p_aout->output.p_sys->p_dsnotify, 2,
+                                    p_aout->output.p_sys->p_notif->p_events ) )
     {
         msg_Warn( p_aout, "cannot set position Notification" );
-        /* Go on anyway */
+        goto error;
     }
 
-    return( 0 );
+    p_aout->output.output.i_format = AOUT_FMT_S16_NE;
+    p_aout->output.i_nb_samples = FRAME_SIZE;
+
+    return 0;
+
+ error:
+    if( p_aout->output.p_sys->p_dsbuffer )
+    {
+        IDirectSoundBuffer_Release( p_aout->output.p_sys->p_dsbuffer );
+        p_aout->output.p_sys->p_dsbuffer = NULL;
+    }
+    if( p_aout->output.p_sys->p_dsnotify )
+    {
+        IDirectSoundBuffer_Release( p_aout->output.p_sys->p_dsbuffer );
+        p_aout->output.p_sys->p_dsnotify = NULL;
+    }
+    return 1;
 }
 
 /*****************************************************************************
  * DirectxCreateSecondaryBuffer
  *****************************************************************************
- * This function destroy the secondary buffer.
+ * This function destroys the secondary buffer.
  *****************************************************************************/
-static void DirectxDestroySecondaryBuffer( aout_thread_t *p_aout )
+static void DirectxDestroySecondaryBuffer( aout_instance_t *p_aout )
 {
     /* make sure the buffer isn't playing */
-    if( p_aout->p_sys->p_dsbuffer != NULL )
-    {
-        IDirectSoundBuffer_Stop( p_aout->p_sys->p_dsbuffer );
-    }
+    if( p_aout->output.p_sys->p_dsbuffer )
+        IDirectSoundBuffer_Stop( p_aout->output.p_sys->p_dsbuffer );
 
-    if( p_aout->p_sys->p_dsnotify != NULL )
+    if( p_aout->output.p_sys->p_dsnotify )
     {
-        IDirectSoundNotify_Release( p_aout->p_sys->p_dsnotify );
-        p_aout->p_sys->p_dsnotify = NULL;
+        IDirectSoundNotify_Release( p_aout->output.p_sys->p_dsnotify );
+        p_aout->output.p_sys->p_dsnotify = NULL;
     }
 
-    if( p_aout->p_sys->p_dsbuffer != NULL )
+    if( p_aout->output.p_sys->p_dsbuffer )
     {
-        IDirectSoundBuffer_Release( p_aout->p_sys->p_dsbuffer );
-        p_aout->p_sys->p_dsbuffer = NULL;
+        IDirectSoundBuffer_Release( p_aout->output.p_sys->p_dsbuffer );
+        p_aout->output.p_sys->p_dsbuffer = NULL;
     }
 }
 
 /*****************************************************************************
  * DirectSoundThread: this thread will capture play notification events. 
  *****************************************************************************
- * As Direct Sound uses circular buffers, we need to use event notification to
- * manage them.
- * Using event notification implies blocking the thread until the event is
- * signaled so we really need to run this in a separate thread.
+ * We use this thread to emulate a callback mechanism. The thread probes for
+ * event notification and fills up the DS secondary buffer when needed.
  *****************************************************************************/
 static void DirectSoundThread( notification_thread_t *p_notif )
 {
     HANDLE  notification_events[2];
-    VOID    *p_write_position, *p_start_buffer;
-    long    l_bytes1, l_bytes2;
     HRESULT dsresult;
-    long    l_buffer_size, l_play_position, l_data_in_buffer;
+    aout_instance_t *p_aout = p_notif->p_aout;
 
-    aout_thread_t *p_aout = p_notif->p_aout;
-
-#define P_EVENTS p_aout->p_sys->p_notif->p_events
-    notification_events[0] = P_EVENTS[0].hEventNotify;
-    notification_events[1] = P_EVENTS[1].hEventNotify;
+    notification_events[0] = p_notif->p_events[0].hEventNotify;
+    notification_events[1] = p_notif->p_events[1].hEventNotify;
 
     /* Tell the main thread that we are ready */
     vlc_thread_ready( p_notif );
@@ -662,93 +503,86 @@ static void DirectSoundThread( notification_thread_t *p_notif )
     if( !SetThreadPriority( GetCurrentThread(),
                             THREAD_PRIORITY_ABOVE_NORMAL ) )
     {
-        msg_Warn( p_notif, "DirectSoundThread could not renice itself" );
+        msg_Warn( p_notif, "DirectSoundThread could not raise its priority" );
     }
 
     msg_Dbg( p_notif, "DirectSoundThread ready" );
 
     while( !p_notif->b_die )
     {
+        int i_which_event;
+        void *p_write_position, *p_wrap_around;
+        long l_bytes1, l_bytes2;
+        aout_buffer_t * p_buffer;
+
         /* wait for the position notification */
-        l_play_position = WaitForMultipleObjects( 2, notification_events,
-                                                  0, INFINITE ); 
-        vlc_mutex_lock( &p_aout->p_sys->buffer_lock );
+        i_which_event = WaitForMultipleObjects( 2, notification_events, 0,
+                                                INFINITE ) - WAIT_OBJECT_0;
+
+        vlc_mutex_lock( &p_aout->output.p_sys->buffer_lock );
 
         if( p_notif->b_die )
         {
+            vlc_mutex_unlock( &p_aout->output.p_sys->buffer_lock );
             break;
         }
 
-        /* check for buffer underflow (bodge for wrap around) */
-        l_buffer_size = p_aout->p_sys->l_buffer_size;
-        l_play_position = (l_play_position - WAIT_OBJECT_0) * l_buffer_size/2;
-        p_aout->p_sys->l_data_played_from_beginning += (l_buffer_size/2);
-        l_data_in_buffer = p_aout->p_sys->l_data_written_from_beginning -
-                               p_aout->p_sys->l_data_played_from_beginning; 
-
-        /* detect wrap-around */
-        if( l_data_in_buffer < (-l_buffer_size/2) )
+        /* Before copying anything, we have to lock the buffer */
+        dsresult = IDirectSoundBuffer_Lock(
+                                                                /* DS buffer */
+            p_aout->output.p_sys->p_dsbuffer,
+                                                     /* Offset of lock start */
+            i_which_event ? 0 : p_notif->i_buffer_size,
+            p_notif->i_buffer_size,                 /* Number of bytes */
+            &p_write_position,                      /* Address of lock start */
+            &l_bytes1,           /* Count of bytes locked before wrap around */
+            &p_wrap_around,                /* Buffer adress (if wrap around) */
+            &l_bytes2,                   /* Count of bytes after wrap around */
+            0 );                                                    /* Flags */
+        if( dsresult == DSERR_BUFFERLOST )
         {
-            msg_Dbg( p_notif, "DirectSoundThread wrap around: %li",
-                              l_data_in_buffer );
-            l_data_in_buffer += l_buffer_size;
+            IDirectSoundBuffer_Restore( p_aout->output.p_sys->p_dsbuffer );
+            dsresult = IDirectSoundBuffer_Lock(
+                           p_aout->output.p_sys->p_dsbuffer,
+                           i_which_event ? 0 : p_notif->i_buffer_size,
+                           p_notif->i_buffer_size,
+                           &p_write_position,
+                           &l_bytes1,
+                           &p_wrap_around,
+                           &l_bytes2,
+                           0 );
         }
-
-        /* detect underflow */
-        if( l_data_in_buffer <= 0 )
+        if( dsresult != DS_OK )
         {
-            msg_Warn( p_notif,
-                      "DirectSoundThread underflow: %li", l_data_in_buffer );
-            p_aout->p_sys->b_buffer_underflown = 1;
-            p_aout->p_sys->l_write_position =
-                  (l_play_position + l_buffer_size/2) % l_buffer_size;
-            l_data_in_buffer = l_buffer_size / 2;
-            p_aout->p_sys->l_data_played_from_beginning -= (l_buffer_size/2);
+            msg_Warn( p_notif, "cannot lock buffer" );
+            vlc_mutex_unlock( &p_aout->output.p_sys->buffer_lock );
+            continue;
         }
 
+        /* FIXME : take into account DirectSound latency instead of mdate() */
+        p_buffer = aout_OutputNextBuffer( p_aout, mdate() );
 
-        /* Clear the data which has already been played */
+        /* Now do the actual memcpy into the circular buffer */
+        if ( l_bytes1 != p_notif->i_buffer_size )
+            msg_Err( p_aout, "Wrong buffer size: %d, %d", l_bytes1,
+                     p_notif->i_buffer_size );
 
-        /* Before copying anything, we have to lock the buffer */
-        dsresult = IDirectSoundBuffer_Lock( p_aout->p_sys->p_dsbuffer,
-                   p_aout->p_sys->l_write_position,  /* Offset of lock start */
-                   l_buffer_size - l_data_in_buffer,      /* Number of bytes */
-                   &p_write_position,               /* Address of lock start */
-                   &l_bytes1,    /* Count of bytes locked before wrap around */
-                   &p_start_buffer,        /* Buffer adress (if wrap around) */
-                   &l_bytes2,            /* Count of bytes after wrap around */
-                   0);                                              /* Flags */
-        if( dsresult == DSERR_BUFFERLOST )
+        if ( p_buffer != NULL )
         {
-            IDirectSoundBuffer_Restore( p_aout->p_sys->p_dsbuffer );
-            dsresult = IDirectSoundBuffer_Lock( p_aout->p_sys->p_dsbuffer,
-                                          p_aout->p_sys->l_write_position,
-                                          l_buffer_size - l_data_in_buffer,
-                                          &p_write_position,
-                                          &l_bytes1,
-                                          &p_start_buffer,
-                                          &l_bytes2,
-                                          0);
+            p_aout->p_vlc->pf_memcpy( p_write_position, p_buffer->p_buffer,
+                                      l_bytes1 );
+            aout_BufferFree( p_buffer );
         }
-        if( dsresult != DS_OK )
-        {
-            msg_Warn( p_notif, "Play cannot lock buffer" );
-            vlc_mutex_unlock( &p_aout->p_sys->buffer_lock );
-            return;
-        }
-
-        /* Now do the actual memcpy (two because the buffer is circular) */
-        memset( p_write_position, 0, l_bytes1 );
-        if( p_start_buffer != NULL )
+        else
         {
-            memset( p_start_buffer, 0, l_bytes2 );
+            memset( p_write_position, 0, l_bytes1 );
         }
 
         /* Now the data has been copied, unlock the buffer */
-        IDirectSoundBuffer_Unlock( p_aout->p_sys->p_dsbuffer, 
-                        p_write_position, l_bytes1, p_start_buffer, l_bytes2 );
+        IDirectSoundBuffer_Unlock( p_aout->output.p_sys->p_dsbuffer,
+                        p_write_position, l_bytes1, p_wrap_around, l_bytes2 );
 
-        vlc_mutex_unlock( &p_aout->p_sys->buffer_lock );
+        vlc_mutex_unlock( &p_aout->output.p_sys->buffer_lock );
 
     }