Interfaccia del player

Un player è il componente dell'app che semplifica la riproduzione di elementi multimediali. L'interfaccia Media3 Player definisce un'organizzazione per le funzionalità generalmente gestite da un player. Sono inclusi:

  • Interessa i controlli di riproduzione, ad esempio la riproduzione, la messa in pausa e la ricerca
  • Eseguire query sulle proprietà dei contenuti multimediali in riproduzione, ad esempio la posizione di riproduzione
  • Gestione di una playlist/coda di elementi multimediali
  • Configurazione delle proprietà di riproduzione, ad esempio riproduzione casuale, ripetizione, velocità e volume
  • Rendering del video sullo schermo

Media3 fornisce anche un'implementazione dell'interfaccia Player, chiamata ExoPlayer.

Un'interfaccia comune tra i componenti

Diversi componenti in Media3 implementano l'interfaccia Player, ad esempio:

Componente Descrizione e note sul comportamento
ExoPlayer Un'API di media player e l'implementazione predefinita dell'interfaccia Player.
MediaController Interagisce con un MediaSession per inviare comandi di riproduzione. Se il tuo Player e il tuo MediaSession si trovano in un Service separato dal Activity o dal Fragment in cui si trova l'interfaccia utente del tuo player, puoi assegnare il tuo MediaController come player per l'interfaccia PlayerView. Le chiamate ai metodi di riproduzione e delle playlist vengono inviate al tuo Player tramite il tuo MediaSession.
MediaBrowser Oltre alla funzionalità offerta da un MediaController, interagisce con un MediaLibrarySession per sfogliare i contenuti multimediali disponibili.
ForwardingPlayer Un'implementazione Player che inoltra le chiamate dei metodi a un altro Player. Utilizza questa classe per eliminare o modificare operazioni specifiche eseguendo l'override dei rispettivi metodi.
SimpleBasePlayer Un'implementazione di Player che riduce al minimo il numero di metodi da implementare. Utile quando utilizzi un player personalizzato che vuoi collegare a un MediaSession.
CastPlayer Un'implementazione Player che comunica con un'app ricevitore Cast. Il comportamento dipende dalla sessione di trasmissione sottostante.

Anche se MediaSession non implementa l'interfaccia Player, richiede Player durante la creazione. Il suo scopo è fornire l'accesso a Player da altri processi o thread.

Architettura di riproduzione Media3

Se hai accesso a un Player, devi chiamare i relativi metodi direttamente per emettere comandi di riproduzione. Puoi pubblicizzare la tua riproduzione e concedere il controllo della riproduzione a fonti esterne implementando un MediaSession. Queste sorgenti esterne implementano un MediaController, che facilita la connessione a una sessione multimediale e l'invio di richieste di comandi di riproduzione.

Quando riproduci contenuti multimediali in background, devi inserire la sessione multimediale e il media player in un MediaSessionService o MediaLibraryService che viene eseguito come servizio in primo piano. In questo caso, puoi separare il player dall'attività nell'app che contiene l'interfaccia utente per il controllo della riproduzione. Potrebbe essere necessario utilizzare un controllo multimediale.

Un diagramma che mostra come i componenti di riproduzione di Media3 si inseriscono in un'architettura di app multimediali.
Figura 1: l'interfaccia Player svolge un ruolo chiave nell'architettura di Media3.

Stato del player

Lo stato di un media player che implementa l'interfaccia Player è costituito principalmente da quattro categorie di informazioni:

  1. Stato di riproduzione
  2. Playlist di elementi multimediali
  3. Proprietà di riproduzione/messa in pausa, ad esempio:
    • playWhenReady: indicazione se l'utente vuole che i contenuti multimediali vengano riprodotti quando possibile o che rimangano in pausa
    • Motivo dell'eliminazione della riproduzione: un'indicazione del motivo per cui la riproduzione viene eliminata, se applicabile, anche se playWhenReady è true
    • isPlaying: Un'indicazione che indica se il player è attualmente in riproduzione, opzione disponibile soltanto true se lo stato di riproduzione è STATE_READY, playWhenReady è true e la riproduzione non è soppressa
  4. Posizione di riproduzione, tra cui:

