Skip to content
Giuseppe-sciarraPublic

About

Self-hosted video meetings for teams and clients: mediasoup SFU, screen sharing with live annotations, virtual backgrounds and face effects, waiting room, scheduled meetings with email invites, local recording. Node.js + Docker. AGPL-3.0.

Topics

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

56 Commits

Folders and files

Repository files navigation

Tiditalk

Self-hosted video meetings for teams and clients — WebRTC with a mediasoup SFU, on your own server, with Docker. No accounts for guests, no third-party cloud, your branding.

🌐 Website (in Italian): tastieredigitali.tech/casi-studio/tiditalk

🇮🇹 Leggi in italiano


Screenshots

Screen sharing with live annotations (highlighter, arrow, text, pen) on the presenter's slides — speaker view with the participants on the side

Home: device check with camera preview, live mic level and speakers test; new meeting with the room code generated while you type
Home: device check with camera preview, live mic level and speakers test; new meeting with the room code generated while you type
Waiting room like Google Meet: the hosts admit or deny guests from a card, badge on the People button
Waiting room like Google Meet: the hosts admit or deny guests from a card, badge on the People button
Call settings — Room section: waiting room, lock the room, guest permissions, mute everyone
Call settings — Room section: waiting room, lock the room, guest permissions, mute everyone
Polls: live results, anonymous or with names, change your vote while it is open
Polls: live results, anonymous or with names, change your vote while it is open
Network & quality: bandwidth, latency and jitter graphs, loss, one row per stream, direct or TURN path
Network & quality: bandwidth, latency and jitter graphs, loss, one row per stream, direct or TURN path
End-of-call page for guests: your branding, constellation of the participants, star rating, contact card
End-of-call page for guests: your branding, constellation of the participants, star rating, contact card
Schedule tab: the next meetings on the calendar, with invite link and one-tap join
Schedule tab: the next meetings on the calendar, with invite link and one-tap join
Recent meetings: date, duration, who took part,
Recent meetings: date, duration, who took part, "live" badge, rejoin with one tap
Pre-join screen for guests: name, microphone test, speakers and camera
Pre-join screen for guests: name, microphone test, speakers and camera
Login page with the company info set in Settings
Login page with the company info set in Settings

On the phone: home, screen sharing with annotations, speaker view
On the phone: home, screen sharing with annotations, speaker view

The people in the screenshots are illustrations rendered into a fake camera; everything else is the real UI.


Features

Meetings

  • Waiting room like Google Meet: guests wait until a host admits them (Admit / Deny / Admit all card, on by default, switchable per meeting); registered users get straight in; guests go back to waiting if the last host leaves. Hosts can also lock the room and remove a guest. From the waiting room card hosts write to the people waiting (three quick replies or free text) and each guest also sees their place in line
  • "Ready to join?" pre-join page: a large preview with your name and the microphone and camera buttons inside it, pills for microphone, speakers and webcam, who is already in (only with a valid link) and other ways to join: as a second screen (the laptop in the meeting room with no microphone, speakers or camera, so no echo; Back to the call makes it a normal participant) or joining and presenting right away
  • End the meeting for everyone: pressing Leave, a host chooses whether to just leave or close the meeting for everyone, waiting room included
  • Home page with a full device check (camera preview, microphone level, speakers test on the chosen output) — switching tab does not close and reopen camera and microphone (they are released only after 10 minutes away), and registered users then go straight into the meeting — plus recent meetings (date, duration, who took part, live badge, one tap to rejoin; the last 5, the others with Show more) and the next scheduled ones
  • Scheduled meetings with email invitations and .ics calendar event
  • Guest links that expire, no sign-up — works in the browser on desktop and phone
  • Grid view that sizes every tile to the available space (all participants visible, same size, 16:9, last row centered) and speaker view
  • Change layout from the View button: Auto, Grid, Spotlight or Sidebar, maximum number of tiles (a "+N" tile beyond that), hide people with the camera off, your own tile in the grid, as a draggable small window or hidden — only for you, saved in the browser
  • Portrait (phone) cameras shown in full instead of cropped

Presenting

  • Screen sharing with live annotations on top of the shared screen: pen, highlighter, arrow, rectangle, circle, text, eraser and laser pointer with the presenter's name; hide drawings for yourself, save a PNG of the shared screen with the drawings
  • While someone presents, the participants sit in a row above the shared screen, smaller as more people join
  • The presenter decides whether everyone can draw or only presenter and hosts
  • Local recording that includes annotations and laser pointer; leaving the room waits for the file to be saved

