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

相关推荐
别拿曾经看以后~19 分钟前
【el-form】记一例好用的el-input输入框回车调接口和el-button按钮防重点击
javascript·vue.js·elementui
我要洋人死22 分钟前
导航栏及下拉菜单的实现
前端·css·css3
科技探秘人34 分钟前
Chrome与火狐哪个浏览器的隐私追踪功能更好
前端·chrome
科技探秘人34 分钟前
Chrome与傲游浏览器性能与功能的深度对比
前端·chrome
JerryXZR40 分钟前
前端开发中ES6的技术细节二
前端·javascript·es6
七星静香41 分钟前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
q24985969344 分钟前
前端预览word、excel、ppt
前端·word·excel
小华同学ai1 小时前
wflow-web:开源啦 ,高仿钉钉、飞书、企业微信的审批流程设计器,轻松打造属于你的工作流设计器
前端·钉钉·飞书
Gavin_9151 小时前
【JavaScript】模块化开发
前端·javascript·vue.js
懒大王爱吃狼2 小时前
Python教程:python枚举类定义和使用
开发语言·前端·javascript·python·python基础·python编程·python书籍