WP26:观众唯一调度与双窗口操作
状态:已完成(2026-10-18)。阶段:M2。主责:Runtime / Presenter。 上层工作项:R05(窗口接入)、E04(双屏入口);详见模块计划。本包是该工作项的实施拆分,不是另一份配置契约。
前置与输入
前置完成:WP16、WP24、WP25。 字段与行为以统一契约为准;所有依赖编号见执行清单。
修改范围与交付
- 修改范围:控制台发命令/回显,观众窗口唯一推进;进入退出模式的暂停交接、窗口 ready/关闭重开、可见性和全屏。
- 交付物:无双重计时、可暂停恢复的演讲者自动放映用户路径。
- 提交边界:不做远程设备控制;未就绪时不由控制台偷偷接管推进。
完成标准
- [x] 实现及评审覆盖上述修改范围,未超出提交边界。
- [x] 行为验收:控制台隐藏不影响可见观众;观众隐藏暂停;旧 owner 先失效;关闭重开需显式继续;演讲计时与剩余时间分开。
- [x] 验证范围:挂载/状态集成和真实双窗口 E2E,关闭重开、重复命令、键盘与全屏回归。
- [x] 关联验收:A21、A22、A23;见联调与验收计划。
- [x] 记录代码版本、实际测试命令/结果、未运行项及原因,产物保存到任务专属临时目录。
- [x] 回填本卡状态与证据;阶段能力是否开放由对应阶段出口包决定,单包完成不等于整阶段交付。
建议提交标题:WP26:观众唯一调度与双窗口操作。通常按一个可评审 PR 实施;若实际改动仍过大,先按输入/输出再拆子包,保留父编号和依赖。
实施记录(2026-10-18)
- 唯一调度:观众窗口使用
usePlaybackHost({ autoStart: false })并由控制台命令启动;控制台只显示观众快照与剩余时间,不创建放映宿主。进入演讲模式先经会话登记的pausePlayback暂停普通窗口推进和媒体。 - 命令与交接:控制台命令携带
targetOwnerEpoch,旧观众窗口忽略;新观众ready后控制台回发快照。观众先加载时会针对控制台来源补发一次display-status与playback-state,避免控制台晚加载时永久未连接。关闭观众窗口后控制台保持暂停,重开只显示“开始放映”,需显式继续。 - 失效与去重:协议信封增加
role(console/display);观众窗口只接受控制台来源的导航/状态,控制台忽略低于当前观众 owner 的非权威状态。owner epoch 水位按角色隔离,避免观众 owner 数值高于控制台时阻塞后续命令;重复、旧 revision 与旧 owner 仍由 Receiver 拒绝。 - 可见性与全屏:只有观众窗口响应
visibilitychange暂停;控制台隐藏不触发暂停。观众重新可见不自动继续,恢复后按暂停剩余时间倒计时。全屏进入/退出只更新状态,播放进度与剩余时间不变;屏幕检测被拒时提供“当前窗口全屏”回退。控制台倒计时在状态变化时刷新本地时钟,不累计暂停时长。 - 验证:presenter 定向 8 files/40 passed;Runtime 全量 142 files/1098 passed/3 skipped;
pnpm --dir runtime check与改动文件 ESLint 通过。 - 真实 Chromium(Runtime 7373,双窗口,4s timer,同源 standalone):控制台先加载显示未连接且无命令;观众后加载连接并显式开始;自动翻页间隔 3947ms/8016ms,控制台跟随且无双重推进;控制台/观众键盘与页面按钮导航双方一致;控制台隐藏后观众继续自动翻页;观众隐藏暂停、4.5s 内不翻页、重新可见保持暂停且剩余 0:03,显式继续后不重置并完成翻页;全屏进入/退出剩余时间 0:04→0:03→0:03→0:02;关闭观众后回显“已关闭”并暂停,重开未显式开始 4.5s 内不翻页,开始后恢复自动翻页;注入重复/旧 owner/旧 revision 消息不改变路径;页面无运行时错误。
- 未运行:Firefox/WebKit 的媒体/全屏差异、移动端行内播放与远程设备控制不在本包范围;媒体模式双窗口与 A18–A20/A24 由 WP30 统一回归。
- 产物:
.tmp/wp26/browser/(evidence.json、run.mjs、routes.config.yaml、12 张截图)。 - 提交:
e1f3c42。
测试环境与命令选择遵循 dev-start-test,不因执行本卡重复启动服务或重置开发数据。