initial
This commit is contained in:
319
soundsystem/lowlevel/device_null.cpp
Normal file
319
soundsystem/lowlevel/device_null.cpp
Normal file
@@ -0,0 +1,319 @@
|
||||
#include "basetypes.h"
|
||||
#include "commonmacros.h"
|
||||
#include "soundsystem/lowlevel.h"
|
||||
#include "soundsystem/audio_mix.h"
|
||||
|
||||
CInterlockedInt g_nDetectedAudioError(0);
|
||||
CInterlockedInt g_nDetectedBufferStarvation( 0 );
|
||||
uint g_nDeviceStamp = 0x100;
|
||||
|
||||
class CAudioDeviceNull2 : public IAudioDevice2
|
||||
{
|
||||
public:
|
||||
CAudioDeviceNull2()
|
||||
{
|
||||
m_pName = "Sound Disabled";
|
||||
m_nChannels = 2;
|
||||
m_nSampleBits = 16;
|
||||
m_nSampleRate = int(MIX_DEFAULT_SAMPLING_RATE);
|
||||
m_bIsActive = false;
|
||||
m_bIsHeadphone = false;
|
||||
m_bSupportsBufferStarvationDetection = false;
|
||||
m_bIsCaptureDevice = false;
|
||||
}
|
||||
|
||||
virtual ~CAudioDeviceNull2() {}
|
||||
virtual void OutputBuffer( int nChannels, CAudioMixBuffer *pChannelArray ) {}
|
||||
virtual void Shutdown() {}
|
||||
virtual int QueuedBufferCount() { return 0; }
|
||||
virtual int EmptyBufferCount() { return 0; }
|
||||
virtual void CancelOutput() {}
|
||||
virtual void WaitForComplete() {}
|
||||
virtual void UpdateFocus( bool bWindowHasFocus ) {}
|
||||
virtual void ClearBuffer() {}
|
||||
virtual const wchar_t *GetDeviceID() const
|
||||
{
|
||||
static wchar_t deviceID[4] = {0};
|
||||
return deviceID;
|
||||
}
|
||||
virtual void OutputDebugInfo() const
|
||||
{
|
||||
Msg( "Sound Disabled.\n" );
|
||||
}
|
||||
virtual bool SetShouldPlayWhenNotInFocus( bool bPlayEvenWhenNotInFocus ) OVERRIDE
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
IAudioDevice2 *Audio_CreateNullDevice()
|
||||
{
|
||||
return new CAudioDeviceNull2;
|
||||
}
|
||||
|
||||
int Audio_EnumerateDevices( eSubSystems_t nSubsystem, audio_device_description_t *pDeviceListOut, int nListCount )
|
||||
{
|
||||
int nDeviceCount = 0;
|
||||
switch( nSubsystem )
|
||||
{
|
||||
#ifdef IS_WINDOWS_PC
|
||||
case AUDIO_SUBSYSTEM_XAUDIO:
|
||||
nDeviceCount = Audio_EnumerateXAudio2Devices( pDeviceListOut, nListCount );
|
||||
break;
|
||||
case AUDIO_SUBSYSTEM_DSOUND:
|
||||
nDeviceCount = Audio_EnumerateDSoundDevices( pDeviceListOut, nListCount );
|
||||
break;
|
||||
#endif
|
||||
#ifdef POSIX
|
||||
case AUDIO_SUBSYSTEM_SDL:
|
||||
nDeviceCount = Audio_EnumerateSDLDevices( pDeviceListOut, nListCount );
|
||||
break;
|
||||
#endif
|
||||
case AUDIO_SUBSYSTEM_NULL:
|
||||
nDeviceCount = 1;
|
||||
if ( nListCount > 0 )
|
||||
{
|
||||
pDeviceListOut[0].InitAsNullDevice();
|
||||
V_strcpy_safe( pDeviceListOut[0].m_friendlyName, "Sound Disabled" );
|
||||
}
|
||||
break;
|
||||
}
|
||||
return nDeviceCount;
|
||||
}
|
||||
|
||||
int CAudioDeviceList::FindDeviceById( const wchar_t *pId, finddevice_t nFind )
|
||||
{
|
||||
for ( int i = 0; i < m_list.Count(); i++ )
|
||||
{
|
||||
if ( nFind == FIND_AVAILABLE_DEVICE_ONLY && !m_list[i].m_bIsAvailable )
|
||||
continue;
|
||||
if ( !V_wcscmp( pId, m_list[i].m_deviceName ) )
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
audio_device_description_t *CAudioDeviceList::FindDeviceById( const char *pId )
|
||||
{
|
||||
wchar_t tempName[256];
|
||||
V_strtowcs( pId, -1, tempName, Q_ARRAYSIZE(tempName) );
|
||||
int nDevice = FindDeviceById( tempName, FIND_AVAILABLE_DEVICE_ONLY );
|
||||
if ( nDevice >= 0 && nDevice < m_list.Count() )
|
||||
return &m_list[nDevice];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void CAudioDeviceList::BuildDeviceList( eSubSystems_t nPreferredSubsystem )
|
||||
{
|
||||
m_nDeviceStamp = g_nDeviceStamp;
|
||||
audio_device_description_t initList[32];
|
||||
int nCount = Audio_EnumerateDevices( nPreferredSubsystem, initList, Q_ARRAYSIZE(initList) );
|
||||
|
||||
// No XAudio2? Fall back to direct sound.
|
||||
if ( nCount == 0 && nPreferredSubsystem == AUDIO_SUBSYSTEM_XAUDIO )
|
||||
{
|
||||
nPreferredSubsystem = AUDIO_SUBSYSTEM_DSOUND;
|
||||
nCount = Audio_EnumerateDevices( nPreferredSubsystem, initList, Q_ARRAYSIZE(initList) );
|
||||
}
|
||||
|
||||
m_nSubsystem = nPreferredSubsystem;
|
||||
// No sound devices? Add a NULL device.
|
||||
if ( nCount == 0 )
|
||||
{
|
||||
nCount = Audio_EnumerateDevices( AUDIO_SUBSYSTEM_NULL, initList, Q_ARRAYSIZE(initList) );
|
||||
}
|
||||
if ( !m_list.Count() )
|
||||
{
|
||||
m_list.CopyArray( initList, nCount );
|
||||
for ( int i = 0; i < m_list.Count(); i++ )
|
||||
{
|
||||
m_list[i].m_bIsAvailable = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( int i = 0; i < m_list.Count(); i++ )
|
||||
{
|
||||
m_list[i].m_bIsAvailable = false;
|
||||
m_list[i].m_bIsDefault = false;
|
||||
}
|
||||
for ( int i = 0; i < nCount; i++ )
|
||||
{
|
||||
int nIndex = FindDeviceById( initList[i].m_deviceName, FIND_ANY_DEVICE );
|
||||
if ( nIndex >= 0 )
|
||||
{
|
||||
m_list[nIndex] = initList[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
m_list.AddToTail( initList[i] );
|
||||
}
|
||||
}
|
||||
}
|
||||
UpdateDefaultDevice();
|
||||
}
|
||||
|
||||
bool CAudioDeviceList::UpdateDeviceList()
|
||||
{
|
||||
if ( m_nDeviceStamp == g_nDeviceStamp )
|
||||
return false;
|
||||
|
||||
BuildDeviceList( m_nSubsystem );
|
||||
return true;
|
||||
}
|
||||
|
||||
void CAudioDeviceList::UpdateDefaultDevice()
|
||||
{
|
||||
#if IS_WINDOWS_PC
|
||||
// BUG: DirectSound devices use a different string format for GUIDs. Fix so this works?
|
||||
wchar_t deviceName[256];
|
||||
if ( GetWindowsDefaultAudioDevice( deviceName, sizeof(deviceName ) ) )
|
||||
{
|
||||
int nIndex = FindDeviceById( deviceName, FIND_AVAILABLE_DEVICE_ONLY );
|
||||
if ( nIndex >= 0 )
|
||||
{
|
||||
m_nDefaultDevice = nIndex;
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
m_nDefaultDevice = -1;
|
||||
int nFirst = -1;
|
||||
for ( int i = 0; i < m_list.Count(); i++ )
|
||||
{
|
||||
if ( m_list[i].m_bIsAvailable )
|
||||
{
|
||||
if ( nFirst < 0 )
|
||||
{
|
||||
nFirst = i;
|
||||
}
|
||||
if ( m_list[i].m_bIsDefault )
|
||||
{
|
||||
m_nDefaultDevice = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( m_nDefaultDevice < 0 )
|
||||
{
|
||||
m_nDefaultDevice = nFirst;
|
||||
}
|
||||
}
|
||||
|
||||
IAudioDevice2 *CAudioDeviceList::CreateDevice( audio_device_init_params_t ¶ms )
|
||||
{
|
||||
Assert( IsValid() );
|
||||
int nSubsystem = m_nSubsystem;
|
||||
|
||||
#if !defined( _GAMECONSOLE )
|
||||
if ( params.m_bOverrideDevice )
|
||||
{
|
||||
nSubsystem = params.m_nOverrideSubsystem;
|
||||
}
|
||||
#endif
|
||||
#if IS_WINDOWS_PC
|
||||
// try xaudio2
|
||||
if ( nSubsystem == AUDIO_SUBSYSTEM_XAUDIO )
|
||||
{
|
||||
IAudioDevice2 *pDevice = Audio_CreateXAudio2Device( params );
|
||||
if ( pDevice )
|
||||
return pDevice;
|
||||
Warning("Failed to initialize XAudio2 device!\n");
|
||||
nSubsystem = AUDIO_SUBSYSTEM_DSOUND;
|
||||
}
|
||||
|
||||
if ( nSubsystem == AUDIO_SUBSYSTEM_DSOUND )
|
||||
{
|
||||
// either we were asked for dsound or we failed to create xaudio2, try dsound
|
||||
IAudioDevice2 *pDevice = Audio_CreateDSoundDevice( params );
|
||||
if ( pDevice )
|
||||
return pDevice;
|
||||
Warning("Failed to initialize DirectSound device!\n");
|
||||
nSubsystem = AUDIO_SUBSYSTEM_NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef POSIX
|
||||
nSubsystem = AUDIO_SUBSYSTEM_SDL;
|
||||
|
||||
if ( nSubsystem == AUDIO_SUBSYSTEM_SDL )
|
||||
{
|
||||
IAudioDevice2 *pDevice = Audio_CreateSDLDevice( params );
|
||||
if ( pDevice )
|
||||
return pDevice;
|
||||
|
||||
Warning("Failed to initialize SDL device!\n");
|
||||
nSubsystem = AUDIO_SUBSYSTEM_NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
// failed
|
||||
return Audio_CreateNullDevice();
|
||||
}
|
||||
|
||||
const wchar_t *CAudioDeviceList::GetDeviceToCreate( audio_device_init_params_t ¶ms )
|
||||
{
|
||||
if ( params.m_bOverrideDevice )
|
||||
{
|
||||
int nIndex = FindDeviceById( params.m_overrideDeviceName, FIND_AVAILABLE_DEVICE_ONLY );
|
||||
if ( nIndex >= 0 )
|
||||
{
|
||||
return m_list[nIndex].m_deviceName;
|
||||
}
|
||||
}
|
||||
Assert( m_nDefaultDevice >= 0 && m_nDefaultDevice < m_list.Count() );
|
||||
return m_list[m_nDefaultDevice].m_deviceName;
|
||||
}
|
||||
|
||||
|
||||
int SpeakerConfigValueToChannelCount( int nSpeakerConfig )
|
||||
{
|
||||
// headphone or stereo
|
||||
switch( nSpeakerConfig )
|
||||
{
|
||||
case -1:
|
||||
return 0;
|
||||
case 0: // headphone
|
||||
case 2: // stereo
|
||||
return 2;
|
||||
case 4: // quad surround
|
||||
return 4;
|
||||
|
||||
case 5: // 5.1 surround
|
||||
return 6;
|
||||
|
||||
case 7: // 7.1 surround
|
||||
return 8;
|
||||
}
|
||||
|
||||
// doesn't map to anything, return stereo
|
||||
AssertMsg( 0, "Bad speaker config requested\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
int ChannelCountToSpeakerConfigValue( int nChannelCount, bool bIsHeadphone )
|
||||
{
|
||||
switch( nChannelCount )
|
||||
{
|
||||
case 2:
|
||||
return bIsHeadphone ? 0 : 2;
|
||||
case 4:
|
||||
return 4;
|
||||
case 6:
|
||||
return 5;
|
||||
case 8:
|
||||
return 7;
|
||||
}
|
||||
AssertMsg(0, "Bad channel count\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
bool Audio_PollErrorEvents()
|
||||
{
|
||||
int nError = g_nDetectedAudioError.InterlockedExchange(0);
|
||||
|
||||
return nError != 0;
|
||||
}
|
||||
Reference in New Issue
Block a user