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

Linux服务器用Puppeteer实现带声浏览器录屏如何解决多进程音频串扰

Linux多进程网页音视频录制音频串扰解决方案

核心原理

所有音频串扰的根源是多进程的Chrome默认共用系统PulseAudio的同一个输出 sink,FFmpeg采集时会拾取所有输出到该sink的音频。只要为每个录制进程分配独立的专属虚拟音频sink,让对应Chrome的音频仅输出到该sink,FFmpeg仅采集该sink的音频流,即可完全实现音频隔离。

前置依赖

确保服务器已安装PulseAudio相关工具:

apt install pulseaudio pulseaudio-utils

代码修改点

  • 动态生成唯一ID,用于标识当前录制进程的专属资源
  • 动态分配xvfb显示号,避免多进程显示冲突
  • 启动录制前为当前进程创建专属PulseAudio虚拟sink
  • 启动Chrome时传入环境变量指定音频输出到专属sink
  • FFmpeg音频输入指定为专属sink的monitor端口
  • 进程结束后自动清理虚拟sink资源,避免残留

修改后完整代码

var Xvfb = require('xvfb');
var puppeteer = require('puppeteer');
const { spawn, spawnSync } = require('child_process');

async function record() {
    // 生成当前进程唯一标识
    const uniqueId = Date.now() + '_' + Math.floor(Math.random() * 10000);
    // 动态分配xvfb显示号,避免冲突
    const displayNum = 100 + Math.floor(Math.random() * 100);
    
    // 1. 创建专属PulseAudio虚拟sink
    const loadSinkRes = spawnSync('pactl', [
        'load-module', 'module-null-sink',
        `sink_name=rec_sink_${uniqueId}`,
        `sink_properties=device.description="rec_sink_${uniqueId}"`
    ]);
    const sinkModuleId = loadSinkRes.stdout.toString().trim();
    if (!sinkModuleId) {
        throw new Error('创建虚拟音频设备失败');
    }

    var xvfb = new Xvfb({
        displayNum: displayNum,
        reuse: false,
        xvfb_args: [
            "-screen", "0", "1920x1080x24",
            "-ac",
            "-nolisten", "tcp",
            "-dpi", "96",
            "+extension", "RANDR"
        ]
    });

    xvfb.startSync();

    // 2. 启动Chrome时传入环境变量,指定音频输出到专属sink
    var browser = await puppeteer.launch({
        headless: false,
        defaultViewport: null,
        ignoreDefaultArgs: [
            "--mute-audio",
            "--enable-automation"
        ],
        args: [
            "--use-fake-ui-for-media-stream",
            "--window-size=1920,1080",
            "--start-fullscreen"
        ],
        env: {
            ...process.env,
            PULSE_SINK: `rec_sink_${uniqueId}`
        }
    });
    const page = await browser.newPage();

    var url = "http://www.noiseaddicts.com/free-samples-mp3/?id=2544";
    await page.goto(url);
    await page.click('span.map_play');

    var time = new Date().getTime();

    // 3. FFmpeg音频输入指定为专属sink的monitor
    var options = [
        "-video_size", "1920x1080",
        "-framerate", "30",
        "-f", "x11grab",
        "-draw_mouse", "0",
        "-i", `:${displayNum}`,

        "-f", "pulse",
        "-ac", "2",
        "-i", `rec_sink_${uniqueId}.monitor`,
        "./output" + time + ".mkv"
    ];

    var cmd = 'ffmpeg';

    var proc = spawn(cmd, options);

    proc.stdout.on('data', function (data) {
        console.log(data);
    });

    proc.stderr.setEncoding("utf8")
    proc.stderr.on('data', function (data) {
        console.log(data);
    });

    proc.on('close', async function () {
        console.log('finished');
        // 4. 清理资源:先关浏览器、卸载虚拟sink,再关xvfb
        await browser.close();
        spawnSync('pactl', ['unload-module', sinkModuleId]);
        xvfb.stopSync();
    });
}

record();

注意事项

  • 若PulseAudio以系统服务运行,需确保运行Node.js进程的用户有pactl操作权限
  • 高并发场景下可预先分配一批可用的display号和sink标识,避免动态生成时出现冲突
  • 可添加异常捕获逻辑,确保进程意外退出时也能卸载sink模块,避免残留无效音频设备占用资源

内容的提问来源于stack exchange,提问作者NA GUY

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 09:00:00