* 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();
* 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 */
};
/*****************************************************************************
*****************************************************************************/
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 );
}
/*****************************************************************************
* 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 );
}
/*****************************************************************************
*****************************************************************************/
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 );
}
* 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
{
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;
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 * );
/*****************************************************************************
*****************************************************************************/
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 */
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;
}
/*****************************************************************************
* 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 );
}
/*****************************************************************************
*****************************************************************************/
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
* 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;
+
}
/*****************************************************************************
* 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;
/* 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;
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 );
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 );
}