Skip to content

Latest commit

 

History

1,649 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

📱 Vivid

Android version of the open-source Moblin IRL streaming app

Android Kotlin API License GitHub release GitHub stars CI OpenSSF Best Practices

Professional IRL streaming for Android — aiming for full feature parity with Moblin

Vivid — IRL Streaming auf Android

📲 Install • 📥 Download APK • 📖 User Guide (🇬🇧 EN · 🇫🇷 FR) • 🤖 AI Chat Bot • 🤝 Contribute • 📝 Changelog • 📚 Documentation (DE/EN/FR Handbuch + docs/ai-chat-bot.md + GitHub-Wiki per Doku-Sync synchron) • 🐛 Report Bug • 💬 Discussions


🇬🇧 English quick start

What it is: Vivid is the Android version of Moblin, the open-source IRL streaming app — a professional multi-camera streaming client for Twitch (RTMP/RTMPS) with chat overlay, AI chat bot, widgets, scenes, replays, and manual camera controls, built with Kotlin/Compose and RootEncoder.

Get started:

  • 📲 Install: grab the latest APK via the permanent direct download link, from the Releases list, or add the F-Droid repository for automatic updates (APK 24+)
  • 📖 User guide: English · Français · Deutsch — plus tutorials, FAQ and troubleshooting
  • 🛠 Build from source: ./gradlew assembleFossDebug (Gradle 9.4 wrapper, JDK 25; foss flavor is fully open-source, the standard flavor adds optional Sentry)
  • 🤝 Contribute: bugs and features via Issues, code via pull requests to develop — see CONTRIBUTING.md for the workflow, required checks, and the local pre-push gate; every contribution follows our Code of Conduct
  • 🔒 Security: please report vulnerabilities privately via SECURITY.md — the project's full security posture (supply-chain hardening, OpenSSF Scorecard context) is documented there; the CII Best Practices checklist maps every badge criterion to its evidence; a Security-Loop guard (scripts/check_security_loop.sh, part of the pre-push gate + CI + release pipeline) keeps the release-grade security rules (keystore hardening, signature checks, reproducibility, Sentry opt-out proof) structurally present

📸 Screenshots

Vivid live streaming screen Vivid settings screen


🎯 Goal: Feature Parity with Moblin

Vivid is an Android implementation of the open-source Moblin IRL streaming app. The end goal is to be at least functionally equivalent to Moblin — every feature Moblin offers should work in Vivid, adapted to the Android platform.

This README tracks that progress honestly: the Features section marks what is already implemented, what is in progress, and what is still planned. The Parity Status table gives the per-feature status at a glance — the detailed work list lives in PARITY.md.

⚠️ Note: Features marked as planned are not shipped yet — don't rely on them for production streaming until they land.


📲 Installation

Vivid is not on Google Play (yet) — APKs are published as GitHub Releases. Everything below is free and takes about 2 minutes.

Vivid install quickstart
📄 One-page quickstart: Installation Infographic (SVG)

Step 1: Pick your release channel

Channel What you get Best for
🚀 Latest / Stable (v* tags) Tested releases with auto-generated release notes Daily use
🌙 Nightly (prerelease) Fresh build of every new feature, updated daily Testers, early adopters
🧪 Alpha (v*-alpha) First stage of versioned releases Previewing upcoming features

📄 The full versioning strategy (versionName/versionCode, stage criteria) is documented in RELEASE.md. The complete release history (stable, alpha, nightly — automatically mirrored from GitHub Releases) lives in CHANGELOG.md. How builds get published — cadence, checksums, F-Droid repositories — is documented in docs/distribution.md.

Step 2: Download the APK

Direct download: the latest stable APK is always available at the permanent link releases/latest/download/app-standard-release.apk — GitHub resolves this permalink to the newest stable release automatically. Alternatively via the releases list:

  1. Open the Releases page
  2. Click "Latest" (stable), or expand the prerelease list for nightly / alpha builds
  3. On stable releases download app-standard-release.apk (the app-foss-release.apk is the Sentry-free F-Droid variant); ignore mapping.txt and output-metadata.json — those are for developers only. Verify downloads with SHA256SUMS.txt (sha256sum -c); stable releases now additionally ship a sigstore/cosign keyless signature (SHA256SUMS.txt.bundle — bundle with signature, certificate and transparency-log entry) that authenticates the checksum file itself — see docs/distribution.md
  4. If your browser warns about the file type, confirm "Download anyway"

Step 3: Allow installation from unknown sources

Android blocks APKs from outside the Play Store by default. On first launch of the APK:

  1. Open the downloaded file in your file manager or notification bar
  2. Android shows a dialog like "Install unknown apps" → tap Settings
  3. Allow your browser / file manager to install unknown apps
  4. Go back and tap Install

🔒 Signing: All official APKs are signed with the same release key. If Android ever shows "App not installed", you may have a corrupted download — delete the file and download it again.

Step 4: Grant permissions & go live

After installation, Vivid asks for camera and microphone permissions when you tap Go Live (notifications are requested too on Android 13+ — they power the streaming status notification). Then follow the Platform Setup Guides to connect Twitch, YouTube, Kick, or your own server.

🔋 Background streaming: While streaming, a persistent notification ("Vivid is streaming") with a Stop action keeps the stream alive when you leave the app or turn the screen off. The encoder runs independent of the camera preview surface (GL-free pipeline), so the stream also continues if you swipe Vivid away from the recents list or rotate the device — the preview simply reappears when you reopen the app. Tap the notification's Stop button (or the Stop button in the app) to end the stream.

✅ Go-Live Self-Check: Before starting, Vivid validates the configured URL and stream key on the streaming screen and shows clear messages (e.g. "Keine Stream-URL konfiguriert", "Nicht unterstütztes Protokoll", missing stream key). Blocking problems prevent the start; warnings are shown but don't block.

🔄 Automatic updates (F-Droid Repository)

Recommended for Android 14+: Use our official F-Droid repository for automatic updates:

📱 Quick Start with QR Code:

F-Droid Repository QR Code

  1. Install F-Droid (falls nicht vorhanden)
  2. Open F-Droid → Settings → Repositories
  3. Tap auf + und fügen Sie hinzu: - URL: https://thoser666.github.io/Vivid/fdroid/repo
    • Name: Vivid (schnelle Updates)
  4. Tap Done und warten Sie auf die Synchronisation
  5. Install Vivid über das neue Repository

✅ Benefits: Updates erscheinen automatisch, kein manueller Download nötig, zukunftssicher ab Android 14+ (Google schränkt Sideloading ein).

