just_audio 播放某个文件失败
今天遇到一个十分灵异的问题,使用just audio在macOS上面播放 school.mp3 这个文件的时候死活都会抛异常。
await _player.setAsset('assets/audio/school.mp3'); |
每次都是:flutter: Error playing audio: (-11849) Operation Stopped。
首先想到的就是这个文件发生的错误,于是就重新生成了一个,结果依然是同样的错误。在调试过程中就发现了一些诡异的事情:
- 只要把这个
school.mp3文件改成另外一个文件名,就可以正常播放。 - 其他可以正常播放的文件改成这个
school.mp3文件名就无法播放。
在 Antigravity 中,把这些情况告诉 AI,Claude Opus 4.5 (Thinking) 和 Gemini 3 Pro (High) 都无法解决。Opus 运行了一堆 ffmepg 的命令检查这个文件, 最后干脆一直显示 thinking,不回来了。
于是在网页Gemini中继续提问。 把上面的错误信息丢给它,告诉它只有 school.mp3 无法播放。对于错误代码,它马上给出了解释:
错误代码
(-11849)在 macOS 和 iOS 开发中属于 AVFoundation 错误,对应的描述通常是AVErrorContentUnsupported或类似的路径/格式加载失败。
这个 Antigravity 也是这样说的,这部分应该属于标准错误。
网页 Gemini 第一次给出的尝试是怀疑AssetManifest.json:
当你添加、删除或重命名资源时,Flutter 虽然会更新自己的
AssetManifest.json,但 macOS 的宿主工程(Runner.app)有时会产生僵尸引用。它认为school.mp3还在旧的位置,或者试图从一个已经失效的缓存索引中读取它。改名成school_1.mp3会迫使系统创建一个全新的文件索引,从而绕过了错误的旧缓存。
它给出的解决方案是看能否读取到数据:
ByteData data = await rootBundle.load('assets/audio/school.mp3'); |
很不幸,读取成功。然后它开始怀疑 扩展属性,这个也被证明没有关系。
然后我告诉它:把其他文件改为 school.mp3,也会无法播放。它立刻给出了三个原因。
Gemini:
- 宿主 App 的沙盒缓存死锁 (最可能)
- 隐藏的 Entitlements 权限冲突
- Just Audio 的内部代理缓存
我首先尝试了第三个,用它给出的代码
await player.setAsset('assets/audio/school.mp3', preload: false); // 禁用预加载 |
结果卡死在后续的 play 上。
Gemini:
卡在
await _player.play()且无法返回,进一步证实了这是一个底层死锁(Deadlock)。请按以下三个步骤进行最后的排查:
- 终极手段:重置 macOS App 容器(沙盒)
- ……
- ……
我没看下面两个,直接尝试终极手段:
rm -rf ~/Library/Containers/your.bundle.id |
结果无法删除,上 sudo 也不行:Operation not permitted。
Gemini:
在 macOS 上,如果你对自己的
Containers目录执行rm -rf却提示Operation not permitted,通常意味着:
- 系统级锁死: 某个系统进程(如
birdiCloud 同步、mds聚焦索引,或者最可能的——**AVFoundation的音频服务进程**)正牢牢勾住这个文件夹里的某个资源。- SIP 或 TCC 保护: 你的终端(Terminal/iTerm2)没有“完全磁盘访问权限”。
Gemini:
第一步:给终端“最高权力”
第二步:尝试在 Finder 中删除,直接按Command + Delete移到废纸篓。
第三步:重启coreaudiod(音频服务重置):sudo killall coreaudiod
第四步:修改 Bundle ID (终极绕路方案)
我试了第二步+第三步,问题解决!Gemini 的总结是:
果然还是“物理超度”(直接删掉整个沙盒容器)最管用。
总结一下这次“灵异事件”的本质:
- 路径诅咒: 你的 macOS 系统音频服务(
coreaudiod)在之前的某次运行中,因为某种原因对school.mp3这个路径产生了死锁。- 缓存持久化: 即使你重新运行 Flutter、执行
flutter clean,由于 macOS 容器(Containers)是持久存在的,那个损坏的路径状态一直被保留在系统底层的AVFoundation缓存里。- 权限锁死: 甚至连
rm -rf都被拒绝,说明当时系统进程确实正死死地“咬着”那个文件夹。
通过 Finder 强制删除 加上 重启音频服务,你相当于给 macOS 的音频引擎做了一次“全脑格式化”,它终于忘记了那个让它卡死的school.mp3。
沙盒缓存死锁我还是第一次遇到——第一次听到。我看了一眼,用的是 Gemini 3,Fast 选项。
现在的问题是,我 Android 手机上也是这个 school.mp3 无法播放——为什么会是同一个文件?