Commit 21e2557b authored by Denis Charmet's avatar Denis Charmet

Remove aout_Packet from directsound audio output

parent 8cbd52ac
...@@ -35,25 +35,10 @@ ...@@ -35,25 +35,10 @@
#include <vlc_plugin.h> #include <vlc_plugin.h>
#include <vlc_aout.h> #include <vlc_aout.h>
#include <vlc_charset.h> #include <vlc_charset.h>
#include <vlc_atomic.h>
#include "windows_audio_common.h" #include "windows_audio_common.h"
/***************************************************************************** #define DS_BUF_SIZE (1024*1024)
* notification_thread_t: DirectX event thread
*****************************************************************************/
typedef struct notification_thread_t
{
int i_frame_size; /* size in bytes of one frame */
int i_write_slot; /* current write position in our circular buffer */
mtime_t start_date;
HANDLE event;
vlc_thread_t thread;
vlc_atomic_t abort;
} notification_thread_t;
/***************************************************************************** /*****************************************************************************
* aout_sys_t: directx audio output method descriptor * aout_sys_t: directx audio output method descriptor
...@@ -63,23 +48,24 @@ typedef struct notification_thread_t ...@@ -63,23 +48,24 @@ typedef struct notification_thread_t
*****************************************************************************/ *****************************************************************************/
struct aout_sys_t struct aout_sys_t
{ {
aout_packet_t packet;
HINSTANCE hdsound_dll; /* handle of the opened dsound dll */ HINSTANCE hdsound_dll; /* handle of the opened dsound dll */
LPDIRECTSOUND p_dsobject; /* main Direct Sound object */ LPDIRECTSOUND p_dsobject; /* main Direct Sound object */
LPDIRECTSOUNDBUFFER p_dsbuffer; /* the sound buffer we use (direct sound LPDIRECTSOUNDBUFFER p_dsbuffer; /* the sound buffer we use (direct sound
* takes care of mixing all the * takes care of mixing all the
* secondary buffers into the primary) */ * secondary buffers into the primary) */
LPDIRECTSOUNDNOTIFY p_notify;
HANDLE hnotify_evt;
struct struct
{ {
LONG volume; float volume;
LONG mb; LONG mb;
bool mute; bool mute;
} volume; } volume;
notification_thread_t notif; /* DirectSoundThread id */ int i_bytes_per_sample; /* Size in bytes of one frame */
int i_rate; /* Sample rate */
int i_frame_size; /* Size in bytes of one frame */
int i_speaker_setup; /* Speaker setup override */ int i_speaker_setup; /* Speaker setup override */
...@@ -87,6 +73,8 @@ struct aout_sys_t ...@@ -87,6 +73,8 @@ struct aout_sys_t
uint8_t chan_table[AOUT_CHAN_MAX]; uint8_t chan_table[AOUT_CHAN_MAX];
uint32_t i_channel_mask; uint32_t i_channel_mask;
vlc_fourcc_t format; vlc_fourcc_t format;
size_t i_write;
}; };
/***************************************************************************** /*****************************************************************************
...@@ -95,18 +83,20 @@ struct aout_sys_t ...@@ -95,18 +83,20 @@ struct aout_sys_t
static int Open( vlc_object_t * ); static int Open( vlc_object_t * );
static void Close( vlc_object_t * ); static void Close( vlc_object_t * );
static void Stop( audio_output_t * ); static void Stop( audio_output_t * );
static void Play ( audio_output_t *, block_t * ); static void Play( audio_output_t *, block_t * );
static int VolumeSet ( audio_output_t *, float ); static int VolumeSet( audio_output_t *, float );
static int MuteSet ( audio_output_t *, bool ); static int MuteSet( audio_output_t *, bool );
static void Flush( audio_output_t *, bool );
static void Pause( audio_output_t *, bool, mtime_t );
static int TimeGet( audio_output_t *, mtime_t *);
/* local functions */ /* local functions */
static void Probe( audio_output_t *, const audio_sample_format_t * ); static void Probe( audio_output_t *, const audio_sample_format_t * );
static int InitDirectSound ( audio_output_t * ); static int InitDirectSound ( audio_output_t * );
static int CreateDSBuffer ( audio_output_t *, int, int, int, int, int, bool ); static int CreateDSBuffer ( audio_output_t *, int, int, int, int, bool );
static int CreateDSBufferPCM ( audio_output_t *, vlc_fourcc_t*, int, int, bool ); static int CreateDSBufferPCM ( audio_output_t *, vlc_fourcc_t*, int, int, bool );
static void DestroyDSBuffer ( audio_output_t * ); static void DestroyDSBuffer ( audio_output_t * );
static void* DirectSoundThread( void * ); static int FillBuffer ( audio_output_t *, block_t * );
static int FillBuffer ( audio_output_t *, int, block_t * );
static int ReloadDirectXDevices( vlc_object_t *, const char *, static int ReloadDirectXDevices( vlc_object_t *, const char *,
char ***, char *** ); char ***, char *** );
...@@ -145,7 +135,7 @@ vlc_module_begin () ...@@ -145,7 +135,7 @@ vlc_module_begin ()
add_string( "directx-audio-speaker", "Windows default", add_string( "directx-audio-speaker", "Windows default",
SPEAKER_TEXT, SPEAKER_LONGTEXT, true ) SPEAKER_TEXT, SPEAKER_LONGTEXT, true )
change_string_list( speaker_list, speaker_list ) change_string_list( speaker_list, speaker_list )
add_integer( "directx-volume", DSBVOLUME_MAX, add_float( "directx-volume", 1.0f,
VOLUME_TEXT, VOLUME_LONGTEXT, true ) VOLUME_TEXT, VOLUME_LONGTEXT, true )
change_integer_range( DSBVOLUME_MIN, DSBVOLUME_MAX ) change_integer_range( DSBVOLUME_MIN, DSBVOLUME_MAX )
...@@ -216,19 +206,15 @@ static int Start( audio_output_t *p_aout, audio_sample_format_t *restrict fmt ) ...@@ -216,19 +206,15 @@ static int Start( audio_output_t *p_aout, audio_sample_format_t *restrict fmt )
/* Calculate the frame size in bytes */ /* Calculate the frame size in bytes */
fmt->i_bytes_per_frame = AOUT_SPDIF_SIZE; fmt->i_bytes_per_frame = AOUT_SPDIF_SIZE;
fmt->i_frame_length = A52_FRAME_NB; fmt->i_frame_length = A52_FRAME_NB;
p_aout->sys->i_frame_size = fmt->i_bytes_per_frame;
if( CreateDSBuffer( p_aout, VLC_CODEC_SPDIFL, if( CreateDSBuffer( p_aout, VLC_CODEC_SPDIFL,
fmt->i_physical_channels, fmt->i_physical_channels,
aout_FormatNbChannels( fmt ), fmt->i_rate, aout_FormatNbChannels( fmt ), fmt->i_rate, false )
p_aout->sys->i_frame_size, false )
!= VLC_SUCCESS ) != VLC_SUCCESS )
{ {
msg_Err( p_aout, "cannot open directx audio device" ); msg_Err( p_aout, "cannot open directx audio device" );
goto error; goto error;
} }
aout_PacketInit( p_aout, &p_aout->sys->packet, A52_FRAME_NB, fmt );
} }
else else
{ {
...@@ -254,37 +240,19 @@ static int Start( audio_output_t *p_aout, audio_sample_format_t *restrict fmt ) ...@@ -254,37 +240,19 @@ static int Start( audio_output_t *p_aout, audio_sample_format_t *restrict fmt )
msg_Err( p_aout, "cannot open directx audio device" ); msg_Err( p_aout, "cannot open directx audio device" );
goto error; goto error;
} }
/* Calculate the frame size in bytes */
aout_PacketInit( p_aout, &p_aout->sys->packet, fmt->i_rate / 20, fmt );
} }
p_aout->sys->i_write = 0;
/* Force volume update in thread. TODO: use session volume on Vista+ */ /* Force volume update */
p_aout->sys->volume.volume = p_aout->sys->volume.mb; VolumeSet( p_aout, p_aout->sys->volume.volume );
MuteSet( p_aout, p_aout->sys->volume.mute );
/* Now we need to setup our DirectSound play notification structure */
vlc_atomic_set(&p_aout->sys->notif.abort, 0);
p_aout->sys->notif.event = CreateEvent( 0, FALSE, FALSE, 0 );
if( unlikely(p_aout->sys->notif.event == NULL) )
abort();
p_aout->sys->notif.i_frame_size = p_aout->sys->i_frame_size;
/* then launch the notification thread */ /* then launch the notification thread */
msg_Dbg( p_aout, "creating DirectSoundThread" ); p_aout->time_get = TimeGet;
if( vlc_clone( &p_aout->sys->notif.thread, DirectSoundThread, p_aout,
VLC_THREAD_PRIORITY_HIGHEST ) )
{
msg_Err( p_aout, "cannot create DirectSoundThread" );
CloseHandle( p_aout->sys->notif.event );
p_aout->sys->notif.event = NULL;
aout_PacketDestroy( p_aout );
goto error;
}
p_aout->time_get = aout_PacketTimeGet;
p_aout->play = Play; p_aout->play = Play;
p_aout->pause = NULL; p_aout->pause = Pause;
p_aout->flush = aout_PacketFlush; p_aout->flush = Flush;
return VLC_SUCCESS; return VLC_SUCCESS;
error: error:
...@@ -479,8 +447,7 @@ static void Probe( audio_output_t * p_aout, const audio_sample_format_t *fmt ) ...@@ -479,8 +447,7 @@ static void Probe( audio_output_t * p_aout, const audio_sample_format_t *fmt )
{ {
if( CreateDSBuffer( p_aout, VLC_CODEC_SPDIFL, if( CreateDSBuffer( p_aout, VLC_CODEC_SPDIFL,
fmt->i_physical_channels, fmt->i_physical_channels,
aout_FormatNbChannels( fmt ), fmt->i_rate, aout_FormatNbChannels( fmt ), fmt->i_rate, true )
AOUT_SPDIF_SIZE, true )
== VLC_SUCCESS ) == VLC_SUCCESS )
{ {
msg_Dbg( p_aout, "device supports A/52 over S/PDIF" ); msg_Dbg( p_aout, "device supports A/52 over S/PDIF" );
...@@ -511,26 +478,29 @@ static void Probe( audio_output_t * p_aout, const audio_sample_format_t *fmt ) ...@@ -511,26 +478,29 @@ static void Probe( audio_output_t * p_aout, const audio_sample_format_t *fmt )
*****************************************************************************/ *****************************************************************************/
static void Play( audio_output_t *p_aout, block_t *p_buffer ) static void Play( audio_output_t *p_aout, block_t *p_buffer )
{ {
/* get the playing date of the first aout buffer */ if( FillBuffer( p_aout, p_buffer ) == VLC_SUCCESS )
p_aout->sys->notif.start_date = p_buffer->i_pts; {
/* start playing the buffer */
/* fill in the first samples (zeroes) */ HRESULT dsresult = IDirectSoundBuffer_Play( p_aout->sys->p_dsbuffer,
FillBuffer( p_aout, 0, NULL ); 0, 0, DSBPLAY_LOOPING );
if( dsresult == DSERR_BUFFERLOST )
/* wake up the audio output thread */ {
SetEvent( p_aout->sys->notif.event ); IDirectSoundBuffer_Restore( p_aout->sys->p_dsbuffer );
dsresult = IDirectSoundBuffer_Play( p_aout->sys->p_dsbuffer,
aout_PacketPlay( p_aout, p_buffer ); 0, 0, DSBPLAY_LOOPING );
p_aout->play = aout_PacketPlay; }
if( dsresult != DS_OK )
msg_Err( p_aout, "cannot start playing buffer" );
}
} }
static int VolumeSet( audio_output_t *p_aout, float vol ) static int VolumeSet( audio_output_t *p_aout, float volume )
{ {
aout_sys_t *sys = p_aout->sys; aout_sys_t *sys = p_aout->sys;
int ret = 0; int ret = 0;
/* Convert UI volume to linear factor (cube) */ /* Convert UI volume to linear factor (cube) */
vol = vol * vol * vol; float vol = volume * volume * volume;
/* millibels from linear amplification */ /* millibels from linear amplification */
LONG mb = lroundf(2000.f * log10f(vol)); LONG mb = lroundf(2000.f * log10f(vol));
...@@ -546,28 +516,31 @@ static int VolumeSet( audio_output_t *p_aout, float vol ) ...@@ -546,28 +516,31 @@ static int VolumeSet( audio_output_t *p_aout, float vol )
mb = DSBVOLUME_MIN; mb = DSBVOLUME_MIN;
sys->volume.mb = mb; sys->volume.mb = mb;
if (!sys->volume.mute) sys->volume.volume = volume;
InterlockedExchange(&sys->volume.volume, mb); if( !sys->volume.mute && sys->p_dsbuffer &&
IDirectSoundBuffer_SetVolume( sys->p_dsbuffer, mb ) != DS_OK )
return -1;
/* Convert back to UI volume */ /* Convert back to UI volume */
vol = cbrtf(powf(10.f, ((float)mb) / 2000.f)); aout_VolumeReport( p_aout, volume );
aout_VolumeReport( p_aout, vol );
if( var_InheritBool( p_aout, "volume-save" ) ) if( var_InheritBool( p_aout, "volume-save" ) )
config_PutInt( p_aout, "directx-volume", mb ); config_PutFloat( p_aout, "directx-volume", volume );
return ret; return ret;
} }
static int MuteSet( audio_output_t *p_aout, bool mute ) static int MuteSet( audio_output_t *p_aout, bool mute )
{ {
HRESULT res = DS_OK;
aout_sys_t *sys = p_aout->sys; aout_sys_t *sys = p_aout->sys;
sys->volume.mute = mute; sys->volume.mute = mute;
InterlockedExchange(&sys->volume.volume,
mute ? DSBVOLUME_MIN : sys->volume.mb); if( sys->p_dsbuffer )
res = IDirectSoundBuffer_SetVolume( sys->p_dsbuffer,
mute? DSBVOLUME_MIN : sys->volume.mb );
aout_MuteReport( p_aout, mute ); aout_MuteReport( p_aout, mute );
return 0; return (res != DS_OK);
} }
/***************************************************************************** /*****************************************************************************
...@@ -576,27 +549,19 @@ static int MuteSet( audio_output_t *p_aout, bool mute ) ...@@ -576,27 +549,19 @@ static int MuteSet( audio_output_t *p_aout, bool mute )
static void Stop( audio_output_t *p_aout ) static void Stop( audio_output_t *p_aout )
{ {
aout_sys_t *p_sys = p_aout->sys; aout_sys_t *p_sys = p_aout->sys;
msg_Dbg( p_aout, "closing audio device" ); msg_Dbg( p_aout, "closing audio device" );
/* kill the position notification thread, if any */ if( p_sys->p_notify )
if( p_sys->notif.event != NULL ) IDirectSoundNotify_Release(p_sys->p_notify );
{ p_sys->p_notify = NULL;
vlc_atomic_set(&p_aout->sys->notif.abort, 1);
/* wake up the audio thread if needed */
if( p_aout->play == Play )
SetEvent( p_sys->notif.event );
vlc_join( p_sys->notif.thread, NULL );
CloseHandle( p_sys->notif.event );
aout_PacketDestroy( p_aout );
}
IDirectSoundBuffer_Stop( p_sys->p_dsbuffer );
/* release the secondary buffer */ /* release the secondary buffer */
DestroyDSBuffer( p_aout ); DestroyDSBuffer( p_aout );
/* finally release the DirectSound object */ /* finally release the DirectSound object */
if( p_sys->p_dsobject ) IDirectSound_Release( p_sys->p_dsobject ); if( p_sys->p_dsobject )
IDirectSound_Release( p_sys->p_dsobject );
} }
/***************************************************************************** /*****************************************************************************
...@@ -675,7 +640,7 @@ static int InitDirectSound( audio_output_t *p_aout ) ...@@ -675,7 +640,7 @@ static int InitDirectSound( audio_output_t *p_aout )
*****************************************************************************/ *****************************************************************************/
static int CreateDSBuffer( audio_output_t *p_aout, int i_format, static int CreateDSBuffer( audio_output_t *p_aout, int i_format,
int i_channels, int i_nb_channels, int i_rate, int i_channels, int i_nb_channels, int i_rate,
int i_bytes_per_frame, bool b_probe ) bool b_probe )
{ {
WAVEFORMATEXTENSIBLE waveformat; WAVEFORMATEXTENSIBLE waveformat;
DSBUFFERDESC dsbdesc; DSBUFFERDESC dsbdesc;
...@@ -723,14 +688,16 @@ static int CreateDSBuffer( audio_output_t *p_aout, int i_format, ...@@ -723,14 +688,16 @@ static int CreateDSBuffer( audio_output_t *p_aout, int i_format,
waveformat.Format.nAvgBytesPerSec = waveformat.Format.nAvgBytesPerSec =
waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign; waveformat.Format.nSamplesPerSec * waveformat.Format.nBlockAlign;
p_aout->sys->i_bytes_per_sample = waveformat.Format.nBlockAlign;
p_aout->sys->format = i_format; p_aout->sys->format = i_format;
/* Then fill in the direct sound descriptor */ /* Then fill in the direct sound descriptor */
memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); memset(&dsbdesc, 0, sizeof(DSBUFFERDESC));
dsbdesc.dwSize = sizeof(DSBUFFERDESC); dsbdesc.dwSize = sizeof(DSBUFFERDESC);
dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2/* Better position accuracy */ dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 /* Better position accuracy */
| DSBCAPS_GLOBALFOCUS /* Allows background playing */ | DSBCAPS_GLOBALFOCUS /* Allows background playing */
| DSBCAPS_CTRLVOLUME; /* Allows volume control */ | DSBCAPS_CTRLVOLUME /* Allows volume control */
| DSBCAPS_CTRLPOSITIONNOTIFY; /* Allow position notifications */
/* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */ /* Only use the new WAVE_FORMAT_EXTENSIBLE format for multichannel audio */
if( i_nb_channels <= 2 ) if( i_nb_channels <= 2 )
...@@ -747,7 +714,7 @@ static int CreateDSBuffer( audio_output_t *p_aout, int i_format, ...@@ -747,7 +714,7 @@ static int CreateDSBuffer( audio_output_t *p_aout, int i_format,
dsbdesc.dwFlags |= DSBCAPS_LOCHARDWARE; dsbdesc.dwFlags |= DSBCAPS_LOCHARDWARE;
} }
dsbdesc.dwBufferBytes = FRAMES_NUM * i_bytes_per_frame; /* buffer size */ dsbdesc.dwBufferBytes = DS_BUF_SIZE; /* buffer size */
dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&waveformat; dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&waveformat;
if FAILED( IDirectSound_CreateSoundBuffer( if FAILED( IDirectSound_CreateSoundBuffer(
...@@ -781,7 +748,7 @@ static int CreateDSBuffer( audio_output_t *p_aout, int i_format, ...@@ -781,7 +748,7 @@ static int CreateDSBuffer( audio_output_t *p_aout, int i_format,
return VLC_SUCCESS; return VLC_SUCCESS;
} }
p_aout->sys->i_frame_size = i_bytes_per_frame; p_aout->sys->i_rate = i_rate;
p_aout->sys->i_channel_mask = waveformat.dwChannelMask; p_aout->sys->i_channel_mask = waveformat.dwChannelMask;
p_aout->sys->chans_to_reorder = p_aout->sys->chans_to_reorder =
aout_CheckChannelReorder( pi_channels_in, pi_channels_out, aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
...@@ -792,6 +759,18 @@ static int CreateDSBuffer( audio_output_t *p_aout, int i_format, ...@@ -792,6 +759,18 @@ static int CreateDSBuffer( audio_output_t *p_aout, int i_format,
msg_Dbg( p_aout, "channel reordering needed" ); msg_Dbg( p_aout, "channel reordering needed" );
} }
if( IDirectSoundBuffer_QueryInterface( p_aout->sys->p_dsbuffer,
&IID_IDirectSoundNotify,
(void **) &p_aout->sys->p_notify )
!= DS_OK )
{
msg_Err(p_aout, "Couldn't query IDirectSoundNotify");
p_aout->sys->p_notify = NULL;
}
FillBuffer(p_aout,NULL);
return VLC_SUCCESS; return VLC_SUCCESS;
} }
...@@ -810,13 +789,11 @@ static int CreateDSBufferPCM( audio_output_t *p_aout, vlc_fourcc_t *i_format, ...@@ -810,13 +789,11 @@ static int CreateDSBufferPCM( audio_output_t *p_aout, vlc_fourcc_t *i_format,
if( !var_GetBool( p_aout, "directx-audio-float32" ) || if( !var_GetBool( p_aout, "directx-audio-float32" ) ||
i_nb_channels > 2 || i_nb_channels > 2 ||
CreateDSBuffer( p_aout, VLC_CODEC_FL32, CreateDSBuffer( p_aout, VLC_CODEC_FL32,
i_channels, i_nb_channels, i_rate, i_channels, i_nb_channels, i_rate, b_probe )
(i_rate / 20) * 4 * i_nb_channels, b_probe )
!= VLC_SUCCESS ) != VLC_SUCCESS )
{ {
if ( CreateDSBuffer( p_aout, VLC_CODEC_S16N, if ( CreateDSBuffer( p_aout, VLC_CODEC_S16N,
i_channels, i_nb_channels, i_rate, i_channels, i_nb_channels, i_rate, b_probe )
(i_rate / 20) * 2 * i_nb_channels, b_probe )
!= VLC_SUCCESS ) != VLC_SUCCESS )
{ {
return VLC_EGENERIC; return VLC_EGENERIC;
...@@ -853,10 +830,11 @@ static void DestroyDSBuffer( audio_output_t *p_aout ) ...@@ -853,10 +830,11 @@ static void DestroyDSBuffer( audio_output_t *p_aout )
***************************************************************************** *****************************************************************************
* Returns VLC_SUCCESS on success. * Returns VLC_SUCCESS on success.
*****************************************************************************/ *****************************************************************************/
static int FillBuffer( audio_output_t *p_aout, int i_frame, block_t *p_buffer ) static int FillBuffer( audio_output_t *p_aout, block_t *p_buffer )
{ {
aout_sys_t *p_sys = p_aout->sys; aout_sys_t *p_sys = p_aout->sys;
notification_thread_t *p_notif = &p_sys->notif;
size_t towrite = (p_buffer)?p_buffer->i_buffer:DS_BUF_SIZE;
void *p_write_position, *p_wrap_around; void *p_write_position, *p_wrap_around;
unsigned long l_bytes1, l_bytes2; unsigned long l_bytes1, l_bytes2;
HRESULT dsresult; HRESULT dsresult;
...@@ -864,20 +842,20 @@ static int FillBuffer( audio_output_t *p_aout, int i_frame, block_t *p_buffer ) ...@@ -864,20 +842,20 @@ static int FillBuffer( audio_output_t *p_aout, int i_frame, block_t *p_buffer )
/* Before copying anything, we have to lock the buffer */ /* Before copying anything, we have to lock the buffer */
dsresult = IDirectSoundBuffer_Lock( dsresult = IDirectSoundBuffer_Lock(
p_sys->p_dsbuffer, /* DS buffer */ p_sys->p_dsbuffer, /* DS buffer */
i_frame * p_notif->i_frame_size, /* Start offset */ p_aout->sys->i_write, /* Start offset */
p_notif->i_frame_size, /* Number of bytes */ towrite, /* Number of bytes */
&p_write_position, /* Address of lock start */ &p_write_position, /* Address of lock start */
&l_bytes1, /* Count of bytes locked before wrap around */ &l_bytes1, /* Count of bytes locked before wrap around */
&p_wrap_around, /* Buffer address (if wrap around) */ &p_wrap_around, /* Buffer address (if wrap around) */
&l_bytes2, /* Count of bytes after wrap around */ &l_bytes2, /* Count of bytes after wrap around */
0 ); /* Flags */ 0 ); /* Flags: DSBLOCK_FROMWRITECURSOR is buggy */
if( dsresult == DSERR_BUFFERLOST ) if( dsresult == DSERR_BUFFERLOST )
{ {
IDirectSoundBuffer_Restore( p_sys->p_dsbuffer ); IDirectSoundBuffer_Restore( p_sys->p_dsbuffer );
dsresult = IDirectSoundBuffer_Lock( dsresult = IDirectSoundBuffer_Lock(
p_sys->p_dsbuffer, p_sys->p_dsbuffer,
i_frame * p_notif->i_frame_size, p_aout->sys->i_write,
p_notif->i_frame_size, towrite,
&p_write_position, &p_write_position,
&l_bytes1, &l_bytes1,
&p_wrap_around, &p_wrap_around,
...@@ -904,6 +882,8 @@ static int FillBuffer( audio_output_t *p_aout, int i_frame, block_t *p_buffer ) ...@@ -904,6 +882,8 @@ static int FillBuffer( audio_output_t *p_aout, int i_frame, block_t *p_buffer )
p_sys->format ); p_sys->format );
memcpy( p_write_position, p_buffer->p_buffer, l_bytes1 ); memcpy( p_write_position, p_buffer->p_buffer, l_bytes1 );
if( l_bytes1 < p_buffer->i_buffer)
memcpy(p_wrap_around, p_buffer->p_buffer + l_bytes1, l_bytes2);
block_Release( p_buffer ); block_Release( p_buffer );
} }
...@@ -911,117 +891,10 @@ static int FillBuffer( audio_output_t *p_aout, int i_frame, block_t *p_buffer ) ...@@ -911,117 +891,10 @@ static int FillBuffer( audio_output_t *p_aout, int i_frame, block_t *p_buffer )
IDirectSoundBuffer_Unlock( p_sys->p_dsbuffer, p_write_position, l_bytes1, IDirectSoundBuffer_Unlock( p_sys->p_dsbuffer, p_write_position, l_bytes1,
p_wrap_around, l_bytes2 ); p_wrap_around, l_bytes2 );
p_notif->i_write_slot = (i_frame + 1) % FRAMES_NUM; p_sys->i_write += towrite;
return VLC_SUCCESS; p_sys->i_write %= DS_BUF_SIZE;
}
/*****************************************************************************
* DirectSoundThread: this thread will capture play notification events.
*****************************************************************************
* 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( void *data )
{
audio_output_t *p_aout = (audio_output_t *)data;
notification_thread_t *p_notif = &p_aout->sys->notif;
mtime_t last_time;
msg_Dbg( p_aout, "DirectSoundThread ready" );
/* Wait here until Play() is called */
WaitForSingleObject( p_notif->event, INFINITE );
if( !vlc_atomic_get( &p_notif->abort) )
{
HRESULT dsresult;
mwait( p_notif->start_date - AOUT_MAX_PTS_ADVANCE / 2 );
/* start playing the buffer */
dsresult = IDirectSoundBuffer_Play( p_aout->sys->p_dsbuffer,
0, /* Unused */
0, /* Unused */
DSBPLAY_LOOPING ); /* Flags */
if( dsresult == DSERR_BUFFERLOST )
{
IDirectSoundBuffer_Restore( p_aout->sys->p_dsbuffer );
dsresult = IDirectSoundBuffer_Play(
p_aout->sys->p_dsbuffer,
0, /* Unused */
0, /* Unused */
DSBPLAY_LOOPING ); /* Flags */
}
if( dsresult != DS_OK )
{
msg_Err( p_aout, "cannot start playing buffer" );
}
}
last_time = mdate();
while( !vlc_atomic_get( &p_notif->abort ) )
{
DWORD l_read;
int l_queued = 0, l_free_slots;
unsigned i_frame_siz = p_aout->sys->packet.samples;
mtime_t mtime = mdate();
int i;
/* Update volume if required */
LONG volume = InterlockedExchange( &p_aout->sys->volume.volume, -1 );
if( unlikely(volume != -1) )
IDirectSoundBuffer_SetVolume( p_aout->sys->p_dsbuffer, volume );
/*
* Fill in as much audio data as we can in our circular buffer
*/
/* Find out current play position */
if FAILED( IDirectSoundBuffer_GetCurrentPosition(
p_aout->sys->p_dsbuffer, &l_read, NULL ) )
{
msg_Err( p_aout, "GetCurrentPosition() failed!" );
l_read = 0;
}
/* Detect underruns */
if( l_queued && mtime - last_time >
INT64_C(1000000) * l_queued / p_aout->sys->packet.format.i_rate )
{
msg_Dbg( p_aout, "detected underrun!" );
}
last_time = mtime;
/* Try to fill in as many frame buffers as possible */ return VLC_SUCCESS;
l_read /= (p_aout->sys->packet.format.i_bytes_per_frame /
p_aout->sys->packet.format.i_frame_length);
l_queued = p_notif->i_write_slot * i_frame_siz - l_read;
if( l_queued < 0 ) l_queued += (i_frame_siz * FRAMES_NUM);
l_free_slots = (FRAMES_NUM * i_frame_siz - l_queued) / i_frame_siz;
for( i = 0; i < l_free_slots; i++ )
{
block_t *p_buffer = aout_PacketNext( p_aout,
mtime + INT64_C(1000000) * (i * i_frame_siz + l_queued) /
p_aout->sys->packet.format.i_rate );
/* If there is no audio data available and we have some buffered
* already, then just wait for the next time */
if( !p_buffer && (i || l_queued / i_frame_siz) ) break;
if( FillBuffer( p_aout, p_notif->i_write_slot % FRAMES_NUM,
p_buffer ) != VLC_SUCCESS ) break;
}
/* Sleep a reasonable amount of time */
l_queued += (i * i_frame_siz);
msleep( INT64_C(1000000) * l_queued / p_aout->sys->packet.format.i_rate / 2 );
}
/* make sure the buffer isn't playing */
IDirectSoundBuffer_Stop( p_aout->sys->p_dsbuffer );
msg_Dbg( p_aout, "DirectSoundThread exiting" );
return NULL;
} }
typedef struct typedef struct
...@@ -1106,11 +979,19 @@ static int Open(vlc_object_t *obj) ...@@ -1106,11 +979,19 @@ static int Open(vlc_object_t *obj)
aout->mute_set = MuteSet; aout->mute_set = MuteSet;
/* Volume */ /* Volume */
LONG mb = var_InheritInteger(aout, "directx-volume"); sys->volume.volume = var_InheritFloat(aout, "directx-volume");
sys->volume.mb = mb; aout_VolumeReport(aout, sys->volume.volume );
aout_VolumeReport(aout, cbrtf(powf(10.f, ((float)mb) / 2000.f)));
MuteSet(aout, var_InheritBool(aout, "mute")); MuteSet(aout, var_InheritBool(aout, "mute"));
sys->hnotify_evt = CreateEvent(NULL, FALSE, TRUE, NULL);
if( !sys->hnotify_evt )
{
msg_Err(aout, "cannot create Event");
FreeLibrary(sys->hdsound_dll);
free(sys);
return VLC_EGENERIC;
}
return VLC_SUCCESS; return VLC_SUCCESS;
} }
...@@ -1119,6 +1000,67 @@ static void Close(vlc_object_t *obj) ...@@ -1119,6 +1000,67 @@ static void Close(vlc_object_t *obj)
audio_output_t *aout = (audio_output_t *)obj; audio_output_t *aout = (audio_output_t *)obj;
aout_sys_t *sys = aout->sys; aout_sys_t *sys = aout->sys;
CloseHandle(sys->hnotify_evt);
FreeLibrary(sys->hdsound_dll); /* free DSOUND.DLL */ FreeLibrary(sys->hdsound_dll); /* free DSOUND.DLL */
free(sys); free(sys);
} }
static void Flush ( audio_output_t * aout, bool drain )
{
aout_sys_t *sys = aout->sys;
size_t read;
if( drain )
{
if( sys->p_notify )
{
DSBPOSITIONNOTIFY notif = {.dwOffset = aout->sys->i_write, .hEventNotify = sys->hnotify_evt } ;
if( IDirectSoundNotify_SetNotificationPositions( sys->p_notify, 1, &notif ) == DS_OK )
{
WaitForSingleObject( sys->hnotify_evt, INFINITE );
IDirectSoundBuffer_Stop( aout->sys->p_dsbuffer );
}
}
else
while( IDirectSoundBuffer_GetCurrentPosition( aout->sys->p_dsbuffer,(LPDWORD) &read, NULL) == DS_OK )
{
read %= DS_BUF_SIZE;
if( read == aout->sys->i_write )
break;
msleep(10000);
}
}
else
{
IDirectSoundBuffer_Stop( aout->sys->p_dsbuffer );
IDirectSoundBuffer_SetCurrentPosition( aout->sys->p_dsbuffer,
aout->sys->i_write );
}
}
static void Pause( audio_output_t * aout, bool pause, mtime_t date )
{
(void) date;
if( pause )
IDirectSoundBuffer_Stop( aout->sys->p_dsbuffer );
else
IDirectSoundBuffer_Play( aout->sys->p_dsbuffer, 0, 0, DSBPLAY_LOOPING );
}
static int TimeGet( audio_output_t * aout, mtime_t * delay )
{
uint32_t read;
mtime_t size;
if( IDirectSoundBuffer_GetCurrentPosition( aout->sys->p_dsbuffer, (LPDWORD) &read, NULL) != DS_OK )
return 1;
read %= DS_BUF_SIZE;
size = (mtime_t)aout->sys->i_write - (mtime_t) read;
if( size < 0 )
size += DS_BUF_SIZE;
*delay = ( size / aout->sys->i_bytes_per_sample ) * CLOCK_FREQ / aout->sys->i_rate;
return 0;
}
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