我正在爲iPhone編寫基於VOIP的應用程序。我遇到了一個奇怪的問題,當用戶按下屏幕時音頻出現故障,當您按下電話本身的音量增大/減小按鈕時,也會發生這種情況。經過幾天的調試,我發現它與我的循環緩衝區有關。我換礦的一個位置:iOS UI導致我的音頻流出現故障
http://atastypixel.com/blog/a-simple-fast-circular-buffer-implementation-for-audio-processing/
這一個不造成干擾,但等待時間幾乎比我的長4倍,我必須有最小的延遲和無法弄清楚怎麼回事與我的應用程序。
設置:
我跟着:http://www.stefanpopp.de/2011/capture-iphone-microphone/稍微使基本應用程序,但我有不同的設置/功能等我有了這個SC7314音頻處理器類的特性的視圖控制器,這個類具有用於可變循環緩衝區。在錄音回調中,我發送數據,這很好。在CFSocket回調中,我將數據從網絡添加到此緩衝區,然後回放回調從此緩衝區中提取數據並將其傳遞到系統。
在回放過程中的某個時刻,如果用戶按下觸發UI事件,它將全部進入地獄,這種奇怪的數據顯示出來。我猜測它是一種線程問題,但我在這方面很少或沒有經驗。我會很感激任何幫助。這裏是相對的代碼:
網絡回調 - 將數據添加到緩衝液:
static void addDataToBuffer(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *data, void *info)
{
AudioUnitCBufferProduce(&audioProcessor->auCBuffer, (uint8_t*)[(__bridge NSData *)data bytes], [(__bridge NSData *)data length]);
}
音頻單元重放 - 複製數據形成緩衝和放置到「targetBuffer」,其指向ioData:
static OSStatus playbackCallback(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData)
{
uint8_t *targetBuffer = (uint8_t*)ioData->mBuffers[0].mData;
AudioUnitCBufferConsume(&audioProcessor->auCBuffer, targetBuffer, inNumberFrames);
return noErr;
}
緩衝區的init:
void AudioUnitCBufferInit(AudioUnitCBuffer *b)
{
// create array of bytes of length specified, fill with silence
uint8_t buffer[2048];
for(int i = 0; i < 2048; i++)
{
buffer[i] = 0xd5;
}
// init buffer elements
b->buffer = buffer;
b->consumer = buffer;
b->producer = buffer;
b->length = 2048;
}
緩衝區生產者/消費者:
這是這麼寫的,你在一個函數指針傳遞,然後該指針被填充數據,應該有沒有數據的指針將充滿ALAW十六進制值用於靜音。這樣可以使音頻單元代碼保持較小,因爲緩衝區確保它始終爲其提供數據。這比複製到臨時的某個地方更快,然後memcpy將其存儲到上面鏈接使用的緩衝區中,並且速度遠遠低於我的需要。
inline static void AudioUnitCBufferProduce(AudioUnitCBuffer *b, uint8_t *bytes, int32_t len)
{
//printf("\n\ninside producer: len %i \n\n", len);
while(len--)
{
// if producer catches up with consumer, skip a byte
if (b->producer+1 == b->consumer)
{
//printf("b->producer+1 == b->consumer == continue \n");
continue;
}
else
{
//printf("b->producer+1 != b->consumer == add byte \n");
*b->producer = *bytes++;
b->producer++;
if(b->producer == &b->buffer[b->length-1])
{
//printf("\n\nproducer == end, skipping \n\n");
b->producer = b->buffer;
}
}
}
}
inline static void AudioUnitCBufferConsume(AudioUnitCBuffer *b, uint8_t *bytes, int32_t len)
{
while(len--)
{
// if producer catches up with consumer, skip a byte
if (b->consumer == b->producer)
{
*bytes++ = 0xd5;
}
else
{
*bytes++ = *b->consumer;
b->consumer++;
if(b->consumer == &b->buffer[b->length-1])
{
b->consumer = b->buffer;
}
}
}
}
是您的插座回調安排在哪個線程?嘗試後臺線程。 – ZhangChn
使用GCDAsync我讓它在後臺線程上運行,沒有任何變化。使用它的cf主要運行。這點雖然它工作正常,如果我在鏈接中使用循環緩衝區意味着它不是網絡。只有那個緩衝區的延遲差不多是4倍 –
你是如何確定你的循環緩衝區大小的?它是否大於N個傳入數據包(對於某些N),並預先填充以允許到達時間抖動?如何處理接收音頻採樣率與發送音頻採樣率或網絡數據率略有不同?由於音頻採樣率時鐘不同步,速度更快還是更慢? – hotpaw2