Présentation de MediaRecorder

Le framework multimédia Android prend en charge la capture et l'encodage de divers types aux formats audio et vidéo. Vous pouvez utiliser les API MediaRecorder si elles sont compatibles par le matériel de l'appareil.

Ce document explique comment utiliser MediaRecorder pour écrire une application qui enregistre du contenu audio à partir d'un appareil. micro, enregistrer le contenu audio et le lire (avec MediaPlayer). Pour enregistrer une vidéo, vous devez : utiliser l'appareil photo de l'appareil avec MediaRecorder. Pour en savoir plus, consultez le guide Appareil photo.

Remarque:Android Emulator ne peut pas enregistrer audio. Veillez à tester votre code sur un appareil réel capable d'enregistrer.

Demander l'autorisation d'enregistrer du contenu audio

Pour pouvoir enregistrer, votre application doit indiquer à l'utilisateur qu'elle accédera à l'entrée audio de l'appareil. Vous devez inclure cette balise d'autorisation dans le fichier manifeste de l'application:

<uses-permission android:name="android.permission.RECORD_AUDIO" />

RECORD_AUDIO est considéré comme un "dangereux" autorisation car il peut présenter un risque pour la confidentialité de l'utilisateur. Application à partir d'Android 6.0 (niveau d'API 23) qui utilise une autorisation dangereuse doit demander l'approbation de l'utilisateur au moment de l'exécution. Une fois que l'utilisateur a accorder l'autorisation, l'application doit se souvenir et ne plus demander. L'exemple de code ci-dessous montre comment implémenter ce comportement en utilisant ActivityCompat.requestPermissions()

Créer et exécuter un MediaRecorder

Initialiser une nouvelle instance de MediaRecorder avec les appels suivants:

  • Définir la source audio avec setAudioSource() Vous allez utilisent probablement MIC.

    Remarque:La plupart des sources audio (y compris DEFAULT) appliquent le traitement le signal audio. Pour enregistrer un fichier audio brut, sélectionnez UNPROCESSED Certains appareils ne sont pas compatibles avec les données non traitées saisie. Appelez d'abord AudioManager.getProperty(AudioManager.PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED) pour vérifier qu'elle est disponible. Si ce n'est pas le cas, essayez d'utiliser VOICE_RECOGNITION à la place. qui n'utilise pas l'AGC ni la suppression du bruit. Vous pouvez utiliser UNPROCESSED comme source audio, même lorsque la propriété n'est pas compatible, mais qu'il n'y a aucune garantie le signal ne sera pas traité ou pas dans ce cas.

  • Définissez le format du fichier de sortie à l'aide de setOutputFormat() Notez qu'à partir d'Android 8.0 (niveau d'API 26), MediaRecorder est compatible avec le format MPEG2_TS , ce qui est utile pour le streaming:

    Kotlin

    mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_2_TS)
    

    Java

    mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_2_TS);
    
  • Définissez le nom du fichier de sortie à l'aide de setOutputFile() Vous devez spécifier un descripteur de fichier qui représente un fichier réel.
  • Configurez l'encodeur audio avec setAudioEncoder()
  • Terminez l'initialisation en appelant prepare()

Démarrez et arrêtez l'enregistreur en appelant start() et stop() respectivement.

Lorsque vous avez terminé d'utiliser l'instance MediaRecorder, libérez ses ressources dès que possible en appelant release()

Remarque:Sur les appareils équipés d'Android 9 (niveau d'API 28) ou supérieur, les applications exécutées en arrière-plan ne peuvent pas accéder au micro. Par conséquent, votre application ne doit enregistrer du contenu audio que lorsqu'elle est exécutée au premier plan ou lorsque vous inclure une instance de MediaRecorder dans un service de premier plan.

Utiliser MediaMuxer pour enregistrer plusieurs canaux

À partir d'Android 8.0 (niveau d'API 26), vous pouvez utiliser un MediaMuxer. pour enregistrer plusieurs flux audio et vidéo simultanés. Dans les versions antérieures d'Android, vous ne pouvez enregistrer une piste audio et/ou une piste vidéo à la fois.

Utiliser le addTrack() pour mixer plusieurs pistes.

Vous pouvez aussi ajouter une ou plusieurs pistes de métadonnées avec des informations personnalisées pour chaque image, mais uniquement aux conteneurs MP4. Votre application définit le format et le contenu des métadonnées.

Ajouter des métadonnées

Les métadonnées peuvent être utiles pour un traitement hors connexion. Par exemple, les données collectées à partir de le capteur du gyroscope peut être utilisé pour effectuer la stabilisation vidéo.

Lorsque vous ajoutez une piste de métadonnées, le format MIME de la piste doit commencer par le préfixe application/ L'écriture de métadonnées est identique à l'écriture de données vidéo ou audio, sauf que les données ne proviennent pas d'un MediaCodec. Au lieu de cela, l'application transmet ByteBuffer par un horodatage associé à writeSampleData(). Le code temporel doit être identique à celui des pistes vidéo et audio.

Le fichier MP4 généré utilise le TextMetaDataSampleEntry défini dans la section 12.3.3.2 de la spécification ISO BMFF pour signaler le format MIME des métadonnées. Lorsque vous utilisez un MediaExtractor pour extraire un fichier contenant des pistes de métadonnées, la méthode MIME apparaît en tant qu'instance de MediaFormat.

Exemple de code

MediaRecorder montre comment créer un enregistrement vidéo à l'aide de MediaRecorder et de l'API Camera.

L'exemple d'activité ci-dessous montre comment utiliser MediaRecorder pour enregistrer un fichier audio. Il Utilise également MediaPlayer pour lire l'audio.

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

En savoir plus

Ces pages traitent de sujets liés à l'enregistrement, au stockage et à la lecture de contenus audio et vidéo.