Skip to content

Commit

Permalink
[engine] Make XAudio2 default audio engine on Windows
Browse files Browse the repository at this point in the history
DirectSound8 is obsolete and preserved for backward compatibility.
  • Loading branch information
dimhotepus committed Oct 9, 2024
1 parent 1f7e4b8 commit b4834cd
Show file tree
Hide file tree
Showing 8 changed files with 1,414 additions and 1,152 deletions.
587 changes: 314 additions & 273 deletions engine/audio/private/snd_dev_direct.cpp

Large diffs are not rendered by default.

1,757 changes: 969 additions & 788 deletions engine/audio/private/snd_dev_xaudio.cpp

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion engine/audio/private/snd_dev_xaudio.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ class CXboxVoice
};

CXboxVoice *Audio_GetXVoice( void );
IXAudio2 *Audio_GetXAudio2( void );

#endif

Expand Down
2 changes: 1 addition & 1 deletion engine/audio/private/snd_dma.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ typedef struct

static soundfade_t soundfade; // Client sound fading singleton object

// 0)headphones 2)stereo speakers 4)quad 5)5point1
// 0)headphones 2)stereo speakers 4)quad 5)5point1 7)7point1
// autodetected from windows settings
ConVar snd_surround( "snd_surround_speakers", "-1", FCVAR_INTERNAL_USE );
ConVar snd_legacy_surround( "snd_legacy_surround", "0", FCVAR_ARCHIVE );
Expand Down
4 changes: 2 additions & 2 deletions engine/audio/private/snd_wave_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ extern double realtime;
#define TF_XBOX_WAV_MEMORY_CACHE ( 24 * 1024 * 1024 ) // Team Fortress uses a larger cache

// Dev builds will be missing soundcaches and hitch sometimes, we only care if its being properly launched from steam where sound caches should be complete.
ConVar snd_async_spew_blocking( "snd_async_spew_blocking", "1", 0, "Spew message to console any time async sound loading blocks on file i/o. ( 0=Off, 1=With -steam only, 2=Always" );
ConVar snd_async_spew_blocking( "snd_async_spew_blocking", "1", 0, "Spew message to console any time async sound loading blocks on file I/O. (0=Off, 1=With -steam only, 2=Always)" );
ConVar snd_async_spew( "snd_async_spew", "0", 0, "Spew all async sound reads, including success" );
ConVar snd_async_fullyasync( "snd_async_fullyasync", "0", 0, "All playback is fully async (sound doesn't play until data arrives)." );
ConVar snd_async_stream_spew( "snd_async_stream_spew", "0", 0, "Spew streaming info ( 0=Off, 1=streams, 2=buffers" );
ConVar snd_async_stream_spew( "snd_async_stream_spew", "0", 0, "Spew streaming info (0=Off, 1=streams, 2=buffers)" );

