LogiCam Tuner: fixing my Logitech StreamCam on the Mac with plain UVC
Logi Options+ was sluggish, WhatsApp video ran at 5 fps and auto exposure left my face dark. So I wrote a small open-source Mac app that talks to the camera directly, with smarter auto exposure and a live stats overlay for every call.
I recently bought a Logitech StreamCam and quickly ran into three problems:
- Logi Options+, the official app, was too slow and sluggish to do anything with.
- WhatsApp video calls looked like a slideshow.
- The camera's auto mode gave me a dark face and an amber colour cast that kept drifting for seconds.
So I built LogiCam Tuner, a small native Mac app (Swift and SwiftUI, with a bit of C) that fixed all three. It's free, MIT-licensed, and installs with one command:
brew install --cask harsh-gulhane/tap/logicam-tuner
It's an independent project, not made or endorsed by Logitech.
How the official app actually talks to the camera
Before writing anything, I wanted to know what Options+ does under the hood (I kept notes). The window you see is an Electron app. The real work happens in a separate background agent, which the UI talks to over a local Unix socket. That socket ignores clients that aren't signed by Logitech, so it was a dead end.
ioreg told the more useful story: the agent holds the StreamCam's UVC Video Control
interface. UVC (USB Video Class) is the standard every USB webcam speaks, and the image controls are
plain UVC class control requests: exposure time, gain, white balance, focus, zoom and the rest. So
LogiCam Tuner sends the same requests itself, through IOKit, from a small C shim. No driver, no kernel
extension and no Options+ running in the background, and a slider change reaches the camera instantly.
The first surprise came straight away: every setting that has an auto mode looked permanently locked. The StreamCam sets UVC's "disabled by automatic mode" flag all the time, even when the auto mode is off. The app ignores that flag and works out what is locked from the auto controls' actual values.
Smart Auto: exposure and white balance that stay put
The camera's own automatics were the real annoyance. In a dim room it picked 1/25 s at full gain, left whites amber (about 5230 K), and kept nudging both up and down. Smart Auto replaces them, while any app is using the camera:
- Faces first. It meters the faces it detects in a small copy of the video, blended with the scene, so a bright window behind me no longer leaves my face dark.
- Hysteresis. It starts correcting only when the error is clearly visible (0.25 EV), and stops close to the target. Same idea as alerting thresholds: don't react to noise.
- White balance from grey things. Only near-neutral, well-exposed pixels outside faces count, so a coloured shirt or wall can't pull the colour. With too few of them, it holds the current setting instead of guessing.
- No flicker. It spends shutter time before gain, and snaps the shutter to whole mains periods (10 ms at 50 Hz, 8.3 ms at 60 Hz) so lights don't band.
In that same room it settles at 1/17 s, which still allows 15 fps, with neutral whites at about 3400 K, in roughly two seconds. That's one camera in one room, so your numbers will differ.
The best bug of the project was exposure bouncing between two settings. It was caught by offline tests that run the controller against a simulated camera, built from behaviour measured on the real StreamCam: weak gain, an exaggerated tone curve, and anti-flicker allowing only whole 10 ms shutter steps. Small corrections now go through gain only. Testing against a faithful model of the real thing beats testing against an idealised one, in a webcam as much as in production.
Why WhatsApp ran at 5 fps
To understand what each call app gets from the camera, I added a small floating overlay. It shows which app is using the camera, the resolution, the frame rate the app asked for and the rate actually delivered, plus shutter, ISO and white balance.
It answered the WhatsApp question in a few seconds. WhatsApp picks the camera's largest mode, 2304×1296, and the StreamCam can only deliver that at 5 fps. Every app sharing the camera shares one mode, so LogiCam Tuner switches it to 1080p at 30 fps a couple of seconds after such an app starts. It only switches to a mode with the same picture shape, and gives up after two tries per session, so it never fights an app that insists on its own mode.
Who is using my camera?
macOS has no public API that says which app is using a camera. It only says that the camera is running. But CoreAudio does name the processes capturing the microphone, and call apps capture the mic along with the camera, so those are reported first. Failing that, the overlay shows the frontmost app known to use cameras, marked with a "?". It's a heuristic, and the app labels it as one.
The overlay follows whichever camera a call uses, including the MacBook's built-in camera and Continuity Camera. Those have no manual controls, but every frame carries metadata from the image pipeline, so the overlay can still show shutter speed, ISO and colour temperature.
Respecting the camera light
A camera tool should never be the reason the green light is on. LogiCam Tuner never turns the camera on by itself: Smart Auto runs only while another app is streaming or the preview is open. Video is analysed in memory and never recorded or sent anywhere.
One bug broke exactly that. After a call ended, the camera stayed on, because macOS takes a moment to release the camera and the app mistook its own fading stream for another app. It now waits for the release, and turns the camera off within about 10 seconds of a call ending.
For the terminal people
It comes with a logicam command-line tool:
logicam list
logicam set brightness=140 white_balance_auto=off white_balance=4500
logicam preset save desk
logicam auto --watch # print Smart Auto's measurements, change nothing
logicam who # which cameras are streaming, and the likely apps
What's next
A portrait camera for WhatsApp. The StreamCam only produces landscape video, and delivering a portrait stream to other apps needs a virtual camera. I'm researching that now.
It's built and tested on the StreamCam. Other Logitech webcams (Brio, C920, C922) and most UVC
cameras should work, but are untested. If you have one, a report with logicam list and
logicam describe output would help a lot.
The code is on GitHub.