mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-17 23:39:18 +02:00
feat: follow audio output device changes (reopen on disconnect)
OpenAL does not re-route on its own, so unplugging the active output device (e.g. headphones) mid-game left the sim silent until restart. Poll ALC_CONNECTED (ALC_EXT_disconnect) at ~1 Hz and, when the device is lost, reopen playback on the current default output via alcReopenDeviceSOFT, preserving the context and all sources. Tokens are declared locally since the bundled AL headers ship no alext.h; the entry point is resolved at runtime, so this is a no-op (with a log warning) on OpenAL Soft builds too old to provide ALC_SOFT_reopen_device.
This commit is contained in:
@@ -17,6 +17,12 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "simulation/simulation.h"
|
||||
#include "vehicle/Train.h"
|
||||
|
||||
// ALC_EXT_disconnect / ALC_SOFT_reopen_device tokens; the bundled AL headers ship no alext.h,
|
||||
// but OpenAL Soft provides these at runtime (resolved via alcGetProcAddress).
|
||||
#ifndef ALC_CONNECTED
|
||||
#define ALC_CONNECTED 0x313
|
||||
#endif
|
||||
|
||||
namespace audio {
|
||||
|
||||
openal_renderer renderer;
|
||||
@@ -363,6 +369,32 @@ openal_renderer::update( double const Deltatime ) {
|
||||
if (alcDeviceResumeSOFT)
|
||||
alcDeviceResumeSOFT(m_device);
|
||||
|
||||
// follow audio output device changes (OpenAL won't on its own): if the active device is
|
||||
// gone (e.g. headphones unplugged) reopen playback on the current default output. Polled at
|
||||
// ~1 Hz to avoid per-frame ALC round-trips.
|
||||
if( m_candetectdisconnect ) {
|
||||
m_devicechecktime += Deltatime;
|
||||
if( m_devicechecktime >= 1.0 ) {
|
||||
m_devicechecktime = 0.0;
|
||||
ALCint connected{ ALC_TRUE };
|
||||
::alcGetIntegerv( m_device, ALC_CONNECTED, 1, &connected );
|
||||
if( connected == ALC_FALSE ) {
|
||||
if( alcReopenDeviceSOFT != nullptr ) {
|
||||
// NULL device name selects the current default output; context and sources are preserved
|
||||
if( alcReopenDeviceSOFT( m_device, nullptr, m_contextattributes ) == ALC_TRUE ) {
|
||||
WriteLog( "sound: active audio device lost, reopened on the current default output" );
|
||||
}
|
||||
else {
|
||||
ErrorLog( "sound: active audio device lost, reopening on the default output failed (retrying)" );
|
||||
}
|
||||
}
|
||||
else {
|
||||
ErrorLog( "sound: active audio device lost and ALC_SOFT_reopen_device is unavailable; cannot recover" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update listener
|
||||
// gain
|
||||
::alListenerf( AL_GAIN, Global.AudioVolume );
|
||||
@@ -544,6 +576,7 @@ openal_renderer::init_caps() {
|
||||
WriteLog( "Supported extensions: " + std::string{ (char *)::alcGetString( m_device, ALC_EXTENSIONS ) } );
|
||||
|
||||
ALCint attr[3] = { ALC_MONO_SOURCES, Global.audio_max_sources, 0 }; // request more sounds
|
||||
std::copy( std::begin( attr ), std::end( attr ), std::begin( m_contextattributes ) ); // cached for device reopen
|
||||
|
||||
m_context = ::alcCreateContext( m_device, attr );
|
||||
if( m_context == nullptr ) {
|
||||
@@ -573,6 +606,12 @@ openal_renderer::init_caps() {
|
||||
if (!alcDevicePauseSOFT || !alcDeviceResumeSOFT)
|
||||
WriteLog("sound: warning: extension ALC_SOFT_pause_device not found");
|
||||
|
||||
m_candetectdisconnect = ( alcIsExtensionPresent( m_device, "ALC_EXT_disconnect" ) == ALC_TRUE );
|
||||
if( alcIsExtensionPresent( m_device, "ALC_SOFT_reopen_device" ) == ALC_TRUE )
|
||||
alcReopenDeviceSOFT = (ALCboolean(*)(ALCdevice*, ALCchar const*, ALCint const*))alcGetProcAddress( m_device, "alcReopenDeviceSOFT" );
|
||||
if( !alcReopenDeviceSOFT )
|
||||
WriteLog( "sound: warning: extension ALC_SOFT_reopen_device not found; audio output device changes won't be followed" );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -176,6 +176,12 @@ private:
|
||||
void (*alProcessUpdatesSOFT)() = nullptr;
|
||||
void (*alcDevicePauseSOFT)(ALCdevice*) = nullptr;
|
||||
void (*alcDeviceResumeSOFT)(ALCdevice*) = nullptr;
|
||||
// ALC_SOFT_reopen_device: move playback to the current default output when the active
|
||||
// device disappears (e.g. headphones unplugged mid-game), keeping context and sources
|
||||
ALCboolean (*alcReopenDeviceSOFT)(ALCdevice*, ALCchar const*, ALCint const*) = nullptr;
|
||||
bool m_candetectdisconnect{ false }; // ALC_EXT_disconnect present, ALC_CONNECTED is queryable
|
||||
ALCint m_contextattributes[3]{ 0, 0, 0 }; // cached context attribs, reused when reopening the device
|
||||
double m_devicechecktime{ 0.0 }; // accumulates dt to throttle the ALC_CONNECTED poll to ~1 Hz
|
||||
};
|
||||
|
||||
extern openal_renderer renderer;
|
||||
|
||||
Reference in New Issue
Block a user