概述
基礎(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à)的接口:
- 一個(gè)簡(jiǎn)化的oc接口赴蝇,可以讓我們?cè)L問(wèn)核心音頻會(huì)話(huà)特性。具體可參看 AVAudioSession Class Reference和AVAudioSessionDelegate Protocol Reference巢掺。
- 一個(gè)基于c的接口句伶,通過(guò)對(duì)所有基本和高級(jí)音頻會(huì)話(huà)特性的全面訪問(wèn)。具體可參考 Audio Session Services Reference
我們可以混合和匹配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 Guide和Audio 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ù)仰禽。