static bool SndAsyncSpewBlocking()
{
Expand Down
196 changes: 111 additions & 85 deletions engine/audio/private/snd_win.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=====================================================================================//
// Purpose: Sound device dispatch and initialization.

#include "audio_pch.h"

Expand All @@ -17,135 +15,164 @@ ConVar snd_audioqueue( "snd_audioqueue", "1" );

#endif

#include "snd_dev_xaudio.h"

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

// dimhotepus: Allow to override sound device.
ConVar snd_device_override( "snd_device_override", "0", FCVAR_ARCHIVE,
"Allow to override used sound device.\nPossible values:\n"
"0\tAutodetection\n"
#ifdef PLATFORM_WINDOWS
"1\tXAudio 2 [default]\n"
"2\tDirect Sound 8\n",
#elif defined(OSX)
"1\tMac Audio Queue [default]\n"
"2\tOpen AL\n",
#elif defined(USE_SDL)
"1\tSDL [default]",
#endif
true,
0,
true,
#if defined(PLATFORM_WINDOWS)
2
#elif defined(OSX)
2
#elif defined(USE_SDL)
1
#endif
);

/**
* @brief Audio device kind.
*/
enum class AudioDeviceKind {
/**
* @brief Autodetect.
*/
kAutodetect = 0
#ifdef PLATFORM_WINDOWS
, kXAudio2 = 1
, kDirectSound8 = 2
#elif defined(OSX)
, kMacAudioQueue = 1
, kOpenAL = 2
#elif defined(USE_SDL)
, kSDL = 2
#endif
};

bool snd_firsttime = true;

/*
* Global variables. Must be visible to window-procedure function
* so it can unlock and free the data block after it has been played.
*/
IAudioDevice *g_AudioDevice = NULL;

/*
==================
S_BlockSound
==================
*/
void S_BlockSound( void )
IAudioDevice *g_AudioDevice = nullptr;

void S_BlockSound()
{
if ( !g_AudioDevice )
return;

g_AudioDevice->Pause();
}

/*
==================
S_UnblockSound
==================
*/
void S_UnblockSound( void )
void S_UnblockSound()
{
if ( !g_AudioDevice )
return;

g_AudioDevice->UnPause();
}

/*
==================
AutoDetectInit
Try to find a sound device to mix for.
Returns a CAudioNULLDevice if nothing is found.
==================
*/
/**
* @brief Autodetect and find sound device to mix on.
* @param Unused.
* @return Audio device to mix on. Null device when no sound.
*/
IAudioDevice *IAudioDevice::AutoDetectInit()
{
IAudioDevice *pDevice = NULL;
IAudioDevice *pDevice = nullptr;

if ( IsPC() )
{
#if defined( WIN32 ) && !defined( USE_SDL )
if ( snd_firsttime )
{
pDevice = Audio_CreateDirectSoundDevice();
if ( snd_firsttime )
{
const auto device_override =
static_cast<AudioDeviceKind>(snd_device_override.GetInt());

switch (device_override) {
default:
Warning( "Unknown 'snd_device_override' con var value %d. Using autodetection.\n",
to_underlying(device_override) );
[[fallthrough]];

case AudioDeviceKind::kAutodetect:
case AudioDeviceKind::kXAudio2:
{
pDevice = Audio_CreateXAudioDevice();
if ( pDevice )
{
// XAudio2 requires threaded mixing.
S_EnableThreadedMixing( true );
}
}
break;

case AudioDeviceKind::kDirectSound8:
pDevice = Audio_CreateDirectSoundDevice();
break;
}
}
#elif defined(OSX)
if ( !CommandLine()->CheckParm( "-snd_openal" ) )
{
DevMsg( "Using AudioQueue Interface\n" );
const auto device_override =
static_cast<AudioDeviceKind>(snd_device_override.GetInt());

switch (device_override) {
default:
Warning( "Unknown 'snd_device_override' con var value %d. Using autodetection.\n",
to_underlying(device_override) );
[[fallthrough]];

case AudioDeviceKind::kAutodetect:
case AudioDeviceKind::kMacAudioQueue:
pDevice = Audio_CreateMacAudioQueueDevice();
}
if ( !pDevice )
{
DevMsg( "Using OpenAL Interface\n" );
pDevice = Audio_CreateOpenALDevice(); // fall back to openAL if the audio queue fails
}
#elif defined( USE_SDL )
DevMsg( "Trying SDL Audio Interface\n" );
pDevice = Audio_CreateSDLAudioDevice();

#ifdef NEVER
// Jul 2012. mikesart. E-mail exchange with Ryan Gordon after figuring out that
// Audio_CreatePulseAudioDevice() wasn't working on Ubuntu 12.04 (lots of stuttering).
//
// > I installed libpulse-dev, rebuilt SDL, and now SDL is using pulse
// > audio and everything is working great. However I'm wondering if we
// > need to fall back to PulseAudio in our codebase if SDL is doing that
// > for us. I mean, is it worth me going through and debugging our Pulse
// > Audio path or should I just remove it?
//
// Remove it...it never worked well, and only remained in case there were
// concerns about relying on SDL. The SDL codepath is way easier to read,
// simpler to maintain, and handles all sorts of strange audio backends,
// including Pulse.
if ( !pDevice )
{
DevMsg( "Trying PulseAudio Interface\n" );
pDevice = Audio_CreatePulseAudioDevice(); // fall back to PulseAudio if SDL fails
}
#endif // NEVER
break;

#else
#error "Please define your platform"
#endif
case AudioDeviceKind::kOpenAL:
pDevice = Audio_CreateOpenALDevice();
break;
}
#if defined( _X360 )
else

if ( !pDevice )
{
pDevice = Audio_CreateXAudioDevice( true );
if ( pDevice )
{
// xaudio requires threaded mixing
S_EnableThreadedMixing( true );
}
// fall back to openAL if the audio queue fails
DevMsg( "Using OpenAL Interface\n" );
pDevice = Audio_CreateOpenALDevice();
}
#elif defined( USE_SDL )
DevMsg( "Trying SDL Audio Interface\n" );
pDevice = Audio_CreateSDLAudioDevice();
#else
#error "Please define your platform"
#endif

snd_firsttime = false;

if ( !pDevice )
{
if ( snd_firsttime )
DevMsg( "No sound device initialized\n" );
DevMsg( "No sound device initialized.\n" );

return Audio_GetNullDevice();
}

return pDevice;
}

/*
==============
SNDDMA_Shutdown
Reset the sound device for exiting
===============
*/
void SNDDMA_Shutdown( void )
void SNDDMA_Shutdown()
{
if ( g_AudioDevice != Audio_GetNullDevice() )
{
Expand All @@ -159,4 +186,3 @@ void SNDDMA_Shutdown( void )
g_AudioDevice = Audio_GetNullDevice();
}
}

3 changes: 1 addition & 2 deletions engine/engine.vpc
Original file line number Diff line number Diff line change
Expand Up @@ -520,8 +520,7 @@ $Project "engine"
}
}

// X360 only audio files
$File "audio\private\snd_dev_xaudio.cpp" [$X360] \
$File "audio\private\snd_dev_xaudio.cpp" \
"audio\private\snd_wave_mixer_xma.cpp" [$X360]
{
$Configuration
Expand Down
16 changes: 16 additions & 0 deletions engine/sys_mainwind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,22 @@ LRESULT CGame::WindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

case WM_ACTIVATEAPP:
{
// dimhotepus: Unify way to handle sound mute on focus lost.
ConVarRef snd_mute_losefocus("snd_mute_losefocus");
if (snd_mute_losefocus.GetBool())
{
if ( wParam == 1 )
{
S_UnblockSound();
}
else
{
S_BlockSound();
// dimhotepus: Need to be thread-safe.
// S_ClearBuffer();
}
}

if ( CanPostActivateEvents() )
{
bool bActivated = ( wParam == 1 );
Expand Down

0 comments on commit b4834cd

Please sign in to comment.