624 lines
15 KiB
Markdown
624 lines
15 KiB
Markdown
# Plugin `plugins/google_cast` – Guida pratica / Debug operativo
|
||
|
||
Questa guida è la versione **pratica** del documento di architettura del plugin `google_cast`.
|
||
|
||
L’obiettivo è aiutarti a capire **rapidamente**:
|
||
|
||
- quale parte del flusso è coinvolta
|
||
- quale file toccare
|
||
- dove guardare quando qualcosa non funziona
|
||
- come distinguere i problemi **Google Cast standard** dai problemi **Custom Receiver**
|
||
|
||
---
|
||
|
||
# 1. Mappa mentale rapida
|
||
|
||
## Flusso generale
|
||
|
||
```text
|
||
Flutter UI
|
||
↓
|
||
cast_controller.dart
|
||
↓
|
||
┌───────────────────────────────┬───────────────────────────────┐
|
||
│ GoogleCastController │ CustomCastController │
|
||
│ (Google Cast standard) │ (Custom Receiver CAF/web) │
|
||
└───────────────┬───────────────┴───────────────┬───────────────┘
|
||
↓ ↓
|
||
MethodChannel('google_cast') MethodChannel('google_cast')
|
||
↓ ↓
|
||
FlutterCastFrameworkPlugin.kt (Android)
|
||
↓
|
||
┌──────────────┬───────────────┬──────────────┬──────────────┐
|
||
│ Context │ Session │ MediaClient │ QueueManager │
|
||
│ Manager │ Handler │ │ │
|
||
└──────────────┴───────────────┴──────────────┴──────────────┘
|
||
↓
|
||
Google Cast framework / Receiver
|
||
```
|
||
|
||
---
|
||
|
||
# 2. File principali: a cosa servono in pratica
|
||
|
||
## Lato Flutter / App
|
||
|
||
### `lib/widgets/cast/cast_controller.dart`
|
||
**È la facciata unificata**.
|
||
|
||
Usalo per capire:
|
||
- quale backend è attivo (`google`, `custom`, `dlna`)
|
||
- dove finiscono i comandi UI
|
||
- come vengono sincronizzati i notifier condivisi:
|
||
- indice corrente
|
||
- stato play/pause
|
||
- posizione/durata
|
||
- volume/mute
|
||
|
||
### Se hai un bug tipo:
|
||
- il pulsante UI chiama il backend sbagliato
|
||
- i notifier non si aggiornano
|
||
- la cast bar chiama il backend sbagliato
|
||
|
||
👉 il primo file da guardare è **questo**.
|
||
|
||
---
|
||
|
||
### `lib/widgets/cast/google_cast_controller.dart`
|
||
**È il cervello Dart del Google Cast standard**.
|
||
|
||
Qui trovi:
|
||
- connessione del flusso Google Cast
|
||
- caricamento queue standard
|
||
- slideshow lato Flutter
|
||
- polling media/volume
|
||
- sync verso fullscreen viewer / controlli
|
||
|
||
### Se hai un bug tipo:
|
||
- slideshow Google si ferma
|
||
- foto/video si comportano male
|
||
- seek cambia sulla TV ma non sul telefono
|
||
- volume non si aggiorna nella UI
|
||
- `onCastReady` genera comportamenti strani
|
||
|
||
👉 guarda **questo file**.
|
||
|
||
---
|
||
|
||
### `lib/widgets/cast/custom_cast_controller.dart`
|
||
**È il cervello Dart del Custom Receiver**.
|
||
|
||
Qui trovi:
|
||
- avvio sessione/receiver custom
|
||
- invio messaggi JSON al receiver web
|
||
- polling custom (`MEDIA_STATUS`, `VOLUME_STATUS`)
|
||
- slideshow custom
|
||
- comandi `LOAD_QUEUE`, `NEXT`, `PLAY`, `PAUSE`, ecc.
|
||
|
||
### Se hai un bug tipo:
|
||
- Custom connect funziona ma la TV mostra male il contenuto
|
||
- overlay/progress duplicati
|
||
- volume custom non cambia davvero il video
|
||
- il receiver risponde ma Flutter non si aggiorna
|
||
|
||
👉 guarda **questo file** + il receiver web.
|
||
|
||
---
|
||
|
||
### `lib/widgets/collection/app_bar/cast/cast_icon_button.dart`
|
||
Gestisce il **tap sull’icona Cast** nella app bar.
|
||
|
||
Qui si decide se il tap deve fare:
|
||
- solo **connessione device**
|
||
- oppure connessione + media
|
||
|
||
### Se hai un bug tipo:
|
||
- scegli Google ma sembra partire Custom
|
||
- il cast parte subito quando scegli il device
|
||
- il device si connette ma la UX è sbagliata
|
||
|
||
👉 guarda **questo file**.
|
||
|
||
---
|
||
|
||
### `lib/widgets/collection/app_bar/cast/cast_bar_inline.dart`
|
||
È la **seconda barra orizzontale** con:
|
||
- cast manuale
|
||
- fullscreen cast
|
||
- slideshow
|
||
- prev/next
|
||
- stop slideshow
|
||
- stop cast
|
||
|
||
### Se hai un bug tipo:
|
||
- parte con gli item sbagliati
|
||
- usa una selezione vecchia
|
||
- startIndex invalido
|
||
- overflow orizzontale della barra
|
||
|
||
👉 guarda **questo file**.
|
||
|
||
---
|
||
|
||
### `lib/widgets/collection/app_bar/cast/cast_controls_sheet.dart`
|
||
È il **bottom sheet dei controlli**.
|
||
|
||
Qui trovi:
|
||
- seek
|
||
- prev/play-pause/next
|
||
- volume/mute
|
||
- stop slideshow
|
||
- stop cast
|
||
|
||
### Se hai un bug tipo:
|
||
- il volume non compare
|
||
- il volume compare ma non si aggiorna
|
||
- i controlli interagiscono col backend sbagliato
|
||
- la UI chiama `controller.google` / `controller.custom` direttamente
|
||
|
||
👉 guarda **questo file**.
|
||
|
||
---
|
||
|
||
### `lib/widgets/viewer/fullscreen_cast_viewer.dart`
|
||
È il viewer fullscreen locale sincronizzato col Cast.
|
||
|
||
### Se hai un bug tipo:
|
||
- il video sulla TV cambia seek ma il telefono no
|
||
- il fullscreen non segue l’indice Cast
|
||
- il video locale e il Cast non sono allineati
|
||
|
||
👉 guarda **questo file**.
|
||
|
||
---
|
||
|
||
## Lato plugin Android
|
||
|
||
### `plugins/google_cast/android/src/main/kotlin/com/aves/google_cast/FlutterCastFrameworkPlugin.kt`
|
||
**Router centrale del plugin**.
|
||
|
||
Riceve tutto dal `MethodChannel('google_cast')`.
|
||
|
||
### Se hai un bug tipo:
|
||
- Flutter chiama un metodo ma sembra non arrivare al native
|
||
- un comando non viene instradato bene
|
||
- un handler non viene più registrato
|
||
|
||
👉 guarda **questo file**.
|
||
|
||
---
|
||
|
||
### `CastContextManager.kt`
|
||
Gestisce:
|
||
- `CastContext`
|
||
- `Activity`
|
||
- sessione Cast corrente
|
||
- `RemoteMediaClient`
|
||
|
||
### Se hai un bug tipo:
|
||
- sessione non trovata
|
||
- device connesso ma client nullo
|
||
- callback non agganciata al client corretto
|
||
|
||
👉 guarda **questo file**.
|
||
|
||
---
|
||
|
||
### `CastSessionHandler.kt`
|
||
Gestisce gli eventi di sessione:
|
||
- `onSessionStarted`
|
||
- `onSessionResumed`
|
||
- `onSessionEnded`
|
||
- `onCastReady`
|
||
- `onCastStopped`
|
||
|
||
### Se hai un bug tipo:
|
||
- il device si connette ma Flutter non sa che è pronto
|
||
- la seconda barra non compare
|
||
- la sessione finisce ma Flutter resta “connected”
|
||
|
||
👉 guarda **questo file**.
|
||
|
||
---
|
||
|
||
### `CastDialogLauncher.kt`
|
||
Mostra il dialog nativo di selezione device.
|
||
|
||
### Se hai un bug tipo:
|
||
- l’icona Cast non apre il picker
|
||
- il picker si apre ma non seleziona device
|
||
|
||
👉 guarda **questo file**.
|
||
|
||
---
|
||
|
||
### `CastMediaClient.kt`
|
||
Gestisce:
|
||
- play / pause / seek
|
||
- get media status
|
||
- volume / mute
|
||
- callback `RemoteMediaClient.Callback`
|
||
|
||
### Se hai un bug tipo:
|
||
- `onQueueIndexChanged` non arriva più a Flutter
|
||
- `onVideoFinished` non arriva
|
||
- `Invalid Request`
|
||
- volume nativo Google non si aggiorna
|
||
|
||
👉 guarda **questo file**.
|
||
|
||
---
|
||
|
||
### `CastQueueManager.kt`
|
||
Gestisce:
|
||
- `loadQueue(items, startIndex)`
|
||
- `next()`
|
||
- `prev()`
|
||
- costruzione `MediaQueueItem`
|
||
- metadati (`index`, `isVideo`, mime, title)
|
||
|
||
### Se hai un bug tipo:
|
||
- `Invalid startIndex`
|
||
- queue rotta o item sbagliati
|
||
- Google Cast non va al prossimo item come dovrebbe
|
||
|
||
👉 guarda **questo file**.
|
||
|
||
---
|
||
|
||
### `CastCustomReceiver.kt`
|
||
Gestisce l’avvio del custom receiver web/CAF.
|
||
|
||
### Se hai un bug tipo:
|
||
- il receiver custom non parte
|
||
- parte ma non riceve messaggi
|
||
- la sessione custom sembra connettersi ma non carica nulla
|
||
|
||
👉 guarda **questo file**.
|
||
|
||
---
|
||
|
||
# 3. Mappa dei comandi principali
|
||
|
||
## Comandi Flutter → plugin Android
|
||
|
||
### Connessione
|
||
- `showCastDialog`
|
||
- `startCustomReceiver`
|
||
|
||
### Queue / navigazione
|
||
- `loadQueue`
|
||
- `next`
|
||
- `prev`
|
||
|
||
### Media
|
||
- `play`
|
||
- `pause`
|
||
- `seekTo`
|
||
- `getMediaStatus`
|
||
|
||
### Volume
|
||
- `getVolume`
|
||
- `setVolume`
|
||
- `setMute`
|
||
|
||
### Stop
|
||
- `stopCast`
|
||
|
||
---
|
||
|
||
# 4. Mappa degli eventi di ritorno
|
||
|
||
## Google Cast standard → Flutter
|
||
- `onCastReady`
|
||
- `onCastStopped`
|
||
- `onQueueIndexChanged`
|
||
- `onVideoFinished`
|
||
- `onCastError`
|
||
|
||
## Custom Receiver → Flutter
|
||
Di solito via messaggi custom, per esempio:
|
||
- `CAST_READY`
|
||
- `CAST_STOPPED`
|
||
- `MEDIA_STATUS`
|
||
- `VOLUME_STATUS`
|
||
|
||
---
|
||
|
||
# 5. Troubleshooting rapido
|
||
|
||
## Problema: seleziono il device e subito compaiono
|
||
- `Invalid Request`
|
||
- `MediaQueue error 2001`
|
||
- `IDLE_REASON_ERROR`
|
||
|
||
### Causa probabile
|
||
Il polling media parte **troppo presto**, cioè già su `onCastReady` quando non esiste ancora una queue/media caricata.
|
||
|
||
### Dove guardare
|
||
- `google_cast_controller.dart`
|
||
- `CastMediaClient.kt`
|
||
|
||
### Fix tipico
|
||
- non avviare `startMediaPolling()` dentro `onCastReady`
|
||
- far partire il polling solo dopo `loadQueue`
|
||
- lato native, ignorare gli stati in cui `mediaInfo == null`
|
||
|
||
---
|
||
|
||
## Problema: slideshow Google fa prima e seconda foto, poi si ferma
|
||
|
||
### Causa probabile
|
||
Flutter non riceve più il cambio item queue, quindi il timer slideshow non viene riarmato.
|
||
|
||
### Dove guardare
|
||
- `google_cast_controller.dart`
|
||
- `CastMediaClient.kt`
|
||
- eventualmente `CastQueueManager.kt`
|
||
|
||
### Fix tipico
|
||
- ripristinare la callback `RemoteMediaClient.Callback`
|
||
- reinviare a Flutter `onQueueIndexChanged(index, isVideo)`
|
||
- in Dart riarmare il timer solo per le foto
|
||
|
||
---
|
||
|
||
## Problema: in slideshow un video viene saltato dopo 5 secondi
|
||
|
||
### Causa probabile
|
||
Il timer slideshow delle foto parte anche sui video.
|
||
|
||
### Dove guardare
|
||
- `google_cast_controller.dart`
|
||
- `custom_cast_controller.dart`
|
||
|
||
### Comportamento corretto
|
||
- **foto** → timer
|
||
- **video** → nessun timer, deve finire da solo e poi passare al successivo
|
||
|
||
---
|
||
|
||
## Problema: in presentazione manuale/fullscreen le foto avanzano da sole
|
||
|
||
### Causa probabile
|
||
La logica slideshow è rimasta attiva quando non dovrebbe.
|
||
|
||
### Dove guardare
|
||
- `google_cast_controller.dart`
|
||
- `custom_cast_controller.dart`
|
||
- `cast_bar_inline.dart`
|
||
|
||
### Comportamento corretto
|
||
- **manuale/fullscreen**: le foto restano ferme fino a un comando manuale
|
||
- i video invece vanno al successivo a fine riproduzione
|
||
|
||
---
|
||
|
||
## Problema: `Invalid startIndex: X`
|
||
|
||
### Causa probabile
|
||
Stai caricando una queue con un indice iniziale più grande della lunghezza della lista.
|
||
|
||
### Dove guardare
|
||
- `cast_bar_inline.dart`
|
||
- `google_cast_controller.dart`
|
||
- `custom_cast_controller.dart`
|
||
- `CastQueueManager.kt`
|
||
|
||
### Fix tipico
|
||
- usare `startIndex: 0` nei comandi manuali della cast bar
|
||
- oppure proteggere con una funzione tipo `_safeIndexOrKeep(...)`
|
||
|
||
---
|
||
|
||
## Problema: seek sul video cambia sulla TV ma non sul telefono
|
||
|
||
### Causa probabile
|
||
Il telefono usa un player locale non sincronizzato con `positionNotifier` / `isPlayingNotifier` del Cast.
|
||
|
||
### Dove guardare
|
||
- `google_cast_controller.dart`
|
||
- `fullscreen_cast_viewer.dart`
|
||
|
||
### Fix tipico
|
||
- in `seekCast()` aggiornare subito `positionNotifier`
|
||
- nel `VideoWidget` locale ascoltare `positionNotifier` e `isPlayingNotifier`
|
||
|
||
---
|
||
|
||
## Problema: il volume compare ma la barra non si aggiorna
|
||
|
||
### Causa probabile
|
||
Il comando volume parte, ma il notifier locale non viene riallineato con lo stato reale del device.
|
||
|
||
### Dove guardare
|
||
- `google_cast_controller.dart`
|
||
- `cast_controls_sheet.dart`
|
||
- `fullscreen_cast_viewer.dart`
|
||
- `CastMediaClient.kt`
|
||
|
||
### Fix tipico
|
||
- dopo `setVolume` e `setMute`, chiamare `refreshVolumeStatus()`
|
||
- lato UI, separare `onChanged` e `onChangeEnd` dello slider
|
||
|
||
---
|
||
|
||
## Problema: scegli Google ma sembra partire Custom
|
||
|
||
### Causa probabile
|
||
Il backend attivo del controller unificato non è allineato al backend scelto nella UI.
|
||
|
||
### Dove guardare
|
||
- `cast_icon_button.dart`
|
||
- `cast_controller.dart`
|
||
- `custom_cast_controller.dart`
|
||
- `google_cast_controller.dart`
|
||
|
||
### Fix tipico
|
||
- rendere l’icona Cast “connect-only”
|
||
- impostare esplicitamente il backend attivo (`_backend`) nel controller unificato
|
||
- far partire la queue solo dai pulsanti della cast bar
|
||
|
||
---
|
||
|
||
## Problema: in selection mode la app bar sembra toccare anche le foto sotto
|
||
|
||
### Causa probabile
|
||
La barra non sta assorbendo correttamente i tocchi nell’area header.
|
||
|
||
### Dove guardare
|
||
- `collection_app_bar.dart`
|
||
- `aves_app_bar.dart`
|
||
- `collection_page.dart`
|
||
|
||
### Fix tipico
|
||
- ripristinare il wrapper che assorbe i tap nella barra (`AInkResponse`)
|
||
- verificare il comportamento `pinned`
|
||
- verificare l’uso corretto di `appBarHeightNotifier`
|
||
|
||
---
|
||
|
||
# 6. Regole pratiche di debug
|
||
|
||
## Regola 1
|
||
### Se il problema è “UI Flutter non aggiornata”
|
||
Guarda prima i controller Dart:
|
||
- `cast_controller.dart`
|
||
- `google_cast_controller.dart`
|
||
- `custom_cast_controller.dart`
|
||
- `fullscreen_cast_viewer.dart`
|
||
|
||
---
|
||
|
||
## Regola 2
|
||
### Se il problema è “la TV/device fa una cosa diversa da Flutter”
|
||
Guarda:
|
||
- `CastMediaClient.kt`
|
||
- `CastQueueManager.kt`
|
||
- receiver custom JS/HTML (se custom)
|
||
|
||
---
|
||
|
||
## Regola 3
|
||
### Se il problema avviene subito dopo la connessione device
|
||
Guarda:
|
||
- `CastSessionHandler.kt`
|
||
- `google_cast_controller.dart`
|
||
- `CastMediaClient.kt`
|
||
|
||
Il sospetto classico è la distinzione:
|
||
- connessione sessione
|
||
- queue realmente caricata
|
||
|
||
---
|
||
|
||
## Regola 4
|
||
### Se il problema riguarda slideshow foto/video
|
||
Guarda prima il controller Dart, poi il native.
|
||
|
||
Ordine consigliato:
|
||
1. `google_cast_controller.dart`
|
||
2. `custom_cast_controller.dart`
|
||
3. `CastMediaClient.kt`
|
||
4. `CastQueueManager.kt`
|
||
|
||
---
|
||
|
||
## Regola 5
|
||
### Se il problema riguarda il Custom Receiver
|
||
Non fermarti al controller Flutter.
|
||
|
||
Devi guardare anche:
|
||
- `CastCustomReceiver.kt`
|
||
- `receiver.html`
|
||
- eventuale JS del receiver
|
||
|
||
Perché molti bug Custom sono **receiver-side**, non plugin-side.
|
||
|
||
---
|
||
|
||
# 7. Differenza pratica Google vs Custom (da tenere a mente)
|
||
|
||
## Google Cast standard
|
||
### Più affidabile quando:
|
||
- usi queue nativa
|
||
- usi volume Cast nativo
|
||
- ti affidi a `RemoteMediaClient.Callback`
|
||
|
||
## Custom Receiver
|
||
### Più flessibile quando:
|
||
- vuoi UI custom sul TV
|
||
- vuoi logica media personalizzata
|
||
- vuoi controllare il player HTML5 direttamente
|
||
|
||
### Ma più fragile quando:
|
||
- volume/mute non sono implementati davvero
|
||
- il DOM del receiver non viene pulito bene
|
||
- i messaggi receiver/Flutter non sono perfettamente allineati
|
||
|
||
---
|
||
|
||
# 8. Checklist rapida: dove toccare per ogni categoria
|
||
|
||
## Connessione device
|
||
- `cast_icon_button.dart`
|
||
- `FlutterCastFrameworkPlugin.kt`
|
||
- `CastDialogLauncher.kt`
|
||
- `CastSessionHandler.kt`
|
||
|
||
## Queue / media non partono
|
||
- `cast_bar_inline.dart`
|
||
- `google_cast_controller.dart`
|
||
- `CastQueueManager.kt`
|
||
|
||
## Slideshow foto/video
|
||
- `google_cast_controller.dart`
|
||
- `custom_cast_controller.dart`
|
||
- `CastMediaClient.kt`
|
||
|
||
## Volume Google
|
||
- `google_cast_controller.dart`
|
||
- `cast_controls_sheet.dart`
|
||
- `fullscreen_cast_viewer.dart`
|
||
- `CastMediaClient.kt`
|
||
|
||
## Volume Custom
|
||
- `custom_cast_controller.dart`
|
||
- `CastCustomReceiver.kt`
|
||
- `receiver.html` / JS
|
||
|
||
## Bug UI selection / app bar
|
||
- `collection_app_bar.dart`
|
||
- `aves_app_bar.dart`
|
||
- `collection_page.dart`
|
||
|
||
---
|
||
|
||
# 9. Conclusione pratica
|
||
|
||
Se devi pensare al plugin in modo operativo, ricordati questa formula:
|
||
|
||
## **Flutter decide l’UX → il plugin Android parla con Cast → il receiver riproduce davvero**
|
||
|
||
Quindi ogni bug va classificato subito in una di queste tre famiglie:
|
||
|
||
### A. Bug UX / Flutter
|
||
- notifier
|
||
- selection
|
||
- fullscreen viewer
|
||
- cast bar
|
||
- app bar
|
||
|
||
### B. Bug plugin Android
|
||
- sessione
|
||
- queue
|
||
- callback media
|
||
- volume nativo
|
||
|
||
### C. Bug receiver
|
||
- volume custom
|
||
- progress bar duplicate
|
||
- media status custom
|
||
- UI TV-side
|
||
|
||
Capire **subito** in quale famiglia rientra il bug fa risparmiare tantissimo tempo di debug.
|