MediaPlayer – Übersicht

Das Multimedia-Framework von Android unterstützt die Wiedergabe einer Vielzahl gängiger Medientypen, sodass Sie Audio, Video und Bilder einfach in Ihre Anwendungen einbinden können. Sie können mit MediaPlayer APIs Audio- oder Videoinhalte von Mediendateien wiedergeben, die in den Ressourcen Ihrer Anwendung (Rohressourcen), eigenständigen Dateien im Dateisystem oder aus einem Datenstream, der über eine Netzwerkverbindung eingeht, gespeichert sind.

In diesem Dokument erfahren Sie, wie Sie mit MediaPlayer eine Medienanwendung schreiben, die mit dem Nutzer und dem System interagiert, um eine gute Leistung und eine angenehme Nutzererfahrung zu erzielen. Alternativ können Sie auch ExoPlayer verwenden. Dies ist eine anpassbare Open-Source-Bibliothek, die leistungsstarke Features unterstützt, die in MediaPlayer nicht verfügbar sind.

Hinweis:Sie können die Audiodaten nur auf dem Standardausgabegerät wiedergeben. Im Moment ist dies der Lautsprecher des Mobilgeräts oder ein Bluetooth-Headset. Sie können während eines Anrufs keine Audiodateien in der Audiodatei abspielen.

Grundlagen

Die folgenden Klassen werden zur Wiedergabe von Ton und Videos im Android-Framework verwendet:

MediaPlayer
Diese Klasse ist die primäre API für die Wiedergabe von Ton und Videos.
AudioManager
Diese Klasse verwaltet Audioquellen und die Audioausgabe auf einem Gerät.

Manifestdeklarationen

Bevor du mit der Entwicklung deiner App mit MediaPlayer beginnst, muss dein Manifest die entsprechenden Deklarationen enthalten, die die Verwendung verwandter Funktionen zulassen.

  • Internetberechtigung: Wenn Sie MediaPlayer zum Streamen von netzwerkbasierten Inhalten verwenden, muss Ihre Anwendung Netzwerkzugriff anfordern.
    <uses-permission android:name="android.permission.INTERNET" />
    
  • Wakelock-Berechtigung: Wenn deine Player-App das Dimmen des Bildschirms verhindern oder den Prozessor aus dem Ruhemodus ausschließen muss oder die Methoden MediaPlayer.setScreenOnWhilePlaying() oder MediaPlayer.setWakeMode() verwendet, musst du diese Berechtigung anfordern.
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    

MediaPlayer verwenden

Eine der wichtigsten Komponenten des Medien-Frameworks ist die Klasse MediaPlayer. Ein Objekt dieser Klasse kann mit minimalem Einrichtungsaufwand sowohl Audio- als auch Videoinhalte abrufen, decodieren und wiedergeben. Verschiedene Medienquellen werden unterstützt, z. B.:

  • Lokale Ressourcen
  • Interne URIs, z. B. von einem Content-Resolver
  • Externe URLs (Streaming)

Eine Liste der von Android unterstützten Medienformate findest du auf der Seite Unterstützte Medienformate.

Hier ist ein Beispiel für die Wiedergabe von Audioinhalten, die als lokale Rohressource verfügbar sind und im Verzeichnis res/raw/ Ihrer Anwendung gespeichert sind:

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

In diesem Fall ist eine „Rohressource“ eine Datei, die das System auf keine bestimmte Weise zu parsen versucht. Der Inhalt dieser Ressource sollte jedoch keine Rohaudioinhalte sein. Es sollte eine korrekt codierte und formatierte Mediendatei in einem der unterstützten Formate sein.

Und hier sehen Sie eine Wiedergabe von einem URI, der lokal im System verfügbar ist und den Sie beispielsweise über einen Content-Resolver erhalten haben:

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();

Die Wiedergabe von einer Remote-URL über HTTP-Streaming sieht so aus:

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();

Hinweis:Wenn Sie eine URL zum Streamen einer Online-Mediendatei übergeben, muss die Datei progressiv heruntergeladen werden können.

Achtung:Sie müssen IllegalArgumentException und IOException entweder abfangen oder übergeben, wenn Sie setDataSource() verwenden, da die Datei, auf die Sie verweisen, möglicherweise nicht vorhanden ist.

Asynchrone Vorbereitung

Die Verwendung von MediaPlayer kann im Prinzip einfach sein. Es sind jedoch noch einige weitere Dinge erforderlich, um den Browser korrekt in eine typische Android-App einzubinden. Der Aufruf von prepare() kann beispielsweise lange dauern, da Mediendaten abgerufen und decodiert werden können. Wie bei allen Methoden, deren Ausführung möglicherweise lange dauert, sollten Sie sie niemals aus dem UI-Thread Ihrer Anwendung aufrufen. Dadurch bleibt die Benutzeroberfläche hängen, bis die Methode zurückgegeben wird. Dies ist für Nutzer sehr schlecht und kann einen ANR-Fehler („Application Not Replying“) verursachen. Auch wenn Sie davon ausgehen, dass Ihre Ressource schnell geladen wird, denken Sie daran, dass alles, was mehr als eine Zehntelsekunde zum Antworten in der Benutzeroberfläche benötigt, eine deutliche Pause auslöst und dem Nutzer den Eindruck vermittelt, dass Ihre Anwendung langsam ist.

Damit der UI-Thread nicht hängen bleibt, erstellen Sie einen weiteren Thread, um den MediaPlayer vorzubereiten, und benachrichtigen Sie den Hauptthread, wenn er abgeschlossen ist. Sie können die Threading-Logik zwar selbst schreiben, dieses Muster ist jedoch bei der Verwendung von MediaPlayer so üblich, dass das Framework eine bequeme Möglichkeit bietet, diese Aufgabe mithilfe der Methode prepareAsync() auszuführen. Diese Methode beginnt mit der Vorbereitung der Medien im Hintergrund und kehrt sofort zurück. Wenn die Vorbereitung der Medien abgeschlossen ist, wird die Methode onPrepared() der MediaPlayer.OnPreparedListener aufgerufen, die über setOnPreparedListener() konfiguriert wurde.

Verwaltungsstatus

Ein weiterer Aspekt einer MediaPlayer, den Sie beachten sollten, ist, dass er zustandsbasiert ist. Das MediaPlayer hat also einen internen Status, den du beim Schreiben deines Codes immer beachten musst, da bestimmte Vorgänge nur gültig sind, wenn sich der Player in bestimmten Zuständen befindet. Wenn Sie einen Vorgang im falschen Status ausführen, kann das System eine Ausnahme auslösen oder andere unerwünschte Verhaltensweisen verursachen.

Die Dokumentation in der MediaPlayer-Klasse zeigt ein vollständiges Zustandsdiagramm, das verdeutlicht, welche Methoden das MediaPlayer von einem Status in einen anderen verschieben. Wenn Sie beispielsweise einen neuen MediaPlayer erstellen, befindet er sich im Status Inaktiv. An diesem Punkt sollten Sie es initialisieren, indem Sie setDataSource() aufrufen und den Status Initialized versetzen. Anschließend müssen Sie ihn mit der Methode prepare() oder prepareAsync() vorbereiten. Wenn die Vorbereitung von MediaPlayer abgeschlossen ist, wird der Status Prepared (Bereitgestellt). Das bedeutet, dass Sie start() aufrufen können, damit die Medien abgespielt werden. Wie das Diagramm zeigt, kannst du an dieser Stelle zwischen den Status Gestartet, Pausiert und WiedergabeAbgeschlossen wechseln, indem du Methoden wie start(), pause() und seekTo() aufrufst. Wenn Sie stop() aufrufen, müssen Sie start() erst noch einmal aufrufen, wenn Sie MediaPlayer noch einmal vorbereitet haben.

Beachten Sie beim Schreiben von Code, der mit einem MediaPlayer-Objekt interagiert, immer das Zustandsdiagramm, da der Aufruf seiner Methoden aus dem falschen Zustand eine häufige Ursache für Programmfehler ist.

MediaPlayer freigeben

Ein MediaPlayer kann wertvolle Systemressourcen verbrauchen. Ergreifen Sie daher immer zusätzliche Vorsichtsmaßnahmen, damit Sie sich bei einer MediaPlayer-Instanz nicht länger als nötig befinden. Wenn Sie damit fertig sind, sollten Sie immer release() aufrufen, damit alle ihm zugewiesenen Systemressourcen ordnungsgemäß freigegeben werden. Wenn Sie beispielsweise ein MediaPlayer verwenden und Ihre Aktivität einen Aufruf an onStop() empfängt, müssen Sie MediaPlayer freigeben. Es ist nämlich nicht sinnvoll, sie festzuhalten, wenn Ihre Aktivität nicht mit dem Nutzer interagiert (es sei denn, Sie spielen Medien im Hintergrund ab, wie im nächsten Abschnitt beschrieben). Wenn deine Aktivität fortgesetzt oder neu gestartet wird, musst du natürlich einen neuen MediaPlayer erstellen und diesen noch einmal vorbereiten, bevor du die Wiedergabe fortsetzen kannst.

So sollten Sie MediaPlayer freigeben und dann auf null setzen:

Kotlin

mediaPlayer?.release()
mediaPlayer = null

Java

mediaPlayer.release();
mediaPlayer = null;

Betrachten Sie als Beispiel die Probleme, die auftreten können, wenn Sie vergessen haben, das MediaPlayer beim Beenden Ihrer Aktivität freizugeben, aber ein neues zu erstellen, wenn die Aktivität wieder beginnt. Wenn der Nutzer die Bildschirmausrichtung ändert oder die Gerätekonfiguration auf andere Weise ändert, wird die Aktivität vom System automatisch neu gestartet (standardmäßig). Es kann also sein, dass schnell alle Systemressourcen verbraucht werden, während der Nutzer das Gerät zwischen Hoch- und Querformat hin- und her dreht, da du bei jeder Änderung der Ausrichtung eine neue MediaPlayer erstellst, die du nie freigibst. Weitere Informationen zu Laufzeitneustarts finden Sie unter Laufzeitänderungen verarbeiten.

Sie fragen sich vielleicht, was passiert, wenn Sie „Hintergrundmedien“ auch dann weiter abspielen möchten, wenn der Nutzer Ihre Aktivität verlässt, und zwar ähnlich wie die integrierte Musikanwendung. In diesem Fall benötigen Sie einen MediaPlayer, der von einem Dienst gesteuert wird, wie im nächsten Abschnitt erläutert.

MediaPlayer in einem Dienst verwenden

Wenn Sie möchten, dass Ihre Medien auch dann im Hintergrund wiedergegeben werden, wenn Ihre Anwendung nicht auf dem Bildschirm zu sehen ist, also weiter abgespielt werden soll, während der Nutzer mit anderen Anwendungen interagiert, müssen Sie einen Dienst starten und von dort die Instanz MediaPlayer steuern. Sie müssen den MediaPlayer in einen MediaBrowserServiceCompat-Dienst einbetten und in einer anderen Aktivität mit einem MediaBrowserCompat interagieren lassen.

Sie sollten bei dieser Client-/Serverkonfiguration vorsichtig sein. Es wird erwartet, wie ein im Hintergrund ausgeführter Player mit dem Rest des Systems interagiert. Wenn Ihre Anwendung diese Erwartungen nicht erfüllt, kann das die Nutzerfreundlichkeit beeinträchtigen. Ausführliche Informationen finden Sie unter Audio-App erstellen.

In diesem Abschnitt werden spezielle Anweisungen zum Verwalten eines MediaPlayers beschrieben, wenn er in einem Dienst implementiert wird.

Asynchron ausführen

