Omówienie MediaPlayer

Platforma multimedialna Androida zapewnia obsługę odtwarzania różnych popularnych typów multimediów, aby łatwo zintegrować dźwięk, wideo i obrazy z aplikacjami. Możesz odtworzyć dźwięk lub wideo z plików multimedialnych przechowywanych w zasobach aplikacji (nieprzetworzone zasoby) z samodzielnych plików w systemie plików lub ze strumienia danych przychodzącego przez połączenie sieciowe – a wszystko to przy użyciu interfejsów API MediaPlayer.

Z tego dokumentu dowiesz się, jak korzystać MediaPlayer, aby zapisać informacje o odtwarzaniu multimediów współdziała z użytkownikiem i systemem w celu zapewnienia dobrej wydajności i komfort użytkowania. Możesz też spróbować używa ExoPlayer – oprogramowania open source, które możesz dostosować biblioteka obsługująca funkcje o wysokiej wydajności niedostępne w MediaPlayer

Uwaga: dane audio możesz odtworzyć tylko na standardowym wyjściem wyjściowym. urządzenia. Obecnie jest to głośnik urządzenia mobilnego lub zestaw słuchawkowy Bluetooth. Nie można odtworzyć dźwięku plików w dźwięku rozmowy podczas połączenia.

Podstawy

Do odtwarzania dźwięku i filmu w platformie Androida używane są te klasy:

MediaPlayer
Ta klasa jest podstawowym interfejsem API do odtwarzania dźwięku i wideo.
AudioManager
Te zajęcia służą do zarządzania źródłami dźwięku i wyjściem audio na urządzeniu.

Deklaracje w pliku manifestu

Zanim rozpoczniesz programowanie aplikacji przy użyciu MediaPlayer, upewnij się, że w pliku manifestu odpowiednie deklaracje umożliwiające korzystanie z powiązanych funkcji.

  • Uprawnienia internetowe – jeśli używasz odtwarzacza MediaPlayer do strumieniowego odtwarzania treści treści, aplikacja musi żądać dostępu do sieci.
    <uses-permission android:name="android.permission.INTERNET" />
    
  • Uprawnienia do blokady uśpienia – jeśli aplikacja odtwarzacza musi trzymać ekran przed przyciemnieniem lub uśpieniem procesora albo używa funkcji MediaPlayer.setScreenOnWhilePlaying() lub MediaPlayer.setWakeMode(), musisz poprosić o to uprawnienie.
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    

Korzystanie z MediaPlayer

Jednym z najważniejszych elementów struktury medialnej jest MediaPlayer zajęcia. Obiekt tej klasy może pobierać, dekodować i odtwarzać dźwięk i obraz przy minimalnej konfiguracji. Obsługuje kilka różnych źródeł mediów, takich jak:

  • Zasoby lokalne
  • wewnętrzne identyfikatory URI, np. uzyskane z programu do rozpoznawania treści.
  • Zewnętrzne adresy URL (strumieniowanie)

Lista formatów multimediów obsługiwanych przez Androida: zobacz Obsługiwane multimedia Formaty.

Oto przykład: odtwarzania dźwięku, który jest dostępny jako lokalny, nieprzetworzony zasób (zapisany w pliku res/raw/):

Kotlin

var mediaPlayer = MediaPlayer.create(context, R.raw.sound_file_1)
mediaPlayer.start() // no need to call prepare(); create() does that for you

Java

MediaPlayer mediaPlayer = MediaPlayer.create(context, R.raw.sound_file_1);
mediaPlayer.start(); // no need to call prepare(); create() does that for you

W tym przypadku plik „raw” Zasób to plik, którego system nie analizować w jakikolwiek sposób. Zawartość tego zasobu nie powinna jednak czy nieprzetworzony dźwięk. Powinien to być prawidłowo zakodowany i sformatowany plik multimedialny w jednym z obsługiwanych formatów.

