多媒體音頻播放簡(jiǎn)單介紹

概述

基礎(chǔ)知識(shí)-音頻編解碼,音頻格式魏铅,音頻會(huì)話(huà)(session)

  • ios軟硬件音頻編解碼器
  • 音頻會(huì)話(huà)(Audio Sessions)

播放音頻

  • 使用iPod庫(kù)訪問(wèn)播放音頻項(xiàng)目
  • 使用系統(tǒng)聲音服務(wù)播放UI聲音效果或者調(diào)用震動(dòng)
  • 使用AVAudioPlayer 播放音樂(lè)更輕松
  • 使用音頻隊(duì)列服務(wù)播放控制聲音
  • 使用OpenAL播放定位聲音

音頻錄制

  • 使用AVAudioRecorder 類(lèi)錄制音頻
  • 使用Audio Queue Services 錄制

解析流式音頻

ios中的音頻單元支持

ios音頻最佳實(shí)戰(zhàn)

  • 使用音頻提示
  • ios的首先音頻格式

今天學(xué)習(xí)開(kāi)源框架LFLiveKit,看到音頻錄制的部分铣减,該部分是采用的AVFoundation.frame中AVAudio.framework框架來(lái)完成的趁俊。以前沒(méi)有接觸過(guò)這部分,因此這里摘錄出來(lái)仔細(xì)研究學(xué)習(xí)放椰。

首先想學(xué)習(xí)框架作烟,肯定官網(wǎng)是最佳的場(chǎng)所,我搜尋了下官方文檔砾医,找到這一點(diǎn)相關(guān)知識(shí)multimedia Programming guide拿撩。一點(diǎn)點(diǎn)學(xué)習(xí)嘛,先學(xué)會(huì)這塊再說(shuō)如蚜。

概述

基礎(chǔ)知識(shí)-音頻編解碼压恒,音頻格式,音頻會(huì)話(huà)(session)

ios的音頻開(kāi)發(fā)错邦,了解下ios設(shè)備的硬件和軟件架構(gòu)的有關(guān)知識(shí)是很必要的探赫。

ios軟硬件音頻編解碼器

為確保音頻的最佳性能和質(zhì)量,我們需要選擇正確的音頻格式和音頻編解碼器類(lèi)型撬呢。從ios3.0開(kāi)始伦吠,大多數(shù)音頻格式可以使用軟件編碼和解碼(錄制和播放)。軟件編碼器支持多個(gè)聲音的同時(shí)播放,但是需要大量的cpu開(kāi)銷(xiāo)讨勤。

硬件輔助解碼可以提供很好的性能箭跳,但是就不能支持同時(shí)播放多個(gè)聲音了晨另。如果我們需要在應(yīng)用程序中最大化視頻幀速率潭千,最小的cpu音頻開(kāi)銷(xiāo),那么我們需要使用未壓縮的音頻或者IMA4格式借尿,也可以使用硬件幫助解碼壓縮的音頻刨晴。

下表是ios設(shè)備上可用的播放音頻編解碼器。

Audio decoder/playback format Hardware-assisted decoding Software-based decoding
AAC (MPEG-4 Advanced Audio Coding) Yes Yes, starting in iOS 3.0
ALAC (Apple Lossless) Yes Yes, starting in iOS 3.0
HE-AAC (MPEG-4 High Efficiency AAC) Yes -
iLBC (internet Low Bitrate Codec, another format for speech) - Yes
IMA4 (IMA/ADPCM) - Yes
Linear PCM (uncompressed, linear pulse-code modulation) - Yes
MP3 (MPEG-1 audio layer 3) Yes Yes, starting in iOS 3.0
μ-law and a-law - Yes

通過(guò)上面的表格路翻,我們知道同時(shí)支持硬編碼和軟編碼的格式有aac alac 和 mp3.

使用硬件輔助編碼時(shí)狈癞,設(shè)備一次只能播放一種支持格式的單個(gè)實(shí)例。例如茂契,如果我們使用硬件編解碼器播放立體聲mp3音樂(lè)蝶桶,那么第二個(gè)同步mp3聲音將使用軟件編碼(硬件只能編碼一個(gè),)掉冶。同樣真竖,我們無(wú)法使用硬件同時(shí)編碼aac和alac格式音樂(lè)。

要是要要播放多種聲音厌小,或者在ipod在后臺(tái)播放音樂(lè)恢共,我們應(yīng)該使用線型PCM(未壓縮)或者IMA4(壓縮)音頻。

要了解運(yùn)行時(shí)設(shè)備上可用的硬件和軟件編解碼器璧亚。我們可以看kAudioFormatProperty_HardwareCodecCapabilities常量來(lái)了解讨韭。

如何確定在運(yùn)行時(shí)aac硬件編碼器的可用性。
ios4.0以及更高版本支持使用擴(kuò)展音頻文件和音頻轉(zhuǎn)換器api進(jìn)行硬件脫機(jī)編碼癣蟋。這就是硬編碼
注意 ios3.1 只支持?jǐn)U展音頻文件api透硝。
要檢查acc硬件編碼器的可用性,使用下列代碼

