본문 바로가기

Android

Android : 스피커. 마이크 다루기

스피커. 마이크 다루기



간단한 예제를 위해 버튼 3개 배치.



button.setEnabled(boolean) 을 통해 활성화 / 비활성화를 제어할 수 있다.
첫 실행시에는 PLAY할 녹음본이 없고 PLAY중이 아니라면 STOP할 것도 없으므로 RECORD 버튼만 활성화한다.
btn_play.setEnabled(false)
btn_stop.setEnabled(false);
btn_record.setEnabled(true);

마이크가 현재 하드웨어에 존재하는지 확인하는 코드 추가.
//마이크가 있는지 없는지 확인
if(getPackageManager().hasSystemFeature(PackageManager.FEATURE_MICROPHONE)) { //현재 하드웨어 정보를 가져옴
btn_play.setEnabled(false); //활성화 / 비활성화
btn_stop.setEnabled(false);
btn_record.setEnabled(true);
}else{
btn_play.setEnabled(false);
btn_stop.setEnabled(false);
btn_record.setEnabled(false);
}

AndroidManifest.xml에 권한을 추가한다.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>

권한여부확인후 권한요청메시지를 띄운다.
//권한승인여부 확인후 메시지 띄워줌(둘 중 하나라도)
if(ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED
|| ActivityCompat.checkSelfPermission(getApplicationContext(),Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){

ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.RECORD_AUDIO, Manifest.permission.WRITE_EXTERNAL_STORAGE},0);
}


녹음을 도와주는 MediaRecorder객체와 저장을 위한 Path를 선언한다.
MediaRecorder mediaRecorder; //녹음을 도와주는 객체
String path = "";

경로 가져오기. 외부저장소 경로를 가져왔다. 기본으로 저장되는 파일네임은 audio.3gp가 될 것이다.
//기기마다 경로가 다르기 때문에 외부저장소 경로를 가져온다 / 없으면 내부저장소 경로를 가져옴
path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/audio.3gp"; //녹음저장확장자 3gp

녹음 환경설정을 해준다. 녹음중에는 정지버튼만 활성화된다.
btn_record.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
btn_record.setEnabled(false); //두번 누를 수 있으니까
btn_play.setEnabled(false);
btn_stop.setEnabled(true);

mediaRecorder = new MediaRecorder();
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); //마이크로 녹음하겠다
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); //저장파일 형식 녹음파일은 3gp로 저장
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); //인코딩 방식설정
mediaRecorder.setOutputFile(path); //경로설정
}
});

녹음을 시작한다.
try {
mediaRecorder.prepare(); //녹음을 준비함 : 지금까지의 옵션에서 문제가 발생했는지 검사함
mediaRecorder.start();
Toast.makeText(getApplicationContext(), "녹음시작", Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
}


재생을 누르면, 정지버튼만 활성화되며 path경로를 찾아가 audio.3gp를 재생한다.

btn_play.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
btn_record.setEnabled(false);
btn_play.setEnabled(false);
btn_stop.setEnabled(true);

mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDataSource(path);
mediaPlayer.prepare();
mediaPlayer.start();
} catch (IOException e) {
e.printStackTrace();
}
}
});

위 코드로는 재생이 끝나면 다시 녹음할 수가 없고, 앱을 재실행해야만 한다.
재생이 끝나면 다시 버튼이 재활성화되도록 쓰레드를 추가했다.

Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
if(msg.arg1==1){
btn_record.setEnabled(true);
btn_play.setEnabled(true);
btn_stop.setEnabled(false);
}
}
};

public class myThread implements Runnable{

@Override
public void run() {
while(true){
if(!mediaPlayer.isPlaying()) {
mediaPlayer.stop();
mediaPlayer=null;

Message msg = new Message();
msg.arg1=1;
handler.sendMessage(msg);
return;
}
}
}
}


전체코드
package com.example.pc_20.record;

import android.Manifest;
import android.content.pm.PackageManager;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import java.io.IOException;

public class MainActivity extends AppCompatActivity {

Button btn_record;
Button btn_play;
Button btn_stop;
MediaRecorder mediaRecorder; //녹음을 도와주는 객체
MediaPlayer mediaPlayer; //재생을 위한 객체

String path = "";
boolean isRecording = false; //녹음중인지 아닌지

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

//기기마다 경로가 다르기 때문에 외부저장소 경로를 가져온다 / 없으면 내부저장소 경로를 가져옴
path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/audio.3gp"; //녹음저장확장자 3gp

btn_record = findViewById(R.id.btn_record);
btn_play = findViewById(R.id.btn_play);
btn_stop = findViewById(R.id.btn_stop);

//권한승인여부 확인후 메시지 띄워줌(둘 중 하나라도)
if(ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED
|| ActivityCompat.checkSelfPermission(getApplicationContext(),Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){

ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.RECORD_AUDIO, Manifest.permission.WRITE_EXTERNAL_STORAGE},0);
}

//마이크가 있는지 없는지 확인
if(getPackageManager().hasSystemFeature(PackageManager.FEATURE_MICROPHONE)) { //현재 하드웨어 정보를 가져옴
btn_play.setEnabled(false); //활성화 / 비활성화
btn_stop.setEnabled(false);
btn_record.setEnabled(true);
}else{
btn_play.setEnabled(false);
btn_stop.setEnabled(false);
btn_record.setEnabled(false);
}

btn_record.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
btn_record.setEnabled(false); //두번 누를 수 있으니까
btn_play.setEnabled(false);
btn_stop.setEnabled(true);

isRecording = true;

mediaRecorder = new MediaRecorder();
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); //마이크로 녹음하겠다
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); //저장파일 형식 녹음파일은 3gp로 저장
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); //인코딩 방식설정
mediaRecorder.setOutputFile(path); //경로설정

try {
mediaRecorder.prepare(); //녹음을 준비함 : 지금까지의 옵션에서 문제가 발생했는지 검사함
mediaRecorder.start();
Toast.makeText(getApplicationContext(), "녹음시작", Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
}
}
});

btn_stop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
btn_record.setEnabled(true);
btn_play.setEnabled(true);
btn_stop.setEnabled(false);

if(isRecording){
mediaRecorder.stop();
mediaRecorder = null;
isRecording=false;
Toast.makeText(getApplicationContext(), "녹음중지", Toast.LENGTH_LONG).show();

}else{
mediaPlayer.stop();
mediaPlayer=null;
Toast.makeText(getApplicationContext(), "재생중지", Toast.LENGTH_LONG).show();
}


}
});

btn_play.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
btn_record.setEnabled(false);
btn_play.setEnabled(false);
btn_stop.setEnabled(true);

mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDataSource(path);
mediaPlayer.prepare();
mediaPlayer.start();

Thread thread = new Thread(new myThread());
thread.start();

} catch (IOException e) {
e.printStackTrace();
}
}
});
}

Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
if(msg.arg1==1){
btn_record.setEnabled(true);
btn_play.setEnabled(true);
btn_stop.setEnabled(false);
}
}
};

public class myThread implements Runnable{

@Override
public void run() {
while(true){
if(!mediaPlayer.isPlaying()) {
mediaPlayer.stop();
mediaPlayer=null;

Message msg = new Message();
msg.arg1=1;
handler.sendMessage(msg);
return;
}
}
}
}

}