Android multimedya çerçevesi, yaygın olarak kullanılan çeşitli ses ve video biçimlerini yakalama ve kodlama desteği içerir. Cihaz donanımı tarafından destekleniyorsa MediaRecorder
API'lerini kullanabilirsiniz.
Bu dokümanda, cihazın mikrofonundan ses kaydeden, sesi kaydeden ve çalan (MediaPlayer
ile) bir uygulama yazmak için MediaRecorder
hizmetinin nasıl kullanılacağı gösterilmektedir. Video kaydetmek için MediaRecorder
ile birlikte cihazın kamerasını kullanmanız gerekir. Bu, Kamera kılavuzunda açıklanmaktadır.
Not: Android Emülatör ses kaydedemez. Kodunuzu kayıt yapabilen gerçek bir cihazda test ettiğinizden emin olun.
Ses kaydetme izni isteniyor
Uygulamanızın, kayıt yapabilmesi için kullanıcıya cihazın ses girişine erişebileceğini söylemesi gerekir. Bu izin etiketini, uygulamanın manifest dosyasına eklemeniz gerekir:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
RECORD_AUDIO
, kullanıcının gizliliği için risk oluşturabileceği için "tehlikeli" izin olarak kabul edilir. Android 6.0 (API düzeyi 23) sürümünden itibaren, tehlikeli izin kullanan bir uygulamanın çalışma zamanında kullanıcıdan onay istemesi gerekir. Kullanıcı izin verdikten sonra uygulama bunu hatırlayıp bir daha sormamalıdır. Aşağıdaki örnek kod, ActivityCompat.requestPermissions()
kullanarak bu davranışın nasıl uygulanacağını göstermektedir.
MediaRecorder oluşturma ve çalıştırma
Aşağıdaki çağrılarla yeni bir MediaRecorder
örneğini başlatın:
- Ses kaynağını
setAudioSource()
ile ayarlayın. MuhtemelenMIC
kullanacaksınız.Not: Ses kaynaklarının çoğu (
DEFAULT
dahil) ses sinyaline işleme uygulanır. Ham ses kaydetmek içinUNPROCESSED
öğesini seçin. Bazı cihazlar işlenmemiş girişleri desteklemez. Kullanılabilir olduğunu doğrulamak için önceAudioManager.getProperty(AudioManager.PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED)
numaralı telefonu arayın. Değilse AGC veya gürültü azaltma kullanmayanVOICE_RECOGNITION
kullanmayı deneyin. Mülk desteklenmediğinde bileUNPROCESSED
ses kaynağı olarak kullanabilirsiniz ancak bu durumda sinyalin işlenip işlenmeyeceğini garanti edemeyiz. - Çıkış dosyası biçimini
setOutputFormat()
ile ayarlayın. Android 8.0 (API düzeyi 26) sürümünden itibarenMediaRecorder
özelliğinin, akış için yararlı olan MPEG2_TS biçimini desteklediğini unutmayın:Kotlin
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_2_TS)
Java
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_2_TS);
- Çıkış dosyasının adını
setOutputFile()
ile ayarlayın. Gerçek bir dosyayı temsil eden bir dosya tanımlayıcı belirtmelisiniz. - Ses kodlayıcıyı
setAudioEncoder()
ile ayarlayın. prepare()
yöntemini çağırarak başlatma işlemini tamamlayın.
start()
ve stop()
çağrılarını sırasıyla yaparak kaydediciyi başlatıp durdurun.
MediaRecorder
örneğiyle işiniz bittiğinde, release()
yöntemini çağırarak kaynaklarını en kısa sürede boşaltın.
Not: Android 9 (API düzeyi 28) veya sonraki sürümleri çalıştıran cihazlarda arka planda çalışan uygulamalar mikrofona erişemez. Bu nedenle, uygulamanız yalnızca ön plandayken veya bir ön plan hizmetine MediaRecorder
örneği eklediğinizde ses kaydetmelidir.
Birden çok kanal kaydetmek için MediaMuxer kullanma
Android 8.0 (API düzeyi 26) sürümünden başlayarak, birden fazla eş zamanlı ses ve video akışı kaydetmek için MediaMuxer
kullanabilirsiniz. Android'in önceki sürümlerinde aynı anda yalnızca bir ses parçası ve/veya bir video parçası kaydedebilirsiniz.
Birden fazla parçayı karıştırmak için addTrack()
yöntemini kullanın.
Yalnızca MP4 kapsayıcılarına olmak kaydıyla her kare için özel bilgiler içeren bir veya daha fazla meta veri parçası da ekleyebilirsiniz. Uygulamanız meta verilerin biçimini ve içeriğini tanımlar.
Meta veri ekleme
Meta veriler çevrimdışı işleme için yararlı olabilir. Örneğin, jiroskop sensöründen alınan veriler video sabitleme işlemi için kullanılabilir.
Meta veri parçası eklediğinizde parçanın MIME biçimi application/
önekiyle başlamalıdır. Veriler bir MediaCodec
kaynağından gelmemesi dışında, meta veri yazmak video veya ses verisi yazmakla aynıdır. Bunun yerine, uygulama writeSampleData()
yöntemine ilişkilendirilmiş zaman damgasıyla bir ByteBuffer
aktarır.
Zaman damgası, video ve ses parçalarıyla aynı zaman tabanında olmalıdır.
Oluşturulan MP4 dosyası, meta verinin MIME biçimini belirtmek için ISO BMFF spesifikasyonunun 12.3.3.2 bölümünde tanımlanan TextMetaDataSampleEntry
değerini kullanır. Meta veri parçaları içeren bir dosyayı çıkarmak için MediaExtractor
kullandığınızda meta verinin MIME biçimi, MediaFormat
örneği olarak görünür.
Örnek kod
MediaRecorder örneği, MediaRecorder ve Camera API kullanılarak video kaydının nasıl yapılacağını gösterir.
Aşağıdaki örnek etkinlikte, ses dosyası kaydetmek için MediaRecorder
özelliğinin nasıl kullanılacağı gösterilmektedir. Ayrıca, sesi çalmak için MediaPlayer
kullanır.
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; } } }
Daha fazla bilgi
Bu sayfalarda ses ve video kaydetme, depolama ve oynatmayla ilgili konular ele alınmaktadır.