Boolean IsAACHardwareEncoderAvailable(void)
{
    Boolean isAvailable = false;
    OSStatus error;
    
    // get an array of AudioClassDescriptions for all installed encoders for the given format
    // the specifier is the format that we are interested in - this is 'aac ' in our case
    UInt32 encoderSpecifier = kAudioFormatMPEG4AAC;
    UInt32 size;
    
    error = AudioFormatGetPropertyInfo(kAudioFormatProperty_Encoders, sizeof(encoderSpecifier),
                                       &encoderSpecifier, &size);
    if (error) {
        printf("AudioFormatGetPropertyInfo kAudioFormatProperty_Encoders error %lu %4.4s\n", error, (char*)&error);
        return false;
        
    }
    
    UInt32 numEncoders = size / sizeof(AudioClassDescription);
    AudioClassDescription encoderDescriptions[numEncoders];
    error = AudioFormatGetProperty(kAudioFormatProperty_Encoders, sizeof(encoderSpecifier), &encoderSpecifier, &size, encoderDescriptions);
    if (error) {
        printf("AudioFormatGetProperty kAudioFormatProperty_Encoders error %lu %4.4s\n", error, (char*)&error); return false; }
    
    for (UInt32 i=0; i < numEncoders; ++i) {
        if (encoderDescriptions[i].mSubType == kAudioFormatMPEG4AAC &&
            encoderDescriptions[i].mManufacturer == kAppleHardwareAudioCodecManufacturer) isAvailable = true;
    }
    
    return isAvailable;
}
        

總結(jié)下ios如何支持單個(gè)或者多個(gè)播放音頻格式

  • 線型PCM 和IMA4(IMA/ADPCM) 我們可以在ios中同時(shí)播放多個(gè)線型的PCM或者IMA4 音樂(lè),而不會(huì)產(chǎn)生cpu 性能問(wèn)題疯搅。對(duì)于ILBC語(yǔ)音質(zhì)量格式以及 μ-law 和 a-law 壓縮格式也是一樣的濒生,當(dāng)用壓縮格式,需要檢查音質(zhì)以確保滿(mǎn)足需求秉撇。
  • AAC甜攀,HE-AAC,MP3和ALAC(Apple Lossless) 對(duì)AAC琐馆,HE-AAC规阀,MP3和ALAC(Apple Lossless)的播放可以在設(shè)備上使用高效的硬件輔助編碼,但這些編碼都共享一條硬件路徑瘦麸。因此谁撼,硬件編碼只能播放這些格式之一的單個(gè)實(shí)例。

AAC,HE-AAC厉碟,MP3和ALAC播放的單一硬件路徑對(duì)“播放”風(fēng)格應(yīng)用程序(如虛擬鋼琴)有影響喊巍。如果用戶(hù)正在ipod的應(yīng)用程序中播放這三種格式之一的歌曲,那么我們的應(yīng)用程序?qū)⑼ㄟ^(guò)軟編碼進(jìn)行編碼箍鼓。

下表記錄在ios設(shè)備上可用的錄制音頻編解碼器

Audio encoder/recording format Hardware-assisted encoding Software-based encoding
AAC (MPEG-4 Advanced Audio Coding) Yes, starting in iOS 3.1 for iPhone 3GS and iPod touch (2nd generation) Yes, starting in iOS 3.2 for iPad Yes, starting in iOS 4.0 for iPhone 3GS and iPod touch (2nd generation)
ALAC (Apple Lossless) - Yes
iLBC (internet Low Bitrate Codec, for speech) - Yes
IMA4 (IMA/ADPCM) - Yes
Linear PCM (uncompressed, linear pulse-code modulation) - Yes
μ-law and a-law - Yes

通過(guò)上表崭参,我們知道了錄制音頻,同時(shí)支持硬件和軟件編碼的之后aac格式編碼

音頻會(huì)話(huà)(Audio Sessions)

ios音頻會(huì)話(huà)api允許我們定義應(yīng)用程序的一般音頻行為款咖。相關(guān)api在 Audio Session Services Reference and AVAudioSession Class Reference何暮。這些使用這些api,可以完成下列對(duì)音頻的操作:

  • 設(shè)備靜音
  • 音頻是否在屏幕鎖定時(shí)停止
  • 當(dāng)音頻開(kāi)始的時(shí)候铐殃,其他音頻是否應(yīng)該繼續(xù)播放或者靜音海洼。

音頻會(huì)話(huà)api還會(huì)響應(yīng)用戶(hù)操作,例如插入或者播出耳機(jī)富腊,以及使用設(shè)備聲音硬件的事件坏逢,例如時(shí)鐘和日歷鬧鐘以及來(lái)電。

音頻會(huì)話(huà)的三個(gè)編程功能如下表

音頻會(huì)話(huà)功能 描述
設(shè)置categories category是標(biāo)示應(yīng)用程序的一組音頻行為的key赘被。通過(guò)設(shè)置category是整,我們可以向ios表明我們的音頻意圖,例如屏幕鎖定時(shí)我們的音頻是否應(yīng)該繼續(xù)帘腹。響應(yīng)中斷中描述的六個(gè)類(lèi)別贰盗。我們也可以微調(diào)某些category的行為,例如可以看 Use Modes to Specialize the Category.
處理中斷和路由更改 當(dāng)音頻中斷阳欲,中斷結(jié)束以及硬件音頻路由發(fā)生變化時(shí)舵盈,音頻會(huì)話(huà)會(huì)發(fā)布通知。通過(guò)這些通知球化,我們可以?xún)?yōu)雅的響應(yīng)較大音頻環(huán)境中的更改-例如由于來(lái)電而導(dǎo)致的中斷秽晚。更多細(xì)節(jié)可以看處理音頻硬件路由改變Audio Guidelines By App Type.
優(yōu)化硬件性能 我們可以查詢(xún)音頻會(huì)話(huà)以發(fā)現(xiàn)運(yùn)行的應(yīng)用程序的設(shè)備的特征,例如硬件采樣率筒愚,硬件通道數(shù)以及音頻輸入是否可用有關(guān)詳細(xì)細(xì)節(jié)可看Optimizing for Device Hardware.

