Voidline Meet

A self-hosted video conferencing desktop app built on LiveKit Meet and Electron.

Web users and desktop users join the same rooms — fully interoperable.


Packages

Package Description
packages/meet-core Fork of livekit-examples/meet — Next.js web app, tracks upstream
packages/desktop Electron wrapper with native screen picker and per-app audio capture

Quick start

Prerequisites

Install

pnpm install

Run (Electron desktop app)

cd packages\desktop
pnpm electron:compile
pnpm electron:dev

The app opens directly into the Voidline room. In dev it loads http://localhost:3000/rooms/voidline; in production it loads https://voidline-vid.duckdns.org/rooms/voidline.


Building for distribution

To produce a Windows installer (.exe) to share with others:

cd packages\desktop
pnpm electron:build

This runs three steps in sequence: 1. Builds meet-core (next build) 2. Compiles the Electron TypeScript (tsc) 3. Packages everything with electron-builder

The installer lands at:

packages/desktop/dist/Voidline Meet Setup <version>.exe

Share that file with your friends — they just run it and the app installs like any other Windows program, with a desktop shortcut and Start Menu entry.

Notes for recipients

Bumping the version

Before building a new release, update the version in packages/desktop/package.json:

"version": "0.2.0"

Then tag the commit:

git tag v0.2.0
git push origin main --tags

Architecture

voidline-meet/
  packages/
    meet-core/              ← livekit-examples/meet fork (tracks upstream)
    desktop/
      electron/
        main.ts             ← Main process, BrowserWindow setup
        preload.ts          ← contextBridge for renderer
        screenPicker.ts     ← Intercepts getDisplayMedia, shows native picker
        audio.ts            ← Per-process audio capture (wraps application-loopback)
        picker/             ← Picker UI (HTML/CSS/JS)
      lib/
        AppAudioButton.tsx  ← Audio capture toolbar button + process picker
        useAppAudio.ts      ← Renderer-side AudioWorklet hook
        audioWorkletProcessor.js ← PCM player (int16→float32, 48kHz)
        VolumeControl.tsx   ← Per-user volume slider + mute toggle
        VolumeMixer.tsx     ← Floating mixer panel (one slider per remote participant)
      vendor/
        application-loopback/ ← Vendored WASAPI capture binary (MIT)
  package.json              ← pnpm workspace root
  pnpm-workspace.yaml

How screen sharing works

  1. LiveKit Meet calls getDisplayMedia() internally via @livekit/components-react
  2. Electron intercepts via session.defaultSession.setDisplayMediaRequestHandler()
  3. desktopCapturer.getSources() fetches all screens/windows with thumbnails
  4. A child BrowserWindow renders a picker grid
  5. User selects a source → passed back to LiveKit as if getDisplayMedia() resolved normally

How per-app audio capture works

Audio capture uses application-loopback (vendored, MIT), a thin Node.js wrapper around a custom C++ binary that uses the Windows WASAPI loopback API.

Two capture modes are supported: - Window share → include mode: captures audio only from the shared window’s process - Full-screen share → exclude mode: captures all system audio except a chosen process (e.g. mute Discord while sharing your desktop)

The AppAudioButton toolbar button lets users pick the audio source, mute/unmute, and manage a hide list to reduce noise from system processes. Captured PCM is streamed to the renderer via IPC, decoded in an AudioWorklet, and published as a LiveKit ScreenShareAudio track.

How per-user volume control works

A floating 🎚️ button sits bottom-right above the control bar. Clicking it opens a mixer panel listing all remote participants, each with a name label and volume slider. VolumeControl calls RemoteAudioTrack.setVolume() on all of the participant’s subscribed audio tracks. Works for both web and Electron users.


Pulling upstream updates to meet-core

git fetch upstream-meet
git checkout upstream-meet/main -- packages/meet-core
git add packages/meet-core
git commit -m "chore: sync meet-core with upstream"

Roadmap

Phase Status Description
1 ✅ Complete Electron wrapper + native screen/window picker
2 ✅ Complete Per-app audio capture (WASAPI via vendored application-loopback)
3 ✅ Complete Per-user volume mixer (floating panel, one slider per remote participant)

Infrastructure