OI UIint 實現錄製播放
1.描述音頻元件(kAudioUnitType_Output/kAudioUnitSubType_RemoteIO /kAudioUnitManufacturerApple)。
2.使用 AudioComponentFindNext(NULL, &descriptionOfAudioComponent) 獲得 AudioComponent。AudioComponent有點像生產 Audio Unit 的工廠。
3.使用 AudioComponentInstanceNew(ourComponent, &audioUnit) 獲得 Audio Unit 實例。
4.使用 AudioUnitSetProperty函數爲錄製和回放開啓IO。
5.使用 AudioStreamBasicDescription 結構體描述音頻格式,並使用AudioUnitSetProperty進行設置。
6.使用 AudioUnitSetProperty 設置音頻錄製與放播的回調函數。
7.分配緩衝區。
8.初始化 Audio Unit。
9.啓動 Audio Unit。
//第一步 創建unit 描述
AudioComponentDescription outputDescription = {0};
outputDescription.componentType = kAudioUnitType_Output;
outputDescription.componentSubType = kAudioUnitSubType_RemoteIO;
outputDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
outputDescription.componentFlags = 0;
outputDescription.componentFlagsMask = 0;
//第二步 用AudioComponentFindNext 獲得 AudioComponent
AudioComponent comp = AudioComponentFindNext(NULL, &outputDescription);
//第三步 使用 AudioComponentInstanceNew(ourComponent, &audioUnit) 獲得 Audio Unit 實例。
status = AudioComponentInstanceNew(comp, &audioUnit);
//第四步 使用 AudioUnitSetProperty函數爲錄製和回放開啓IO。(設置uint 爲 IOUnit)
//4.1 設置unit element 1 (輸入元素) kInputBus = 1
UInt32 flag = 1;
status = AudioUnitSetProperty(audioUnit,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Input,
kInputBus,
&flag,
sizeof(flag));
checkStatus(status);
//4.2 設置unit elementt 0(輸出元素) kOutputBus = 0
UInt32 flag2 = 0;// 1 是開啓 0是關閉
status = AudioUnitSetProperty(audioUnit,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Output,
kOutputBus,
&flag2,
sizeof(flag2));
checkStatus(status);
//第5步 使用 AudioStreamBasicDescription 結構體描述音頻格式,並使用AudioUnitSetProperty進行設置。
AudioStreamBasicDescription audioFormat;
audioFormat.mSampleRate = 44100.00; //每秒鐘採樣的次數
audioFormat.mFormatID = kAudioFormatLinearPCM;
audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
audioFormat.mFramesPerPacket = 1;//每個包有多少幀
audioFormat.mChannelsPerFrame = 1;//單聲道
audioFormat.mBitsPerChannel = 16;//mBitsPerChannel是數據大小,即採樣位深,
audioFormat.mBytesPerPacket = 2;//每一包有多少字節
audioFormat.mBytesPerFrame = 2;//每一幀有多少字節
//採樣率SampleRate: 每秒鐘採樣的次數
//幀frame:每一次採樣的數據對應一幀
//聲道數mChannelsPerFrame:人的兩個耳朵對統一音源的感受不同帶來距離定位,多聲道也是爲了立體感,每個聲道有單獨的採樣數據,所以多一個聲道就多一批的數據。
//從上至下是一個包含關係:每秒有SampleRate次採樣, 44100
//每次採樣一個frame, 1
//每個frame有mChannelsPerFrame個樣本, 1
//每個樣本有mBitsPerChannel這麼多數據 16
//5.1 給uint 設置採樣的數據格式
status = AudioUnitSetProperty(audioUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
kInputBus,
&audioFormat,
sizeof(audioFormat));
checkStatus(status);
status = AudioUnitSetProperty(audioUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
kOutputBus,
&audioFormat,
sizeof(audioFormat));
checkStatus(status);
//第6步 設置Unit 的callback 函數
// 設置聲音採集後的回調調函數。當microphone(麥克風)採集到數據時就是調用回調函數傳入數據。
AURenderCallbackStruct callbackStruct;
callbackStruct.inputProc = recordingCallback;
callbackStruct.inputProcRefCon = (__bridge void * _Nullable)(self);
status = AudioUnitSetProperty(audioUnit,
kAudioOutputUnitProperty_SetInputCallback,
kAudioUnitScope_Global,
kInputBus,//1
&callbackStruct,
sizeof(callbackStruct));
checkStatus(status);
// 設置聲音輸出回調函數。當speaker(揚聲器)需要數據時就會調用回調函數去獲取數據。它是 "拉" 數據的概念。
callbackStruct.inputProc = playbackCallback;
callbackStruct.inputProcRefCon = (__bridge void * _Nullable)(self);
status = AudioUnitSetProperty(audioUnit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Global,
kOutputBus,//0
&callbackStruct,
sizeof(callbackStruct));
checkStatus(status);