有兩個(gè)用于處理音頻會(huì)話(huà)的接口:

我們可以混合和匹配AVFoundation和audio sessionServices中的音頻會(huì)話(huà)代碼-他們兩個(gè)是相互兼容的陆淀。

音頻會(huì)話(huà)帶有一些默認(rèn)行為考余,我們可以使用這些開(kāi)始開(kāi)發(fā)。

例如轧苫,使用默認(rèn)音頻會(huì)話(huà)時(shí)楚堤,當(dāng)自動(dòng)鎖定時(shí)間超時(shí)且屏幕鎖定時(shí),應(yīng)用程序中的音頻將停止。 如果要確保在屏幕鎖定的情況下繼續(xù)播放身冬,請(qǐng)?jiān)趹?yīng)用程序的初始化代碼中包含以下行:

NSError *setCategoryErr = nil;
NSError *activationErr  = nil;
[[AVAudioSession sharedInstance]
              setCategory: AVAudioSessionCategoryPlayback
                    error: &setCategoryErr];
[[AVAudioSession sharedInstance]
                setActive: YES
                    error: &activationErr];

AVAudioSessionCategoryPlayback category 確保當(dāng)屏幕鎖屏的時(shí)候可以繼續(xù)播放音頻衅胀。

如何處理來(lái)電或者時(shí)鐘以及日歷鬧鐘導(dǎo)致的中斷取決于我們使用的音頻技術(shù)。見(jiàn)下表

Audio technology How interruptions work
AV Foundation framework AVAudioPlayer和AVAudioRecorder類(lèi)為中斷開(kāi)始和結(jié)束提供委托方法酥筝。實(shí)現(xiàn)這些方法來(lái)更新用戶(hù)界面滚躯,并且我們可以在中斷后,回復(fù)暫停的播放樱哼。系統(tǒng)在中斷時(shí)會(huì)自動(dòng)的暫停播放和錄制哀九,并在恢復(fù)播放或者錄制時(shí)候重新激活音頻會(huì)話(huà)剿配。如果要在應(yīng)用程序啟動(dòng)時(shí)保存和恢復(fù)播放位置搅幅,請(qǐng)?jiān)谥袛嗪蛻?yīng)用程序退出時(shí)保存播放位置。
Audio Queue Services, I/O audio unit 我們可以通過(guò)該技術(shù)處理中斷呼胚。我們需要保存播放盒錄制位置茄唐,并且中斷結(jié)束后重新激活音頻會(huì)話(huà)。實(shí)現(xiàn)AVAudioSession中斷的委托代理方法或者編寫(xiě)監(jiān)聽(tīng)回調(diào)函數(shù)-通知
OpenAL 使用openAL 進(jìn)行播放蝇更,需要實(shí)現(xiàn)AVAudioSession中斷委托方法或編寫(xiě)中斷回調(diào)函數(shù)-與使用音頻隊(duì)列服務(wù)時(shí)一樣的沪编。這里需要注意的時(shí),委托或者回調(diào)必須重新管理openAL上下文
System Sound Services 用系統(tǒng)聲音服務(wù)播放的音樂(lè)在終端開(kāi)始時(shí)保持靜音年扩。如果終端結(jié)束蚁廓,他們可以自動(dòng)的再次使用。應(yīng)用程序不能影響使用此播放技術(shù)的聲音的中斷行為

每個(gè)ios應(yīng)用程序(極少數(shù)例外)都應(yīng)該主動(dòng)管理其音頻會(huì)話(huà)厨幻。有關(guān)如何執(zhí)行此操作的完整說(shuō)明相嵌,可以看這里Audio Session Programming Guide

播放音頻

本節(jié)主要介紹如何播放在 iPod library access, System Sound Services, Audio Queue Services, t AV Foundation framework和OpenAL.中聲音。

使用iPod庫(kù)訪問(wèn)播放音頻項(xiàng)目

在ios3.0開(kāi)始况脆,ipad 庫(kù)訪問(wèn)可以應(yīng)用程序播放用戶(hù)的歌曲饭宾,有聲讀物或者音頻播客。api設(shè)計(jì)使用基本播放非常簡(jiǎn)單格了,同時(shí)還支持高級(jí)搜索和播放控制看铆。

下圖展示應(yīng)用程序有兩種方法來(lái)檢索媒體項(xiàng)目。左側(cè)顯示的媒體項(xiàng)目選擇器是一個(gè)易于使用的預(yù)打包視圖控制器盛末,其行為類(lèi)似于內(nèi)置ipod應(yīng)用程序的音樂(lè)選擇界面弹惦。對(duì)于許多應(yīng)用來(lái)說(shuō),這已經(jīng)足夠了悄但。如果選擇器不能滿(mǎn)足我們的需求棠隐,那么就可以選擇右邊的medai query。他支持來(lái)自ipod庫(kù)的基于謂詞的項(xiàng)目規(guī)范算墨。


如何將媒體項(xiàng)目添加到應(yīng)用程序的完成實(shí)例宵荒,可以參考 *iPod Library Access Programming Guide。例子可以參考 AddMusic工程

使用系統(tǒng)聲音服務(wù)播放UI聲音效果或者調(diào)用震動(dòng)

想要播放用戶(hù)界面聲音效果(如按鈕點(diǎn)擊),或在支持他的設(shè)備上調(diào)用振動(dòng)报咳,請(qǐng)使用系統(tǒng)服務(wù)聲音服務(wù)侠讯。詳細(xì)講解在System Sound Services Reference。我們可以在 iOS Dev Center中找到簡(jiǎn)單的代碼暑刃。

