-
[ Android ] 음성 녹음하기Android/멀티미디어 2020. 3. 26. 14:32
이 글은 부스트코스 강의 와 MediaRecorder를 공부하며 요약한 글입니다.
CatServant
MediaRecorder
Android 멀티미디어 프레임워크에는 다양한 일반 오디오 및 동영상 포맷을 캡처하고 인코딩하는 지원 기능이 포함되어 있습니다. AudioRecorder 는 오디오만 레코딩 가능 하지만, MediaRecorder 의 경우 Audio 및 Video 컨텐츠의 레코딩이 가능 합니다. 다만 인코딩 된 파일을 받기 때문에 AudioRecorder 처럼 PCM Data 를 바로 받아올 수는 없는 단점이 있습니다.
MediaRecorder recorder = new MediaRecorder(); recorder.setAudioSource(MediaRecorder.AudioSource.MIC); recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG2_TS); recorder.setAudioEncoder(MediaRecorder.AudioEncoder.ACC); recorder.setOutputFile(PATH_NAME); recorder.prepare(); recorder.start(); // Recording is now started ... recorder.stop(); recorder.reset(); // You can reuse the object by going back to setAudioSource() step recorder.release(); // Now the object cannot be reused
- setAudioSource()를 사용하여 오디오 소스를 설정합니다. 대개 MIC가 사용됩니다.
- setOutputFormat()을 사용하여 출력 파일 포맷을 설정합니다. Android 8.0(API 레벨 26)부터 MediaRecorder는 스트리밍에 유용한 MPEG2_TS 포맷을 지원합니다.
- setOutputFile()을 사용하여 출력 파일 이름을 설정합니다. 실제 파일을 나타내는 파일 설명자를 지정해야 합니다.
- setAudioEncoder()를 사용하여 오디오 인코더를 설정합니다.
- prepare()를 호출하여 초기화를 완료합니다.
- start() 및 stop()을 각각 호출하여 녹음기를 시작 및 중지합니다.
- 작업이 완료되면 MediaRecorder는 release()를 호출하여 가능한 한 빨리 리소스를 확보합니다.
오디오 녹음을 위한 과정
- MediaRecorder 객체 생성
- 오디오 녹음을 위해 MediaRecorder 객체를 new 연산자를 이용하여 만듬
- 오디오 입력 및 출력 형식 설정
- 오디오 정보를 입력받을 데이터 소스와 함께 출력 형식을 설정함
- 오디오 인코더와 파일 지정
- 오디오 파일을 만들 때 필요한 인코더(Encoder)와 함께 파일 이름을 지정함
- 녹음 시작
- 녹음을 시작하면 오디오 파일이 만들어지고 인코딩된 바이트 스트림이 저장됨
- 매니페스트에 권한 설정
- 애플리케이션에 녹을음 하려면 RECORD_AUDIO 권한이 있어야 하므로 매니페스트에 추가
Code
- AndroidManifest.xml
<uses-permission android:name="android.permission.RECORD_AUDIO"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
녹음하기 위한 RECORD_AUDIO 권한과 SD card에 접근하기 위해서 READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE 권한이 필요합니다.
- MainActivity.java
public class MainActivity extends AppCompatActivity { private static final int REQUEST_RECORD_AUDIO_PERMISSION = 200; private MediaRecorder recorder; private String fileName; private MediaPlayer player; private int position = 0; @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode) { case REQUEST_RECORD_AUDIO_PERMISSION: if (grantResults.length > 0) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { Toast.makeText(this, "Audio 권한을 사용자가 승인함.", Toast.LENGTH_LONG).show(); } else if (grantResults[0] == PackageManager.PERMISSION_DENIED) { Toast.makeText(this, "Audio 권한을 사용자가 거부함.", Toast.LENGTH_LONG).show(); } } else { Toast.makeText(this, "Audio 권한을 부여받지 못함.", Toast.LENGTH_LONG).show(); } break; } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 위험 권한 부여하기 int permissionCheck = ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO); if (permissionCheck == PackageManager.PERMISSION_GRANTED) { Toast.makeText(this, "Audio 권한 있음.", Toast.LENGTH_LONG).show(); } else { Toast.makeText(this, "Audio 권한 없음.", Toast.LENGTH_LONG).show(); if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO)) { Toast.makeText(this, "Audio 권한 설명 필요함.", Toast.LENGTH_LONG).show(); } else { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, REQUEST_RECORD_AUDIO_PERMISSION); } } // Record to the external cache directory for visibility fileName = getExternalCacheDir().getAbsolutePath(); fileName += "/audiorecordtest.3gp"; Log.e("MainActivity", "저장할 파일명 : " + fileName); Button btnRecord = findViewById(R.id.record); btnRecord.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { recordAudio(); } }); Button btnStopRecording = findViewById(R.id.stop); btnStopRecording.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { stopRecording(); } }); Button btnPlay = findViewById(R.id.button); btnPlay.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { playAudio(); } }); Button btnPause = findViewById(R.id.button2); btnPause.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { pauseAudio(); } }); Button btnReplay = findViewById(R.id.button3); btnReplay.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { resumeAudio(); } }); Button btnStop = findViewById(R.id.button4); btnStop.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { stopAudio(); } }); } public void recordAudio() { recorder = new MediaRecorder(); recorder.setAudioSource(MediaRecorder.AudioSource.MIC); recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); recorder.setOutputFile(fileName); recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); try { recorder.prepare(); Toast.makeText(this, "녹음 시작됨.", Toast.LENGTH_LONG).show(); } catch (Exception e) { Log.e("SampleAudioRecorder", "Exception : ", e); } recorder.start(); } public void stopRecording() { if (recorder != null) { recorder.stop(); recorder.release(); recorder = null; Toast.makeText(this, "녹음 중지됨.", Toast.LENGTH_LONG).show(); } } public void playAudio() { try { closePlayer(); player = new MediaPlayer(); player.setDataSource(fileName); player.prepare(); player.start(); Toast.makeText(this, "재생 시작됨.", Toast.LENGTH_LONG).show(); } catch (Exception e) { e.printStackTrace(); } } public void pauseAudio() { if (player != null) { position = player.getCurrentPosition(); player.pause(); Toast.makeText(this, "일시정지됨.", Toast.LENGTH_LONG).show(); } } public void resumeAudio() { if (player != null && !player.isPlaying()) { // position 값도 확인 해야함 player.seekTo(position); player.start(); Toast.makeText(this, "재시작됨.", Toast.LENGTH_LONG).show(); } } public void stopAudio() { if (player != null && player.isPlaying()) { // position 값도 확인 해야함 player.stop(); Toast.makeText(this, "중지됨.", Toast.LENGTH_LONG).show(); } } public void closePlayer() { if (player != null) { player.release(); player = null; } } }
마이크 기능은 위험 권한으로 분류되기 때문에 위험 권한을 부여해주기 위한 코드를 추가해주어야 합니다. ( 위험권한 부여하기 참고 )
Error
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
위의 코드에서 계속 아래와 같은 Error를 만났는데 DEFAULT를 ACC로 고치니까 해결되었다.
AndroidRuntime: FATAL EXCEPTION: main Process: com.example.captrue, PID: 8216 java.lang.RuntimeException: start failed.
출처
'Android > 멀티미디어' 카테고리의 다른 글
[ Android ] 임시 파일 생성해서 외부 앱으로 찍은 사진 받기 (0) 2020.09.16 [ Android ] 음악 재생하기 (0) 2020.03.25 [ Android ] 동영상 파일 재생하기 (0) 2020.03.24 [ Android ] 사진 미리보기 - Camera 이용 (0) 2020.03.17 [ Android ] 사진 찍기 (0) 2020.03.16