AudioRecord를 사용해서 메모리에서 Processing을 할려면
Read()함수를 사용할시, 하드웨어 접근으로 속도로 인해 빠른처리가 불가능한것 같습니다.
이때 callback함수를 사용하게 되면? read함수를 계속 읽어오는것보다 효율적이지 않을까요??
// 아래 소스는 외국 사이트로부터 참조하여 가지고 왔습니다.
// 제가 이를 올리는 것은 해답이 아니라 저 또한 콜백 함수가 필요하여
// 찾다가 올리는 것입니다.
// 그런데 제가 뭉럿을 잘못 했는지 알수가 없으나..
// 실행하면 예기치 못한 오류로 인해 중지가 된다는 메시지와 함께 원하는 콜백이 호출이 되지 않고 프로그램이 중지 됩니다.
// 외국 사이트의 개발자도 사실상 아래 소스와 거의 같게 된 것들을 참조 하였는데 알고 보니 저와 같은 유사한 사례로
// 도움을 청하는 것이더군요
// 혹시 이를 해결 한 분이 한국에 계신다면 도와주십시오...
// 하다 안되는 쓰레드로 돌릴 생각이긴하는데 , 그세 벨런스를 어떻게 가지고 가지도 고민스러워서...
// 콜뱃ㄱ이 필요한 것은 죽~ 녹음만 하면 그만이겠지만
// 녹음하면서 일정 불럭 단위의 소리를 가종한다거나 실시간 녹취(이경운 파일을 생성하여 기록하면 실시간으로 커지는 것을
보실수 있게죠? ) 또는 VOIP등이나 다른 매체로의 전송이 실시간으로 가능 하겠죠?
\// 근데 다른 곳에서 보니 이게 지원의 문제라고도 하고 , 안드로이드 겨우 입문한 입장에선 매우 난해한 분제에 봉착 했습니다.
//아님 MediaRecord로 해야 합니까? 거기에도 일정 블럭 단위로 소리 블럭을 취하는 방법이 있나요...
//어디 예제가 없으니 찾기가 어렵군요? 도와 주시면 제가 솔직히 돈을 좀 힘들고 술을 사드릴수 잇습니다.
// 커뮤니티도 좀더 심층적으로 그리고 아예 공개적으로 하였으면 해서요 도와 주세요?
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.util.Log;
public class AsyncAudioRecorder {
public static final int DEFAULT_SAMPLE_RATE = 8000;
private static final int DEFAULT_BUFFER_SIZE = 1000000;
private static final int CALLBACK_PERIOD = 500;// 500ms 0.5초
private AudioRecord recorder;
private int runningOffset = 0;
byte[] bytes = new byte[DEFAULT_BUFFER_SIZE];
/*
* 콜백 함수가 어던 일을 하는지를 프로그램한다.
* AudioRecord.OnRecordPositionUpdateListener 개체를 생성하면서 해당
* 루틴을 만든다.
*/
private AudioRecord.OnRecordPositionUpdateListener mNotification = new AudioRecord.OnRecordPositionUpdateListener() {
// 마킹된 위치에 도달시 자동 호출
//또는 주어진 시간 만큼 녹음 되는 효과...
@Override
public void onMarkerReached(AudioRecord argRecorder) {
try {
Log.d(this.getClass().getSimpleName(), "onMarkerReached Called");
int byteCount = argRecorder.read(bytes, runningOffset,
DEFAULT_BUFFER_SIZE);
/*runningOffset = runningOffset + byteCount;*/
/*
* 여기서 파일을 저장하고자 한다면 아마도
* 메모리를 문한정 으로 쓰고자ㅣ 한다면,
* 바로 해당 내용을 별개의 스래드등으로 해서 저장 로직을 돌리면 된다.
*/
Log.d(this.getClass().getSimpleName(),
"Bytes read: " + Integer.toString(byteCount));
} catch (Exception e) {
Log.e(this.getClass().getSimpleName(),
"error in onMarkerReached");
}
}
// 지정된 주기마다 호출
@Override
public void onPeriodicNotification(AudioRecord argRecorder) {
try {
Log.d(this.getClass().getSimpleName(),
"onPeriodicNotification Called");
int byteCount = argRecorder.read(bytes, runningOffset,
DEFAULT_BUFFER_SIZE);
/*runningOffset = runningOffset + byteCount;*/
/*
* 여기서 파일을 저장하고자 한다면 아마도
* 메모리를 문한정 으로 쓰고자ㅣ 한다면,
* 바로 해당 내용을 별개의 스래드등으로 해서 저장 로직을 돌리면 된다.
*/
Log.d(this.getClass().getSimpleName(),
"Bytes read: " + Integer.toString(byteCount));
} catch (Exception e) {
Log.e(this.getClass().getSimpleName(),
"error in onPeriodicNotification");
}
}
};
public AsyncAudioRecorder()
{
this(DEFAULT_SAMPLE_RATE);
}
public AsyncAudioRecorder(int sampleRate)
{
/*
* public AudioRecord(int audioSource,
* int sampleRateInHz,
* int channelConfig,
* int audioFormat, int bufferSizeInBytes) throws java.lang.IllegalArgumentException;
*/
//int sampleRate=16000;
try
{
recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, //audioSource를 마이크로 한다.
sampleRate, // 샘플링 레이트를(주기)를 지정한다.
AudioFormat.CHANNEL_IN_MONO, // 채널의 환경 정보를 CHANNEL_IN_MONO 마이크로부터 인입되는 것으로 모노음향이다.
AudioFormat.ENCODING_PCM_16BIT, //16비트 PCM 음원으로 녹취하라(엔코딩 규약 지정)
DEFAULT_BUFFER_SIZE); // 녹취 버퍼 사이지 지정
}
catch (IllegalArgumentException e)
{
e.printStackTrace();
}
int retval = recorder.setPositionNotificationPeriod(DEFAULT_SAMPLE_RATE);
//콜백 함수 mNotification로 지정한다.(리스너)
recorder.setRecordPositionUpdateListener(mNotification);
//콜백 홤수 호출에 대한 주기를 지정 한다.(500ms 0.5초)
Log.d("setPeriodNotificationPeriod",Integer.toString(retval));
//int notificationPeriod = recorder.getPositionNotificationPeriod(); // 콜백 함수 호출 주기 취득
//Log.d("getPeriodNotificationPeriod", Integer.toString(notificationPeriod));
// 특정 포지션의 마킹 즉 해당 위치까지 읽어 드리면
// 해당 콜백 함수 호출(비디오및 플래이어에서 트랙를 이용하여
// 지정하는 것...(단위는 ms일까)*/
retval = recorder.setNotificationMarkerPosition(1000);
Log.d("setNotificationMarkerPosition",Integer.toString(retval));
int notificationMarker = recorder.getNotificationMarkerPosition();
Log.d("getNotificationMarkerPosition", Integer.toString(notificationMarker));
// read once, doesn't help
// 최초의 블럭을 읽으므로서
// 데이터 블럭 소실을 막고, 리스너 가 동작 도리 시간적 여유를 준다.
int byteCount = recorder.read(bytes, runningOffset,
DEFAULT_BUFFER_SIZE);
/*runningOffset = runningOffset + byteCount;//혹시 읽어낸 데이터가 있다면
//그만큼의 메모리를 진전 시켜야 한다.*/
/*
* 여기서 파일을 저장하고자 한다면 아마도
* 메모리를 문한정 으로 쓰고자ㅣ 한다면,
* 바로 해당 내용을 별개의 스래드등으로 해서 저장 로직을 돌리면 된다.
*/
Log.d(this.getClass().getSimpleName(), "Bytes read: " + Integer.toString(byteCount));
}
public void start() {
try {
recorder.startRecording();
} catch (Exception e) {
Log.e(this.getClass().getSimpleName(),
"Error while starting the recording!");
}
}
public void stop() {
try {
recorder.stop();
recorder.release();
} catch (Exception e) {
Log.e(this.getClass().getSimpleName(),
"Error while starting the recording!");
}
}
}
그리고 해당 매소드를 기어들어가면 , Not Source Found라는 것이 이클립스에서 뜹니다. 아이~~~ 힘들다... ㄷ호와 주십시오
콜백 루틴 함수는 액티비티에서만 돌아가면, 해당 개체 또한 그러 하더군요...
치우한님.. 이소스 프로젝트 파일 공유 부탁 드립니다.
wav 녹음이 안되서 애 먹고 있습니다.
부탁 드릴게요. 미리 감사 드립니다.
agguu@lycos.co.kr