You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

合并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');
}

原理说明

  1. Buffer.from(str, 'base64')直接将Base64解码为二进制Buffer,完整保留原始音频字节,无中间转换损耗。
  2. Buffer.concat()高效处理多Buffer合并,内部已完成内存分配和数据拷贝,比手动操作ArrayBuffer更可靠。
  3. 最终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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 13:15:55