需求小能手——播放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清晰播放实时语音流的过程,只能说闻道有先后,术业有专攻 要不是大佬帮着分析字节问题,不知道还要卡多久。

相关推荐
hackeroink34 分钟前
【2024版】最新推荐好用的XSS漏洞扫描利用工具_xss扫描工具
前端·xss
迷雾漫步者2 小时前
Flutter组件————FloatingActionButton
前端·flutter·dart
向前看-3 小时前
验证码机制
前端·后端
燃先生._.4 小时前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js
高山我梦口香糖5 小时前
[react]searchParams转普通对象
开发语言·前端·javascript
m0_748235245 小时前
前端实现获取后端返回的文件流并下载
前端·状态模式
m0_748240255 小时前
前端如何检测用户登录状态是否过期
前端
black^sugar5 小时前
纯前端实现更新检测
开发语言·前端·javascript
寻找沙漠的人6 小时前
前端知识补充—CSS
前端·css