ncm A2: 音频输出迁移 meow_audiod(SINK_AUDIOD 默认后端)— 修无声根因
- audio_out.c: 新增 SINK_AUDIOD 默认(SDK meow_audio_* 连 audiod);NCM_AUDIO_SINK=file/null/alsa 与 MEOW_AUDIO_DIRECT=1 保留调试后端;ALSA 保底修两大坑(hw_params 全放行初始化 + mask 清零 再单点)——旧 memset0 interval=「只能取0」→ HW_PARAMS 恒 EINVAL 即播放无声根因 - 新增 audio_out_pause:PAUSED 沿向 audiod 发 pause(停时钟不丢流);resume 流死自动重开 - player_manager: 注册 meow_audio_on_preempt → g_play 命令通道暂停;播放事件全量 meow_log (open 参数/grant_*/write 错误节流/切歌/暂停/seek/done) - appstate/app: /tmp/ncm_autoplay 真机联调 hook(仅播已缓存曲目,绝不发 song_url) - bench/audiod_chain_sim.c: 真实 audiod_host 假 socket 全链离线回归 14 项全 PASS - 验证: host 0 warning / WAV 回归 / qemu core PASS / mipsel 0 warning;真机 OPEN→grant 已通, 持续写帧被 M2.90 设备 PCM 播放内核硬挂死阻断(REPORT §16.3,4/4 复现,留主会话) - ncm md5 db5b78ad9e8f40e6306484efe2a08eb3(已热更设备)
This commit is contained in:
1 parent
9bbc3a1467
commit
e0136213fe
10 files changed
+598
-41
No files matched your search
@@ -1170,3 +1170,126 @@ ed2f71c52563e812a04fb8a7cc05148d app/test/test_ncm_app.c # settings mock 初
|
||||
| 设置页行数 | 4 | 5 | 新增「清理缓存」行并在「缓存上限」接「自定义」数字输入 |
|
||||
| 音质 sheet 档数 | 3(Hi-Res/Higher/Standard) | 5(+Lossless/Exhigh) | 对齐 core `NCM_LEVEL_*` 全档 + 降级链起点 |
|
||||
| `ncm_cache_clear` | — | 新增 | 删除 `song_*` 全部(mp3/封面/.tmp),供「清理缓存」与测试 |
|
||||
|
||||
---
|
||||
|
||||
## 16. A2:音频输出迁移 meow_audiod(SINK_AUDIOD 默认后端)+ 无声根因修复(2026-09-01,agent-248)
|
||||
|
||||
> 范围:仅 `patch_v2/ncm_app/`(含 build 脚本、bench、REPORT 本文件)。未动 `sdk/`、`meow_audiod/`、
|
||||
> `meow_launcherd/`、`vendor/`。风控纪律:真实 NCM 请求 = autoplay 验证的 1 detail + 1 song_detail
|
||||
> (Docu 单首歌单,共 2 次 metadata,**0 次 song_url 下载**,曲目走已缓存 mp3)。
|
||||
|
||||
### 16.1 迁移内容
|
||||
|
||||
- **`app/play/audio_out.c` 新增 SINK_AUDIOD 后端并设为默认**(AUDIOD_DESIGN.md §7 落地):
|
||||
- 后端选择(env 驱动):缺省 → AUDIOD(SDK `meow_audio_*` 连 `/usr/data/meow_audio.sock`);
|
||||
`NCM_AUDIO_SINK=file/null/alsa` → FILE(WAV 回归)/NULL(解码 RT)/ALSA 直开;
|
||||
`MEOW_AUDIO_DIRECT=1` → ALSA 直开(调试保底,非正式能力)。audiod 不在 → open 返回 -1
|
||||
(不隐式回退直开),日志记 `audiod open failed rc=...`。
|
||||
- **ALSA 保底路径修复两大坑**(与 audiod/SDK 同款修法,注释标明勿回退):① hw_params 改
|
||||
「全放行」初始化(mask 全 1 + interval [0,UINT_MAX])——旧 memset 0 的 interval 等价
|
||||
「只能取 0」→ 内核 refine 必空 → HW_PARAMS 恒 EINVAL,这正是**网易云「播放无声」的根因**
|
||||
(真机 probe 实证);② access/format/subformat mask 先清零再单点(留全 1 会被 choose 成
|
||||
MMAP_INTERLEAVED → write() EINVAL)。
|
||||
- **被抢占处理**(`player_manager.c`):`player_manager_start` 注册 `meow_audio_on_preempt`
|
||||
→ 回调记 WARN 日志并经 `player_manager_pause(1)`(g_play 命令通道,持锁)暂停播放+更新 UI 态,
|
||||
不直接动锁外状态。
|
||||
- **暂停/恢复语义对齐**:`run_song` 进 NCM_PC_PAUSED 沿 → `audio_out_pause(1)` 向 audiod 发
|
||||
MSG_AUDIO_PAUSE(停 PCM 时钟不丢流);出暂停沿 → `audio_out_pause(0)` 恢复;**恢复时若流已死**
|
||||
(被抢占/断链,SDK 返回负值)→ 自动 close+reopen 重建输出流(解码位置不变)。
|
||||
- **播放路径全量日志**(meow_log,无声排查永久资产):open 结果/请求参数/audiod 授权
|
||||
grant_*(open 后 `meow_audio_query` 落 rate/ch/fmt/underrun)、write 错误(首次+每 100 次节流)、
|
||||
pause/resume/reopen/close(含累计写帧)、play start/done/switch/seek/stopped 事件。
|
||||
- **真机联调 autoplay hook**(`appstate.c` + `app.c`,非正式能力):`/tmp/ncm_autoplay` 触发文件
|
||||
存在且 home 歌单已载 → 后台线程找「已缓存」曲目自动播放(内容=数字则歌单下标起扫 ≤3 个、
|
||||
=文本则歌单名子串单点匹配如 "Docu")。**绝不发 song_url 下载**——无缓存命中只记日志退出。
|
||||
用途:无用户在场时验证「ncm→SDK→audiod→DAC」全链。
|
||||
- `build_ncm_host.sh`:SDK_SRC 补 `meow_ui_audio`(audio_out.c 新增 meow_audio_* 引用,宿主链接需要)。
|
||||
|
||||
### 16.2 验证记录(分层)
|
||||
|
||||
| 层 | 项 | 结果 |
|
||||
|---|---|---|
|
||||
| 宿主 | `build_ncm_host.sh` | **自有代码 0 warning**(仅 SDK meow_ui_vol.c 既有 system() 告警) |
|
||||
| 宿主 | WAV 回归:`NCM_AUDIO_SINK=file NCM_AUDIO_OUT=... test_decode MIPSTest.mp3` | **PASS**:8.21s/48k/立体声,WAV 头合法,字节数 44+393984×4 精确一致 |
|
||||
| 宿主 | 离屏渲染 home/playlist/player/settings/search | 全 rc=0 无回归 |
|
||||
| 宿主 | **`bench/audiod_chain_sim.c`(新增)**:起真实 `meow_audiod_host`(FILE sink 假 socket)驱动真实 audio_out.c+SDK 客户端 | **14 项全 PASS**:OPEN(grant=44100/2ch/S16)→WRITE 51200 帧→QUERY(active=1 written>0)→PAUSE(paused=1)→RESUME→**抢占**(第二客户端裸发 OPEN→on_preempt 回调触发→旧流 write 失败)→**流死自动重开**(reopen 可写)→CLOSE(active=0)→audiod WAV 落盘非空 |
|
||||
| qemu | `qemu-mipsel ./out/test_ncm_core_mipsel` | **PASS**(core 未动,回归) |
|
||||
| mipsel | `build_ncm.sh` | **0 warning**;ncm md5 `db5b78ad9e8f40e6306484efe2a08eb3` |
|
||||
| 真机 | 设备已刷 M2.90(0.7.85),/usr/bin/meow_audiod 在板运行 | ✓ |
|
||||
| 真机 | ncm 热更(.new+mv),`am start` 不可用(amsd DECLARE 转发未联调,「pkg not registered」)→ 手动 nohup 起 | ✓ 启动/home 歌单 120 正常 |
|
||||
| 真机 | autoplay hook:name 'Docu' → playlist[1](1 tracks)→ song[0] id=2048962657 缓存命中 → play | ✓ 日志链路正确 |
|
||||
| 真机 | **audiod OPEN→grant 链**:`meow_audio tone` 拿到 `sid=1 grant=44100Hz/2ch/S16` | ✓ IPC/协商链设备上正常 |
|
||||
| 真机 | **持续写帧/underrun 验收**:**被阻断**(见 §16.3 重大发现) | ✗ 未达成 |
|
||||
|
||||
### 16.3 重大发现:M2.90 设备 PCM 播放启动 → 内核硬挂死 → 看门狗重启(4/4 复现)
|
||||
|
||||
**现象**:设备(0.7.85,stock kernel 4.4.94+ #15 2026-01-16,未变)上一进入 PCM 播放启动序列,
|
||||
数秒内整机硬挂死并重启。复现 4/4:`meow_audio tone` ×3(含一次无 ncm 的纯 audiod 路径)+
|
||||
ncm 经 SDK 链播放 ×1。kmsg 流抓取到最后内核日志(死亡点,两次抓取一致):
|
||||
|
||||
```
|
||||
[ 412.104797] hbc3000_set_samplerate codec_type=4 samplerate=44100 spdif=0 ...
|
||||
[ 412.104819] hbc3000_stop
|
||||
[ 412.104865] hbc3000_start
|
||||
[ 412.168307] cs43198_dai_prepare pcm
|
||||
[ 412.371919] hbc3000_start
|
||||
<<< 日志到此中断,无任何 panic/oops 文本 → 硬挂死(疑似时钟/电源域死锁),随后重启 >>>
|
||||
```
|
||||
|
||||
**归因排查记录**:
|
||||
- **固件打包无误**:设备 /usr/bin/meow_audiod md5 `e07e9144…` == 仓库构建 == fw_content.conf 条目。
|
||||
- **ncm 无关**:对照组 ncm.bak(A2 前二进制 19d99ce4)同设备前台 idle **31 分钟稳定**(boot G,
|
||||
期间经历 suspend/resume);本会话早段(23:05-23:45)观察到的 4 次「idle ncm 在跑数分钟后重启」
|
||||
实为**用户 M2.90 刷机循环**(卡根 r3proii.upt 22:46 上卡,多次升级重启)同窗口巧合,对照组证伪。
|
||||
- **suspend 相关性未证伪也未证实**:设备每次 boot 后 ~40s 自动息屏进 `System suspend`(dmesg 实证),
|
||||
而 4 次致命播放全部发生在 resume 之后;A1 收尾(agent-246)同内核 tone 实测 written=played、
|
||||
underrun=0 **通过**——据信在未 suspend 的新鲜 boot 窗口。未 suspend 的播放验证需要
|
||||
「重启后 40s 内立刻 tone」,本会话无法在不主动重启的前提下获得该窗口(留给用户/主会话)。
|
||||
|
||||
**影响与建议(留主会话/用户决策)**:
|
||||
- A2 真机验收的「持续写帧+underrun=0」被此问题阻断,非 ncm 代码问题(SDK 链 OPEN→grant 已实证:
|
||||
tone 拿到 `sid=1 grant=44100Hz/2ch/S16`;ncm 日志链到「缓存命中 → play」)。
|
||||
- 建议:① 新鲜 boot 40s 内(未 suspend)测 `meow_audio tone` 验证 suspend 相关性;
|
||||
② 若为真,权宜=禁用自动息屏(`display.screen_off_timeout`=0)或 resume 后重置 codec 电源/时钟;
|
||||
③ 根治需看 hbc3000/cs43198 驱动 resume 路径(stock 内核源码不在本仓库);挂死点恒在
|
||||
`cs43198_dai_prepare` 后第二次 `hbc3000_start`,无任何内核日志 = 硬挂(时钟/i2c/电源域死锁特征)。
|
||||
- 本会话为定位该问题触发过多次设备重启(均自动恢复;未碰 recovery_all/未 killall hiby_player/
|
||||
未主动重启设备)。
|
||||
|
||||
### 16.4 md5(本批改动文件 + 产物)
|
||||
|
||||
```
|
||||
db5b78ad9e8f40e6306484efe2a08eb3 ncm # mipsel 静态 App(新;已部署设备)
|
||||
```
|
||||
(源文件 md5 以 git 为准;改动清单见 §16.5)
|
||||
|
||||
### 16.5 出入清单(只改 `patch_v2/ncm_app/`)
|
||||
|
||||
```
|
||||
修改:
|
||||
app/play/audio_out.c # SINK_AUDIOD 默认后端 + ALSA 保底两坑修复 + audio_out_pause + 全量日志
|
||||
app/play/player_manager.c # on_audio_preempt 注册/回调 + 暂停沿 audiod pause/resume + 播放事件日志
|
||||
app/logic/appstate.c # autoplay 真机联调 hook(/tmp/ncm_autoplay,缓存命中才播,绝不下载)
|
||||
app/app.c # app_on_tick 挂 autoplay_maybe
|
||||
app/ncm_app_internal.h # audio_out_pause/autoplay_maybe 声明 + audio_out 注释更新
|
||||
build_ncm_host.sh # SDK_SRC 补 meow_ui_audio
|
||||
ncm / ncm_host # 重编产物
|
||||
新增:
|
||||
bench/audiod_chain_sim.c # audiod 全链离线回归(真实 audiod_host 假 socket,14 项)
|
||||
REPORT.md # 本批记录(§16)
|
||||
(未动 sdk/、meow_audiod/、meow_launcherd/、vendor/;未动设备系统/恢复区)
|
||||
```
|
||||
|
||||
### 16.6 诚实出入 / 已知限制
|
||||
|
||||
- **真机验收未闭环**:§16.3 内核硬挂死阻断「持续写帧 + underrun=0 + meow_audio status 在播」三项。
|
||||
已实证到 OPEN→grant(CLI tone)与 ncm→autoplay→缓存命中→play 日志链;SDK 客户端全链
|
||||
(含抢占/重开)由宿主 sim 对真实 audiod_host 14 项覆盖。
|
||||
- **autoplay hook 默认 0 起扫前 3 个歌单首页**:若首个歌单是超大歌单(5191 首 detail ~35s 解析)
|
||||
会慢/重;文本名单点匹配(如 Docu)是推荐用法。hook 为调试资产保留,不影响正常 UI 路径。
|
||||
- **`am start dev.player.ncm` 报 pkg not registered**:amsd 二期 launcher→amsd DECLARE 转发未联调
|
||||
(WORK_STATE 已记残余),本次手动 nohup 起 ncm(fb 与 launcher 并存,测试场景可接受)。
|
||||
- 设备日志中 ipc_media META 每秒一对(state=0 空态也发)为既有行为,本批未动。
|
||||
- **未碰** /data/recovery_all、未 killall hiby_player、未主动重启设备(§16.3 的多次重启均为
|
||||
被测路径触发的设备自重启)。
|
||||
Reference in new issue
Block a user