Oto jak można odtworzyć z identyfikatora URI dostępnego lokalnie w systemie (np. uzyskane za pomocą programu do rozpoznawania treści):

Kotlin

val myUri: Uri = .... // initialize Uri here
val mediaPlayer = MediaPlayer().apply {
    setAudioAttributes(
        AudioAttributes.Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
            .setUsage(AudioAttributes.USAGE_MEDIA)
            .build()
    )
    setDataSource(applicationContext, myUri)
    prepare()
    start()
}

Java

Uri myUri = ....; // initialize Uri here
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioAttributes(
    new AudioAttributes.Builder()
        .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
        .setUsage(AudioAttributes.USAGE_MEDIA)
        .build()
);
mediaPlayer.setDataSource(getApplicationContext(), myUri);
mediaPlayer.prepare();
mediaPlayer.start();

Odtwarzanie ze zdalnego adresu URL w ramach strumieniowego przesyłania danych HTTP wygląda tak:

Kotlin

val url = "http://........" // your URL here
val mediaPlayer = MediaPlayer().apply {
    setAudioAttributes(
        AudioAttributes.Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
            .setUsage(AudioAttributes.USAGE_MEDIA)
            .build()
    )
    setDataSource(url)
    prepare() // might take long! (for buffering, etc)
    start()
}

Java

String url = "http://........"; // your URL here
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioAttributes(
    new AudioAttributes.Builder()
        .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
        .setUsage(AudioAttributes.USAGE_MEDIA)
        .build()
);
mediaPlayer.setDataSource(url);
mediaPlayer.prepare(); // might take long! (for buffering, etc)
mediaPlayer.start();

Uwaga: Jeśli przekazujesz adres URL do strumieniowego przesyłania pliku multimedialnego online, plik musi mieć możliwość pobieranie progresywne.

Uwaga: musisz złapać lub zdać. IllegalArgumentException i IOException, gdy używasz setDataSource(), ponieważ plik, do którego się odwołujesz, może nie istnieć.

Przygotowanie asynchroniczne

Korzystanie z usługi MediaPlayer jest proste w: tej zasady. Trzeba jednak pamiętać, że niezbędne do jego prawidłowej integracji z typową aplikacją na Androida. Dla: na przykład wywołanie prepare() może ich realizacja może zająć dużo czasu, może wymagać pobrania i dekodowania danych multimedialnych. Podobnie jak w przypadku innych firm, której wykonanie może zająć dużo czasu, nigdy nie wywoływać jej na stronie wątku UI aplikacji. Interfejs powoduje wtedy zawieszanie się interfejsu do czasu zwrócenia metody. co jest bardzo złym doświadczeniem dla użytkowników i może powodować błąd ANR (Aplikacja nie odpowiada). Nawet jeśli spodziewasz się szybkiego ładowania zasobu, pamiętaj, że wszystko, co zajmuje więcej niż 1/10 na odpowiedź interfejsu użytkownika trwa dłużej niż sekundę, co powoduje wyraźną przerwę i daje że aplikacja działa wolno.

Aby uniknąć zawieszenia wątku interfejsu użytkownika, utwórz kolejny wątek, przygotuj MediaPlayer, a gdy skończysz, powiadom wątek główny. Chociaż jednak możesz napisać logikę tworzenia wątków ten wzorzec jest tak powszechny w przypadku korzystania z interfejsu MediaPlayer, że platforma zapewnia wygodny sposób na wykonanie tego zadania przy użyciu Metoda prepareAsync(). Ta metoda rozpoczyna przygotowywanie multimediów w tle i zwraca się natychmiast. Gdy media zakończy się przygotowanie, onPrepared() metody MediaPlayer.OnPreparedListener, konfigurowanej przez Funkcja setOnPreparedListener() jest wywoływana.

Stan zarządzania

