diff --git a/TUICallKit-Vue3/training/static/README.md b/TUICallKit-Vue3/training/static/README.md index 1c5442f4..86616b8b 100644 --- a/TUICallKit-Vue3/training/static/README.md +++ b/TUICallKit-Vue3/training/static/README.md @@ -103,3 +103,120 @@ node scripts/generate-voice.mjs --force - 微信小程序对单个文件大小有 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. **全局单例**:整个小程序同一时刻只能播一个,多场景要协调切换 +2. **音频时长 ≥ 1 秒**:太短的 click 会被微信判定异常忽略 +3. **必填 metadata**:`title` / `coverImgUrl` / `singer` / `epname` / `webUrl` 缺一会报错 +4. **切 src 有延迟**:200~500ms 初始化抖动,频繁切换会卡顿 +5. **必须声明 `requiredBackgroundModes:["audio"]`** 才能后台播放 +6. **iOS 锁屏豁免**:声明后能锁屏继续播,无 5 分钟时长限制(vs InnerAudio 的 5min) +7. **会显示系统控制条**:锁屏/通知栏出现带封面+暂停按钮的控制条 + +### 推荐架构(健身模块上线时) + +``` +training/hooks/ +├── useTrainingBgm.ts → BackgroundAudioManager (后台/锁屏继续放音乐) +├── useVoiceCoach.ts → InnerAudioContext (语音指导,前台用) +└── useMetronome.ts → InnerAudioContext (节拍器,池子方案,保持现状) +``` + +页面 `pages.json` 声明: + +```json +{ + "path": "pages/index", + "style": { + "navigationBarTitleText": "练一练", + "requiredBackgroundModes": ["audio"] + } +} +``` + +锁屏会显示 BGM 控制条,老人能直接在锁屏点暂停。训练页面通过 `bgm.onPause()` 监听同步暂停训练,体验连贯。 + +### 必备资产清单 + +到时候要准备的文件: + +- **BGM 2 首**:`bgm/train-light.mp3`(训练)、`bgm/rest-meditation.mp3`(休息) + - 每个 30s~1min,128kbps 单声道,30~80KB + - 推荐来源:[pixabay.com/music](https://pixabay.com/music) 搜 "calm" / "meditation" / "lofi" +- **锁屏封面**:`audio/cover.jpg` 200×200 + - 简洁绿色背景 + 训练 emoji 即可 + +### BackgroundAudioManager API 速查 + +```ts +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) }) +``` + +### 切换不同场景音乐的模式 + +```ts +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` 够用。