Commit db527697 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

DirectSound: reorder to reduce forward declarations

parent 43291e2e
......@@ -40,61 +40,8 @@
#define DS_BUF_SIZE (6*1024*1024)
/*****************************************************************************
* aout_sys_t: directx audio output method descriptor
*****************************************************************************
* This structure is part of the audio output thread descriptor.
* It describes the direct sound specific properties of an audio device.
*****************************************************************************/
struct aout_sys_t
{
HINSTANCE hdsound_dll; /* handle of the opened dsound dll */
LPDIRECTSOUND p_dsobject; /* main Direct Sound object */
LPDIRECTSOUNDBUFFER p_dsbuffer; /* the sound buffer we use (direct sound
* takes care of mixing all the
* secondary buffers into the primary) */
LPDIRECTSOUNDNOTIFY p_notify;
HANDLE hnotify_evt;
struct
{
float volume;
LONG mb;
bool mute;
} volume;
int i_bytes_per_sample; /* Size in bytes of one frame */
int i_rate; /* Sample rate */
uint8_t chans_to_reorder; /* do we need channel reordering */
uint8_t chan_table[AOUT_CHAN_MAX];
uint32_t i_channel_mask;
vlc_fourcc_t format;
size_t i_write;
};
/*****************************************************************************
* Local prototypes.
*****************************************************************************/
static int Open( vlc_object_t * );
static void Close( vlc_object_t * );
static void Stop( audio_output_t * );
static void Play( audio_output_t *, block_t * );
static int VolumeSet( audio_output_t *, float );
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 */
static int InitDirectSound ( audio_output_t * );
static int CreateDSBuffer ( audio_output_t *, int, int, int, int, bool );
static int CreateDSBufferPCM ( audio_output_t *, vlc_fourcc_t*, int, int, bool );
static void DestroyDSBuffer ( audio_output_t * );
static int FillBuffer ( audio_output_t *, block_t * );
static int ReloadDirectXDevices( vlc_object_t *, const char *,
char ***, char *** );
......@@ -139,359 +86,200 @@ vlc_module_begin ()
set_callbacks( Open, Close )
vlc_module_end ()
/*****************************************************************************
* OpenAudio: open the audio device
*****************************************************************************
* This function opens and setups Direct Sound.
*****************************************************************************/
static int Start( audio_output_t *p_aout, audio_sample_format_t *restrict fmt )
/**
* DirectSound audio output method descriptor
*
* This structure is part of the audio output thread descriptor.
* It describes the direct sound specific properties of an audio device.
*/
struct aout_sys_t
{
char * psz_speaker;
int i = 0;
const char * const * ppsz_compare = speaker_list;
msg_Dbg( p_aout, "Opening DirectSound Audio Output" );
HINSTANCE hdsound_dll; /* handle of the opened dsound dll */
/* Retrieve config values */
var_Create( p_aout, "directx-audio-float32",
VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
psz_speaker = var_CreateGetString( p_aout, "directx-audio-speaker" );
LPDIRECTSOUND p_dsobject; /* main Direct Sound object */
LPDIRECTSOUNDBUFFER p_dsbuffer; /* the sound buffer we use (direct sound
* takes care of mixing all the
* secondary buffers into the primary) */
while ( *ppsz_compare != NULL )
{
if ( !strncmp( *ppsz_compare, psz_speaker, strlen(*ppsz_compare) ) )
LPDIRECTSOUNDNOTIFY p_notify;
HANDLE hnotify_evt;
struct
{
break;
}
ppsz_compare++; i++;
}
float volume;
LONG mb;
bool mute;
} volume;
if ( *ppsz_compare == NULL )
{
msg_Err( p_aout, "(%s) isn't valid speaker setup option", psz_speaker );
msg_Err( p_aout, "Defaulting to Windows default speaker config");
i = 0;
}
free( psz_speaker );
int i_bytes_per_sample; /* Size in bytes of one frame */
int i_rate; /* Sample rate */
/* Initialise DirectSound */
if( InitDirectSound( p_aout ) )
{
msg_Err( p_aout, "cannot initialize DirectSound" );
goto error;
}
uint8_t chans_to_reorder; /* do we need channel reordering */
uint8_t chan_table[AOUT_CHAN_MAX];
uint32_t i_channel_mask;
vlc_fourcc_t format;
if ( AOUT_FMT_SPDIF( fmt ) && var_InheritBool( p_aout, "spdif" )
&& CreateDSBuffer( p_aout, VLC_CODEC_SPDIFL, fmt->i_physical_channels,
aout_FormatNbChannels( fmt ), fmt->i_rate, false )
== VLC_SUCCESS )
{
msg_Dbg( p_aout, "using A/52 pass-through over S/PDIF" );
fmt->i_format = VLC_CODEC_SPDIFL;
size_t i_write;
};
/* Calculate the frame size in bytes */
fmt->i_bytes_per_frame = AOUT_SPDIF_SIZE;
fmt->i_frame_length = A52_FRAME_NB;
}
else
{
if( i == 0 )
{
DWORD ui_speaker_config;
int i_channels = 2; /* Default to stereo */
int i_orig_channels = aout_FormatNbChannels( fmt );
static int TimeGet( audio_output_t * aout, mtime_t * delay )
{
DWORD read;
mtime_t size;
/* Check the speaker configuration to determine which channel
* config should be the default */
if( FAILED( IDirectSound_GetSpeakerConfig( p_aout->sys->p_dsobject,
&ui_speaker_config ) ) )
{
ui_speaker_config = DSSPEAKER_STEREO;
msg_Dbg( p_aout, "GetSpeakerConfig failed" );
}
if( IDirectSoundBuffer_GetCurrentPosition( aout->sys->p_dsbuffer, &read,
NULL) != DS_OK )
return -1;
const char *name = "Unknown";
switch( DSSPEAKER_CONFIG(ui_speaker_config) )
{
case DSSPEAKER_7POINT1:
case DSSPEAKER_7POINT1_SURROUND:
name = "7.1";
i_channels = 8;
break;
case DSSPEAKER_5POINT1:
case DSSPEAKER_5POINT1_SURROUND:
name = "5.1";
i_channels = 6;
break;
case DSSPEAKER_QUAD:
name = "Quad";
i_channels = 4;
break;
#if 0 /* Lots of people just get their settings wrong and complain that
* this is a problem with VLC so just don't ever set mono by default. */
case DSSPEAKER_MONO:
name = "Mono";
i_channels = 1;
break;
#endif
case DSSPEAKER_SURROUND:
name = "Surround";
i_channels = 4;
break;
case DSSPEAKER_STEREO:
name = "Stereo";
i_channels = 2;
break;
}
read %= DS_BUF_SIZE;
if( i_channels >= i_orig_channels )
i_channels = i_orig_channels;
size = (mtime_t)aout->sys->i_write - (mtime_t) read;
if( size < 0 )
size += DS_BUF_SIZE;
msg_Dbg( p_aout, "%s speaker config: %s and stream has "
"%d channels, using %d channels", "Windows", name,
i_orig_channels, i_channels );
*delay = ( size / aout->sys->i_bytes_per_sample ) * CLOCK_FREQ
/ aout->sys->i_rate;
return 0;
}
switch( i_channels )
{
case 8:
fmt->i_physical_channels = AOUT_CHANS_7_1;
break;
case 7:
case 6:
fmt->i_physical_channels = AOUT_CHANS_5_1;
break;
case 5:
case 4:
fmt->i_physical_channels = AOUT_CHANS_4_0;
break;
default:
fmt->i_physical_channels = AOUT_CHANS_2_0;
break;
}
}
else
{ /* Overriden speaker configuration */
const char *name = "Non-existant";
switch( i )
{
case 1: /* Mono */
name = "Mono";
fmt->i_physical_channels = AOUT_CHAN_CENTER;
break;
case 2: /* Stereo */
name = "Stereo";
fmt->i_physical_channels = AOUT_CHANS_2_0;
break;
case 3: /* Quad */
name = "Quad";
fmt->i_physical_channels = AOUT_CHANS_4_0;
break;
case 4: /* 5.1 */
name = "5.1";
fmt->i_physical_channels = AOUT_CHANS_5_1;
break;
case 5: /* 7.1 */
name = "7.1";
fmt->i_physical_channels = AOUT_CHANS_7_1;
break;
}
msg_Dbg( p_aout, "%s speaker config: %s", "VLC", name );
}
/**
* Fills in one of the DirectSound frame buffers.
*
* @return VLC_SUCCESS on success.
*/
static int FillBuffer( audio_output_t *p_aout, block_t *p_buffer )
{
aout_sys_t *p_sys = p_aout->sys;
/* Open the device */
aout_FormatPrepare( fmt );
size_t towrite = (p_buffer)? p_buffer->i_buffer : DS_BUF_SIZE;
void *p_write_position, *p_wrap_around;
unsigned long l_bytes1, l_bytes2;
uint32_t i_read;
size_t i_size;
mtime_t i_buf;
HRESULT dsresult;
if( CreateDSBufferPCM( p_aout, &fmt->i_format,
fmt->i_physical_channels, fmt->i_rate, false )
!= VLC_SUCCESS )
size_t toerase = p_sys->i_bytes_per_sample * p_sys->i_rate / 4;
mtime_t max = towrite;
if( IDirectSoundBuffer_GetCurrentPosition( p_aout->sys->p_dsbuffer, (LPDWORD) &i_read, NULL) == DS_OK )
{
msg_Err( p_aout, "cannot open directx audio device" );
goto error;
}
max = (mtime_t)i_read - (mtime_t)p_aout->sys->i_write;
if( max <= 0 )
max += DS_BUF_SIZE;
}
p_aout->sys->i_write = 0;
/* Force volume update */
VolumeSet( p_aout, p_aout->sys->volume.volume );
MuteSet( p_aout, p_aout->sys->volume.mute );
/* then launch the notification thread */
p_aout->time_get = TimeGet;
p_aout->play = Play;
p_aout->pause = Pause;
p_aout->flush = Flush;
return VLC_SUCCESS;
error:
Stop( p_aout );
return VLC_EGENERIC;
}
if( towrite + toerase <= max )
i_buf = towrite + toerase;
else
i_buf = towrite;
/*****************************************************************************
* Play: we'll start playing the directsound buffer here because at least here
* we know the first buffer has been put in the aout fifo and we also
* know its date.
*****************************************************************************/
static void Play( audio_output_t *p_aout, block_t *p_buffer )
{
if( FillBuffer( p_aout, p_buffer ) == VLC_SUCCESS )
{
/* start playing the buffer */
HRESULT dsresult = IDirectSoundBuffer_Play( p_aout->sys->p_dsbuffer,
0, 0, DSBPLAY_LOOPING );
/* Before copying anything, we have to lock the buffer */
dsresult = IDirectSoundBuffer_Lock(
p_sys->p_dsbuffer, /* DS buffer */
p_aout->sys->i_write, /* Start offset */
i_buf, /* Number of bytes */
&p_write_position, /* Address of lock start */
&l_bytes1, /* Count of bytes locked before wrap around */
&p_wrap_around, /* Buffer address (if wrap around) */
&l_bytes2, /* Count of bytes after wrap around */
0 ); /* Flags: DSBLOCK_FROMWRITECURSOR is buggy */
if( dsresult == DSERR_BUFFERLOST )
{
IDirectSoundBuffer_Restore( p_aout->sys->p_dsbuffer );
dsresult = IDirectSoundBuffer_Play( p_aout->sys->p_dsbuffer,
0, 0, DSBPLAY_LOOPING );
IDirectSoundBuffer_Restore( p_sys->p_dsbuffer );
dsresult = IDirectSoundBuffer_Lock(
p_sys->p_dsbuffer,
p_aout->sys->i_write,
i_buf,
&p_write_position,
&l_bytes1,
&p_wrap_around,
&l_bytes2,
0 );
}
if( dsresult != DS_OK )
msg_Err( p_aout, "cannot start playing buffer" );
{
msg_Warn( p_aout, "cannot lock buffer" );
if( p_buffer != NULL )
block_Release( p_buffer );
return VLC_EGENERIC;
}
}
static int VolumeSet( audio_output_t *p_aout, float volume )
{
aout_sys_t *sys = p_aout->sys;
int ret = 0;
/* Directsound doesn't support amplification, so we use software
gain if we need it and only for this */
float gain = volume > 1.f ? volume * volume * volume : 1.f;
aout_GainRequest( p_aout, gain );
/* millibels from linear amplification */
LONG mb = lroundf( 6000.f * log10f( __MIN( volume, 1.f ) ));
/* Clamp to allowed DirectSound range */
static_assert( DSBVOLUME_MIN < DSBVOLUME_MAX, "DSBVOLUME_* confused" );
if( mb > DSBVOLUME_MAX )
if( p_buffer == NULL )
{
mb = DSBVOLUME_MAX;
ret = -1;
memset( p_write_position, 0, l_bytes1 );
memset( p_wrap_around, 0, l_bytes2 );
}
if( mb <= DSBVOLUME_MIN )
mb = DSBVOLUME_MIN;
sys->volume.mb = mb;
sys->volume.volume = volume;
if( !sys->volume.mute && sys->p_dsbuffer &&
IDirectSoundBuffer_SetVolume( sys->p_dsbuffer, mb ) != DS_OK )
return -1;
/* Convert back to UI volume */
aout_VolumeReport( p_aout, volume );
if( var_InheritBool( p_aout, "volume-save" ) )
config_PutFloat( p_aout, "directx-volume", volume );
return ret;
}
static int MuteSet( audio_output_t *p_aout, bool mute )
{
HRESULT res = DS_OK;
aout_sys_t *sys = p_aout->sys;
sys->volume.mute = mute;
else
{
if( p_sys->chans_to_reorder ) /* Do the channel reordering here */
aout_ChannelReorder( p_buffer->p_buffer, p_buffer->i_buffer,
p_sys->chans_to_reorder, p_sys->chan_table,
p_sys->format );
if( sys->p_dsbuffer )
res = IDirectSoundBuffer_SetVolume( sys->p_dsbuffer,
mute? DSBVOLUME_MIN : sys->volume.mb );
aout_MuteReport( p_aout, mute );
return (res != DS_OK);
}
i_size = ( p_buffer->i_buffer < l_bytes1 ) ? p_buffer->i_buffer : l_bytes1;
memcpy( p_write_position, p_buffer->p_buffer, i_size );
memset( (uint8_t*) p_write_position + i_size, 0, l_bytes1 - i_size );
/*****************************************************************************
* CloseAudio: close the audio device
*****************************************************************************/
static void Stop( audio_output_t *p_aout )
{
aout_sys_t *p_sys = p_aout->sys;
msg_Dbg( p_aout, "closing audio device" );
if( l_bytes1 < p_buffer->i_buffer)
{ /* Compute the remaining buffer space to be written */
i_buf = i_buf - i_size - (l_bytes1 - i_size);
i_size = ( p_buffer->i_buffer - l_bytes1 < l_bytes2 ) ? p_buffer->i_buffer - l_bytes1 : l_bytes2;
memcpy( p_wrap_around, p_buffer->p_buffer + l_bytes1, i_size );
memset( (uint8_t*) p_wrap_around + i_size, 0, i_buf - i_size );
}
block_Release( p_buffer );
}
if( p_sys->p_notify )
IDirectSoundNotify_Release(p_sys->p_notify );
p_sys->p_notify = NULL;
/* Now the data has been copied, unlock the buffer */
IDirectSoundBuffer_Unlock( p_sys->p_dsbuffer, p_write_position, l_bytes1,
p_wrap_around, l_bytes2 );
if( p_sys->p_dsbuffer )
IDirectSoundBuffer_Stop( p_sys->p_dsbuffer );
/* release the secondary buffer */
DestroyDSBuffer( p_aout );
p_sys->i_write += towrite;
p_sys->i_write %= DS_BUF_SIZE;
/* finally release the DirectSound object */
if( p_sys->p_dsobject )
IDirectSound_Release( p_sys->p_dsobject );
return VLC_SUCCESS;
}
/*****************************************************************************
* InitDirectSound: handle all the gory details of DirectSound initialisation
*****************************************************************************/
static int InitDirectSound( audio_output_t *p_aout )
static void Play( audio_output_t *p_aout, block_t *p_buffer )
{
aout_sys_t *sys = p_aout->sys;
GUID guid, *p_guid = NULL;
HRESULT (WINAPI *OurDirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN);
if( FillBuffer( p_aout, p_buffer ) != VLC_SUCCESS )
return;
OurDirectSoundCreate = (void *)
GetProcAddress( p_aout->sys->hdsound_dll,
"DirectSoundCreate" );
if( OurDirectSoundCreate == NULL )
/* start playing the buffer */
HRESULT dsresult = IDirectSoundBuffer_Play( p_aout->sys->p_dsbuffer,
0, 0, DSBPLAY_LOOPING );
if( dsresult == DSERR_BUFFERLOST )
{
msg_Warn( p_aout, "GetProcAddress FAILED" );
goto error;
IDirectSoundBuffer_Restore( p_aout->sys->p_dsbuffer );
dsresult = IDirectSoundBuffer_Play( p_aout->sys->p_dsbuffer,
0, 0, DSBPLAY_LOOPING );
}
if( dsresult != DS_OK )
msg_Err( p_aout, "cannot start playing buffer" );
}
char *dev = var_GetNonEmptyString( p_aout, "directx-audio-device" );
if( dev != NULL )
{
LPOLESTR lpsz = ToWide( dev );
free( dev );
if( SUCCEEDED( IIDFromString( lpsz, &guid ) ) )
p_guid = &guid;
static void Pause( audio_output_t * aout, bool pause, mtime_t date )
{
if( pause )
IDirectSoundBuffer_Stop( aout->sys->p_dsbuffer );
else
msg_Err( p_aout, "bad device GUID: %ls", lpsz );
free( lpsz );
}
/* Create the direct sound object */
if FAILED( OurDirectSoundCreate( p_guid, &sys->p_dsobject, NULL ) )
{
msg_Warn( p_aout, "cannot create a direct sound device" );
goto error;
}
/* Set DirectSound Cooperative level, ie what control we want over Windows
* sound device. In our case, DSSCL_EXCLUSIVE means that we can modify the
* settings of the primary buffer, but also that only the sound of our
* application will be hearable when it will have the focus.
* !!! (this is not really working as intended yet because to set the
* cooperative level you need the window handle of your application, and
* I don't know of any easy way to get it. Especially since we might play
* 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 !VLC_WINSTORE_APP
if( IDirectSound_SetCooperativeLevel( p_aout->sys->p_dsobject,
GetDesktopWindow(),
DSSCL_EXCLUSIVE) )
{
msg_Warn( p_aout, "cannot set direct sound cooperative level" );
}
#endif
return VLC_SUCCESS;
error:
sys->p_dsobject = NULL;
return VLC_EGENERIC;
IDirectSoundBuffer_Play( aout->sys->p_dsbuffer, 0, 0,
DSBPLAY_LOOPING );
(void) date;
}
static void Flush( audio_output_t * aout, bool drain )
{
IDirectSoundBuffer_Stop( aout->sys->p_dsbuffer );
if( !drain )
IDirectSoundBuffer_SetCurrentPosition( aout->sys->p_dsbuffer,
aout->sys->i_write );
}
/*****************************************************************************
* CreateDSBuffer: Creates a direct sound buffer of the required format.
*****************************************************************************
/**
* Creates a DirectSound buffer of the required format.
*
* This function creates the buffer we'll use to play audio.
* In DirectSound there are two kinds of buffers:
* - the primary buffer: which is the actual buffer that the soundcard plays
......@@ -500,7 +288,7 @@ static int InitDirectSound( audio_output_t *p_aout )
*
* Once you create a secondary buffer, you cannot change its format anymore so
* you have to release the current one and create another.
*****************************************************************************/
*/
static int CreateDSBuffer( audio_output_t *p_aout, int i_format,
int i_channels, int i_nb_channels, int i_rate,
bool b_probe )
......@@ -641,154 +429,359 @@ static int CreateDSBuffer( audio_output_t *p_aout, int i_format,
return VLC_SUCCESS;
}
/*****************************************************************************
* CreateDSBufferPCM: creates a PCM direct sound buffer.
*****************************************************************************
/**
* Creates a PCM DirectSound buffer.
*
* We first try to create a WAVE_FORMAT_IEEE_FLOAT buffer if supported by
* the hardware, otherwise we create a WAVE_FORMAT_PCM buffer.
****************************************************************************/
*/
static int CreateDSBufferPCM( audio_output_t *p_aout, vlc_fourcc_t *i_format,
int i_channels, int i_rate, bool b_probe )
{
unsigned i_nb_channels = popcount( i_channels );
if( !var_GetBool( p_aout, "directx-audio-float32" ) ||
CreateDSBuffer( p_aout, VLC_CODEC_FL32,
i_channels, i_nb_channels, i_rate, b_probe )
!= VLC_SUCCESS )
if( var_GetBool( p_aout, "directx-audio-float32" )
&& CreateDSBuffer( p_aout, VLC_CODEC_FL32, i_channels, i_nb_channels,
i_rate, b_probe ) == VLC_SUCCESS )
{
if ( CreateDSBuffer( p_aout, VLC_CODEC_S16N,
i_channels, i_nb_channels, i_rate, b_probe )
!= VLC_SUCCESS )
*i_format = VLC_CODEC_FL32;
return VLC_SUCCESS;
}
if( CreateDSBuffer( p_aout, VLC_CODEC_S16N, i_channels, i_nb_channels,
i_rate, b_probe ) == VLC_SUCCESS )
{
*i_format = VLC_CODEC_S16N;
return VLC_SUCCESS;
}
return VLC_EGENERIC;
}
/**
* Closes the audio device.
*/
static void Stop( audio_output_t *p_aout )
{
aout_sys_t *p_sys = p_aout->sys;
msg_Dbg( p_aout, "closing audio device" );
if( p_sys->p_notify != NULL )
{
IDirectSoundNotify_Release(p_sys->p_notify );
p_sys->p_notify = NULL;
}
if( p_sys->p_dsbuffer != NULL )
{
IDirectSoundBuffer_Stop( p_sys->p_dsbuffer );
IDirectSoundBuffer_Release( p_aout->sys->p_dsbuffer );
p_aout->sys->p_dsbuffer = NULL;
}
if( p_sys->p_dsobject != NULL )
{
IDirectSound_Release( p_sys->p_dsobject );
p_sys->p_dsobject = NULL;
}
}
/**
* Handles all the gory details of DirectSound initialization.
*/
static int InitDirectSound( audio_output_t *p_aout )
{
aout_sys_t *sys = p_aout->sys;
GUID guid, *p_guid = NULL;
HRESULT (WINAPI *OurDirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN);
OurDirectSoundCreate = (void *)
GetProcAddress( p_aout->sys->hdsound_dll,
"DirectSoundCreate" );
if( OurDirectSoundCreate == NULL )
{
msg_Warn( p_aout, "GetProcAddress FAILED" );
goto error;
}
char *dev = var_GetNonEmptyString( p_aout, "directx-audio-device" );
if( dev != NULL )
{
LPOLESTR lpsz = ToWide( dev );
free( dev );
if( SUCCEEDED( IIDFromString( lpsz, &guid ) ) )
p_guid = &guid;
else
msg_Err( p_aout, "bad device GUID: %ls", lpsz );
free( lpsz );
}
/* Create the direct sound object */
if FAILED( OurDirectSoundCreate( p_guid, &sys->p_dsobject, NULL ) )
{
msg_Warn( p_aout, "cannot create a direct sound device" );
goto error;
}
/* Set DirectSound Cooperative level, ie what control we want over Windows
* sound device. In our case, DSSCL_EXCLUSIVE means that we can modify the
* settings of the primary buffer, but also that only the sound of our
* application will be hearable when it will have the focus.
* !!! (this is not really working as intended yet because to set the
* cooperative level you need the window handle of your application, and
* I don't know of any easy way to get it. Especially since we might play
* 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 !VLC_WINSTORE_APP
if( IDirectSound_SetCooperativeLevel( p_aout->sys->p_dsobject,
GetDesktopWindow(),
DSSCL_EXCLUSIVE) )
{
msg_Warn( p_aout, "cannot set direct sound cooperative level" );
}
#endif
return VLC_SUCCESS;
error:
sys->p_dsobject = NULL;
return VLC_EGENERIC;
}
static int VolumeSet( audio_output_t *p_aout, float volume )
{
aout_sys_t *sys = p_aout->sys;
int ret = 0;
/* Directsound doesn't support amplification, so we use software
gain if we need it and only for this */
float gain = volume > 1.f ? volume * volume * volume : 1.f;
aout_GainRequest( p_aout, gain );
/* millibels from linear amplification */
LONG mb = lroundf( 6000.f * log10f( __MIN( volume, 1.f ) ));
/* Clamp to allowed DirectSound range */
static_assert( DSBVOLUME_MIN < DSBVOLUME_MAX, "DSBVOLUME_* confused" );
if( mb > DSBVOLUME_MAX )
{
mb = DSBVOLUME_MAX;
ret = -1;
}
if( mb <= DSBVOLUME_MIN )
mb = DSBVOLUME_MIN;
sys->volume.mb = mb;
sys->volume.volume = volume;
if( !sys->volume.mute && sys->p_dsbuffer &&
IDirectSoundBuffer_SetVolume( sys->p_dsbuffer, mb ) != DS_OK )
return -1;
/* Convert back to UI volume */
aout_VolumeReport( p_aout, volume );
if( var_InheritBool( p_aout, "volume-save" ) )
config_PutFloat( p_aout, "directx-volume", volume );
return ret;
}
static int MuteSet( audio_output_t *p_aout, bool mute )
{
HRESULT res = DS_OK;
aout_sys_t *sys = p_aout->sys;
sys->volume.mute = mute;
if( sys->p_dsbuffer )
res = IDirectSoundBuffer_SetVolume( sys->p_dsbuffer,
mute? DSBVOLUME_MIN : sys->volume.mb );
aout_MuteReport( p_aout, mute );
return (res != DS_OK);
}
static int Start( audio_output_t *p_aout, audio_sample_format_t *restrict fmt )
{
char *psz_speaker;
int i = 0;
const char *const *ppsz_compare = speaker_list;
msg_Dbg( p_aout, "Opening DirectSound Audio Output" );
/* Retrieve config values */
var_Create( p_aout, "directx-audio-float32",
VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
psz_speaker = var_CreateGetString( p_aout, "directx-audio-speaker" );
while ( *ppsz_compare != NULL )
{
return VLC_EGENERIC;
}
else
if ( !strncmp( *ppsz_compare, psz_speaker, strlen(*ppsz_compare) ) )
{
*i_format = VLC_CODEC_S16N;
return VLC_SUCCESS;
break;
}
ppsz_compare++; i++;
}
else
if ( *ppsz_compare == NULL )
{
*i_format = VLC_CODEC_FL32;
return VLC_SUCCESS;
msg_Err( p_aout, "(%s) isn't valid speaker setup option", psz_speaker );
msg_Err( p_aout, "Defaulting to Windows default speaker config");
i = 0;
}
}
free( psz_speaker );
/*****************************************************************************
* DestroyDSBuffer
*****************************************************************************
* This function destroys the secondary buffer.
*****************************************************************************/
static void DestroyDSBuffer( audio_output_t *p_aout )
{
if( p_aout->sys->p_dsbuffer )
/* Initialise DirectSound */
if( InitDirectSound( p_aout ) )
{
IDirectSoundBuffer_Release( p_aout->sys->p_dsbuffer );
p_aout->sys->p_dsbuffer = NULL;
msg_Err( p_aout, "cannot initialize DirectSound" );
goto error;
}
}
/*****************************************************************************
* FillBuffer: Fill in one of the direct sound frame buffers.
*****************************************************************************
* Returns VLC_SUCCESS on success.
*****************************************************************************/
static int FillBuffer( audio_output_t *p_aout, block_t *p_buffer )
{
aout_sys_t *p_sys = p_aout->sys;
size_t towrite = (p_buffer)? p_buffer->i_buffer : DS_BUF_SIZE;
void *p_write_position, *p_wrap_around;
unsigned long l_bytes1, l_bytes2;
uint32_t i_read;
size_t i_size;
mtime_t i_buf;
HRESULT dsresult;
size_t toerase = p_sys->i_bytes_per_sample * p_sys->i_rate / 4;
mtime_t max = towrite;
if( IDirectSoundBuffer_GetCurrentPosition( p_aout->sys->p_dsbuffer, (LPDWORD) &i_read, NULL) == DS_OK )
if ( AOUT_FMT_SPDIF( fmt ) && var_InheritBool( p_aout, "spdif" )
&& CreateDSBuffer( p_aout, VLC_CODEC_SPDIFL, fmt->i_physical_channels,
aout_FormatNbChannels( fmt ), fmt->i_rate, false )
== VLC_SUCCESS )
{
max = (mtime_t)i_read - (mtime_t)p_aout->sys->i_write;
if( max <= 0 )
max += DS_BUF_SIZE;
}
msg_Dbg( p_aout, "using A/52 pass-through over S/PDIF" );
fmt->i_format = VLC_CODEC_SPDIFL;
if( towrite + toerase <= max )
i_buf = towrite + toerase;
/* Calculate the frame size in bytes */
fmt->i_bytes_per_frame = AOUT_SPDIF_SIZE;
fmt->i_frame_length = A52_FRAME_NB;
}
else
i_buf = towrite;
{
if( i == 0 )
{
DWORD ui_speaker_config;
int i_channels = 2; /* Default to stereo */
int i_orig_channels = aout_FormatNbChannels( fmt );
/* Before copying anything, we have to lock the buffer */
dsresult = IDirectSoundBuffer_Lock(
p_sys->p_dsbuffer, /* DS buffer */
p_aout->sys->i_write, /* Start offset */
i_buf, /* Number of bytes */
&p_write_position, /* Address of lock start */
&l_bytes1, /* Count of bytes locked before wrap around */
&p_wrap_around, /* Buffer address (if wrap around) */
&l_bytes2, /* Count of bytes after wrap around */
0 ); /* Flags: DSBLOCK_FROMWRITECURSOR is buggy */
if( dsresult == DSERR_BUFFERLOST )
/* Check the speaker configuration to determine which channel
* config should be the default */
if( FAILED( IDirectSound_GetSpeakerConfig( p_aout->sys->p_dsobject,
&ui_speaker_config ) ) )
{
IDirectSoundBuffer_Restore( p_sys->p_dsbuffer );
dsresult = IDirectSoundBuffer_Lock(
p_sys->p_dsbuffer,
p_aout->sys->i_write,
i_buf,
&p_write_position,
&l_bytes1,
&p_wrap_around,
&l_bytes2,
0 );
ui_speaker_config = DSSPEAKER_STEREO;
msg_Dbg( p_aout, "GetSpeakerConfig failed" );
}
if( dsresult != DS_OK )
const char *name = "Unknown";
switch( DSSPEAKER_CONFIG(ui_speaker_config) )
{
msg_Warn( p_aout, "cannot lock buffer" );
if( p_buffer ) block_Release( p_buffer );
return VLC_EGENERIC;
case DSSPEAKER_7POINT1:
case DSSPEAKER_7POINT1_SURROUND:
name = "7.1";
i_channels = 8;
break;
case DSSPEAKER_5POINT1:
case DSSPEAKER_5POINT1_SURROUND:
name = "5.1";
i_channels = 6;
break;
case DSSPEAKER_QUAD:
name = "Quad";
i_channels = 4;
break;
#if 0 /* Lots of people just get their settings wrong and complain that
* this is a problem with VLC so just don't ever set mono by default. */
case DSSPEAKER_MONO:
name = "Mono";
i_channels = 1;
break;
#endif
case DSSPEAKER_SURROUND:
name = "Surround";
i_channels = 4;
break;
case DSSPEAKER_STEREO:
name = "Stereo";
i_channels = 2;
break;
}
if( p_buffer == NULL )
if( i_channels >= i_orig_channels )
i_channels = i_orig_channels;
msg_Dbg( p_aout, "%s speaker config: %s and stream has "
"%d channels, using %d channels", "Windows", name,
i_orig_channels, i_channels );
switch( i_channels )
{
memset( p_write_position, 0, l_bytes1 );
memset( p_wrap_around, 0, l_bytes2 );
case 8:
fmt->i_physical_channels = AOUT_CHANS_7_1;
break;
case 7:
case 6:
fmt->i_physical_channels = AOUT_CHANS_5_1;
break;
case 5:
case 4:
fmt->i_physical_channels = AOUT_CHANS_4_0;
break;
default:
fmt->i_physical_channels = AOUT_CHANS_2_0;
break;
}
}
else
{ /* Overriden speaker configuration */
const char *name = "Non-existant";
switch( i )
{
if( p_sys->chans_to_reorder )
/* Do the channel reordering here */
aout_ChannelReorder( p_buffer->p_buffer, p_buffer->i_buffer,
p_sys->chans_to_reorder, p_sys->chan_table,
p_sys->format );
case 1: /* Mono */
name = "Mono";
fmt->i_physical_channels = AOUT_CHAN_CENTER;
break;
case 2: /* Stereo */
name = "Stereo";
fmt->i_physical_channels = AOUT_CHANS_2_0;
break;
case 3: /* Quad */
name = "Quad";
fmt->i_physical_channels = AOUT_CHANS_4_0;
break;
case 4: /* 5.1 */
name = "5.1";
fmt->i_physical_channels = AOUT_CHANS_5_1;
break;
case 5: /* 7.1 */
name = "7.1";
fmt->i_physical_channels = AOUT_CHANS_7_1;
break;
}
msg_Dbg( p_aout, "%s speaker config: %s", "VLC", name );
}
i_size = ( p_buffer->i_buffer < l_bytes1 ) ? p_buffer->i_buffer : l_bytes1;
memcpy( p_write_position, p_buffer->p_buffer, i_size );
memset( (uint8_t*) p_write_position + i_size, 0, l_bytes1 - i_size );
/* Open the device */
aout_FormatPrepare( fmt );
if( l_bytes1 < p_buffer->i_buffer)
if( CreateDSBufferPCM( p_aout, &fmt->i_format,
fmt->i_physical_channels, fmt->i_rate, false )
!= VLC_SUCCESS )
{
/* Compute the remaining buffer space to be written */
i_buf = i_buf - i_size - (l_bytes1 - i_size);
i_size = ( p_buffer->i_buffer - l_bytes1 < l_bytes2 ) ? p_buffer->i_buffer - l_bytes1 : l_bytes2;
memcpy( p_wrap_around, p_buffer->p_buffer + l_bytes1, i_size );
memset( (uint8_t*) p_wrap_around + i_size, 0, i_buf - i_size );
msg_Err( p_aout, "cannot open directx audio device" );
goto error;
}
block_Release( p_buffer );
}
p_aout->sys->i_write = 0;
/* Now the data has been copied, unlock the buffer */
IDirectSoundBuffer_Unlock( p_sys->p_dsbuffer, p_write_position, l_bytes1,
p_wrap_around, l_bytes2 );
/* Force volume update */
VolumeSet( p_aout, p_aout->sys->volume.volume );
MuteSet( p_aout, p_aout->sys->volume.mute );
p_sys->i_write += towrite;
p_sys->i_write %= DS_BUF_SIZE;
/* then launch the notification thread */
p_aout->time_get = TimeGet;
p_aout->play = Play;
p_aout->pause = Pause;
p_aout->flush = Flush;
return VLC_SUCCESS;
error:
Stop( p_aout );
return VLC_EGENERIC;
}
typedef struct
......@@ -819,9 +812,9 @@ static int CALLBACK DeviceEnumCallback( LPGUID guid, LPCWSTR desc,
return true;
}
/*****************************************************************************
* ReloadDirectXDevices: store the list of devices in preferences
*****************************************************************************/
/**
* Stores the list of devices in preferences
*/
static int ReloadDirectXDevices( vlc_object_t *p_this, char const *psz_name,
char ***values, char ***descs )
{
......@@ -936,39 +929,3 @@ static void Close(vlc_object_t *obj)
FreeLibrary(sys->hdsound_dll); /* free DSOUND.DLL */
free(sys);
}
static void Flush ( audio_output_t * aout, bool drain )
{
IDirectSoundBuffer_Stop( aout->sys->p_dsbuffer );
if( !drain )
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