1.申請后臺權(quán)限。Capabilities-Background Modes
建網(wǎng)站原本是網(wǎng)站策劃師、網(wǎng)絡(luò)程序員、網(wǎng)頁設(shè)計師等,應用各種網(wǎng)絡(luò)程序開發(fā)技術(shù)和網(wǎng)頁設(shè)計技術(shù)配合操作的協(xié)同工作。成都創(chuàng)新互聯(lián)公司專業(yè)提供成都網(wǎng)站設(shè)計、成都網(wǎng)站建設(shè)、外貿(mào)網(wǎng)站建設(shè),網(wǎng)頁設(shè)計,網(wǎng)站制作(企業(yè)站、響應式網(wǎng)站建設(shè)、電商門戶網(wǎng)站)等服務(wù),從網(wǎng)站深度策劃、搜索引擎友好度優(yōu)化到用戶體驗的提升,我們力求做到極致!
2.設(shè)置后臺播放模式
3.創(chuàng)建播放器
注意:AVAudioPlayer只能播放本地文件,且一次只能播放一個文件,如果需要上一曲、下一曲功能,可以通過創(chuàng)建多個AVAudioPlayer實現(xiàn)。
4.申請后臺task
默認情況下切換到后臺后,播放完當前音頻后,就無法繼續(xù)播放了。需要申請后臺task;
在- (void)applicationWillResignActive:(UIApplication*)application中申請,在- (void)applicationWillEnterForeground:(UIApplication*)application取消。
5.后臺控制
在AppDelegare中處理
在相關(guān)類中處理:
6.顯示歌曲信息
iOS 4開始引入的multitask,我們可以實現(xiàn)像ipod程序那樣在后臺播放音頻了。如果音頻操作是用蘋果官方的AVFoundation.framework實現(xiàn),像用AvAudioPlayer,AvPlayer播放的話,要實現(xiàn)完美的后臺音頻播放,依據(jù)app的功能需要,可能需要實現(xiàn)幾個關(guān)鍵的功能。
首先,播放音頻之前先要設(shè)置AVAudioSession模式,通常只用來播放的App可以設(shè)為AVAudioSessionCategoryPlayback即可。模式意義及其他模式請參考文檔。
1 //后臺播放音頻設(shè)置
2 AVAudioSession *session = [AVAudioSession sharedInstance];
3 [session setActive:YES error:nil];
4 [session setCategory:AVAudioSessionCategoryPlayback error:nil];
1.通知IOS該app支持background audio。缺省情況下,當按下home鍵時,當前正在運行的程序被suspend,狀態(tài)從active變成in-active,也就是說如果正在播放音頻,按下HOME后就會停止。這里需要讓app在按在HOME后,轉(zhuǎn)到后臺運行而非被suspend,解決辦法是在程序的-info.plist中增加required background modes這個key項,并選擇App plays audio or streams audio/video using AirPlay這個value項(如果用過Xcode5.0,在TARGETS-Capabilities-Background Modes設(shè)置為ON,勾選Audio and AirPlay選項)。
2.如果你在后臺播放使用的時加載網(wǎng)絡(luò)音頻,恰巧網(wǎng)速很慢,音頻被停止下來這時候程序也隨之suspend,曾經(jīng)有山寨的解決辦法是專門起一個player的實例連續(xù)不停的放同一無聲音片斷,阻止程序被suspend。這里提供的方法是通過申請后臺taskID達到后臺切換播放文件的功能。
即使聲明taskID也最多只能在后臺運行600秒鐘。(在ios7sdk中可以使用NSURLSession來實現(xiàn)后臺緩沖)
(一般情況下,按HOME將程序送到后臺,可以有5或10秒時間可以進行一些收尾工作,具體時間[[UIApplication sharedApplication] backgroundTimeRemaining]返回值,超時后app會被suspend。)
3.ipod播放程序在后臺時,雙擊HOME鍵,會有個控制界面,可以對它進行播放控制(暫停開始、上一曲、下一曲)。如果您想讓您的app可以像ipod一樣在后臺也可以方便的通過雙擊HOME鍵來控制(在ios7中是使用上拉菜單控制),就要用到遠程控制事件了。
首先在viewdidload等初始化的地方聲明App接收遠程控制事件,并在相應地方結(jié)束聲明
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
}
- (void) viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[UIApplication sharedApplication] endReceivingRemoteControlEvents];
[self resignFirstResponder];
}
- (BOOL)canBecomeFirstResponder
{
return YES;
}
當然也不一定是在viewcontroller中,也可以是在applicationDidEnterBackground:方法中開始接受遠程控制,applicationDidBecomeActive:中結(jié)束接受遠程控制,但是當前的appdelegate中要繼承與UIResponder,因為在激活遠程控制以后要把當前類變成第一響應,重寫canBecomeFirstResponder方法。
最后定義?remoteControlReceivedWithEvent,處理具體的播放、暫停、前進、后退等具體事件
//重寫父類方法,接受外部事件的處理
- (void) remoteControlReceivedWithEvent: (UIEvent *) receivedEvent {
if (receivedEvent.type == UIEventTypeRemoteControl) {
switch (receivedEvent.subtype) {
case UIEventSubtypeRemoteControlTogglePlayPause:
[self playAndStopSong:self.playButton];
break;
case UIEventSubtypeRemoteControlPreviousTrack:
[self playLastButton:self.lastButton];
break;
case UIEventSubtypeRemoteControlNextTrack:
[self playNextSong:self.nextButton];
break;
case UIEventSubtypeRemoteControlPlay:
[self playAndStopSong:self.playButton];
break;
case UIEventSubtypeRemoteControlPause:
[self playAndStopSong:self.playButton];
break;
default:
break;
}
}
}
其它外部事件也可通過這種方式實現(xiàn),如“搖一搖”響應等。
4. 至此,您有播放App已經(jīng)基本完成了,其次插拔耳機是否響應停止播放時間需要進一步研究耳機檢測和聲音路由切換的問題,再次不詳細講述。
5. 還有一些開發(fā)者可能會發(fā)現(xiàn),有一些音視頻app在定義的時候自定一些控件可以調(diào)節(jié)系統(tǒng)的音量大小,不需要用戶調(diào)整音量按鈕。經(jīng)查看相關(guān)的資料總結(jié)出有兩種方法:
一種是調(diào)用控件MPVolumeView在屏幕中創(chuàng)建一個音量條,拖動可以改變系統(tǒng)的音量大小。
另一種是使用MPMusicPlayerController類,可以自定義控件調(diào)整系統(tǒng)音量的大?。ǖ窃趇os7sdk中已經(jīng)被棄用,估計以后幾個版本中可能找不到這個方法了)。
MPMusicPlayerController *mpc = [MPMusicPlayerController applicationMusicPlayer];
mpc.volume = 0;? //0.0~1.0
6. 在一些其他的音樂播放軟件中如:酷我、qq音樂等,你會發(fā)在播放的時候,當設(shè)備鎖屏以后依然可以看到用戶播放的音樂名稱、演唱者、專輯名稱、音樂時長、專輯圖片等信息。這些就需要在用戶切換完歌去的時候,在程序中設(shè)置信息了。
//設(shè)置鎖屏狀態(tài),顯示的歌曲信息
-(void)configNowPlayingInfoCenter{
if (NSClassFromString(@"MPNowPlayingInfoCenter")) {
NSDictionary *info = [self.musicList objectAtIndex:_playIndex];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
//歌曲名稱
[dict setObject:[info objectForKey:@"name"] forKey:MPMediaItemPropertyTitle];
//演唱者
[dict setObject:[info objectForKey:@"singer"] forKey:MPMediaItemPropertyArtist];
//專輯名
[dict setObject:[info objectForKey:@"album"] forKey:MPMediaItemPropertyAlbumTitle];
//專輯縮略圖
UIImage *image = [UIImage imageNamed:[info objectForKey:@"image"]];
MPMediaItemArtwork *artwork = [[MPMediaItemArtwork alloc] initWithImage:image];
[dict setObject:artwork forKey:MPMediaItemPropertyArtwork];
//音樂剩余時長
[dict setObject:[NSNumber numberWithDouble:self.player.duration] forKey:MPMediaItemPropertyPlaybackDuration];
//音樂當前播放時間 在計時器中修改
//[dict setObject:[NSNumber numberWithDouble:0.0] forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime];
//設(shè)置鎖屏狀態(tài)下屏幕顯示播放音樂信息
[[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:dict];
}
}
上面的if?(NSClassFromString(@”MPNowPlayingInfoCenter”))語句,說是為了避免了版本兼容問題,這個API貌似只出現(xiàn)在5里面。
7. 下面就在計時器中不斷刷新鎖屏狀態(tài)下的播放進度條了。
//計時器修改進度
- (void)changeProgress:(NSTimer *)sender{
if(self.player){
//當前播放時間
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:[[MPNowPlayingInfoCenter defaultCenter] nowPlayingInfo]];
[dict setObject:[NSNumber numberWithDouble:self.player.currentTime] forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime]; //音樂當前已經(jīng)過時間
[[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:dict];
}
}
8. 當前的很多常見的播放器都可以在鎖屏狀態(tài)下顯示顯示歌詞,經(jīng)過一番查找后,終于找到方法(詳情: 點擊查看 ),大致就是根據(jù)播放的時間和歌詞顯示時間,利用計時器不斷的用歌詞和專輯封面合成圖片,達到顯示歌詞的效果。還有就是在屏幕變暗停止這一操作、屏幕點亮的時候開始計時器,以節(jié)省電量和cpu,有兩種方法可以監(jiān)聽上述現(xiàn)象:
一種是監(jiān)聽內(nèi)核層DarwinNotification,在Darwin中,有很多的系統(tǒng)事件,但apple的api文檔描述這些api使用有限制,也就是灰色地帶的api,所以能不用則不用;
另一種方法可以通過notify_get_state來獲取com.apple.springboard.hasBlankedScreen?的狀態(tài)值,通過狀態(tài)值我們可以判斷屏幕狀態(tài),屏幕亮或者暗系統(tǒng)會給出不同狀態(tài)值,然后根據(jù)狀態(tài)值,通過NotificationCenter發(fā)送消息通知給相應的函數(shù)處理。
注冊 AVAudioSession.interruptionNotification 的通知,可以收到播放打斷通知。 系統(tǒng)將此通知發(fā)布到主線程。
其中userinfo有如下字段:
分began與end,用來表示打斷開始與打斷結(jié)束。
只在打斷結(jié)束時返回。選項用 shouldResume 來指示:另一個音頻會話的中斷已結(jié)束,應用程序可以恢復其音頻會話。
該屬性只在打斷開始時返回。存在于版本iOS 10.3-14.5。
用于確定這次中斷是否由于系統(tǒng)掛起App所致。
獲取到的是一個NSNumber表示的Bool。為true表示中斷是由于系統(tǒng)掛起,false是被另一音頻打斷。
該屬性只在打斷開始時返回。存在于版本iOS 14.5以后,用來代替 AVAudioSessionInterruptionWasSuspendedKey 。
default :因為另一個音頻會話被激活,音頻中斷。(例如后臺播著音頻,此時播放微信語音)
appWasSuspended :由于APP被系統(tǒng)掛起,音頻中斷
builtInMicMuted :音頻因內(nèi)置麥克風靜音而中斷(例如iPad智能關(guān)閉套【iPad's Smart Folio】合上)
一、簡單介紹
簡單來說,音頻可以分為2種
(1)音效
又稱“短音頻”,通常在程序中的播放時長為1~2秒
在應用程序中起到點綴效果,提升整體用戶體驗
(2)音樂
比如游戲中的“背景音樂”,一般播放時間較長
框架:播放音頻需要用到AVFoundation.framework框架
二、音效的播放
1.獲得音效文件的路徑
復制代碼 代碼如下:
NSURL *url = [[NSBundle mainBundle] URLForResource:@"m_03.wav" withExtension:nil];
2.加載音效文件,得到對應的音效ID
復制代碼 代碼如下:
SystemSoundID soundID = 0;
AudioServicesCreateSystemSoundID((__bridge CFURLRef)(url), soundID);
3.播放音效
復制代碼 代碼如下:
AudioServicesPlaySystemSound(soundID);
注意:音效文件只需要加載1次
4.音效播放常見函數(shù)總結(jié)
加載音效文件
復制代碼 代碼如下:
AudioServicesCreateSystemSoundID(CFURLRef inFileURL, SystemSoundID *outSystemSoundID)
釋放音效資源
復制代碼 代碼如下:
AudioServicesDisposeSystemSoundID(SystemSoundID inSystemSoundID)
播放音效
復制代碼 代碼如下:
AudioServicesPlaySystemSound(SystemSoundID inSystemSoundID)
播放音效帶點震動
復制代碼 代碼如下:
AudioServicesPlayAlertSound(SystemSoundID inSystemSoundID)
三、程序示例
先導入需要依賴的框架
導入需要播放的音效文件素材
說明:AVFoundation.framework框架中的東西轉(zhuǎn)換為CF需要使用橋接。
代碼示例:
復制代碼 代碼如下:
YYViewController.m文件
//
// YYViewController.m
// 14-音效播放
//
// Created by apple on 14-8-8.
// Copyright (c) 2014年 yangyong. All rights reserved.
//
#import "YYViewController.h"
#import
@interface YYViewController ()
@end
復制代碼 代碼如下:
@implementation YYViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//1.獲得音效文件的全路徑
NSURL *url=[[NSBundle mainBundle]URLForResource:@"buyao.wav" withExtension:nil];
//2.加載音效文件,創(chuàng)建音效ID(SoundID,一個ID對應一個音效文件)
SystemSoundID soundID=0;
AudioServicesCreateSystemSoundID((__bridge CFURLRef)url, soundID);
//把需要銷毀的音效文件的ID傳遞給它既可銷毀
//AudioServicesDisposeSystemSoundID(soundID);
//3.播放音效文件
//下面的兩個函數(shù)都可以用來播放音效文件,第一個函數(shù)伴隨有震動效果
AudioServicesPlayAlertSound(soundID);
//AudioServicesPlaySystemSound(#systemsoundid)
}
@end
說明:點擊屏幕可以播放音效文件。
音樂的播放
一、簡單說明
音樂播放用到一個叫做AVAudioPlayer的`類,這個類可以用于播放手機本地的音樂文件。
注意:
(1)該類(AVAudioPlayer)只能用于播放本地音頻。
(2)時間比較短的(稱之為音效)使用AudioServicesCreateSystemSoundID來創(chuàng)建,而本地時間較長(稱之為音樂)使用AVAudioPlayer類。
二、代碼示例
AVAudioPlayer類依賴于AVFoundation框架,因此使用該類必須先導入AVFoundation框架,并包含其頭文件(包含主頭文件即可)。
導入必要的,需要播放的音頻文件到項目中。
代碼示例:
復制代碼 代碼如下:
//
// YYViewController.m
// 15-播放音樂
//
#import "YYViewController.h"
#import
@interface YYViewController ()
@end
復制代碼 代碼如下:
@implementation YYViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//1.音頻文件的url路徑
NSURL *url=[[NSBundle mainBundle]URLForResource:@"235319.mp3" withExtension:Nil];
//2.創(chuàng)建播放器(注意:一個AVAudioPlayer只能播放一個url)
AVAudioPlayer *audioPlayer=[[AVAudioPlayer alloc]initWithContentsOfURL:url error:Nil];
//3.緩沖
[audioPlayer prepareToPlay];
//4.播放
[audioPlayer play];
}
@end
代碼說明:運行程序,點擊模擬器界面,卻并沒有能夠播放音頻文件,原因是代碼中創(chuàng)建的AVAudioPlayer播放器是一個局部變量,應該調(diào)整為全局屬性。
可將代碼調(diào)整如下,即可播放音頻:
復制代碼 代碼如下:
#import "YYViewController.h"
#import
@interface YYViewController ()
@property(nonatomic,strong)AVAudioPlayer *audioplayer;
@end
復制代碼 代碼如下:
@implementation YYViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//1.音頻文件的url路徑
NSURL *url=[[NSBundle mainBundle]URLForResource:@"235319.mp3" withExtension:Nil];
//2.創(chuàng)建播放器(注意:一個AVAudioPlayer只能播放一個url)
self.audioplayer=[[AVAudioPlayer alloc]initWithContentsOfURL:url error:Nil];
//3.緩沖
[self.audioplayer prepareToPlay];
//4.播放
[self.audioplayer play];
}
@end
注意:一個AVAudioPlayer只能播放一個url,如果想要播放多個文件,那么就得創(chuàng)建多個播放器。
三、相關(guān)說明
新建一個項目,在storyboard中放三個按鈕,分別用來控制音樂的播放、暫停和停止。
程序代碼如下:
復制代碼 代碼如下:
#import "YYViewController.h"
#import
@interface YYViewController ()
@property(nonatomic,strong)AVAudioPlayer *player;
- (IBAction)play;
- (IBAction)pause;
- (IBAction)stop;
@end
@implementation YYViewController
- (void)viewDidLoad
{
[super viewDidLoad];
//1.音頻文件的url路徑
NSURL *url=[[NSBundle mainBundle]URLForResource:@"235319.mp3" withExtension:Nil];
//2.創(chuàng)建播放器(注意:一個AVAudioPlayer只能播放一個url)
self.player=[[AVAudioPlayer alloc]initWithContentsOfURL:url error:Nil];
//3.緩沖
[self.player prepareToPlay];
}
- (IBAction)play {
//開始播放/繼續(xù)播放
[self.player play];
}
- (IBAction)pause {
//暫停
[self.player pause];
}
- (IBAction)stop {
//停止
//注意:如果點擊了stop,那么一定要讓播放器重新創(chuàng)建,否則會出現(xiàn)一些莫名其面的問題
[self.player stop];
}
@end
注意:如果點了“停止”,那么一定要播放器重新創(chuàng)建,不然的話會出現(xiàn)莫名其妙的問題。
點擊了stop之后,播放器實際上就不能再繼續(xù)使用了,如果還繼續(xù)使用,那么后續(xù)的一些東西會無法控制。
推薦代碼:
復制代碼 代碼如下:
#import "YYViewController.h"
#import
@interface YYViewController ()
@property(nonatomic,strong)AVAudioPlayer *player;
- (IBAction)play;
- (IBAction)pause;
- (IBAction)stop;
@end
復制代碼 代碼如下:
@implementation YYViewController
#pragma mark-懶加載
-(AVAudioPlayer *)player
{
if (_player==Nil) {
//1.音頻文件的url路徑
NSURL *url=[[NSBundle mainBundle]URLForResource:@"235319.mp3" withExtension:Nil];
//2.創(chuàng)建播放器(注意:一個AVAudioPlayer只能播放一個url)
self.player=[[AVAudioPlayer alloc]initWithContentsOfURL:url error:Nil];
//3.緩沖
[self.player prepareToPlay];
}
return _player;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (IBAction)play {
//開始播放/繼續(xù)播放
[self.player play];
}
- (IBAction)pause {
//暫停
[self.player pause];
}
- (IBAction)stop {
//停止
//注意:如果點擊了stop,那么一定要讓播放器重新創(chuàng)建,否則會出現(xiàn)一些莫名其面的問題
[self.player stop];
self.player=Nil;
}
@end
四、播放多個文件
點擊,url,按住common建查看。
可以發(fā)現(xiàn),這個url是只讀的,因此只能通過initWithContentsOfUrl的方式進行設(shè)置,也就意味著一個播放器對象只能播放一個音頻文件。
那么如何實現(xiàn)播放多個音頻文件呢?
可以考慮封裝一個播放音樂的工具類,下一篇文章將會介紹具體怎么實現(xiàn)。
前段時間在閱讀蘋果音頻文檔(均列在參考資料一節(jié)里面了),并做了一些音頻相關(guān)的開發(fā)(主要是帶回音消除的錄音)。這里做一個總結(jié)。
每一個 app 帶有一個 AVAudioSession 的單例(也就是說正常情況下你無法獲得第二個 AVAudioSession 實例)。iOS 系統(tǒng)上每個 app 有各自不同的 AVAudioSession 實例。通過使用這個實例的方法可以告訴系統(tǒng)當前的 app 是怎樣使用手機的音頻服務(wù)的,然后系統(tǒng)會根據(jù)每個 app 的配置進行相應的協(xié)調(diào), 盡量 滿足所有 app 的請求,當無法滿足的時候,系統(tǒng)盡量滿足前臺 app 的要求或者系統(tǒng)電話服務(wù)等。比如說,如果當前另外一個 app 正在播放的話,當前 app 可能希望能將其播放的音頻和其他 app 的音頻一起播放,而不是暫停其他 app 的音頻服務(wù);又比如說當前 app 需要播放音頻或者進行錄音;比如當前 app 只是播放音頻;比如當前 app 只是錄音;比如當前 app 播放音頻時候屏蔽所有其他 app 的音頻等等,總之就是告訴系統(tǒng)當前 app 是如何使用它的音頻服務(wù)的。
Audio Session 有三個比較重要的概念:
通過配置這三個內(nèi)容,表達了當前 app 的使用音頻服務(wù)的具體意圖。
在某些情況下,我們不需要配置 Audio Session 的 category,比如如果使用 AVAudioRecorder 來錄音,并不需要配置 category 為 AVAudioSessionCategoryRecord ,因為系統(tǒng)在我們使用 AVAudioRecorder 的錄音服務(wù)的時候已經(jīng)為我們配置了。同時 Audio Session 有默認配置(如果當前 app 不進行配置的話)。當默認配置無法滿足需求的時候,就可以手動配置 Audio Session
Audio Session 另一個重要功能是配置系統(tǒng)音頻服務(wù)硬件參數(shù),比如配置輸入的聲道數(shù),采樣率,IO 緩存時間等等。其 API 中 setPreferred__ 開頭的方法作用就是這些。
配置完 Audio Session 以后,當我們要求的音頻服務(wù)受到打斷(比如,電話來了,則系統(tǒng)要停止錄音和播放;比如,app 退到后臺運行了,如果沒有配置后臺運行的話,系統(tǒng)也會停止當前 app 的音頻服務(wù);),我們可以使用通知中心的方式來監(jiān)聽,并做一下相應的處理。音頻服務(wù)中斷有兩個概念比較重要,就是中斷開始以及中斷結(jié)束,我們可以在中斷開始的時候記錄當前播放時間點,中斷結(jié)束的時候重新開始播放(當然系統(tǒng)默認行為是會在中斷結(jié)束時重新開始播放音頻,但是如果默認行為無法滿足需求時候,就需要自行處理了)。
Audio Session 另一個重要我們需要監(jiān)聽的變化是路由變化 (Route Change)。比如有新的輸出源來了(比如用戶把耳機插進去或者是用戶開始使用藍牙耳機),或者原來的輸出源不可用了(用戶拔掉耳機等)。
還有一些其他的功能,比如當前其他 app 是否在播放音頻,請求麥克風權(quán)限等,可以查看具體的 API 文檔 AVAudioSession 。
使用 Audio Queue Service 我們可以做到錄音或者播放音頻。當然我們使用 AVAudioPlayer 也能很簡單的做播放音頻功能,那為什么要用到 Audio Queue Service 呢?它有幾個優(yōu)點
理解 Audio Queue Service 比較重要的是它的 buffer queue。拿錄音來說,一般設(shè)置的緩存是3個。首先通過 AudioQueueEnqueueBuffer 將可用緩存提供給相應的 queue。然后系統(tǒng)開始將記錄下的音頻數(shù)據(jù)放到第一個緩存,當緩存滿的時候,回調(diào)函數(shù)會將該 buffer 返回給你并將該緩存出列,在回調(diào)函數(shù)中我們可以對這些數(shù)據(jù)進行處理,與此同時系統(tǒng)開始將數(shù)據(jù)寫到第二個緩存,當我們的回調(diào)函數(shù)處理完第一個返回的緩存時候,我們需要重新使用 AudioQueueEnqueueBuffer 將該緩存入列,以便系統(tǒng)再次使用。當?shù)诙€緩存返回的時候,系統(tǒng)開始往第三個緩存寫數(shù)據(jù),寫完之后返回第三個緩存,并開始往之前返回的第一個緩存寫數(shù)據(jù)。這就是一個典型的隊列結(jié)構(gòu)(先進先出,后進后出)。
Audio Unit 是所有 iOS 以及 macOS 上音頻框架的最底層,無論使用的是 AVAudioRecorder、AVAudioPlayer、或者 Audio Queue Service、OpenAL 等,最終底層實現(xiàn)都是通過 Audio Unit 來完成的。
在 iOS 上可用的 audio unit 是有限的,macOS 上面可以自定義一個 audio unit 但是 iOS 上不行,只能使用系統(tǒng)提供的 audio unit。
什么時候使用 Audio Unit ?官方的說法是,當你需要高度可控的、高性能、高靈活性或者需要某種特別的功能(比如回音消除,只在 audio unit 提供支持,所有高層 API 均不支持回音消除)的時候,才需要使用 audio unit。
有4類 audio unit(具體用途看名字就能理解):
使用 audio unit 有兩種方式:
第一種方式是對于比較簡單的結(jié)構(gòu)。
第二種方式是用于構(gòu)建復雜的音頻處理流程。配置具體的 audio unit 的屬性的時候還是會用到直接使用種的方法。
audio unit 重要的概念是 scope 和 element。scope 包含 element。
scope 分三種:
scope 概念有一點抽象,可以這樣理解 scope,比如 input scope 表示里面所有的 element 都需要一個輸入。output scope 表示里面所有的 element 都會輸出到某個地方。至于 global scope,應該是用來配置一些和輸入輸出概念無關(guān)的屬性。
element 官方的解釋是可以理解成 bus,就是將數(shù)據(jù)從 element 的一頭傳到另一頭。
這里有些問題我也不知道如何解答,若有了解的,請多多指教一下。
任何吸引人的游戲都少不了聲音。iOS開發(fā)者在游戲中需要使用聲音時有多種選擇,取決于對游戲中音頻的控制需求,可以選擇簡單的內(nèi)置服務(wù),也可以選擇更高級的API(比如OpenAL)。
通過音頻API,可以實現(xiàn)流式音頻,播放簡短音效,甚至模擬3d空間的音頻。有些游戲可以通過音軌讓玩家沉浸在特定的心境中玩游戲,設(shè)置鼓勵用戶使用耳機來獲得更完美的體驗。
本系列文章中,會陸續(xù)整理近幾年來在工作中涉及到的音頻的相關(guān)知識,以算做對自己知識體系的一次梳理吧,大體包括Core Audio、OpenAL 以及Cocos2d引擎中的音效部分等三個方面。
? Core Audio 是什么?
? Core Audio 中提供的音頻服務(wù)
? Core Audio 中的有關(guān)音頻框架
? 有關(guān) Core Audio 的變化及更新
Core Audio 是什么?
Core Audio 是iOS和 MAC 的關(guān)于數(shù)字音頻處理的基礎(chǔ),它提供應用程序用來處理音頻的一組軟件框架,所有關(guān)于IOS音頻開發(fā)的接口都是由Core Audio來提供或者經(jīng)過它提供的接口來進行封裝的,按照官方的說法是集播放、音頻處理、錄制為一體的專業(yè)技術(shù),通過它我們的程序可以同時錄制,播放一個或者多個音頻流,自動適應耳機,藍牙耳機等硬件,響應各種電話中斷,靜音,震動等,甚至提供3D效果的音樂播放。
相關(guān)鏈接:
Core Audio Overview
Audio Video Starting Point
Core Audio Glossary
Core Audio中提供的音頻服務(wù)
Core Audio 本身是一個很龐大的話題,涉及到多個領(lǐng)域中的不同服務(wù),為了更方便的使用Core Audio,通??梢詫⑵浞指顬楦〉哪K。圖一展示了根據(jù)應用程序服務(wù)層分解的示意圖。構(gòu)建在應用程序棧最下面的是底層硬件。接下來往上是驅(qū)動程序?qū)?。?gòu)建在驅(qū)動層之上的每一層都是蘋果提供給開發(fā)人員的應用層服務(wù),包括各類音頻API和框架。
主要的幾類服務(wù):
Audio Unit
Audio Unit 是Core Audio 在應用層中最底層的服務(wù)。在使用其他音頻API時,最終在底層都會調(diào)用到Audio Unit。在所有的API中,Audio Unit 是延遲最短且最靈活的,但代價就是它的使用相當?shù)膹碗s,幸運的是在實際使用中,我們很少直接使用Audio Unit。
相關(guān)鏈接:
Audio Unit Framework Reference
相關(guān)項目工程:
Core Audio Utility Classes
Audio File Service
通過Audio File Service 提供的API可以打開并讀取或者寫入磁盤上存儲的文件。
Audio File Stream Service
它是對Audio File Service 的擴展補充。Audio File Service 對存儲到磁盤上的音頻文件進行操作,而Audio File Stream Service
并不一定關(guān)聯(lián)到某個文件上,它更適合基于網(wǎng)絡(luò)的音頻應用程序。
Audio Conversion Service
通過它可以將數(shù)據(jù)轉(zhuǎn)換為PCM格式或者從PCM格式轉(zhuǎn)換成數(shù)據(jù)。
Extended Audio File Service
可以將它理解為Audio File Service 和 Audio File Service 的組合。通過這種API 可以直接加在并轉(zhuǎn)換音頻文件。
Audio Session Service
和Core Audio中的其他API不同,它的主要用于 iOS 系統(tǒng)中協(xié)調(diào)應用程序之間的音頻播放的 API 的。例如,當有電話打進來時,音頻的播放就會被暫停;在用戶啟動電影時,音樂的播放就會停止。我們需要使用這些 API 來確保一個應用程序能夠正確響應并處理這類事件。
System Sound Service
它是一種允許播放短音效和警告的基本服務(wù),還具有提供振動功能的獨特能力,Core Audio中的其他任何服務(wù)都不能訪問振動系統(tǒng)。
Audio Queue Service
它可以對播放音頻進行精細的控制,比如暫停、繼續(xù)、循環(huán)播放和音頻同步等,因此特別適合于播放和錄制持續(xù)時間很長的音頻。在游戲中進行語音敘述等情景時,需要音樂或者長時間的播放文件,便會需要它。
AVFoundation
它是Core Audio中唯一基于Objective-C的框架。這個框架提供了AVAudioPlayer類用于播放,AVAudioReconder類用于錄音,以及AVAudioSession類用于設(shè)置音頻回話。和其他高層API一樣,我們需要在易用性和功能之間做出權(quán)衡。如果在此框架中找不到我們需要的特性或者功能,那么就必須深入底層服務(wù)并直接使用底層的API。
相關(guān)鏈接:
AV Foundation Framework Reference
AV Foundation Programming Guide
Audio Session Programming Guide
相關(guān)的項目工程:
AVCaptureAudioDataOutput To AudioUnit iOS
OpenAL
和其他專用API不同,OpenAL是一個狂平臺的用于播放和捕捉音頻的工業(yè)標準。OpenAL更適合播放空間音頻(spatialized sound)或者定位音頻(positional sound)。可以將空間音頻理解成3D空間中的聲音,通過OpanAL可以對音效添加一些效果,比如位置屬性,這樣會使遠程的聲音比近處的聲音聽起來要弱一些。
相關(guān)鏈接:
OpenAL FAQ for iPhone OS
相關(guān)的項目工程:
oalTouch
Core Audio中的有關(guān)音頻框架
Core Audio 中的服務(wù)和框架并沒有一對一的對應關(guān)系,應用層的服務(wù)實際上分為5個不同的框架:Core Audio、Audio Toolbox、Audio Unit、AVFoundtaion、OpenAL。圖二中很好的展示了這些框架和服務(wù)之間的映射關(guān)系。
Audio Unit、AVFoundation和OpenAL的框架非常明了,和他們同名的服務(wù)直接對應,其中AVFoundtion有三個Objective-C類組成:AVAudioPlayer、AVAudioRecorder和AVAudioSession。
Audio Toolbox 框架提供了前面列出的其他剩下的應用層服務(wù),包括非常重要的Audio Session Service。
相關(guān)鏈接:
Audio Toolbox Framework Reference
其他相關(guān)框架:
Media Player Framework
它是一個用于音頻和視頻播放的高層級接口,它包含了一個可以在應用中直接使用的默認的用戶界面,可以使用它來播放用戶在 iPod 庫中的項目,或者播放本地文件以及網(wǎng)絡(luò)流。另外,這個框架也包括了查找用戶媒體庫中內(nèi)容的 API,同時還可以配置像是在鎖屏界面或者控制中心里的音頻控件。
相關(guān)鏈接:
Media Player Framework Reference
Core MIDI Framework
提供與MIDI設(shè)備通訊的標準方式,包括硬件鍵盤和合成器??梢允褂眠@個框架來發(fā)送和接收MIDI消息以及與通過dock連接器或網(wǎng)絡(luò)連接到iOS設(shè)備的MIDI外設(shè)交互。
相關(guān)鏈接:
Core MIDI Framework Reference
OS 4.0以后的功能變化如下:
iOS 7.1
Support for External Media Players (CarPlay相關(guān)的)
iOS 7.0
新增 Inter-App Audio和 AudioCopy
強化 Media Player / AV Foundation Framework
棄用 Audio Toolbox framework內(nèi)的Audio Session API
iOS 6.0
新增 Audio UnitのComponent
強化 Media Player / Core Media / AV Foundation Framework
iOS 5.0
新增 Audio UnitのComponent
強化 Media Player / AV Foundation / AudioToolbox Frameworks
iOS 4.3
強化 AV Foundation
強化 Media Player / Audio Unit / Audio Toolbox Frameworks
iOS 4.2
新增 Core MIDI framework
強化 Media Player Framework
新增 AirPlay
iOS 4.1
強化 AV Foundation
iOS 4.0
新增 Core Media Framework
強化 AV Foundation
相關(guān)鏈接:What's New in iOS