In the room

  • Chat, participant list and an Activities button with polls (hosts create, everyone votes, live results, anonymous or with names), a meeting timer (a countdown for everyone on the server clock, pause, +1 minute, rings at the end) and questions and answers (also anonymous, voted by everyone, marked answering now and answered by the host, downloadable for Excel)
  • Chat with pinned messages (hosts, up to 3), reactions on each message, reply with a quote, clickable links and "… is typing"
  • Notifications at the bottom left for joins, leaves, chat (reply without opening the chat) and recording, with the person's initials and the time
  • Zoom on a shared screen (− % +, Ctrl + wheel or pinch, drag, minimap) and open it in a new window for a second monitor, with drawings still aligned
  • Tiles that show who is talking: a voice badge with live bars or a crossed-out microphone, a ring around whoever talks, and with the camera off the avatar colour, a large circle with the initials and rings while talking
  • Menu ⋮ on tiles and in the People list: pin for me or for everyone (up to 3), full screen, and for hosts mute one person, send back to the waiting room or remove
  • Second screen from the pre-join screen, the home page or More in the room
  • Phone layout: five large buttons (microphone, camera, hand, More, Leave), everything else in More, a floating chat button and your own video in a small draggable window
  • Reactions bar with skin tones and every emoji, rising with the name of who sent them and staying for a few seconds on their tile
  • Raised hands in a queue: order of arrival in the People list, place in line on the tile, Lower and Lower all; the hand goes down by itself after you have spoken for a few seconds
  • Microphone and speakers are separate controls: mute yourself without muting the others, or silence the others (A) without touching your microphone. The speakers ▾ picks the output (system default unless you choose), shows the level, plays a test sound and can reconnect the audio
  • Push-to-talk: while muted, hold Space to talk
  • Advanced noise reduction (RNNoise neural network in WebAssembly, runs in the browser, no data leaves the computer) and echo cancellation: on or off by default from Settings → Rooms, everyone can switch their own from the microphone popup for that meeting
  • Network & quality window: live bandwidth, latency and jitter graphs, packet loss, per-stream stats, direct/TURN path; hosts also see a Participants section with every participant's connection as the server sees it (quality, bitrates, latency, jitter, loss, direct or TURN, browser and device network)
  • End-of-call page for guests: branded two-column page with an animated constellation of the participants, stats, optional star rating, contact card and buttons — or a redirect to your own URL (Settings → End of call)
  • Floating window with the whole meeting (Chrome/Edge): all participants, speaker highlight, mic/camera/hand/leave. Opens by itself when you switch tab
  • Virtual backgrounds (blur, 56 photos — offices, homes, libraries, Italy, nature, space, abstract, video games — synthwave and pixel-art illustrations, or your own image), color styles and face effects (MediaPipe) in a side panel with a live preview, opened from More or from the button on your own tile
  • 411 3D face effects like Meet (characters that copy your expressions, animals with real fur and kawaii animals, costumes, cute accessories, fun and Halloween effects that react to your smile, mouth and eyebrows, wigs, beards, hats, glasses, painted masks, scenes with your face in a frame) that follow the head in 3D: MediaPipe Face Landmarker in a Web Worker + three.js, all served locally. A search box at the top finds an effect by name in any of the app's languages, by section, or just "animals". The classic 2D effects stay in their own tab
  • Call settings window with sections: audio & video devices, room rules (hosts), recording quality, appearance, shortcuts, info
  • Microphone popup with live mic and speaker levels and a switch for automatic gain control
  • Microphone watchdog: a mic silenced by the OS or another app, or dead after a device change, is reopened without interrupting the call
  • Per-tile connection quality with detailed stats, data saver mode; native share sheet for the invite link on phones
  • Tooltips and keyboard shortcuts on every control, optional first-join guide
  • Light and dark theme, UI in Italian, English, French and German

Administration

  • Branding panel: name, tagline, logo, favicon, accent color (automatically adjusted for contrast in both themes), default theme, footer, company info
  • Users with admin and host roles — from the panel or from .env
  • Room rules: waiting room, guest screen sharing, drawing permissions, first-join guide, default echo cancellation and noise reduction
  • External REST API to create meetings and guest links from a CRM
  • Automatic daily updates with email report, automatic rollback and ready-to-paste rollback commands

Requirements

  • A Linux server with Docker and the Docker Compose plugin
  • A public IP and a domain name
  • A reverse proxy with HTTPS and WebSocket support (Nginx Proxy Manager, Traefik, Caddy, plain Nginx…)
  • systemd for scheduled updates (present on Debian/Ubuntu, LXC containers included); cron is used as a fallback
  • These ports reachable from the internet:
