Jetpack Media3 definiuje interfejs Player
, który określa podstawowe funkcje odtwarzania plików wideo i audio. ExoPlayer
to domyślna implementacja tego interfejsu w Media3. Zalecamy korzystanie z odtwarzacza ExoPlayer, ponieważ zapewnia on obszerny zestaw funkcji, które obejmują większość przypadków użycia związanych z odtwarzaniem i można je dostosować do wszelkich dodatkowych zastosowań. ExoPlayer wyodrębnia też fragmentację danych z urządzenia i systemu operacyjnego, dzięki czemu kod działa spójnie w całym ekosystemie Androida. ExoPlayer zawiera:
- obsługa playlist.
- Obsługa różnych formatów strumieniowania progresywnego i adaptacyjnego.
- Obsługa wstawiania reklam po stronie klienta i serwera
- obsługa odtwarzania z zabezpieczeniem DRM.
Na tej stronie znajdziesz najważniejsze informacje o tworzeniu aplikacji do odtwarzania. Więcej informacji znajdziesz w pełnych przewodnikach po narzędziu Media3 ExoPlayer.
Wprowadzenie
Aby rozpocząć, dodaj zależność od modułów ExoPlayer, UI i Common w Jetpack Media3:
implementation "androidx.media3:media3-exoplayer:1.3.1" implementation "androidx.media3:media3-ui:1.3.1" implementation "androidx.media3:media3-common:1.3.1"
W zależności od zastosowania możesz też potrzebować dodatkowych modułów z Media3, np. exoplayer-dash
, aby odtwarzać strumienie w formacie DASH.
Zastąp 1.3.1
wybraną wersją biblioteki. Najnowszą wersję znajdziesz w informacjach o wersji.
Tworzenie odtwarzacza multimediów
W Media3 możesz użyć dołączonej implementacji interfejsu Player
(ExoPlayer
) lub utworzyć własną implementację.
Tworzenie ExoPlayer
Najprostszy sposób utworzenia instancji ExoPlayer
jest następujący:
Kotlin
val player = ExoPlayer.Builder(context).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context).build();
Odtwarzacz możesz utworzyć w metodzie cyklu życia onCreate()
w Activity
, Fragment
lub Service
, w której się znajduje.
Builder
zawiera szereg opcji dostosowywania, które mogą Cię zainteresować. Należą do nich:
setAudioAttributes()
, aby skonfigurować obsługę fokusu audiosetHandleAudioBecomingNoisy()
, aby skonfigurować zachowanie odtwarzania po odłączeniu urządzenia wyjściowego audiosetTrackSelector()
, aby skonfigurować wybór ścieżki
Media3 udostępnia komponent interfejsu PlayerView
, który możesz umieścić w pliku układu aplikacji. Ten komponent zawiera obiekt PlayerControlView
(elementy sterujące odtwarzaniem), SubtitleView
do wyświetlania napisów oraz Surface
do renderowania filmu.
Przygotowywanie odtwarzacza
Dodawanie elementów multimedialnych do playlisty w celu jej odtwarzania za pomocą metod takich jak setMediaItem()
czy addMediaItem()
.
Następnie wywołaj metodę prepare()
, aby rozpocząć wczytywanie multimediów i pozyskanie niezbędnych zasobów.
Nie należy wykonywać tych czynności przed uruchomieniem aplikacji na pierwszym planie. Jeśli Twój odtwarzacz znajduje się w Activity
lub Fragment
, oznacza to przygotowanie go w metodzie cyklu życia onStart()
na poziomie API 24 lub wyższym lub metodzie onResume()
cyklu życia na poziomie API 23 i niższym. W przypadku gracza, który znajduje się w klastrze Service
,
możesz przygotować go w programie onCreate()
.
Sterowanie odtwarzaczem
Po przygotowaniu odtwarzacza możesz sterować odtwarzaniem, wywołując w nim następujące metody:
play()
ipause()
, aby rozpocząć i wstrzymać odtwarzanieseekTo()
, aby przewinąć do pozycji w bieżącym elemencie multimedialnymseekToNextMediaItem()
iseekToPreviousMediaItem()
, aby poruszać się po playliście
Komponenty interfejsu, takie jak PlayerView
czy PlayerControlView
, są aktualizowane odpowiednio po powiązaniu z odtwarzaczem.
Zwolnij odtwarzacz
Odtwarzanie może wymagać zasobów, których dostępność jest ograniczona (np. dekodery wideo), dlatego ważne jest wywołanie funkcji release()
w odtwarzaczu, aby zwolnić zasoby, gdy odtwarzacz nie jest już potrzebny.
Jeśli Twój odtwarzacz znajduje się w Activity
lub Fragment
, opublikuj go w metodzie cyklu życia onStop()
na poziomie API na poziomie 24 lub wyższym lub w metodzie onPause()
na poziomie API 23 i niższym. W przypadku gracza, który znajduje się w elemencie Service
,
możesz go zwolnić w onDestroy()
.
Zarządzanie odtwarzaniem w ramach sesji multimediów
Sesje multimedialne na Androidzie pozwalają wchodzić w interakcje z odtwarzaczem w standardowy sposób bez przekraczania granic procesów. Połączenie sesji multimediów z odtwarzaczem pozwala reklamować odtwarzanie multimediów na zewnątrz i otrzymywać polecenia odtwarzania ze źródeł zewnętrznych, na przykład w celu integracji z systemowymi elementami sterującymi multimediami na urządzeniach mobilnych i urządzeniach z dużym ekranem.
Aby używać sesji multimediów, dodaj zależność w module Sesja Media3:
implementation "androidx.media3:media3-session:1.3.1"
Tworzenie sesji multimediów
MediaSession
możesz utworzyć po zainicjowaniu odtwarzacza 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 elementu Player
ze stanem MediaSession
. Działa to z każdą implementacją Player
, w tym z metodami ExoPlayer
i CastPlayer
, oraz w implementacji niestandardowej.
Przyznaj kontrolę innym klientom
Aplikacje klienckie mogą wdrożyć kontroler multimediów,
aby sterować odtwarzaniem sesji multimediów. Aby móc odbierać te żądania, ustaw obiekt wywołania zwrotnego podczas tworzenia obiektu MediaSession
.
Gdy kontroler ma zamiar połączyć się z sesją multimediów, wywoływana jest metoda onConnect()
. Możesz użyć podanego ControllerInfo
, aby zdecydować, czy chcesz zaakceptować, czy odrzucić prośbę. Zobacz ten przykład w aplikacji demonstracyjnej sesji Media3.
Po podłączeniu kontroler może wysyłać do sesji polecenia odtwarzania. Następnie sesja przekazuje te polecenia do odtwarzacza. Polecenia dotyczące odtwarzania i playlist zdefiniowane w interfejsie Player
są automatycznie obsługiwane przez sesję.
Inne metody wywołania zwrotnego umożliwiają na przykład obsługę żądań niestandardowych poleceń odtwarzania czy modyfikowania playlisty. Te wywołania zwrotne podobnie zawierają obiekt ControllerInfo
, dzięki czemu możesz określić kontrolę dostępu dla poszczególnych żądań.
Odtwarzanie multimediów w tle
Aby można było kontynuować odtwarzanie multimediów, gdy aplikacja nie działa na pierwszym planie, na przykład do słuchania muzyki, audiobooków lub podcastów, nawet gdy użytkownik nie ma otwartej aplikacji, urządzenia Player
i MediaSession
powinny być umieszczone w usłudze na pierwszym planie. W tym celu Media3 udostępnia interfejs MediaSessionService
.
Wdrażanie: MediaSessionService
Utwórz klasę, która rozszerza MediaSessionService
i tworzy instancję 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 Twoja klasa Service
z filtrem intencji MediaSessionService
i żądanie uprawnienia FOREGROUND_SERVICE
do uruchomienia 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 utworzonej klasie zastąp metodę onGetSession()
, aby kontrolować dostęp klienta do sesji multimediów. Zwróć 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; }
Łączę z interfejsem
Gdy sesja multimediów znajduje się Service
w Activity
lub Fragment
miejscu, w którym znajduje się interfejs odtwarzacza, możesz je ze sobą połączyć za pomocą elementów MediaController
. W metodzie onStart()
metody Activity
lub Fragment
w Twoim interfejsie utwórz SessionToken
dla: MediaSession
, a potem użyj SessionToken
do utworzenia MediaController
. Tworzenie elementu 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
implementuje interfejs 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 metodzie cyklu życia onStop()
obiektu Activity
przez wywołanie MediaController.releaseFuture()
.
Publikowanie powiadomienia
Usługi działające na pierwszym planie są wymagane do publikowania powiadomień, gdy są aktywne. MediaSessionService
automatycznie utworzy powiadomienie MediaStyle
w formie MediaNotification
.
Aby podać niestandardowe powiadomienie, utwórz MediaNotification.Provider
z DefaultMediaNotificationProvider.Builder
lub utwórz niestandardową implementację interfejsu dostawcy. Dodaj dostawcę do usługi MediaSession
za pomocą aplikacji setMediaNotificationProvider
.
Reklamowanie biblioteki treści
Interfejs MediaLibraryService
opiera się na MediaSessionService
, umożliwiając aplikacjom klienckim przeglądanie treści multimedialnych dostarczanych przez aplikację. Aplikacje klienckie implementują interfejs MediaBrowser
, aby wchodzić w interakcję z MediaLibraryService
.
Implementacja MediaLibraryService
jest podobna do implementacji MediaSessionService
, z tą różnicą, że w onGetSession()
należy zwrócić MediaLibrarySession
zamiast MediaSession
. W porównaniu z metodą MediaSession.Callback
obiekt MediaLibrarySession.Callback
zawiera dodatkowe metody, które umożliwiają klientowi przeglądarki poruszanie się po treściach oferowanych w usłudze biblioteki.
Podobnie jak w przypadku MediaSessionService
zadeklaruj w manifeście element MediaLibraryService
i poproś o uprawnienie FOREGROUND_SERVICE
do uruchomienia usługi 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" />
Powyższy przykład zawiera filtr intencji zarówno dla elementu MediaLibraryService
, jak i dla zgodności wstecznej dla starszej wersji MediaBrowserService
. Dodatkowy filtr intencji umożliwia aplikacjom klienckim korzystającym z interfejsu API MediaBrowserCompat
rozpoznawanie Service
.
MediaLibrarySession
umożliwia wyświetlanie biblioteki treści w strukturze drzewa z pojedynczym elementem głównym MediaItem
. Każdy element MediaItem
w drzewie może mieć dowolną liczbę podrzędnych węzłów MediaItem
. Możesz obsługiwać inny poziom główny lub inne drzewo w zależności od żądania aplikacji klienta. Na przykład drzewo, które zwracasz do klienta szukającego listy zalecanych elementów multimedialnych, może zawierać tylko główny węzeł MediaItem
i jeden poziom podrzędnych węzłów MediaItem
, natomiast drzewo, do którego wrócisz do innej aplikacji klienckiej, może reprezentować pełniejszą bibliotekę treści.
Tworzę MediaLibrarySession
MediaLibrarySession
rozszerza interfejs API MediaSession
o interfejsy API przeglądania treści. W porównaniu z wywołaniem zwrotnym MediaSession
wywołanie zwrotne MediaLibrarySession
dodaje metody takie jak:
onGetLibraryRoot()
w przypadku, gdy klient żąda głównego elementuMediaItem
drzewa treścionGetChildren()
w przypadku, gdy klient żąda elementów podrzędnychMediaItem
w drzewie treścionGetSearchResult()
w przypadku, gdy klient zażąda wyników wyszukiwania z drzewa treści dla danego zapytania
Odpowiednie metody wywołania zwrotnego obejmują obiekt LibraryParams
z dodatkowymi sygnałami dotyczącymi typu drzewa treści, którym interesuje się aplikacja kliencka.