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 ExoPlayer, ponieważ zapewnia on kompleksowy zestaw funkcji, które obejmują większość przypadków użycia odtwarzania, i można go dostosować do obsługi dodatkowych przypadków użycia. ExoPlayer abstrahuje też od fragmentacji urządzeń i systemów operacyjnych, dzięki czemu Twój kod działa spójnie w całym ekosystemie Androida. ExoPlayer obejmuje:
- obsługę playlist;
- obsługę różnych formatów progresywnego i adaptacyjnego przesyłania strumieniowego formatów
- obsługę wstawiania reklam po stronie klienta i po stronie serwera; wstawiania reklam
- obsługę odtwarzania treści chronionych przez DRM.
Na tej stronie znajdziesz opis najważniejszych kroków związanych z tworzeniem 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.10.0" implementation "androidx.media3:media3-ui:1.10.0" implementation "androidx.media3:media3-common:1.10.0"
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.
Pamiętaj, aby zastąpić 1.10.0 preferowaną wersją biblioteki. Najnowszą wersję znajdziesz w informacjach o wersji.
Tworzenie odtwarzacza multimediów
W Media3 możesz użyć dołączonej implementacji Player
interfejsu, ExoPlayer, lub utworzyć własną implementację niestandardową.
Tworzenie ExoPlayer
Najprostszy sposób na utworzenie instancji ExoPlayer jest taki:
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 Activity, Fragment lub Service, w której się znajduje.
Builder zawiera
szereg opcji dostosowywania, które mogą Cię zainteresować, np.:
setAudioAttributes()do konfigurowania obsługi aktywności audiosetHandleAudioBecomingNoisy()do konfigurowania zachowania odtwarzania po odłączeniu urządzenia wyjściowego audio;setTrackSelector()do konfigurowania wyboru ścieżki
Media3 udostępnia komponent interfejsu 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 wideo.
Przygotowywanie odtwarzacza
Dodaj elementy multimedialne do playlisty, aby je
odtworzyć, za pomocą metod takich jak
setMediaItem()
i addMediaItem().
Następnie wywołaj prepare(), aby
rozpocząć wczytywanie multimediów i uzyskać niezbędne zasoby.
Nie należy wykonywać tych czynności, zanim aplikacja nie znajdzie się na pierwszym planie. Jeśli odtwarzacz znajduje się w Activity lub Fragment, oznacza to, że należy go przygotować w metodzie cyklu życia onStart() na poziomie interfejsu API 24 lub wyższym albo w metodzie cyklu życia onResume() na poziomie interfejsu API 23 lub niższym. W przypadku odtwarzacza, który znajduje się w Service, możesz go przygotować w onCreate(). Przykład implementacji metod cyklu życia znajdziesz w ćwiczeniach z programowania dotyczących ExoPlayer (zobacz
ExoPlayer codelab).
Sterowanie odtwarzaczem
Po przygotowaniu odtwarzacza możesz sterować odtwarzaniem, wywołując metody odtwarzacza, takie jak:
play()ipause()do rozpoczynania i wstrzymywania odtwarzaniaseekTo()do przewijania do pozycji w bieżącym elemencie multimedialnym;seekToNextMediaItem()iseekToPreviousMediaItem()do poruszania się po playliście.
Komponenty interfejsu, takie jak PlayerView lub PlayerControlView, zostaną odpowiednio zaktualizowane po powiązaniu z odtwarzaczem.
Zwalnianie odtwarzacza
Odtwarzanie może wymagać zasobów, które są ograniczone, np. dekoderów 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 Activity lub Fragment, zwolnij go w metodzie cyklu życia onStop() na poziomie interfejsu API 24 lub wyższym albo w metodzie onPause() na poziomie interfejsu API 23 lub niższym. W przypadku odtwarzacza, który znajduje się w Service, możesz go zwolnić w onDestroy(). Przykład implementacji metod cyklu życia znajdziesz w ćwiczeniach z programowania dotyczących ExoPlayer (zobacz
ExoPlayer codelab).
Zarządzanie odtwarzaniem za pomocą sesji multimedialnej
W Androidzie sesje multimedialne zapewniają standardowy sposób interakcji z odtwarzaczem multimediów w różnych procesach. Połączenie sesji multimedialnej z odtwarzaczem umożliwia przekazywanie informacji o odtwarzaniu multimediów źródłom zewnętrznym i otrzymywanie poleceń odtwarzania ze źródeł zewnętrznych, np. w celu integracji z systemowymi opcjami sterowania multimediami na urządzeniach mobilnych i urządzeniach z dużym ekranem.
Aby korzystać z sesji multimedialnych, dodaj zależność od modułu Media3 Session:
implementation "androidx.media3:media3-session:1.10.0"
Tworzenie sesji multimedialnej
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 Player ze stanem MediaSession. Działa to z każdą Player implementacją, w tym
ExoPlayer, CastPlayer i
implementacją niestandardową.
Przyznawanie kontroli innym klientom
Aplikacje klienckie mogą implementować kontroler multimediów
aby sterować odtwarzaniem sesji multimedialnej. Aby otrzymywać te żądania, ustaw a
wywołania zwrotnego obiekt podczas
tworzenia MediaSession.
Gdy kontroler ma się połączyć z sesją multimedialną, wywoływana jest metoda
onConnect(). Na podstawie podanego obiektu ControllerInfo
możesz zdecydować, czy zaakceptować
czy odrzucić
prośbę. Przykład znajdziesz w aplikacji w wersji demonstracyjnej sesji Media3.
Po nawiązaniu połączenia kontroler może wysyłać do sesji polecenia odtwarzania. Sesja przekazuje te polecenia do odtwarzacza. Polecenia odtwarzania i playlisty zdefiniowane w interfejsie Player są automatycznie obsługiwane przez sesję.
Inne metody wywołania zwrotnego umożliwiają obsługę np. żądań
niestandardowych poleceń odtwarzania
i modyfikowania playlisty. Te wywołania zwrotne również zawierają obiekt ControllerInfo, dzięki czemu możesz określać kontrolę dostępu na podstawie poszczególnych żądań.
Odtwarzanie multimediów w tle
Aby kontynuować odtwarzanie multimediów, gdy aplikacja nie jest na pierwszym planie (np.
odtwarzać muzykę, audiobooki lub podcasty, nawet gdy użytkownik nie ma otwartej aplikacji
), Player i MediaSession powinny być zamknięte w
usłudze na pierwszym planie. W tym celu Media3 udostępnia interfejs MediaSessionService.
Implementowanie MediaSessionService
Utwórz klasę, która rozszerza 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 dodaj klasę 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(), aby kontrolować dostęp klienta do sesji multimedialnej. Aby zaakceptować prośbę o połączenie, zwróć MediaSession, a aby ją odrzucić, zwróć null.
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
Teraz, gdy sesja multimedialna znajduje się w Service oddzielnej od Activity lub Fragment, w której znajduje się interfejs odtwarzacza, możesz użyć MediaController, aby je połączyć. W metodzie onStart() w Activity lub Fragment z interfejsem utwórz SessionToken dla MediaSession, a następnie użyj SessionToken, aby utworzyć 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 implementuje interfejs Player, więc możesz używać tych samych metod, takich jak play() i pause(), do sterowania odtwarzaniem. Podobnie jak w przypadku innych
komponentów, pamiętaj, aby zwolnić MediaController, gdy nie jest już
potrzebny, np. w metodzie cyklu życia onStop() w Activity, wywołując
MediaController.releaseFuture().
Publikowanie powiadomienia
Usługi na pierwszym planie muszą publikować powiadomienie, gdy są aktywne. A
MediaSessionService automatycznie utworzy powiadomienie dla
Ciebie w postaci MediaNotification.MediaStyle
Aby udostępnić powiadomienie niestandardowe, utwórz a
MediaNotification.Provider
za pomocą DefaultMediaNotificationProvider.Builder
lub tworząc niestandardową implementację interfejsu dostawcy. Dodaj dostawcę do MediaSession za pomocą
setMediaNotificationProvider.
Reklamowanie biblioteki treści
A MediaLibraryService opiera się na MediaSessionService, umożliwiając aplikacjom klienckim przeglądanie treści multimedialnych udostępnianych przez Twoją aplikację. Aplikacje klienckie implementują MediaBrowser, aby wchodzić w interakcje z MediaLibraryService.
Implementowanie MediaLibraryService jest podobne do implementowania
MediaSessionService, z tym wyjątkiem, że w onGetSession() należy zwrócić
MediaLibrarySession zamiast MediaSession. W porównaniu z MediaSession.Callback, 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ę działającą 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 MediaLibraryService, jak i dla starszej wersji MediaBrowserService w celu zapewnienia zgodności wstecznej. Dodatkowy filtr intencji umożliwia aplikacjom klienckim korzystającym z interfejsu API MediaBrowserCompat rozpoznawanie Twojej Service.
MediaLibrarySession umożliwia udostępnianie biblioteki treści w strukturze drzewa z jednym głównym MediaItem. Każdy MediaItem w drzewie może mieć dowolną liczbę podrzędnych węzłów MediaItem. Możesz udostępniać inny katalog główny lub inne drzewo w zależności od żądania aplikacji klienckiej. Na przykład drzewo, które zwracasz klientowi szukającemu listy polecanych elementów multimedialnych, może zawierać tylko główny MediaItem i jeden poziom podrzędnych węzłów MediaItem, natomiast drzewo, które zwracasz innej aplikacji klienckiej, może reprezentować pełniejszą bibliotekę treści.
Tworzenie MediaLibrarySession
MediaLibrarySession
rozszerza interfejs API MediaSession, dodając interfejsy API do 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 prosi o głównyMediaItemdrzewa treści;onGetChildren()w przypadku, gdy klient prosi o elementy podrzędneMediaItemw drzewie treści;onGetSearchResult()w przypadku, gdy klient prosi o wyniki wyszukiwania w drzewie treści dla danego zapytania.
Odpowiednie metody wywołania zwrotnego będą zawierać obiekt LibraryParams
z dodatkowymi sygnałami dotyczącymi typu drzewa treści, które interesuje aplikację kliencką.