iOS 通過 Audio Unit 播放音頻數(shù)據(jù)

關(guān)于AudioUnit

Audio Unit 是iOS系統(tǒng)音頻架構(gòu)的最底層了,這一層架構(gòu)是最接近硬件層的,也是開發(fā)者目前能操作最的層的API架構(gòu)了。


Audio Unit

這里先解釋一下DSP(digital signal processing)數(shù)字信號處理,音頻信號是需要通過設(shè)備采樣之后變成的數(shù)字信號,以方便數(shù)據(jù)的傳輸和記錄。目前最常用的是PCM格式的音頻數(shù)據(jù)信號,因為這種高保真的信號方便后續(xù)的處理,還有就是它保留了數(shù)據(jù)的完整性。

關(guān)于音頻流參數(shù)

1、采樣率
每秒鐘采得聲音樣本的次數(shù),聲音是一種能量波,有振幅和頻率,人的耳朵可以聽到的頻率在20-Hz~20kHz之間的聲波,所以采樣率越高,獲取的到的頻率信息就更為豐富,由于人耳的分辨率很有限,太高的頻率并不能分辨出來。22050 的采樣頻率是常用的,44100已是CD音質(zhì),超過48000或96000的采樣對人耳已經(jīng)沒有意義。

常用的采樣率:

8000 Hz - 電話所用采樣率
22050 Hz - 無線電廣播所用采樣率
32000 Hz - miniDV 數(shù)碼視頻 camcorder、DAT (LP mode)所用采樣率
44100 Hz - 音頻 CD, 也常用于 MPEG-1 音頻(VCD,SVCD,MP3)所用采樣率
47250 Hz - 商用 PCM 錄音機(jī)所用采樣率
48000 Hz - miniDV、數(shù)字電視、DVD、DAT、電影和專業(yè)音頻所用的數(shù)字聲音所用采樣率
50000 Hz - 商用數(shù)字錄音機(jī)所用采樣率
96000 Hz或者 192000 Hz - DVD-Audio、一些 LPCM DVD 音軌、BD-ROM(藍(lán)光盤)音軌、和 HD-DVD (高清晰度 DVD)音軌所用所用采樣率

2、采樣位數(shù)
采樣位數(shù),他是衡量聲音播到變化的一個參數(shù),它的數(shù)值越大,分辨率就越高,錄制和回放的聲音就越接近真實。常見的聲卡主要有8位和16位兩種,如今市面上所有的主流產(chǎn)品都是16位及以上的聲卡。

 每個采樣數(shù)據(jù)記錄的是振幅, 采樣精度取決于采樣位數(shù)的大小:
1 字節(jié)(也就是8bit) 只能記錄 256 個數(shù), 也就是只能將振幅劃分成 256 個等級;
2 字節(jié)(也就是16bit) 可以細(xì)到 65536 個數(shù), 這已是 CD 標(biāo)準(zhǔn)了;
4 字節(jié)(也就是32bit) 能把振幅細(xì)分到 4294967296 個等級, 實在是沒必要了.

3、通道數(shù)
即聲音的通道的數(shù)目,目前使用較多的是單聲道和立體聲,相當(dāng)于從多位置采集聲音。
4、比特率
每秒的傳輸速率(位速, 也叫比特率)。如705.6kbps 或 705600bps, 其中的 b 是 bit, ps 是每秒的意思,表示每秒705600bit的容量。不同的音頻格式編碼,對PCM都有一個壓縮比,所以比特率一般等于原始比特率/音頻壓縮比。
5、幀長
幀長記錄了一個聲音單元字節(jié)為單位,其長度為:樣本長度 * 通道數(shù) = 幀長
6、幀數(shù)
每秒數(shù)據(jù)分為都少幀: 幀長 * 幀數(shù) * 8 = 比特率

Audio Unit 工作時的腦圖和流程圖

AudioUnit 涉及到的知識圖.png

整體的一個流程圖如下:


Audio Unit Flow.png

使用流程

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、查找、創(chuàng)建對應(yīng)的音頻輸出單元組件

 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、配置對應(yīng)需要播放的音頻數(shù)據(jù)格式內(nèi)容

 // 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; // 聲道數(shù)
    outputFormat.mBytesPerFrame    = 2; // 每幀只有2個byte 聲道*位深*Packet數(shù)
    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、指定播放源的相關(guān)信息

    // 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、給目標(biāo)播放組件輸入播放內(nèi)容


static OSStatus PlayCallback(void *inRefCon,
                             AudioUnitRenderActionFlags *ioActionFlags,
                             const AudioTimeStamp *inTimeStamp,
                             UInt32 inBusNumber,
                             UInt32 inNumberFrames,
                             AudioBufferList *ioData) {
    yourPlayerClass *player = (__bridge yourPlayerClass *)inRefCon;//這里獲取之前初始化時配置給播放組件的類對象
   // 這里是靜音數(shù)據(jù),需要播放更對內(nèi)容可以往ioData->mBuffers輸入數(shù)據(jù)
  for (int iBuffer = 0; iBuffer < ioData->mNumberBuffers; ++iBuffer) {
        memset(ioData->mBuffers[iBuffer].mData, 0, ioData->mBuffers[iBuffer].mDataByteSize);
    }
   return noErr;
  }
}

7、這里想要補(bǔ)充說明一下
上面的配置和初始中,多次用到了AudioUnitSetProperty,這是一個設(shè)置音頻單元屬性的函數(shù),它的幾個參數(shù)如下:


參數(shù)補(bǔ)充.png

上面用到了兩個宏定義 作用于設(shè)置AudioUnit的I/O口設(shè)置

#define INPUT_BUS 1
#define OUTPUT_BUS 0
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容