diff --git a/src/core/libraries/audio/openal_audio_out.cpp b/src/core/libraries/audio/openal_audio_out.cpp index d472e786d..a28a3f67d 100644 --- a/src/core/libraries/audio/openal_audio_out.cpp +++ b/src/core/libraries/audio/openal_audio_out.cpp @@ -191,8 +191,15 @@ public: private: bool Initialize(OrbisAudioOutPort type) { - if (!OpenALDevice::GetInstance().IsInitialized()) { - LOG_ERROR(Lib_AudioOut, "OpenAL device not initialized"); + const std::string device_name = GetDeviceName(type); + + if (!OpenALDevice::GetInstance().SelectDevice(device_name)) { + if (device_name == "None") { + LOG_INFO(Lib_AudioOut, "Audio device disabled for port type {}", + static_cast(type)); + } else { + LOG_ERROR(Lib_AudioOut, "Failed to open OpenAL device '{}'", device_name); + } return false; } @@ -268,6 +275,18 @@ private: return true; } + std::string GetDeviceName(OrbisAudioOutPort type) const { + switch (type) { + case OrbisAudioOutPort::Main: + case OrbisAudioOutPort::Bgm: + return Config::getMainOutputDevice(); + case OrbisAudioOutPort::PadSpk: + return Config::getPadSpkOutputDevice(); + default: + return Config::getMainOutputDevice(); + } + } + void Cleanup() { if (!device_context->MakeCurrent()) { return; diff --git a/src/core/libraries/audio/openal_manager.h b/src/core/libraries/audio/openal_manager.h index 4f58fca18..44af724fd 100644 --- a/src/core/libraries/audio/openal_manager.h +++ b/src/core/libraries/audio/openal_manager.h @@ -1,9 +1,9 @@ // SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later - #pragma once - #include +#include +#include #include #include @@ -17,24 +17,25 @@ public: } bool IsInitialized() const { + std::lock_guard lock(mutex); return initialized; } ALCdevice* GetDevice() const { + std::lock_guard lock(mutex); return device; } ALCcontext* GetContext() const { + std::lock_guard lock(mutex); return context; } bool MakeCurrent() { std::lock_guard lock(mutex); - if (!initialized) { return false; } - return alcMakeContextCurrent(context); } @@ -43,11 +44,57 @@ public: alcMakeContextCurrent(nullptr); } -private: - OpenALDevice() { - Initialize(); + // Select a specific audio device + bool SelectDevice(const std::string& device_name) { + std::lock_guard lock(mutex); + + // If already initialized, clean up first + if (initialized) { + CleanupInternal(); + } + + return InitializeInternal(device_name); } + // Get the name of the currently opened device + std::string GetCurrentDeviceName() const { + std::lock_guard lock(mutex); + return current_device_name; + } + + // Check if device enumeration is supported + static bool IsDeviceEnumerationSupported() { + return alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT") || + alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT"); + } + + // Get list of available devices (returns empty vector if enumeration not supported) + static std::vector GetAvailableDevices() { + std::vector devices_list; + + if (!IsDeviceEnumerationSupported()) { + return devices_list; + } + + // Get device list + const ALCchar* devices = alcGetString(nullptr, ALC_DEVICE_SPECIFIER); + if (!devices) { + return devices_list; + } + + // Parse null-separated list + const ALCchar* ptr = devices; + while (ptr && *ptr) { + devices_list.emplace_back(ptr); + ptr += strlen(ptr) + 1; + } + + return devices_list; + } + +private: + OpenALDevice() {} + ~OpenALDevice() { Cleanup(); } @@ -55,17 +102,28 @@ private: OpenALDevice(const OpenALDevice&) = delete; OpenALDevice& operator=(const OpenALDevice&) = delete; - void Initialize() { - std::lock_guard lock(mutex); - - if (initialized) { - return; + bool InitializeInternal(const std::string& device_name) { + // Handle disabled audio + if (device_name == "None") { + initialized = false; + return false; + } + + // Open the requested device + if (device_name.empty() || device_name == "Default Device") { + device = alcOpenDevice(nullptr); // Default device + } else { + // Try to open specific device + device = alcOpenDevice(device_name.c_str()); + + if (!device) { + // Device not found, fall back to default + device = alcOpenDevice(nullptr); + } } - // Open default device - device = alcOpenDevice(nullptr); if (!device) { - return; + return false; } // Create context @@ -73,20 +131,28 @@ private: if (!context) { alcCloseDevice(device); device = nullptr; - return; + return false; } + // Get actual device name + const ALCchar* actual_name = alcGetString(device, ALC_DEVICE_SPECIFIER); + current_device_name = actual_name ? actual_name : "Unknown"; + initialized = true; + return true; } void Cleanup() { std::lock_guard lock(mutex); + CleanupInternal(); + } + void CleanupInternal() { if (!initialized) { return; } - ReleaseContext(); + alcMakeContextCurrent(nullptr); if (context) { alcDestroyContext(context); @@ -98,12 +164,14 @@ private: device = nullptr; } + current_device_name.clear(); initialized = false; } ALCdevice* device{nullptr}; ALCcontext* context{nullptr}; bool initialized{false}; + std::string current_device_name; mutable std::mutex mutex; };