最近在研究 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