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()
oderMediaPlayer.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:
- Wenn Ihre App eine benutzerdefinierte Konfiguration ausführen soll, definieren Sie eine
OnDrmConfigHelper
-Schnittstelle und hängen Sie sie mithilfe vonsetOnDrmConfigHelper()
an den Player an. prepare()
anrufen.getDrmInfo()
anrufen. Wenn die Quelle DRM-Inhalte enthält, gibt die Methode einenMediaPlayer.DrmInfo
-Wert zurück, der nicht null ist.
Wenn MediaPlayer.DrmInfo
vorhanden ist:
- Sehen Sie sich die Zuordnung der verfügbaren UUIDs an und wählen Sie eine aus.
- 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ährendprepareDrm()
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, dasprepareDrm()
aufgerufen hat. RufegetDrmPropertyString()
undsetDrmPropertyString()
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. - Rufen Sie
getKeyRequest()
auf, um ein intransparentes Byte-Array für Schlüsselanfragen zum Senden an einen Lizenzserver abzurufen. - 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.
- Wenn die Antwort eine Offline-Schlüsselanfrage betrifft, ist das Ergebnis eine Schlüsselsatz-ID. Sie können diese Schlüsselsatz-ID mit
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.