有在Android的一些固有的延遲,你應該考慮,但除了...
創建循環緩衝區。無論多大,只要它對於N 0個樣本來說足夠大。現在用N'0'樣本寫下來。
N在這種情況下是(以秒爲單位延遲)*(以赫茲爲單位的採樣率)。
實例:通過16kHz的立體聲的200ms:
0.2秒* * 16000,(2個通道)= 3200個* 2個樣品=樣品6400
你將有可能與PCM數據工作太,其是16-位,所以使用短而不是字節。
用適量的零填充緩衝區後,開始讀取揚聲器的數據,同時填充麥克風的數據。
PCM先進先出:
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的沒有經驗,所以如果他們只處理字節數組,修改的FIFO字節,而不是短期。
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下可能發生的雙緩衝怎麼樣?必須有其他一些存在播放間隙的風險。 :) – 2013-02-24 13:43:42
好吧,這聽起來合理,非常整潔。謝謝:) – gtRfnkN 2013-02-24 14:09:49
我會先嚐試MusiGenesis的建議,因爲它非常簡單。如果遇到問題,請嘗試使用FIFO並使用更小的緩衝區。我只和Android一起工作過,所以不知道你在純Java和MusiGenesis的建議下得到的音頻層可能工作得很好。我將很快發佈FIFO的代碼。 – 2013-02-24 15:20:36