注意:使用聲音系統(tǒng)服務(wù)播放的聲音不受使用音頻會(huì)話(huà)的配置限制厢漩。因此,我們無(wú)法使system sound services 音頻的行為和應(yīng)用程序中的其他音頻行為保持一致岩臣。這是避免將system sound services用于除預(yù)期用途之外的任何音頻的最重要原因溜嗜。

AudioServicesPlaySystemSound 函數(shù)能讓我們可以非常簡(jiǎn)單的播放簡(jiǎn)短的聲音文件。簡(jiǎn)單必定帶來(lái)一些限制架谎。我們的聲音文件必須是滿(mǎn)足下列要求:

  • 持續(xù)時(shí)間不能超過(guò)30s
  • 采用pcm 或者IMA4(IMA/ADPCM)格式
  • 打包在.caf .aif 或者 .wav文件中

此外炸宵,我們可以使用AudioServicesPlaySystemSound函數(shù)時(shí):

  • 聲音播放使用當(dāng)前系統(tǒng)音量叼耙,沒(méi)有可用的編程音量控制
  • 聲音立刻播放
  • 無(wú)法進(jìn)行循環(huán)和立體聲定位
  • 同時(shí)不放不可用:我們一次只能播放一種聲音

有個(gè)類(lèi)似的AudioServicesPlayAlertSound函數(shù)端铛,可以用來(lái)播放短聲音作為警報(bào)符相。如果用戶(hù)已將其設(shè)備配置為在“震動(dòng)設(shè)置”中的震動(dòng)丑慎,那么調(diào)用此功能除了播放聲音文件之外還會(huì)調(diào)用振動(dòng)哨毁。

注意:應(yīng)用程序無(wú)法使用系統(tǒng)提供的警報(bào)聲和系統(tǒng)提供的用戶(hù)界面聲音效果熊榛。例如疯攒,使用kSystemSoundID_UserPreferredAlert常量作為AudioServicesPlayAlertSound函數(shù)的參數(shù)將不會(huì)播放任何內(nèi)容会喝。

舉例如下:

  // Get the main bundle for the app
    CFBundleRef mainBundle = CFBundleGetMainBundle ();
    
    // Get the URL to the sound file to play. The file in this case
    // is "tap.aif"
    CFURLRef soundFileURLRef;
    soundFileURLRef  = CFBundleCopyResourceURL(mainBundle,CFSTR ("2"),CFSTR ("caf"),NULL);
    SystemSoundID soundFileObject =0 ;
    AudioServicesCreateSystemSoundID (soundFileURLRef,
    &soundFileObject);
    self.soundFileObject = soundFileObject;

播放音樂(lè)

    AudioServicesPlaySystemSound (self.soundFileObject);

如何獲取.caf 文件呢?
通過(guò)終端命令末秃,將簡(jiǎn)單的mp3文件轉(zhuǎn)換,命令如下
afconvert /Users/Mina/Desktop/1.mp3 /Users/Mina/Desktop/2.caf -d ima4 -f caff -v

在典型的使用中概页,包含偶爾或者重復(fù)播放音樂(lè),我們需要保留聲音的ID對(duì)象练慕,知道應(yīng)用程序退出釋放對(duì)象惰匙。如果我們知道只使用一次,那我們可以播放聲音后里面銷(xiāo)毀對(duì)象贺待,釋放內(nèi)存徽曲。

在支持振動(dòng)的ios設(shè)備上運(yùn)行的app可以使用 system sound services 觸發(fā)該共功能。使用kSystemSoundID_Vibrate標(biāo)識(shí)符指定vibrate(振動(dòng)) 選項(xiàng)麸塞。要觸發(fā)她秃臣,使用AudioServicesPlaySystemSound函數(shù)。

#import <AudioToolbox/AudioToolbox.h>
#import <UIKit/UIKit.h>
- (void) vibratePhone {
    AudioServicesPlaySystemSound (kSystemSoundID_Vibrate);
}

iPod touch不支持此功能哪工。

使用AVAudioPlayer 播放音樂(lè)更輕松

AVAudioPlayer 類(lèi)提供了一個(gè)簡(jiǎn)單的oc接口奥此,用于播放聲音。如果我們的app不需要立體聲定位或者精確同步雁比,并且不需要播放從網(wǎng)絡(luò)流捕獲的音頻稚虎。我們可以使用此類(lèi)播放。
該類(lèi)可以完成下列功能:

  • 播放任何持續(xù)時(shí)間的聲音
  • 播放文件或內(nèi)存緩存區(qū)的聲音
  • 循環(huán)聲音
  • 同時(shí)播放多個(gè)聲音(沒(méi)有精確同步)
  • 控制正在播放的每個(gè)聲音的相對(duì)播放水平
  • 尋找聲音文件中的特定點(diǎn)偎捎,該文件吃吃快進(jìn)和快退等功能
  • 獲取音頻的電源數(shù)據(jù)蠢终,該數(shù)據(jù)可以用來(lái)音頻水平的測(cè)量序攘。

AVAudioPlayer 類(lèi)允許我們?cè)趇os中使用可用的任何音頻格式播放音樂(lè)。具體可以參考 AVAudioPlayer Class Reference

如何配置音頻播放器

  • 1.指定一個(gè)音樂(lè)文件給音頻播放器
  • 2.準(zhǔn)備播放音頻播放器寻拂,獲取所需的硬件資源
  • 3.指定音頻播放器委托對(duì)象程奠,該對(duì)象處理中斷以及播放完成的事件。

具體可看下面例子