Port Protocol What
PORT (default 3010) TCP Web app — behind your reverse proxy
RTC_MIN_PORT–RTC_MAX_PORT (default 40000–40400) UDP + TCP Media (mediasoup) — directly, not through the proxy
3478 UDP + TCP STUN/TURN (coturn)
TURN_MIN_PORT–TURN_MAX_PORT (default 49152–49200) UDP TURN relay

Installation

git clone https://github.com/Giuseppe-sciarra/TiDiTalk.git
cd TiDiTalk

# 1. Configuration
cp .env.template .env
nano .env        # at least: SERVER_SECRET, BASE_URL, ANNOUNCED_IP, TURN_*, USERS, SMTP_*

# 2. Third-party assets (MediaPipe for backgrounds/effects and the 3D face
#    effects, three.js, emoji images, background photos from Unsplash).
#    Updating from 1.6.x: run setup-mediapipe.sh again for the 3D effects
bash setup-mediapipe.sh
bash setup-effects.sh
bash setup-backgrounds.sh

# 3. Start
docker compose up -d --build
docker compose logs -f app

# 4. Nightly automatic updates (at 05:00)
bash installa-aggiornamento.sh

Generate SERVER_SECRET with:

openssl rand -hex 32

ANNOUNCED_IP must be the numeric public IP of the server: mediasoup does not resolve hostnames. Set DEFAULT_UI_LANGUAGE (it, en, fr, de) to the language used for emails when the browser doesn't declare one.

Then open your BASE_URL, sign in with a user from USERS and finish the setup from Settings.


Users and roles

Role Can
admin everything, including Settings and user management
host create, schedule and run meetings
guest join through an invitation link, no account

From .env — created at startup if missing:

USERS=alice:StrongPassword1:Alice Smith:admin,bob:StrongPassword2:Bob:host
USERS_MODE=create   # or "sync": .env becomes the source of truth

Passwords can also be bcrypt hashes ($2b$...; inside a compose env file write $ as $$). With USERS_MODE=sync those users are read-only in the panel.

From the panel — Settings → Users.


What goes where

What Where
Name, logo, favicon, accent color, theme, footer, company info Settings → Branding
Guest screen sharing, drawing for everyone, first-join guide, echo cancellation and noise reduction by default Settings → Rooms
Users and passwords Settings → Users, or USERS in .env
SMTP, TURN, IPs, ports, secrets, API keys, updates .env

Updates

Automatic (recommended)

bash installa-aggiornamento.sh            # every night at 05:00, Italian time
bash installa-aggiornamento.sh 4:30       # ...or at another time
bash installa-aggiornamento.sh --status   # is it scheduled? next run? last result
bash installa-aggiornamento.sh --remove   # stop it

