本文档引用的文件
音频播放系统是一个基于UniApp框架构建的移动端音频播放解决方案,支持TTS文本转语音、章节音频播放、播放列表管理、进度记录与恢复等功能。系统采用前后端分离架构,前端使用Vue3 + Pinia状态管理,后端使用Koa框架和Prisma ORM。
该系统主要面向AI有声书场景,提供完整的音频播放体验,包括播放控制、列表管理、进度跟踪、后台播放支持等核心功能。
音频播放系统的项目结构采用模块化组织方式:
graph TB
subgraph "前端 (my-uniapp-vue3)"
A[src/store/audio.ts - 音频状态管理]
B[src/pages/player/index.vue - 播放器页面]
C[src/components/MiniPlayer.vue - 迷你播放器]
D[src/types/index.ts - 类型定义]
end
subgraph "后端 (server)"
E[src/modules/player/player.controller.ts - 播放器控制器]
F[src/modules/player/player.service.ts - 播放器服务]
G[src/services/websocket.service.ts - WebSocket服务]
H[src/modules/tts/audio-merger.ts - 音频合并器]
I[prisma/schema.prisma - 数据库模型]
end
subgraph "数据库"
J[PlayRecord - 播放记录表]
K[BookChapter - 章节表]
L[User - 用户表]
end
A --> B
B --> E
E --> F
F --> I
G --> B
H --> F
I --> J
I --> K
I --> L
图表来源
章节来源
音频状态管理是整个播放系统的核心,负责维护播放器的各种状态和行为:
后端播放器控制器提供RESTful API接口:
播放器服务层负责数据持久化和业务逻辑:
章节来源
系统采用分层架构设计,确保关注点分离和代码可维护性:
graph TB
subgraph "表现层 (Presentation Layer)"
UI[播放器UI组件]
Mini[迷你播放器组件]
end
subgraph "应用层 (Application Layer)"
Controller[播放器控制器]
Service[播放器服务]
WebSocket[WebSocket服务]
end
subgraph "领域层 (Domain Layer)"
AudioMerger[音频合并器]
PlayRecord[播放记录模型]
BookChapter[章节模型]
end
subgraph "基础设施层 (Infrastructure Layer)"
Prisma[Prisma ORM]
MySQL[MySQL数据库]
FFmpeg[FFmpeg处理]
end
UI --> Controller
Mini --> Controller
Controller --> Service
Service --> AudioMerger
Service --> PlayRecord
Service --> BookChapter
Service --> Prisma
Prisma --> MySQL
AudioMerger --> FFmpeg
WebSocket --> UI
图表来源
音频播放控制机制通过Pinia状态管理实现,提供完整的播放生命周期管理:
sequenceDiagram
participant UI as 播放器UI
participant Store as 音频Store
participant AudioCtx as 音频上下文
participant API as 后端API
UI->>Store : play(audio)
Store->>Store : initAudioContext()
Store->>AudioCtx : 创建InnerAudioContext
Store->>AudioCtx : 设置事件监听器
Store->>AudioCtx : 设置音频源URL
Store->>AudioCtx : 开始播放
AudioCtx->>Store : onTimeUpdate
Store->>Store : 更新currentTime和duration
AudioCtx->>Store : onEnded
Store->>Store : 处理播放模式
Store->>API : 保存播放进度
UI->>Store : pause/resume
Store->>AudioCtx : 暂停/继续播放
UI->>Store : seek(time)
Store->>AudioCtx : 跳转到指定位置
图表来源
系统支持四种播放模式,每种模式都有特定的行为逻辑:
| 播放模式 | 行为描述 | 实现要点 |
|---|---|---|
| 顺序播放 (sequence) | 按列表顺序播放,播放完不自动下一首 | 基础播放模式,不自动切换 |
| 列表循环 (loop) | 播放到最后一首后回到第一首 | 检查边界条件,循环播放 |
| 单曲循环 (single) | 重复播放当前歌曲 | 重新播放当前音频 |
| 随机播放 (random) | 随机选择下一首播放 | 生成随机索引,更新currentIndex |
章节来源
播放列表管理提供了灵活的音频组织和导航能力:
flowchart TD
Start([开始播放]) --> CheckPlaylist{检查播放列表}
CheckPlaylist --> |有播放列表| LoadPlaylist[加载播放列表]
CheckPlaylist --> |无播放列表| FetchGeneric[获取通用播放列表]
LoadPlaylist --> SetCurrent[设置当前音频]
FetchGeneric --> SetCurrent
SetCurrent --> InitAudio[初始化音频上下文]
InitAudio --> PlayAudio[开始播放]
PlayAudio --> NextCheck{检查下一首}
NextCheck --> |有下一首| PlayNext[播放下一首]
NextCheck --> |无下一首| ModeCheck{检查播放模式}
ModeCheck --> |单曲循环| SingleLoop[单曲循环]
ModeCheck --> |列表循环| LoopPlaylist[列表循环]
ModeCheck --> |随机播放| RandomPlay[随机播放]
ModeCheck --> |顺序播放| Stop[停止播放]
PlayNext --> PlayAudio
SingleLoop --> PlayAudio
LoopPlaylist --> PlayAudio
RandomPlay --> PlayAudio
图表来源
播放列表使用统一的AudioItem接口,支持多种音频来源:
interface AudioItem {
id?: string | number;
_id: string;
audioId?: string;
title: string;
text: string;
audioUrl: string;
audioDuration: number;
wordCount: number;
isFavorite: boolean;
albumId?: string;
albumName?: string;
lrcLyrics?: string;
}
章节来源
进度记录系统提供了完整的播放进度跟踪和恢复功能:
sequenceDiagram
participant Audio as 音频播放器
participant Store as 状态管理
participant API as 后端API
participant DB as 数据库
Audio->>Store : onTimeUpdate
Store->>Store : 更新currentTime
loop 每30秒
Store->>API : POST /player/progress
API->>DB : 保存播放进度
DB-->>API : 确认保存
API-->>Store : 返回保存结果
end
Note over Audio,DB : 用户重新打开应用时
Audio->>API : GET /player/progress
API->>DB : 查询播放进度
DB-->>API : 返回进度记录
API-->>Audio : 返回最近播放进度
Audio->>Store : 恢复播放状态
Audio->>Audio : 从上次位置继续播放
图表来源
播放记录使用PlayRecord模型,支持用户级别的进度跟踪:
erDiagram
PLAYRECORD {
int id PK
int userId FK
int chapterId FK
float progress
float duration
datetime createdAt
datetime updatedAt
}
USER {
int id PK
string phone
string openid
string nickname
}
BOOKCHAPTER {
int id PK
int bookId FK
string title
string audioUrl
int audioDuration
}
USER ||--o{ PLAYRECORD : has
BOOKCHAPTER ||--o{ PLAYRECORD : has
图表来源
章节来源
播放器状态管理采用响应式设计,确保UI与状态的实时同步:
stateDiagram-v2
[*] --> Idle : 初始化
Idle --> Loading : 开始加载音频
Loading --> Playing : 音频准备就绪
Loading --> Error : 加载失败
Playing --> Paused : 用户暂停
Paused --> Playing : 用户继续
Playing --> Ended : 播放完成
Ended --> Idle : 重置状态
Error --> Idle : 重试或取消
state Playing {
[*] --> Buffering : 缓冲中
Buffering --> Seeking : 用户跳转
Seeking --> Playing : 跳转完成
Playing --> Updating : 更新进度
Updating --> Playing : 进度更新完成
}
图表来源
前端通过Pinia的响应式系统实现状态同步:
章节来源
系统实现了智能的音频缓冲策略,优化移动端播放体验:
flowchart TD
Start([开始播放]) --> CheckNetwork{检查网络状态}
CheckNetwork --> |WiFi| FullBuffer[完全缓冲]
CheckNetwork --> |移动网络| AdaptiveBuffer[自适应缓冲]
FullBuffer --> PlayDirect[直接播放]
AdaptiveBuffer --> CheckSize{检查音频大小}
CheckSize --> |小于10MB| Preload[预加载]
CheckSize --> |大于10MB| Stream[流式播放]
Preload --> PlayDirect
Stream --> PlayDirect
PlayDirect --> Monitor[监控播放状态]
Monitor --> BufferCheck{检查缓冲}
BufferCheck --> |不足| ExtendBuffer[延长缓冲]
BufferCheck --> |充足| Continue[继续播放]
ExtendBuffer --> Monitor
Continue --> End([播放完成])
图表来源
网络音频处理支持多种音频格式和来源,包括OSS存储的音频文件:
sequenceDiagram
participant Client as 客户端
participant Controller as 播放器控制器
participant Service as 播放器服务
participant Merger as 音频合并器
participant Storage as 存储服务
Client->>Controller : 获取章节音频
Controller->>Service : 验证访问权限
Service->>Storage : 检查音频URL
Storage-->>Service : 返回音频信息
alt 章节音频
Service->>Merger : 检查是否需要合并
Merger->>Storage : 获取子章节音频
Storage-->>Merger : 返回子音频列表
Merger->>Merger : 合并音频文件
Merger-->>Service : 返回合并后的URL
end
Service-->>Controller : 返回音频详情
Controller-->>Client : 返回音频信息
图表来源
章节来源
播放器服务实现了完整的音频播放生命周期管理:
classDiagram
class PlayerController {
+getProgress(ctx) Promise
+saveProgress(ctx) Promise
+updateProgress(ctx) Promise
+deleteProgress(ctx) Promise
+getAudioList(ctx) Promise
+getAudioDetail(ctx) Promise
}
class PlayerService {
+getPlayProgress(userId, chapterId) Promise
+savePlayProgress(userId, chapterId, progress, duration) Promise
+updatePlayProgress(userId, chapterId, progress, duration) Promise
+deletePlayRecord(userId, chapterId) Promise
+mergeChapterAudios(chapterId) Promise
+getChapterAudioUrl(chapterId) Promise
+getRecentPlayRecords(userId, limit) Promise
}
class AudioMerger {
+merge(inputFiles, outputPath) Promise
+mergeLocalFiles(inputFiles, outputPath) Promise
+getDuration(filePath) Promise
}
class WebSocketService {
+addClient(clientId, ws) void
+removeClient(clientId) void
+sendToClient(clientId, event, data) boolean
+broadcast(event, data) void
+pushAudioGenerationComplete(bookId, chapterId, status) void
}
PlayerController --> PlayerService : 使用
PlayerService --> AudioMerger : 调用
PlayerService --> WebSocketService : 推送事件
图表来源
章节来源
前端状态同步通过Vue的响应式系统和Pinia状态管理实现:
sequenceDiagram
participant Page as 播放器页面
participant Store as 音频Store
participant AudioCtx as 音频上下文
participant API as 后端API
Page->>Store : onShow生命周期
Store->>Page : 同步当前音频状态
Page->>AudioCtx : 获取实时播放状态
AudioCtx-->>Page : 返回播放进度
loop 每秒更新
AudioCtx->>Store : onTimeUpdate事件
Store->>Store : 更新currentTime
Store->>API : 异步保存播放进度
end
Page->>Store : 用户交互
Store->>AudioCtx : 执行播放控制命令
AudioCtx-->>Store : 返回执行结果
Store-->>Page : 更新UI状态
图表来源
迷你播放器提供后台播放支持,即使用户离开播放器页面也能控制播放:
flowchart LR
Page[播放器页面] --> |离开页面| Mini[迷你播放器]
Mini --> |点击| Player[播放器页面]
Mini --> |控制| Store[音频状态]
Store --> AudioCtx[音频上下文]
Store -.->|状态变化| Mini
AudioCtx -.->|播放状态| Store
Store -.->|播放状态| Page
图表来源
章节来源
播放历史记录管理提供了用户播放历史的完整追踪:
erDiagram
USER {
int id PK
string phone
string nickname
}
PLAYRECORD {
int id PK
int userId FK
int chapterId FK
float progress
float duration
datetime updatedAt
}
BOOKCHAPTER {
int id PK
int bookId FK
string title
string audioUrl
int audioDuration
}
BOOK {
int id PK
int userId FK
string title
string coverUrl
}
USER ||--o{ PLAYRECORD : has
BOOKCHAPTER ||--o{ PLAYRECORD : has
BOOK ||--o{ BOOKCHAPTER : contains
图表来源
章节来源
系统针对移动端进行了专门的适配优化:
播放器界面采用响应式设计,适配不同屏幕尺寸:
graph TB
subgraph "桌面端"
Desktop[宽屏布局<br/>完整播放列表<br/>歌词显示]
end
subgraph "移动端"
Mobile[紧凑布局<br/>滚动播放列表<br/>歌词自动滚动]
MiniPlayer[固定迷你播放器<br/>底部悬浮]
end
subgraph "平板端"
Tablet[中等布局<br/>侧边播放列表<br/>触摸优化]
end
Desktop --> Mobile
Desktop --> Tablet
Mobile --> MiniPlayer
章节来源
系统实现了完整的后台播放支持:
sequenceDiagram
participant User as 用户
participant App as 应用程序
participant System as 系统服务
participant Audio as 音频服务
User->>App : 关闭播放器页面
App->>System : 注册后台播放服务
System->>Audio : 启动音频播放
Audio-->>System : 播放状态更新
System-->>App : 后台播放通知
loop 播放过程中
Audio->>System : 进度更新
System->>App : 进度回调
App->>App : 更新状态管理
end
User->>App : 打开播放器页面
App->>System : 获取当前播放状态
System-->>App : 返回播放状态
App-->>User : 显示当前播放状态
图表来源
系统提供睡眠定时功能,支持定时停止播放:
flowchart TD
Start([开始播放]) --> SetTimer[设置睡眠定时]
SetTimer --> CountDown[倒计时进行中]
CountDown --> TimerTick{定时器滴答}
TimerTick --> |剩余时间>0| CountDown
TimerTick --> |剩余时间<=0| PauseAudio[暂停播放]
PauseAudio --> End([定时结束])
图表来源
章节来源
系统实现了播放统计收集功能,为数据分析提供支持:
flowchart TD
PlayStart[开始播放] --> TrackStart[记录开始时间]
TrackStart --> ProgressUpdate[进度更新]
ProgressUpdate --> SaveProgress[保存进度]
SaveProgress --> CheckCompletion{检查播放完成}
CheckCompletion --> |未完成| ProgressUpdate
CheckCompletion --> |已完成| TrackEnd[记录结束时间]
TrackEnd --> CalculateDuration[计算播放时长]
CalculateDuration --> SaveStats[保存统计数据]
SaveStats --> SendAnalytics[发送分析数据]
SendAnalytics --> End([统计完成])
图表来源
系统各组件之间的依赖关系清晰明确:
graph TB
subgraph "前端依赖"
Vue[Vue3框架]
Pinia[Pinia状态管理]
UniApp[UniApp跨平台框架]
Axios[HTTP客户端]
end
subgraph "后端依赖"
Koa[Koa框架]
Prisma[Prisma ORM]
WS[WebSocket]
FFmpeg[FFmpeg处理]
end
subgraph "数据库依赖"
MySQL[MySQL数据库]
Redis[Redis缓存]
end
Vue --> Pinia
Vue --> UniApp
Vue --> Axios
Koa --> Prisma
Koa --> WS
Prisma --> MySQL
Prisma --> Redis
FFmpeg --> Koa
图表来源
章节来源
系统采用智能的内存管理策略:
可能原因:
解决步骤:
可能原因:
解决步骤:
可能原因:
解决步骤:
章节来源
音频播放系统是一个功能完整、架构清晰的移动端音频播放解决方案。系统采用现代化的技术栈,提供了优秀的用户体验和良好的扩展性。
系统提供以下核心API接口:
| 接口 | 方法 | 描述 | 参数 |
|---|---|---|---|
| /player/progress | GET | 获取播放进度列表 | audioId(可选) |
| /player/progress | POST | 保存播放进度 | audioId, progress, duration |
| /player/progress/:audioId | PUT | 更新播放进度 | progress, duration(可选) |
| /player/progress/:audioId | DELETE | 删除播放记录 | 无 |
| /player/audio/list | GET | 获取播放列表 | page, pageSize |
| /player/audio/:id | GET | 获取音频详情 | 无 |
系统使用以下核心数据模型:
系统支持以下配置选项: