Currently we are all stuck in front of webcams, at least half the time. I do have a laptop—a gift from a kind friend—and it does get used, but the rest of the time I am sitting before two old monitors (one of which recently had to be repaired) and a lovely cherry keyboard: and no webcam. No matter: I’ve a cheapo usb-thing and it works fine. I’ve also an old phone handset from an 80s landline wired into two 3.5mm jacks—it had an electret microphone and works fine. It gets laughs on zoom, but it’s easier to pick up and put down than a headset, and I can hear if anyone’s creeping up behind me.
Problem: the el-cheapo usb camera is permanently on when plugged in. And crawling down behind the computer to plug it in isn’t really an option. Worse, it has no status indicating light. Now I’m not that paranoid—if the NSA wants to see me in jumpy 640x480 frames, they can probably get at my webcam. I doubt they care much. But still, not knowing whether one’s webcam is on is a little unsettling…
It’s a usb device, so the first thing to look at is /sys
. A quick
google suggested that first we need the bus and port ID, and then we
can bind and unbind a driver by writing to
/sys/bus/usb/drivers/unbind
. Thus:
def get_webcam():
"""Get webcam usb."""
cameras = []
for product in Path("/sys/bus/usb/devices").glob("*/product"):
if "camera" in product.read_text().lower():
cameras.append(str(product).split("/")[-2])
return cameras
Liable to have false positives if a digital camera is plugged in, but
better safe than sorry (don’t go running --disable
unless you’re
sure only one webcam is attached…)
and then something like:
def disable_webcam(webcam: str):
with Path("/sys/bus/usb/drivers/usb/unbind").open("w") as f:
f.write(webcam)
To query the status, we can look to see if 1. any webcams are found
and 2. they have a bound driver. I run i3 and
use i3status with a python wrapper
script as per the docs to display the status of redshift
and the
amount of time I have spent typing at the computer that day, from my
anti-rsi package. Thus it was easy enough to add another function:
def webcam_status():
webcams = get_webcam()
statuses = []
for webcam in webcams:
if webcam:
status = get_webcam_status(webcam)
if status:
statuses.append(("R", red))
else:
statuses.append(("", green))
else:
statuses.append(("O", orange))
return statuses
where the colours are html codes defined elsewhere. This is then injected into the json:
for webcam, colour in webcam_status():
j.insert(0, {"full_text": webcam, "name": "webcam", "color": colour})
and if the webcam is recording, a red ‘R’ appears in the status line.
I’m sure there are ways to trick this, but the kind of access you’d
need to the system to be able to rename a usb device or access it
without the kernel knowing a driver had been bound (or indeed, just
replace my wrapper.py
) is probably more than I care to defend
against anyhow.
The script is up on GitLab if anyone else has need of it.