-(void)avplay{
    NSString *soundFilePath =
    [[NSBundle mainBundle] pathForResource: @"1"
                                    ofType: @"mp3"];
    
    NSURL *fileURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];
    AVAudioPlayer *newPlayer =
    [[AVAudioPlayer alloc] initWithContentsOfURL: fileURL
                                           error: nil];
    self.player = newPlayer;
    [self.player prepareToPlay];
    [self.player setDelegate: self];
}

-(void)buttonEvent:(id)button{
    [self.player play];
}

我們可以設(shè)置音量

[self.player setVolume: 1.0];    // available range is 0.0 through 1.0

對(duì)于更多信息祭钉,可以看AVAudioPlayer Class Reference

使用音頻隊(duì)列服務(wù)播放控制聲音

音頻隊(duì)列服務(wù)增加了AVAudioPlayer的可用的播放功能瞄沙。使用音頻隊(duì)列服務(wù)進(jìn)行播放可以實(shí)現(xiàn)下來(lái)功能:

  • 精確的安排播放音樂(lè),允許同步
  • 在煮個(gè)緩沖區(qū)的基礎(chǔ)上精確的控制音量
  • 使用音頻文件流服務(wù)播放您從六中捕獲的音頻慌核。

音頻隊(duì)列服務(wù)允許我們播放任何可用的音頻格式音樂(lè)距境。該技術(shù)不僅可以播放,也可以用來(lái)錄制垮卓。
對(duì)于更多細(xì)節(jié)垫桂,可以看 Audio Queue Services Programming GuideAudio Queue Services Reference。 簡(jiǎn)單代碼可以看SpeakHere

創(chuàng)建音頻隊(duì)列對(duì)象
創(chuàng)建音頻隊(duì)列對(duì)象進(jìn)行播放音樂(lè)扒接,用一下幾步:

  • 1.創(chuàng)建數(shù)據(jù)結(jié)構(gòu)以管理音頻對(duì)象所需的信息伪货,例如我們需要播放的數(shù)據(jù)的音頻格式。
  • 2.定義用于管理音頻隊(duì)列緩沖區(qū)的回調(diào)函數(shù)钾怔。回調(diào)使用音頻文件服務(wù)來(lái)讀取我們需要播放的文件蒙挑。
  • 3.使用AudioQueueNewOutput函數(shù)實(shí)例化播放音頻隊(duì)列

代碼如下:

static const int kNumberBuffers = 3;
// Create a data structure to manage information needed by the audio queue
struct myAQStruct {
    AudioFileID                     mAudioFile;
    CAStreamBasicDescription        mDataFormat;
    AudioQueueRef                   mQueue;
    AudioQueueBufferRef             mBuffers[kNumberBuffers];
    SInt64                          mCurrentPacket;
    UInt32                          mNumPacketsToRead;
    AudioStreamPacketDescription    *mPacketDescs;
    bool                            mDone;
};
// Define a playback audio queue callback function
static void AQTestBufferCallback(
    void                   *inUserData,
    AudioQueueRef          inAQ,
    AudioQueueBufferRef    inCompleteAQBuffer
) {
    myAQStruct *myInfo = (myAQStruct *)inUserData;
    if (myInfo->mDone) return;
    UInt32 numBytes;
    UInt32 nPackets = myInfo->mNumPacketsToRead;
 
    AudioFileReadPackets (
        myInfo->mAudioFile,
        false,
        &numBytes,
        myInfo->mPacketDescs,
        myInfo->mCurrentPacket,
        &nPackets,
        inCompleteAQBuffer->mAudioData
    );
    if (nPackets > 0) {
        inCompleteAQBuffer->mAudioDataByteSize = numBytes;
        AudioQueueEnqueueBuffer (
            inAQ,
            inCompleteAQBuffer,
            (myInfo->mPacketDescs ? nPackets : 0),
            myInfo->mPacketDescs
        );
        myInfo->mCurrentPacket += nPackets;
    } else {
        AudioQueueStop (
            myInfo->mQueue,
            false
        );
        myInfo->mDone = true;
    }
}
// Instantiate an audio queue object
AudioQueueNewOutput (
    &myInfo.mDataFormat,
    AQTestBufferCallback,
    &myInfo,
    CFRunLoopGetCurrent(),
    kCFRunLoopCommonModes,
    0,
    &myInfo.mQueue
);

這段代碼直接復(fù)制到工程中會(huì)發(fā)生錯(cuò)誤的.想要詳細(xì)了如何使用應(yīng)該看SpeakHere宗侦,改工程中包含以上代碼。

因?yàn)檫@篇文章只是講解音頻知識(shí)的大概忆蚀。所以不會(huì)過(guò)多設(shè)計(jì)技術(shù)細(xì)節(jié)矾利。

控制播放水平
音頻隊(duì)列對(duì)象為我們提供了兩種控制播放級(jí)別的方法。
最直接的方式是用下列代碼

Float32 volume = 1;    // linear scale, range from 0.0 through 1.0
AudioQueueSetParameter (
    myAQstruct.audioQueueObject,
    kAudioQueueParam_Volume,
    volume
);

這里說(shuō)的播放水平就是音量大小啦馋袜。
我們還可以使用AudioQueueEnqueueBufferWithParameters函數(shù)設(shè)置音頻隊(duì)列緩沖區(qū)的播放級(jí)別男旗。這可以讓我們指定音頻隊(duì)列來(lái)設(shè)置,產(chǎn)生的效果是欣鳖,改隊(duì)列攜帶了這次操作察皇,當(dāng)該隊(duì)列進(jìn)行播放是,該設(shè)置才能生效泽台。

以上兩種方式更改音頻隊(duì)列將一直有效什荣。

提高播放水平

