[AvPlayer] Start a player on its own when the title registers no event callback

Reporting a loaded source as active before Start regressed Quake, which
waits for its player to go inactive before starting its queued intro
videos. A player left loaded but unstarted stays active forever. Only a
title that registers an event callback can see the ready state and call
sceAvPlayerStart itself, so a player whose title asks for autoStart or
registers no callback now plays by itself once its source is ready,
reaches the end of the stream and reports inactive. Titles that start
playback themselves keep seeing a loaded source as active.
This commit is contained in:
kuba 2026-09-29 22:57:13 +02:00
parent 830eeaff53
commit fbacc494ed
2 changed files with 25 additions and 2 deletions

View File

@ -541,7 +541,9 @@ public static class AvPlayerExports
{
Handle = handle,
IsGen5 = IsGen5Target(ctx.TargetGeneration),
AutoStart = TryReadByte(ctx, initDataAddress + autoStartOffset, out var autoStart) && autoStart != 0,
AutoStart = StartsAutomatically(
TryReadByte(ctx, initDataAddress + autoStartOffset, out var autoStart) && autoStart != 0,
TryReadUInt64(ctx, initDataAddress + 88, out var eventCallbackForStart) ? eventCallbackForStart : 0),
GuestBuffers = new ulong[ReadOutputVideoFrameBufferCount(
ctx,
initDataAddress,
@ -615,7 +617,9 @@ public static class AvPlayerExports
{
Handle = handle,
IsGen5 = IsGen5Target(ctx.TargetGeneration),
AutoStart = TryReadByte(ctx, initDataAddress + autoStartOffset, out var autoStart) && autoStart != 0,
AutoStart = StartsAutomatically(
TryReadByte(ctx, initDataAddress + autoStartOffset, out var autoStart) && autoStart != 0,
TryReadUInt64(ctx, initDataAddress + 96, out var eventCallbackForStart) ? eventCallbackForStart : 0),
GuestBuffers = new ulong[ReadOutputVideoFrameBufferCount(
ctx,
initDataAddress,
@ -2620,6 +2624,13 @@ public static class AvPlayerExports
internal static bool IsGen5Target(Generation generation) =>
(generation & Generation.Gen5) != 0;
// A player plays on its own once its source is ready when the title asks for autoStart or
// registers no event callback: without one nothing could observe the ready state and start
// it. Such a title never calls sceAvPlayerStart and waits for the player to go inactive at the
// end of the stream, so leaving it unstarted kept it active forever.
internal static bool StartsAutomatically(bool autoStartRequested, ulong eventCallback) =>
autoStartRequested || eventCallback == 0;
internal static ulong GetAutoStartOffset(Generation generation, bool extended) =>
IsGen5Target(generation)
? extended ? 116UL : 108UL

View File

@ -11,6 +11,18 @@ namespace SharpEmu.Libs.Tests.AvPlayer;
public sealed class AvPlayerAbiTests
{
[Theory]
[InlineData(true, 0x1000UL, true)]
[InlineData(false, 0UL, true)]
[InlineData(true, 0UL, true)]
[InlineData(false, 0x1000UL, false)]
public void APlayerWithoutAnEventCallbackStartsOnItsOwn(bool autoStartRequested, ulong eventCallback, bool expected)
{
// Only a title that registers an event callback can see the ready state and call Start;
// without one the player plays by itself, ends, and reports inactive.
Assert.Equal(expected, AvPlayerExports.StartsAutomatically(autoStartRequested, eventCallback));
}
[Theory]
[InlineData(Generation.Gen4, false, 108UL)]
[InlineData(Generation.Gen5, false, 108UL)]