首先理清思路
我這邊使用AudioUnit錄音,AudioQueue播放
1、創建AudioUnit對象,并初始化設置參數等
2、創建AudioQueue對象,初始化并設置參數
3、在AudioUnit回調方法中獲取到采集到的數據,并將獲取到的數據喂給AudioQueue的容器中,并給它播放
思路是不是很清晰了??
需理解的重點
1、AudioQueue播放是從2-3個(最好3個)AudioQueueBufferRef類型的緩存中不停地讀取的。
代碼開始
1、使用AVAudioSession獲取音頻錄制播放權限,并激活
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
[[AVAudioSession sharedInstance] setActive:YES error:nil];
2、創建AudioUnit
AudioComponentInstanceNew(_audioComponment, &_audioUint);
3、設置AudioUint
AudioUnitSetProperty(_audioUint,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Input,
1,
&flagOne,
sizeof(flagOne));
AudioUnitSetProperty(_audioUint, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &asbd, sizeof(asbd));
AudioUnitSetProperty(_audioUint, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 1, &cb, sizeof(cb));
4、初始化/Start
AudioUnitInitialize(_audioUint);
AudioOutputUnitStart(_audioUint);
5、創建AudioQueue實例
AudioQueueNewOutput(&_asbd, BufferCallback, (__bridge void * _Nullable)(self), nil, nil, 0, &_audioQueue);
6、初始化音頻緩沖區,這3個音頻緩沖區地址不會改變,往里面填數據的時候,只是里面的數據變化而已(官方文檔表明地址不可改變)
//初始化音頻緩沖區
for (int i = 0; i < 3; i++) {
//創建buffer
result = AudioQueueAllocateBuffer(_audioQueue, 2048, &_audioQueueBuffers[i]);
if (result != noErr) {
NSLog(@"creat AudioQueue fail");
}
//初始化
memset(_audioQueueBuffers[i]->mAudioData, 0, 2048);
}
7、AudioUnit回調中處理數據
AudioUnitRender(vc->_audioUint, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, &bufferList);使用該函數來講數據填充到我們創建的bufferList中
便于后續處理
void *data = malloc(bufferList.mBuffers[0].mDataByteSize);
memcpy(data, bufferList.mBuffers[0].mData, bufferList.mBuffers[0].mDataByteSize);
//play
AudioQueueBufferRef audioBuffer = NULL;
if (vc->_index == 2) {
vc->_index = 0;
}
audioBuffer = vc->_audioQueueBuffers[vc->_index];
vc->_index ++;
audioBuffer->mAudioDataByteSize = bufferList.mBuffers[0].mDataByteSize;
memset(audioBuffer->mAudioData, 0, bufferList.mBuffers[0].mDataByteSize);
memcpy(audioBuffer->mAudioData, data, bufferList.mBuffers[0].mDataByteSize);
//將數據壓入AudioQueue播放緩存中
AudioQueueEnqueueBuffer(vc->_audioQueue, audioBuffer, 0, NULL);
free(data);
8、至于AudioQueue的回調,該demo中沒什么用,但是有個坑,我之前AudioQueue創建好,沒有使用AudioQueueEnqueueBuffer填充數據,該回調方法就不會走,我莫名其妙了好久。
demo的話:鏈接: https://pan.baidu.com/s/1hsmSY3a 密碼: 1631