Kolejnym aspektem MediaPlayer, o którym warto pamiętać, jest: że bazuje na stanach. Oznacza to, że MediaPlayer ma stan wewnętrzny o czym należy pamiętać podczas pisania kodu, ponieważ niektóre operacje działają tylko wtedy, gdy odtwarzacz jest w określonych stanach. Jeśli wykonujesz operację w nieprawidłowy stan, system może zgłosić wyjątek lub wywołać inne niepożądane zachowania.

Dokumentacja w Klasa MediaPlayer pokazuje kompletny diagram stanu, wyjaśniające, które metody przenoszenia elementu MediaPlayer z jednego stanu do innego. Gdy na przykład tworzysz nowy element MediaPlayer, znajduje się on w stanie Nieaktywny stanu. W tym momencie należy zainicjować go, wywołując Pobieram setDataSource() do stanu Zainicjowano. Potem trzeba będzie przygotować ją za pomocą prepare() lub Metoda prepareAsync(). Kiedy Gdy MediaPlayer jest gotowy, trafia do sekcji Prepared (Przygotowane) w tym stanie, co oznacza, że możesz zadzwonić pod numer start() w celu odtwarzania multimediów. W tym momencie, jak widać na schemacie, można przełączać między stanami Rozpoczęte, Wstrzymane i Odtwarzanie ukończone. wywołujących takie metody, jak start(), pause() i seekTo(), między innymi. Gdy stop(), jednak zauważ, że nie możesz ponownie zadzwonić do użytkownika start(), dopóki nie przygotuj ponownie MediaPlayer.

Zawsze zachowuj diagram stanu. należy pamiętać przy pisaniu kodu, który wchodzi w interakcje z MediaPlayer, ponieważ wywoływanie jego metod z niewłaściwego stanu jest jest częstą przyczyną błędów.

Zwalnianie odtwarzacza MediaPlayer

MediaPlayer może zużywać cenne zasobów systemowych. Dlatego należy zawsze podjąć dodatkowe środki ostrożności, aby zapobiec i korzystanie z instancji MediaPlayer dłużej, niż jest to konieczne. Gdy po zakończeniu tego procesu, zawsze należy zadzwonić release(), aby upewnić się, że: przydzielone do niej zasoby systemowe są prawidłowo zwalniane. Jeśli na przykład jesteś za pomocą: MediaPlayer, a Twoja aktywność otrzymuje wywołanie do: onStop(), musisz zwolnić MediaPlayer, ponieważ nie ma sensu ich trzymać, gdy aktywność nie wchodzi w interakcję użytkownika (chyba że odtwarzasz multimedia w tle, co zostało omówione w następnej sekcji). Oczywiście po wznowieniu lub wznowieniu aktywności musisz: utwórz nowy plik MediaPlayer i przygotuj go ponownie, zanim wznowisz odtwarzanie.

Oto jak zwolnić, a następnie unieważnić MediaPlayer:

Kotlin

mediaPlayer?.release()
mediaPlayer = null

Java

mediaPlayer.release();
mediaPlayer = null;

Rozważmy na przykład problemy, które mogą wystąpić, jeśli zapomniano zwolnić MediaPlayer, gdy Twoja aktywność jest zatrzymana, ale utwórz nowy, gdy aktywność zacznie się od nowa. Jak być może wiesz, gdy użytkownik zmieni orientacja ekranu (lub zmiana konfiguracji urządzenia w inny sposób), system to umożliwia, ponownie uruchamiając aktywność (domyślnie), dzięki czemu możesz szybko wykorzystują wszystkie zasoby systemowe jako użytkownik obraca urządzenie do orientacji pionowej i poziomej, ponieważ zmiany orientacji ekranu, utworzysz nowy MediaPlayer, wersji. Więcej informacji o ponownym uruchamianiu środowiska wykonawczego znajdziesz w artykule Obsługa zmian środowiska wykonawczego.

Być może zastanawiasz się, co się stanie, jeśli zechcesz grać dalej. „multimedia w tle” nawet gdy użytkownik opuści Twoją aktywność, sposób działania wbudowanej aplikacji YouTube Music. W tym przypadku potrzebujesz MediaPlayer kontrolowane przez Usługę, jak zostaną omówione w następnej sekcji.

