fix: refresh the retained on-air scene

This commit is contained in:
2026-07-11 13:58:23 +09:00
parent c71ea425e8
commit bb4a3ec3e0
2 changed files with 300 additions and 32 deletions

View File

@@ -550,18 +550,33 @@ internal sealed class DynamicK3dSession : IK3dGuardedConnectSession
var engine = _engine!;
var player = _player!;
var outputChannel = _outputChannel;
object? playingScene = null;
// Tornado2 can return an incomplete GetPlayingScene proxy. The scene loaded,
// prepared, and promoted by Play is the only trusted reference for an in-place
// refresh, and it remains retained until the normal take-out/unload lifecycle.
if (_preparedScene is not null)
{
throw new InvalidOperationException(
"An on-air update cannot run while another scene is prepared.");
}
var currentScene = ReusableScene(_currentScene, cue.SceneName)
?? throw new InvalidOperationException(
"No matching retained on-air scene is available.");
if (SupportsLifecycleCallbacks && _pendingPlayCallbacks != 0)
{
throw new InvalidOperationException(
"An on-air update cannot run while scene playback is pending.");
}
var transactionStarted = false;
try
{
playingScene = InvokeRequired(player, "GetPlayingScene", layoutIndex);
foreach (var mutation in cue.Mutations ?? [])
{
if (IsBeforeTransactionSceneSetupMutation(mutation))
{
ApplySceneSetupMutation(playingScene, mutation);
ApplySceneSetupMutation(currentScene.Value, mutation);
}
}
@@ -570,7 +585,7 @@ internal sealed class DynamicK3dSession : IK3dGuardedConnectSession
foreach (var field in cue.Fields ?? [])
{
ApplyField(playingScene, field);
ApplyField(currentScene.Value, field);
}
foreach (var mutation in cue.Mutations ?? [])
@@ -580,11 +595,11 @@ internal sealed class DynamicK3dSession : IK3dGuardedConnectSession
// explicit in-transaction ordering.
if (!IsBeforeTransactionSceneSetupMutation(mutation))
{
ApplyTransactionMutation(playingScene, mutation);
ApplyTransactionMutation(currentScene.Value, mutation);
}
}
Invoke(playingScene, "QueryVariables");
Invoke(currentScene.Value, "QueryVariables");
if (outputChannel.HasValue)
{
Invoke(engine, "EndTransactionOnChannel", outputChannel.GetValueOrDefault());
@@ -595,20 +610,8 @@ internal sealed class DynamicK3dSession : IK3dGuardedConnectSession
}
transactionStarted = false;
Invoke(player, "Prepare", layoutIndex, playingScene);
Invoke(player, "Prepare", layoutIndex, currentScene.Value);
InvokeTrackedPlay(layoutIndex);
// GetPlayingScene can return the same RCW or another RCW for the same COM
// scene. An in-place page update must never retire/unload the active scene.
if (_currentScene is null)
{
_currentScene = new SceneReference(playingScene, cue.SceneName);
playingScene = null;
}
else if (ReferenceEquals(_currentScene.Value, playingScene))
{
playingScene = null;
}
}
catch
{
@@ -626,10 +629,6 @@ internal sealed class DynamicK3dSession : IK3dGuardedConnectSession
throw;
}
finally
{
ReleaseComObject(playingScene);
}
}
public void TakeOut(int layoutIndex, PlayoutTakeOutScope scope)