【iOS筆記】AudioUnit錄音異常(聽起來類似於丟幀丟資料)
阿新 • • 發佈:2018-12-14
在做語音識別專案時候發現一個問題,識別率奇低無比……所以就把原始音訊資料錄下來,發現音訊丟資料。
實驗機器:iPhone6s iOS12
問題程式碼如下:
OSStatus AudioUnitInput::RecordCallback( void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) { int count = 0; OSStatus status = noErr; if (inNumberFrames > 0) { AudioUnitInput *ars = (AudioUnitInput *)inRefCon; status = AudioUnitRender(ars->mRecordUnit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ars->recordBufList); } else { NSLog(@"inNumberFrames is %d", inNumberFrames); } return noErr; } ………… ………… ………… bufferByteSize = ComputeRecordBufferSize(&mRecordFormat, kBufferDurationSeconds); NSLog(@"Compute recorder %f seconds data buffer size is %d.", kBufferDurationSeconds, bufferByteSize); recordBufList = (AudioBufferList *)malloc(sizeof(AudioBufferList)); recordBufList->mNumberBuffers = 1; recordBufList->mBuffers[0].mNumberChannels = 1; recordBufList->mBuffers[0].mDataByteSize = bufferByteSize * 2; recordBufList->mBuffers[0].mData = malloc(bufferByteSize * 2);
以上程式碼可以看出,AudioBufferList我是在初始化的時候進行了malloc,然後在recordCallback中進行資料獲取。理論上這樣是沒問題的,很多教程這麼寫。mData的malloc大小是通過計算的,bufferByteSize是20ms 16k 16bit的大小,即640。但是我發現recordCallback中frame數為341,即682位元組,所以我就malloc了640的兩倍。這裡還有一個很好玩的點,就是如果我把playout開起來進行echo,在playCallback進行資料儲存,這樣獲取的資料就非常正常。
以下給出兩種解決方法:
1. 把malloc放在recordCallback中進行
OSStatus AudioUnitInput::RecordCallback( void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) { int count = 0; OSStatus status = noErr; UInt16 numSamples = inNumberFrames*1; if (inNumberFrames > 0) { AudioUnitInput *ars = (AudioUnitInput *)inRefCon; ars->recordBufList = (AudioBufferList *)malloc(sizeof(AudioBufferList)); ars->recordBufList->mNumberBuffers = 1; ars->recordBufList->mBuffers[0].mNumberChannels = 1; ars->recordBufList->mBuffers[0].mDataByteSize = numSamples * sizeof(UInt16); ars->recordBufList->mBuffers[0].mData = malloc(numSamples * sizeof(UInt16)); status = AudioUnitRender(ars->mRecordUnit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ars->recordBufList); } else { NSLog(@"inNumberFrames is %d", inNumberFrames); } return noErr; }
2.還有一種是不用malloc了,也是在recordCallback中分配一個AudioBufferList
OSStatus AudioUnitInput::RecordCallback(
void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData)
{
int count = 0;
OSStatus status = noErr;
AudioBufferList bufferList;
UInt16 numSamples = inNumberFrames*1;
UInt16 samples[numSamples];
memset(&samples, 0, sizeof(samples));
bufferList.mNumberBuffers = 1;
bufferList.mBuffers[0].mData = samples;
bufferList.mBuffers[0].mNumberChannels = 1;
bufferList.mBuffers[0].mDataByteSize = numSamples * sizeof(UInt16);
if (inNumberFrames > 0) {
AudioUnitInput *ars = (AudioUnitInput *)inRefCon;
status = AudioUnitRender(ars->mRecordUnit,
ioActionFlags,
inTimeStamp,
inBusNumber,
inNumberFrames,
&bufferList);
} else {
NSLog(@"inNumberFrames is %d", inNumberFrames);
}
return noErr;
}
具體為什麼還不是很清楚,難道是堆疊的問題?
感謝