我們可以通過(guò)下列方式獲取當(dāng)前播放水平:

  • 通過(guò)將kAudioQueueProperty_EnableLevelMetering屬性設(shè)置為true來(lái)啟用音頻隊(duì)列對(duì)象的計(jì)量
  • 查詢(xún)音頻隊(duì)列對(duì)象的kAudioQueueProperty_CurrentLevelMeter

此屬性的值是AudioQueueLevelMeterState結(jié)構(gòu)的數(shù)組,每個(gè)通道一個(gè)怀酷。

typedef struct AudioQueueLevelMeterState {
    Float32     mAveragePower;
    Float32     mPeakPower;
};  AudioQueueLevelMeterState;

播放多個(gè)音樂(lè)

要同時(shí)播放多個(gè)聲音稻爬,我們需要為每個(gè)聲音創(chuàng)建一個(gè)播放音頻隊(duì)列對(duì)象。對(duì)于每個(gè)音頻隊(duì)列蜕依,使用AudioQueueEnqueueBufferWithParameters函數(shù)安排第一個(gè)音頻緩沖區(qū)同時(shí)啟動(dòng)桅锄。

從iOS 3.0開(kāi)始琉雳,幾乎所有支持的音頻格式都可用于同步播放 - 即所有可以使用軟件解碼播放的格式,如表1-1所示友瘤。 對(duì)于處理器效率最高的多重播放咐吼,請(qǐng)使用線性PCM(未壓縮)或IMA4(壓縮)音頻。

使用OpenAL播放定位聲音

OpenAL框架中的ios中的提供的開(kāi)源openAL 音頻api提供了一個(gè)優(yōu)化的界面商佑,用于在播放期間定位立體生成中的聲音锯茄。播放,定位和移動(dòng)聲音就想其他的平臺(tái)上一樣茶没。openAL 還可以讓你混合聲音肌幽。openAL使用I / O單元進(jìn)行播放,從而實(shí)現(xiàn)最低延遲抓半。

出于以上原因喂急,openAL是基于ios的設(shè)備上播放游戲應(yīng)用程序中的聲音的最佳選擇。但是笛求,openAL也是一般ios應(yīng)用程序音頻播放需求的不錯(cuò)的選擇廊移。

對(duì)于更多的使用,我們可以看OpenAL FAQ for iPhone OS探入。demo 可以看oalTouch

音頻錄制

ios 可以使用AVAudioRecorder類(lèi)和Audio Queue Services 進(jìn)行音頻錄制狡孔。這些接口可以根據(jù)需要連接音頻硬件,管理內(nèi)存和使用編解碼器蜂嗽。錄制音頻的格式見(jiàn)上面的表苗膝。

錄制音頻可以在系統(tǒng)定義的輸入水平進(jìn)行。系統(tǒng)可以從用戶(hù)選擇的音頻源來(lái)獲取輸入信息-例如內(nèi)置的麥克風(fēng)植旧,或者如果耳機(jī)連接辱揭,那么輸入源也可以是耳機(jī)麥克風(fēng)或者其他輸入源。

使用AVAudioRecorder 類(lèi)錄制音頻

在ios 中錄制聲音的最簡(jiǎn)單的方式是使用AVAudioRecorder類(lèi)病附。該類(lèi)提供了一個(gè)高度簡(jiǎn)化的oc接口问窃,可以輕松的提供諸如暫停恢復(fù)錄制和處理音頻中斷等復(fù)雜操作完沪。同時(shí)域庇,我們也可以控制錄音的格式。

準(zhǔn)備錄音需要以下步驟:

  • 1.指定一個(gè)聲音文件地址
  • 2.設(shè)置音頻會(huì)話(huà)
  • 3.配置音頻錄制的初始化的狀態(tài)

app在啟動(dòng)的時(shí)候就對(duì)此部分進(jìn)行配置是很好的時(shí)機(jī)丽焊。如下

- (void) audioRecorder {
    
    NSString *tempDir = NSTemporaryDirectory ();
    NSString *soundFilePath =
    [tempDir stringByAppendingString: @"sound.caf"];
    
    NSURL *newURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];
    self.soundFileURL = newURL;
    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    audioSession.delegate = self;
    [audioSession setActive: YES error: nil];
}

要處理中斷和錄制完成较剃,我們需要增加AVAudioSessionDelegate和AVAudioRecorderDelegate協(xié)議的實(shí)現(xiàn)。如果我們的應(yīng)用程序也需要播放技健,我們需要參考AVAudioPlayerDelegate Protocol Reference

開(kāi)啟錄制代碼如下

- (IBAction) recordOrStop: (id) sender {
    
        
        [[AVAudioSession sharedInstance]
         setCategory: AVAudioSessionCategoryRecord
         error: nil];
        
        NSDictionary *recordSettings =
        [[NSDictionary alloc] initWithObjectsAndKeys:
         [NSNumber numberWithFloat: 44100.0], AVSampleRateKey,
         [NSNumber numberWithInt: kAudioFormatAppleLossless], AVFormatIDKey,
         [NSNumber numberWithInt: 1], AVNumberOfChannelsKey,
         [NSNumber numberWithInt: AVAudioQualityMax],
         AVEncoderAudioQualityKey,
         nil];
        
        AVAudioRecorder *newRecorder =
        [[AVAudioRecorder alloc] initWithURL: self.soundFileURL  settings: recordSettings
                                       error: nil];
        self.soundRecorder = newRecorder;
        self.soundRecorder.delegate = self;
        [self.soundRecorder prepareToRecord];
        [self.soundRecorder record];    
}

想要了解更多AVAudioRecorder信息可以看AVAudioRecorder Class Reference

使用Audio Queue Services 錄制