🗄️ Archive: Das Repository enthält zusätzlich ein separates Archiv mit allen älteren Versionen (https://thoser666.github.io/Vivid/fdroid/archive). Der F-Droid-Client erkennt es automatisch — ältere Versionen bleiben für Downgrades und als Fallback installierbar.

📝 Note: Dieses Build enthält Sentry für Crash-Reporting. Für ein vollständig FOSS-Build ohne Telemetrie verwenden Sie das offizielle F-Droid-Repository (wenn verfügbar).

📲 Alternative: Automatic updates (Obtainium)

Für Benutzer, die Obtainium bevorzugen:

  1. Install Obtainium von obtainium.imranr.dev (oder eigenen GitHub Releases)
  2. Tap + → geben Sie https://github.com/thoser666/Vivid als Quelle ein
  3. Es erkennt automatisch GitHub Releases — wählen Sie Ihren Kanal:
    • Nur Stable: Neueste Version verfolgen ("Include pre-releases" deaktiviert)
    • Nightly: "Include pre-releases" aktivieren, um jeden Feature-Build zu verfolgen
  4. Tap Hinzufügen — Obtainium prüft jetzt automatisch auf Updates und installiert sie

Da jedes APK mit demselben Schlüssel signiert ist, werden Updates (einschließlich Nightly → Stable und umgekehrt) nahtlos über die vorherige Version installiert.

🧪 Update-Flow testen

  1. Install ein älteres Nightly APK von der Releases-Seite (z.B. den vorherigen Build)
  2. Open Settings — die installierte Version wird unten angezeigt, und ein „⬆ Update verfügbar: …" Badge erscheint automatisch, wenn ein neuerer Build existiert
  3. Fügen Sie die App in Obtainium wie oben beschrieben hinzu (Include pre-releases für nightly aktiviert)
  4. (Optional) In Settings → „Über Vivid & Updates" tippen Sie auf „Nach Updates suchen", um den neuesten GitHub-Release zu sehen
  5. In Obtainium tippen Sie Update — das neuere APK wird über die alte Version installiert (gleicher Signatur-Schlüssel)
  6. Open erneut Settings — die Versionsnummer hat sich erhöht und das Badge ist verschwunden ✅

Die Überprüfung auf dem Über-Bildschirm folgt denselben Regeln wie in RELEASE.md: Es schlägt nur neuere Versionen vor (nightly → nightly/alpha/beta/stable, nie ein Downgrade).


✨ Features

✅ Implemented

  • 🎛️ OBS WebSocket Control - Control OBS Studio directly from your phone (switch scenes, start/stop recording and streaming, input mute, audio levels (dB), audio sync offset, source snapshot, screen black)
  • 🌐 Streaming Pipeline - RootEncoder-based live streaming to your configured RTMP/SRT ingest (Twitch, YouTube, Kick, or your own server)
  • 🔗 Multi-Streaming - Send the same stream to two RTMP(S) targets in parallel (primary + optional secondary): add a secondary URL/key in Settings → Stream („Multi-Streaming (optional)“) and both targets start on Go Live. Each target shows its own status on the streaming screen (bereit / verbinde… / sendet live / fehlgeschlagen), and if one target fails it stops on its own while the other keeps streaming — ideal for cross-streaming to Twitch and YouTube at the same time
  • 🔒 RTMPS (TLS) - Encrypted ingest via rtmps:// (verified against RootEncoder 2.7.5: native TLS handshake, port 443); enabled per-platform or via the TLS toggle, standard port 1935 is auto-normalized to 443
  • ✅ Go-Live Self-Check - Before starting the stream, Vivid validates the configured URL and stream key (missing/invalid URL, unsupported protocol, missing key) and shows clear, actionable German messages directly on the streaming screen — blocking errors prevent starting, warnings (e.g. missing key) are shown but don't block
  • 🔍 Focus Lock - Toggle autofocus ⇄ infinity lock on the streaming camera to prevent focus hunting (rain drops, dirt on the windshield) during drive/train streams — Moblin #377; works on the actual RootEncoder camera (not just the preview) and can be set before going live
  • 👆 Camera Controls on the Streaming Preview - Tap-to-focus (single tap), pinch to zoom (clamped to the camera's zoom range) and zoom reset (double tap) directly on the live preview — gestures drive the real RootEncoder camera, not the preview only. Plus a stabilization toggle (optical stabilization preferred, EIS fallback) and a torch/flashlight toggle (RootEncoder lantern API, also available as !torch owner bot command) next to the focus-lock button
  • 🎨 Video Effects - 11 OpenGL filters (Grayscale, Sepia, Noise, Negative, Edge Detection, Cartoon, Pixelated, Blur, Beauty, Duotone + No Filter) via RootEncoder's setFilter/GlFilter API — effects apply to both the live preview and the encoded stream. A cycle button in the streaming screen switches between filters with the current filter name displayed; the owner can also switch filters from chat with !filter <name> (or !filter / !fx to cycle). Localized in all three app languages (de/en/fr)
  • 💬 Twitch Chat Integration - Full Twitch chat data layer via EventSub (read) + Helix (send), no IRC — TwitchChatEventSubReader (WebSocket channel.chat.message) + Helix POST /helix/chat/messages; on top of it the chat overlay, the AI chat bot and a full settings screen (see below). Formally ✅ with Twitch scope (Beta-Gate): Kick/YouTube/SOOP + Twitch OAuth browser flow (sending & moderation) = post-beta roadmap
  • 💬 Twitch Chat Overlay - Show the chat of any Twitch channel over the live preview (read via Twitch EventSub, no IRC). Configure the channel and toggle the overlay in Settings → Chat-Overlay; the latest messages appear bottom-left with each user's Twitch color, Twitch badges (Broadcaster/Moderator/Subscriber, fetched via the Helix Chat-Badges API and rendered as CDN images before the username), inline Twitch emotes (rendered as CDN images via Coil) and event alerts (follows, subscriptions, gift subs, resubs and raids — shown as colored banner lines above the chat, auto-dismissed after a few seconds; the bot token needs moderator:read:followers for follows, i.e. the bot must be a moderator, and channel:read:subscriptions for subs/gifts/resubs). A test alert can be triggered locally via the triggerTestAlert API (or the owner command !testalert follow|sub|gift|resub|raid) to verify the overlay before going live. The connection auto-reconnects, and the overlay hides itself as soon as it is disabled in the settings
  • 📊 Twitch-Kanalsteuerung - Die Streaming-Ansicht zeigt die aktuelle Viewerzahl (automatische Aktualisierung alle 30 Sekunden). Unter Settings → Streaming & OBS → Twitch-Kanalsteuerung lassen sich Titel und Kategorie über Twitch Helix setzen. Dafür werden Kanal, Twitch-App-Client-ID und ein Broadcaster-OAuth-Token mit channel:manage:broadcast benötigt; fehlt der Broadcaster-Token, wird abwärtskompatibel der Chat-Bot-Token verwendet. OAuth-Tokens (Access + Refresh) werden nach dem PKCE-Login AES-256/GCM-verschlüsselt im Android Keystore gespeichert und bei einem 401 automatisch über den Refresh-Token erneuert — der Klartext-Settings-Fallback bleibt für bestehende Installationen erhalten. Kategorien werden vor dem Update über die Twitch-Suche in eine Game-ID aufgelöst; Start-Ads und Hype-Train-Steuerung sind weiterhin offen.
  • 🤖 AI Chat Bot - A fully automated, in-app chat bot (inspired by cloud services like Stream Chat AI): it connects to your Twitch chat when you go live, answers viewers through an LLM of your choice (any OpenAI-compatible endpoint — OpenAI, Gemini, Groq, DeepSeek, or a local Ollama server) and shuts down cleanly when the stream ends. A mode switch in the settings picks between „Bot (wie Moblin)“ (deterministic !-commands like !help/!uptime/!tts/!bot, no LLM needed) and „KI autonom“ (the AI decides itself whether and how to reply, including staying silent). !tts toggles chat text-to-speech (owner-only, reads chat messages aloud on the streamer's device, like Moblin's bot). Media commands (!next/!pause/!play/!prev) control the music player (owner + moderators). Mentions-only mode, a reply cooldown and a per-minute rate limit keep it from spamming; configurable limits protect against spam and LLM cost: a per-viewer cooldown (default 60 s), a per-viewer reply cap per stream, and an hourly reply budget (0 = off for each) — platform-neutral via user id, moderators bypass the per-viewer limits; a quick-start preset bar (Locker/Balanced/Streng/Eigene, the last choice is persisted and restored on app start) fills the three limits in one tap, and a live usage readout (replies this hour vs. budget, per-stream total, top viewers) lets the streamer watch the cost budget in the settings screen. A coexistence mode lets it run side by side with another tool's bot (e.g. Rivulet): other bot logins can be ignored and a command scope (@vividbot mention or a custom prefix like !v!help) prevents double replies and double actions. An owner mode (streamer only) adds exclusive commands — !start/!stop/!diag/!ask/!fix/!torch/!filter — that can start/stop the stream, run a diagnostic with recommendations, query a separate, more powerful owner LLM, toggle the flashlight, and cycle through video effects, only the channel owner (broadcaster badge) and explicitly listed logins (e.g. a second account) can use them, viewers get a hint instead. Auto-connect/auto-shutdown is wired into the streaming foreground service — see docs/ai-chat-bot.md
  • ⚙️ Persisted Stream Settings - Stream URL/key (incl. optional secondary target for multi-streaming) and OBS connection details are stored and reused across sessions
  • 🔄 In-App Update Check - Settings shows the installed version + an „Update verfügbar“ badge; the About screen (Settings → "About Vivid & Updates") adds a manual check against GitHub Releases — ideal for verifying Obtainium updates. Results are cached for 1 hour (DataStore), so opening Settings does not hammer the GitHub API rate limit; the manual check in About always refreshes and shows the release notes of the newest build
  • 📋 In-App Logs (Logs & Diagnose) - A Settings category „Logs & Diagnose“ with daily log rotation and a configurable retention period (1–30 days, default 7): each calendar day is stored in its own app-internal log file, older days are pruned automatically (also on app start). Crashes are clearly marked — the default uncaught-exception handler writes them with a red CRASH badge (redacted stacktrace) before handing them to Sentry, and the screen shows day sections (Today/Yesterday/date), an „errors & crashes“ filter and a crash summary („X crashes in the last Y days“) so you can analyze and fix recurring failures. Copy/share/clear works across all retained days. Timber trees are planted in the app (DebugTree for Logcat in debug builds + a LogBufferTree ring buffer + persistent LogStore), and a redaction filter strips stream keys, RTMP URLs, OAuth/LLM/Twitch tokens and passwords before anything is stored or shown — sensitive data never leaves the device in cleartext. This is the foundation for the open remote „logs“ item of the Web Remote Control (later served token-protected via the LAN server)
  • 🕹️ Web Remote Control - A small LAN server (port 8080, token-protected) exposes the streaming status via http://<phone-ip>:8080/status and allows starting/stopping the stream from any browser in the same network — see Installation
  • 🔋 Background Streaming (Foreground Service) - The stream keeps running when the app is in the background (home button, screen off) and even if the Activity is destroyed (recents swipe, rotation): a foreground service with a persistent notification (live status + stop action) and a partial wake lock keeps the encoder and camera alive, and the encoder runs on a view-independent GL pipeline (RootEncoder Context-constructor) so it never depends on the camera preview surface
  • 🔓 Open Source - Completely free and open source
  • 🌍 I18n Support — all UI strings externalized into per-module strings.xml (German default, full English values-en and full French values-fr — three complete languages), including validator/notification/update-check messages; CI gates enforce externalization and values ↔ values-en ↔ values-fr completeness (docs/i18n-plan.md). Bot/!diag texts are intentionally not localized (streamer language).

📋 Planned (Roadmap to Moblin parity)

  • 📡 Multi-Network Bonding (SRTLA) - Combine WiFi and mobile data for rock-solid streams
  • 💬 Chat Extensions - Emotes (BTTV/FFZ/7TV) plus chat polish: chat polls are implemented (!poll/!vote/!pollend), and chat display details (hide/gray out deleted messages, replies, /me styling, cheered bits, adjustable overlay layout) — Viewer count and setting the Twitch stream title/category are implemented; note: moderation (!ban/!timeout/!delete), chat-bot media player control via MediaSession (Apple Music, Spotify, etc.; adapted from Moblin 33.12.0) and the AI chat bot itself are already implemented (see above)
  • 🎨 Overlays & Widgets - Follower/donation alerts, custom graphics and branding; text widgets incl. weather, timer/stopwatch, distance, G-force and road/route variables (altitude, GPS and speed are already implemented — see above); implemented widgets include the image widget, QR-code widget, battery indicator (with low-battery chat warning) and grid overlay for positioning; further widget types and speech-to-text subtitles remain planned
  • 📹 High-Quality Streaming - Up to 4K resolution at 60fps with H.264/AVC and H.265/HEVC
  • 🔒 Extended Protocols - SRTLA, RIST, and WHIP (WebRTC) — RTMPS is already implemented (see below); RTMP-Pull/ingest server mode (community request #407); adaptive bitrate for SRT(LA) + per-connection upload statistics
  • 🎬 Scenes & Video Sources - ✅ Basic scenes implemented — save and switch complete stream configurations (video source, widget state, stream target) incl. a time-based auto scene switcher; screen capture ✅ and video player ✅ as additional stream sources (multi-cam) — the full „Screen Capture + Video Player“ bucket is done
  • 🎛️ Pro Camera Controls - Manual exposure bias, white balance, ISO and focus; back-camera lens selection (ultra-wide/wide/tele); torch and low-light boost
  • 📼 Replays - Record to disk (MP4) while streaming and save/play replays
  • 🖥️ Externes Display / Streamer-Browser - Video on an external display (Android Cast / Presentation) and a built-in browser visible only to the streamer (Moblin feature)
  • 📱 Landscape & Portrait - Landscape in both orientations (video always gravity-down) and a portrait UI with landscape video (Vivid is currently portrait-only)
  • ❤️ BLE Fitness Sensors - Heart-rate belt and cycling power monitor (BLE) shown in the text widget — related to the Oura-ring cloud row
  • 🕹️ Remote & Companion Features - Web remote control (incl. talkback mic selection, mic/bitrate/zoom control, logs), game controller support, deep linking
  • 📸 Photo Shoot Quick Button - Periodically capture high-resolution clean pictures to the gallery; manual snapshots with optional Discord auto-upload (new in Moblin 33.12.0)

🛣️ Roadmap

Current stage: Beta — the Beta-Gate is formally reached (17/17 Moblin parity ✅, Twitch chat ✅ with scope, ≥1 widget ✅); current: v0.5.8-beta.1 with F-Droid repo. M1 is functionally complete: Slideshow Widget, Twitch OAuth browser flow (PKCE) and optional Twitch start ads are implemented. OAuth callbacks validate the custom scheme, state and PKCE flow before accepting a code; the app exchanges the authorization code with Twitch over HTTPS using the PKCE verifier. The Roborazzi JVM lane remains intentionally disabled under AGP 9/JDK 25; visual coverage currently runs through the emulator Screengrab lane. Snyk now uses the supported CLI setup instead of the deprecated gradle-jdk17 action, with bounded scans, valid directory exclusions and guarded SARIF upload. Tokens must not be logged or embedded in source. The next focus is production hardening, Hype Train support and multi-platform chat.

🎯 Milestones

Milestone Version Ziel Features
M1: Core Streaming Enhancement v0.6.0 Interaktive Chat- und Overlay-Features ✅ Abgeschlossen: Slideshow-Widget, Twitch-OAuth-Browser-Flow und optionale Start-Ads
M2: Advanced Camera & Video v0.7.0 Pro-Kamera-Steuerung + verbesserte Videoqualität Untertitel (Speech-to-Text), OBS Audio-Levels, 4K/60fps + HEVC, Replays (Record-to-Disk)
M3: Multi-Platform & Pro Features v0.8.0 Multi-Plattform-Chat + erweiterte Streaming-Features Multi-Platform Chat (Kick, YouTube, SOOP), Adaptive Bitrate, SRTLA Bonding, Streamer-Browser
M4: Polish & Ecosystem v0.9.0 UI/UX-Verbesserungen + Integrationen Landscape/Portrait, VTuber/PNGTuber, Externes Display/Cast, BLE-Sensoren

Aktueller Stand: 39 ✅ / 2 🚧 / 26 📋 von 67 Features. M1 ist abgeschlossen und ausgeliefert (via v0.5.12-beta): Slideshow-Widget, Twitch-OAuth und optionale Start-Ads sind implementiert.

Offene Checklists

  • 🧪 Beta-Build-Checkliste — Beta-Gate-Bedingungen + Play-Unterlagen + ≥2 manuelle Tester
  • ✅ Play-Vorbereitung P0–P2 — Master-Checkliste für den ersten Play-Upload; scripts/test_play_checklist.sh schützt die Pflichtpunkte im Pre-Push-Gate

Post-Beta Roadmap Buckets

Release stages & criteria: RELEASE.md.

📋 Platform Setup Guides

🟣 Twitch Setup
  1. Go to Twitch Creator Dashboard
  2. Navigate to Settings → Stream
  3. Copy your Stream Key
  4. In Vivid:
    • Server: rtmp://live.twitch.tv/live/
    • Stream Key: [paste your key]
  5. Für die Kanalsteuerung unter Settings → Streaming & OBS → Twitch-Kanalsteuerung zusätzlich die Twitch-App-Client-ID, den Kanalnamen und einen Broadcaster-OAuth-Token mit channel:manage:broadcast eintragen. Vivid verwendet keinen Client-Secret; Tokens werden als geheime Einstellungen behandelt.
  6. Viewerzahl aktualisieren liest den Live-Status. Mit Titel/Kategorie setzen wird die Kategorie über die Twitch-Suche aufgelöst und anschließend zusammen mit dem Titel aktualisiert.
🔴 YouTube Setup
  1. Open YouTube Studio
  2. Click "Go Live" → "Stream"
  3. Copy the Stream URL and Stream Key
  4. In Vivid:
    • Server: [paste stream URL]
    • Stream Key: [paste stream key]
🟢 Kick Setup
  1. Go to Kick Creator Dashboard
  2. Navigate to Settings → Stream Settings
  3. Copy your Stream Key
  4. In Vivid:
    • Server: rtmp://ingest.kick.com/live/
    • Stream Key: [paste your key]
⚙️ Owncast / Custom Platform (freie RTMP-URL)

Vivid streams protocol-based (RTMP / RTMPS / SRT) — you are not limited to Twitch, YouTube or Kick. Any platform with a standard ingest works via the free Stream URL field; the platform templates (Twitch/YouTube/Kick) are only convenience presets. Example: Owncast (open-source, self-hosted):

  1. Install Owncast (e.g. Docker: docker run -p 8080:8080 -p 1935:1935 ghcr.io/owncast/owncast:latest) and open the web UI
  2. Get the ingest data: Owncast shows its RTMP ingest (rtmp://<your-server>/live) and Stream Key in the admin/stream page
  3. In Vivid → Settings → Streaming & OBS: tap „Benutzerdefiniert“ (Custom) to clear the URL, then enter those values as Stream URL + Stream Key — the field accepts any RTMP(S)/SRT URL; the TLS toggle stays as you left it
  4. Go Live — the stream goes directly to your server

⚠️ Chat: Vivid's chat (overlay + AI bot) currently connects only to Twitch — Owncast chat is not read yet. Streaming to Owncast works fully; chat integration for custom platforms is on the post-beta roadmap.

🎛️ OBS Studio Setup (WebSocket-Steuerung)

Vivid OBS setup quickstart
📄 One-page quickstart: OBS-Setup-Infografik (SVG)

  1. In OBS aktivieren: Extras → WebSocket-Server-Settings → "Enable WebSocket server" anhaken
  2. Port & Passwort: Standard-Port 4455 behalten, optional ein Passwort setzen (wenn keins gesetzt ist, das Feld in Vivid leer lassen)
  3. IP ermitteln: LAN-IP des OBS-Rechners (Windows: ipconfig, Mac/Linux: ip addr) — Handy und PC müssen im selben WLAN sein
  4. In Vivid verbinden: OBS-Steuerung → ⚙️ Settings → Host = IP, Port = 4455, Passwort + „Secure connection (wss://)“ passend zum Setup (LAN = ws://, Remote = wss://)

🧪 Probleme beim Verbinden? Siehe die OBS-FAQ-Einträge (Verbindung schlägt fehl, Passwort, ws:// vs. wss://).

📡 SRT Server Setup
  1. Set up your SRT server or use a service provider
  2. Get your server IP, port, and stream ID
  3. In Vivid:
    • Protocol: SRT
    • Server: srt://[server-ip]:[port]
    • Stream ID: [your stream ID]
    • Configure latency and encryption as needed
🕹️ Web Remote Control (Stream per Browser steuern)

Vivid startet einen kleinen LAN-Server (Port 8080), über den du den Stream-Status abfragen und den Stream starten/stoppen kannst — praktisch, wenn das Handy als Kamera läuft und du vom Laptop steuern willst:

  1. Handy und Laptop ins selbe WLAN bringen

  2. Token holen: In Vivid unter Settings → Web-Remote-Control steht dein Remote-Token (wird einmalig erzeugt und gespeichert)

  3. IP ermitteln: LAN-IP des Handys (Android: Settings → WLAN → Verbundenes Netz → Details)

  4. Status abfragen (ohne Token):

    curl http://<handy-ip>:8080/status
    # → {"status":"IDLE"} | {"status":"STREAMING"} | ...
  5. Stream starten/stoppen (mit Token):

    curl -X POST http://<handy-ip>:8080/start -H "Authorization: Bearer <dein-token>"
    curl -X POST http://<handy-ip>:8080/stop  -H "Authorization: Bearer <dein-token>"

🔒 Der Server läuft nur, solange die App geöffnet ist, und Aktionen benötigen das Token — im selben WLAN ist die Verbindung unverschlüsselt (wie bei OBS ws://), außerhalb des LAN nicht erreichbar.

ℹ️ Android 17 (API 37): Seit targetSdk 37 verlangt Android die "Access local network" permission (ACCESS_LOCAL_NETWORK) für LAN-Server. Falls /status nicht erreichbar ist, in Vivid unter Settings → Web-Remote-Control auf "Allow LAN access for remote control" tippen (der Server startet danach automatisch neu).


❓ FAQ — Häufige Probleme

🔧 "App not installed" when installing

Meistens ist der Download beschädigt oder unvollständig:

  1. Lösche die heruntergeladene app-release.apk aus deinem Download-Ordner
  2. Lade sie neu von der Releases-Seite herunter
  3. Prüfe, dass die Datei ~7 MB groß ist (eine deutlich kleinere Datei ist ein fehlgeschlagener Download)
  4. Versuche es erneut — wenn der Fehler bleibt, installiere über Obtainium (unten), das die Datei verifiziert herunterlädt

Falls du Vivid von einer älteren Version aktualisierst und der Fehler weiterhin auftritt: Deinstalliere zuerst die alte Version (Achtung: Stream-Settings gehen dabei verloren) und installiere dann neu.

📥 "Unknown source not allowed" / Installations-Button ist grau

Android blockiert APKs außerhalb des Play Stores standardmäßig:

  1. Beim ersten Installationsversuch erscheint ein Note → tippe auf Settings
  2. Erlaube dem verwendeten Browser / Dateimanager, unbekannte Apps zu installieren
  3. Go back and tap Install again
  4. Falls kein Note erscheint: Settings → Apps → [Browser/Dateimanager] → Unbekannte Apps installieren → erlauben
🎥 „Kein Bild“ / Kamera bleibt schwarz beim Streaming
  1. Prüfe die Kamera-Berechtigung: Settings → Apps → Vivid → Berechtigungen → Kamera = Erlauben (nicht „Nur während der Nutzung“ kann bei Hintergrund-Streaming Probleme machen)
  2. Teste die Kamera in einer anderen App (z. B. der Standard-Kamera-App) — wenn sie dort auch schwarz ist, liegt es am Gerät
  3. Falls du mehrere Kameras hast: Wähle in Vivid die richtige Kamera (Front-/Rückkamera) aus
  4. Starte den Stream neu (Stop → Go Live)

⚠️ Android schließt die Kamera, wenn eine andere App sie belegt (z. B. eine offene Kamera-App oder ein Video-Call). Schließe solche Apps vor dem Streamen.

📶 Verbindungsabbrüche / Stream bricht regelmäßig ab
  1. Signal prüfen: Mobiles Internet + WiFi — wechsle notfalls den Netzwerktyp und teste erneut
  2. Ingest-Server wechseln: Wähle in Vivid einen anderen RTMP/SRT-Server deiner Plattform (z. B. einen näher gelegenen)
  3. Stream-Key prüfen: Ein falscher oder abgelaufener Stream-Key führt zum Abbruch nach wenigen Sekunden — neu kopieren (auf Twitch wird der Key bei jedem Zurücksetzen ungültig)
  4. OBS-Steuerung deaktivieren: Wenn du OBS nicht benutzt, entferne die OBS-Verbindungsdaten in den Settings — eine fehlgeschlagene OBS-Verbindung kann den Stream-Start blockieren
  5. Latenz erhöhen: Bei SRT kann eine höhere Latenz (200–500 ms) instabile Verbindungen glätten

📡 Tipp für unterwegs: Ein stabilerer Upload als der nötige ist wichtiger als die maximale Auflösung — senke Qualität/Auflösung bei schwachem Signal, statt den Stream abreißen zu lassen.

🔑 Stream startet, aber Plattform zeigt „Kein Signal“ / Fehler im Dashboard
  1. Prüfe, ob Server-URL und Stream-Key in Vivid exakt den Werten aus dem Plattform-Dashboard entsprechen (kein Leerzeichen, keine zusätzlichen Zeichen)
  2. Vergleiche mit den Platform Setup Guides oben
  3. Twitch: Der Server ist rtmp://live.twitch.tv/live/ — den Key nie mit dem Server verwechseln
  4. Teste den Key zuerst im Plattform-Dashboard („Test stream“), bevor du Vivid startest
🎛️ OBS-Steuerung: Verbindung schlägt fehl

Vivid kann OBS Studio nur steuern, wenn der WebSocket-Server in OBS aktiv und Vivid im selben Netzwerk erreichbar ist:

  1. WebSocket-Server aktivieren: In OBS unter Extras → WebSocket-Server-Settings → Haken bei "Enable WebSocket server" setzen. Erst dann lauscht OBS auf Verbindungen.
  2. Host prüfen: In Vivid die IP-Adresse des OBS-Rechners eintragen (z. B. 192.168.1.50) — localhost funktioniert nur, wenn OBS auf demselben Gerät läuft. IP unter Windows mit ipconfig, unter macOS/Linux mit ip addr herausfinden.
  3. Port prüfen: Standard ist 4455 — in OBS (WebSocket-Server-Settings) nachsehen, ob ein anderer Port konfiguriert ist, und denselben in Vivid eintragen.
  4. Gleiches Netzwerk: Handy und OBS-Rechner müssen im selben WLAN/LAN sein (bzw. über VPN verbunden) — prüfe, ob z. B. das Handy im Mobilfunknetz hängt.
  5. Firewall: Die Windows-Firewall muss eingehende Verbindungen auf Port 4455 erlauben (der OBS-Installer legt meist eine Regel an — nach Updates prüfen).
  6. Passwort & TLS: Stimmen Passwort und die Option „Secure connection (wss://)“ mit den OBS-Settings überein? Siehe die nächsten beiden FAQ-Einträge.

🧪 Schnelltest: Öffne im Browser auf dem Handy ws://<OBS-IP>:4455 — erscheint eine Meldung, dass die Verbindung hergestellt wurde (auch wenn sie danach geschlossen wird), ist OBS erreichbar und das Problem liegt an Passwort/TLS.

🔑 OBS: Passwort vergessen / „Authentifizierung fehlgeschlagen“

OBS zeigt das WebSocket-Passwort nie wieder an — du kannst es nur neu setzen:

  1. In OBS: Extras → WebSocket-Server-Settings öffnen
  2. Haken bei „Passwort aktivieren“ setzen (falls noch nicht geschehen) und ein neues Passwort eingeben
  3. OK klicken — das neue Passwort gilt sofort
  4. In Vivid unter OBS-Settings das neue Passwort eintragen und erneut verbinden

⚠️ Kein Passwort in OBS gesetzt? Dann lasse das Passwort-Feld in Vivid leer — ein eingegebenes, falsches Passwort führt zum Abbruch der Verbindung. Umgekehrt: Verlangt OBS ein Passwort und Vivid hat keins, bricht die Verbindung ebenfalls ab (Vivid bricht die Verbindung bewusst ab, statt unauthentifiziert weiterzumachen).

Tipp gegen vergessene Passwörter: Verwende einen Passwort-Manager oder ein einheitliches LAN-Passwort — OBS selbst bietet keine „Passwort anzeigen“-Funktion.

🔐 OBS: ws:// oder wss://? (Secure connection)

Die Option „Secure connection (wss://)“ in den OBS-Settings von Vivid muss zum OBS-Setup passen:

Verbindung Wann verwenden OBS-Voraussetzung
ws:// (Standard, Schalter aus) OBS im eigenen LAN/WLAN Keine — OBS liefert standardmäßig Klartext-WebSockets auf Port 4455
wss:// (Schalter an) OBS remote über das Internet OBS muss TLS konfiguriert haben (Zertifikat) oder ein TLS-Reverse-Proxy (z. B. Caddy/nginx) davor laufen
  1. Standard-OBS-Setup im LAN = ws:// — also den Schalter aus lassen
  2. Für Remote-Zugriff (z. B. von unterwegs über Port-Forwarding/VPN) wss:// aktivieren — nur wenn OBS tatsächlich TLS anbietet, sonst schlägt die Verbindung fehl
  3. Zeigt OBS im Log „WebSocket server started on ws://…“ bzw. „wss://…“, siehst du direkt, welches Protokoll aktiv ist

🔒 Sicherheit: Über öffentliches Internet wird immer wss:// empfohlen — unverschlüsseltes ws:// macht das OBS-Passwort (und damit die Steuerung) für jeden im Netz lesbar. Im heimischen WLAN ist ws:// vertretbar.

🔇 Kein Ton beim Streaming (Audio fehlt)

Bild läuft, aber Zuschauer hören nichts? Das sind die häufigsten Ursachen:

  1. Mikrofon-Berechtigung prüfen: Settings → Apps → Vivid → Berechtigungen → Mikrofon = Erlauben — ohne sie startet der Audio-Encoder nicht (Vivid zeigt „Failed to prepare audio/video“)
  2. Mikrofon ist belegt: Android gibt das Mikrofon nur an eine App gleichzeitig — schließe andere Apps, die es nutzen (Anrufe, Sprachassistent, andere Streaming-/Aufnahme-Apps), und starte den Stream neu
  3. Bluetooth trennen: Ist ein BT-Headset/Headset verbunden, nutzt Android dessen Mikrofon — für IRL-Streaming das Bluetooth-Gerät trennen oder in den Bluetooth-Settings aufs Handy-Mikrofon umstellen
  4. Lautstärke: Prüfe die Media-Lautstärke (nicht nur Klingelton) — bei 0 ist auch das Streaming stumm
  5. Neu starten: Nach Berechtigungs-/Bluetooth-Änderungen hilft ein kompletter App-Neustart (Stream stoppen → App beenden → neu starten)

🎧 Plattformseitig: Auch im Plattform-Dashboard prüfen, ob der Audiopegel ankommt (z. B. Twitch Stream Manager) — so unterscheidest du ein Handy- von einem Plattform-Problem.

🔄 Updates kommen nicht an (Obtainium)
  1. Prüfe, ob du in Obtainium Pre-Releases aktiviert hast (für Nightly-Builds) — Stable-Nutzer bekommen nur v*-Releases
  2. Tippe in Obtainium auf „Aktualisieren“ (manueller Check), um den letzten Stand abzurufen
  3. Alle offiziellen APKs sind mit demselben Schlüssel signiert — ein Update sollte immer installierbar sein; falls „App not installed“ erscheint, siehe FAQ oben
❓ Obtainium zeigt eine falsche „Neueste Version“ (z. B. ein altes v0.2.x)

Symptom: Obtainium meldet „Installierte Version ist 0.5.3-beta“, aber „Neueste Version ist v0.2.5“ (oder eine andere Version, die es in Vivid nie gab).

Ursache: Vivid veröffentlicht ausschließlich unter vX.Y.Z-alpha/-beta (aktuell v0.5.4-beta), Nightly-Builds als Pre-Release. Eine „v0.2.5“ existiert weder als Release noch als Tag. Die Anzeige stammt dann aus einem veralteten Cache des Obtainium-Eintrags oder der Eintrag zeigt auf eine falsche/alte Quelle.

Lösung:

  1. In Obtainium den Vivid-Eintrag öffnen → ⋮-Menü → „App-Daten aktualisieren“ (Refresh), danach „Aktualisieren“ tippen
  2. Bleibt die Anzeige falsch: Eintrag löschen und neu hinzufügen mit exakt https://github.com/thoser666/Vivid
  3. Pre-Releases-Toggle: Für Beta/Alpha nicht nötig — diese Releases sind auf GitHub als normale Releases markiert (kein Pre-Release-Flag). Nur für Nightly-Builds den Toggle aktivieren
  4. Gegenprobe in der App: Settings → "About Vivid & Updates" → "Check for updates" zeigt die echte neueste GitHub-Version — weicht Obtainium davon ab, liegt es am Eintrag, nicht an Vivid

🧱 Tech Stack

Area Technology Version
Language Kotlin 2.2.20
Build Android Gradle Plugin 9.3.1
JDK Eclipse Temurin (LTS) 25
SDK minSdk / compile+target 24 / 37
UI Jetpack Compose (BOM) 2025.09.00
DI Hilt + KSP 2.59.2 / 2.3.11
Networking OkHttp / Ktor 5.3.2 / 3.5.2
Image Loading Coil 2.7.0
Camera RootEncoder (Stream-Pipeline + Vorschau) 2.7.5
Media Media3 (ExoPlayer) 1.9.0
Serialization kotlinx.serialization 1.11.0
Code Analysis Sentry Gradle Plugin 6.6.0

All versions are centrally defined in gradle/libs.versions.toml.

📊 Parity Status

Status: ✅ implemented · 🚧 in progress · 📋 planned

📋 Full per-feature tracking (responsible module + open tasks) lives in PARITY.md.

Moblin Feature Vivid Notes
OBS WebSocket Control ✅ Scenes, recording, stream start/stop
OBS Config via QR Code ✅ Import obsws:// / obswebsocket connect info (host, port, password) from the OBS QR code
Streaming (RTMP / SRT) ✅ Configurable URL/key via settings
RTMPS (TLS ingest) ✅ rtmps:// via RootEncoder 2.7.5, port 443, TLS verified
Background Streaming (Foreground Service) ✅ Stream continues in background: notification + wake lock, stop action
Go-Live Self-Check ✅ Validates URL/key before starting, clear error messages
Focus Lock (∞) ✅ Autofocus ⇄ infinity lock toggle on the streaming camera (Moblin #377)
Persisted Stream Settings ✅ Stream & OBS config across sessions
I18n Support ✅ All UI strings externalized (per-module strings.xml, German default + full English values-en + full French values-fr); CI gates: externalization + values↔values-en↔values-fr completeness + hint-content guard — docs/i18n-plan.md
H.264/H.265, up to 4K/60fps 🚧 Encoder presets (2160p60…480p30) + codec preference (HEVC-first auto fallback) implemented
Multi-Network Bonding (SRTLA) 📋 SRTLA algorithm to be ported
Chat (Twitch) + Emotes + Moderation ✅ Twitch-Scope feature-chat — Twitch EventSub reader (channel.chat.message) + Helix send (POST /helix/chat/messages) + chat overlay over the live preview + inline Twitch emotes (CDN rendering via Coil) + moderation done (!ban/!timeout/!delete) + AI chat bot done (IRC removed); third-party emotes (BTTV/FFZ/7TV) partially implemented (API clients + cache + overlay rendering); Kick/YouTube/SOOP + OAuth (sending/moderation) = post-beta roadmap
AI Chat Bot (Vivid extra) ✅ Fully automatic LLM chat bot: auto-connect on go-live, clean shutdown on stream end; OpenAI-compatible LLM providers; owner mode (!start/!stop/!diag/!ask, streamer-only via broadcaster badge + allow-list, separate owner LLM)
UI Color Schemes (Vivid extra) ✅ Material-3 palette (seed #3DDC84) replaces the template colors; appearance settings category „Darstellung“: user toggle System/Light/Dark/AMOLED (pure-black surfaces for OLED) + 6 curated accent colors (M3 TonalSpot palettes, Vivid Green stays the default) — applies live, no restart. Typography follows the current Material-3 baseline of the bundled material3 (no template overrides)
Chat-Bot Media Player Control ✅ Generic media control via MediaSession (Apple Music, Spotify, …); Android adaptation of Moblin 33.12.0 — commands !song/!next/!pause/!play/!prev (needs notification access)
Overlays & Widgets 🚧 feature-widgets: text/info widget (time, GPS coordinates, speed, altitude) live as overlay — time/date ticker, LocationProvider (LocationManager), settings toggles, permission flow; template variables ({time}, {date}, {speed}, {altitude}, {lat}, {lon}, {road}, {city}, {country} — placenames via Android Geocoder with a TTL+distance cache) via WidgetVariableResolver + widgetTemplate setting; image, QR-code, battery and grid widgets implemented; further widget types and speech-to-text subtitles remain planned (Twitch chat overlay + event alerts already implemented in feature-chat)
Audio Tools (levels, muting, talk-back) 📋
Extended Protocols (RIST, WHIP) 📋
RTMP-Pull / Ingest (Server mode) 📋 Community request #407; Moblin offers ingests (RTMP, SRT(LA), RIST, RTSP, WHIP)
Web Remote Control ✅ LAN server (port 8080) with token auth: status, start/stop
Photo Shoot Quick Button 📋 Periodic high-res photos to the gallery; new in Moblin 33.12.0
Game Controller Support 📋
Deep Linking (moblin://) 📋
Scenes (basic) + Auto Scene Switcher ✅ StreamScene + SceneRepository (persisted, active scene) + SceneController (applies source/widget/stream target) + time-based AutoSceneSwitcher (interval ≥ 5 s); scene bar in the streaming screen (chips, save, delete, auto toggle — de/en/fr) — open: rule-based switcher, settings section, scene/source widget, live source switching while streaming
Pro Camera Controls + Lens Selection 🚧 Manual focus distance + lens selection (wide/ultra-wide/tele) implemented with UI (Settings screen); exposure/white balance lock pending RootEncoder upgrade
Screen Capture + Video Player as source ✅ MediaProjection + basic video player as stream source — bucket done: VideoSourceKind/VideoSource/VideoSourceRegistry (S1), RootEncoder MultiDisplay + consent flow + source toggle (S2), RootEncoder MultiFromFile + SAF video picker (S3); all three sources switchable in the streaming screen
Record to Disk (MP4) + Replays ✅ MP4-Recording parallel zum Stream, Replay-Bibliothek (Liste, Inline-Wiedergabe, Löschen, Teilen), Audio-Konfiguration (ReplayAudioMode ALL/VIDEO_ONLY) + Thumbnail-Vorschauen, Replay als Szenen-Quelle (Dauerschleife, „Als Stream-Quelle verwenden“ in der Bibliothek) (09.09.)
Video Effects (Grayscale, Sepia, Noise, …) ✅ 11 OpenGL filters via RootEncoder setFilter/GlFilter, cycle button in streaming screen, !filter owner bot command, i18n de/en/fr
Torch / Low-Light Boost ✅ Torch: RootEncoder lantern API + !torch bot command. Low-Light Boost: software brightness filter (1.5x gain via GLSL) + !boost bot command — works on all video sources
External Display (Cast / HDMI-out) 📋 Video on an external display via Android Cast/Presentation
VTuber / PNGTuber 📋 Basic avatar instead of the camera
Image / QR / Battery / Grid Widgets 🚧 Image, QR code, battery indicator (+ low-battery chat warning) and grid overlay are implemented; additional widget types remain planned
Speech-to-Text Subtitles 📋 Live subtitles from the mic as overlay
Twitch: Viewer Count, Title/Category, Ads ✅ feature-chat, feature-settings, feature-streaming
Chat Display Details (deleted msgs, replies, /me, bits) 📋 Hide/gray out deleted messages, show replies, /me styling, cheered bits, adjustable layout
Chat Poll ✅ feature-chat
Adaptive Bitrate (SRT/SRTLA) + Upload Stats ✅ feature-streaming, core
Streamer Browser 📋 Built-in browser, visible to the streamer only
Landscape / Portrait 📋 Landscape 0/180 (gravity-down video) + portrait UI with landscape video
BLE Fitness Sensors (HR, Cycling Power) 📋 Heart-rate belt + cycling power monitor (related to the Oura-ring row)

🛠️ Development

Project Structure

Module Purpose
app Application entry point, navigation, DI wiring
core Shared utilities and base classes
domain Business logic, models, use cases
data Repositories and data sources
feature-streaming Streaming pipeline (RootEncoder, encoding)
feature-chat Live chat integration
feature-settings App settings
feature-widgets Stream overlays and widgets
feature-obs-control OBS Studio WebSocket control

Building from Source

Requirements:

  • JDK 17 (minimum) — required by Android Gradle Plugin 9.x
  • JDK 25 (recommended, LTS) — newest long-term support version, works perfectly with Gradle 9.7.0
# Clone the repository
git clone https://github.com/thoser666/Vivid.git
cd Vivid

# Open in Android Studio
# OR build with Gradle
./gradlew assembleDebug

Running Tests & Lint

# Unit tests for all modules (320 tests across core, app, feature-*)
./gradlew testDebugUnitTest

# Live check: run the in-app UpdateChecker against the real GitHub releases
# (disabled in the normal test run; CI runs it with GITHUB_TOKEN)
./gradlew :core:testDebugUnitTest --tests "com.vivid.core.update.LiveUpdateCheckTest" -PliveUpdateCheck=true

# Lint & static analysis
./gradlew lintDebug

Both run automatically in CI (.github/workflows/android-ci.yml) on every push and pull request to develop/master.

Release Builds (Fastlane)

Release builds use Fastlane (see Gemfile); dependencies are pinned in Gemfile.lock:

# Install the Ruby toolchain and pinned gems (fastlane 2.237.0 and friends)
bundle install

# Run the same lanes as CI
bundle exec fastlane test
bundle exec fastlane build_debug
bundle exec fastlane build_release   # requires the signing secrets from CI

# Build the release APK and publish it as a GitHub release
# (requires the gh CLI and GH_TOKEN; tag defaults to the nearest git tag)
bundle exec fastlane release_github

# Create and push an alpha release tag (runs tests, auto-versions)
bundle exec fastlane release_alpha

Version source of truth

app/build.gradle.kts reads the default versionName from the VERSION file and derives a fallback versionCode with the same schema as Fastlane (major*1,000,000 + minor*1,000 + patch*10 + stage; 0.5.14 → 5144). The Ruby self-test scripts/test_version_fallback.rb re-implements that schema and runs in the pre-push gate and CI, so the Gradle fallback and fastlane/release_safety.rb can never drift apart. Fastlane remains authoritative for release builds — the Gradle fallback only covers plain ./gradlew builds without Fastlane.

The release-pipeline.yml workflow runs these lanes in CI. Two release paths are automated:

  • A scheduled build runs once per day at 06:00 UTC (and the workflow can be triggered manually via gh workflow run release-pipeline.yml --ref develop) — it builds the signed release APK and publishes it as a rolling nightly prerelease with a version derived from the git tag + CI run number. The nightly release is replaced on each build, so it always contains the latest feature build; since 21.08.2026 it is built once per day, not on every push (develop pushes only run tests/builds, no new nightly).
  • Pushing a v* tag (e.g. git tag v0.2.0 && git push origin v0.2.0) publishes a stable GitHub release with auto-generated notes.

Both release the same signed APK; Obtainium users can track the latest release for stable versions or enable pre-releases to follow the nightly builds. If a lockfile update is needed (e.g. a security bump), run bundle update <gem> and commit the new Gemfile.lock.

📋 Release stages & criteria (nightly → alpha → beta → stable) are documented in RELEASE.md. The PARITY.md tracker determines which stage is active.

Contributing

We welcome contributions! Join our Discussions to pitch an idea, then fork and submit a Pull Request:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

🆘 Support & Community

🙏 Acknowledgments

  • Moblin - The original iOS app that inspired this project
  • Erik Moqvist - Creator of the original Moblin
  • The entire open-source streaming community
  • All contributors and beta testers

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🔒 Privacy

Vivid does not collect, sell, or share your personal data. Crash reports are sent to Sentry only if you enable them in Settings. See PRIVACY.md for the full privacy policy.

⭐ Show Your Support

If Vivid helps you with your streaming, please consider:

  • ⭐ Starring this repository
  • 🍴 Forking and contributing
  • 📢 Sharing with other streamers
  • 💝 Supporting the original Moblin project

Made with ❤️ for the IRL streaming community

⬆ Back to Top

About

Android version of the open-source Moblin IRL streaming app. Vivid lets you broadcast high-quality live video to platforms like Twitch, YouTube, Facebook, Kick or your own SRT server, with advanced features like multi-network bonding, OBS WebSocket control, configurable overlays, and full I18n support.

Resources

Code of conduct

Contributing

Security policy

Stars

27 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages