nodejs播放MP3
依赖:
npm i speaker
下载 ffmpeg.exe 文件放到可执行目录
const ffmpeg = require('fluent-ffmpeg');
const Speaker = require('speaker');
const WaveFile = require('wavefile').WaveFile;
const tempDir = require('os').tmpdir();
const fs = require('fs');
const { spawn } = require('child_process');
function convertMP3ToWAV(inputPath, outputPath) {
return new Promise((resolve, reject) => {
ffmpeg(inputPath)
.toFormat('wav')
.audioCodec('pcm_s16le') // 16位有符号整数
.audioChannels(1) // 单声道(适合语音)
.audioFrequency(16000) // 16kHz 采样率(与 edge-tts 一致)
.on('end', () => {
console.log(`✅ 转换完成: ${outputPath}`);
resolve(outputPath);
})
.on('error', (err) => {
console.error('❌ 转换失败:', err);
reject(err);
})
.save(outputPath);
});
}
async function play() {
const mp3Path = './output.mp3'//`${tempDir}/speech_${Date.now()}.mp3`;
const wavPath = mp3Path.replace('.mp3', '.wav');
// if (!fs.existsSync(wavPath)) {
// 2. 转换为 WAV
// await convertMP3ToWAV(mp3Path, wavPath);
// console.log('✅ WAV 已生成:', wavPath);
// // }
// // 3. 用 speaker 播放
// await playWAVSilent(wavPath);
playMP3WithFFmpeg(mp3Path)
}
async function playWAVSilent(filePath) {
return new Promise((resolve, reject) => {
const buffer = fs.readFileSync(filePath);
// 读取 WAV 文件头获取参数
const waveFile = new WaveFile(buffer);
const format = waveFile.fmt;
const speaker = new Speaker({
channels: format.numChannels,
bitDepth: format.bitDepth,
sampleRate: format.sampleRate,
});
speaker.write(buffer);
speaker.end();
speaker.on('close', () => {
console.log('✅ 静默播放完成');
resolve();
});
speaker.on('error', (err) => {
console.error('❌ 播放错误:', err);
reject(err);
});
});
}
function playMP3WithFFmpeg(inputPath) {
return new Promise((resolve, reject) => {
// 获取 ffmpeg 路径(假设放在项目根目录)
const ffmpegPath = './ffmpeg.exe'; // 👈 修改为你自己的路径
// 构造 ffmpeg 命令:解码 MP3 → 输出为 PCM(stdout)
const args = [
'-i', inputPath, // 输入文件
'-f', 's16le', // 输出格式:16位有符号小端 PCM
'-ac', '1', // 单声道
'-ar', '16000', // 采样率 16kHz
'-acodec', 'pcm_s16le', // 编码器
'pipe:1' // 输出到 stdout
];
// 启动 ffmpeg 子进程
const ffmpegProc = spawn(ffmpegPath, args);
// 创建 Speaker 实例
let speaker = null;
// 监听 ffmpeg 输出
ffmpegProc.stdout.on('data', (chunk) => {
if (!speaker) {
// 第一次收到数据时初始化 Speaker
speaker = new Speaker({
channels: 1,
bitDepth: 16,
sampleRate: 16000,
});
// 将 PCM 数据写入扬声器
ffmpegProc.stdout.pipe(speaker);
// 播放完成回调
speaker.on('close', () => {
console.log('✅ 静默播放完成');
resolve();
});
speaker.on('error', (err) => {
console.error('❌ 播放错误:', err);
reject(err);
});
}
});
// 监听错误
ffmpegProc.stderr.on('data', (data) => {
// console.error('FFmpeg 错误:', data.toString());
});
ffmpegProc.on('error', (err) => {
console.error('❌ ffmpeg 启动失败:', err);
reject(err);
});
ffmpegProc.on('close', (code) => {
if (code !== 0) {
reject(new Error(`ffmpeg 退出码: ${code}`));
}
});
});
}
play()