snapshot of https://github.com/jitsi/jibri.git @ 3b45602c539ec69d128ea152ae587d0b6582191a (2026-09-15)
Some checks failed
Java CI with Maven / Java 17 (push) Failing after 4m40s
Java CI with Maven / Java 21 (push) Failing after 4m41s

This commit is contained in:
upstream-mirror
2026-09-15 16:13:58 +05:00
commit 650a143b63
166 changed files with 14301 additions and 0 deletions

310
doc/local-run/README.md Normal file
View File

@@ -0,0 +1,310 @@
# Running jibri locally against a docker-jitsi-meet deployment
This directory contains a script and a docker-compose override that let you
run jibri **from this source tree** while the rest of the Jitsi stack
(prosody, jicofo, jvb, web) runs in docker via
[docker-jitsi-meet](https://github.com/jitsi/docker-jitsi-meet). Useful for
iterating on jibri code changes without rebuilding the docker image.
## Files
- `run-jibri-local.sh` — generates `jibri.conf` + `logging.properties` from
your `docker-jitsi-meet/.env`, builds jibri if needed, and launches it.
- `prosody.override.yml` — publishes prosody's port 5222 on `127.0.0.1` so
the host-side jibri can reach it. The default compose only `expose:`s
this port inside the docker network.
## Prerequisites
- `docker` + `docker compose`
- `mvn` and Java 17 (to build jibri)
- `ffmpeg` on `PATH` (jibri shells out to it for capture)
- A clone of [docker-jitsi-meet](https://github.com/jitsi/docker-jitsi-meet)
(defaults to `~/dev/docker-jitsi-meet`; override with `DOCKER_JITSI_DIR`)
- A `chromedriver` binary at the jibri repo root, matching your installed
Chrome milestone (download from <https://googlechromelabs.github.io/chrome-for-testing/>)
## Step by step
### 1. Set up docker-jitsi-meet
```sh
cd ~/dev/docker-jitsi-meet
cp env.example .env
./gen-passwords.sh
mkdir -p ~/.jitsi-meet-cfg/{web,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri}
```
### 2. Edit `.env`: enable recording and set `PUBLIC_URL`
Two changes in `~/dev/docker-jitsi-meet/.env`:
**Enable recording.** This is what tells prosody to provision the `jibri`
and `recorder` accounts (using `JIBRI_XMPP_PASSWORD` /
`JIBRI_RECORDER_PASSWORD` from `gen-passwords.sh`) and what makes the web
UI surface the record button. Without it, jibri can't even log into
prosody.
```sh
ENABLE_RECORDING=true
```
**Point `PUBLIC_URL` at your LAN IP.** Jibri opens the conference URL in
Chrome from the host. `localhost` won't do, because Chrome's WebRTC needs
an address that resolves the same way for jibri *and* the other browsers
joining the call. Use the host's LAN address.
Find your local IP:
```sh
# macOS
ipconfig getifaddr en0
# Linux
hostname -I | awk '{print $1}'
```
Then set (HTTP/HTTPS port already exist in env.example — adjust if you
moved them):
```sh
HTTP_PORT=8000
HTTPS_PORT=8443
PUBLIC_URL=https://192.168.1.42:8443 # ← your IP and the HTTPS_PORT
```
The script copies `PUBLIC_URL` into jibri's `base-url`, so jibri opens
`https://192.168.1.42:8443/<room>` instead of the default `https://meet.jitsi/`.
### 3. Bring the stack up with prosody 5222 published
The host-side jibri talks to prosody over XMPP, so we need 5222 reachable
from the host. Apply the override from this directory:
```sh
cd ~/dev/docker-jitsi-meet
docker compose \
-f docker-compose.yml \
-f ~/dev/jibri/doc/local-run/prosody.override.yml \
up -d
```
Confirm prosody is listening on the host:
```sh
nc -zv 127.0.0.1 5222 # → "succeeded!"
```
### 4. Build jibri
```sh
cd ~/dev/jibri
mvn -B -DskipTests clean package
```
The script will also build automatically if no jar is found in `target/`.
### 5. Drop a matching `chromedriver` next to the jibri repo
```sh
# look up your Chrome major version
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --version
# fetch the matching chromedriver and place it at ~/dev/jibri/chromedriver
# (see https://googlechromelabs.github.io/chrome-for-testing/)
chmod +x ~/dev/jibri/chromedriver
```
### 6. (Linux only) Set up audio routing for ffmpeg
Jibri's default ffmpeg config captures audio from the ALSA PCM `plug:bsnoop`,
which is a custom loopback device defined in `/etc/jitsi/jibri/asoundrc` and
backed by the kernel `snd-aloop` module. The .deb postinst sets this up for
the system `jibri` user; if you're running locally as your own user, you
need to do it yourself, or switch to PulseAudio capture.
**Option A — ALSA loopback (matches the deb):**
```sh
# 1. Load the kernel loopback module (creates ALSA card "Loopback")
sudo modprobe snd-aloop
# Persist across reboots
echo snd-aloop | sudo tee /etc/modules-load.d/snd-aloop.conf
# 2. Drop jibri's asoundrc as your user's ALSA config
cp ~/dev/jibri/resources/debian-package/etc/jitsi/jibri/asoundrc ~/.asoundrc
# Verify
aplay -L | grep bsnoop
arecord -D plug:bsnoop -f cd -d 1 /tmp/t.wav && echo OK
```
Caveat: this changes your default ALSA device to a loopback, and on a
modern Ubuntu desktop Chrome routes audio through PulseAudio/PipeWire — so
even with `bsnoop` defined, Chrome won't play into the loopback unless you
also force Chrome to ALSA (e.g. `PULSE_SERVER=/dev/null`).
**Option B — PulseAudio capture (recommended on a desktop dev box):**
Skip the asoundrc/snd-aloop setup entirely and override the audio knobs
when invoking the script:
```sh
JIBRI_AUDIO_SOURCE=pulse \
JIBRI_AUDIO_DEVICE=default \
~/dev/jibri/doc/local-run/run-jibri-local.sh
```
`default` reads from Pulse's default source. To capture system audio
specifically, find the right monitor source with `pactl list short sources`
and pass it as `JIBRI_AUDIO_DEVICE` (e.g. `alsa_output.pci-…analog-stereo.monitor`).
### 6b. (macOS only) Capture the screen instead of the camera
Jibri's default macOS ffmpeg input is `-i 0:0` — whatever avfoundation
device 0 is (usually a camera + the mic). To record the conference you
want a **screen** device for video and a **loopback** device for audio.
1. **Grant Screen Recording permission** to the terminal app you launch
the script from (System Settings → Privacy & Security → Screen
Recording), then fully quit and relaunch the terminal. Without it
avfoundation silently produces black frames.
2. **Install a loopback audio device**, e.g. [BlackHole](https://github.com/ExistentialAudio/BlackHole)
(`brew install blackhole-2ch`), and route the call audio into it:
Audio MIDI Setup → `+` → *Create Multi-Output Device* → check both
BlackHole and your speakers, then select that multi-output device as
the system sound output. (Selecting BlackHole alone also works, but
you won't hear anything.)
3. **Find the device indices**:
```sh
ffmpeg -f avfoundation -list_devices true -i ""
# e.g. video: [2] Capture screen 0 audio: [2] BlackHole 2ch
```
4. **Run with the indices**:
```sh
JIBRI_MAC_VIDEO_DEVICE=2 JIBRI_MAC_AUDIO_DEVICE=2 \
~/dev/jibri/doc/local-run/run-jibri-local.sh
```
Note avfoundation screen devices capture the *whole* display at native
(retina) resolution — there is no per-window capture in ffmpeg on macOS.
The script scales the output down to `JIBRI_RECORDING_RESOLUTION` width,
but whatever else is on that screen ends up in the recording, so keep the
jibri Chrome window in front (or point it at a secondary display, e.g.
`Capture screen 1`).
### 7. Run jibri
```sh
~/dev/jibri/doc/local-run/run-jibri-local.sh
```
You should see:
```
config: /Users/you/dev/jibri/.local/jibri.conf
jar: /Users/you/dev/jibri/target/jibri-*-jar-with-dependencies.jar
chromedriver: /Users/you/dev/jibri/chromedriver
xmpp: 127.0.0.1:5222 (domain=meet.jitsi)
… INFO: Jibri starting up …
… INFO: Connecting to xmpp environment on 127.0.0.1 …
… INFO: Joined MUC: jibribrewery@internal-muc.meet.jitsi
```
Now open `https://192.168.1.42:8443/<room>` in two browsers, click the
record button — jibri will pick up the start IQ and join the call.
## Where things land
Generated files live under `~/dev/jibri/.local/`:
| File | Purpose |
|---|---|
| `jibri.conf` | HOCON config built from `.env` |
| `logging.properties` | JUL config (console + ffmpeg/browser file handlers) |
| `recordings/<session-id>/*.mp4` | recorded files |
| `ffmpeg.0.txt` | ffmpeg stderr (JUL captures it; not on console) |
| `browser.0.txt` | chrome browser logs |
| `chromedriver.log` | chromedriver's own log |
## Configuration knobs
All overridable as env vars when invoking the script:
| Var | Default | Notes |
|---|---|---|
| `JIBRI_DIR` | resolved from script path | jibri repo root |
| `DOCKER_JITSI_DIR` | `$HOME/dev/docker-jitsi-meet` | source of `.env` |
| `XMPP_HOST` | `127.0.0.1` | where prosody is reachable |
| `XMPP_PORT` | `5222` | matches `.env` if set there |
| `JIBRI_INSTANCE_ID` | `jibri-local-$$` | shows up as MUC nickname |
| `CHROMEDRIVER` | `$JIBRI_DIR/chromedriver` | path to chromedriver binary |
| `JIBRI_AUDIO_SOURCE` | `alsa` | Linux: ffmpeg `-f` for audio (`alsa`, `pulse`) |
| `JIBRI_AUDIO_DEVICE` | `plug:bsnoop` | Linux: ffmpeg audio input device (e.g. `default` for pulse) |
| `JIBRI_MAC_VIDEO_DEVICE` | unset | macOS: avfoundation video index (use a `Capture screen N` device) |
| `JIBRI_MAC_AUDIO_DEVICE` | unset | macOS: avfoundation audio index (use a loopback device, e.g. BlackHole) |
## Troubleshooting
**`permission denied while trying to connect to the docker API at unix:///var/run/docker.sock`**
— Linux only; your user isn't in the `docker` group. Fix:
```sh
sudo usermod -aG docker $USER
newgrp docker # apply the new group in this shell, or log out/in
docker ps # verify
```
Avoid `sudo docker compose …` — files written to `~/.jitsi-meet-cfg` end up
root-owned and bite you later.
**`cannot reach prosody at 127.0.0.1:5222`** — you brought up the stack
without `prosody.override.yml`. Re-run step 3.
**`This version of ChromeDriver only supports Chrome version N`** — your
chromedriver and Chrome milestones don't match. Re-fetch chromedriver for
your Chrome version (step 5).
**Jibri opens `https://meet.jitsi/<room>` instead of your IP** — `PUBLIC_URL`
isn't set in `.env`, or you didn't restart the script after editing `.env`.
**`No such file or directory: /var/log/jitsi/jibri/chromedriver.log`** —
older jibri pinned that path unconditionally. Pull a tree where
`webdriver.chrome.logfile` is overridable, or `mkdir -p` the path with
write permissions.
**ffmpeg quits with `Unknown PCM bsnoop` / `cannot open audio device plug:bsnoop`**
on Linux — you don't have the ALSA loopback set up. Either follow step 6
Option A (snd-aloop + `~/.asoundrc`) or skip ALSA and use Pulse via
`JIBRI_AUDIO_SOURCE=pulse JIBRI_AUDIO_DEVICE=default`.
**ffmpeg quits abruptly with "Error opening output files: Invalid argument"**
on macOS — usually an avfoundation arg conflict. Inspect
`~/dev/jibri/.local/ffmpeg.0.txt` for the real ffmpeg stderr. Note that the
default macOS ffmpeg input is `-i 0:0` (camera + system mic), so the
resulting mp4 records your camera, **not** the chrome window — see step 6b
for screen capture via `JIBRI_MAC_VIDEO_DEVICE`/`JIBRI_MAC_AUDIO_DEVICE`.
**Black video on macOS** — the terminal app that launched the script lacks
the Camera (default `0:0` input) or Screen Recording (screen-capture input)
permission. avfoundation doesn't error on a denied device; it delivers
black frames. Grant the permission in System Settings → Privacy & Security
and fully restart the terminal app.
**Black video on Linux** — you're on a Wayland session
(`echo $XDG_SESSION_TYPE`), where `x11grab` cannot see the screen and
records black. Either log into an Xorg session, or run a dedicated virtual
display and point both Chrome and ffmpeg at it:
```sh
Xvfb :1 -screen 0 1280x720x24 &
DISPLAY=:1 ~/dev/jibri/doc/local-run/run-jibri-local.sh
```
(the second part — overriding ffmpeg's hardcoded `-i :0.0+0,0` grab target —
currently requires editing `input-linux` in the generated conf).