MediaRecorder – Übersicht

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

    Hinweis:Die meisten Audioquellen, einschließlich DEFAULT, verarbeiten das Audiosignal. Wählen Sie zum Aufzeichnen von RAW-Audio UNPROCESSED aus. Einige Geräte unterstützen keine nicht verarbeiteten Eingaben. Rufe zuerst AudioManager.getProperty(AudioManager.PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED) an, um zu prüfen, ob sie verfügbar ist. Ist dies nicht der Fall, verwenden Sie stattdessen VOICE_RECOGNITION. Hier werden keine AGC- oder Rauschunterdrückung eingesetzt. Du kannst UNPROCESSED 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ützt MediaRecorder 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.