Commit 5bbe0409 authored by Gildas Bazin's avatar Gildas Bazin

* modules/video_output/directx/aout.c: adapted the directx audio plugin to aout3.
* 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 :)
parent f8ec3801
......@@ -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
......
......@@ -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>
*
......@@ -32,28 +32,36 @@
#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,169 +129,189 @@ 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 );
/* calculate the frame size in bytes */
p_aout->output.p_sys->i_buffer_size = FRAME_SIZE * sizeof(s16)
* p_aout->output.output.i_channels;
/* 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;
}
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 );
return 0;
}
/*****************************************************************************
* GetBufInfo: buffer status query
* Play: play a sound buffer
*****************************************************************************
* returns the number of bytes in the audio buffer that have not yet been
* sent to the sound device.
* This doesn't actually play the buffer. This just stores the buffer so it
* can be played by the callback thread.
*****************************************************************************/
static int GetBufInfo( aout_thread_t *p_aout, int i_buffer_limit )
static void Play( aout_instance_t *p_aout, aout_buffer_t *p_buffer )
{
MMTIME mmtime;
aout_FifoPush( p_aout, &p_aout->output.fifo, p_buffer );
}
/*****************************************************************************
* Close: close the audio device
*****************************************************************************/
static void Close( vlc_object_t *p_this )
{
aout_instance_t *p_aout = (aout_instance_t *)p_this;
mmtime.wType = TIME_BYTES;
if( (waveOutGetPosition(p_aout->p_sys->h_waveout, &mmtime, sizeof(MMTIME)))
!= MMSYSERR_NOERROR || (mmtime.wType != TIME_BYTES) )
/* Before calling waveOutClose we must reset the device */
waveOutReset( p_aout->output.p_sys->h_waveout );
/* Close the device */
if( waveOutClose( p_aout->output.p_sys->h_waveout ) != MMSYSERR_NOERROR )
{
msg_Warn( p_aout, "waveOutGetPosition failed" );
return i_buffer_limit;
msg_Err( p_aout, "waveOutClose failed" );
}
/* Free silence buffer */
free( p_aout->output.p_sys->p_silence_buffer );
#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);
if( p_aout->output.p_sys != NULL )
{
free( p_aout->output.p_sys );
p_aout->output.p_sys = NULL;
}
}
/*****************************************************************************
* Play: play a sound buffer
*****************************************************************************
* This function writes a buffer of i_length bytes
*****************************************************************************/
static void Play( aout_thread_t *p_aout, byte_t *p_buffer, int i_size )
* OpenWaveOut: open the waveout sound device
****************************************************************************/
static int OpenWaveOut( aout_instance_t *p_aout, int i_format,
int i_channels, int i_rate )
{
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;
/* Set sound format */
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;
result = waveOutPrepareHeader( p_aout->p_sys->h_waveout,
&p_aout->p_sys->waveheader[current_buffer],
sizeof(WAVEHDR) );
if( result != MMSYSERR_NOERROR )
/* Open the device */
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, "waveOutPrepareHeader failed" );
return;
msg_Err( p_aout, "waveOutOpen failed WAVERR_BADFORMAT" );
return( 1 );
}
/* 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;
msg_Err( p_aout, "waveOutOpen failed" );
return 1;
}
/* keep track of number of bytes played */
p_aout->p_sys->dw_counter += i_size;
return 0;
}
/*****************************************************************************
* Close: close the audio device
* PlayWaveOut: play a buffer through the WaveOut device
*****************************************************************************/
static void Close( vlc_object_t *p_this )
static int PlayWaveOut( aout_instance_t *p_aout, HWAVEOUT h_waveout,
WAVEHDR *p_waveheader, aout_buffer_t *p_buffer )
{
aout_thread_t *p_aout = (aout_thread_t *)p_this;
int i;
MMRESULT result;
/* Before calling waveOutClose we must reset the device */
waveOutReset( p_aout->p_sys->h_waveout );
/* 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;
/* Close the device */
if( waveOutClose( p_aout->p_sys->h_waveout ) != MMSYSERR_NOERROR )
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, "waveOutClose failed" );
msg_Err( p_aout, "waveOutPrepareHeader failed" );
return 1;
}
/* Deallocate memory */
for( i=0; i<NUMBUF; i++ )
free( p_aout->p_sys->waveheader[i].lpData );
if( p_aout->p_sys != NULL )
/* Send the buffer to the waveOut queue */
result = waveOutWrite( h_waveout, p_waveheader, sizeof(WAVEHDR) );
if( result != MMSYSERR_NOERROR )
{
free( p_aout->p_sys );
p_aout->p_sys = NULL;
msg_Err( p_aout, "waveOutWrite failed" );
return 1;
}
return 0;
}
/*****************************************************************************
* OpenWaveOutDevice: open the sound device
****************************************************************************/
static int OpenWaveOutDevice( aout_thread_t *p_aout )
* 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 )
{
MMRESULT result;
/* initialize played bytes counter */
p_aout->p_sys->dw_counter = 0;
aout_instance_t * p_aout = (aout_instance_t *)_p_aout;
WAVEHDR *p_waveheader = (WAVEHDR *)dwParam1;
aout_buffer_t * p_buffer;
/* 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;
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 );
/* 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 );
if( result != MMSYSERR_NOERROR )
{
msg_Err( p_aout, "waveOutOpen failed" );
return( 1 );
}
/* FIXME : take into account WaveOut latency instead of mdate() */
p_buffer = aout_OutputNextBuffer( p_aout, mdate() );
return( 0 );
PlayWaveOut( p_aout, h_waveout, p_waveheader, p_buffer );
}
......@@ -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>
*
......@@ -32,10 +32,13 @@
#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,
dsresult = IDirectSound_CreateSoundBuffer(p_aout->output.p_sys->p_dsobject,
&dsbuffer_desc,
&p_aout->p_sys->p_dsbuffer_primary,
&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;
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 );
}
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 );
}
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);
msg_Err( p_aout, "cannot create buffer" );
vlc_mutex_unlock( &p_aout->output.p_sys->buffer_lock );
return 1;
}
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->output.p_sys->buffer_lock );
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 )
{
vlc_object_detach_all( p_aout->output.p_sys->p_notif );
if( p_aout->output.p_sys->p_notif->b_thread )
{
p_aout->p_sys->p_notif->b_die = 1;
vlc_thread_join( p_aout->p_sys->p_notif );
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 );
goto error;
}
OurDirectSoundCreate = (void *)GetProcAddress( p_aout->p_sys->hdsound_dll,
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 );
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,
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,
if FAILED( IDirectSoundBuffer_QueryInterface(
p_aout->output.p_sys->p_dsbuffer,
&IID_IDirectSoundNotify,
(LPVOID *)&p_aout->p_sys->p_dsnotify ) )
(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_thread_t *p_aout = p_notif->p_aout;
aout_instance_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) )
{
msg_Dbg( p_notif, "DirectSoundThread wrap around: %li",
l_data_in_buffer );
l_data_in_buffer += l_buffer_size;
}
/* detect underflow */
if( l_data_in_buffer <= 0 )
{
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);
}
/* Clear the data which has already been played */
/* 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 */
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_start_buffer, /* Buffer adress (if wrap around) */
&p_wrap_around, /* Buffer adress (if wrap around) */
&l_bytes2, /* Count of bytes after wrap around */
0); /* Flags */
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,
l_buffer_size - l_data_in_buffer,
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_start_buffer,
&p_wrap_around,
&l_bytes2,
0);
0 );
}
if( dsresult != DS_OK )
{
msg_Warn( p_notif, "Play cannot lock buffer" );
vlc_mutex_unlock( &p_aout->p_sys->buffer_lock );
return;
msg_Warn( p_notif, "cannot lock buffer" );
vlc_mutex_unlock( &p_aout->output.p_sys->buffer_lock );
continue;
}
/* Now do the actual memcpy (two because the buffer is circular) */
memset( p_write_position, 0, l_bytes1 );
if( p_start_buffer != NULL )
/* FIXME : take into account DirectSound latency instead of mdate() */
p_buffer = aout_OutputNextBuffer( p_aout, mdate() );
/* 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 );
if ( p_buffer != NULL )
{
p_aout->p_vlc->pf_memcpy( p_write_position, p_buffer->p_buffer,
l_bytes1 );
aout_BufferFree( p_buffer );
}
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 );
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment