diff --git a/docs/APP_YOUTUBE_LIVE.md b/docs/APP_YOUTUBE_LIVE.md index 873ce4f..a89c092 100644 --- a/docs/APP_YOUTUBE_LIVE.md +++ b/docs/APP_YOUTUBE_LIVE.md @@ -47,7 +47,7 @@ Poi tocca la card o conferma dal foglio: si apre il wizard (Partita → Trasmiss 1. Nel wizard, seleziona **YouTube Live** (se il piano lo consente e il canale è pronto) 2. Completa i passi → **Camera** -3. Il telefono invia RTMP a MediaMTX; il server avvia **automaticamente** overlay (tabellone + logo) e RTMPS verso YouTube — nessun intervento manuale +3. Il telefono invia RTMP a MediaMTX (con overlay tabellone già nel flusso, se attivo); il server avvia **automaticamente** il relay RTMPS verso YouTube (`Streams::YoutubeRelay`) — nessun intervento manuale ## Sviluppo locale @@ -67,9 +67,9 @@ Vedi [YOUTUBE_MORNING_CHECKLIST.md](./YOUTUBE_MORNING_CHECKLIST.md) — APK **1. | YouTube disabilitato | Premium Light o Full | | YouTube non selezionabile | Token canale Match Live TV sul server (`admin` → YouTube piattaforma) | | OAuth «app non verificata» | Utente di test Google + Avanzate | -| Live non su YouTube | Pipeline automatica (`Youtube::LivePipeline`): overlay → ingest active → activate. Controlla `docker logs infra-sidekiq-1` per `[OverlayRelay] started` e `[YoutubeBroadcastActivate]`. | -| YouTube «In programma» / copertina | Nessun intervento manuale: entro ~20–90s il server avvia overlay (tee RTMPS) e attiva la broadcast quando ingest è `active`. | -| YouTube resta in «waiting» | `log/overlay_relay_.log` in **sidekiq**; poll ogni 5s (`StreamPublisherSyncJob`). Attivazione ritenta ~6 min. | +| Live non su YouTube | Pipeline `Youtube::LivePipeline` + `YoutubeRelay`. Controlla `docker logs infra-sidekiq-1` per `[YoutubeRelay] started` / `[YoutubeBroadcastActivate]`. | +| YouTube «In programma» / copertina | Entro ~20–90s il server avvia il relay RTMPS e attiva la broadcast quando l’ingest è pronto; in pausa MediaMTX manda la slate. | +| YouTube resta in «waiting» | Log `log/youtube_relay_*.log` in **sidekiq**; poll `StreamPublisherSyncJob`. Attivazione ritenta ~6 min. | | Banner «sync limitata: Cannot add event after closing» | APK aggiornato: il wizard non apre un secondo WebSocket `controller` dopo la camera. | | Timer «IN DIRETTA» sbagliato (es. 10:33 subito) | `started_at` arriva dal server al primo frame RTMP; fino ad allora il timer resta a 0. | | App 0 Mbps / 0 fps ma LIVE | RTMP non pubblica: controlla permessi camera, messaggio «Connessione RTMP»; relay YouTube non parte finché il telefono non è online su MediaMTX. | diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 7633f48..2750f42 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -2,7 +2,7 @@ Documento di riferimento per l'intero sistema: rete, container Docker, flussi video, replay, monitoraggio ops e rilasci. -**Ultimo aggiornamento:** 2026-06-14 +**Ultimo aggiornamento:** 2026-07-29 **Produzione:** `eminux@192.168.1.146` → `/opt/matchlivetv` --- @@ -193,39 +193,41 @@ Vedi anche [`LIVE_STREAMING.md`](LIVE_STREAMING.md) per pause, overlay e player ### Flusso ingest ``` -App Android (RTMP 720p, AAC mono) +App (Android/iOS) RTMP 720p AAC mono + + overlay GPU (tabellone/watermark) se overlay_kind ≠ none │ ▼ -MediaMTX :1935 — path live/match_{uuid} (grezzo, telefono) - │ - ▼ overlay ffmpeg (Streams::OverlayRelay) -path live/match_{uuid}_air (tabellone + badge bruciati nel video) +MediaMTX :1935 — path live/match_{uuid} │ ├──► HLS :8888 ──► edge /hls/ ──► spettatori web - └──► ffmpeg -c copy ──► YouTube RTMP (Streams::YoutubeRelay, Premium) + └──► (solo platform=youtube) + Streams::YoutubeRelay in Sidekiq + ffmpeg: -c:v copy, -c:a aac ──► YouTube RTMPS ``` | Componente | Ruolo | |------------|--------| -| `Mediamtx::PathManager` | Crea path dinamici via API :9997 | +| Path dinamici via API :9997 | `Mediamtx::Client` (`create_path`, recording patch, …) | | `alwaysAvailable` + slate | Copertina `/slates/offline.mp4` senza interrompere HLS | -| `Streams::OverlayRelay` | Ricodifica con PNG 1280×720 aggiornata ogni ~2s | -| `Streams::YoutubeRelay` | Legge HLS da `mediamtx:8888` (non più via Rails) | -| `Mediamtx::PublisherSync` | Stato publisher online/offline in Rails | +| Overlay tabellone | **App nativa** (non più ricodifica server) | +| `Streams::YoutubeRelay` | Legge RTMP (o HLS) da MediaMTX; copy video + AAC → YouTube | +| `Mediamtx::PublisherSync` | Publisher online/offline, go_live, recording on/off | + +Dettaglio pause, player e ruolo ffmpeg: [`LIVE_STREAMING.md`](LIVE_STREAMING.md). ### Pausa e continuità 1. App chiama `PATCH /sessions/:id/pause` → stop RTMP. 2. MediaMTX passa alla slate sullo **stesso path** (stesso URL HLS). -3. YouTube relay continua sulla stessa uscita (vede slate). +3. Se attivo, YouTube relay continua sulla stessa uscita (vede slate). 4. Ripresa: `resume` → app ripubblica RTMP; MediaMTX concatena camera senza nuovo URL. -**Recording inline MediaMTX disabilitato** (`record: false` su path live): il recorder al switch slate→camera distruggeva il muxer HLS. I replay usano job dedicato (vedi sotto). +**Recording:** path creato con `record: false`; acceso solo con publisher online e entitlement (`PublisherSync`). I replay usano job dedicato (vedi sotto). ### Pagina live web - URL: `/live/:session_id` -- Player: HLS.js su `HLS_PUBLIC_URL/live/match_{uuid}_air/index.m3u8` +- Player: HLS.js su `HLS_PUBLIC_URL/live/match_{uuid}/index.m3u8` - Stato: `GET /live/:id/status.json` (badge, recovery buffer, no-store) --- @@ -278,8 +280,8 @@ App Android ◄──── REST API (/api/v1/...) ────► Rails │ Sidekiq ◄── Redis ◄──────┘ │ - ├── HealthMonitorJob, UploadJob, overlay refresh - ├── YoutubeRelay, OverlayRelay (ffmpeg) + ├── HealthMonitorJob, UploadJob (merge/thumbnail ffmpeg) + ├── YoutubeRelay (ffmpeg copy+AAC, solo dirette YouTube) └── PublishToYoutubeJob, purge replay, ecc. ``` @@ -395,10 +397,10 @@ cd infra && cp .env.example .env && docker compose up -d --build | Documento | Contenuto | |-----------|-----------| | [`infrastructure/SERVER_DEPLOYMENT.md`](infrastructure/SERVER_DEPLOYMENT.md) | Bootstrap server, NPM, cron, backup | -| [`LIVE_STREAMING.md`](LIVE_STREAMING.md) | MediaMTX, pause, overlay, HLS.js | +| [`LIVE_STREAMING.md`](LIVE_STREAMING.md) | MediaMTX, pausa, HLS, ruolo ffmpeg | | [`REPLAY_MODULE.md`](REPLAY_MODULE.md) | Garage, retention, YouTube VOD | | [`OPS_MONITORING.md`](OPS_MONITORING.md) | ntfy, variabili ops, troubleshooting | -| [`TABELLONI_E_OVERLAY.md`](TABELLONI_E_OVERLAY.md) | Grafica in stream | +| [`TABELLONI_E_OVERLAY.md`](TABELLONI_E_OVERLAY.md) | Tabelloni e overlay (app nativa) | | [`PRODUCT_PREMIUM.md`](PRODUCT_PREMIUM.md) | Piani e funzionalità premium | | [`native/android/README.md`](../native/android/README.md) | App Android | @@ -412,5 +414,6 @@ cd infra && cp .env.example .env && docker compose up -d --build | 2026-06 | Replay: redirect 302 a `/media/` → Garage (fuori da Puma) | | 2026-06 | HLS live: edge → MediaMTX (fuori da Puma) | | 2026-06 | Ops: check `http_rails` + `http_public` separati, latenza p95 `UpLatencyTracker` | -| 2026-06 | `RAILS_MAX_THREADS=5`; relay YouTube legge `mediamtx:8888` diretto | +| 2026-06 | `RAILS_MAX_THREADS=5`; relay YouTube da MediaMTX (non via Puma) | | 2026-06 | Cleanup path MediaMTX orfani (`Mediamtx::CleanupOrphanPaths`); delete path sempre a fine diretta | +| 2026-07 | Rimosso overlay server (`OverlayRelay`); tabellone bruciato in app; HLS su path camera (non `*_air`); `YoutubeRelay` = copy video + AAC | diff --git a/docs/LIVE_STREAMING.md b/docs/LIVE_STREAMING.md index f894f78..3e4d991 100644 --- a/docs/LIVE_STREAMING.md +++ b/docs/LIVE_STREAMING.md @@ -1,23 +1,25 @@ # Diretta live — architettura MediaMTX -## Idea (non è folle) +**Ultimo aggiornamento:** 2026-07-29 + +## Idea MediaMTX espone **un unico flusso di uscita** per path (`live/match_{uuid}`): -1. **Telefono in onda** → publisher RTMP (camera). +1. **Telefono in onda** → publisher RTMP (camera + **overlay grafico bruciato in app**). 2. **Pausa / rete assente** → `alwaysAvailable` con file slate (`/slates/offline.mp4`) **senza interrompere** l’HLS verso il sito. -3. **YouTube** → `ffmpeg` in container Rails/Sidekiq legge **sempre** quell’uscita (`-c copy`) e inoltra a `rtmp://a.rtmp.youtube.com/live2/...` per tutta la sessione. +3. **YouTube** (solo se `platform=youtube`) → `Streams::YoutubeRelay` in **Sidekiq**: un processo `ffmpeg` legge RTMP/HLS da MediaMTX e inoltra a YouTube (`-c:v copy`, audio ricodificato in AAC). -Il telefono **non** invia la copertina: risparmia banda; lo switch è lato server. +Il telefono **non** invia la copertina di pausa: risparmia banda; lo switch slate ↔ camera è lato MediaMTX. ## Componenti | Pezzo | Ruolo | |--------|--------| -| App Android | RTMP 48 kHz mono, 720p — solo quando in onda | -| MediaMTX | Path dinamico, `alwaysAvailable` + slate | -| `Streams::YoutubeRelay` | Relay continuo verso YouTube (no hook wget su distroless) | -| `Mediamtx::PublisherSync` | Stato Rails da API paths (publisher online) | +| App Android / iOS | RTMP 720p AAC mono; overlay tabellone/watermark in GPU sul flusso | +| MediaMTX | Path dinamico, `alwaysAvailable` + slate, HLS | +| `Streams::YoutubeRelay` | Relay continuo verso YouTube (solo Sidekiq con `YOUTUBE_RELAY_WORKER=1`) | +| `Mediamtx::PublisherSync` | Stato Rails da API paths (publisher online) + recording on/off | | `/hls/...` (edge → MediaMTX in prod; Rails proxy in dev) | Player web | ## Pausa e continuità @@ -27,36 +29,44 @@ Il telefono **non** invia la copertina: risparmia banda; lo switch è lato serve 3. MediaMTX → passa alla slate sul **medesimo path** (senza interrompere l’uscita HLS). 4. **Ripresa** → API `resume` → `connecting`, recording on, app `resumeStream()`; MediaMTX concatena di nuovo camera sulla stessa uscita HLS. 5. **Sito** → **un solo** player HLS per tutta la sessione (mai reload in pausa/ripresa). Copertina brand (`brand/CopertinaCanale_6.png` → `infra/slates/offline.mp4`) muxata da MediaMTX; in pausa solo un messaggio leggero sopra il video. -6. **YouTube** → relay ffmpeg continuo; vede la stessa uscita MediaMTX. +6. **YouTube** → se attivo, il relay ffmpeg continua sulla stessa uscita MediaMTX (vede slate in pausa). Non fare `patch` del path MediaMTX in pausa: ricarica il path e interrompe gli HLS reader. -**Recording**: disabilitato sul path live (`record: false`) — il recorder MediaMTX al switch slate→camera distruggeva il muxer HLS (`too many reordered frames`). I replay vanno gestiti con job dedicato (vedi `REPLAY_MODULE.md`). +**Recording**: sul path live parte `record: false`; viene acceso via API solo con publisher online e entitlement (`PublisherSync`). I replay finiscono in Garage con job dedicato (vedi `REPLAY_MODULE.md`). Il player web resta attivo finché `ready|available|online` sul path (non solo quando il telefono è `online`). ## Infrastruttura vs browser ``` -Telefono RTMP ──► MediaMTX path live/match_{uuid} - │ - publisher ON ├─► camera (H.264/AAC) - publisher OFF└─► alwaysAvailable → /slates/offline.mp4 - │ - ├─► HLS (segmenti ~1s) ──► edge /hls/ → MediaMTX (prod) o proxy Rails (dev) ──► player web (HLS.js) - └─► RTMP lettura ──► Streams::YoutubeRelay (ffmpeg -c copy) ──► YouTube +Telefono RTMP (camera + overlay app) + │ + ▼ +MediaMTX path live/match_{uuid} + │ + publisher ON → camera H.264/AAC (già con tabellone se overlay ≠ none) + publisher OFF → alwaysAvailable → /slates/offline.mp4 + │ + ├──► HLS (segmenti ~1s) ──► edge /hls/ → MediaMTX ──► player web (HLS.js) + └──► (solo platform=youtube) + Streams::YoutubeRelay + ffmpeg: -c:v copy, -c:a aac ──► RTMPS YouTube ``` | Responsabilità | Dove | |----------------|------| | Switch copertina ↔ live | **MediaMTX** (stesso path, stesso URL HLS) | -| Continuità YouTube | **Relay ffmpeg** sulla stessa uscita | -| Badge «In onda» / stato pausa | **Rails** (`status.json`, `PublisherSync`) | +| Tabellone / watermark sullo stream | **App nativa** (GPU → RTMP) | +| Continuità YouTube | **`Streams::YoutubeRelay`** (ffmpeg in Sidekiq) | +| Badge «In onda» / stato pausa | **Rails** (`status.json`, `PublisherSync`) + UI web | | Uscire dal buffer copertina dopo ripresa | **Browser** (`pendingLiveRecovery`, reload HLS) | | Fluidità playback | **Browser** (evitare seek continui su `liveSyncPosition`) | Lo switch slate→camera **non** richiede un nuovo URL lato player: MediaMTX concatena sulla playlist. Il sito può però restare «indietro» nel buffer HLS (ancora segmenti della slate) anche con `publisher_online: true` — da qui i recovery controllati in `show.html.erb`, **senza** chiamare `jumpToLiveEdge()` a ogni frammento bufferizzato. +URL HLS pubblico: `https://www.matchlivetv.it/hls/live/match_{uuid}/index.m3u8` (`StreamSession#effective_hls_path_name` = path camera, **non** più `*_air`). + ### Player web — anti-scatti (HLS.js) Configurazione in `backend/app/views/public/live/show.html.erb`: @@ -67,27 +77,32 @@ Configurazione in `backend/app/views/public/live/show.html.erb`: - Sync iniziale una volta su `LEVEL_LOADED`; recovery solo se `liveEdgeLagSec() > 4` o `pendingLiveRecovery`. - Interval 6s solo durante recovery attivo (`tryEscapeCoverBuffer`). -### Grafica nel video (overlay server) +### Grafica nel video (overlay) -Tabellone, badge stato («In onda», «In pausa», «Copertina», …) e banner **Match Live TV** sono **bruciati nel flusso** da `Streams::OverlayRelay`: +**Non** c’è più un relay server `Streams::OverlayRelay` che ricodifica con PNG. -``` -Telefono → live/match_{uuid} (grezzo) - └─► ffmpeg + PNG 1280×720 (Streams::Overlay::Refresh ogni ~2s) - └─► live/match_{uuid}_air - ├─► HLS (sito, anche fullscreen) - └─► YouTube relay (-c copy) -``` +Il tabellone è composito **sul telefono** prima dell’RTMP (vedi [`TABELLONI_E_OVERLAY.md`](TABELLONI_E_OVERLAY.md)): -- `Streams::Overlay::SvgBuilder` + `rsvg-convert` generano `tmp/stream_overlays/{session_id}/overlay.png` -- `Streams::Overlay::Refresh` + `bin/overlay_png_feeder.rb` aggiornano la PNG ogni ~2s (e su punteggio/stato); il feeder la invia a ffmpeg via FIFO perché `-loop 1` non rilegge il file su disco -- Volume Docker condiviso `stream_overlays` tra **rails** (ffmpeg) e **sidekiq** (OverlayRefreshJob); altrimenti il job scrive PNG su un filesystem diverso e badge/punteggio restano congelati -- La pagina live **non** sovrappone più HTML sul player (evita incongruenze con fullscreen / YouTube) -- **Qualità video**: il relay normalizza a **30 fps CFR** (l’app RTMP può inviare timestamp errati) e ricodifica a **≥4.5 Mbps** (`fast`, no B-frame). Override: `OVERLAY_RELAY_VIDEO_KBPS`, `OVERLAY_RELAY_X264_PRESET`, `OVERLAY_RELAY_FPS`. +1. `OverlayState` da `effectiveOverlayKind` + `ScoreState` +2. `OverlayRenderer` / canvas → bitmap +3. Filtro GPU sul encoder RTMP + +La pagina live può mostrare badge HTML di stato (in onda / pausa / attesa); non sostituisce il tabellone nel video. + +### Ruolo di ffmpeg oggi + +| Quando | Cosa | Peso CPU | +|--------|------|----------| +| Diretta `platform=youtube` | `YoutubeRelay`: demux + **copy video** + AAC audio → RTMPS | Medio-basso **per diretta**, scala con N processi | +| Diretta solo `matchlivetv` | Nessun ffmpeg in live | Quasi zero | +| Fine diretta | `UploadFromSession`: concat segmenti (`-c copy`) | Picco breve | +| Post-process | `GenerateThumbnail`: un frame → JPEG | Trascurabile | + +Non esiste più la ricodifica H.264 server-side dell’overlay (era il carico principale). ### Punteggio (persistenza) -L’app mobile persiste il punteggio con `PATCH /api/v1/sessions/:id/score` (`Scoring::SyncState`), poi refresh overlay. +L’app mobile persiste il punteggio con `PATCH /api/v1/sessions/:id/score` (o `score_action`) → `Scoring::SyncState`, poi aggiorna l’overlay locale in camera. `GET /live/:id/status.json` resta per messaggi sotto il player e recovery HLS; `Cache-Control: no-store`. diff --git a/docs/TABELLONI_E_OVERLAY.md b/docs/TABELLONI_E_OVERLAY.md index 8ddf5b2..751e31a 100644 --- a/docs/TABELLONI_E_OVERLAY.md +++ b/docs/TABELLONI_E_OVERLAY.md @@ -2,6 +2,8 @@ Questo documento descrive come Match Live TV modella gli sport, applica i regolamenti di punteggio e li traduce in **tabelloni** (logica + controlli) e **overlay** (grafica sul video in diretta). +**Importante (2026-07):** l’overlay video è composito **solo sull’app nativa** (Android/iOS) e viaggia già nel RTMP verso MediaMTX. Non esiste più un relay server (`Streams::OverlayRelay`) che ricodifica con PNG. Vedi anche [`LIVE_STREAMING.md`](LIVE_STREAMING.md). + --- ## Panoramica @@ -162,12 +164,14 @@ Esempio: il basket ammette `[basket, none]` — si può trasmettere con tabellon ### Layout app mobile (Android e iOS) -Sull’app nativa l’overlay è composito in GPU senza ricodifica aggiuntiva: +Sull’app nativa l’overlay è composito in GPU **prima** dell’encode RTMP (nessuna ricodifica server aggiuntiva): 1. `BroadcastScreen` costruisce un `OverlayState` a partire da `effectiveOverlayKind` e `ScoreState`. 2. `OverlayRenderer` → `OverlayCanvasRenderer` disegna gli elementi su bitmap trasparente. 3. Il bitmap viene applicato come filtro sul flusso RTMP (OpenGL su Android, HaishinKit su iOS). +MediaMTX e `YoutubeRelay` ricevono quindi un flusso già “brandizzato”; il relay YouTube fa solo `-c:v copy` (+ AAC). + Elementi grafici (`OverlayCanvasRenderer`): | Elemento | Quando è attivo | diff --git a/docs/YOUTUBE_MORNING_CHECKLIST.md b/docs/YOUTUBE_MORNING_CHECKLIST.md index 680d000..dfe1ca3 100644 --- a/docs/YOUTUBE_MORNING_CHECKLIST.md +++ b/docs/YOUTUBE_MORNING_CHECKLIST.md @@ -1,56 +1,32 @@ -# YouTube Live — verificato ✅ (5 giu 2026) +# YouTube Live — checklist operativa -## Test completato automaticamente +**Aggiornato:** 2026-07-29 +Pipeline attuale: telefono → MediaMTX → `Streams::YoutubeRelay` (ffmpeg copy+AAC in Sidekiq) → YouTube. Overlay tabellone in **app**, non più `OverlayRelay` server. -Pipeline end-to-end **funzionante** sul server di produzione: - -| Step | Esito | -|------|--------| -| Setup broadcast + stream_key | ✅ | -| Overlay ffmpeg con tee RTMPS YouTube | ✅ | -| Copertina / tabellone su YouTube | ✅ | -| RTMP simulato (test pattern) | ✅ | -| Broadcast `lifecycle=live` | ✅ | - -**Prova visiva:** https://www.youtube.com/watch?v=0WmCsW_Luik -(Titolo: *Tigers Volley vs Avversario prova* — sessione di test, ora terminata) - -## APK da installare sul telefono - -```bash -# Sul PC (già compilato): -mobile/build/app/outputs/flutter-apk/app-release.apk -# Versione: 1.2.10+13 — API https://www.matchlivetv.it -``` - -Installa sul Redmi (sostituisce versioni precedenti). - -## Avvio diretta dall’app (2 minuti) - -1. Partita → **YouTube Live** → wizard → **Camera** -2. Attendi sul passo rete che compaia il link YouTube (poll automatico, fino a 3 min) -3. Avvia: entro ~90s su YouTube compare **copertina**, poi video con tabellone quando il telefono pubblica RTMP - -## Test server senza telefono +## Verifica rapida su server ```bash ssh eminux@192.168.1.146 -docker exec infra-rails-1 bin/rails youtube:e2e -docker exec infra-sidekiq-1 pgrep -a ffmpeg # deve contenere rtmps://...youtube.com/live2 +docker exec infra-rails-1 bin/rails youtube:e2e # se il task è ancora presente +docker exec infra-sidekiq-1 pgrep -a ffmpeg # deve contenere rtmps://...youtube.com/live2 +docker logs infra-sidekiq-1 2>&1 | grep -E 'YoutubeRelay|YoutubeBroadcastActivate|LivePipeline' | tail -40 ``` +## Avvio diretta dall’app + +1. Partita → **YouTube Live** → wizard → **Camera** +2. Attendi sul passo rete che compaia il link YouTube (poll automatico) +3. Avvia: entro ~90s su YouTube compare video (slate MediaMTX se il telefono non pubblica ancora; tabellone quando l’app pubblica RTMP con overlay) + ## Se qualcosa non va | Sintomo | Cosa fare | |---------|-----------| | «YouTube temporaneamente occupato» | Attendi 15–20 min (rate limit Google). **Non** creare molte sessioni di fila. | -| Pagina YouTube vuota | `docker logs infra-sidekiq-1 \| grep OverlayRelay` — manca `stream_key` o tee RTMPS | -| App errore avvio diretta | APK 1.2.10+13; controlla rete verso matchlivetv.it | +| Pagina YouTube vuota | `docker logs infra-sidekiq-1 \| grep YoutubeRelay` — manca `stream_key` o relay non partito | +| App 0 Mbps / 0 fps ma LIVE | RTMP non pubblica: permessi camera / messaggio «Connessione RTMP»; relay YouTube non parte finché MediaMTX non vede il publisher | +| YouTube resta in waiting | Log relay in sidekiq; `StreamPublisherSyncJob` + activate retry | -## Fix deployati (server) +## Note storiche -- Retry setup broadcast su rate limit (fino a 15 tentativi) -- Un solo job setup per sessione (lock Redis) -- Throttle API YouTube globale -- Riavvio overlay quando arriva `stream_key` dopo start senza tee -- Activate solo con overlay attivo + broadcast pronta +Checklist precedente (giu 2026) citava `OverlayRelay` / tee RTMPS dall’overlay server: **deprecato**. Non cercare più log `OverlayRelay` o `overlay_relay_*.log`. diff --git a/docs/YOUTUBE_SETUP.md b/docs/YOUTUBE_SETUP.md index 8fdc1ef..9fd9531 100644 --- a/docs/YOUTUBE_SETUP.md +++ b/docs/YOUTUBE_SETUP.md @@ -7,7 +7,7 @@ Match Live TV supporta due modalità YouTube, legate al piano società: | **Premium Light** | `matchlivetv_light` | Canale YouTube **Match Live TV** (gestito da te) | | **Premium Full** | `team` | Canale YouTube **della società** (OAuth del club) | -Flusso tecnico: telefono → RTMP MediaMTX → (relay ffmpeg) → YouTube Live. +Flusso tecnico: telefono (camera + overlay app) → RTMP MediaMTX → `Streams::YoutubeRelay` (ffmpeg `-c:v copy`, AAC) → YouTube Live. --- @@ -85,5 +85,5 @@ YOUTUBE_MOCK_STREAM_KEY=mock-stream-key ## 6. Produzione - `YOUTUBE_REDIRECT_URI` deve essere **esattamente** quello registrato in Google (HTTPS, dominio pubblico). -- Il relay ffmpeg gira nel container MediaMTX (`runOnReady`). +- Il relay ffmpeg (`Streams::YoutubeRelay`) gira nel container **sidekiq** (`YOUTUBE_RELAY_WORKER=1`), non su MediaMTX `runOnReady`. - Apri RTMP **1935** sul router verso il server.