Erstens wird wie bei einem Activity standardmäßig alles in einem Service in einem einzelnen Thread ausgeführt. Wenn Sie eine Aktivität und einen Dienst aus derselben Anwendung ausführen, verwenden sie standardmäßig denselben Thread (den „Hauptthread“). Daher müssen Dienste eingehende Intents schnell verarbeiten und nie langwierige Berechnungen als Antworten darauf ausführen. Wenn harte Arbeit oder blockierende Aufrufe erwartet werden, müssen Sie diese Aufgaben asynchron ausführen: entweder aus einem anderen Thread, den Sie selbst implementieren, oder unter Verwendung der vielen Funktionen des Frameworks für die asynchrone Verarbeitung.

Wenn Sie beispielsweise einen MediaPlayer aus Ihrem Hauptthread verwenden, sollten Sie prepareAsync() statt prepare() aufrufen und einen MediaPlayer.OnPreparedListener implementieren, damit Sie benachrichtigt werden, wenn die Vorbereitung abgeschlossen ist und Sie mit dem Spielen beginnen können. Beispiele:

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();
    }
}

Umgang mit asynchronen Fehlern

Bei synchronen Vorgängen würden Fehler normalerweise mit einer Ausnahme oder einem Fehlercode signalisiert werden. Wenn Sie jedoch asynchrone Ressourcen verwenden, sollten Sie Ihre Anwendung entsprechend benachrichtigen. Im Fall eines MediaPlayer können Sie dies erreichen, indem Sie einen MediaPlayer.OnErrorListener implementieren und in der MediaPlayer-Instanz festlegen:

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!
    }
}

Beim Auftreten eines Fehlers wird der MediaPlayer in den Status Error (Fehler) versetzt. Das vollständige Zustandsdiagramm finden Sie in der Dokumentation zur Klasse MediaPlayer. Sie müssen ihn dann zurücksetzen, bevor Sie ihn wieder verwenden können.

Wakelocks verwenden

Bei der Entwicklung von Anwendungen, die Medien im Hintergrund abspielen, kann das Gerät in den Ruhemodus wechseln, während Ihr Dienst ausgeführt wird. Da das Android-System versucht, den Akku zu schonen, während sich das Gerät im Ruhezustand befindet, versucht das System, alle nicht erforderlichen Funktionen des Smartphones zu deaktivieren, einschließlich CPU und WLAN-Hardware. Wenn Ihr Dienst jedoch Musik wiedergibt oder streamt, möchten Sie verhindern, dass das System die Wiedergabe stört.

Damit Ihr Dienst unter diesen Bedingungen weiter ausgeführt wird, müssen Sie „Wakelocks“ verwenden. Ein Wakelock ist eine Möglichkeit, dem System zu signalisieren, dass Ihre App eine Funktion verwendet, die verfügbar bleiben sollte, auch wenn das Smartphone inaktiv ist.

Hinweis: Du solltest Wakelocks immer sparsam verwenden und nur so lange wie nötig verwenden, da sie die Akkulaufzeit des Geräts deutlich verkürzen.

Damit die CPU weiterhin ausgeführt wird, während MediaPlayer ausgeführt wird, rufen Sie beim Initialisieren von MediaPlayer die Methode setWakeMode() auf. Anschließend behält MediaPlayer die angegebene Sperre während der Wiedergabe und hebt die Sperre auf, wenn sie pausiert oder angehalten wird:

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);

Der in diesem Beispiel erworbene Wakelock sorgt jedoch nur dafür, dass die CPU aktiv bleibt. Wenn Sie Medien über das Netzwerk streamen und WLAN verwenden, sollten Sie auch ein WifiLock haben, das Sie manuell abrufen und freigeben müssen. Wenn Sie also mit der Vorbereitung des MediaPlayer mit der Remote-URL beginnen, sollten Sie die WLAN-Sperre erstellen und beziehen. Beispiele:

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();

Wenn Sie die Wiedergabe von Medien pausieren oder beenden oder wenn Sie das Netzwerk nicht mehr benötigen, sollten Sie die Sperre wieder aufheben:

Kotlin

wifiLock.release()

