《倒带大挑战》的技术实现
《倒带大挑战》是一款基于音频处理技术的趣味交互应用,详情请参考 倒放的灵感。多人在线部分我们之前有你画我猜的经验,这里不做赘述。本文将深入探讨声音的录制、上传,存储和倒放实现。
上传和存储
这里有两方面的考虑,一是实时性,关系到应用体验,二是存储和传输成本,关系到服务器成本。
经过多方考虑,我选择客户端那临时鉴权,然后上传到阿里云oss。而下载通过 cdn 加速。这样既保证了实时性,又降低了服务器成本。文件保留时间为暂定 7 天。所以存储成本也相对可控。这种方案理论上速度也可以,但还需要实际论证。
格式方面,打算使用WebM (Opus 编码)格式。5 秒的语音,在使用 Opus 编码(16kbps - 24kbps)的情况下,体积可以压缩到 10KB - 30KB 左右,且音质对这一项目绰绰有余。H5 使用 MediaRecorder API 时,指定 mimeType: ‘audio/webm;codecs=opus’。
另外,如果用户量极大,服务器申请 STS Token 的接口可能会被打爆。可能需要:
前端缓存 Token: 只要 Token 没过期(比如 15 分钟内),前端就不需要重复请求。
PostObject 策略: 使用 PostObject 预签名(V4 签名)。服务器预先生成一个包含“有效期、文件大小限制、目标路径”的表单签名发给前端,前端直接 POST 到 OSS。这种方式服务器压力最小,且不需要 STS 接口。
在录制结束时,可以写一个简单的算法剔除首尾的静音部分(Silence Trimming),这样不仅能进一步缩小体积,还能让“合集大放送”环节衔接得更紧凑,更有鬼畜感!
倒放的实现技术
在 H5 环境下实现音频倒放,核心工具是 Web Audio API。它的处理逻辑非常直观:音频在计算机眼中就是一串数字(采样点),倒放本质上就是把这个数组反转。
以下是实现倒放的技术全流程:
- 核心原理:AudioBuffer 处理
Web Audio API 允许我们将音频文件解码为 AudioBuffer。这是一个存储在内存中的非压缩音频对象,包含了音频的原始采样数据。
倒放核心代码:
1 | |
- 完整流程实现
步骤 A:录制音频
使用 MediaRecorder API 获取用户的语音。
1 | |
步骤 B:解码与反转
录制得到的是一个压缩后的 Blob,我们需要先将其解码回 AudioBuffer 才能操作。
1 | |
另外,一个重要的策略是上传原始录音,客户端即时倒放。所有的“倒放”效果全靠 Web Audio API 在每个玩家的本地浏览器里实时计算。
性能优化
避免重复解码
在客户端,同一个音频文件可能会被播放多次(例如玩家反复听某个倒放片段)。为了避免每次播放都重新解码(decodeAudioData),应该将解码后的 AudioBuffer 缓存起来。当需要再次播放时,直接使用缓存的 Buffer,这样可以极大减少 CPU 消耗并提升响应速度。音量标准化(Normalization):
有些玩家录音声音小。处理 AudioBuffer 时,可以找到最大振幅,按比例把整个数组的数值放大到 1.0 附近。这样复盘合集大放送时,每个人的声音音量才统一。采样率统一:
为了确保所有人的音频在合集播放时不卡顿,建议在 decodeAudioData 后检查采样率。如果不同,虽然 AudioContext 会自动重采样,但统一使用 24000Hz 会更稳。
最后要考虑的是 iOS 的交互限制。iOS 上的 Safari 浏览器对音频播放有严格的限制,要求音频必须由用户的手势触发才能播放。所以,所有声音都由用户点击按钮播放。UI 设计上也要考虑好这一点。