mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-09 03:29:43 -10:00
audio: seed runloop controls during transport preparation
Prepare native transport and its initial runloop tempo/cutoff in one parked-worker transaction. Validate unsupported speed before allocation and retain the previous session on failure. Reuse the speed resolver and keep existing preparation semantics intact. Cover failure preservation and pre-source control readiness, and use the transaction in the existing real-wrapper runloop startup/restart suite.
This commit is contained in:
1 parent
c88d7cbca1
commit
3ba9724372
4 files changed
+91
-10
No files matched your search
+34
-4
@@ -4574,11 +4574,10 @@ bool audio_driver_pipeline_transport_request_speed(uint32_t tempo_q16,
|
||||
tempo_q16) : 0);
|
||||
}
|
||||
|
||||
bool audio_driver_pipeline_transport_request_runloop(bool reset, bool lowpass)
|
||||
static bool audio_driver_transport_runloop_tempo(uint32_t *tempo)
|
||||
{
|
||||
settings_t *settings = config_get_ptr();
|
||||
uint32_t flags = runloop_get_flags();
|
||||
uint32_t tempo;
|
||||
uint64_t bits;
|
||||
double duration = 1.0;
|
||||
if (!(flags & RUNLOOP_FLAG_PAUSED))
|
||||
@@ -4595,7 +4594,14 @@ bool audio_driver_pipeline_transport_request_runloop(bool reset, bool lowpass)
|
||||
memcpy(&bits, &duration, sizeof(bits));
|
||||
if (bits >= UINT64_C(0x7ff0000000000000)
|
||||
|| !(duration >= 1.0 / 32.0 && duration <= 4.0)) return false;
|
||||
tempo = (uint32_t)(65536.0 / duration + 0.5);
|
||||
*tempo = (uint32_t)(65536.0 / duration + 0.5);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool audio_driver_pipeline_transport_request_runloop(bool reset, bool lowpass)
|
||||
{
|
||||
uint32_t tempo;
|
||||
if (!audio_driver_transport_runloop_tempo(&tempo)) return false;
|
||||
return audio_driver_pipeline_transport_request_speed(tempo,
|
||||
tempo != 65536, reset, lowpass);
|
||||
}
|
||||
@@ -6859,7 +6865,7 @@ static bool audio_driver_transport_bind(audio_driver_state_t *audio_st,
|
||||
struct audio_transport_prepare
|
||||
{
|
||||
unsigned rate;
|
||||
uint32_t search;
|
||||
uint32_t search, control, cutoff;
|
||||
bool release, result;
|
||||
};
|
||||
|
||||
@@ -6877,8 +6883,16 @@ static void audio_driver_transport_control(void *userdata)
|
||||
&& audio_st->context_audio_data
|
||||
&& !retro_spsc_read_avail(&audio_st->pipe_ring)
|
||||
&& !audio_st->pipe_pending_bytes)
|
||||
{
|
||||
request->result = audio_driver_transport_bind(audio_st,
|
||||
request->rate, request->search, audio_st->pipe_float);
|
||||
if (request->result && request->control)
|
||||
{
|
||||
audio_pipeline_layout_t *q = &audio_st->pipe_layouts;
|
||||
q->published_control = q->current_control = request->control;
|
||||
q->published_cutoff = q->current_cutoff = request->cutoff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void audio_driver_transport_transaction(struct audio_transport_prepare *request)
|
||||
@@ -6896,6 +6910,21 @@ bool audio_driver_pipeline_transport_prepare(unsigned rate, uint32_t search_chan
|
||||
{
|
||||
struct audio_transport_prepare request;
|
||||
request.rate = rate; request.search = search_channels;
|
||||
request.control = request.cutoff = 0;
|
||||
request.release = request.result = false;
|
||||
audio_driver_transport_transaction(&request);
|
||||
return request.result;
|
||||
}
|
||||
|
||||
bool audio_driver_pipeline_transport_prepare_runloop(unsigned rate,
|
||||
uint32_t search_channels, bool lowpass)
|
||||
{
|
||||
struct audio_transport_prepare request;
|
||||
uint32_t tempo;
|
||||
if (!audio_driver_transport_runloop_tempo(&tempo)) return false;
|
||||
request.rate = rate; request.search = search_channels;
|
||||
request.control = tempo == 65536 ? tempo : tempo | AUDIO_PIPELINE_STRETCH;
|
||||
request.cutoff = lowpass ? audio_speed_lpf_cutoff(rate, tempo) : 0;
|
||||
request.release = request.result = false;
|
||||
audio_driver_transport_transaction(&request);
|
||||
return request.result;
|
||||
@@ -6905,6 +6934,7 @@ void audio_driver_pipeline_transport_release(void)
|
||||
{
|
||||
struct audio_transport_prepare request;
|
||||
request.rate = 0; request.search = 0;
|
||||
request.control = request.cutoff = 0;
|
||||
request.release = true; request.result = false;
|
||||
audio_driver_transport_transaction(&request);
|
||||
}
|
||||
|
||||
@@ -965,6 +965,13 @@ struct audio_pipeline_stretch;
|
||||
* Empty-ring format renegotiation rebuilds the session; allocation failure
|
||||
* releases it while preserving the new native ring format. */
|
||||
bool audio_driver_pipeline_transport_prepare(unsigned rate, uint32_t search_channels);
|
||||
|
||||
/* Prepare and seed current runloop tempo/cutoff in one parked transaction.
|
||||
* Empty source/no pending device output required. Failure preserves the old
|
||||
* transport and metadata; unsupported speed is rejected before allocation.
|
||||
* Explicit startup API: does not register an automatic update caller. */
|
||||
bool audio_driver_pipeline_transport_prepare_runloop(unsigned rate,
|
||||
uint32_t search_channels, bool lowpass);
|
||||
void audio_driver_pipeline_transport_release(void);
|
||||
/* Main source producer only, before publishing the affected audio. Tempo is
|
||||
* source frames/output frame in Q16, 0.25..32 when active (ignored when inactive).
|
||||
|
||||
@@ -1665,6 +1665,41 @@ static void transport_owner_cases(void)
|
||||
CHECK(!st->pipe_transport && !st->pipe_transport_output, "failed prepare left state");
|
||||
CHECK(audio_driver_pipeline_transport_prepare(48000, 1), "owner prepare");
|
||||
stage = st->pipe_transport; output = st->pipe_transport_output;
|
||||
runloop_state_get_ptr()->flags = RUNLOOP_FLAG_SLOWMOTION;
|
||||
config_get_ptr()->floats.slowmotion_ratio = 8;
|
||||
calls = transport_control_calls;
|
||||
CHECK(!audio_driver_pipeline_transport_prepare_runloop(48000, 1, true)
|
||||
&& transport_control_calls == calls, "unsupported startup parked worker");
|
||||
runloop_state_get_ptr()->flags = RUNLOOP_FLAG_FASTMOTION;
|
||||
config_get_ptr()->bools.audio_fastforward_speedup = true;
|
||||
retro_atomic_store_release_int(&st->pipe_ff_mult_q16, 16384);
|
||||
transport_fail_stage = true;
|
||||
CHECK(!audio_driver_pipeline_transport_prepare_runloop(48000, 1, true),
|
||||
"failed runloop startup accepted");
|
||||
transport_fail_stage = false;
|
||||
CHECK(st->pipe_transport == stage && st->pipe_transport_output == output
|
||||
&& st->pipe_layouts.published_control == 65536
|
||||
&& st->pipe_layouts.published_cutoff == 0,
|
||||
"failed runloop startup changed session");
|
||||
calls = transport_control_calls;
|
||||
CHECK(audio_driver_pipeline_transport_prepare_runloop(48000, 1, true)
|
||||
&& transport_control_calls == calls + 1, "runloop startup parking");
|
||||
CHECK(st->pipe_layouts.current_control == (262144 | AUDIO_PIPELINE_STRETCH)
|
||||
&& st->pipe_layouts.published_control == st->pipe_layouts.current_control
|
||||
&& st->pipe_layouts.current_cutoff == 5400
|
||||
&& st->pipe_layouts.published_cutoff == 5400
|
||||
&& !retro_atomic_load_relaxed_size(&st->pipe_layouts.head),
|
||||
"startup did not seed coherent speed controls");
|
||||
CHECK(audio_pipeline_stretch_next(st->pipe_transport, 0, 1, &block)
|
||||
&& !block.frames && audio_pipeline_stretch_needs_input(st->pipe_transport),
|
||||
"startup controls not ready before source");
|
||||
runloop_state_get_ptr()->flags = 0;
|
||||
config_get_ptr()->bools.audio_fastforward_speedup = false;
|
||||
config_get_ptr()->floats.slowmotion_ratio = 1;
|
||||
CHECK(audio_driver_pipeline_transport_prepare_runloop(48000, 1, false)
|
||||
&& st->pipe_layouts.current_control == 65536
|
||||
&& st->pipe_layouts.current_cutoff == 0, "normal startup was not dry");
|
||||
stage = st->pipe_transport; output = st->pipe_transport_output;
|
||||
CHECK(stage && output && !((uintptr_t)output % 64), "owner storage/alignment");
|
||||
wrapper.wait_writable = NULL;
|
||||
CHECK(!audio_driver_pipeline_transport_prepare(48000, 1)
|
||||
@@ -1682,6 +1717,8 @@ static void transport_owner_cases(void)
|
||||
bytes = st->pipe_frame_bytes;
|
||||
CHECK(retro_spsc_write(&st->pipe_ring, &input, bytes) == bytes, "queued owner source");
|
||||
CHECK(!audio_driver_pipeline_transport_prepare(48000, 1), "replaced queued owner");
|
||||
CHECK(!audio_driver_pipeline_transport_prepare_runloop(48000, 1, true)
|
||||
&& st->pipe_transport == stage, "runloop startup replaced queued owner");
|
||||
audio_driver_set_core_float(!floating);
|
||||
CHECK(st->pipe_float == (floating != 0) && st->pipe_transport == stage,
|
||||
"queued format changed session");
|
||||
@@ -1690,6 +1727,8 @@ static void transport_owner_cases(void)
|
||||
retro_atomic_load_relaxed_size(&st->pipe_ring.head), 2000), "owner pending control");
|
||||
st->pipe_pending = (const uint8_t*)output; st->pipe_pending_bytes = bytes;
|
||||
CHECK(!audio_driver_pipeline_transport_prepare(48000, 1), "replaced pending device output");
|
||||
CHECK(!audio_driver_pipeline_transport_prepare_runloop(48000, 1, true)
|
||||
&& st->pipe_transport == stage, "runloop startup replaced pending output");
|
||||
calls = transport_control_calls;
|
||||
audio_driver_set_core_float(!floating);
|
||||
CHECK(transport_control_calls == calls + 1, "native rebind bypassed parking");
|
||||
|
||||
@@ -438,6 +438,15 @@ static float frame_audio_float[32768 * 8];
|
||||
|
||||
/* --- fixture --------------------------------------------------------- */
|
||||
|
||||
static bool prepare_transport(bool reset)
|
||||
{
|
||||
if (runloop_policy)
|
||||
return audio_driver_pipeline_transport_prepare_runloop(CORE_RATE, 3, speed_lowpass);
|
||||
return audio_driver_pipeline_transport_prepare(CORE_RATE, 3)
|
||||
&& audio_driver_pipeline_transport_request(tempo_q16,
|
||||
transport_mode == 3, reset, transport_mode == 2 ? 1000 : 0);
|
||||
}
|
||||
|
||||
static bool pipeline_up(unsigned latency_ms)
|
||||
{
|
||||
audio_driver_state_t *st = &audio_driver_st;
|
||||
@@ -549,9 +558,7 @@ static bool pipeline_up(unsigned latency_ms)
|
||||
&st->context_audio_data, NULL, OUT_RATE, NULL, latency_ms,
|
||||
false, false, &clocked_driver))
|
||||
return false;
|
||||
if (transport_mode && (!audio_driver_pipeline_transport_prepare(CORE_RATE, 3)
|
||||
|| !audio_driver_pipeline_transport_request(tempo_q16,
|
||||
transport_mode == 3, false, transport_mode == 2 ? 1000 : 0)))
|
||||
if (transport_mode && !prepare_transport(false))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
@@ -704,9 +711,7 @@ static void wrapper_restart(void)
|
||||
if (transport_mode)
|
||||
{
|
||||
audio_driver_pipeline_transport_release();
|
||||
if (!audio_driver_pipeline_transport_prepare(CORE_RATE, 3)
|
||||
|| !audio_driver_pipeline_transport_request(tempo_q16,
|
||||
transport_mode == 3, true, transport_mode == 2 ? 1000 : 0))
|
||||
if (!prepare_transport(true))
|
||||
fixture_failures++;
|
||||
}
|
||||
if (before != retro_atomic_load_acquire_size(&cnt_wakes)) fixture_failures++;
|
||||
|
||||
Reference in new issue
Block a user