feat: align legacy operator and playout behavior
This commit is contained in:
@@ -122,7 +122,7 @@ PREPARE의 공통 순서는 다음과 같다.
|
||||
|
||||
TAKE IN은 PREPARE 때의 오래된 DTO를 그대로 재생하지 않는다. 원본 `ONAirMode`와 같이 현재 playlist snapshot의 같은 entry/page를 실제 DB에서 다시 조회하고 새 scene을 `LoadScene` → transaction → `Prepare(10)`한 뒤, 그 prepare가 명확히 성공한 경우에만 `Play(10)`을 한 번 호출한다. PREPARE를 다시 누르는 원본 toggle은 `TakeOut(All)`/`StopAll`로 state를 정리한다. timeout 또는 `OutcomeUnknown`은 retry 가능한 실패로 낮추지 않는다.
|
||||
|
||||
공통 fade와 배경은 Web 입력이 아니라 로컬 trusted playout 설정에서만 온다. `legacySceneFadeDuration`의 원본 기본값은 6이며, `legacySceneBackgroundKind`, scene root 아래의 상대 `legacySceneBackgroundAssetPath`, video loop 설정을 `PlayoutSceneCompositionFactory`가 검증한다. `DryRun`에서도 경로 탈출, 절대 경로, 허용되지 않은 확장자, reparse point, 누락 파일을 실제 COM 전에 fail-closed preflight한다. asset 경로는 Web 상태와 preview에 노출하지 않는다.
|
||||
공통 배경 경로는 Web 입력이 아니라 로컬 trusted playout 설정과 네이티브 파일 선택에서만 온다. `legacySceneFadeDuration`의 원본 기본 인덱스는 6(화면 표시 7)이고 화면의 `DissolveTime`은 선택 인덱스 0~19만 C#에 보낸다. 실제 K3D에는 원본 raw `SetSceneEffectType(10, FADE, index)` 및 공통 배경 `(path, 2004, 10)`을 전달하며 s5006의 `(path, 1, 1)`과 구분한다. `legacySceneBackgroundKind`, scene root 아래의 상대 `legacySceneBackgroundAssetPath`, video loop 설정을 `PlayoutSceneCompositionFactory`가 검증한다. `DryRun`에서도 경로 탈출, 절대 경로, 허용되지 않은 확장자, reparse point, 누락 파일을 실제 COM 전에 fail-closed preflight한다. asset 경로는 Web 상태와 preview에 노출하지 않는다.
|
||||
|
||||
이 순서는 `RegisteredLegacySceneCueProviderTests`, `LegacyPlayoutWorkflowTests`, Playout의 `DynamicK3dSessionTests`, `TornadoPlayoutEngineTests`에서 검증한다. 실제 COM 형식과 vendor 구현은 계속 `IPlayoutEngine` 뒤에 있다.
|
||||
|
||||
@@ -136,7 +136,7 @@ TAKE IN은 PREPARE 때의 오래된 DTO를 그대로 재생하지 않는다. 원
|
||||
- `s5088`의 NXT 인덱스는 비교와 조회 모두 `i + pageIndex * 12`를 사용한다.
|
||||
- 현재 항목에 다음 page가 있으면 operator Page NEXT는 playlist index를 유지하되 원본 `Next_Scene(0)`처럼 다음 page 데이터를 조회하고 새 scene을 `LoadScene` → transaction mutation → `QueryVariables` → `EndTransaction` → `Prepare(10)` → `Play(10)`한다. 이 경로는 `GetPlayingScene` in-place refresh가 아니다.
|
||||
- 마지막 page면 다음 활성 playlist 항목으로 이동한다. 비활성 항목은 원본처럼 앞으로 건너뛰며 끝에서 wrap하지 않는다.
|
||||
- 원본 timer는 TAKE IN과 playlist NEXT 뒤 반복되며 첫 `m_time` 이후 3초 주기로 계속 실행된다. 새 runtime도 반복 갱신을 유지하지만, 이전 tracked `Play`의 `OnScenePlayed` callback을 drain한 뒤에야 첫 `m_time` 또는 3초의 **전체 cooldown**을 시작한다. 이는 callback 대기와 delay가 겹쳐 operator window가 사라지는 일을 막는 의도적 안전 적응이다. 모든 operator command는 현재 epoch를 먼저 중단하고 Page NEXT 뒤에는 refresh를 재시작하지 않는다.
|
||||
- 원본 timer는 TAKE IN과 playlist NEXT 뒤 반복되며 첫 `m_time` 이후 3초 주기로 계속 실행된다. 새 runtime도 반복 갱신을 유지하지만, 이전 tracked `Play`의 `OnScenePlayed` callback을 drain한 뒤에야 첫 `m_time` 또는 3초의 **전체 cooldown**을 시작한다. 이는 callback 대기와 delay가 겹쳐 operator window가 사라지는 일을 막는 의도적 안전 적응이다. 모든 operator command는 현재 epoch를 먼저 중단하고 Page NEXT 뒤에는 refresh를 재시작하지 않는다. 단, 5076/5079/5080/5081은 원본의 `m_time * 1000` Int32 overflow 뒤 Timer 설정 예외로 실제 갱신이 시작되지 않으므로 명시적으로 비활성화한다.
|
||||
- 원본 `timer1_Tick`에는 mutation 전 선행 `Play(10)`과 `Prepare` 뒤 후행 `Play(10)`이 모두 있다. 마이그레이션은 불완전한 `GetPlayingScene` proxy 대신 retained on-air scene에 fresh DTO mutation을 적용하고 `BeginTransaction → mutation → QueryVariables → EndTransaction → Prepare(10) → tracked Play(10)` 한 번만 보낸다. 선행 replay를 생략한 것은 callback 추적 없이 PLAY를 중복시키지 않기 위한 명시적 안전 차이이며 Round H의 정확한 PLAY/callback 4회 예산에 반영됐다.
|
||||
- refresh CTS와 공개 상태는 atomic epoch로 결합한다. `Replace`/`Stop`/조건부 update/completion이 같은 lock에서 generation을 확인하므로 취소된 이전 loop가 `active`, `NextAt`, success 또는 fault를 새 loop나 중단 상태 위에 다시 쓰지 못한다.
|
||||
|
||||
@@ -155,6 +155,7 @@ TAKE IN은 PREPARE 때의 오래된 DTO를 그대로 재생하지 않는다. 원
|
||||
- `OnCutOut`은 해당 layout의 on-air 참조를, `OnStopAll`은 player의 모든 on-air 참조를 정리할 근거다.
|
||||
- 이전 connection generation의 늦은 callback은 현재 state를 바꾸지 않는다.
|
||||
- pending Play callback이 있으면 TAKE OUT을 제외한 PREPARE/TAKE IN/NEXT/timer refresh를 fail-closed 차단한다. 어떤 lifecycle callback이든 pending이면 Disconnect와 session recycle을 하지 않고 abandon/quarantine 및 `OutcomeUnknown`으로 보수적으로 전환한다.
|
||||
- pending CutOut/StopAll callback이 있으면 반복 TAKE OUT을 포함한 모든 scene 명령을 SDK 전에 차단하며, 일치하는 완료 callback 뒤에만 다음 PREPARE를 허용한다.
|
||||
- `StopAll`/`CutOut`은 SDK dispatch 전에 각 pending completion counter를 올리고 동기 호출 실패 시 되돌린다. 성공 callback은 대응 counter를 정확히 하나 줄이며, 성공한 stop/cut은 중단된 Play가 뒤늦게 `OnScenePlayed`를 보내지 않을 수 있으므로 해당 pending Play accounting을 취소한다. dispatch 뒤 cancellation/timeout은 결과 불명확으로 취급한다.
|
||||
- 장기 실행 시 retired scene은 callback으로 안전성이 확인된 뒤 unload/release한다.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user