MediaRecorder'a genel bakış

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. Muhtemelen MIC kullanacaksınız.

    Not: Ses kaynaklarının çoğu (DEFAULT dahil) ses sinyaline işleme uygulanır. Ham ses kaydetmek için UNPROCESSED öğesini seçin. Bazı cihazlar işlenmemiş girişleri desteklemez. Kullanılabilir olduğunu doğrulamak için önce AudioManager.getProperty(AudioManager.PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED) numaralı telefonu arayın. Değilse AGC veya gürültü azaltma kullanmayan VOICE_RECOGNITION kullanmayı deneyin. Mülk desteklenmediğinde bile UNPROCESSED 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 itibaren MediaRecorder ö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.