Używanie MediaPlayer w usłudze

Jeśli chcesz, aby multimedia były odtwarzane w tle, nawet gdy aplikacja nie jest na ekranie, czyli chcesz, by był on odtwarzany, interakcji z innymi aplikacjami – wtedy trzeba rozpocząć i kontrolować MediaPlayer instancję z tego miejsca. Musisz umieścić komponent MediaPlayer w usłudze MediaBrowserServiceCompat i zawierające wchodzi w interakcję z MediaBrowserCompat w innej aktywności.

Zachowaj ostrożność przy tej konfiguracji klienta/serwera. Istnieją oczekiwania jak odtwarzacz działający w usłudze działającej w tle współdziała z pozostałymi elementami systemu. Jeśli aplikacja nie spełnia tych oczekiwań, użytkownik może mają złe doświadczenia. Odczytano Tworzenie aplikacji audio .

W tej sekcji znajdziesz specjalne instrukcje dotyczące zarządzania odtwarzaczem MediaPlayer zaimplementowanym w usłudze.

Działanie asynchroniczne

Przede wszystkim, tak jak Activity, wszystkie działania Service to zadanie w jednym wątku przez domyślnie – jeśli w tej samej aplikacji uruchamiasz aktywność i usługę, domyślnie używać tego samego wątku („wątku głównego”). W związku z tym usługi muszą szybkie przetwarzanie przychodzących intencji i nigdy nie przeprowadzać długich obliczeń. Jeśli jakieś będą obfite oczekiwane są operacje wykonywania lub blokowania, należy je wykonywać asynchronicznie: kolejny wątek wdrażany samodzielnie lub z wykorzystaniem dostępnych narzędzi platformy. do asynchronicznego przetwarzania.

Na przykład gdy używasz uprawnienia MediaPlayer z wątku głównego, należy dzwonić pod numer prepareAsync(), a nie prepare() i zaimplementuj MediaPlayer.OnPreparedListener , aby otrzymać powiadomienie, gdy przygotowania się zakończą i możesz zacząć grać. Na przykład:

Kotlin

private const val ACTION_PLAY: String = "com.example.action.PLAY"

class MyService: Service(), MediaPlayer.OnPreparedListener {

    private var mMediaPlayer: MediaPlayer? = null

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        ...
        val action: String = intent.action
        when(action) {
            ACTION_PLAY -> {
                mMediaPlayer = ... // initialize it here
                mMediaPlayer?.apply {
                    setOnPreparedListener(this@MyService)
                    prepareAsync() // prepare async to not block main thread
                }

            }
        }
        ...
    }

    /** Called when MediaPlayer is ready */
    override fun onPrepared(mediaPlayer: MediaPlayer) {
        mediaPlayer.start()
    }
}

Java

public class MyService extends Service implements MediaPlayer.OnPreparedListener {
    private static final String ACTION_PLAY = "com.example.action.PLAY";
    MediaPlayer mediaPlayer = null;

    public int onStartCommand(Intent intent, int flags, int startId) {
        ...
        if (intent.getAction().equals(ACTION_PLAY)) {
            mediaPlayer = ... // initialize it here
            mediaPlayer.setOnPreparedListener(this);
            mediaPlayer.prepareAsync(); // prepare async to not block main thread
        }
    }

    /** Called when MediaPlayer is ready */
    public void onPrepared(MediaPlayer player) {
        player.start();
    }
}

Obsługa błędów asynchronicznych

W przypadku operacji synchronicznych błędy zwykle występują być sygnalizowane wyjątkiem lub kodem błędu, ale jeśli używasz asynchronicznego , upewnij się, że aplikacja została powiadomiona podejmuj odpowiednie działania. W przypadku atrybutu MediaPlayer możesz to osiągnąć, implementując tag MediaPlayer.OnErrorListener i konfigurując go w instancji MediaPlayer:

Kotlin

class MyService : Service(), MediaPlayer.OnErrorListener {

    private var mediaPlayer: MediaPlayer? = null

    fun initMediaPlayer() {
        // ...initialize the MediaPlayer here...
        mediaPlayer?.setOnErrorListener(this)
    }

    override fun onError(mp: MediaPlayer, what: Int, extra: Int): Boolean {
        // ... react appropriately ...
        // The MediaPlayer has moved to the Error state, must be reset!
    }
}

Java

public class MyService extends Service implements MediaPlayer.OnErrorListener {
    MediaPlayer mediaPlayer;

    public void initMediaPlayer() {
        // ...initialize the MediaPlayer here...
        mediaPlayer.setOnErrorListener(this);
    }

    @Override
    public boolean onError(MediaPlayer mp, int what, int extra) {
        // ... react appropriately ...
        // The MediaPlayer has moved to the Error state, must be reset!
    }
}

Pamiętaj, że gdy wystąpi błąd, MediaPlayer przechodzi do stanu Błąd (zobacz dokumentację MediaPlayer klasy dla diagramu pełnego stanu) i trzeba go zresetować, zanim będzie można go użyć.

Używanie blokad uśpienia

Podczas projektowania aplikacji, które odtwarzają multimedia w tle, urządzenie może zostać uśpione. gdy usługa jest uruchomiona. System Android stara się oszczędzać baterii, gdy urządzenie jest w trybie uśpienia, system będzie próbował wyłączyć wszystkie funkcje telefonu Nie jest to konieczne, obejmuje to procesor i sprzęt Wi-Fi. Jeśli jednak Twoja usługa odtwarza lub odtwarza muzykę, chcesz zapobiec przed zakłóceniami w odtwarzaniu.

Aby zapewnić, że Twoja usługa będzie nadal działać zgodnie z tych warunków, należy użyć funkcji „wybudzenia blokad”. Blokada uśpienia to sygnał dla system, w którym aplikacja korzysta z funkcji, która powinna pozostają dostępne nawet wtedy, gdy telefon jest nieaktywny.

Uwaga: blokad uśpienia należy zawsze stosować z umiarem i przytrzymywać je dlatego tak długo, jak to konieczne, ponieważ znacznie zmniejszają żywotność baterii urządzenia.

Aby zapewnić nieprzerwane działanie procesora, gdy MediaPlayer jest w trybie odtwarzania, przy inicjowaniu urządzenia MediaPlayer wywołaj metodę setWakeMode(). Gdy to zrobisz, podczas odtwarzania MediaPlayer trzyma podaną blokadę i zwalnia ją po wstrzymaniu lub zatrzymaniu:

Kotlin

mediaPlayer = MediaPlayer().apply {
    // ... other initialization here ...
    setWakeMode(applicationContext, PowerManager.PARTIAL_WAKE_LOCK)
}

Java

mediaPlayer = new MediaPlayer();
// ... other initialization here ...
mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);

Jednak uzyskana w tym przykładzie blokada uśpienia gwarantuje jedynie, że procesor pozostanie aktywny. Jeśli przesyłasz multimedia przez i używasz Wi-Fi, WifiLock jako który trzeba pozyskać i uwolnić ręcznie. Kiedy zaczniesz przygotowywać MediaPlayer ze zdalnym adresem URL, należy utworzyć i uzyskać blokadę sieci Wi-Fi. Na przykład:

Kotlin

val wifiManager = getSystemService(Context.WIFI_SERVICE) as WifiManager
val wifiLock: WifiManager.WifiLock =
    wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock")

wifiLock.acquire()

Java

WifiLock wifiLock = ((WifiManager) getSystemService(Context.WIFI_SERVICE))
    .createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock");

wifiLock.acquire();

Gdy wstrzymasz lub zatrzymasz odtwarzanie albo gdy nie będziesz już potrzebować sieci, zwolnij blokadę:

Kotlin

wifiLock.release()

Java

wifiLock.release();

Trwa czyszczenie

Jak wspomnieliśmy wcześniej, obiekt MediaPlayer może wykorzystywać znaczną zasobów systemowych. Należy więc przechowywać go tylko tak długo, jak to potrzebne, release(). To ważne jawnego wywoływania tej metody czyszczenia, zamiast polegać na funkcji czyszczenia pamięci systemu, ponieważ odzyskanie pamięci MediaPlayer przez śmieciar może trochę potrwać, ponieważ uwzględnia jedynie potrzeby związane z pamięcią i nie brakuje innych zasobów związanych z multimediami. W przypadku korzystania z usługi należy zawsze zastąpić parametr Metoda onDestroy(), która pozwala upewnić się, że publikujesz MediaPlayer:

Kotlin

class MyService : Service() {

    private var mediaPlayer: MediaPlayer? = null
    // ...

    override fun onDestroy() {
        super.onDestroy()
        mediaPlayer?.release()
    }
}

Java

public class MyService extends Service {
   MediaPlayer mediaPlayer;
   // ...

   @Override
   public void onDestroy() {
       super.onDestroy();
       if (mediaPlayer != null) mediaPlayer.release();
   }
}

Zawsze należy szukać innych możliwości udostępnienia MediaPlayer a także nie zwalniać go z możliwością zamknięcia. Jeśli na przykład spodziewasz się, że nie na odtwarzanie multimediów przez dłuższy czas (np. po utracie ostrości audio), zdecydowanie należy zwolnić istniejący MediaPlayer i utworzyć go ponownie później. Dzień Jeśli spodziewasz się zatrzymania odtwarzania tylko na bardzo krótki czas, prawdopodobnie MediaPlayer, aby uniknąć problemów z tworzeniem i przygotowywaniem ponownie.

Zarządzanie prawami cyfrowymi (DRM)

Począwszy od Androida 8.0 (poziom interfejsu API 26) MediaPlayer zawiera interfejsy API, które umożliwiają odtwarzanie materiałów chronionych DRM. Są podobne do niskopoziomowego interfejsu API udostępnianego przez MediaDrm, ale działają one na wyższym poziomie i nie i udostępnić bazowy mechanizm wyodrębniania, drm i obiekty kryptograficzne.

Chociaż interfejs MediaPlayer DRM API nie zapewnia pełnej funkcjonalności MediaDrm, obsługuje większość typowych przypadków użycia. Obecna implementacja obsługuje te typy treści:

  • Lokalne pliki multimedialne chronione przez Widevine
  • Zdalne/strumieniowe pliki multimedialne chronione przez Widevine

Ten fragment kodu pokazuje, jak korzystać z nowego odtwarzacza MediaPlayer DRM w prostej implementacji synchronicznej.

Aby zarządzać multimediami kontrolowanymi przez DRM, musisz dodać nowe metody do pliku normalny przebieg wywołań MediaPlayer, jak pokazano poniżej:

Kotlin

mediaPlayer?.apply {
    setDataSource()
    setOnDrmConfigHelper() // optional, for custom configuration
    prepare()
    drmInfo?.also {
        prepareDrm()
        getKeyRequest()
        provideKeyResponse()
    }

    // MediaPlayer is now ready to use
    start()
    // ...play/pause/resume...
    stop()
    releaseDrm()
}

Java

setDataSource();
setOnDrmConfigHelper(); // optional, for custom configuration
prepare();
if (getDrmInfo() != null) {
  prepareDrm();
  getKeyRequest();
  provideKeyResponse();
}

// MediaPlayer is now ready to use
start();
// ...play/pause/resume...
stop();
releaseDrm();