Java

wifiLock.release();

Bereinigung wird durchgeführt

Wie bereits erwähnt, kann ein MediaPlayer-Objekt eine erhebliche Menge an Systemressourcen verbrauchen. Daher sollten Sie es nur so lange wie nötig aufbewahren und release() aufrufen, wenn Sie damit fertig sind. Es ist wichtig, diese Bereinigungsmethode explizit aufzurufen und sich nicht auf die automatische Speicherbereinigung des Systems zu verlassen, da es einige Zeit dauern kann, bis die automatische Speicherbereinigung das MediaPlayer zurückbezieht. Es ist nämlich nur empfindlich auf Speicheranforderungen und nicht auf einen Mangel an anderen medienbezogenen Ressourcen. Wenn Sie also einen Dienst verwenden, sollten Sie immer die Methode onDestroy() überschreiben, damit die MediaPlayer freigegeben wird:

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();
   }
}

Sie sollten immer auch nach anderen Möglichkeiten zum Freigeben des MediaPlayer suchen – abgesehen von der Freigabe beim Herunterfahren. Wenn Sie beispielsweise davon ausgehen, dass Sie über einen längeren Zeitraum keine Medien wiedergeben können (z. B. nach dem Verlust des Audiofokus), sollten Sie die vorhandene MediaPlayer-Datei auf jeden Fall freigeben und später noch einmal erstellen. Wenn Sie die Wiedergabe allerdings nur für sehr kurze Zeit beenden möchten, sollten Sie MediaPlayer beibehalten, um den Aufwand zu vermeiden, den Sie noch einmal erstellen und vorbereiten müssen.

Digitale Rechteverwaltung (Digital Rights Management, DRM)

Ab Android 8.0 (API-Level 26) umfasst MediaPlayer APIs, die die Wiedergabe von DRM-geschützten Inhalten unterstützen. Sie ähneln der von MediaDrm bereitgestellten Low-Level-API, arbeiten jedoch auf einer höheren Ebene und geben nicht den zugrunde liegenden Extrahierer, drm und die Kryptoobjekte frei.

Obwohl die MediaPlayer DRM API nicht alle Funktionen von MediaDrm bietet, unterstützt sie die gängigsten Anwendungsfälle. Die aktuelle Implementierung kann die folgenden Inhaltstypen verarbeiten:

  • Widevine-geschützte lokale Mediendateien
  • Widevine-geschützte Remote-/Streaming-Mediendateien

Das folgende Code-Snippet zeigt, wie die neuen DRM MediaPlayer-Methoden in einer einfachen synchronen Implementierung verwendet werden.

Um DRM-gesteuerte Medien zu verwalten, müssen Sie neben dem üblichen Ablauf von MediaPlayer-Aufrufen die neuen Methoden einbinden:

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();

Initialisieren Sie zuerst wie gewohnt das Objekt MediaPlayer und legen Sie seine Quelle mit setDataSource() fest. Führen Sie dann die folgenden Schritte aus, um DRM zu verwenden:

  1. Wenn Ihre App eine benutzerdefinierte Konfiguration ausführen soll, definieren Sie eine OnDrmConfigHelper-Schnittstelle und hängen Sie sie mithilfe von setOnDrmConfigHelper() an den Player an.
  2. prepare() anrufen.
  3. getDrmInfo() anrufen. Wenn die Quelle DRM-Inhalte enthält, gibt die Methode einen MediaPlayer.DrmInfo-Wert zurück, der nicht null ist.

