Das Multimedia-Framework von Android unterstützt die Erfassung und Codierung einer Vielzahl gängiger Audio- und Videoformate. Sie können die MediaRecorder
APIs verwenden, wenn sie von der Gerätehardware unterstützt werden.
In diesem Dokument wird beschrieben, wie Sie mit MediaRecorder
eine Anwendung schreiben, die Audio über ein Gerätemikrofon aufzeichnet, die Audioinhalte speichert und sie dann mit MediaPlayer
wiedergibt. Zum Aufzeichnen von Videos müssen Sie die Kamera des Geräts zusammen mit MediaRecorder
verwenden. Weitere Informationen dazu finden Sie im Kamerahandbuch.
Hinweis:Der Android-Emulator kann keine Audioinhalte aufzeichnen. Testen Sie Ihren Code unbedingt auf einem realen, aufgezeichneten Gerät.
Berechtigung zum Aufzeichnen von Audio wird angefordert
Damit eine Aufnahme möglich ist, muss die App dem Nutzer mitteilen, dass sie auf die Audioeingabe des Geräts zugreift. Du musst dieses Berechtigungs-Tag in die Manifestdatei der App aufnehmen:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
RECORD_AUDIO
gilt als „gefährliche“ Berechtigung, da sie ein Risiko für die Privatsphäre des Nutzers darstellen kann. Ab Android 6.0 (API-Level 23) muss eine App, die eine gefährliche Berechtigung verwendet, den Nutzer während der Laufzeit um Genehmigung bitten. Nachdem der Nutzer die Berechtigung erteilt hat, sollte die App sich diese merken und nicht noch einmal danach fragen. Der folgende Beispielcode zeigt, wie dieses Verhalten mit ActivityCompat.requestPermissions()
implementiert wird.
MediaRekorder erstellen und ausführen
Initialisieren Sie mit folgenden Aufrufen eine neue Instanz von MediaRecorder
:
- Lege die Audioquelle mit
setAudioSource()
fest. Wahrscheinlich verwenden SieMIC
.Hinweis:Die meisten Audioquellen, einschließlich
DEFAULT
, verarbeiten das Audiosignal. Wählen Sie zum Aufzeichnen von RAW-AudioUNPROCESSED
aus. Einige Geräte unterstützen keine nicht verarbeiteten Eingaben. Rufe zuerstAudioManager.getProperty(AudioManager.PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED)
an, um zu prüfen, ob sie verfügbar ist. Ist dies nicht der Fall, verwenden Sie stattdessenVOICE_RECOGNITION
. Hier werden keine AGC- oder Rauschunterdrückung eingesetzt. Du kannstUNPROCESSED
auch dann als Audioquelle verwenden, wenn die Eigenschaft nicht unterstützt wird. Es gibt jedoch keine Garantie dafür, dass das Signal in diesem Fall unverarbeitet wird oder nicht. - Legen Sie das Format der Ausgabedatei mit
setOutputFormat()
fest. Hinweis: Ab Android 8.0 (API-Level 26) unterstütztMediaRecorder
das MPEG2_TS-Format, das für Streaming nützlich ist:Kotlin
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_2_TS)
Java
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_2_TS);
- Legen Sie den Namen der Ausgabedatei mit
setOutputFile()
fest. Sie müssen einen Dateideskriptor angeben, der eine tatsächliche Datei darstellt. - Stelle den Audio-Encoder mit
setAudioEncoder()
ein. - Schließen Sie die Initialisierung durch Aufrufen von
prepare()
ab.
Starten und beenden Sie den Rekorder, indem Sie start()
bzw. stop()
aufrufen.
Wenn Sie die MediaRecorder
-Instanz nicht mehr benötigen, geben Sie ihre Ressourcen so schnell wie möglich kostenlos, indem Sie release()
aufrufen.
Hinweis: Auf Geräten mit Android 9 (API-Level 28) oder höher können im Hintergrund ausgeführte Apps nicht auf das Mikrofon zugreifen. Daher sollte Ihre App nur dann Audio aufzeichnen, wenn sie im Vordergrund ausgeführt wird oder wenn Sie eine Instanz von MediaRecorder
in einen Dienst im Vordergrund einfügen.
Mit MediaMuxer mehrere Kanäle aufnehmen
Ab Android 8.0 (API-Level 26) kannst du MediaMuxer
verwenden, um mehrere Audio- und Videostreams gleichzeitig aufzunehmen. In früheren Android-Versionen kann jeweils nur ein Audiotrack und/oder ein Videotrack aufgenommen werden.
Mit der Methode addTrack()
kannst du mehrere Tracks miteinander mischen.
Sie können auch eine oder mehrere Metadatenspuren mit benutzerdefinierten Informationen für jeden Frame hinzufügen, jedoch nur in MP4-Containern. Ihre App definiert das Format und den Inhalt der Metadaten.
Metadaten hinzufügen
Metadaten können für die Offlineverarbeitung nützlich sein. So könnten die vom Gyrossensor erfassten Daten zur Videostabilisierung verwendet werden.
Wenn Sie einen Metadatenspur hinzufügen, muss das MIME-Format des Tracks mit dem Präfix application/
beginnen. Metadaten werden wie Video- oder Audiodaten geschrieben, mit der Ausnahme, dass die Daten nicht aus einer MediaCodec
stammen. Stattdessen übergibt die Anwendung einen ByteBuffer
mit einem zugehörigen Zeitstempel an die Methode writeSampleData()
.
Der Zeitstempel muss auf derselben Zeit basieren wie die Video- und Audiotracks.
Die generierte MP4-Datei verwendet den in Abschnitt 12.3.3.2 der ISO BMFF-Spezifikation definierten TextMetaDataSampleEntry
, um das MIME-Format der Metadaten zu signalisieren. Wenn Sie mit einem MediaExtractor
eine Datei mit Metadatenspuren extrahieren, wird das MIME-Format der Metadaten als Instanz von MediaFormat
angezeigt.
Beispielcode
Im Beispiel MediaRecorder wird gezeigt, wie Sie mit MediaRecorder und der Camera API eine Videoaufzeichnung machen.
Die folgende Beispielaktivität zeigt, wie Sie mit MediaRecorder
eine Audiodatei aufnehmen. Außerdem wird MediaPlayer
für die Audiowiedergabe verwendet.
Kotlin
package com.android.audiorecordtest import android.Manifest import android.content.Context import android.content.pm.PackageManager import android.media.MediaPlayer import android.media.MediaRecorder import android.os.Bundle import android.support.v4.app.ActivityCompat import android.support.v7.app.AppCompatActivity import android.util.Log import android.view.View.OnClickListener import android.view.ViewGroup import android.widget.Button import android.widget.LinearLayout import java.io.IOException private const val LOG_TAG = "AudioRecordTest" private const val REQUEST_RECORD_AUDIO_PERMISSION = 200 class AudioRecordTest : AppCompatActivity() { private var fileName: String = "" private var recordButton: RecordButton? = null private var recorder: MediaRecorder? = null private var playButton: PlayButton? = null private var player: MediaPlayer? = null // Requesting permission to RECORD_AUDIO private var permissionToRecordAccepted = false private var permissions: Array<String> = arrayOf(Manifest.permission.RECORD_AUDIO) override fun onRequestPermissionsResult( requestCode: Int, permissions: Array<String>, grantResults: IntArray ) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) permissionToRecordAccepted = if (requestCode == REQUEST_RECORD_AUDIO_PERMISSION) { grantResults[0] == PackageManager.PERMISSION_GRANTED } else { false } if (!permissionToRecordAccepted) finish() } private fun onRecord(start: Boolean) = if (start) { startRecording() } else { stopRecording() } private fun onPlay(start: Boolean) = if (start) { startPlaying() } else { stopPlaying() } private fun startPlaying() { player = MediaPlayer().apply { try { setDataSource(fileName) prepare() start() } catch (e: IOException) { Log.e(LOG_TAG, "prepare() failed") } } } private fun stopPlaying() { player?.release() player = null } private fun startRecording() { recorder = MediaRecorder().apply { setAudioSource(MediaRecorder.AudioSource.MIC) setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP) setOutputFile(fileName) setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB) try { prepare() } catch (e: IOException) { Log.e(LOG_TAG, "prepare() failed") } start() } } private fun stopRecording() { recorder?.apply { stop() release() } recorder = null } internal inner class RecordButton(ctx: Context) : Button(ctx) { var mStartRecording = true var clicker: OnClickListener = OnClickListener { onRecord(mStartRecording) text = when (mStartRecording) { true -> "Stop recording" false -> "Start recording" } mStartRecording = !mStartRecording } init { text = "Start recording" setOnClickListener(clicker) } } internal inner class PlayButton(ctx: Context) : Button(ctx) { var mStartPlaying = true var clicker: OnClickListener = OnClickListener { onPlay(mStartPlaying) text = when (mStartPlaying) { true -> "Stop playing" false -> "Start playing" } mStartPlaying = !mStartPlaying } init { text = "Start playing" setOnClickListener(clicker) } } override fun onCreate(icicle: Bundle?) { super.onCreate(icicle) // Record to the external cache directory for visibility fileName = "${externalCacheDir.absolutePath}/audiorecordtest.3gp" ActivityCompat.requestPermissions(this, permissions, REQUEST_RECORD_AUDIO_PERMISSION) recordButton = RecordButton(this) playButton = PlayButton(this) val ll = LinearLayout(this).apply { addView(recordButton, LinearLayout.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, 0f)) addView(playButton, LinearLayout.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, 0f)) } setContentView(ll) } override fun onStop() { super.onStop() recorder?.release() recorder = null player?.release() player = null } }
Java
package com.android.audiorecordtest; import android.Manifest; import android.content.Context; import android.content.pm.PackageManager; import android.media.MediaPlayer; import android.media.MediaRecorder; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v4.app.ActivityCompat; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.LinearLayout; import java.io.IOException; public class AudioRecordTest extends AppCompatActivity { private static final String LOG_TAG = "AudioRecordTest"; private static final int REQUEST_RECORD_AUDIO_PERMISSION = 200; private static String fileName = null; private RecordButton recordButton = null; private MediaRecorder recorder = null; private PlayButton playButton = null; private MediaPlayer player = null; // Requesting permission to RECORD_AUDIO private boolean permissionToRecordAccepted = false; private String [] permissions = {Manifest.permission.RECORD_AUDIO}; @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode){ case REQUEST_RECORD_AUDIO_PERMISSION: permissionToRecordAccepted = grantResults[0] == PackageManager.PERMISSION_GRANTED; break; } if (!permissionToRecordAccepted ) finish(); } private void onRecord(boolean start) { if (start) { startRecording(); } else { stopRecording(); } } private void onPlay(boolean start) { if (start) { startPlaying(); } else { stopPlaying(); } } private void startPlaying() { player = new MediaPlayer(); try { player.setDataSource(fileName); player.prepare(); player.start(); } catch (IOException e) { Log.e(LOG_TAG, "prepare() failed"); } } private void stopPlaying() { player.release(); player = null; } private void startRecording() { recorder = new MediaRecorder(); recorder.setAudioSource(MediaRecorder.AudioSource.MIC); recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); recorder.setOutputFile(fileName); recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); try { recorder.prepare(); } catch (IOException e) { Log.e(LOG_TAG, "prepare() failed"); } recorder.start(); } private void stopRecording() { recorder.stop(); recorder.release(); recorder = null; } class RecordButton extends Button { boolean mStartRecording = true; OnClickListener clicker = new OnClickListener() { public void onClick(View v) { onRecord(mStartRecording); if (mStartRecording) { setText("Stop recording"); } else { setText("Start recording"); } mStartRecording = !mStartRecording; } }; public RecordButton(Context ctx) { super(ctx); setText("Start recording"); setOnClickListener(clicker); } } class PlayButton extends Button { boolean mStartPlaying = true; OnClickListener clicker = new OnClickListener() { public void onClick(View v) { onPlay(mStartPlaying); if (mStartPlaying) { setText("Stop playing"); } else { setText("Start playing"); } mStartPlaying = !mStartPlaying; } }; public PlayButton(Context ctx) { super(ctx); setText("Start playing"); setOnClickListener(clicker); } } @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); // Record to the external cache directory for visibility fileName = getExternalCacheDir().getAbsolutePath(); fileName += "/audiorecordtest.3gp"; ActivityCompat.requestPermissions(this, permissions, REQUEST_RECORD_AUDIO_PERMISSION); LinearLayout ll = new LinearLayout(this); recordButton = new RecordButton(this); ll.addView(recordButton, new LinearLayout.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, 0)); playButton = new PlayButton(this); ll.addView(playButton, new LinearLayout.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, 0)); setContentView(ll); } @Override public void onStop() { super.onStop(); if (recorder != null) { recorder.release(); recorder = null; } if (player != null) { player.release(); player = null; } } }
Weitere Informationen
Auf diesen Seiten geht es um das Aufzeichnen, Speichern und Abspielen von Audio und Video.