Node.js中如何将多段文本转语音生成的音频缓冲区拼接为单个音频文件
问题根因
- 当前代码中
audioContents.join()的逻辑完全错误:audioContent是Node.js Buffer类型,默认的join()方法会将Buffer转为字符串并用逗号拼接,直接破坏了二进制音频数据。 - 即使替换为
Buffer.concat(audioContents)拼接MP3也无法正常播放:TTS接口返回的每一段MP3都是独立完整的文件,自带文件头/帧头元数据,直接拼接后播放器无法识别多段头信息,会出现只有第一段能播放、时长错误、杂音等问题。
方案1:改用LINEAR16编码(TTS领域推荐方案)
LINEAR16是无压缩的原始PCM音频流,没有任何文件头元信息,只要所有TTS请求的采样率、声道数、位深参数完全一致,多段音频可以直接二进制拼接,零额外处理开销,是长文本TTS拼接场景的首选方案。
实现代码参考:
const client = new textToSpeech.TextToSpeechClient(); // 全局统一音频参数,所有请求必须使用同一套配置 const AUDIO_CONFIG = { audioEncoding: 'LINEAR16', sampleRateHertz: 16000, // 可选8000/16000/24000/48000,保持统一即可 audioChannelCount: 1 // 单声道是TTS场景通用配置 } const promises = ['hi','world'].map(text => { const requestBody = { audioConfig: AUDIO_CONFIG, input: { text }, voice: { languageCode: 'en-US', ssmlGender: 'NEUTRAL' }, }; return client.synthesizeSpeech(requestBody) }) const responses = await Promise.all(promises) const audioContents = responses.map(res => res[0].audioContent) // 直接拼接Buffer即可得到完整可用的LINEAR16流 const fullAudioPcm = Buffer.concat(audioContents)
使用说明:
- 拼接完成的LINEAR16可以直接送入语音识别、直播推流等链路使用
- 如果需要导出为可直接播放的WAV格式,只需要给拼接后的PCM添加标准WAV头即可;如果需要转MP3,可以统一调用一次FFmpeg转码即可,比多段MP3拼接性能高很多
- 浏览器环境下可以直接用
AudioContext解码LINEAR16流实时播放,适合长文本流式合成场景
方案2:继续使用MP3格式的拼接方案
如果业务要求必须输出MP3,有两种实现方式:
- Node.js环境下用
fluent-ffmpeg合并:将每一段MP3 Buffer写入临时文件,调用FFmpeg的concat滤镜合并多段音频,自动处理头信息兼容问题 - 浏览器/轻量场景下用
mp3-concat等专门的JS库:自动剥离每段MP3的头信息,只拼接有效音频帧,最终输出完整MP3
内容的提问来源于stack exchange,提问作者Wt.N
相关产品推荐
相关产品推荐

