需求小能手——播放pcm实时语音流

前言

前两周做了播放实时语音流的需求,就这一个需求跟后端联调了两天,最后还是拉外援才成功联调。这个需求本质也不是特别难,下面来看一下具体的实现过程

ws获取

标题中的语音流是实时的,公司项目是通过webSocket进行实时语音的获取,如果不是实时语音流,直接跳过。实时听起来很复杂,对于前端而言实现起来却很简单,调用ws几个方法就能实现。

  • 创建,new WebSocket实例化一个ws。
  • 连接,onopen监听ws连接状态。
  • 消息,ommessage监听ws连接的消息,send方法向ws发送消息。
  • 错误,onerror监听ws错误消息。
  • 关闭,onclose监听ws关闭,close方法关闭ws。

通过ws一系列操作我们就能实时获取后端传过来的数据。

语音流播放

如果直接传语音流前端直接当成流处理会很简单,但后端是通过调用其他平台获取的语音流,传到前端就变成字符串了,于是就是不断尝试的联调过程。

AudioContext

刚开始我的想法是通过AudioContext.createBufferSource()播放,该方法接收AudioBuffer对象,所以我们现在的目的就是将字符串转成AudioBuffer。获取AudioBuffer的方式有两种:

  • AudioContext.createBuffer():创建空白的AudioBuffer对象,然后将音频数据填充进去。
  • AudioContext.decodeAudioData():将ArrayBuffer(字节数组)数据解码为AduioBuffer。ArrayBuffer一般就是接口返回的文件流。
    对比两个方法选用第二个,第二个是需要传过来将字符串变为ArrayBuffer,跟后端沟通了下,反馈这字符串直接就是音频流,所以我就直接当成ArrayBuffer去处理。

传入字符串,运行报错,decodeAudioData解码不了这数据,看了不能直接用。搜索了一番,发现可以用charCodeAt将字符变为unicode编码,就尝试把字符串都变为uniCode再解析,还是不行,继续尝试。

base64编码

尝试了几次,跟后端商议把数据进行base64编码,前端拿到进行解码再进行处理。首先使用window.atob进行解码,然后用new ArrayBuffer创建为字节数组。

再次运行还是不行,因为是pcm流所以另一个同事引入了pcm-player依赖尝试进行播放。

pcm-player

pcm-player是一个简单的pcm流播放器,我们安装此依赖,再页面引入然后初始化一个实例。

然后我们将数据进行处理使用feed方法进行播放,注意该插件也是通过AudioContext.createBufferSource实现语音流播放,只是播放没有可视化的东西。实例化时我们要注意两个参数:

  • inputCodec:编码格式,表示类型化数组的类型。
  • sampleRate:采样率,录音相关属性。
    简单来说这两个属性影响着音质。引入了新插件,继续尝试,因为feed只接受类型化数据,所以我们要把解码后的数据变成TypedArray。我们先声明一个类型化数据,然后利用chatCodeAt将字节数据添加进去。注意,声明的TypedArray的类型要跟inputCodec保持一致。
js 复制代码
base64ToInt16Array(base64String) {
const rawData = window.atob(base64String)
const typedArray = new Int16Array(rawData.length)
for (let i = 0; i < rawData.length; i++) {
  typedArray[i] = rawData.charCodeAt(i)
}
return typedArray
}

因为是实时的,所以我们用watch监听ws的消息,将获取的字符串处理成TypedArray,然后用feed方法去播放。运行语音成功播放出来了,但是,但是音质不行。就因为音质问题跟后端对接了两天,改编码格式、采样率就是不能清晰播放出来,最终拉了一个外援,研究了一下午终于搞出来了。简单来说问题就是字节没对上,也就是前端处理方法有问题,上面给Int16Array赋值的时候需要把两个字节合成一个

到此录音能实时播放,并且播放的很清晰,完美收官。

总结

以上就是pcm清晰播放实时语音流的过程,只能说闻道有先后,术业有专攻 要不是大佬帮着分析字节问题,不知道还要卡多久。

相关推荐
slongzhang_16 分钟前
jquery 修复怪异模式html未声明“<!DOCTYPE html>”
前端·html·jquery
云水一下1 小时前
Vue.js从零到精通系列(三):组件化基础——Props、Emits、插槽与生命周期
前端·javascript·vue.js
SEO_juper2 小时前
新独立站冷启动收录全攻略:配置、推送、抓取配额优化完整手册
前端·谷歌·seo·跨境电商·外贸·geo·独立站
TinssonTai2 小时前
这个 VS Code 插件让我的 AI Coding 又快又稳 - 旧瓶装新酒
前端·人工智能·程序员
体验家2 小时前
体验家 XMPlus 网页端问卷 SDK 技术解析:用几行 JavaScript 实现精准场景触发与防打扰机制
开发语言·前端·javascript
Maimai108082 小时前
Web3 前端交易系统如何落地:从下单 UI 到 Operation 编码、签名与实时状态更新
前端·react.js·ui·架构·前端框架·web3
kidding7232 小时前
高效备忘清单工具类小程序
前端·计算机网络·微信小程序·小程序
IMPYLH2 小时前
HTML 的 <abbr> 元素
前端·算法·html
李白的天不白3 小时前
Tree-Shaking
前端
Csvn3 小时前
TypeScript:你以为安全的 `JSON.parse` 其实是颗雷 — 运行时类型安全实战
前端·javascript