Kivy SoundLoader 如何判断音频是否真正加载成功?
结论
SoundLoader.load() 返回音频对象时,不能保证音频已经成功解码。对于题述 SoundGstplayer 情况,if sound: 只能确认拿到了音频对象,source 也只是保存的资源地址。
对于普通本地音频,length > 0 可以作为初步筛选条件,但不能严格证明文件完整、格式受支持且能够正常播放。要可靠处理加载失败,需要接收音频后端的错误通知,区分“准备完成”“失败”和“尚未确定”。
为什么文件不存在也会返回对象?
以 Kivy 2.3.1 的实现为例,SoundLoader.load() 根据文件扩展名查找 provider,找到后直接返回 classobj(source=filename);只有没有匹配的 provider 时才返回 None。因此,扩展名受支持,不代表文件内容一定能够解码。原问题没有说明版本,这里用该版本源码解释这一行为的原因。SoundLoader 源码
GStreamer 的部分错误通过消息回调传递,不会在调用 SoundLoader.load() 时作为 Python 异常抛出。对应版本的底层 GstPlayer 会将 GST_MESSAGE_ERROR 转交给 message_cb('error', ...),因此日志报错时,调用方仍可能持有对象。GstPlayer 源码
普通本地音频可以先做哪些检查?
可以先解析资源路径、检查文件是否存在,再检查是否创建了对象。如果业务只接受有明确正时长的短音频,还可以加上时长筛选:
import math
from pathlib import Path
from kivy.core.audio import SoundLoader
from kivy.resources import resource_find
def load_sound_candidate(filename):
resolved = resource_find(filename)
path = Path(resolved if resolved is not None else filename)
if not path.is_file():
raise FileNotFoundError(str(path))
sound = SoundLoader.load(str(path))
if sound is None:
raise RuntimeError("No audio provider accepted the file")
try:
length = sound.length
if (
length is None
or not math.isfinite(length)
or length <= 0
):
raise RuntimeError("No usable positive duration is available")
except Exception:
sound.unload()
raise
return sound
这个函数返回的是通过初步筛选的对象,并未验证整段音频能否解码,也无法捕获返回后发生的异步错误。
没有有效时长不一定说明文件损坏:可能是后端尚未准备好,也可能是资源没有可用的时长信息。即使能读到正时长,文件后半段仍可能损坏。
怎样获得更可靠的失败结果?
如果应用需要准确提示“文件不存在”“缺少解码器”或“解码失败”,应在实际使用的 provider 层处理错误,不要依靠解析终端日志。
对于 GStreamer 路径,可以封装或扩展 provider,将底层错误消息传给应用自己的错误回调。Kivy 2.3.1 的底层 GstPlayer 提供了 message_cb 构造参数,但这是后端接口,不能直接作为 SoundLoader.load() 的参数。采用这一方案时,需要核对实际安装版本的实现。GstPlayer 回调实现
处理流程应包括:
- 加载前检查本地路径,排除文件缺失。
- 启动后端加载或预加载,接收明确的错误消息。
- 根据后端提供的准备状态确认资源可用,不能用“暂时没报错”代替成功。
- 对迟迟没有结果的请求设置超时,并将其标记为未能确认就绪。
- 播放期间继续处理错误,因为预加载成功也不保证后续所有数据都可解码。
后端回调可能来自工作线程,更新 Kivy 界面时应通过 Clock 调度回主线程。处理音频事件也需要正常运行的事件循环。Kivy 音频事件说明
需要验证整个文件时怎么办?
如果要求在播放前检查整段文件,需要实际解码到结束。只检查文件是否存在、读取容器信息或获取时长,都达不到这一要求。
使用独立解码工具时,还要注意它与 Kivy 后端支持的格式可能不同。外部工具能够解码,只能证明该工具支持这个文件,不能保证当前 Kivy provider 也能播放。
对于题述问题,可以保留 sound is None 检查,并用时长做有限筛选。需要可靠的错误反馈时,应接入 GStreamer 后端的错误通知和准备状态,而不是单独寻找一个通用的 loaded 布尔属性。
备注:内容仅供参考。
