nodejs 使用speaker + ffmpeg 实现静默播放MP3

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()
相关推荐
happybasic14 小时前
在CMD下使用FFmpeg将.wav文件转换成指定的格式~
ffmpeg
shao91851618 小时前
第10章 Streaming(上):初级音频应用(1)——项目三:自建服务器的Mini-Omni实时语音聊天机器人
ffmpeg·whisper·asr·mini-omni·自建语音服务器
Leon_Chenl1 天前
【已开源】【嵌入式 Linux 音视频+ AI 实战项目】瑞芯微 Rockchip 系列 RK3588-基于深度学习的人脸门禁+ IPC 智能安防监控系统
深度学习·opencv·yolo·ffmpeg·音视频·边缘计算·人脸识别+检测
antzou2 天前
视频图片/文字水印
ffmpeg·视频水印·批量水印
AC赳赳老秦3 天前
DBA 专属方案:用 OpenClaw 实现 SQL 语句优化、慢查询分析、数据库备份巡检全自动化
服务器·前端·数据库·ffmpeg·自动化·deepseek·openclaw
小叮当⇔4 天前
M4A 转 MP3 桌面转换器(PyQt5 + FFmpeg)
开发语言·qt·ffmpeg
aovenus7 天前
FFmpeg 官网及文档
ffmpeg
aovenus7 天前
FFmpeg 工具介绍
ffmpeg
jr-create(•̀⌄•́)7 天前
简单视频编辑tools
python·ffmpeg
山栀shanzhi7 天前
在做直播时,I帧的间隔(GOP)一般是多少?
网络·c++·面试·ffmpeg