记录未来做健身模块时上 BackgroundAudioManager 的完整方案, 避免再调研一次。包含: - 引擎选择对照表(BGM 用 BgAudio / 短音用 InnerAudio) - BackgroundAudioManager 7 条限制清单 - 健身模块推荐架构(双引擎共存) - 必备资产清单(BGM mp3 + 200×200 封面) - BgAudio API 速查 + 场景切换模式代码 - 节拍器为何不一并升级的判断依据 Co-authored-by: Cursor <cursoragent@cursor.com>
训练模块静态资源
本目录用于存放"练一练"功能的所有音频素材。
目录结构
training/static/
├── audio/
│ └── click.mp3 # 节拍器主音(短促金属敲击声,约 50ms)
├── voice/
│ ├── numbers/
│ │ └── 1.mp3 ~ 30.mp3 # 数字报数
│ └── prompts/
│ ├── start.mp3
│ ├── ready.mp3
│ ├── rest.mp3
│ ├── next-set.mp3
│ ├── last-rep.mp3
│ ├── keep-it-up.mp3
│ ├── good-job.mp3
│ ├── breathe-in.mp3
│ └── breathe-out.mp3
└── bgm/
├── train-light.mp3 # 训练时背景乐(轻快有节奏感)
└── rest-meditation.mp3 # 休息时背景乐(舒缓冥想)
准备步骤
1. 语音素材(小米 MiMo TTS 自动生成)
需要 Node 18+(用内置 fetch)。先准备小米 MiMo API Key:
- 文档: https://platform.xiaomimimo.com/
- API Key 形如
sk-xxxxxxxx
export MIMO_API_KEY=sk-your-key-here
cd uniapp
node scripts/generate-voice.mjs
会自动调用 mimo-v2.5-tts 模型生成 39 个 mp3(30 个数字 + 9 个口令)到 voice/ 目录。
可选参数:
# 换音色(默认 冰糖;可选:冰糖/茉莉/苏打/白桦/Mia/Chloe/Milo/Dean)
node scripts/generate-voice.mjs --voice 茉莉
# 换格式(默认 mp3,需要跟 hooks/useVoiceCoach.ts 里的 .mp3 后缀对应)
node scripts/generate-voice.mjs --format wav
# 强制重新生成(默认存在则跳过)
node scripts/generate-voice.mjs --force
音色推荐(中文女声更适合健身教练):
冰糖:温柔甜美,亲和力强(默认)茉莉:清爽利落,有"运动博主"感苏打:年轻男声,有力量感白桦:成熟男声,沉稳
2. 节拍器 click 音
已内置 3 种音色(来自 chrono-bump MIT 协议项目):
| 文件 | 用途 | 大小 |
|---|---|---|
audio/click.mp3 |
默认 click(标准节拍器音) | 3.4 KB |
audio/click-soft.mp3 |
柔和音色 | 4.2 KB |
audio/click-wood.mp3 |
木鱼/原木质感(推荐用于重音 accent) | 4.6 KB |
如果想换更好听的,可以去:
- freesound.org 搜 "click" / "tick"(注意 CC 协议)
- pixabay.com/sound-effects 搜 "metronome"(免费可商用)
替换时保持文件名不变即可,无需改代码。
3. 背景音乐
每首 30 秒~2 分钟即可(loop 后听不出接缝)。
推荐来源(免费可商用):
- pixabay.com/music 搜 "calm" / "meditation" / "lofi"
- freemusicarchive.org
- bensound.com(含署名)
文件大小建议 < 1MB(mp3 128kbps 单声道即可)。
在代码里被引用的位置
training/hooks/useMetronome.ts→audio/click.mp3training/hooks/useVoiceCoach.ts→voice/numbers/*.mp3、voice/prompts/*.mp3training/hooks/useTrainingBgm.ts→bgm/*.mp3
如需修改路径,修改对应 hook 文件里的常量即可。
注意事项
- 微信小程序对单个文件大小有 10MB 上限,本目录所有文件加起来建议控制在 5MB 以内。
- 小程序整包大小限制(主包 2MB / 总包 20MB),如果资源较大建议放 CDN 而非本地 static。
- 把
useVoiceCoach.ts里的VOICE_BASE改成 CDN URL 即可。
- 把
后台/锁屏播放设计备忘(未来健身模块用)
节拍器目前用
InnerAudioContext+requiredBackgroundModes:["audio"]已能覆盖 5~10 分钟健走场景。 真要做长时间训练 BGM、锁屏控制条等高级能力,参考下面的BackgroundAudioManager方案。
引擎选择对照表
健身模块的音频天然分两类,配两套引擎不冲突:
| 音频类型 | 时长 | 推荐引擎 | 理由 |
|---|---|---|---|
| 训练/休息 BGM | 30s~2min 循环 | BackgroundAudioManager | 长流、需要后台/锁屏不停 |
| 语音教练("开始/休息/再来") | 1~3s 单句 | InnerAudioContext | 短促,前台用即可 |
| 报数(1, 2, 3...) | 0.5~1s | InnerAudioContext + 池子 | 高频短促 |
| 节拍器 click | 50~150ms | InnerAudioContext + 池子 | 极短,BgAudio 不接受 |
关键约束:BgAudio 是全局单例,一次只能播 1 个音频。所以让它专门播 BGM 这类"长流",其他短音用 InnerAudio 配合,互不打架。
BackgroundAudioManager 限制清单(踩坑预警)
- 全局单例:整个小程序同一时刻只能播一个,多场景要协调切换
- 音频时长 ≥ 1 秒:太短的 click 会被微信判定异常忽略
- 必填 metadata:
title/coverImgUrl/singer/epname/webUrl缺一会报错 - 切 src 有延迟:200~500ms 初始化抖动,频繁切换会卡顿
- 必须声明
requiredBackgroundModes:["audio"]才能后台播放 - iOS 锁屏豁免:声明后能锁屏继续播,无 5 分钟时长限制(vs InnerAudio 的 5min)
- 会显示系统控制条:锁屏/通知栏出现带封面+暂停按钮的控制条
推荐架构(健身模块上线时)
training/hooks/
├── useTrainingBgm.ts → BackgroundAudioManager (后台/锁屏继续放音乐)
├── useVoiceCoach.ts → InnerAudioContext (语音指导,前台用)
└── useMetronome.ts → InnerAudioContext (节拍器,池子方案,保持现状)
页面 pages.json 声明:
{
"path": "pages/index",
"style": {
"navigationBarTitleText": "练一练",
"requiredBackgroundModes": ["audio"]
}
}
锁屏会显示 BGM 控制条,老人能直接在锁屏点暂停。训练页面通过 bgm.onPause() 监听同步暂停训练,体验连贯。
必备资产清单
到时候要准备的文件:
- BGM 2 首:
bgm/train-light.mp3(训练)、bgm/rest-meditation.mp3(休息)- 每个 30s
1min,128kbps 单声道,3080KB - 推荐来源:pixabay.com/music 搜 "calm" / "meditation" / "lofi"
- 每个 30s
- 锁屏封面:
audio/cover.jpg200×200- 简洁绿色背景 + 训练 emoji 即可
BackgroundAudioManager API 速查
const bgm = uni.getBackgroundAudioManager()
/* 必填 metadata,缺一会报错 */
bgm.title = '健走训练中'
bgm.coverImgUrl = '/training/static/audio/cover.jpg'
bgm.epname = '甄养堂'
bgm.singer = '健走节拍'
bgm.webUrl = '' // 必填,空字符串可
/* src 一旦赋值会自动播放 */
bgm.src = '/training/static/audio/bgm/train-light.mp3'
/* 控制 */
bgm.pause() // 暂停 (锁屏控制条仍在)
bgm.play() // 继续
bgm.stop() // 真停 + 隐藏控制条
bgm.seek(30) // 跳到 30s
/* 事件监听 — 用户从锁屏点暂停时会触发 */
bgm.onPause(() => { /* 同步训练 UI 状态 */ })
bgm.onPlay(() => {})
bgm.onStop(() => {})
bgm.onEnded(() => { /* 不 loop 时触发,可手动接下一首 */ })
bgm.onError((err) => { console.error(err) })
切换不同场景音乐的模式
function switchBgm(scene: 'training' | 'resting' | 'none') {
if (scene === 'none') {
bgm.stop()
return
}
bgm.title = scene === 'training' ? '健走训练中' : '休息恢复中'
bgm.src = scene === 'training'
? '/training/static/audio/bgm/train-light.mp3'
: '/training/static/audio/bgm/rest-meditation.mp3'
/* 注:setSrc 会自动播放,有 200~500ms 切换延迟 */
}
节拍器要不要也升级到 BgAudio?
目前不需要。节拍器升级 BgAudio 的代价:
- 需要预合成 3 个档位的循环 mp3(80/110/130 BPM × 2 拍)
- 必须砍掉右下角微调按钮(预合成 mp3 改不了 BPM)
- 切档位有 200~500ms 卡顿
如果未来发现"健走 30 分钟以上锁屏会停"才考虑改。当前 5~10 分钟场景 InnerAudio + requiredBackgroundModes 够用。