Wenn MediaPlayer.DrmInfo vorhanden ist:

  1. Sehen Sie sich die Zuordnung der verfügbaren UUIDs an und wählen Sie eine aus.
  2. Bereiten Sie die DRM-Konfiguration für die aktuelle Quelle durch Aufrufen von prepareDrm() auf.
    • Wenn Sie einen OnDrmConfigHelper-Callback erstellt und registriert haben, wird er aufgerufen, während prepareDrm() ausgeführt wird. So kannst du vor dem Öffnen der DRM-Sitzung eine benutzerdefinierte Konfiguration der DRM-Eigenschaften vornehmen. Der Callback wird synchron in dem Thread aufgerufen, das prepareDrm() aufgerufen hat. Rufe getDrmPropertyString() und setDrmPropertyString() auf, um auf die Eigenschaften der digitalen Rechteverwaltung zuzugreifen. Vermeiden Sie langwierige Vorgänge.
    • Wenn das Gerät noch nicht bereitgestellt wurde, greift prepareDrm() auch auf den Bereitstellungsserver zu, um das Gerät bereitzustellen. Je nach Netzwerkverbindung kann dies unterschiedlich lange dauern.
  3. Rufen Sie getKeyRequest() auf, um ein intransparentes Byte-Array für Schlüsselanfragen zum Senden an einen Lizenzserver abzurufen.
  4. Rufe provideKeyResponse() auf, um die DRM-Engine über die vom Lizenzserver empfangene Schlüsselantwort zu informieren. Das Ergebnis hängt vom Typ der Schlüsselanfrage ab:
    • Wenn die Antwort eine Offline-Schlüsselanfrage betrifft, ist das Ergebnis eine Schlüsselsatz-ID. Sie können diese Schlüsselsatz-ID mit restoreKeys() verwenden, um die Schlüssel in einer neuen Sitzung wiederherzustellen.
    • Wenn sich die Antwort auf eine Streaming- oder Release-Anfrage bezieht, ist das Ergebnis null.

prepareDrm() asynchron ausführen

Standardmäßig wird prepareDrm() synchron ausgeführt und blockiert, bis die Vorbereitung abgeschlossen ist. Die allererste Vorbereitung der digitalen Rechteverwaltung auf einem neuen Gerät kann jedoch auch eine Bereitstellung erfordern, die intern von prepareDrm() verwaltet wird und je nach Netzwerkbetrieb einige Zeit in Anspruch nehmen kann. Sie können das Blockieren von prepareDrm() vermeiden, indem Sie einen MediaPlayer.OnDrmPreparedListener definieren und festlegen.

Wenn Sie ein OnDrmPreparedListener festlegen, führt prepareDrm() die Bereitstellung (falls erforderlich) und die Vorbereitung im Hintergrund aus. Wenn die Bereitstellung und Vorbereitung abgeschlossen sind, wird der Listener aufgerufen. Sie sollten keine Annahmen über die aufrufende Sequenz oder den Thread anstellen, in dem der Listener ausgeführt wird (es sei denn, der Listener ist mit einem Handler-Thread registriert). Der Listener kann vor oder nach der Rückgabe von prepareDrm() aufgerufen werden.

DRM asynchron einrichten

Sie können die digitale Rechteverwaltung asynchron initialisieren. Erstellen und registrieren Sie dazu den MediaPlayer.OnDrmInfoListener für die Vorbereitung der digitalen Rechteverwaltung und den MediaPlayer.OnDrmPreparedListener zum Starten des Players. Sie funktionieren in Verbindung mit prepareAsync(), wie unten gezeigt:

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();
}

Umgang mit verschlüsselten Medien

Ab Android 8.0 (API-Level 26) kann MediaPlayer auch ein Common Encryption Scheme (CENC) und HLS-verschlüsselte Medien auf Stichprobenebene (METHOD=Example-AES) für die grundlegenden Streamtypen H.264 und AAC entschlüsseln. Früher wurden vollständig segmentierte Medien (METHOD=AES-128) unterstützt.

Medien aus einem ContentResolver abrufen

Eine weitere nützliche Funktion in einer Mediaplayer-Anwendung ist die Möglichkeit, Musik abzurufen, die sich auf dem Gerät des Nutzers befindet. Fragen Sie dazu den ContentResolver nach externen Medien ab:

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());
}

So kannst du dies mit dem MediaPlayer verwenden:

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...

Weitere Informationen

Auf diesen Seiten geht es um das Aufzeichnen, Speichern und Abspielen von Audio und Video.