mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 19:07:01 +02:00
fix AudioOut pacing
Co-authored-by: Stefanos Costa <stefanos.costa1999@gmail.com>
This commit is contained in:
+19
-5
@@ -82,6 +82,7 @@ public:
|
||||
Id AudioOutOpen(int type, uint32_t samples_num, uint32_t freq, Format format);
|
||||
bool AudioOutClose(Id handle);
|
||||
bool AudioOutValid(Id handle);
|
||||
bool AudioOutHasDevice(Id handle);
|
||||
bool AudioOutSetVolume(Id handle, uint32_t bitflag, const int* volume);
|
||||
uint32_t AudioOutOutputs(OutputParam* params, uint32_t num, bool blocking = true);
|
||||
bool AudioOutGetStatus(Id handle, int* type, int* channels_num);
|
||||
@@ -152,6 +153,10 @@ void AudioOutClose(int handle) {
|
||||
}
|
||||
}
|
||||
|
||||
bool AudioOutHasDevice(int handle) {
|
||||
return g_audio != nullptr && handle > 0 && g_audio->AudioOutHasDevice(Audio::Id(handle));
|
||||
}
|
||||
|
||||
uint32_t AudioOutOutputs(const OutputParam* params, uint32_t num, bool blocking) {
|
||||
if (g_audio == nullptr || params == nullptr || num == 0) {
|
||||
return 0;
|
||||
@@ -451,6 +456,13 @@ bool Audio::AudioOutValid(Id handle) {
|
||||
m_out_ports[handle.GetId()].used);
|
||||
}
|
||||
|
||||
bool Audio::AudioOutHasDevice(Id handle) {
|
||||
Common::LockGuard lock(m_mutex);
|
||||
|
||||
return (handle.GetId() >= 0 && handle.GetId() < OUT_PORTS_MAX &&
|
||||
m_out_ports[handle.GetId()].used && m_out_ports[handle.GetId()].audio_device != 0);
|
||||
}
|
||||
|
||||
bool Audio::AudioOutGetStatus(Id handle, int* type, int* channels_num) {
|
||||
Common::LockGuard lock(m_mutex);
|
||||
|
||||
@@ -516,16 +528,18 @@ uint32_t Audio::AudioOutOutputs(OutputParam* params, uint32_t num, bool blocking
|
||||
max_wait_time = (wait_time > max_wait_time ? wait_time : max_wait_time);
|
||||
}
|
||||
|
||||
bool all_ports_have_device = true;
|
||||
bool any_port_has_device = false;
|
||||
for (uint32_t i = 0; i < num; i++) {
|
||||
if (m_out_ports[params[i].handle.GetId()].audio_device == 0) {
|
||||
all_ports_have_device = false;
|
||||
if (m_out_ports[params[i].handle.GetId()].audio_device != 0) {
|
||||
any_port_has_device = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Device-backed ports are paced by the SDL queue above.
|
||||
if (blocking && max_wait_time != 0 && !all_ports_have_device) {
|
||||
// One real output device is enough to pace the whole synchronized batch. Applying the fallback
|
||||
// when a vibration port is present would rate-limit the device-backed ports to exactly 1x and
|
||||
// prevent their SDL queues from building an underrun cushion.
|
||||
if (blocking && max_wait_time != 0 && !any_port_has_device) {
|
||||
Common::Thread::SleepMicro(max_wait_time);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ static constexpr int OUT_PORTS_MAX = 32;
|
||||
|
||||
int AudioOutOpen(int type, uint32_t samples_num, uint32_t freq, Format format);
|
||||
void AudioOutClose(int handle);
|
||||
bool AudioOutHasDevice(int handle);
|
||||
uint32_t AudioOutOutputs(const OutputParam* params, uint32_t num, bool blocking = true);
|
||||
|
||||
} // namespace Libs::Audio::AudioInternal
|
||||
|
||||
+21
-2
@@ -336,6 +336,17 @@ static AudioOut2PortStateEntry* audioout2_find_port_locked(AudioOut2PortHandle p
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool audioout2_context_has_queueable_device(AudioOut2ContextHandle ctx) {
|
||||
Common::LockGuard lock(g_audioout2_port_mutex);
|
||||
for (const auto& state: g_audioout2_ports) {
|
||||
if (state.used && state.context == ctx && state.audio_handle > 0 &&
|
||||
state.pcm_data != nullptr && AudioInternal::AudioOutHasDevice(state.audio_handle)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void audioout2_queue_context_audio(AudioOut2ContextHandle ctx, bool blocking) {
|
||||
std::vector<AudioInternal::OutputParam> params;
|
||||
params.reserve(AudioInternal::OUT_PORTS_MAX);
|
||||
@@ -493,15 +504,23 @@ int KYTY_SYSV_ABI AudioOut2ContextPush(AudioOut2ContextHandle ctx, uint32_t bloc
|
||||
uint32_t sleep_micros = audioout2_grain_micros(512);
|
||||
|
||||
for (;;) {
|
||||
// Only a synchronous submission carrying PCM to a real device can rely on the SDL queue for
|
||||
// pacing. Async pushes must retain queue-depth backpressure, and a handle without PCM (or a
|
||||
// vibration/failed-open handle) has no downstream operation that can block this call.
|
||||
const bool use_device_clock =
|
||||
blocking != 0 && audioout2_context_has_queueable_device(ctx);
|
||||
|
||||
g_audioout2_context_mutex.Lock();
|
||||
if (auto* state = audioout2_find_context_locked(ctx); state != nullptr) {
|
||||
audioout2_update_context_locked(state);
|
||||
sleep_micros = audioout2_grain_micros(state->num_grains);
|
||||
if (state->queued < state->queue_depth) {
|
||||
if (state->queued < state->queue_depth || use_device_clock) {
|
||||
if (state->queued == 0) {
|
||||
state->last_update = LibKernel::KernelGetProcessTime();
|
||||
}
|
||||
state->queued++;
|
||||
if (state->queued < state->queue_depth) {
|
||||
state->queued++;
|
||||
}
|
||||
g_audioout2_context_mutex.Unlock();
|
||||
audioout2_queue_context_audio(ctx, blocking != 0);
|
||||
return OK;
|
||||
|
||||
Reference in New Issue
Block a user