diff --git a/src/SharpEmu.Libs/AvPlayer/AvPlayerExports.cs b/src/SharpEmu.Libs/AvPlayer/AvPlayerExports.cs index 4e201bd..2c2ccb2 100644 --- a/src/SharpEmu.Libs/AvPlayer/AvPlayerExports.cs +++ b/src/SharpEmu.Libs/AvPlayer/AvPlayerExports.cs @@ -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 diff --git a/tests/SharpEmu.Libs.Tests/AvPlayer/AvPlayerAbiTests.cs b/tests/SharpEmu.Libs.Tests/AvPlayer/AvPlayerAbiTests.cs index f6dc735..0643e54 100644 --- a/tests/SharpEmu.Libs.Tests/AvPlayer/AvPlayerAbiTests.cs +++ b/tests/SharpEmu.Libs.Tests/AvPlayer/AvPlayerAbiTests.cs @@ -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)]