以下是可能用到的函数
// base64 转 ArrayBuffer
function _base64ToArrayBuffer(base64) {
var binary_string = window.atob(base64); //解码使用base64编码的字符串
var len = binary_string.length; //获取长度
var bytes = new Uint8Array(len);
for (var i = 0; i < len; i++) {
bytes[i] = binary_string.charCodeAt(i);
}
// console.log(bytes); //打印解析出来的byte
// return bytes;
return bytes.buffer;
}
// 下载 ArrayBuffer
function download(buff) {
let url = window.URL.createObjectURL(
new Blob([buff], { type: "arraybuffer" })
);
const link = document.createElement("a");
link.style.display = "none";
link.href = url;
link.setAttribute("download", "out");
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
// 拼接 ArrayBuffer
function mergeArrayBuffers(arrayBuffers) {
// 计算新的ArrayBuffer的总长度
let totalLength = 0;
for (const buffer of arrayBuffers) {
totalLength += buffer.byteLength;
}
// 创建一个新的ArrayBuffer
const mergedBuffer = new ArrayBuffer(totalLength);
// 创建一个Uint8Array以便操作新的ArrayBuffer
const uint8Array = new Uint8Array(mergedBuffer);
let offset = 0;
// 逐个复制ArrayBuffer到新的ArrayBuffer中
for (const buffer of arrayBuffers) {
const sourceArray = new Uint8Array(buffer);
uint8Array.set(sourceArray, offset);
offset += sourceArray.length;
}
return mergedBuffer;
}
// ArrayBuffer 转 Float32Array
function convertArrayBufferToFloat32Array(arrayBuffer) {
const dataView = new DataView(arrayBuffer);
// const float32Array = new Float32Array(arrayBuffer.byteLength / Float32Array.BYTES_PER_ELEMENT);
const float32Array = new Float32Array(arrayBuffer.byteLength / 2);
for (let i = 0; i < float32Array.length; i++) {
const pcmValue = dataView.getInt16(i * 2, true);
float32Array[i] = pcmValue / 32768.0;
}
return float32Array;
}
其中PCM的数据 单声道 8000采样率
由于我这边返回的base64,所以需要把base64转换成ArrayBuffer,随后是 ArrayBuffer 转换成 Float32Array,再进行播放操作,另外,由于ws返回的数据太短了,所以这里对返回的数据进行拼接,拼接十段后再进行播放,使音频流畅起来,至于是否需要拼接可根据实际情况考虑,具体代码如下
var num = -1;
var all_ArrayBuffer = [];
// _this.wsList[index].wsObj.binaryType = "arraybuffer";
const audioContext = new (window.AudioContext ||
window.webkitAudioContext)();
_this.wsList[index].wsObj.onmessage = async (event) => {
var data = _base64ToArrayBuffer(event.data); // Uint8Array ArrayBuffer
num++;
if (num < 10) {
all_ArrayBuffer.push(data);
} else if (num == 10) {
var arr = mergeArrayBuffers(all_ArrayBuffer);
// download(arr) // 下载到本地
all_ArrayBuffer = [];
num = 0;
// 将 ArrayBuffer 格式的 PCM 数据转换为 Float32Array 格式
const float32Array = convertArrayBufferToFloat32Array(arr);
// 创建 AudioBufferSourceNode
const audioBufferSource = audioContext.createBufferSource();
// 创建 AudioBuffer
const audioBuffer = audioContext.createBuffer(
1,
float32Array.length,
8000
);
// 获取 AudioBuffer 的数据通道
const channelData = audioBuffer.getChannelData(0);
// 将 Float32Array 格式的 PCM 数据填充到 AudioBuffer 的数据通道
channelData.set(float32Array);
// 将 AudioBuffer 设置为 AudioBufferSourceNode 的音频数据
audioBufferSource.buffer = audioBuffer;
// 连接 AudioBufferSourceNode 到音频输出
audioBufferSource.connect(audioContext.destination);
// 播放音频
audioBufferSource.start();
}
};