docs(ncm §25): REPORT 根因/修法/测试证据/新ncm md5(commit a01e5ca 配套)
§25 记录切音质后重播同曲恒「缓冲中」:根因(player_manager.c 同 idx 新 play intent 不被解码主循环识别)、修法(seq 化 intent 护栏 still_intent + 解码主循环 seq 断 + 外层自然播完收紧 state==PLAYING)、测试证据(player_flow_sim 新 P12 + P1-P11 零回归 + stream_sim 全矩阵)、新 ncm md5 28698dd0e。用户所问「歌单离线缓存/手动刷新」顺带核实: 离线缓存未落地(appstate_load_playlists 每次网络拉取),手动刷新已落地。
This commit is contained in:
1 parent
a01e5ca18a
commit
a5f675750b
1 file changed
+74
@@ -2318,3 +2318,77 @@ e767bb75b7f7ec096b9c9dc01791691d REPORT.md # 本批记录(§24)
|
||||
- 重试仅覆盖「预缓冲(<128KB)前网络失败」;开播后失败不重连(§4.1)。`STREAM_RETRY_BACKOFF_MS=800`
|
||||
为固定值,未做指数退避多档(retry=1 时一档即可)。
|
||||
- 未动 sdk/、meow_launcherd/、vendor/;部署链路同 §13.5 留主会话。
|
||||
|
||||
## 25. 修复:切音质后重播同一曲恒「缓冲中」——同 idx 再 play 未重启换档(2026-09-01,commit `a01e5ca`)
|
||||
|
||||
> 范围:仅 `patch_v2/ncm_app/`。真机用户反馈:切音质后再播同一首歌,声音已喷出但播放页
|
||||
> 「采样率/格式信息」处恒显示「缓冲中」。风控:真实 NCM 请求 **0 次**(全离线 stub);未部署真机(留主会话)。
|
||||
|
||||
### 25.1 根因(文件:行)
|
||||
|
||||
`app/play/player_manager.c`:**同 idx 的新播放意图不被解码主循环识别**——旧 `still_current`
|
||||
(原 L297-303)与解码主循环(原 L564-577)只认 `cur_song != idx` 与 `state == STOPPED`。
|
||||
|
||||
切音质后重播同一曲 = `player_manager_play(idx)`,而该 idx 恰与在播曲相同,于是 `play` 只改了
|
||||
`player_manager.c` L100 `g_play.seq++`、L95 `g_play.state=BUFFER`,`cur_song` 不变。解码主循环
|
||||
每轮比对 `cur != idx`(不变→不 break)与 `st == STOPPED`(BUFFER→不 break),导致:
|
||||
|
||||
1. **旧曲(旧档位)继续喷声**(audio 写照旧走),而 `g_play.state` 停在 `BUFFER` → UI
|
||||
`plr_draw_cover_dyn` 读 `player_manager_state()==BUFFER` → 恒「缓冲中」(`app/ui/player.c` L268-281);
|
||||
`dl_done/dl_total` 保持 0,缓冲文案退化为无 %、无 KB 的「缓冲中…」(L279)。
|
||||
2. **新档位下载/缓存条目从未发起**(换档 = 新缓存键 `song_<id>_<level>`,本应走新下载)。
|
||||
3. 旧曲播完后外层线程把 `BUFFER` 当「自然播完」→ `player_manager_next(1)`(原 L693)→ **顺延
|
||||
下一首**,新档位永不生效。
|
||||
|
||||
`still_current` 同理漏判:同 idx 重播时 `cur==idx && state==BUFFER` 恒真,下载/预缓冲/物化/
|
||||
解码各护栏均不终止旧 intent。三条路径(缓存命中/边下边播/.part 续传)统一受影响——根因在
|
||||
播放意图层,不在某条取数路径。
|
||||
|
||||
### 25.2 修法(play intent 以 seq 标识,层层判别)
|
||||
|
||||
- 新增 `still_intent(idx, my_seq)`(`player_manager.c` L306):
|
||||
`cur==idx && state==BUFFER && seq==my_seq`——严格强于旧 `still_current`(同 idx 重播时 seq 变
|
||||
即判过期),替换全部 `still_current` 调用点。
|
||||
- `run_song` 入口捕获 `my_seq`(L509),沿 `song_local_file`(L424)/`song_download_attempt`
|
||||
(L319)下传,预缓冲(L386)/重试退避(L482)/物化(L522)/预缓冲后(L540)/解码 open 失败
|
||||
(L556)各护栏改 `still_intent(idx, my_seq)`。
|
||||
- **解码主循环**(L597):`seq != my_seq`(同 idx 新 intent)→ `break` 回外层重跑 `run_song`
|
||||
(换档重播),不再静默续播旧档。
|
||||
- **外层线程**「自然播完」收紧为 `st2 == NCM_PC_PLAYING`(L720):不再把 `BUFFER`(挂起的新
|
||||
intent)当「播完」顺延下一首;同 idx 新 intent 落外层后按当前 `cur/state` 重跑 `run_song(idx)`。
|
||||
|
||||
### 25.3 测试证据(0 真实 NCM 请求)
|
||||
|
||||
| 项 | 方式 | 结果 |
|
||||
|---|---|---|
|
||||
| 状态机回归 | **player_flow_sim P1-P11 全量**(缓存命中/下载/.part 续传/重试/门禁,0 网络) | 宿主 + qemu-mipsel **ALL PASS**(零回归) |
|
||||
| 本 bug 复现 | **player_flow_sim 新 P12**(§25):standard 档缓存命中播 song0 → 切 lossless → 同 idx 再 play | 宿主 + qemu **ALL PASS**:状态回 PLAYING、新档位下载发起(downloads=1)、缓存键 `1000_lossless`、eff_level 按非会员钳顶回填 EXHIGH(UI 据此显示实际档位,不再停 BUFFER「缓冲中」)。修前 P12 断言 FAIL(恒 PLAYING 不了、键仍 `1000_standard`、downloads=0、eff=-1) |
|
||||
| 边下边播全矩阵 | stream_sim 原 16 用例 + 2 resume(PCM 金标准) | 宿主 **ALL PASS**(后台任务复核;player_manager 未动 stream_src 链,理论零影响) |
|
||||
| core 回归 | test_ncm_core_host + qemu test_ncm_core_mipsel | PASS |
|
||||
| mipsel 构建 | build_ncm.sh 自有代码 -Wall -Wextra | **0 warning**(set -e 下任何告警即失败) |
|
||||
| 宿主离屏 | build_ncm_host.sh + NCM_PAGE=player MEOW_UI_DUMP | rc=0、渲染正常(仅 sdk `meow_ui_vol.c` 既有告警,与本批无关) |
|
||||
|
||||
**状态→UI 对应**:`plr_draw_cover_dyn`(`app/ui/player.c` L268)按 `player_manager_state()` 直判
|
||||
——`BUFFER` 画「缓冲中…N%」、否则画时间行/采样率。P12 断言 `state==PLAYING` 即等于「UI 显示
|
||||
采样率/时间而非缓冲中」。三条路径的 BUFFER→PLAYING 转换分别由 P1(缓存命中)、P6/P7(边下边播
|
||||
下载)、P9(.part 206 续传)覆盖,P12 补同 idx 重播(换档)路径。
|
||||
|
||||
### 25.4 顺带核实(用户问,未改)
|
||||
|
||||
- **歌单列表「离线缓存」:未落地**——`appstate_load_playlists`(`app/logic/appstate.c` L144)
|
||||
每次进入/刷新都走 `ncm_api_user_playlist` 网络拉取(存 `g_st.playlists[]` 内存),无磁盘离线
|
||||
缓存;断网时返回错误、列表空态。歌曲级元数据有落盘(songmeta,滑窗出窗不丢),但「我的歌单」
|
||||
列表本身无持久化。
|
||||
- **手动刷新按钮:已落地**——home topbar 刷新动作(↻ action0)→ `home_reload()`(`app/ui/home.c`
|
||||
L221/L253,后台 worker 非阻塞);歌单详情页 `playlist_refresh()`(`app/ui/playlist.c` L263)重拉当前页。
|
||||
|
||||
### 25.5 md5(本批产物)
|
||||
|
||||
```
|
||||
28698dd0e097c3de73b243de1dae5417 ncm # mipsel 静态 App(新;未部署,留主会话)
|
||||
26480e69c258d56e17464adf0141d21e ncm_host # 宿主离屏调试二进制(重链)
|
||||
fe6302544ae8e09eb340b257b2731e71 app/play/player_manager.c # §25:seq 化 intent 护栏 + 解码主循环重启
|
||||
d9bfe3d7a6eaa76b00161a4e97196eb8 bench/player_flow_sim.c # 新 P12:同 idx 重播换档重启断言
|
||||
```
|
||||
|
||||
(`REPORT.md` 追加 §25;`WORK_STATE.md` 同步锚点见 devdocs。)
|
||||
Reference in new issue
Block a user