If you're like many of us, video conferencing has become an essential part of your daily workflow. With that comes a shared—and often frustrating—experience:
The Universal Struggle of Scattered Controls
- The frantic hunt for the mute button while presenting or whiteboarding
- Maybe you've tried using Keyboard shortcuts, only to find out they only work with the foreground app or betray you by conflicting with other apps
- The uncomfortable moment of "The host has muted you" because who knows when your mic was left open
- Or contrary to that, realizing you've been passionately making a point to no one, because you were on mute the whole time... 🤦
As someone who spends a significant part of their day presenting to customers, hunting for the unmute icon is a familiar frustration. It breaks the flow of the presentation and, frankly, feels unprofessional.
This is the story of how I built an open-source telephony controller to get back that control. It's a custom ESP32 device engineered to solve a tricky remote desktop problem using multi-device Bluetooth, giving me tactile and visual control over my calls.
A Smart, Dedicated Google Meet Controller
To address these challenges head-on, I developed Yapper for Google Meet. It's just a mute button really—just a couple of extra bells and whistles—but it's a device designed to integrate into a complex, real-world workflow involving multiple applications and remote connections.
Key Features:
🎯 Multiple Inputs: A capacitive touch sensor, mechanical buttons, and a rotary encoder provide a range of tactile control options suited for different actions
🔄 Dual-Mode HID: It can send HID USB keyboard commands for things like volume control while also providing status updates via Bluetooth
📡 Multi-Client Bluetooth: This allows for a simultaneous connection to multiple computers
🌐 Cross-Platform Support: The device is compatible with Windows, macOS, Linux, and mobile devices using the HID-compliant protocol
💡 Visual Feedback System: An RGB LED strip gives you an unmistakable, at-a-glance confirmation of your mute status, with customizable brightness that's saved to the device's flash memory
You can check it out NOW in this repo: rolandostar/google-meet-yapper
Technical Deep Dive: The Story Behind the Build
Every part of this project tells a story of iteration and discovery. The final device is the result of tackling unexpected problems and rethinking initial assumptions. Here's a walk-through of the journey and the key hardware decisions I made along the way.
I'm certainly not the first to tackle the mute button problem. There are other fantastic projects out there, like this excellent USB mute button.
My approach, however, focuses a bit more on the hardware interface decisions—the story of how those choices shaped the final device.
From USB to Multi-Client BLE
My first choice for the controller's brain was the ESP32-S3 DevKit-C-1. It seemed perfect. I specifically wanted to use its native USB HID support to emulate a keyboard directly. The plan was simple: the device would connect via USB and communicate with Google Meet via HID Telephony Events and Outputs.
Then I Hit a Wall 🚧
When I connected to my work laptop via Remote Desktop, my simple USB approach failed completely. I needed two things, sending Keyboard strokes, and capturing Telephony HID data. If I connected the device my work's laptop then the RDP client captures keyboard inputs from my local machine, meaning any keyboard commands from a USB device connected to the host laptop were ignored.
And conversely if I connected the device to my PC, then Telephony events don't bubble up through the remote desktop protocol, so even though the device was "connected" to the laptop, it was unable to receive call-related data. If this was a simple one-device one-machine setup, I could have reached this point and be done. (I'm sharing a version of this code as well, as a simple "starting point" for other implementations.)
But for me and my real-world setup, my project was dead in the water—until I had a realization.
BLE-HID was a thing, it just came down to implementation. Instead of a simple USB device, I decided to build a BLE HID device with multi-client support. This would allow the controller to connect to both my host laptop and my RDP client at the same time, routing commands to both.
The Mute Button Evolution
Creating an effective mute button presented a key technical challenge. I decided early on that the primary control should be a silent, capacitive touch sensor, avoiding distracting clicks during calls.
My initial concept involved a sleek, flat "screen" with edge-lighting, using an acrylic sheet wrapped in aluminum foil to improve the glow. I found a YouTube video, which demonstrated promising results for diffusing LED light with acrylic tiles and aluminum tape.
The Prototype Failed ❌
The light did not illuminate the screen correctly, resulting in an uneven glow with noticeable hotspots. I struggled to combine the capacitive touch requirements, such as a conductive plane or at least a capacitive copper plate as a sensing area, with thin layers of material. The reliability of the capacitive sensor remained a significant challenge. It was finicky, accidentally triggering or not responding at all. After a period of frustration and research, I discovered a breakthrough: I could use a ground plane behind the sensing area, in the form of yet another copper plate.
This simple addition made the sensor directional and significantly improved its consistency, providing the reliable touch detection I needed while still accommodating an edge-lighting solution that did not rely on bouncing light within the acrylic sheet.
Excuse the wiring, ahem...
From Screen to Silicon Button
While I was testing the capacitive screen concept, I had only the screen on the device—no other buttons were installed yet. Aesthetically, it looked clean. But when I added the mechanical buttons for other functions, the flat screen suddenly looked too low and out of place. The whole design felt unbalanced.
This led to another iteration. Inspired by the satisfying feel of MIDI launchpads, I decided to create a raised, soft-touch silicon button instead of a flat screen.
I 3D-printed a custom mold and filled it with a standard silicon gun. It's obviously not an ideal production method, but it worked beautifully. It solved the height problem and gave the device a unique, professional feel ——even with the bubbles trapped in there, it's not too shabby.
As a final touch, I dabbed some ink from a fountain pen onto the relief of the text, and the end result passes the good-enough bar.
Labels for Mechanical Buttons
For secondary functions, I wanted the satisfying, tactile feedback of mechanical Cherry MX-style switches. They feel great to press, but I immediately ran into a new problem: how could I label them? I don't own a laser engraver, and I wanted a solution that would let me change the labels as I got more acquainted with the device.
My solution was to modify an existing 3D model. I 3D-printed a set of low-profile keycaps but added a "window" slot to the design. This allows a small piece of paper to be inserted as a label, giving me fully customizable, professional-looking buttons.
The paper will wear out, of course, but it's a great proof of concept until I can get my hands on some transparent filament to upgrade.
I created the window with a negative box volume in SuperSlicer, and here's a document with other, alternative icons you can print and cut for your own build: Icons for Keycaps Labels
Google Meet Integration
Google Meet offers native telephony controls, but they aren't enabled by default. To utilize a custom device like the Yapper for Google Meet, you'll need to enable these settings within Google Meet's call control section.
Once your device is connected via Bluetooth and correctly reports its telephony descriptor, it should appear as an available option in these settings. This allows Google Meet to recognize and respond to the device's commands, seamlessly integrating the hardware controller into your conferencing experience.
One small disavantage is that the BLE HID mechanism does not support device name, so even when set, it'll always show as "Unkown device" in the pairing screen, which I can live with.
Finally some videos, here's the host device pushing mute state to the device:
And Push-to-Talk funcitonality:
(Notice the mute state on both calls updating at the same time)
Final thoughts
This entire process of iteration—from USB to BLE, from acrylic screen to silicon button—is a perfect example of how technical projects evolve. I found this project to be an artistic approach to engineering, a very organic journey which taught me that the best designs often emerge from overcoming unexpected roadblocks.
Ready to Build? 🚀
Ready to build a tool that truly understands your workflow? Find all the resources you need below. Contributions to the open-source project are always welcome.
Resources:
- 📂 Source Code: Github Repo
- 🔧 Hardware Wiring: Pin Configuration
- 🖨️ 3D Models (including silicon mold): OnShape Public File
- 💬 Community: Feel free to raise any issue-based discussions
Top comments (0)