我正在为 iPhone 编写一个基于 VOIP 的应用程序。我遇到了一个奇怪的问题,当用户按下屏幕时音频出现故障,当您按下手机本身的音量增大/减小按钮时也会发生这种情况。经过几天的调试,我发现它与我的循环缓冲区有关。我在这里换了一个:
http://atastypixel.com/blog/a-simple-fast-circular-buffer-implementation-for-audio-processing/
这不会导致故障,但延迟比我的要长近 4 倍,我必须有最小的延迟并且无法弄清楚我的应用程序发生了什么。
设置:
我跟着: http: //www.stefanpopp.de/2011/capture-iphone-microphone/有点制作基本应用程序,但我有不同的设置/功能等。我有一个视图控制器,它有这个 audioProcessor 类的属性,这个类有一个用于循环缓冲区的变量。在录制回调中我发送数据,这一切都很好。在 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]);
}
音频单元播放 - 从缓冲区复制数据并放入指向 ioData 的“targetBuffer”:
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;
}
缓冲区初始化:
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;
}
}
}
}