Stream Your Screen as a Webcam
Why
Well, Microsoft Teams sucks, and it sucks even more on Linux. Now the web app was bearable until I realized it wouldn’t let me share my screen. This isn’t an isolated issue. A lot of video calling clients struggle to handle screen sharing on Linux. Discord at least manages to share the screen without audio. In this blog post, I’ll walk you through a workaround that works on all clients I tested.
Sharing your audio through your mic
Using a patch bay or an audio routing tool. You can route a certain application’s audio to the input of the application you’d like to steam to. Avoid routing your output monitor to your input, as the people you’re on call with will be able to hear themselves.
I would recommend using PipeWire to handle routing and any routing/patchbay GUI applications built for it. Reference this Arch wiki page to find a application that works for you.
Sharing your screen as a virtual camera
This is where the fun begins. If you are less experienced with Linux, I would highly recommend using OBS and its virtual cam functionality to get started quickly. Combining it with the techniques covered, you can get full “steaming” functionality.
Otherwise, I created a Python script to directly create a virtual camera using the v4l2loopback
module and stream screen to the virtual camera using ffmpeg
The commands used
First things first, lets cover the commands that we will automate:
-
To ensure that
v4l2loopback
is loaded:modprobe v4l2loopback devices=1 video_nr=10 card_label="VirtualCam" exclusive_caps=1
-
We then create a virtual camera:
sudo modprobe v4l2loopback devices=1 video_nr=10 card_label="VirtualCam" exclusive_caps=1
-
Finally we use
FFMPEG
to stream screen directly to the virtual camera:ffmpeg -video_size 1920x1080 -framerate 30 -f x11grab \ -i :0.0+0,0 -pix_fmt yuv420p -f v4l2 /dev/video10
The Python script
I created a Python script to automate this process. Scripting this allows us to check weather everything is in order.
-
The modules used:
1#!/bin/python 2import shutil 3import os
-
Some helper functions
1def is_tool(name): 2 """Check whether `name` is on PATH and marked as executable.""" 3 return shutil.which(name) is not None 4 5 6def checking_loopback(): 7 res = os.popen("whereis v4l2loopback") 8 out = res.read().split(':')[1] 9 if len(out) >= 2: 10 return True 11 else: 12 return False
checking_looopback
specifically checks ifv4l2loopback
is available. -
The
main
function1def main(): 2 print("Please ensure v4l2loopback is installed") 3 if not checking_loopback(): 4 print("Can't find v4l2loopback") 5 return 0 6 7 for i in ["modprobe", "ffmpeg"]: 8 if not is_tool(i): 9 print(f"Tool not found, install {i}") 10 return 0 11 12 print("Reloading v4l2loopback") 13 cmd = "sudo modprobe -r v4l2loopback" 14 if os.system(cmd) != 0: 15 print("Failed to reload v4l2loopback") 16 17 print("Creating virtual camera") 18 cmd = """sudo modprobe v4l2loopback devices=1 \ 19video_nr=10 card_label="VirtualCam" exclusive_caps=1""" 20 if os.system(cmd) != 0: 21 print(f"Failed to load module: {cmd}") 22 23 print("Running stream") 24 cmd = """ffmpeg -video_size 1920x1080 -framerate 30 -f x11grab \ 25-i :0.0+0,0 -pix_fmt yuv420p -f v4l2 /dev/video10""" 26 os.system(cmd)
The code first checks that v4l2loopback
, modprobe
and ffmpeg
are installed. Then we simply run the commands to get everything set up.
You can find virtual_cam.py
here.
Conclusion
As cool as this is, it is a workaround nonetheless. I hope to see developers on all platforms take a more active approach to supporting Linux. I think most applications can deal with this by relying on PipeWire being installed.