合并react-native-live-audio-stream的Base64音频块后音频异常问题
问题:合并react-native-live-audio-stream的Base64音频块后音频乱码
我使用react-native-live-audio-stream采集麦克风音频,该库会输出Base64编码的音频块,代码如下:
LiveAudioStream.on('data', data => { // base64-encoded audio data chunks });
我希望将这些块合并为单个Base64字符串,用于语音转文本服务。目前的实现是先将音频块存入数组:
let bufferedAudioData = []; LiveAudioStream.on('data', data => { bufferedAudioData.push(data); });
然后调用combineBase64Audio函数合并:
export function combineBase64Audio(base64Strings) { // decode the base64 strings to ArrayBuffers const buffers = base64Strings.map(base64ToArrayBuffer); // create a new ArrayBuffer to hold the combined audio const combinedBuffer = new ArrayBuffer(buffers.reduce((totalLength, buffer) => totalLength + buffer.byteLength, 0)); // create a view for each ArrayBuffer and copy the audio data into the combined buffer let offset = 0; buffers.forEach((buffer) => { const view = new Uint8Array(combinedBuffer, offset, buffer.byteLength); view.set(new Uint8Array(buffer)); offset += buffer.byteLength; }); // encode the combined ArrayBuffer as a base64 string return arrayBufferToBase64(combinedBuffer); } function base64ToArrayBuffer(base64) { // decode the base64 string to a Uint8Array const binaryString = Buffer(base64, 'base64').toString() const binaryLength = binaryString.length; const bytes = new Uint8Array(binaryLength); for (let i = 0; i < binaryLength; i++) { bytes[i] = binaryString.charCodeAt(i); } // return the Uint8Array as an ArrayBuffer return bytes.buffer; } function arrayBufferToBase64(arrayBuffer) { // create a Uint8Array view of the ArrayBuffer const bytes = new Uint8Array(arrayBuffer); // convert the Uint8Array to a binary string let binaryString = ''; for (let i = 0; i < bytes.length; i++) { binaryString += String.fromCharCode(bytes[i]); } return Buffer(binaryString).toString('base64'); }
我将合并后的Base64字符串通过API保存为文件,用Audacity导入为原始数据(设置编码为Signed 16-bit PCM)后,音频是乱码。经排查,单个解码后的音频块正常,问题出在合并代码中,请问我哪里做错了?
问题排查与修复
核心问题出在base64ToArrayBuffer和arrayBufferToBase64的二进制数据处理逻辑:
Buffer(base64, 'base64').toString()会把二进制Buffer转成默认的UTF-8字符串,但音频的二进制字节并非全部是合法UTF-8字符,转换过程会破坏原始数据(比如替换无效字节为占位符),导致合并后音频乱码。- 手动拼接二进制字符串的方式不仅低效,还可能在处理特殊字节时出现编码偏差。
修复后的简化代码
直接利用Buffer原生能力处理二进制,跳过错误的字符串转换步骤:
export function combineBase64Audio(base64Strings) { // 将每个Base64字符串解码为Buffer,再合并成一个大Buffer const combinedBuffer = Buffer.concat(base64Strings.map(str => Buffer.from(str, 'base64'))); // 转成Base64字符串返回 return combinedBuffer.toString('base64'); }
原理说明
Buffer.from(str, 'base64')直接将Base64解码为二进制Buffer,完整保留原始音频字节,无中间转换损耗。Buffer.concat()高效处理多Buffer合并,内部已完成内存分配和数据拷贝,比手动操作ArrayBuffer更可靠。- 最终
toString('base64')基于二进制直接转换,确保输出的Base64字符串对应完整原始音频数据。
兼容ArrayBuffer的版本(若需和Web API交互)
export function combineBase64Audio(base64Strings) { // 将每个Base64转成Uint8Array const uint8Arrays = base64Strings.map(str => new Uint8Array(Buffer.from(str, 'base64'))); // 计算总字节长度 const totalLength = uint8Arrays.reduce((sum, arr) => sum + arr.length, 0); // 创建合并后的Uint8Array const combinedArray = new Uint8Array(totalLength); let offset = 0; for (const arr of uint8Arrays) { combinedArray.set(arr, offset); offset += arr.length; } // 转成Base64字符串 return Buffer.from(combinedArray).toString('base64'); }
这两个版本都能避免原始代码中破坏二进制数据的步骤,合并后的音频数据与原始采集块完全一致。
内容的提问来源于stack exchange,提问作者Adam B
相关产品推荐
相关产品推荐

