为 Headless Linux 安装 Virtual Camera + Microphone

最近在研究 WebRTC,但由于本地环境不具有 Camara 和 Microphone,测试就变得不是很方便。再加上我把开发环境塞进了的 VM 中,Chrome 会阻止在非 HTTPS 页面上启动相关服务,因此考虑直接在 VM 中进行一些通话测试。

视 OS 不同,虚拟设备的实现方案会有所不同。其中 Windows 和 MacOS 是比较简单的:OBS 搞定 Camera 和视频源,VB-CABLE 搞定 Microphone,一个能选择输出设备的音乐播放器 (例如 QQ 音乐) 和音频源。

Linux 的情况则有所不同。虽然 OBS 也有 Linux 版本,但实践下来安装时会存在各种依赖问题,并不怎么好用;另外也还是需要单独的方案来实现 Virtual Microphone。因此我采用了下述方案:

  • tigervnc + x11 + xfce4 + chromium – 提供远程操作、调试环境;
  • v4l2loopback 内核模块 – 用于创建一个视频的回环设备;
  • pulseaudio module-pipe-source 模块 – 用于创建一个音频的 pipe source;
  • ffmpeg – 解码媒体文件,重编码音视频流并输出到设备。

在 Headless Linux 上安装 VNC 和 GUI 环境的方法已经有很多文章介绍了,因此本文就跳过不提了,着重描述音视频模块的安装部分。

v4l2loopback 模块

v4l2loopback 是一个内核模块,可以直接用 modprobe 命令安装。不过需要注意的是,想让 Chromium 能够正确捕获视频,还需要传递一些额外参数:

  • max_buffer=2 – 最多缓存 2 帧
  • video_nr=10 – 指定设备路径为 /dev/video10
  • exclusive_caps=1 – 开启独占捕获

因此模块加载和卸载的命令如下:

sudo modprobe v4l2loopback max_buffers=2 exclusive_caps=1 video_nr=10 card_label="VirtualCam"
sudo modprobe -r v4l2loopback

pulseaudio 模块

pulseaudio 内建有 module-pipe-source 模块,该模块允许从 Linux 管道文件中接收指定格式的音频流来作为一个音频 Source。在这里我们需要传递一些额外参数来描述数据格式:

  • format=s16le – 数据格式为 PCM signed 16-bit little-endian
  • rate=44100 – 采样率为 44100 Hz
  • channels=1 – 单声道
  • source_name=virtmic – 管理名称
  • file=/tmp/virtmic.input – 对应的管道文件

加载的同时不要忘记将其设置为默认 source,另外还可以开启一个 arecord 进程来避免管道处于阻塞状态。因此这部分的加载和卸载命令如下:

PIPE_MODULE_NO="/tmp/pa-module-$RANDOM"

pactl load-module module-pipe-source source_name=virtmic file=/tmp/virtmic.input format=s16le rate=44100 channels=1 > ${PIPE_SOURCE_NO}
pactl set-default-source virtmic
arecord /dev/null

pactl unload-module `cat ${PIPE_MODULE_NO}`

ffmpeg 推流

两个虚拟设备准备好后,还需要把用户加入 audio video 组中 (当然想偷懒其实也可以无脑 sudo),就可以开始推流了。这里使用了 ffmpeg 进行推流,但需要注意输出的音视频格式必须与前述设备参数相匹配:

  • -y – 直接覆盖文件
  • -re – 以原始帧率读入
  • -stream_loop -1 – 始终循环播放
  • -i output.mp4 – 输入的视频文件
  • -f v4l2 /dev/video10 – 视频以 v4l2 格式编码,写入 /dev/video10
  • -f s16le -ar 44100 -ac 1 /tmp/virtmic.input – 音频以 s16le 44100Hz 单声道方式编码,写入 /tmp/virtmic.input

因此这部分推流命令如下:

ffmpeg -y -re -stream_loop -1 -i output.mp4 -f v4l2 /dev/video10 -f s16le -ar 44100 -ac 1 /tmp/virtmic.input

如果看到 ffmpeg 启动且进度条开始往后播放,说明一切工作已经就绪,接下来就可以打开 Chromium 愉快的玩耍啦 XD

发表评论