당신이 고려해야합니다 안드로이드에 내재 된 약간의 지연이 있습니다 ...
원형 버퍼를 만들기 . 얼마나 큰지는 중요하지 않습니다. N 0 샘플만큼 충분합니다. 이제 N '0'샘플로 작성하십시오.
N은 (초 단위 지연) * (샘플 속도 (헤르쯔))입니다.
예 : 16kHz의 스테레오와 200 밀리 :
0.2 초 * 16000Hz * (2 개 채널) = 3200 개 * 2 개 샘플 = 6400 개 샘플
당신은 아마 너무 PCM 데이터로 작업 될 것입니다 16 바이트가 아닌 바이트를 사용하십시오.
올바른 양의 0으로 버퍼를 채운 후 마이크에서 데이터를 채우면서 스피커에 대한 데이터를 읽기 시작합니다.
PCM들 Fifo :
그들은 단지, 바이트 배열을 처리 바이트 대신 짧은을 위해 FIFO를 수정, 그래서 만약
public class PcmQueue
{
private short mBuf[] = null;
private int mWrIdx = 0;
private int mRdIdx = 0;
private int mCount = 0;
private int mBufSz = 0;
private Object mSync = new Object();
private PcmQueue(){}
public PcmQueue(int nBufSz)
{
try {
mBuf = new short[nBufSz];
} catch (Exception e) {
Log.e(this.getClass().getName(), "AudioQueue allocation failed.", e);
mBuf = null;
mBufSz = 0;
}
}
public int doWrite(final short pWrBuf[], final int nWrBufIdx, final int nLen)
{
int sampsWritten = 0;
if (nLen > 0) {
int toWrite;
synchronized(mSync) {
// Write nothing if there isn't room in the buffer.
toWrite = (nLen <= (mBufSz - mCount)) ? nLen : 0;
}
// We can definitely read toWrite shorts.
while (toWrite > 0)
{
// Calculate how many contiguous shorts to the end of the buffer
final int sampsToCopy = Math.min(toWrite, (mBufSz - mWrIdx));
// Copy that many shorts.
System.arraycopy(pWrBuf, sampsWritten + nWrBufIdx, mBuf, mWrIdx, sampsToCopy);
// Circular buffering.
mWrIdx += sampsToCopy;
if (mWrIdx >= mBufSz) {
mWrIdx -= mBufSz;
}
// Increment the number of shorts sampsWritten.
sampsWritten += sampsToCopy;
toWrite -= sampsToCopy;
}
synchronized(mSync) {
// Increment the count.
mCount = mCount + sampsWritten;
}
}
return sampsWritten;
}
public int doRead(short pcmBuffer[], final int nRdBufIdx, final int nRdBufLen)
{
int sampsRead = 0;
final int nSampsToRead = Math.min(nRdBufLen, pcmBuffer.length - nRdBufIdx);
if (nSampsToRead > 0) {
int sampsToRead;
synchronized(mSync) {
// Calculate how many shorts can be read from the RdBuffer.
sampsToRead = Math.min(mCount, nSampsToRead);
}
// We can definitely read sampsToRead shorts.
while (sampsToRead > 0)
{
// Calculate how many contiguous shorts to the end of the buffer
final int sampsToCopy = Math.min(sampsToRead, (mBufSz - mRdIdx));
// Copy that many shorts.
System.arraycopy(mBuf, mRdIdx, pcmBuffer, sampsRead + nRdBufIdx, sampsToCopy);
// Circular buffering.
mRdIdx += sampsToCopy;
if (mRdIdx >= mBufSz) {
mRdIdx -= mBufSz;
}
// Increment the number of shorts read.
sampsRead += sampsToCopy;
sampsToRead -= sampsToCopy;
}
// Decrement the count.
synchronized(mSync) {
mCount = mCount - sampsRead;
}
}
return sampsRead;
}
}
그리고 FIFO에 대한 수정 코드, ... 나는 TargetDataLine를 /은 SourceDataLine와 경험이 없다.
private int mBufferSize; // 256
private TargetDataLine mLineOutput;
private SourceDataLine mLineInput;
public void run() {
... creating the DataLines and getting the lines from AudioSystem ...
// short buffer for audio
short[] data = new short[256];
final int emptySamples = (int)(44100.0 * 0.2);
final int bufferSize = emptySamples*2;
PcmQueue pcmQueue = new PcmQueue(bufferSize);
// Create a temporary empty buffer to write to the PCM queue
{
short[] emptyBuf = new short[emptySamples];
Arrays.fill(emptyBuf, (short)emptySamples);
pcmQueue.doWrite(emptyBuf, 0, emptySamples);
}
// start recording and playing back
while (running) {
mLineOutput.read(data, 0, mBufferSize);
pcmQueue.doWrite(data, 0, mBufferSize);
pcmQueue.doRead(data, 0, mBufferSize);
mLineInput.write(data, 0, mBufferSize);
}
... closing the lines and exiting ...
}
사소한 질문 : 아마도 오디오 API에서 이중 버퍼링이 발생했을 것입니다.재생시 틈이 생길 위험이있는 다른 것이 있어야합니다. :) –
음, 정말 합리적이고 예쁜 청초한 소리. 고마워요. – gtRfnkN
MusiGenesis의 제안을 먼저 시도해 보겠습니다. 문제가 생기면 FIFO로 광산을 시도하고 더 작은 버퍼를 사용하십시오. 나는 안드로이드로만 작업 했으므로 어떤 종류의 오디오 레이어를 'Java와 MusiGenesis'의 제안이 잘 작동하는지 확실하지 않습니다. FIFO에 대한 코드를 곧 게시 할 예정입니다. –