Inoltre, l'interfaccia di Player consente di accedere a tracce disponibili, metadati multimediali, velocità di riproduzione, volume e altre proprietà ausiliarie della riproduzione.

Ascolta le modifiche

Utilizza un Player.Listener per rilevare le modifiche in un Player. Consulta la documentazione di ExoPlayer sugli eventi del player per informazioni dettagliate su come creare e utilizzare un ascoltatore.

Tieni presente che l'interfaccia listener non include callback per tracciare la normale avanzamento della riproduzione. Per monitorare continuamente l'avanzamento della riproduzione, ad esempio per impostare un'interfaccia utente della barra di avanzamento, devi eseguire una query sulla posizione corrente a intervalli appropriati.

Kotlin

val handler = Handler(Looper.getMainLooper())
fun checkPlaybackPosition(delayMs: Long): Boolean =
  handler.postDelayed(
    {
      val currentPosition = player.currentPosition
      // Update UI based on currentPosition
      checkPlaybackPosition(delayMs)
    },
    delayMs)

Java

Handler handler = new Handler(Looper.getMainLooper());
boolean checkPlaybackPosition(long delayMs) {
    return handler.postDelayed(() -> {
        long currentPosition = player.getCurrentPosition();
        // Update UI based on currentPosition
        checkPlaybackPosition(delayMs);
    }, delayMs);
}

Controlla la riproduzione

L'interfaccia Player offre molti modi per manipolare lo stato e controllare la riproduzione:

Implementazioni personalizzate di Player

Per creare un player personalizzato, puoi estendere il SimpleBasePlayer incluso in Media3. Questa classe fornisce un'implementazione di base dell'interfaccia Player per ridurre al minimo il numero di metodi da implementare.

Per iniziare, sostituisci il metodo getState(). Questo metodo dovrebbe compilare lo stato attuale del player quando viene chiamato, tra cui:

  • L'insieme di comandi disponibili
  • Proprietà di riproduzione, ad esempio se il player deve avviare la riproduzione quando lo stato di riproduzione è STATE_READY, l'indice dell'elemento multimediale attualmente in riproduzione e la posizione di riproduzione all'interno dell'elemento corrente

Kotlin

class CustomPlayer : SimpleBasePlayer(looper) {
  override fun getState(): State {
    return State.Builder()
      .setAvailableCommands(...) // Set which playback commands the player can handle
      // Configure additional playback properties
      .setPlayWhenReady(true, PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST)
      .setCurrentMediaItemIndex(0)
      .setContentPositionMs(0)
      .build()
  }
}

Java

public class CustomPlayer extends SimpleBasePlayer {
  public CustomPlayer(Looper looper) {
    super(looper);
  }

  @Override
  protected State getState() {
    return new State.Builder()
      .setAvailableCommands(...) // Set which playback commands the player can handle
      // Configure additional playback properties
      .setPlayWhenReady(true, PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST)
      .setCurrentMediaItemIndex(0)
      .setContentPositionMs(0)
      .build();
  }
}

SimpleBasePlayer imporrà che State venga creato con una combinazione valida di valori di stato. Gestirà anche gli ascoltatori e li informerà delle modifiche dello stato. Se devi attivare manualmente un aggiornamento dello stato, chiama invalidateState().

Oltre al metodo getState(), devi implementare solo i metodi utilizzati per i comandi dichiarati disponibili dal tuo player. Trova il metodo di gestore override che corrisponde alla funzionalità che vuoi implementare. Ad esempio, esegui l'override del metodo handleSeek() per supportare operazioni come COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM e COMMAND_SEEK_TO_NEXT_MEDIA_ITEM.