使用 ExtAudioFile 结合循环缓冲区读取数据时会出现故障
Glitches occur when data is read using ExtAudioFile in combination with a circular buffer
我正在尝试处理使用 ExtAudioFile
读取的音频数据。但是,当我尝试将此数据放入循环缓冲区时,我听到了一些故障。
在下面的示例代码中,我将数据从 "inBuffer" 直接传递到 "outBuffer"(都是 Michael Tyson 的 TPCircularBuffer
类型)。两个缓冲区的大小都是 10 x numberOfFrames * sizeof(float)
。客户端流格式是带有浮点样本的单声道。
为什么我什至没有处理任何数据就听到这些故障?如果没有循环缓冲区,声音流会很好。我做错了什么或者另一种方法会更好?
static OSStatus recordingCallback(
void* inRefCon,
AudioUnitRenderActionFlags* ioActionFlags,
const AudioTimeStamp* inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList* ioData){
PlayAudioFile* player = (__bridge PlayAudioFile*)inRefCon;
Info *info = (Info *)player.info;
ExtAudioFileRead(info->extAudioFile, &inNumberFrames, info->inputBuffer);
if (inNumberFrames == 0) {
ExtAudioFileSeek(info->extAudioFile, 0);
}
// Put data in circular buffer
TPCircularBufferProduceBytes(info->inBuffer, info->inputBuffer->mBuffers[0].mData, info->inputBuffer->mBuffers[0].mDataByteSize);
UInt32 frameSize = inNumberFrames*sizeof(float);
if (info->inBuffer->fillCount >= frameSize) {
int32_t availableBytes;
float *tail = TPCircularBufferTail(info->inBuffer, &availableBytes);
if (availableBytes > frameSize){
memcpy(info->tempBuffer, tail, frameSize);
TPCircularBufferConsume(info->inBuffer, frameSize);
// Currently, data is not processed but just put to the output buffer
TPCircularBufferProduceBytes(info->outBuffer, info->tempBuffer, frameSize);
}
}
return noErr;
}
static OSStatus renderCallback(
void* inRefCon,
AudioUnitRenderActionFlags* ioActionFlags,
const AudioTimeStamp* inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList* ioData){
PlayAudioFile* player = (__bridge PlayAudioFile*)inRefCon;
Info *info = (Info *)play.info;
for (int i=0; i < ioData->mNumberBuffers; i++) {
AudioBuffer buffer = ioData->mBuffers[i];
if (info->outBuffer->fillCount > ioData->mBuffers[0].mDataByteSize) {
int32_t availableBytes;
float *tail = TPCircularBufferTail(info->outBuffer, &availableBytes);
memcpy(buffer.mData, tail, buffer.mDataByteSize);
TPCircularBufferConsume(info->outBuffer, buffer.mDataByteSize);
/* Messaging is not used for this example
// Notify delegate
if ([player.delegate respondsToSelector:@selector(player:audioBuffer:bufferSize:)])
{
[player.delegate player:player
audioBuffer:buffer.mData
bufferSize:inNumberFrames];
}
*/
}
else {
memset((char*)ioData->mBuffers[i].mData, 0, ioData->mBuffers[i].mDataByteSize * info->clientFormat.mBytesPerFrame);
}
}
return noErr;
}
编辑
根据下面的答案,我通过在回调函数之外分配和释放内存以及增加循环缓冲区的大小来修改代码。不幸的是,声音仍然比没有循环缓冲区时差。这些故障还有其他原因吗?
不应在音频回调中分配或释放内存。也不应该发送 Objective C 消息。
渲染回调应始终将数据放入缓冲区列表缓冲区。但是您的代码缺少执行此操作的 else 语句。尝试更大的循环缓冲区并确保在开始渲染回调之前它已被充分预填充。
我正在尝试处理使用 ExtAudioFile
读取的音频数据。但是,当我尝试将此数据放入循环缓冲区时,我听到了一些故障。
在下面的示例代码中,我将数据从 "inBuffer" 直接传递到 "outBuffer"(都是 Michael Tyson 的 TPCircularBuffer
类型)。两个缓冲区的大小都是 10 x numberOfFrames * sizeof(float)
。客户端流格式是带有浮点样本的单声道。
为什么我什至没有处理任何数据就听到这些故障?如果没有循环缓冲区,声音流会很好。我做错了什么或者另一种方法会更好?
static OSStatus recordingCallback(
void* inRefCon,
AudioUnitRenderActionFlags* ioActionFlags,
const AudioTimeStamp* inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList* ioData){
PlayAudioFile* player = (__bridge PlayAudioFile*)inRefCon;
Info *info = (Info *)player.info;
ExtAudioFileRead(info->extAudioFile, &inNumberFrames, info->inputBuffer);
if (inNumberFrames == 0) {
ExtAudioFileSeek(info->extAudioFile, 0);
}
// Put data in circular buffer
TPCircularBufferProduceBytes(info->inBuffer, info->inputBuffer->mBuffers[0].mData, info->inputBuffer->mBuffers[0].mDataByteSize);
UInt32 frameSize = inNumberFrames*sizeof(float);
if (info->inBuffer->fillCount >= frameSize) {
int32_t availableBytes;
float *tail = TPCircularBufferTail(info->inBuffer, &availableBytes);
if (availableBytes > frameSize){
memcpy(info->tempBuffer, tail, frameSize);
TPCircularBufferConsume(info->inBuffer, frameSize);
// Currently, data is not processed but just put to the output buffer
TPCircularBufferProduceBytes(info->outBuffer, info->tempBuffer, frameSize);
}
}
return noErr;
}
static OSStatus renderCallback(
void* inRefCon,
AudioUnitRenderActionFlags* ioActionFlags,
const AudioTimeStamp* inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList* ioData){
PlayAudioFile* player = (__bridge PlayAudioFile*)inRefCon;
Info *info = (Info *)play.info;
for (int i=0; i < ioData->mNumberBuffers; i++) {
AudioBuffer buffer = ioData->mBuffers[i];
if (info->outBuffer->fillCount > ioData->mBuffers[0].mDataByteSize) {
int32_t availableBytes;
float *tail = TPCircularBufferTail(info->outBuffer, &availableBytes);
memcpy(buffer.mData, tail, buffer.mDataByteSize);
TPCircularBufferConsume(info->outBuffer, buffer.mDataByteSize);
/* Messaging is not used for this example
// Notify delegate
if ([player.delegate respondsToSelector:@selector(player:audioBuffer:bufferSize:)])
{
[player.delegate player:player
audioBuffer:buffer.mData
bufferSize:inNumberFrames];
}
*/
}
else {
memset((char*)ioData->mBuffers[i].mData, 0, ioData->mBuffers[i].mDataByteSize * info->clientFormat.mBytesPerFrame);
}
}
return noErr;
}
编辑 根据下面的答案,我通过在回调函数之外分配和释放内存以及增加循环缓冲区的大小来修改代码。不幸的是,声音仍然比没有循环缓冲区时差。这些故障还有其他原因吗?
不应在音频回调中分配或释放内存。也不应该发送 Objective C 消息。
渲染回调应始终将数据放入缓冲区列表缓冲区。但是您的代码缺少执行此操作的 else 语句。尝试更大的循环缓冲区并确保在开始渲染回调之前它已被充分预填充。