iOS使用AudioUnit/AudioQueue實現耳返功能

首先理清思路
我這邊使用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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容