Jetpack Media3 definiuje interfejs Player
, który zawiera podstawowe funkcje odtwarzania plików wideo i audio. ExoPlayer
to domyślna implementacja tego interfejsu w Media3. Zalecamy korzystanie z ExoPlayera, ponieważ zapewnia on kompleksowy zestaw funkcji, które obejmują większość przypadków użycia odtwarzania, a także można go dostosować do innych przypadków użycia. ExoPlayer eliminuje też problemy związane z fragmentacją urządzeń i systemów operacyjnych, dzięki czemu Twój kod działa spójnie w całym ekosystemie Androida. ExoPlayer obejmuje:
- Obsługa playlist
- Obsługa różnych formatów strumieniowego przesyłania progresywnego i adaptacyjnego.
- obsługa wstawiania reklam po stronie klienta i po stronie serwera;
- Obsługa odtwarzania chronionego przez DRM
Na tej stronie znajdziesz omówienie niektórych kluczowych kroków tworzenia aplikacji do odtwarzania. Więcej informacji znajdziesz w pełnych przewodnikach dotyczących Media3 ExoPlayer.
Pierwsze kroki
Aby rozpocząć, dodaj zależność od modułów ExoPlayer, UI i Common w Jetpack Media3:
implementation "androidx.media3:media3-exoplayer:1.4.1" implementation "androidx.media3:media3-ui:1.4.1" implementation "androidx.media3:media3-common:1.4.1"
W zależności od zastosowania możesz też potrzebować dodatkowych modułów Media3, takich jak exoplayer-dash
, aby odtwarzać strumienie w formacie DASH.
Pamiętaj, aby zastąpić 1.4.1
preferowaną wersją biblioteki. Aby dowiedzieć się więcej o najnowszej wersji, zapoznaj się z informacjami o wersji.
Tworzenie odtwarzacza
W Media3 możesz użyć dołączonej implementacji interfejsu Player
(ExoPlayer
) lub utworzyć własną implementację niestandardową.
Tworzenie ExoPlayera
Najprostszym sposobem utworzenia instancji ExoPlayer
jest:
Kotlin
val player = ExoPlayer.Builder(context).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context).build();
Odtwarzacz multimediów możesz utworzyć w metodzie cyklu życia onCreate()
w ramach Activity
, Fragment
lub Service
, w których się on znajduje.
Builder
zawiera szereg opcji dostosowywania, które mogą Cię zainteresować, takie jak:
setAudioAttributes()
aby skonfigurować obsługę aktywności audio.setHandleAudioBecomingNoisy()
aby skonfigurować sposób odtwarzania po odłączeniu urządzenia wyjściowego audio.setTrackSelector()
aby skonfigurować wybór ścieżki
Media3 udostępnia komponent UI PlayerView
, który możesz umieścić w pliku układu aplikacji. Ten komponent zawiera PlayerControlView
do sterowania odtwarzaniem, SubtitleView
do wyświetlania napisów i Surface
do renderowania filmu.
Przygotowywanie odtwarzacza
Dodaj elementy multimedialne do playlisty, aby odtwarzać je za pomocą metod takich jak setMediaItem()
i addMediaItem()
.
Następnie zadzwoń pod numer prepare()
, aby rozpocząć wczytywanie multimediów i pobrać niezbędne zasoby.
Zanim aplikacja będzie na pierwszym planie, nie wykonuj tych czynności. Jeśli odtwarzacz znajduje się w stanach Activity
lub Fragment
, oznacza to, że należy go przygotować w metodach cyklu życia onStart()
(poziom interfejsu API 24 lub nowszy) lub onResume()
(poziom interfejsu API 23 lub starszy). Jeśli gracz jest w Service
, możesz go przygotować w onCreate()
.
Sterowanie odtwarzaczem
Po przygotowaniu odtwarzacza możesz sterować odtwarzaniem, wywołując metody odtwarzacza, takie jak:
play()
ipause()
– aby rozpocząć i wstrzymać odtwarzanie.seekTo()
– aby przejść do pozycji w bieżącym elemencie multimedialnym.seekToNextMediaItem()
iseekToPreviousMediaItem()
aby poruszać się po playlistzie.
Komponenty interfejsu, takie jak PlayerView
lub PlayerControlView
, będą się odpowiednio aktualizować po połączeniu z odtwarzaczem.
Zwolnij odtwarzacz
Odtwarzanie może wymagać zasobów, których podaż jest ograniczona, takich jak dekodery wideo, dlatego ważne jest, aby wywołać release()
w odtwarzaczu, aby zwolnić zasoby, gdy odtwarzacz nie jest już potrzebny.
Jeśli odtwarzacz znajduje się w komponencie Activity
lub Fragment
, zwalniaj go w metodzie cyklu życia onStop()
na poziomie interfejsu API 24 lub nowszym albo w metodzie onPause()
na poziomie interfejsu API 23 lub niższym. Jeśli gracz znajduje się w Service
, możesz go zwolnić w onDestroy()
.
Zarządzanie odtwarzaniem za pomocą sesji multimediów
Na Androidzie sesje multimediów zapewniają ustandaryzowany sposób interakcji z odtwarzaczem multimediów niezależnie od granic procesów. Połączenie sesji multimediów z odtwarzaczem pozwala reklamować odtwarzanie multimediów na zewnątrz i odbierać polecenia odtwarzania z zewnętrznych źródeł, na przykład w celu integracji z elementami sterującymi multimediów w systemie na urządzeniach mobilnych i urządzeniach z dużym ekranem.
Aby korzystać z sesji multimediów, dodaj zależność od modułu Media3 Session:
implementation "androidx.media3:media3-session:1.4.1"
Tworzenie sesji multimedialnej
Po zainicjowaniu odtwarzacza możesz utworzyć MediaSession
w ten sposób:
Kotlin
val player = ExoPlayer.Builder(context).build() val mediaSession = MediaSession.Builder(context, player).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context).build(); MediaSession mediaSession = new MediaSession.Builder(context, player).build();
Media3 automatycznie synchronizuje stan Player
ze stanem MediaSession
. Ta funkcja działa z dowolną implementacją Player
, w tym ExoPlayer
, CastPlayer
lub implementacją niestandardową.
Przyznawanie kontroli innym klientom
Aplikacje klienckie mogą stosować sterownik multimediów do kontrolowania odtwarzania multimediów. Aby otrzymywać te żądania, podczas tworzenia MediaSession
ustaw obiekt callback.
Gdy kontroler ma się połączyć z sesją multimediów, wywoływana jest metoda onConnect()
. Możesz użyć otrzymanego ControllerInfo
, aby zdecydować, czy zaakceptować, czy odrzucić prośbę. Przykład znajdziesz w aplikacji demonstracyjnej Media3 Session.
Po nawiązaniu połączenia kontroler może wysyłać do sesji polecenia odtwarzania. Sesja przekazuje te polecenia odtwarzaczowi. Polecenia odtwarzania i playlist zdefiniowane w interfejsie Player
są automatycznie obsługiwane przez sesję.
Inne metody wywołania umożliwiają obsługę np. żądań niestandardowych poleceń odtwarzania i modyfikowania playlisty. Te funkcje zwracane zawierają również obiekt ControllerInfo
, dzięki czemu możesz określać kontrolę dostępu w przypadku poszczególnych żądań.
odtwarzanie multimediów w tle,
Aby kontynuować odtwarzanie multimediów, gdy aplikacja nie jest na pierwszym planie (np. aby odtwarzać muzykę, audiobooki lub podcasty, gdy użytkownik nie ma otwartej aplikacji), funkcje Player
i MediaSession
powinny być zapakowane w usługę na pierwszym planie. W tym celu Media3 udostępnia interfejs MediaSessionService
.
Wdrażanie MediaSessionService
Utwórz klasę rozszerzającą klasę MediaSessionService
i utwórz instancję klasy MediaSession
w metodzie cyklu życia onCreate()
.
Kotlin
class PlaybackService : MediaSessionService() { private var mediaSession: MediaSession? = null // Create your Player and MediaSession in the onCreate lifecycle event override fun onCreate() { super.onCreate() val player = ExoPlayer.Builder(this).build() mediaSession = MediaSession.Builder(this, player).build() } // Remember to release the player and media session in onDestroy override fun onDestroy() { mediaSession?.run { player.release() release() mediaSession = null } super.onDestroy() } }
Java
public class PlaybackService extends MediaSessionService { private MediaSession mediaSession = null; @Override public void onCreate() { super.onCreate(); ExoPlayer player = new ExoPlayer.Builder(this).build(); mediaSession = new MediaSession.Builder(this, player).build(); } @Override public void onDestroy() { mediaSession.getPlayer().release(); mediaSession.release(); mediaSession = null; super.onDestroy(); } }
W pliku manifestu klasa Service
z filtrem intencji MediaSessionService
i uprawnieniem FOREGROUND_SERVICE
do uruchamiania usługi na pierwszym planie:
<service
android:name=".PlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="true">
<intent-filter>
<action android:name="androidx.media3.session.MediaSessionService"/>
</intent-filter>
</service>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
Na koniec w utworzonym przez siebie module zastąpij metodę onGetSession()
, aby kontrolować dostęp klienta do sesji multimediów. Zwracaj wartość MediaSession
, aby zaakceptować prośbę o połączenie, lub null
, aby ją odrzucić.
Kotlin
// This example always accepts the connection request override fun onGetSession( controllerInfo: MediaSession.ControllerInfo ): MediaSession? = mediaSession
Java
@Override public MediaSession onGetSession(MediaSession.ControllerInfo controllerInfo) { // This example always accepts the connection request return mediaSession; }
Łączenie z interfejsem użytkownika
Teraz, gdy sesja multimediów jest w Service
oddzielna od Activity
lub
Fragment
, gdzie znajduje się interfejs użytkownika odtwarzacza, możesz użyć MediaController
, aby połączyć je ze sobą. W metodzie onStart()
klasy Activity
lub Fragment
w interfejsie użytkownika utwórz obiekt SessionToken
dla obiektu MediaSession
, a następnie użyj obiektu SessionToken
do utworzenia obiektu MediaController
. Tworzenie MediaController
odbywa się asynchronicznie.
Kotlin
override fun onStart() { val sessionToken = SessionToken(this, ComponentName(this, PlaybackService::class.java)) val controllerFuture = MediaController.Builder(this, sessionToken).buildAsync() controllerFuture.addListener( { // Call controllerFuture.get() to retrieve the MediaController. // MediaController implements the Player interface, so it can be // attached to the PlayerView UI component. playerView.setPlayer(controllerFuture.get()) }, MoreExecutors.directExecutor() ) }
Java
@Override public void onStart() { SessionToken sessionToken = new SessionToken(this, new ComponentName(this, PlaybackService.class)); ListenableFuture<MediaController> controllerFuture = new MediaController.Builder(this, sessionToken).buildAsync(); controllerFuture.addListener(() -> { // Call controllerFuture.get() to retrieve the MediaController. // MediaController implements the Player interface, so it can be // attached to the PlayerView UI component. playerView.setPlayer(controllerFuture.get()); }, MoreExecutors.directExecutor()) }
MediaController
korzysta z interfejsu Player
, więc do sterowania odtwarzaniem możesz używać tych samych metod, takich jak play()
i pause()
. Podobnie jak w przypadku innych komponentów, pamiętaj, aby zwolnić MediaController
, gdy nie jest już potrzebny, np. w metodach cyklu życia onStop()
w komponencie Activity
, wywołując funkcję MediaController.releaseFuture()
.
Publikowanie powiadomienia
Usługi na pierwszym planie muszą publikować powiadomienia podczas działania. MediaSessionService
automatycznie utworzy dla Ciebie powiadomienie MediaStyle
w postaci MediaNotification
.
Aby wyświetlić powiadomienie niestandardowe, utwórz MediaNotification.Provider
za pomocą DefaultMediaNotificationProvider.Builder
lub stwórz niestandardową implementację interfejsu dostawcy. Dodaj dostawcę do MediaSession
za pomocą setMediaNotificationProvider
.
Promowanie biblioteki treści
MediaLibraryService
opiera się na MediaSessionService
, umożliwiając aplikacjom klienta przeglądanie treści multimedialnych udostępnianych przez Twoją aplikację. Aplikacje klienta implementują MediaBrowser
, aby wchodzić w interakcje z Twoją aplikacją MediaLibraryService
.
Wdrażanie funkcji MediaLibraryService
jest podobne do wdrażania funkcji MediaSessionService
, z tą różnicą, że w funkcji onGetSession()
zamiast MediaSession
należy zwracać MediaLibrarySession
. W porównaniu z MediaSession.Callback
usługa MediaLibrarySession.Callback
zawiera dodatkowe metody, które umożliwiają klientowi przeglądarki poruszanie się po treściach oferowanych przez Twoją usługę biblioteki.
Podobnie jak w przypadku MediaSessionService
, zadeklaruj MediaLibraryService
w pliku manifestu i poproś o uprawnienie FOREGROUND_SERVICE
, aby uruchomić usługę na pierwszym planie:
<service
android:name=".PlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="true">
<intent-filter>
<action android:name="androidx.media3.session.MediaLibraryService"/>
<action android:name="android.media.browse.MediaBrowserService"/>
</intent-filter>
</service>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
Przykład powyżej zawiera filtr intencji zarówno dla MediaLibraryService
, jak i dla starszego MediaBrowserService
(ze względu na zgodność wsteczną). Dodatkowy filtr intencji umożliwia aplikacjom klienckim korzystającym z interfejsu API MediaBrowserCompat
rozpoznawanie Twojego Service
.
MediaLibrarySession
umożliwia wyświetlanie biblioteki treści w strukturze drzewa z jednym MediaItem
na poziomie głównym. Każdy węzeł MediaItem
w drzewie może mieć dowolną liczbę węzłów podrzędnych MediaItem
. Możesz wyświetlać inny element rdzeniowy lub inny element drzewa na podstawie żądania aplikacji klienckiej. Na przykład drzewo zwracane klientowi, który szuka listy polecanych elementów multimedialnych, może zawierać tylko węzeł główny MediaItem
i jeden poziom węzłów podrzędnych MediaItem
, podczas gdy drzewo zwracane innej aplikacji klienta może reprezentować bardziej kompletną bibliotekę treści.
Tworzenie MediaLibrarySession
MediaLibrarySession
rozszerza interfejs API MediaSession
, aby dodać interfejsy API przeglądania treści. W porównaniu z MediaSession
wywołaniem zwrotnym wywołanie zwrotne MediaLibrarySession
zawiera takie metody jak:
onGetLibraryRoot()
(gdy klient poprosi o korzeńMediaItem
drzewa treści)onGetChildren()
gdy klient prosi o podanie elementów podrzędnych elementuMediaItem
w drzewie treścionGetSearchResult()
dla przypadku, gdy klient żąda wyników wyszukiwania z drzewa treści dla danego zapytania
Odpowiednie metody wywołania będą zawierać obiekt LibraryParams
z dodatkowymi sygnałami o typie drzewa treści, którym zainteresowana jest aplikacja klienta.