Zacznij od zainicjowania obiektu i ustawienia MediaPlayer jego źródło za pomocą funkcji setDataSource(), jak zwykle. Następnie, aby użyć DRM, wykonaj te czynności:

  1. Jeśli chcesz, aby aplikacja przeprowadzała konfigurację niestandardową, zdefiniuj OnDrmConfigHelper i dołącz go do gracz korzystający z setOnDrmConfigHelper()
  2. Będziesz dzwonić pod numer prepare().
  3. Będziesz dzwonić pod numer getDrmInfo(). Jeśli źródło ma DRM content, metoda zwraca wartość inną niż null Wartość: MediaPlayer.DrmInfo.

Jeśli MediaPlayer.DrmInfo istnieje:

  1. Przeanalizuj mapę dostępnych identyfikatorów UUID i wybierz jeden z nich.
  2. Przygotuj konfigurację DRM dla bieżącego źródła, wywołując funkcję prepareDrm().
    • Jeśli masz utworzoną i zarejestrowaną Wywołanie zwrotne OnDrmConfigHelper, nosi nazwę podczas gdy prepareDrm() . Pozwala to na przeprowadzenie niestandardowej konfiguracji DRM przed otwarciem sesji DRM. Wywołanie zwrotne synchronicznie w wątku o nazwie prepareDrm() Do dostępu do właściwości DRM, wywołaj getDrmPropertyString() i setDrmPropertyString() Unikaj wykonywania długich operacji.
    • Jeśli urządzenie nie zostało jeszcze obsłużone, prepareDrm() również uzyskuje dostęp do serwera obsługi administracyjnej w celu obsługi administracyjnej urządzenia. Może to potrwać zmienną ilość czasu w zależności od połączenia sieciowego.
  3. Aby wysłać tablicę bajtową żądania nieprzejrzystego klucza do serwera licencji, wywołaj getKeyRequest()
  4. Aby poinformować mechanizm DRM o odpowiedzi klucza otrzymanej z serwera licencji, wywołaj provideKeyResponse() Wynik zależy od typu żądania klucza:
    • Jeśli odpowiedź jest żądaniem klucza offline, wynikiem jest identyfikator zestawu kluczy. Za pomocą ten identyfikator zestawu kluczy za pomocą funkcji restoreKeys() w celu przywrócenia kluczy do nowego .
    • Jeśli odpowiedź dotyczy żądania strumieniowego lub zwolnienia, wynik ma wartość null.

Asynchroniczne uruchamianie prepareDrm()

Domyślnie prepareDrm() działa synchronicznie i blokuje do momentu zakończenia przygotowań. Jednakże pierwsze przygotowanie systemu DRM na nowym urządzeniu może też wymagać obsługi administracyjnej, obsługiwane wewnętrznie przez prepareDrm() i może zająć trochę czasu ze względu na operacje sieciowe. Dostępne opcje unikaj blokowania na prepareDrm(), autor: określić i skonfigurować MediaPlayer.OnDrmPreparedListener.

Gdy ustawisz OnDrmPreparedListener, prepareDrm() przeprowadza obsługę administracyjną (w razie potrzeby) i przygotowanie w tle. Kiedy gdy zakończy się udostępnianie i przygotowanie, detektor jest wywoływany. Zalecenia nie należy przyjmować żadnych założeń na temat sekwencji wywoływania ani wątku, w którym działa (chyba że jest zarejestrowany w wątku modułu obsługi). Detektor można wywołać przed lub po prepareDrm() „powrót karetki”.

Asynchroniczne konfigurowanie DRM

DRM można zainicjować asynchronicznie, tworząc i rejestrując MediaPlayer.OnDrmInfoListener na potrzeby przygotowania do zabezpieczeń DRM oraz MediaPlayer.OnDrmPreparedListener, aby uruchomić odtwarzacz. Współpracują one z prepareAsync(), jak pokazano poniżej:

Kotlin

setOnPreparedListener()
setOnDrmInfoListener()
setDataSource()
prepareAsync()
// ...

