Il framework multimediale Android include il supporto per l'acquisizione e la codifica di una serie di
formati audio e video. Puoi utilizzare le API MediaRecorder
, se supportate
dall'hardware del dispositivo.
Questo documento mostra come utilizzare MediaRecorder
per scrivere un'applicazione che acquisisce l'audio da un dispositivo
microfono, salva l'audio e riproducilo (con MediaPlayer
). Per registrare un video dovrai:
usa la fotocamera del dispositivo insieme a MediaRecorder
. Questa operazione è descritta nella guida Fotocamera.
Nota: l'emulatore Android non può registrare audio. Assicurati di testare il codice su un dispositivo reale in grado di registrare.
Richiesta di autorizzazione per la registrazione di audio
Per poter registrare, l'app deve comunicare all'utente che accederà all'input audio del dispositivo. Devi includere questo tag di autorizzazione nel file manifest dell'app:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
RECORD_AUDIO
è considerata un
"pericoloso" autorizzazione
perché potrebbe rappresentare un rischio per la privacy dell'utente. A partire da Android 6.0 (livello API 23), un'app
che utilizza un'autorizzazione pericolosa deve chiedere l'approvazione dell'utente in fase di esecuzione. Dopo che l'utente ha
l'autorizzazione, l'app dovrebbe ricordarla e non chiederla di nuovo. Il codice di esempio riportato di seguito mostra come
questo comportamento utilizzando
ActivityCompat.requestPermissions()
.
Creazione ed esecuzione di un MediaRecorder
Inizializza una nuova istanza di MediaRecorder
con le seguenti chiamate:
- Imposta la sorgente audio utilizzando
setAudioSource()
. Dovrai probabilmente useraiMIC
.Nota: la maggior parte delle sorgenti audio (tra cui la
DEFAULT
) applica l'elaborazione alla segnale audio. Per registrare un audio RAW, selezionaUNPROCESSED
. Alcuni dispositivi non supportano i dati non elaborati di testo. Chiama primaAudioManager.getProperty(AudioManager.PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED)
per verificare che sia disponibile. In caso contrario, prova a usareVOICE_RECOGNITION
, che non impiega AGC o soppressione del rumore. Puoi usareUNPROCESSED
come sorgente audio anche quando la proprietà non è supportata, ma non vi è alcuna garanzia in caso contrario, l'indicatore non verrà elaborato. - Imposta il formato file di output utilizzando
setOutputFormat()
. Tieni presente che a partire da Android 8.0 (livello API 26)MediaRecorder
supporta lo standard MPEG2_TS , che è utile per i flussi di dati:Kotlin
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_2_TS)
Java
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_2_TS);
- Imposta il nome del file di output utilizzando
setOutputFile()
. Devi specificare un descrittore del file che rappresenti un file effettivo. - Imposta il codificatore audio utilizzando
setAudioEncoder()
. - Completa l'inizializzazione chiamando
prepare()
.
Avvia e interrompi il registratore chiamando
start()
e
stop()
rispettivamente.
Quando hai finito di utilizzare l'istanza MediaRecorder
, libera le sue risorse
il prima possibile chiamando
release()
.
Nota:sui dispositivi con Android 9 (livello API 28) o
superiore, le app in esecuzione in background non possono accedere al microfono. Pertanto,
l'app dovrebbe registrare audio soltanto quando è in primo piano o quando
includi un'istanza di MediaRecorder
in un
servizio in primo piano.
Uso di MediaMuxer per registrare più canali
A partire da Android 8.0 (livello API 26) puoi utilizzare un MediaMuxer
per registrare più stream audio e video simultanei. Nelle versioni precedenti di Android, era possibile
registrare una traccia audio e/o una traccia video alla volta.
Usa addTrack()
per mixare più tracce insieme.
Puoi anche aggiungere una o più tracce di metadati con informazioni personalizzate per ogni frame, solo ai container MP4. La tua app definisce il formato e i contenuti dei metadati.
Aggiunta di metadati
I metadati possono essere utili per l'elaborazione offline. Ad esempio, i dati acquisiti il giroscopio potrebbe essere usato per la stabilizzazione dei video.
Quando aggiungi una traccia di metadati, il formato MIME della traccia deve iniziare con il prefisso
application/
. Scrivere metadati equivale a scrivere dati video o audio, ad eccezione del
che i dati non provengano da un MediaCodec
. L'app trasmette invece
ByteBuffer
con un timestamp associato al valore
Metodo writeSampleData()
.
Il timestamp deve trovarsi nella stessa base temporale delle tracce video e audio.
Il file MP4 generato utilizza il criterio TextMetaDataSampleEntry
definito nella sezione 12.3.3.2
della specifica ISO BMFF
per segnalare il formato MIME dei metadati. Quando usi MediaExtractor
per estrarre un file che contiene tracce di metadati, il mimo dei metadati
viene visualizzato come un'istanza di MediaFormat
.
Codice di esempio
MediaRecorder mostra come realizzare una registrazione video utilizzando MediaRecorder e l'API Camera.
L'attività di esempio riportata di seguito mostra come utilizzare MediaRecorder
per registrare un file audio. it
Usa anche MediaPlayer
per riprodurre 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; } } }
Scopri di più
In queste pagine vengono trattati argomenti relativi alla registrazione, all'archiviazione e alla riproduzione di audio e video.