반응형
private class AudioThread extends Thread {
// Sample rate must be one supported by Opus.
static final int SAMPLE_RATE = 8000;
// Number of samples per frame is not arbitrary,
// it must match one of the predefined values, specified in the standard.
static final int FRAME_SIZE = 160;
// 1 or 2
static final int NUM_CHANNELS = 1;
@Override
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_MORE_FAVORABLE);
//녹음용 버퍼 사이즈 구하기 및 버퍼 초기화
int minBufSize = AudioRecord.getMinBufferSize(SAMPLE_RATE,
NUM_CHANNELS == 1 ? AudioFormat.CHANNEL_IN_MONO : AudioFormat.CHANNEL_IN_STEREO,
AudioFormat.ENCODING_PCM_16BIT);
// initialize audio recorder
AudioRecord recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,
SAMPLE_RATE,
NUM_CHANNELS == 1 ? AudioFormat.CHANNEL_IN_MONO : AudioFormat.CHANNEL_IN_STEREO,
AudioFormat.ENCODING_PCM_16BIT,
minBufSize);
// init opus encoder
OpusEncoder encoder = new OpusEncoder();
encoder.init(SAMPLE_RATE, NUM_CHANNELS, OpusEncoder.OPUS_APPLICATION_VOIP);
// init audio track STREAM_VOICE_CALL을 STREAM_MUSIC으로 하면 스피커로 바뀐다
AudioTrack track = new AudioTrack(AudioManager.STREAM_VOICE_CALL,
SAMPLE_RATE,
NUM_CHANNELS == 1 ? AudioFormat.CHANNEL_OUT_MONO : AudioFormat.CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_16BIT,
minBufSize,
AudioTrack.MODE_STREAM);
// init opus decoder
OpusDecoder decoder = new OpusDecoder();
decoder.init(SAMPLE_RATE, NUM_CHANNELS);
// start
recorder.startRecording();
track.play();
byte[] inBuf = new byte[FRAME_SIZE * NUM_CHANNELS * 2];
byte[] encBuf = new byte[1024];
short[] outBuf = new short[FRAME_SIZE * NUM_CHANNELS];
try {
while (!Thread.interrupted()) {
// Encoder must be fed entire frames.
int to_read = inBuf.length;
int offset = 0;
while (to_read > 0) {
int read = recorder.read(inBuf, offset, to_read);
if (read < 0) {
throw new RuntimeException("recorder.read() returned error " + read);
}
to_read -= read;
offset += read;
}
int encoded = encoder.encode(inBuf, FRAME_SIZE, encBuf);
Log.v(TAG, "Encoded " + inBuf.length + " bytes of audio into " + encoded + " bytes");
byte[] encBuf2 = Arrays.copyOf(encBuf, encoded);
int decoded = decoder.decode(encBuf2, outBuf, FRAME_SIZE);
Log.v(TAG, "Decoded back " + decoded * NUM_CHANNELS * 2 + " bytes");
track.write(outBuf, 0, decoded * NUM_CHANNELS);
}
} finally {
recorder.stop();
recorder.release();
track.stop();
track.release();
}
}
}
반응형
위의 소스코드는 Opus 오픈 소스를 가져왔으며 MainActivity에 작성되어 있는 AudioThread 부분이다. 내가 필요했던 건 목소리가 스피커폰으로 출력이 되게끔 하는 것. 그러기 위해서는 위의 소스코드중 이 부분을 변경해야 한다.
// init audio track STREAM_VOICE_CALL을 STREAM_MUSIC으로 하면 스피커로 바뀐다
AudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC,
SAMPLE_RATE,
NUM_CHANNELS == 1 ? AudioFormat.CHANNEL_OUT_MONO : AudioFormat.CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_16BIT,
minBufSize,
AudioTrack.MODE_STREAM);
STREAM_MUSIC은 스피커로 출력해주는 것을 말하며 다른 방법으로는 AudioManger 객체를 선언해서 하는 방법도 있는데, 나는 저런 방식으로 되어 있어서 저렇게 변경을 했다.
또 출력해주는 부분이 AudioTrack이라는 걸 알았으며, AudioRecord는 말 그대로 녹음을 하는 것이다. 즉 입력을 하는 부분이라고 할 수 있다.
스피커 출력을 하고, 마이크로 말하면, Example 코드는 말하는 걸 그대로 돌려주는 TalkBack이라 에코가 생기게 된다. 이러한 에코를 방지하기 위해선, 어차피 서버로 값을 주고 받을 것이기 때문에,
입력을 AudioRecord recorder = new AudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION, 으로 변경을 했다. 사실 맞는지 아닌지 모르지만
그래들 문제로 부터 시작된 오늘 하루 여정이 너무 길었다 ㅠㅠ
반응형
'언어 공부 > Android' 카테고리의 다른 글
[Android/Java] 그냥 UI를 변경하려고 하는데 오류는 왜 나오는걸까 ? - Thread Error (0) | 2022.07.21 |
---|---|
[Android] Nvidia Jetson Nano에 Android 올리기 (AOSP) (0) | 2021.01.06 |
[Android] Retrofit2, Rxjava2, OkHttp에 대해서 알아보자 (0) | 2020.09.29 |
[Android/JAVA] Adapter ..LayoutInflater.. ViewHolder 어렵다.. (0) | 2020.09.21 |
[[Android/JAVA]] observe.. 문자열 Resource.. (0) | 2020.09.18 |
댓글