// If the data source content is protected you receive a call to the onDrmInfo() callback.
override fun onDrmInfo(mediaPlayer: MediaPlayer, drmInfo: MediaPlayer.DrmInfo) {
    mediaPlayer.apply {
        prepareDrm()
        getKeyRequest()
        provideKeyResponse()
    }
}

// When prepareAsync() finishes, you receive a call to the onPrepared() callback.
// If there is a DRM, onDrmInfo() sets it up before executing this callback,
// so you can start the player.
override fun onPrepared(mediaPlayer: MediaPlayer) {
    mediaPlayer.start()
}

Java

setOnPreparedListener();
setOnDrmInfoListener();
setDataSource();
prepareAsync();
// ...

// If the data source content is protected you receive a call to the onDrmInfo() callback.
onDrmInfo() {
  prepareDrm();
  getKeyRequest();
  provideKeyResponse();
}

// When prepareAsync() finishes, you receive a call to the onPrepared() callback.
// If there is a DRM, onDrmInfo() sets it up before executing this callback,
// so you can start the player.
onPrepared() {

start();
}

Obsługa zaszyfrowanych multimediów

Począwszy od Androida 8.0 (poziom interfejsu API 26) MediaPlayer może też odszyfrowywać System CENC (Common Encryption Scheme) Multimedia zaszyfrowane na poziomie próbki HLS (METHOD=SAMPLE-AES) na potrzeby typów strumieni podstawowych H.264 i AAC. Wcześniej obsługiwane były pliki multimedialne szyfrowane w pełnym segmencie (metoda=AES-128).

Pobieranie multimediów z narzędzia Content resolver

Inną funkcją, która może być przydatna w odtwarzaczu multimediów, jest możliwość pobiera muzykę zapisaną na urządzeniu. Możesz to zrobić, wysyłając zapytanie do ContentResolver o media zewnętrzne:

Kotlin

val resolver: ContentResolver = contentResolver
val uri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
val cursor: Cursor? = resolver.query(uri, null, null, null, null)
when {
    cursor == null -> {
        // query failed, handle error.
    }
    !cursor.moveToFirst() -> {
        // no media on the device
    }
    else -> {
        val titleColumn: Int = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media.TITLE)
        val idColumn: Int = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media._ID)
        do {
            val thisId = cursor.getLong(idColumn)
            val thisTitle = cursor.getString(titleColumn)
            // ...process entry...
        } while (cursor.moveToNext())
    }
}
cursor?.close()

Java

ContentResolver contentResolver = getContentResolver();
Uri uri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
Cursor cursor = contentResolver.query(uri, null, null, null, null);
if (cursor == null) {
    // query failed, handle error.
} else if (!cursor.moveToFirst()) {
    // no media on the device
} else {
    int titleColumn = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media.TITLE);
    int idColumn = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media._ID);
    do {
       long thisId = cursor.getLong(idColumn);
       String thisTitle = cursor.getString(titleColumn);
       // ...process entry...
    } while (cursor.moveToNext());
}

Aby używać tej funkcji z MediaPlayer, możesz to zrobić:

Kotlin

val id: Long = /* retrieve it from somewhere */
val contentUri: Uri =
    ContentUris.withAppendedId(android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id )

mediaPlayer = MediaPlayer().apply {
    setAudioAttributes(
        AudioAttributes.Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
            .setUsage(AudioAttributes.USAGE_MEDIA)
            .build()
    )
    setDataSource(applicationContext, contentUri)
}

// ...prepare and start...

Java

long id = /* retrieve it from somewhere */;
Uri contentUri = ContentUris.withAppendedId(
        android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id);

mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioAttributes(
    new AudioAttributes.Builder()
        .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
        .setUsage(AudioAttributes.USAGE_MEDIA)
        .build()
);
mediaPlayer.setDataSource(getApplicationContext(), contentUri);

// ...prepare and start...

Więcej informacji

Te strony zawierają omówienie tematów związanych z nagrywaniem, przechowywaniem i odtwarzaniem dźwięku i wideo.