用Audio Queue Services錄制音頻写穴,首先我們需要實(shí)例化一個(gè)錄制音頻隊(duì)列對(duì)象,提供一個(gè)回調(diào)函數(shù)雌贱“∷停回調(diào)將傳入的音頻數(shù)據(jù)存儲(chǔ)在內(nèi)存中以供立即使用偿短,或者將其寫(xiě)入文件以進(jìn)行長(zhǎng)期存儲(chǔ)。

與回放功能一樣馋没,我們可以通過(guò)查詢(xún)其kAudioQueueProperty_CurrentLevelMeter屬性從音頻隊(duì)列對(duì)象獲取當(dāng)前錄制音頻級(jí)別昔逗。

對(duì)于更多細(xì)節(jié)如何使用Audio Queue Services錄制音頻,可以參考Recording Audio inAudio Queue Services Programming Guide

解析流式音頻

要播放流式音頻內(nèi)容篷朵,例如來(lái)說(shuō)網(wǎng)絡(luò)的內(nèi)容勾怒,我們需要用Audio Queue Services中的音頻文件流服務(wù)。音頻文件流服務(wù)從網(wǎng)絡(luò)比特流中的公共音頻文件容器格式解析音頻數(shù)據(jù)包和元數(shù)據(jù)声旺。我們也可以使用他來(lái)解析磁盤(pán)文件中的數(shù)據(jù)包和元數(shù)據(jù)笔链。

在ios中,我們可以解析的音頻文件和比特流數(shù)據(jù)形式如下

  • MPEG-1 Audio Layer 3, used for .mp3 files
  • MPEG-2 ADTS, used for the .aac audio data format
  • AIFC
  • AIFF
  • CAF
  • MPEG-4, used for .m4a, .mp4, and .3gp files
  • NeXT
  • WAVE

檢索到音頻數(shù)據(jù)包后腮猖,我們可以播放ios中支持的任何格式的恢復(fù)聲音鉴扫。

想了解更多流信息,參考Audio File Stream Services Reference

ios中的音頻單元支持

ios提供了一組音頻處理插件澈缺,稱(chēng)為音頻單元坪创,可以在任何的應(yīng)用程序中使用。Audio Unit框架中的接口允許我們打開(kāi)姐赡,連接和使用這些音頻單元莱预。

使用audio unit框架的功能,我們需要將audio toolbox 框架添加到xocde工程中雏吭。 #import <AudioToolbox/AudioToolbox.h>

下列表就是在ios提供的 audio units

Audio unit Description
iPod Equalizer unit iPod EQ單元的類(lèi)型是kAudioUnitSubType_AUiPodEQ锁施,它提供一個(gè)簡(jiǎn)單的,基于預(yù)設(shè)的均衡器杖们,可以在app中使用。有關(guān)如何使用此音頻單元肩狂,參考Mixer iPodEQ AUGraph Test
3D Mixer unit 3D混音器單元的類(lèi)型是kAudioUnitSubType_AU3DMixerEmbedded摘完,可以讓我們混合多個(gè)音頻流,指定立體聲輸出平移傻谁,操作播放速率等孝治。OpenAL構(gòu)建于此音頻單元之上,提供更適合游戲應(yīng)用程序的更高級(jí)API
Multichannel Mixer unit 多通道混音器單元审磁,類(lèi)型是kAudioUnitSubType_MultiChannelMixer谈飒,允許將多個(gè)單聲道或者立體聲音頻流混合到單個(gè)立體聲中。他還支持每個(gè)輸入的左/右平移态蒂。
Remote I/O unit 遠(yuǎn)程I/O單元杭措,類(lèi)型是kAudioUnitSubType_RemoteIO,連接到音頻輸入和輸出硬件钾恢,并支持實(shí)時(shí)I.O. aurioTouch
Voice Processing I/O unit 語(yǔ)音處理I/O,單元類(lèi)型是kAudioUnitSubType_VoiceProcessingIO手素,具有I/O一單元的特性鸳址,并為雙向通信添加了回聲抑制和其他功能
Generic Output unit 通用輸出單元,類(lèi)型是kAudioUnitSubType_GenericOutput泉懦,支持轉(zhuǎn)換為線型PCM格式和從線型PCM格式的轉(zhuǎn)換稿黍。;可以用于啟動(dòng)和停止 graph
Converter unit 轉(zhuǎn)換器單元的類(lèi)型是kAudioUnitSubType_AUConverter崩哩,允許我們將音頻數(shù)據(jù)從一種格式轉(zhuǎn)換成領(lǐng)一種格式巡球。通常使用包含轉(zhuǎn)換器單元的遠(yuǎn)程I/O單元獲得此音頻單元的功能

更多細(xì)節(jié)參考 Audio Unit Hosting Guide for iOS

簡(jiǎn)單demo aurioTouch

ios音頻最佳實(shí)戰(zhàn)