installa-aggiornamento.sh installs a systemd timer (persistent: if the server was off at the scheduled time, the update runs as soon as it's back) on Italian time, even when the container runs in UTC. Without systemd it falls back to cron (/etc/cron.d). It removes the old install-cron.sh schedule (up to 1.8.8, every morning at 08:00) by itself, so the two never run together. install-cron.sh and auto-update.sh are still there and hand everything over to the new names.

Every night aggiorna-tutto.sh:

  1. postpones if a meeting is in progress (3 × 15 minutes, then proceeds);
  2. downloads the latest node:22-alpine base image, so security fixes in Node and Alpine (like the Brotli one of October 2026) actually arrive;
  3. upgrades every dependency in server/package.json to its latest version, majors included, together with package-lock.json. This runs in a throwaway container that only gets those two files. A dependency with an upper limit (e.g. "mediasoup": ">=3.14 <4") stays as it is: that's how you hold one back;
  4. rebuilds the app (always with --pull) when something changed: base image, dependencies, versions inside the image older than on npm, or Dockerfile and code different from the last successful build (e.g. after copying a patch);
  5. tests it: /api/health must answer and the container must not restart by itself for 20 seconds. Otherwise it restores the previous package.json, lock file and image — automatic rollback;
  6. updates coturn when a new image is out, with the same check and a return to the previous image if it doesn't stay up;
  7. sends the report: a table of what changed, tagged major / minor / patch, what happened (app, Node, coturn) and the exact command to go back;
  8. cleans Docker safely: keeps the last UPDATE_KEEP_ROLLBACK rollback images (default 5), removes stopped containers, untagged images and build cache older than 7 days. It never runs prune -a.

Backups: backups/ (last 10). Log: logs/aggiorna-tutto.log (plus logs/build.log, logs/npm-risoluzione.log).

Variable Default Meaning
UPDATE_NOTIFY_EMAIL (or AGG_MAIL_A) — where the report goes
UPDATE_MAIL_ALWAYS (or AGG_MAIL_SEMPRE) 0 1 = email even when nothing changed
UPDATE_SKIP_IF_BUSY 1 postpone while people are connected
UPDATE_BUSY_RETRIES / UPDATE_BUSY_WAIT 3 / 900 how many times / every how many seconds
UPDATE_KEEP_ROLLBACK (or AGG_TIENI_ROLLBACK) 5 rollback images to keep
AGG_ATTESA_SERVIZI 600 seconds to wait for coturn to stay up on a new image
UPDATE_CHECK 0 old "updates available" email, without updating

Manual

bash aggiorna-tutto.sh --dry-run    # show what would change, touch nothing
bash aggiorna-tutto.sh              # update now
bash aggiorna-tutto.sh --force      # update now even during meetings
docker compose build --pull app && docker compose up -d app   # after changing server/, public/assets/i18n or the Dockerfile
docker compose restart app          # after changing CSS/JS/HTML (mounted live)

External API

Enabled when EXTERNAL_API_KEY is set. Send the key in the x-api-key header.

Method Endpoint Purpose
GET /api/external/health liveness
POST /api/external/generate-guest-token guest link for a room
POST /api/external/schedule-meeting create a meeting and send invitations
DELETE /api/external/meeting/:id delete a meeting

GET /api/health (no key) returns { ok, uptime, rooms, peers, version } and is used by the updater to avoid restarting during a call.


Keyboard shortcuts

M microphone · A speakers · V camera · S present · D draw · H raise hand · C chat · U people · hold Space while muted to talk (push-to-talk). While drawing: P pen, E highlighter, A arrow, R rectangle, O circle, T text, X eraser, L laser, Ctrl+Z undo, Esc exit.


Troubleshooting

  • Build fails with gyp ERR! … FetchError … headers.tar.gz — from 1.5.3 the Dockerfile uses the Node headers already inside the image (npm_config_nodedir=/usr/local) instead of downloading them from unofficial-builds.nodejs.org. Update the Dockerfile and rebuild.
  • Video/audio doesn't connect for some users — the RTC port range must be forwarded as UDP and TCP and ANNOUNCED_IP must be the public IP. Behind strict firewalls TURN is what saves the day: check TURN_*.
  • Camera or microphone blocked — the page must be served over HTTPS.
  • Someone sounds too quiet — microphone popup (arrow next to the mic): the level bar shows the real signal. If it barely moves, raise the input volume in the computer's sound settings. If the input volume keeps dropping by itself, turn off "Adjust microphone volume automatically".
  • Echo — usually speakers without headphones, or two devices in the same room.
  • Invitations not delivered — Settings → System shows the SMTP status and has a test button.
  • Updates not happening — bash installa-aggiornamento.sh --status.
  • You can't hear the others — speakers ▾ → Play a test sound. If you can't hear even that, the browser has lost its audio output: Reconnect the audio, and if that doesn't help close and reopen the browser. With Bluetooth headphones, pick the computer's microphone: using the headphones' own microphone switches them to "phone mode" (low quality, and on Mac it can leave the browser without sound).
  • The camera does not come back after a FaceTime / Zoom call — when another app takes the webcam the camera turns off and a message appears; it comes back by itself as soon as the other app frees it (it retries every few seconds, always on the same camera). You can also press Retry or turn the camera on from the bar: no need to reload the page.
  • Someone joins and can't hear — open ⋮ → Network & quality as a host: the Participants section shows their connection. On the server, docker logs tdt-app 2>&1 | grep CONN also logs what their browser did with the audio (audio ev=play-blocked = the browser blocked playback until a tap, no-data = the stream carries no data, consume-error, sink-error), plus rejoin lines when someone comes back after a network drop.
  • Browser console diagnostics (hosts): tdConnLog('Name') disconnections and microphone events of a participant, tdMicInfo() real state of your microphone, tdCamInfo() resolution of preview, sent video and camera.

License

Tiditalk is free software released under the GNU Affero General Public License v3.0 or later — see LICENSE.

You can use, modify and redistribute it, commercially too. If you run a modified version as a network service, you must offer its source code to your users: the "About" window in every room links to the source — set SOURCE_URL in .env to point to your fork.

Third-party components and their licenses: THIRD-PARTY.md.

Copyright © Giuseppe Sciarra — Tastiere Digitali


Support the project

If Tiditalk is useful to you, you can support its development:

paypal.me/raxiel87

Bug reports and pull requests are welcome.

About

Self-hosted video meetings for teams and clients: mediasoup SFU, screen sharing with live annotations, virtual backgrounds and face effects, waiting room, scheduled meetings with email invites, local recording. Node.js + Docker. AGPL-3.0.

Topics

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages