mirror of
https://github.com/SysRay/psOff_public.git
synced 2024-11-27 00:20:54 +00:00
Audio device reconnection handler
This commit is contained in:
parent
7df783272d
commit
8feac0644a
@ -163,6 +163,51 @@ std::string getTitle(int handle, uint64_t frame, size_t fps, FlipRate maxFPS) {
|
||||
|
||||
} // namespace
|
||||
|
||||
class EventSDL {
|
||||
struct SDLEvent {
|
||||
uint32_t type;
|
||||
SDLEventFunc func;
|
||||
void* userData;
|
||||
};
|
||||
|
||||
std::vector<SDLEvent> m_events = {};
|
||||
|
||||
public:
|
||||
void addListener(uint32_t type, SDLEventFunc func, void* userData) { m_events.push_back({type, func, userData}); }
|
||||
|
||||
bool removeListener(uint32_t type, SDLEventFunc func) {
|
||||
for (auto it = m_events.begin(); it != m_events.end(); ++it) {
|
||||
if (it->type == type && it->func == func) {
|
||||
m_events.erase(it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool removeListener(SDLEventFunc func) {
|
||||
bool removed = false;
|
||||
|
||||
for (auto it = m_events.begin(); it != m_events.end();) {
|
||||
if (it->func == func) {
|
||||
it = m_events.erase(it);
|
||||
continue;
|
||||
}
|
||||
|
||||
++it;
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
void call(SDL_Event* event) {
|
||||
for (auto& handler: m_events) {
|
||||
if (event->type == handler.type) handler.func(event, handler.userData);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class VideoOut: public IVideoOut, private IEventsGraphics {
|
||||
std::array<Context, WindowsMAX> m_windows;
|
||||
|
||||
@ -184,8 +229,16 @@ class VideoOut: public IVideoOut, private IEventsGraphics {
|
||||
|
||||
std::queue<Message> m_messages;
|
||||
|
||||
EventSDL m_sdlEvents;
|
||||
|
||||
uint64_t m_vblankTime = (uint64_t)(1e6 / 59.0); // in us
|
||||
|
||||
void SDLEventReg(uint32_t type, SDLEventFunc func, void* userData) { m_sdlEvents.addListener(type, func, userData); }
|
||||
|
||||
bool SDLEventUnreg(uint32_t type, SDLEventFunc func) { return m_sdlEvents.removeListener(type, func); }
|
||||
|
||||
bool SDLEventUnreg(SDLEventFunc func) { return m_sdlEvents.removeListener(func); }
|
||||
|
||||
void vblankEnd(int handle, uint64_t curTime, uint64_t curProcTime);
|
||||
|
||||
// Callback Graphics
|
||||
@ -782,7 +835,7 @@ std::thread VideoOut::createSDLThread() {
|
||||
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS);
|
||||
|
||||
// SDL polling helper
|
||||
auto func_pollSDL = [](auto& window) {
|
||||
auto func_pollSDL = [this](auto& window) {
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
switch (event.type) {
|
||||
@ -800,6 +853,8 @@ std::thread VideoOut::createSDLThread() {
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
m_sdlEvents.call(&event);
|
||||
}
|
||||
};
|
||||
// -
|
||||
|
@ -7,12 +7,15 @@
|
||||
|
||||
namespace vulkan {
|
||||
struct SwapchainData;
|
||||
}
|
||||
} // namespace vulkan
|
||||
|
||||
constexpr int VIDEO_OUT_EVENT_FLIP = 0;
|
||||
constexpr int VIDEO_OUT_EVENT_VBLANK = 1;
|
||||
|
||||
class IGraphics;
|
||||
union SDL_Event;
|
||||
|
||||
typedef void (*SDLEventFunc)(SDL_Event*, void*);
|
||||
|
||||
class IVideoOut {
|
||||
CLASS_NO_COPY(IVideoOut);
|
||||
@ -154,6 +157,32 @@ class IVideoOut {
|
||||
*/
|
||||
virtual int SDLInit(uint32_t flags) = 0;
|
||||
|
||||
/**
|
||||
* @brief Register SDL event listener
|
||||
*
|
||||
* @param type
|
||||
* @param eventFunc
|
||||
* @return int
|
||||
*/
|
||||
virtual void SDLEventReg(uint32_t type, SDLEventFunc eventFunc, void* userData) = 0;
|
||||
|
||||
/**
|
||||
* @brief Unrgister SDL event listener by type and function pointer
|
||||
*
|
||||
* @param type
|
||||
* @param eventFunc
|
||||
* @return int
|
||||
*/
|
||||
virtual bool SDLEventUnreg(uint32_t type, SDLEventFunc eventFunc) = 0;
|
||||
|
||||
/**
|
||||
* @brief Unrgister all the SDL event listeners by function pointer
|
||||
*
|
||||
* @param eventFunc
|
||||
* @return int
|
||||
*/
|
||||
virtual bool SDLEventUnreg(SDLEventFunc eventFunc) = 0;
|
||||
|
||||
/**
|
||||
* @brief Notify a gpu visible memory range
|
||||
*
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <SDL2/SDL.h>
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <core/videoout/videoout.h>
|
||||
#include <mutex>
|
||||
|
||||
LOG_DEFINE_MODULE(libSceAudioOut);
|
||||
@ -28,6 +29,7 @@ struct PortOut {
|
||||
SDL_AudioFormat sdlFormat = AUDIO_F32;
|
||||
float volumeModifier = 0.5f;
|
||||
std::vector<uint8_t> mixedAudio;
|
||||
std::string deviceName;
|
||||
};
|
||||
|
||||
class PortsOut {
|
||||
@ -39,6 +41,65 @@ class PortsOut {
|
||||
static inline uint8_t rangeEnd(uint16_t range) { return range & 0xFF; }
|
||||
|
||||
public:
|
||||
PortsOut() {
|
||||
auto handler = [](SDL_Event* event, void* ud) {
|
||||
if (event->adevice.iscapture) return; // Ignoring capture device events
|
||||
PortsOut* self = (PortsOut*)ud;
|
||||
switch (event->type) {
|
||||
case SDL_AUDIODEVICEADDED: self->AlertConnect(event->adevice.which); break;
|
||||
|
||||
case SDL_AUDIODEVICEREMOVED: self->AlertDisconnect(event->adevice.which); break;
|
||||
}
|
||||
};
|
||||
|
||||
accessVideoOut().SDLEventReg(SDL_AUDIODEVICEADDED, handler, this);
|
||||
accessVideoOut().SDLEventReg(SDL_AUDIODEVICEREMOVED, handler, this);
|
||||
}
|
||||
|
||||
void AlertConnect(int devIndex) {
|
||||
LOG_USE_MODULE(libSceAudioOut);
|
||||
auto devName = SDL_GetAudioDeviceName(devIndex, 0);
|
||||
|
||||
for (int i = 0; i < m_ports.size(); i++) {
|
||||
auto& port = m_ports[i];
|
||||
if (!port.open || port.device != 0 || port.deviceName.length() == 0) continue;
|
||||
/**
|
||||
* SDL appends to reconnected device's name "(<number>)" string.
|
||||
* So we have to politely ignore it.
|
||||
*/
|
||||
if (port.deviceName.compare(0, std::string::npos, devName, 0, port.deviceName.length()) != 0) continue;
|
||||
|
||||
SDL_AudioSpec fmt {
|
||||
.freq = static_cast<int>(port.freq),
|
||||
.format = port.sdlFormat,
|
||||
.channels = static_cast<uint8_t>(port.channelsNum),
|
||||
.samples = static_cast<uint16_t>(port.samplesNum),
|
||||
.callback = nullptr,
|
||||
.userdata = nullptr,
|
||||
};
|
||||
|
||||
if ((port.device = SDL_OpenAudioDevice(devName, 0, &fmt, NULL, 0)) == 0) {
|
||||
LOG_ERR(L"Failed to reopen %S audio device: %S", devName, SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_INFO(L"Welcome back, %S!", devName);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void AlertDisconnect(int devIndex) {
|
||||
LOG_USE_MODULE(libSceAudioOut);
|
||||
for (int i = 0; i < m_ports.size(); i++) {
|
||||
auto& port = m_ports[i];
|
||||
if (!port.open || (port.device != devIndex)) continue;
|
||||
SDL_CloseAudioDevice(port.device);
|
||||
port.device = 0;
|
||||
LOG_ERR(L"Oh no! %S got disconnected", port.deviceName.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PortOut* GetPort(int handle) {
|
||||
if (handle < 1 || handle > m_ports.size()) return nullptr;
|
||||
auto port = &m_ports[handle - 1];
|
||||
@ -90,7 +151,8 @@ struct Pimpl {
|
||||
|
||||
boost::mutex mutexInt;
|
||||
PortsOut portsOut;
|
||||
Pimpl() = default;
|
||||
|
||||
Pimpl(): portsOut() {}
|
||||
};
|
||||
|
||||
Pimpl* getData() {
|
||||
@ -267,8 +329,8 @@ EXPORT SYSV_ABI int32_t sceAudioOutOpen(int32_t userId, SceAudioOutPortType type
|
||||
port->volume[i] = AudioOut::VOLUME_0DB;
|
||||
}
|
||||
} else {
|
||||
SDL_AudioSpec fmt_curr;
|
||||
if ((*jData)["device"] == "[default]") {
|
||||
SDL_AudioSpec fmt_curr;
|
||||
SDL_GetDefaultAudioInfo((char**)&dname, &fmt_curr, 0);
|
||||
} else if ((*jData)["device"] == "[null]") {
|
||||
LOG_INFO(L"%S audio output device is nulled!", getDevName(type));
|
||||
@ -281,6 +343,7 @@ EXPORT SYSV_ABI int32_t sceAudioOutOpen(int32_t userId, SceAudioOutPortType type
|
||||
} catch (const json::exception& e) {
|
||||
LOG_ERR(L"Invalid audio device name: %S", e.what());
|
||||
dname = NULL;
|
||||
SDL_GetDefaultAudioInfo((char**)&dname, &fmt_curr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -296,6 +359,7 @@ EXPORT SYSV_ABI int32_t sceAudioOutOpen(int32_t userId, SceAudioOutPortType type
|
||||
|
||||
LOG_INFO(L"%S audio device %S opened for user #%d", getDevName(type), dname, userId);
|
||||
port->mixedAudio.resize(port->sampleSize * port->samplesNum * port->channelsNum);
|
||||
port->deviceName.assign(dname);
|
||||
return handle;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user