Jetpack Media3 ma interfejs Player
, który przedstawia podstawowe funkcje odtwarzania plików wideo i audio. ExoPlayer
jest domyślną implementacją tego interfejsu w Media3. Zalecamy korzystanie z platformy ExoPlayer, ponieważ zawiera ona kompleksowy zestaw funkcji do stosowania w większości przypadków użycia związanych z odtwarzaniem. Można go też dostosować do innych celów. ExoPlayer dodatkowo wyodrębnia fragmentację urządzenia i systemu operacyjnego, aby Twój kod działał spójnie w całym ekosystemie Androida. ExoPlayer obejmuje:
- Obsługa playlist
- Obsługa różnych formatów progresywnej i adaptacyjnej transmisji strumieniowej
- obsługa wstawienia reklam po stronie klienta i po stronie serwera;
- Obsługa odtwarzania z zabezpieczeniem DRM.
Na tej stronie opisujemy najważniejsze etapy tworzenia aplikacji do odtwarzania treści. Więcej informacji znajdziesz w pełnych przewodnikach po Media3 ExoPlayer.
Wprowadzenie
Zacznij od dodania zależności do 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 przypadku użycia możesz też potrzebować dodatkowych modułów z Media3, np. exoplayer-dash
, aby odtwarzać strumienie w formacie DASH.
Zastąp 1.3.1
preferowaną wersją biblioteki. Najnowszą wersję znajdziesz w informacjach o wersji.
Tworzenie odtwarzacza
W Media3 możesz użyć zawartej w nim implementacji interfejsu Player
(ExoPlayer
) lub utworzyć własną implementację niestandardową.
Tworzenie odtwarzacza ExoPlayer
Najprostszy sposób utworzenia instancji ExoPlayer
to:
Kotlin
val player = ExoPlayer.Builder(context).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context).build();
Odtwarzacz możesz utworzyć, korzystając z metody cyklu życia onCreate()
elementów Activity
, Fragment
lub Service
, w których się on znajduje.
Builder
zawiera różne opcje dostosowywania, które mogą Cię zainteresować, na przykład:
setAudioAttributes()
, aby skonfigurować obsługę fokusu audiosetHandleAudioBecomingNoisy()
, aby skonfigurować działanie 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 uwzględnić w pliku układu swojej aplikacji. Ten komponent zawiera obiekt PlayerControlView
do sterowania odtwarzaniem, SubtitleView
do wyświetlania napisów i Surface
do renderowania wideo.
Przygotowywanie odtwarzacza
Dodaj elementy multimedialne do playlisty, aby umożliwić ich odtwarzanie za pomocą metod takich jak setMediaItem()
i addMediaItem()
.
Następnie wywołaj prepare()
, aby rozpocząć ładowanie multimediów i pozyskać niezbędne zasoby.
Nie wykonuj tych czynności, dopóki aplikacja nie będzie działać na pierwszym planie. Jeśli odtwarzacz znajduje się w strefie Activity
lub Fragment
, oznacza to przygotowanie go do użycia metody cyklu życia onStart()
na poziomie API 24 lub wyższym albo metod cyklu życia onResume()
na poziomie API 23 i niższych. W przypadku gracza, którego pozycja obejmuje Service
,
możesz przygotować ją w aplikacji onCreate()
.
Sterowanie odtwarzaczem
Po przygotowaniu odtwarzacza możesz sterować odtwarzaniem, wywołując w nim metody, takie jak:
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
, będą się aktualizować zgodnie z oczekiwaniami po powiązaniu z odtwarzaczem.
Zwolnij odtwarzacz
Odtwarzanie może wymagać zasobów, które są ograniczone, takich jak dekodery wideo, dlatego ważne jest, aby wywołać release()
w odtwarzaczu, co pozwoli zwolnić zasoby, gdy odtwarzacz nie jest już potrzebny.
Jeśli odtwarzacz korzysta z interfejsu Activity
lub Fragment
, opublikuj go w metodzie cyklu życia onStop()
na poziomie API 24 lub wyższym albo w metodzie onPause()
na poziomie API 23 i niższych. W przypadku gracza, którego obszar obejmuje Service
, możesz zwolnić go w okresie onDestroy()
.
Zarządzanie odtwarzaniem w sesji multimediów
Na Androidzie sesje multimediów to ustandaryzowany sposób interakcji z odtwarzaczem multimediów niezależnie od granic procesów. Połączenie sesji multimedialnej z odtwarzaczem pozwala reklamować odtwarzanie multimediów na zewnątrz i odbierać polecenia odtwarzania ze źródeł zewnętrznych, na przykład dzięki integracji z systemowymi elementami sterującymi multimediami na urządzeniach mobilnych i urządzeniach z dużymi ekranami.
Aby używać sesji multimediów, dodaj zależność do modułu Media3 Session:
implementation "androidx.media3:media3-session:1.3.1"
Utwórz sesję multimediów
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
. Działa to w każdej implementacji Player
, w tym z implementacją ExoPlayer
, CastPlayer
oraz z implementacją niestandardową.
Przekazywanie kontroli innym klientom
Aplikacje klienckie mogą zaimplementować kontroler multimediów,
by sterować odtwarzaniem sesji multimediów. Aby je odbierać, ustaw obiekt wywołania zwrotnego podczas kompilowania MediaSession
.
Gdy kontroler ma się połączyć z sesją multimediów, wywoływana jest metoda onConnect()
. Możesz użyć udostępnionego ControllerInfo
, aby zdecydować, czy chcesz zaakceptować, czy odrzucić żądanie. Odpowiedni przykład znajdziesz w aplikacji demonstracyjnej Media3 Session.
Po nawiązaniu połączenia kontroler może wysyłać do sesji polecenia odtwarzania. W sesji te polecenia są przekazywane graczowi. Zdefiniowane w interfejsie Player
polecenia dotyczące odtwarzania i playlisty są obsługiwane automatycznie przez sesję.
Inne metody wywołania zwrotnego pozwalają obsługiwać np. żądania niestandardowych poleceń odtwarzania czy modyfikowanie playlisty. Te wywołania zwrotne podobnie zawierają obiekt ControllerInfo
, więc możesz określić kontrolę dostępu dla każdego żądania.
Odtwarzanie multimediów w tle
Aby odtwarzać multimedia, gdy aplikacja nie jest na pierwszym planie, np. aby odtwarzać muzykę, audiobooki lub podcasty, nawet gdy użytkownik jej nie ma, urządzenia Player
i MediaSession
powinny być zawarte w usłudze na pierwszym planie. Media3 udostępnia do tego celu interfejs MediaSessionService
.
Implementowanie: MediaSessionService
Utwórz klasę, która rozszerza zakres MediaSessionService
, i utwórz 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 klasa Service
z filtrem intencji MediaSessionService
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.MediaSessionService"/>
</intent-filter>
</service>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
Na koniec w utworzonej klasie zastąp metodę onGetSession()
, by 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 Twoim UI
Teraz gdy sesja multimediów znajduje się w strefie Service
innej niż Activity
lub Fragment
, gdzie działa interfejs odtwarzacza, możesz je połączyć za pomocą MediaController
. W metodzie onStart()
Activity
lub Fragment
w swoim interfejsie utwórz SessionToken
dla MediaSession
, a następnie użyj SessionToken
, aby utworzyć MediaController
. Tworzenie obiektu 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
, dzięki czemu możesz sterować odtwarzaniem za pomocą 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, na przykład w metodzie cyklu życia onStop()
obiektu Activity
, wywołując metodę MediaController.releaseFuture()
.
Publikowanie powiadomienia
Usługi na pierwszym planie muszą być aktywne, aby publikować powiadomienia. MediaSessionService
automatycznie utworzy dla Ciebie powiadomienie MediaStyle
w postaci MediaNotification
.
Aby udostępnić powiadomienie niestandardowe, utwórz MediaNotification.Provider
za pomocą DefaultMediaNotificationProvider.Builder
lub niestandardową implementację interfejsu dostawcy. Dodaj dostawcę do urządzenia MediaSession
za pomocą setMediaNotificationProvider
.
Reklamowanie biblioteki treści
MediaLibraryService
bazuje na MediaSessionService
, umożliwiając aplikacjom klienckim przeglądanie treści multimedialnych dostarczanych przez Twoją aplikację. Aplikacje klienckie implementują tag MediaBrowser
, który umożliwia interakcję z Twoim MediaLibraryService
.
Implementacja MediaLibraryService
jest podobna do implementowania MediaSessionService
. Jedyna różnica jest taka, że w obiekcie onGetSession()
trzeba zwracać wartość MediaLibrarySession
zamiast MediaSession
. W porównaniu z elementem MediaSession.Callback
właściwość MediaLibrarySession.Callback
zawiera dodatkowe metody, które umożliwiają klientowi przeglądarki poruszanie się po treściach oferowanych przez 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" />
Powyższy przykład zawiera filtr intencji dla elementów MediaLibraryService
oraz (na potrzeby zgodności wstecznej) starszej wersji MediaBrowserService
. Dodatkowy filtr intencji umożliwia aplikacjom klienckim korzystanie z interfejsu API MediaBrowserCompat
do rozpoznawania Twojego elementu Service
.
Element MediaLibrarySession
umożliwia udostępnianie biblioteki treści w strukturze drzewa z pojedynczym poziomem głównym MediaItem
. Każdy element MediaItem
w drzewie może mieć dowolną liczbę podrzędnych węzłów MediaItem
. Możesz udostępnić inny poziom główny lub inne drzewo w zależności od żądania aplikacji klienckiej. Na przykład drzewo zwracane klientowi szukającemu listy zalecanych elementów multimedialnych może zawierać tylko główny element MediaItem
i 1 poziom podrzędnych węzłów MediaItem
. Drzewo wyświetlane w innej aplikacji klienckiej może przedstawiać pełniejszą bibliotekę treści.
Tworzę MediaLibrarySession
MediaLibrarySession
rozszerza interfejs API MediaSession
, aby dodać interfejsy API do przeglądania treści. W porównaniu z wywołaniem zwrotnym MediaSession
wywołanie zwrotne MediaLibrarySession
dodaje metody takie jak:
onGetLibraryRoot()
, gdy klient żąda dostępu do rootaMediaItem
drzewa treścionGetChildren()
, gdy klient wysyła żądanie elementów podrzędnych obiektuMediaItem
w drzewie treścionGetSearchResult()
, gdy klient wysyła dla danego zapytania do drzewa treści żądanie wyników wyszukiwania
Odpowiednie metody wywołania zwrotnego obejmują obiekt LibraryParams
z dodatkowymi sygnałami dotyczącymi typu drzewa treści, którym interesuje się aplikacja kliencka.