[AvPlayer] Report a loaded source as active before playback starts

sceAvPlayerIsActive answered true only after sceAvPlayerStart. Titles poll it
after adding a source and before starting playback; Superliminal waits for it
to turn true before it calls Start, so New Game never left the loading screen.
Report a player as active from the moment its source is loaded until it is
stopped or reaches its end, and track Stop explicitly so a stopped player
stays inactive.
This commit is contained in:
kuba 2026-09-27 17:20:59 +02:00
parent 4d65ff6d51
commit 830eeaff53
2 changed files with 19 additions and 2 deletions

View File

@ -437,6 +437,7 @@ public static class AvPlayerExports
public uint AvSyncMode { get; set; } = AvSyncModeDefault;
public bool IsGen5 { get; init; }
public bool Started { get; set; }
public bool Stopped { get; set; }
public bool Paused { get; set; }
public bool Looping { get; set; }
public bool EndOfStream { get; set; }
@ -724,6 +725,7 @@ public static class AvPlayerExports
player = foundPlayer;
player.Started = true;
player.Stopped = false;
player.Paused = false;
player.EndOfStream = false;
Trace($"start handle=0x{player.Handle:X16}");
@ -767,6 +769,7 @@ public static class AvPlayerExports
player.ResetPlayback();
player.Started = false;
player.Stopped = true;
}
NotifyEvent(ctx, player, 1); // StateStop
@ -1001,7 +1004,9 @@ public static class AvPlayerExports
lock (StateGate)
{
var found = Players.TryGetValue(ctx[CpuRegister.Rdi], out var player);
var active = found && player!.Started && !player.EndOfStream;
// Active from the moment a source is ready until it stops, fails or reaches its end,
// whether or not playback has started (titles poll it before calling sceAvPlayerStart).
var active = found && player!.SourcePath is not null && !player.Stopped && !player.EndOfStream;
TraceOnce(
"is_active",
$"is_active found={found} started={(found && player!.Started)} " +
@ -1388,6 +1393,7 @@ public static class AvPlayerExports
player.DurationMilliseconds = duration;
player.HasAudio = hasAudio;
player.Started = player.AutoStart;
player.Stopped = false;
autoStart = player.AutoStart;
Trace(
$"source guest='{guestPath}' host='{hostPath}' {width}x{height} " +

View File

@ -96,6 +96,17 @@ public sealed class AvPlayerPlaybackTests
Assert.Equal(1, playback.IsActive());
}
[Fact]
public void ALoadedSourceIsActiveBeforePlaybackStarts()
{
using var playback = new DecodedPlayback(0, 3, 2, 0);
playback.SetState("Started", false);
Assert.Equal(1, playback.IsActive());
playback.SetState("Stopped", true);
Assert.Equal(0, playback.IsActive());
}
private sealed class DecodedPlayback : IDisposable
{
private const ulong Handle = 0xA0_0000_2300;
@ -215,7 +226,7 @@ public sealed class AvPlayerPlaybackTests
public TValue GetState<TValue>(string propertyName) =>
(TValue)_player.GetType().GetProperty(propertyName)!.GetValue(_player)!;
private void SetState(string propertyName, object value) =>
public void SetState(string propertyName, object value) =>
_player.GetType().GetProperty(propertyName)!.SetValue(_player, value);
private void SetArguments()