使用音頻提示
Tip Action
適當(dāng)使用壓縮視頻 對(duì)于aac,mp3,alac音頻,可以使用硬件輔助編碼器進(jìn)行解碼邓嘹。雖然有效酣栈,但一次僅限一個(gè)音頻流。如果需要同時(shí)播放多個(gè)聲音吴超,請(qǐng)使用IMA4(壓縮)或者線型PCM(未壓縮)格式存儲(chǔ)這些聲音
轉(zhuǎn)換為我們需要的數(shù)據(jù)格式和文件 Mac OS X中的afconvert工具允許我們轉(zhuǎn)換為各種音頻數(shù)據(jù)格式和文件類(lèi)型钉嘹。 具體用法可以用man afconvert 或者 Preferred Audio Formats in iOS
評(píng)估音頻內(nèi)存問(wèn)題 使用音頻隊(duì)列服務(wù)播放聲音時(shí),我們需要編寫(xiě)一個(gè)回調(diào)鲸阻,將短段音頻數(shù)據(jù)發(fā)送到音頻隊(duì)列的緩沖區(qū)跋涣。在默寫(xiě)情況下,最好將整個(gè)聲音文件加載到內(nèi)存中進(jìn)行播放鸟悴,從而最大限度的減少磁盤(pán)訪問(wèn)陈辱。在其他情況下,一次加載足夠的數(shù)據(jù)以保持緩沖區(qū)滿(mǎn)是最好的细诸。
通過(guò)限制采樣率沛贪,位深度和通道來(lái)減小音頻文件大小 采樣率和每個(gè)采樣的位數(shù)會(huì)直接影響音頻文件的大小。如果您需要播放許多此類(lèi)聲音或者長(zhǎng)時(shí)間聲音震贵,需要考慮減少這些值以減少音頻數(shù)據(jù)的內(nèi)存占用利赋。例如,我們可以使用32KHZ或者更低的采樣率猩系,而不是使用44.2KHZ的采樣率來(lái)獲取合理的音質(zhì)效果媚送。使用單聲道音頻而不是立體聲(雙聲道)可減少文件大小。對(duì)于每個(gè)聲音asset寇甸,需要考慮單聲道是否可以滿(mǎn)足需求
選擇合適的技術(shù) 如果需要方便的高階界面來(lái)定位立體聲場(chǎng)中的聲音或者低延遲播放時(shí)塘偎,可以使用openAL。要解析文件或網(wǎng)絡(luò)流總的音頻數(shù)據(jù)包拿霉,請(qǐng)使用 Audio File Stream Services吟秩。要簡(jiǎn)單播放單個(gè)或者多個(gè)聲音,請(qǐng)使用AVAudioRecorder類(lèi)绽淘。對(duì)于音頻聊天涵防,可以使用語(yǔ)音處理I/O單元。要播放從用戶(hù)的iTunes資料庫(kù)同步的音頻資源收恢,使用iPod Library Access武学。當(dāng)我們需要音頻播放警報(bào)和用戶(hù)界面音效時(shí)祭往,我們使用Core Audio’s System Sound Services。對(duì)于其他音頻應(yīng)用程序火窒,包含流式音頻的播放硼补,精確同步以及對(duì)傳入音頻數(shù)據(jù)包的訪問(wèn),使用Audio Queue Services.
低延遲的代碼 要獲得盡可能低的播放延遲熏矿,使用openAL或者直接使用I/O單元
ios的首先音頻格式

對(duì)于未壓縮(最高質(zhì)量的)音頻已骇,請(qǐng)使用導(dǎo)報(bào)在caf文件中的16位小端線型PCM 音頻格式。我們可以使用afconvert 命令行工具來(lái)mac os x中將音頻文件轉(zhuǎn)換為此格式

/usr/bin/afconvert -f caff -d LEI16 {INPUT} {OUTPUT}

afconvert 工具允許我們轉(zhuǎn)換為各種音頻數(shù)據(jù)格式和文件類(lèi)型票编。我們可以用 man afconvert 查看其功能褪储。或者afconvert -h 查看

 man afconvert

對(duì)于一次播放一個(gè)聲音的壓縮音頻慧域,以及當(dāng)不需要與ipod應(yīng)用程序同時(shí)播放音頻時(shí)鲤竹,可以使用CAF或者m4a文件中打包成aac格式。

當(dāng)需要同時(shí)播放多個(gè)聲音時(shí)候昔榴,為了減少內(nèi)存使用量辛藻,使用IMA4(IMA/ADPCM)壓縮。這樣可以減少文件大小互订,但在解壓縮過(guò)程中對(duì)CPU的影響最小吱肌。與線型PCM數(shù)據(jù)一樣,在caf 文件中打包IMA4 數(shù)據(jù)仰禽。


Audio Session Programming Guide

multimedia Programming guide

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末氮墨,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子吐葵,更是在濱河造成了極大的恐慌规揪,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件温峭,死亡現(xiàn)場(chǎng)離奇詭異粒褒,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)诚镰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)祥款,“玉大人清笨,你說(shuō)我怎么就攤上這事∪絮耍” “怎么了抠艾?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)桨昙。 經(jīng)常有香客問(wèn)我检号,道長(zhǎng)腌歉,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任齐苛,我火速辦了婚禮翘盖,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘凹蜂。我一直安慰自己馍驯,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布玛痊。 她就那樣靜靜地躺著汰瘫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪擂煞。 梳的紋絲不亂的頭發(fā)上混弥,一...
    開(kāi)封第一講書(shū)人閱讀 52,246評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音对省,去河邊找鬼蝗拿。 笑死,一個(gè)胖子當(dāng)著我的面吹牛官辽,可吹牛的內(nèi)容都是我干的蛹磺。 我是一名探鬼主播,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼同仆,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼萤捆!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起俗批,我...
    開(kāi)封第一講書(shū)人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤俗或,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后岁忘,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體辛慰,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年干像,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了帅腌。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡麻汰,死狀恐怖速客,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情五鲫,我是刑警寧澤溺职,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響浪耘,放射性物質(zhì)發(fā)生泄漏乱灵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一七冲、第九天 我趴在偏房一處隱蔽的房頂上張望痛倚。 院中可真熱鬧,春花似錦癞埠、人聲如沸状原。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)颠区。三九已至,卻和暖如春通铲,著一層夾襖步出監(jiān)牢的瞬間毕莱,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工颅夺, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留朋截,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓吧黄,卻偏偏與公主長(zhǎng)得像部服,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子拗慨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359