Added device change notifier to XAudio2 outputs
This commit is contained in:
parent
4d174be28a
commit
d2e00a0085
|
@ -12,11 +12,130 @@
|
||||||
// XAudio2
|
// XAudio2
|
||||||
#include <xaudio2.h>
|
#include <xaudio2.h>
|
||||||
|
|
||||||
|
// MMDevice API
|
||||||
|
#include <mmdeviceapi.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
// Internals
|
// Internals
|
||||||
#include "../System.h" // for systemMessage()
|
#include "../System.h" // for systemMessage()
|
||||||
#include "../gba/Globals.h"
|
#include "../gba/Globals.h"
|
||||||
|
|
||||||
|
|
||||||
|
class XAudio2_Output;
|
||||||
|
|
||||||
|
static void xaudio2_device_changed( XAudio2_Output * );
|
||||||
|
|
||||||
|
class XAudio2_Device_Notifier : public IMMNotificationClient
|
||||||
|
{
|
||||||
|
volatile LONG registered;
|
||||||
|
IMMDeviceEnumerator *pEnumerator;
|
||||||
|
|
||||||
|
std::wstring last_device;
|
||||||
|
|
||||||
|
CRITICAL_SECTION lock;
|
||||||
|
std::vector<XAudio2_Output*> instances;
|
||||||
|
|
||||||
|
public:
|
||||||
|
XAudio2_Device_Notifier() : registered( 0 )
|
||||||
|
{
|
||||||
|
InitializeCriticalSection( &lock );
|
||||||
|
}
|
||||||
|
~XAudio2_Device_Notifier()
|
||||||
|
{
|
||||||
|
DeleteCriticalSection( &lock );
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG STDMETHODCALLTYPE AddRef()
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG STDMETHODCALLTYPE Release()
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, VOID **ppvInterface )
|
||||||
|
{
|
||||||
|
if (IID_IUnknown == riid)
|
||||||
|
{
|
||||||
|
*ppvInterface = (IUnknown*)this;
|
||||||
|
}
|
||||||
|
else if (__uuidof(IMMNotificationClient) == riid)
|
||||||
|
{
|
||||||
|
*ppvInterface = (IMMNotificationClient*)this;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*ppvInterface = NULL;
|
||||||
|
return E_NOINTERFACE;
|
||||||
|
}
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged( EDataFlow flow, ERole role, LPCWSTR pwstrDeviceId )
|
||||||
|
{
|
||||||
|
if ( flow == eRender && last_device.compare( pwstrDeviceId ) != 0 )
|
||||||
|
{
|
||||||
|
last_device = pwstrDeviceId;
|
||||||
|
|
||||||
|
EnterCriticalSection( &lock );
|
||||||
|
for ( auto it = instances.begin(); it < instances.end(); ++it )
|
||||||
|
{
|
||||||
|
xaudio2_device_changed( *it );
|
||||||
|
}
|
||||||
|
LeaveCriticalSection( &lock );
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE OnDeviceAdded( LPCWSTR pwstrDeviceId ) { return S_OK; }
|
||||||
|
HRESULT STDMETHODCALLTYPE OnDeviceRemoved( LPCWSTR pwstrDeviceId ) { return S_OK; }
|
||||||
|
HRESULT STDMETHODCALLTYPE OnDeviceStateChanged( LPCWSTR pwstrDeviceId, DWORD dwNewState ) { return S_OK; }
|
||||||
|
HRESULT STDMETHODCALLTYPE OnPropertyValueChanged( LPCWSTR pwstrDeviceId, const PROPERTYKEY key ) { return S_OK; }
|
||||||
|
|
||||||
|
void do_register(XAudio2_Output * p_instance)
|
||||||
|
{
|
||||||
|
if ( InterlockedIncrement( ®istered ) == 1 )
|
||||||
|
{
|
||||||
|
pEnumerator = NULL;
|
||||||
|
HRESULT hr = CoCreateInstance( __uuidof( MMDeviceEnumerator ), NULL, CLSCTX_INPROC_SERVER, __uuidof( IMMDeviceEnumerator ), ( void** ) &pEnumerator );
|
||||||
|
if ( SUCCEEDED( hr ) )
|
||||||
|
{
|
||||||
|
pEnumerator->RegisterEndpointNotificationCallback( this );
|
||||||
|
registered = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EnterCriticalSection( &lock );
|
||||||
|
instances.push_back( p_instance );
|
||||||
|
LeaveCriticalSection( &lock );
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_unregister( XAudio2_Output * p_instance )
|
||||||
|
{
|
||||||
|
if ( InterlockedDecrement( ®istered ) == 0 )
|
||||||
|
{
|
||||||
|
pEnumerator->UnregisterEndpointNotificationCallback( this );
|
||||||
|
pEnumerator->Release();
|
||||||
|
registered = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
EnterCriticalSection( &lock );
|
||||||
|
for ( auto it = instances.begin(); it < instances.end(); ++it )
|
||||||
|
{
|
||||||
|
if ( *it == p_instance )
|
||||||
|
{
|
||||||
|
instances.erase( it );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LeaveCriticalSection( &lock );
|
||||||
|
}
|
||||||
|
} g_notifier;
|
||||||
|
|
||||||
// Synchronization Event
|
// Synchronization Event
|
||||||
class XAudio2_BufferNotify : public IXAudio2VoiceCallback
|
class XAudio2_BufferNotify : public IXAudio2VoiceCallback
|
||||||
{
|
{
|
||||||
|
@ -68,6 +187,8 @@ public:
|
||||||
void pause();
|
void pause();
|
||||||
void resume();
|
void resume();
|
||||||
void reset();
|
void reset();
|
||||||
|
void close();
|
||||||
|
void device_change();
|
||||||
|
|
||||||
// Configuration Changes
|
// Configuration Changes
|
||||||
void setThrottle( unsigned short throttle );
|
void setThrottle( unsigned short throttle );
|
||||||
|
@ -82,6 +203,8 @@ private:
|
||||||
int currentBuffer;
|
int currentBuffer;
|
||||||
int soundBufferLen;
|
int soundBufferLen;
|
||||||
|
|
||||||
|
volatile bool device_changed;
|
||||||
|
|
||||||
IXAudio2 *xaud;
|
IXAudio2 *xaud;
|
||||||
IXAudio2MasteringVoice *mVoice; // listener
|
IXAudio2MasteringVoice *mVoice; // listener
|
||||||
IXAudio2SourceVoice *sVoice; // sound source
|
IXAudio2SourceVoice *sVoice; // sound source
|
||||||
|
@ -101,16 +224,25 @@ XAudio2_Output::XAudio2_Output()
|
||||||
bufferCount = theApp.xa2BufferCount;
|
bufferCount = theApp.xa2BufferCount;
|
||||||
buffers = NULL;
|
buffers = NULL;
|
||||||
currentBuffer = 0;
|
currentBuffer = 0;
|
||||||
|
device_changed = false;
|
||||||
|
|
||||||
xaud = NULL;
|
xaud = NULL;
|
||||||
mVoice = NULL;
|
mVoice = NULL;
|
||||||
sVoice = NULL;
|
sVoice = NULL;
|
||||||
ZeroMemory( &buf, sizeof( buf ) );
|
ZeroMemory( &buf, sizeof( buf ) );
|
||||||
ZeroMemory( &vState, sizeof( vState ) );
|
ZeroMemory( &vState, sizeof( vState ) );
|
||||||
|
|
||||||
|
g_notifier.do_register( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
XAudio2_Output::~XAudio2_Output()
|
XAudio2_Output::~XAudio2_Output()
|
||||||
|
{
|
||||||
|
g_notifier.do_unregister( this );
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void XAudio2_Output::close()
|
||||||
{
|
{
|
||||||
initialized = false;
|
initialized = false;
|
||||||
|
|
||||||
|
@ -120,6 +252,7 @@ XAudio2_Output::~XAudio2_Output()
|
||||||
ASSERT( hr == S_OK );
|
ASSERT( hr == S_OK );
|
||||||
}
|
}
|
||||||
sVoice->DestroyVoice();
|
sVoice->DestroyVoice();
|
||||||
|
sVoice = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( buffers ) {
|
if( buffers ) {
|
||||||
|
@ -129,6 +262,7 @@ XAudio2_Output::~XAudio2_Output()
|
||||||
|
|
||||||
if( mVoice ) {
|
if( mVoice ) {
|
||||||
mVoice->DestroyVoice();
|
mVoice->DestroyVoice();
|
||||||
|
mVoice = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( xaud ) {
|
if( xaud ) {
|
||||||
|
@ -137,6 +271,11 @@ XAudio2_Output::~XAudio2_Output()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void XAudio2_Output::device_change()
|
||||||
|
{
|
||||||
|
device_changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool XAudio2_Output::init(long sampleRate)
|
bool XAudio2_Output::init(long sampleRate)
|
||||||
{
|
{
|
||||||
|
@ -276,6 +415,8 @@ bool XAudio2_Output::init(long sampleRate)
|
||||||
ASSERT( hr == S_OK );
|
ASSERT( hr == S_OK );
|
||||||
playing = true;
|
playing = true;
|
||||||
|
|
||||||
|
currentBuffer = 0;
|
||||||
|
device_changed = false;
|
||||||
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
return true;
|
return true;
|
||||||
|
@ -287,6 +428,11 @@ void XAudio2_Output::write(u16 * finalWave, int length)
|
||||||
if( !initialized || failed ) return;
|
if( !initialized || failed ) return;
|
||||||
|
|
||||||
while( true ) {
|
while( true ) {
|
||||||
|
if ( device_changed ) {
|
||||||
|
close();
|
||||||
|
if (!init(freq)) return;
|
||||||
|
}
|
||||||
|
|
||||||
sVoice->GetState( &vState );
|
sVoice->GetState( &vState );
|
||||||
|
|
||||||
ASSERT( vState.BuffersQueued <= bufferCount );
|
ASSERT( vState.BuffersQueued <= bufferCount );
|
||||||
|
@ -305,7 +451,9 @@ void XAudio2_Output::write(u16 * finalWave, int length)
|
||||||
// the maximum number of buffers is currently queued
|
// the maximum number of buffers is currently queued
|
||||||
if( synchronize && !speedup && !theApp.throttle ) {
|
if( synchronize && !speedup && !theApp.throttle ) {
|
||||||
// wait for one buffer to finish playing
|
// wait for one buffer to finish playing
|
||||||
WaitForSingleObject( notify.hBufferEndEvent, INFINITE );
|
if (WaitForSingleObject( notify.hBufferEndEvent, 10000 ) == WAIT_TIMEOUT) {
|
||||||
|
device_changed = true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// drop current audio frame
|
// drop current audio frame
|
||||||
return;
|
return;
|
||||||
|
@ -375,6 +523,11 @@ void XAudio2_Output::setThrottle( unsigned short throttle )
|
||||||
ASSERT( hr == S_OK );
|
ASSERT( hr == S_OK );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void xaudio2_device_changed( XAudio2_Output * instance )
|
||||||
|
{
|
||||||
|
instance->device_change();
|
||||||
|
}
|
||||||
|
|
||||||
SoundDriver *newXAudio2_Output()
|
SoundDriver *newXAudio2_Output()
|
||||||
{
|
{
|
||||||
return new XAudio2_Output();
|
return new XAudio2_Output();
|
||||||
|
|
|
@ -10,11 +10,130 @@
|
||||||
// XAudio2
|
// XAudio2
|
||||||
#include <XAudio2.h>
|
#include <XAudio2.h>
|
||||||
|
|
||||||
|
// MMDevice API
|
||||||
|
#include <mmdeviceapi.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
// Internals
|
// Internals
|
||||||
#include "../System.h" // for systemMessage()
|
#include "../System.h" // for systemMessage()
|
||||||
#include "../gba/Globals.h"
|
#include "../gba/Globals.h"
|
||||||
|
|
||||||
|
|
||||||
|
class XAudio2_Output;
|
||||||
|
|
||||||
|
static void xaudio2_device_changed( XAudio2_Output * );
|
||||||
|
|
||||||
|
class XAudio2_Device_Notifier : public IMMNotificationClient
|
||||||
|
{
|
||||||
|
volatile LONG registered;
|
||||||
|
IMMDeviceEnumerator *pEnumerator;
|
||||||
|
|
||||||
|
std::wstring last_device;
|
||||||
|
|
||||||
|
CRITICAL_SECTION lock;
|
||||||
|
std::vector<XAudio2_Output*> instances;
|
||||||
|
|
||||||
|
public:
|
||||||
|
XAudio2_Device_Notifier() : registered( 0 )
|
||||||
|
{
|
||||||
|
InitializeCriticalSection( &lock );
|
||||||
|
}
|
||||||
|
~XAudio2_Device_Notifier()
|
||||||
|
{
|
||||||
|
DeleteCriticalSection( &lock );
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG STDMETHODCALLTYPE AddRef()
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG STDMETHODCALLTYPE Release()
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, VOID **ppvInterface )
|
||||||
|
{
|
||||||
|
if (IID_IUnknown == riid)
|
||||||
|
{
|
||||||
|
*ppvInterface = (IUnknown*)this;
|
||||||
|
}
|
||||||
|
else if (__uuidof(IMMNotificationClient) == riid)
|
||||||
|
{
|
||||||
|
*ppvInterface = (IMMNotificationClient*)this;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*ppvInterface = NULL;
|
||||||
|
return E_NOINTERFACE;
|
||||||
|
}
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged( EDataFlow flow, ERole role, LPCWSTR pwstrDeviceId )
|
||||||
|
{
|
||||||
|
if ( flow == eRender && last_device.compare( pwstrDeviceId ) != 0 )
|
||||||
|
{
|
||||||
|
last_device = pwstrDeviceId;
|
||||||
|
|
||||||
|
EnterCriticalSection( &lock );
|
||||||
|
for ( auto it = instances.begin(); it < instances.end(); ++it )
|
||||||
|
{
|
||||||
|
xaudio2_device_changed( *it );
|
||||||
|
}
|
||||||
|
LeaveCriticalSection( &lock );
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE OnDeviceAdded( LPCWSTR pwstrDeviceId ) { return S_OK; }
|
||||||
|
HRESULT STDMETHODCALLTYPE OnDeviceRemoved( LPCWSTR pwstrDeviceId ) { return S_OK; }
|
||||||
|
HRESULT STDMETHODCALLTYPE OnDeviceStateChanged( LPCWSTR pwstrDeviceId, DWORD dwNewState ) { return S_OK; }
|
||||||
|
HRESULT STDMETHODCALLTYPE OnPropertyValueChanged( LPCWSTR pwstrDeviceId, const PROPERTYKEY key ) { return S_OK; }
|
||||||
|
|
||||||
|
void do_register(sound_out_i_xaudio2 * p_instance)
|
||||||
|
{
|
||||||
|
if ( InterlockedIncrement( ®istered ) == 1 )
|
||||||
|
{
|
||||||
|
pEnumerator = NULL;
|
||||||
|
HRESULT hr = CoCreateInstance( __uuidof( MMDeviceEnumerator ), NULL, CLSCTX_INPROC_SERVER, __uuidof( IMMDeviceEnumerator ), ( void** ) &pEnumerator );
|
||||||
|
if ( SUCCEEDED( hr ) )
|
||||||
|
{
|
||||||
|
pEnumerator->RegisterEndpointNotificationCallback( this );
|
||||||
|
registered = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EnterCriticalSection( &lock );
|
||||||
|
instances.push_back( p_instance );
|
||||||
|
LeaveCriticalSection( &lock );
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_unregister( sound_out_i_xaudio2 * p_instance )
|
||||||
|
{
|
||||||
|
if ( InterlockedDecrement( ®istered ) == 0 )
|
||||||
|
{
|
||||||
|
pEnumerator->UnregisterEndpointNotificationCallback( this );
|
||||||
|
pEnumerator->Release();
|
||||||
|
registered = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
EnterCriticalSection( &lock );
|
||||||
|
for ( auto it = instances.begin(); it < instances.end(); ++it )
|
||||||
|
{
|
||||||
|
if ( *it == p_instance )
|
||||||
|
{
|
||||||
|
instances.erase( it );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LeaveCriticalSection( &lock );
|
||||||
|
}
|
||||||
|
} g_notifier;
|
||||||
|
|
||||||
// Synchronization Event
|
// Synchronization Event
|
||||||
class XAudio2_BufferNotify : public IXAudio2VoiceCallback
|
class XAudio2_BufferNotify : public IXAudio2VoiceCallback
|
||||||
{
|
{
|
||||||
|
@ -66,6 +185,8 @@ public:
|
||||||
void pause();
|
void pause();
|
||||||
void resume();
|
void resume();
|
||||||
void reset();
|
void reset();
|
||||||
|
void close();
|
||||||
|
void device_change();
|
||||||
|
|
||||||
// Configuration Changes
|
// Configuration Changes
|
||||||
void setThrottle( unsigned short throttle );
|
void setThrottle( unsigned short throttle );
|
||||||
|
@ -80,6 +201,8 @@ private:
|
||||||
int currentBuffer;
|
int currentBuffer;
|
||||||
int soundBufferLen;
|
int soundBufferLen;
|
||||||
|
|
||||||
|
volatile bool device_changed;
|
||||||
|
|
||||||
IXAudio2 *xaud;
|
IXAudio2 *xaud;
|
||||||
IXAudio2MasteringVoice *mVoice; // listener
|
IXAudio2MasteringVoice *mVoice; // listener
|
||||||
IXAudio2SourceVoice *sVoice; // sound source
|
IXAudio2SourceVoice *sVoice; // sound source
|
||||||
|
@ -99,16 +222,25 @@ XAudio2_Output::XAudio2_Output()
|
||||||
bufferCount = gopts.audio_buffers;
|
bufferCount = gopts.audio_buffers;
|
||||||
buffers = NULL;
|
buffers = NULL;
|
||||||
currentBuffer = 0;
|
currentBuffer = 0;
|
||||||
|
device_changed = false;
|
||||||
|
|
||||||
xaud = NULL;
|
xaud = NULL;
|
||||||
mVoice = NULL;
|
mVoice = NULL;
|
||||||
sVoice = NULL;
|
sVoice = NULL;
|
||||||
ZeroMemory( &buf, sizeof( buf ) );
|
ZeroMemory( &buf, sizeof( buf ) );
|
||||||
ZeroMemory( &vState, sizeof( vState ) );
|
ZeroMemory( &vState, sizeof( vState ) );
|
||||||
|
|
||||||
|
g_notifier.do_register( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
XAudio2_Output::~XAudio2_Output()
|
XAudio2_Output::~XAudio2_Output()
|
||||||
|
{
|
||||||
|
g_notifier.do_unregister( this );
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void XAudio2_Output::close()
|
||||||
{
|
{
|
||||||
initialized = false;
|
initialized = false;
|
||||||
|
|
||||||
|
@ -118,6 +250,7 @@ XAudio2_Output::~XAudio2_Output()
|
||||||
assert( hr == S_OK );
|
assert( hr == S_OK );
|
||||||
}
|
}
|
||||||
sVoice->DestroyVoice();
|
sVoice->DestroyVoice();
|
||||||
|
sVoice = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( buffers ) {
|
if( buffers ) {
|
||||||
|
@ -127,6 +260,7 @@ XAudio2_Output::~XAudio2_Output()
|
||||||
|
|
||||||
if( mVoice ) {
|
if( mVoice ) {
|
||||||
mVoice->DestroyVoice();
|
mVoice->DestroyVoice();
|
||||||
|
mVoice = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( xaud ) {
|
if( xaud ) {
|
||||||
|
@ -135,6 +269,11 @@ XAudio2_Output::~XAudio2_Output()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void XAudio2_Output::device_change()
|
||||||
|
{
|
||||||
|
device_changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int XA2GetDev(IXAudio2 *);
|
static int XA2GetDev(IXAudio2 *);
|
||||||
|
|
||||||
|
@ -277,6 +416,8 @@ bool XAudio2_Output::init(long sampleRate)
|
||||||
assert( hr == S_OK );
|
assert( hr == S_OK );
|
||||||
playing = true;
|
playing = true;
|
||||||
|
|
||||||
|
currentBuffer = 0;
|
||||||
|
device_changed = false;
|
||||||
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
return true;
|
return true;
|
||||||
|
@ -288,6 +429,11 @@ void XAudio2_Output::write(u16 * finalWave, int length)
|
||||||
if( !initialized || failed ) return;
|
if( !initialized || failed ) return;
|
||||||
|
|
||||||
while( true ) {
|
while( true ) {
|
||||||
|
if ( device_changed ) {
|
||||||
|
close();
|
||||||
|
if (!init(freq)) return;
|
||||||
|
}
|
||||||
|
|
||||||
sVoice->GetState( &vState );
|
sVoice->GetState( &vState );
|
||||||
|
|
||||||
assert( vState.BuffersQueued <= bufferCount );
|
assert( vState.BuffersQueued <= bufferCount );
|
||||||
|
@ -306,7 +452,9 @@ void XAudio2_Output::write(u16 * finalWave, int length)
|
||||||
// the maximum number of buffers is currently queued
|
// the maximum number of buffers is currently queued
|
||||||
if( synchronize && !speedup && !gopts.throttle ) {
|
if( synchronize && !speedup && !gopts.throttle ) {
|
||||||
// wait for one buffer to finish playing
|
// wait for one buffer to finish playing
|
||||||
WaitForSingleObject( notify.hBufferEndEvent, INFINITE );
|
if (WaitForSingleObject( notify.hBufferEndEvent, 10000 ) == WAIT_TIMEOUT) {
|
||||||
|
device_changed = true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// drop current audio frame
|
// drop current audio frame
|
||||||
return;
|
return;
|
||||||
|
@ -376,6 +524,11 @@ void XAudio2_Output::setThrottle( unsigned short throttle )
|
||||||
assert( hr == S_OK );
|
assert( hr == S_OK );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void xaudio2_device_changed( XAudio2_Output * instance )
|
||||||
|
{
|
||||||
|
instance->device_change();
|
||||||
|
}
|
||||||
|
|
||||||
SoundDriver *newXAudio2_Output()
|
SoundDriver *newXAudio2_Output()
|
||||||
{
|
{
|
||||||
return new XAudio2_Output();
|
return new XAudio2_Output();
|
||||||
|
|
Loading…
Reference in New Issue