apppublic/aidocs/audioplayer.md
2025-10-05 11:23:33 +08:00

280 lines
6.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# `AudioPlayer` 技术文档
基于 `ffpyplayer` 的 Python 音频播放器类,支持加载音频文件、播放控制(播放/暂停/停止)、循环播放、音量调节和事件回调等功能。
---
## 📦 概述
`AudioPlayer` 是一个轻量级的音频播放器封装类,利用 `ffpyplayer` 库实现对本地音频文件的播放控制。该类提供了简洁的接口用于常见操作,如播放、暂停、跳转、循环等,并支持自定义事件处理。
---
## 🧩 依赖库
- `ffpyplayer`: 多媒体播放后端(基于 FFmpeg
- `time`: 用于时间相关操作
```bash
pip install ffpyplayer
```
> ⚠️ 注意:`ffpyplayer` 在某些平台上可能需要手动编译或安装预构建版本。
---
## 🧱 类定义
### `class AudioPlayer(source=None, autoplay=False, loop=False, on_stop=None)`
初始化一个音频播放器实例。
#### 参数说明:
| 参数 | 类型 | 默认值 | 描述 |
|------|------|--------|------|
| `source` | `str``None` | `None` | 音频文件路径(可选,在初始化时设置或后续通过 `set_source()` 设置) |
| `autoplay` | `bool` | `False` | 是否在加载音频后自动开始播放 |
| `loop` | `bool` | `False` | 是否启用循环播放模式 |
| `on_stop` | `callable``None` | `None` | 当音频停止时调用的回调函数 |
---
## 🔧 属性列表
| 属性名 | 类型 | 描述 |
|--------|------|------|
| `volume` | `float` | 当前音量(范围 0.0 ~ 1.0),默认为 `1.0` |
| `state` | `str` | 当前状态:`'play'`, `'pause'`, `'stop'` |
| `source` | `str` | 当前音频源路径 |
| `quitted` | `bool` | 标记是否已请求退出(内部使用) |
| `loop` | `bool` | 是否开启循环播放 |
| `autoplay` | `bool` | 是否自动播放 |
| `player` | `MediaPlayer` 实例或 `None` | `ffpyplayer.player.MediaPlayer` 对象 |
| `on_stop` | `callable``None` | 停止播放时触发的用户回调函数 |
| `cmds` | `list` | (预留)命令队列(当前未使用) |
---
## 📚 方法说明
### `set_source(source: str)`
设置音频源并立即加载。
**参数:**
- `source` (str): 音频文件路径
**行为:**
- 更新 `self.source`
- 调用 `load()` 加载新资源
---
### `load() -> None`
加载当前 `source` 指定的音频文件。
**逻辑流程:**
1. 若无 `source`,直接返回。
2. 卸载已有播放器(调用 `unload()`)。
3. 创建新的 `MediaPlayer` 实例,配置选项:
- `vn=True`: 禁用视频流
- `sn=True`: 启用字幕流(不影响音频)
4. 使用 `callback``loglevel='info'`
5. 等待最多 10 秒获取音频元数据(尤其是 duration
6. 初始暂停播放器以准备控制
7. 设置音量
8.`autoplay=True`,则调用 `play()`
> ⚠️ **注意**:此方法包含阻塞等待(最大 10s用于确保能读取到音频时长信息。
---
### `unload() -> None`
释放当前播放器资源,重置状态。
**效果:**
- 清空 `player`
- 设置状态为 `'stop'`
- 重置 `quitted` 标志
---
### `__del__()`
析构函数,确保对象销毁时调用 `unload()`
---
### `play() -> None`
开始播放音频。
**行为:**
- 若尚未加载,则先调用 `load()`
- 若已在播放状态,直接返回
- 否则调用 `toggle_pause()` 并更新状态为 `'play'`
---
### `pause() -> None`
暂停播放。
**行为:**
- 若未加载,尝试加载
- 若已在暂停状态,不执行操作
- 否则调用 `toggle_pause()` 并更新状态为 `'pause'`
---
### `stop() -> None`
停止播放,重置播放位置至开头。
**行为:**
- 如果正在播放,先暂停
- 将播放进度跳转至 0`seek(0)`
- 更新状态为 `'stop'`
- 触发 `on_stop` 回调(如果存在)
---
### `seek(pos: float) -> None`
跳转到指定时间点(单位:秒)。
**参数:**
- `pos` (float): 目标时间位置(绝对时间)
**示例:**
```python
p.seek(30.0) # 跳转到第30秒
```
---
### `get_pos() -> float`
获取当前播放时间(单位:秒)。
**返回:**
- 当前播放时间戳PTS若无播放器则返回 `0`
---
### `is_busy() -> bool`
判断是否正在播放中。
**返回:**
- `True` 表示处于 `'play'` 状态且有有效播放器
- `False` 表示暂停或停止
---
### `player_callback(selector: str, value: any)`
内部回调函数,由 `ffpyplayer` 触发。
**触发事件:**
- `'quit'`: 播放器退出 → 调用 `close()` 清理资源
- `'eof'`: 播放结束 → 调用 `_do_eos()`
> ✅ 日志输出可用于调试。
---
### `_do_eos(*args) -> None`
处理播放结束End of Stream事件。
**行为:**
- 若启用 `loop`,则跳回开头继续播放
- 否则调用 `stop()` 结束播放
---
## 🎯 使用示例
### 基本使用
```python
from audio_player import AudioPlayer
def on_audio_stopped():
print("音频已停止")
# 初始化播放器
player = AudioPlayer(
source="music.mp3",
autoplay=True,
loop=True,
on_stop=on_audio_stopped
)
# 控制播放
player.play()
time.sleep(5)
player.pause()
player.seek(10.0) # 跳转到第10秒
player.play()
# 查询位置
print(f"当前时间: {player.get_pos()}s")
# 停止
player.stop()
```
### 手动交互式控制(主程序示例)
运行脚本时传入音频路径:
```bash
python audio_player.py /path/to/audio.mp3
```
交互命令:
- `play` — 开始播放
- `pause` — 暂停
- `stop` — 停止并归零
- `quit` — 退出程序
---
## ⚙️ 内部机制说明
### 播放器初始化选项 (`ff_opts`)
```python
ff_opts = {'vn': True, 'sn': True}
```
- `vn=True`: 忽略视频流(仅音频)
- `sn=True`: 启用字幕流(不影响播放)
### 元数据加载等待机制
使用 `time.perf_counter()` 最多等待 10 秒以获取 `duration`,避免因媒体分析过慢导致后续操作失败。
### 状态管理
通过 `self.state` 维护播放状态机,防止重复操作。
---
## ❗ 已知限制与注意事项
1. **线程安全**:未考虑多线程并发访问,建议在单线程环境中使用。
2. **异常处理**:缺少对无效文件路径、格式不支持等情况的捕获,需外部保障输入合法性。
3. **资源释放**:虽然有 `__del__`,但推荐显式调用 `unload()` 或及时删除引用。
4. **性能**`load()` 中的循环等待可能导致短暂阻塞 UI适用于非 GUI 场景)。
5. **日志级别**:固定为 `'info'`,可通过扩展参数暴露配置。
---
## 🛠️ 扩展建议
- 添加音量控制接口(如 `set_volume()`
- 支持获取总时长 `get_duration()`
- 引入事件系统替代硬编码回调
- 支持网络流媒体 URL
- 增加错误处理与异常通知机制
---
## 📄 许可与版权
本代码基于 MIT 或类似自由许可发布(具体取决于 `ffpyplayer` 的使用条款)。请遵守其开源协议。
---
> 文档版本v1.0
> 最后更新2025年4月5日