1、關于AudioUnit
Audio Unit 是iOS系統音頻架構的最底層了,這一層架構是最接近硬體層的,也是開發者目前能操作最的層的API架構了。
Audio Unit
這裡先解釋一下DSP(digital signal processing)數字信号處理,音頻信号是需要通過裝置采樣之後變成的數字信号,以友善資料的傳輸和記錄。目前最常用的是PCM格式的音頻資料信号,因為這種高保真的信号友善後續的處理,還有就是它保留了資料的完整性。
2、關于音頻流參數
1、采樣率 每秒鐘采得聲音樣本的次數,聲音是一種能量波,有振幅和頻率,人的耳朵可以聽到的頻率在20-Hz~20kHz之間的聲波,是以采樣率越高,擷取的到的頻率資訊就更為豐富,由于人耳的分辨率很有限,太高的頻率并不能分辨出來。22050 的采樣頻率是常用的,44100已是CD音質,超過48000或96000的采樣對人耳已經沒有意義。
常用的采樣率:
8000 Hz - 電話所用采樣率
22050 Hz - 無線電廣播所用采樣率
32000 Hz - miniDV 數位視訊 camcorder、DAT (LP mode)所用采樣率
44100 Hz - 音頻 CD, 也常用于 MPEG-1 音頻(VCD,SVCD,MP3)所用采樣率
47250 Hz - 商用 PCM 錄音機所用采樣率
48000 Hz - miniDV、數字電視、DVD、DAT、電影和專業音頻所用的數字聲音所用采樣率
50000 Hz - 商用數字錄音機所用采樣率
96000 Hz或者 192000 Hz - DVD-Audio、一些 LPCM DVD 音軌、BD-ROM(藍CD光牒)音軌、和 HD-DVD (高清晰度 DVD)音軌所用所用采樣率
2、采樣位數 采樣位數,他是衡量聲音播到變化的一個參數,它的數值越大,分辨率就越高,錄制和回放的聲音就越接近真實。常見的聲霸卡主要有8位和16位兩種,如今市面上所有的主流産品都是16位及以上的聲霸卡。
每個采樣資料記錄的是振幅, 采樣精度取決于采樣位數的大小:
1 位元組(也就是8bit) 隻能記錄 256 個數, 也就是隻能将振幅劃分成 256 個等級;
2 位元組(也就是16bit) 可以細到 65536 個數, 這已是 CD 标準了;
4 位元組(也就是32bit) 能把振幅細分到 4294967296 個等級, 實在是沒必要了.
3、通道數 即聲音的通道的數目,目前使用較多的是單聲道和立體聲,相當于從多位置采集聲音。 4、比特率 每秒的傳輸速率(位速, 也叫比特率)。如705.6kbps 或 705600bps, 其中的 b 是 bit, ps 是每秒的意思,表示每秒705600bit的容量。不同的音頻格式編碼,對PCM都有一個壓縮比,是以比特率一般等于原始比特率/音頻壓縮比。 5、幀長 幀長記錄了一個聲音單元位元組為機關,其長度為:樣本長度 * 通道數 = 幀長 6、幀數 每秒資料分為都少幀: 幀長 * 幀數 * 8 = 比特率
3、Audio Unit 工作時的腦圖和流程圖
AudioUnit 涉及到的知識圖.png
整體的一個流程圖如下:
Audio Unit Flow.png
C++音視訊學習資料免費擷取方法:關注音視訊開發T哥,點選「連結」即可免費擷取2023年最新C++音視訊開發進階獨家免費學習大禮包!
4、使用流程
1、iOS 涉及音頻使用和會話都需要使用到 AudioSessionInitialize去初始化音頻會話對象。
// set audio session
NSError *error = nil;
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayback error:&error];
[audioSession setActive:YES error:&error];
2、配置音頻元件Audio Unit 并描述輸出的單元
//set audio component information
AudioComponentDescription audioDesc;
audioDesc.componentType = kAudioUnitType_Output;
audioDesc.componentSubType = kAudioUnitSubType_RemoteIO;
audioDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
audioDesc.componentFlags = 0;
audioDesc.componentFlagsMask = 0;
3、查找、建立對應的音頻輸出單元元件
AudioUnit audioUnit;
//set audio component information
AudioComponentDescription audioDesc;
audioDesc.componentType = kAudioUnitType_Output;
audioDesc.componentSubType = kAudioUnitSubType_RemoteIO;
audioDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
audioDesc.componentFlags = 0;
audioDesc.componentFlagsMask = 0;
//Finds the next component that matches a specified AudioComponentDescription structure after a specified audio component.
AudioComponent inputComponent = AudioComponentFindNext(NULL, &audioDesc);
//create a new instance of an audio component
AudioComponentInstanceNew(inputComponent, &audioUnit);
//audio property
UInt32 flag = 1;
if (flag) {
status = AudioUnitSetProperty(audioUnit,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Output,
OUTPUT_BUS,
&flag,
sizeof(flag));
}
4、配置對應需要播放的音頻資料格式内容
// format
AudioStreamBasicDescription outputFormat;
memset(&outputFormat, 0, sizeof(outputFormat));
outputFormat.mSampleRate = 44100; // 采樣率
outputFormat.mFormatID = kAudioFormatLinearPCM; // PCM格式
outputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; // 整形
outputFormat.mFramesPerPacket = 1; // 每幀隻有1個packet
outputFormat.mChannelsPerFrame = 1; // 聲道數
outputFormat.mBytesPerFrame = 2; // 每幀隻有2個byte 聲道*位深*Packet數
outputFormat.mBytesPerPacket = 2; // 每個Packet隻有2個byte
outputFormat.mBitsPerChannel = 16; // 位深
[self printAudioStreamBasicDescription:outputFormat];
status = AudioUnitSetProperty(audioUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
OUTPUT_BUS,
&outputFormat,
sizeof(outputFormat));
if (status) {
NSLog(@"AudioUnitSetProperty eror with status:%d", status);
}
5、指定播放源的相關資訊
// callback
AURenderCallbackStruct playCallback;
playCallback.inputProc = PlayCallback;
playCallback.inputProcRefCon = (__bridge void *)self;
AudioUnitSetProperty(audioUnit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input,
OUTPUT_BUS,
&playCallback,
sizeof(playCallback));
OSStatus result = AudioUnitInitialize(audioUnit);
6、給目标播放元件輸入播放内容
static OSStatus PlayCallback(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData) {
yourPlayerClass *player = (__bridge yourPlayerClass *)inRefCon;//這裡擷取之前初始化時配置給播放元件的類對象
// 這裡是靜音資料,需要播放更對内容可以往ioData->mBuffers輸入資料
for (int iBuffer = 0; iBuffer < ioData->mNumberBuffers; ++iBuffer) {
memset(ioData->mBuffers[iBuffer].mData, 0, ioData->mBuffers[iBuffer].mDataByteSize);
}
return noErr;
}
}
7、這裡想要補充說明一下 上面的配置和初始中,多次用到了AudioUnitSetProperty,這是一個設定音頻單元屬性的函數,它的幾個參數如下:
參數補充.png
上面用到了兩個宏定義 作用于設定AudioUnit的I/O口設定
#define INPUT_BUS 1
#define OUTPUT_BUS 0
原文連結:iOS 通過 Audio Unit 播放音頻資料 - 簡書