Blog


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:

  1. To ensure that v4l2loopback is loaded:

    modprobe v4l2loopback devices=1 video_nr=10 card_label="VirtualCam" exclusive_caps=1

  2. We then create a virtual camera:

    sudo modprobe v4l2loopback devices=1 video_nr=10 card_label="VirtualCam" exclusive_caps=1

  3. 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.

  1. The modules used:

    1#!/bin/python
    2import shutil
    3import os

  2. 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 if v4l2loopback is available.

  3. The main function

     1def 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.