在iOS中音頻播放從形式上可以分為音效播放和音樂播放。前者主要指的是一些短音頻播放,通常作為點綴音頻,對於這類音頻不需要進行進度、循環等控制。后者指的是一些較長的音頻,通常是主音頻,對於這些音頻的播放通常需要進行精確的控制。在iOS中播放兩類音頻分別使用AudioToolbox.framework和AVFoundation.framework來完成音效和音樂播放。
音效
AudioToolbox.framework是一套基於C語言的框架,使用它來播放音效其本質是將短音頻注冊到系統聲音服務(System Sound Service)。System Sound Service是一種簡單、底層的聲音播放服務,但是它本身也存在着一些限制:
- 音頻播放時間不能超過30s
- 數據必須是PCM或者IMA4格式
- 音頻文件必須打包成.caf、.aif、.wav中的一種(注意這是官方文檔的說法,實際測試發現一些.mp3也可以播放)
使用System Sound Service 播放音效的步驟如下:
- 調用AudioServicesCreateSystemSoundID( CFURLRef inFileURL, SystemSoundID* outSystemSoundID)函數獲得系統聲音ID。
- 如果需要監聽播放完成操作,則使用AudioServicesAddSystemSoundCompletion( SystemSoundID inSystemSoundID,
CFRunLoopRef inRunLoop, CFStringRef inRunLoopMode, AudioServicesSystemSoundCompletionProc inCompletionRoutine, void* inClientData)方法注冊回調函數。 - 調用AudioServicesPlaySystemSound(SystemSoundID inSystemSoundID) 或者AudioServicesPlayAlertSound(SystemSoundID inSystemSoundID) 方法播放音效(后者帶有震動效果)。
音樂
如果播放較大的音頻或者要對音頻有精確的控制則System Sound Service可能就很難滿足實際需求了,通常這種情況會選擇使用AVFoundation.framework中的AVAudioPlayer來實現。AVAudioPlayer可以看成一個播放器,它支持多種音頻格式,而且能夠進行進度、音量、播放速度等控制。首先簡單看一下AVAudioPlayer常用的屬性和方法:
屬性 | 說明 |
@property(readonly, getter=isPlaying) BOOL playing | 是否正在播放,只讀 |
@property(readonly) NSUInteger numberOfChannels | 音頻聲道數,只讀 |
@property(readonly) NSTimeInterval duration | 音頻時長 |
@property(readonly) NSURL *url | 音頻文件路徑,只讀 |
@property(readonly) NSData *data | 音頻數據,只讀 |
@property float pan | 立體聲平衡,如果為-1.0則完全左聲道,如果0.0則左右聲道平衡,如果為1.0則完全為右聲道 |
@property float volume | 音量大小,范圍0-1.0 |
@property BOOL enableRate | 是否允許改變播放速率 |
@property float rate | 播放速率,范圍0.5-2.0,如果為1.0則正常播放,如果要修改播放速率則必須設置enableRate為YES |
@property NSTimeInterval currentTime | 當前播放時長 |
@property(readonly) NSTimeInterval deviceCurrentTime | 輸出設備播放音頻的時間,注意如果播放中被暫停此時間也會繼續累加 |
@property NSInteger numberOfLoops | 循環播放次數,如果為0則不循環,如果小於0則無限循環,大於0則表示循環次數 |
@property(readonly) NSDictionary *settings | 音頻播放設置信息,只讀 |
@property(getter=isMeteringEnabled) BOOL meteringEnabled | 是否啟用音頻測量,默認為NO,一旦啟用音頻測量可以通過updateMeters方法更新測量值 |
對象方法 | 說明 |
- (instancetype)initWithContentsOfURL:(NSURL *)url error:(NSError **)outError | 使用文件URL初始化播放器,注意這個URL不能是HTTP URL,AVAudioPlayer不支持加載網絡媒體流,只能播放本地文件 |
- (instancetype)initWithData:(NSData *)data error:(NSError **)outError | 使用NSData初始化播放器,注意使用此方法時必須文件格式和文件后綴一致,否則出錯,所以相比此方法更推薦使用上述方法或- (instancetype)initWithData:(NSData *)data fileTypeHint:(NSString *)utiString error:(NSError **)outError方法進行初始化 |
- (BOOL)prepareToPlay; | 加載音頻文件到緩沖區,注意即使在播放之前音頻文件沒有加載到緩沖區程序也會隱式調用此方法。 |
- (BOOL)play; | 播放音頻文件 |
- (BOOL)playAtTime:(NSTimeInterval)time | 在指定的時間開始播放音頻 |
- (void)pause; | 暫停播放 |
- (void)stop; | 停止播放 |
- (void)updateMeters | 更新音頻測量值,注意如果要更新音頻測量值必須設置meteringEnabled為YES,通過音頻測量值可以即時獲得音頻分貝等信息 |
- (float)peakPowerForChannel:(NSUInteger)channelNumber; | 獲得指定聲道的分貝峰值,注意如果要獲得分貝峰值必須在此之前調用updateMeters方法 |
- (float)averagePowerForChannel:(NSUInteger)channelNumber | 獲得指定聲道的分貝平均值,注意如果要獲得分貝平均值必須在此之前調用updateMeters方法 |
@property(nonatomic, copy) NSArray *channelAssignments | 獲得或設置播放聲道 |
代理方法 | 說明 |
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag | 音頻播放完成 |
- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error | 音頻解碼發生錯誤 |
音頻會話
事實上上面的播放器還存在一些問題,例如通常我們看到的播放器即使退出到后台也是可以播放的,而這個播放器如果退出到后台它會自動暫停。如果要支持后台播放需要做下面幾件事情:
事實上上面的播放器還存在一些問題,例如通常我們看到的播放器即使退出到后台也是可以播放的,而這個播放器如果退出到后台它會自動暫停。如果要支持后台播放需要做下面幾件事情:
1.設置后台運行模式:在plist文件中添加Required background modes,並且設置item 0=App plays audio or streams audio/video using AirPlay(其實可以直接通過Xcode在Project Targets-Capabilities-Background Modes中設置)
2.設置AVAudioSession的類型為AVAudioSessionCategoryPlayback並且調用setActive::方法啟動會話。
AVAudioSession *audioSession=[AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
[audioSession setActive:YES error:nil];
3.為了能夠讓應用退到后台之后支持耳機控制,建議添加遠程控制事件(這一步不是后台播放必須的)
前兩步是后台播放所必須設置的,第三步主要用於接收遠程事件,這部分內容之前的文章中有詳細介紹,如果這一步不設置雖讓也能夠在后台播放,但是無法獲得音頻控制權(如果在使用當前應用之前使用其他播放器播放音樂的話,此時如果按耳機播放鍵或者控制中心的播放按鈕則會播放前一個應用的音頻),並且不能使用耳機進行音頻控制。第一步操作相信大家都很容易理解,如果應用程序要允許運行到后台必須設置,正常情況下應用如果進入后台會被掛起,通過該設置可以上應用程序繼續在后台運行。但是第二步使用的AVAudioSession有必要進行一下詳細的說明。
在iOS中每個應用都有一個音頻會話,這個會話就通過AVAudioSession來表示。AVAudioSession同樣存在於AVFoundation框架中,它是單例模式設計,通過sharedInstance進行訪問。在使用Apple設備時大家會發現有些應用只要打開其他音頻播放就會終止,而有些應用卻可以和其他應用同時播放,在多種音頻環境中如何去控制播放的方式就是通過音頻會話來完成的。下面是音頻會話的幾種會話模式:
會話類型 | 說明 | 是否要求輸入 | 是否要求輸出 | 是否遵從靜音鍵 |
AVAudioSessionCategoryAmbient | 混音播放,可以與其他音頻應用同時播放 | 否 | 是 | 是 |
AVAudioSessionCategorySoloAmbient | 獨占播放 | 否 | 是 | 是 |
AVAudioSessionCategoryPlayback | 后台播放,也是獨占的 | 否 | 是 | 否 |
AVAudioSessionCategoryRecord | 錄音模式,用於錄音時使用 | 是 | 否 | 否 |
AVAudioSessionCategoryPlayAndRecord | 播放和錄音,此時可以錄音也可以播放 | 是 | 是 | 否 |
AVAudioSessionCategoryAudioProcessing | 硬件解碼音頻,此時不能播放和錄制 | 否 | 否 | 否 |
AVAudioSessionCategoryMultiRoute | 多種輸入輸出,例如可以耳機、USB設備同時播放 | 是 | 是 | 否 |
注意:是否遵循靜音鍵表示在播放過程中如果用戶通過硬件設置為靜音是否能關閉聲音。
好了,基本的特點和屬性已經介紹的差不多了,為此,我寫了一個框架,專門用來播放音視頻文件,地址如下:
github:https://github.com/xiayuanquan/XYQPlayer
cnblogs:http://www.cnblogs.com/XYQ-208910/p/6685412.html