Repository navigation
Description
由 wayfinder 地图 #75 的 #76–#84 九张票的 linked decisions 折叠而成;地图已于 2026-11-07 关闭。
完整规格是doc/player-state-contract.md(§1–§10),唯一 ADR 是 0004。
本 issue 是面向实现、可独立阅读的建设计划,不是地图;决策的完整依据仍在各票的 resolution comment。
实现属图外新 effort:本 spec 之后走/to-tickets拆垂直切片 →/implement-spec在 integration branch 上实现。
Problem Statement
soundbridge::Player 的公开契约一直靠实现隐式决定:公开头对回调线程 / 顺序 / 重入零注释;两条错误路径的 state 与 error 先后不一致;position 回调经二次 asyncRunTask 回投 priority_queue,同刻不保证 FIFO;durationMs == 0 时 seek 的「显式 INVALID_OPERATION」在 void API 上根本无法表达;播放列表错误路径的自动跳轨判据与解码路径不一致。这些空白让调用方(含 app)只能猜,且没有任何一条契约是可红可绿的判据。
Solution
把已裁定的八项决策落成代码内注释 + 生产链最小改动 + 可判定用例,不引入新状态机、不改任何公开签名:
| 编号 | 内容 |
|---|---|
| C1 | 两条错误路径统一为 error→state;skip 失败补一次状态事件 |
| C2 | position 二次 asyncRunTask 保证同曲目会话内单调不回退 |
| C3 | player.h 加注释:线程 / 重入 / 异常 / 所有权 / 停机期(建议文本见规格 §10.2) |
| C4 | durationMs==0 的 seek 空操作与「无新回调」判据用例 |
| C5 | 播放列表错误路径是否补 ErrorAction::SkipTrack 检查(规格 §6.3 登记项) |
| C6 | 回调顺序 / 幂等 / 必须上报清单的补强用例(不改既有数值) |
决策要点:保持三态;回调承诺 SDK 内单一串行线程同步发出、marshal 归调用方、曲目三连固定、错误统一 error→state、回调内禁发命令 / 析构 / 抛异常;七个入口保持 void,被丢弃命令不产生回调也不改查询值;查询是真相源、回调是变更通知;INVALID_OPERATION 是内部降级码不对外暴露,duration() == 0 是唯一「不可 seek」信号。
User Stories
- 作为 SDK 接入方,我想从公开头直接读到回调的线程 / 重入 / 所有权约束,不用读实现。
- 作为 SDK 接入方,我想在任何错误下都先收到原因、再看到状态变化,且 autoSkip 跳轨成功时不会收到一个撒谎的状态。
- 作为 UI 作者,我想 position 回调在同一曲目内单调不回退、换曲时归零,不会因队列同刻无序而倒退。
- 作为 UI 作者,我想只用
duration() == 0就判断不可 seek,不需要额外能力位。 - 作为测试作者,我想三态边界、回调三连、幂等、上报清单、时长为零的空操作都有可红可绿的判据。
- 作为维护者,我想这些改动不触碰坏输入 55 例与覆盖度基线、不新增 CI gate。
Implementation Decisions
- 生产链改动集中在错误上报顺序、position 回调的单调钳制、以及播放列表错误路径的口径统一;公开签名与状态机结构不变。
- 注释文本按规格 §10.2 原样落地(线程 / 重入 / 异常 / 所有权 / 停机期五条),不额外扩写 API 文档或时序图。
- C5 是登记项:以「统一到与解码路径相同的
ErrorAction::SkipTrack口径」为推荐,但以不使坏输入基线变红为硬边界;若两者冲突,保留现状并在票里写清理由。 INVALID_OPERATION保持sdk_utils::status_t = -ENOSYS的内部降级语义,不进公开ErrorCode、不经onError。
Testing Decisions
- 好测试只断言外部可见行为(回调序列、查询值、状态序列),不断言内部队列调度。
- 沿用既有接缝:
sdk/test/mocks/PlayerMocks.hpp的回调记录器、sdk_player_tests/sdk_unit_tests/sdk_interaction_tests三个分组;优先扩展既有记录器而不是新建 mock。 - 既有数值判据原样复用;重入 / 所有权 / ABI 类只写注释与规格,不做最小可测替身(回调内发命令会自锁)。
Out of Scope
- app UI 重设计与
PlayerViewState重构、API 文档 / 时序图 / CLI 接入示例、错误码体系重构。 - 网络流 / 边下边播 /
IAudioSink/ 格式扩展;端到端 drift 与观测指标判据。 - 状态机改写、公开签名变更、新增错误码、CI 分组与 TIMEOUT 调整。
Further Notes
- 契约漂移的长期观测口径仍属后续 effort;若像 [T13] CI 观测与端到端 drift 记录 #68 的 StreamingBudget 一样只记录不设门槛,须写明「不作为失败门禁」。
- 跨平台改动必须等 Linux
sdk-coverage绿,本地 Windows 全绿不算完成。 - 实现清单见规格 §10.1;本批票以
[Tnn]前缀编号,阻塞边用 GitHub 原生依赖关系。
Activity
docs: 回填实现清单落地记录与审查结果(#92 / T07)
wt159 commentedon Nov 8, 2026
Spec 完成(2026-11-08)
doc/player-state-contract.md§10.1 的 C1–C6 已全部落地,执行票 #86–#92 逐票关闭并在各自 resolution comment 留完整依据。implement/player-state-contract(9 提交)→ PR feat: 播放器状态与公开 API 契约落地(C1–C6 / #85–#92) #93 → master。ctest -j414/14;审查修复后 14/14(59.6s),含坏输入四段与覆盖度。code-review,4 Major + 4 Minor 在一个修复提交里全部处理。void,无新增错误码 / 状态机 / 状态值,既有容差数值、坏输入 55 例、14 个目标与 TIMEOUT 全部未动。遗留:契约漂移观测口径交后续 effort;C1 顺序与 C5 设备错误不跳轨缺端到端判据(原因见规格 §10.4)。
Merge pull request #93 from wt159/implement/player-state-contract