十年網(wǎng)站開(kāi)發(fā)經(jīng)驗(yàn) + 多家企業(yè)客戶 + 靠譜的建站團(tuán)隊(duì)
量身定制 + 運(yùn)營(yíng)維護(hù)+專業(yè)推廣+無(wú)憂售后,網(wǎng)站問(wèn)題一站解決
注冊(cè) AVAudioSession.interruptionNotification 的通知,可以收到播放打斷通知。 系統(tǒng)將此通知發(fā)布到主線程。
成都創(chuàng)新互聯(lián)專業(yè)為企業(yè)提供光澤網(wǎng)站建設(shè)、光澤做網(wǎng)站、光澤網(wǎng)站設(shè)計(jì)、光澤網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁(yè)設(shè)計(jì)與制作、光澤企業(yè)網(wǎng)站模板建站服務(wù),十余年光澤做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。
其中userinfo有如下字段:
分began與end,用來(lái)表示打斷開(kāi)始與打斷結(jié)束。
只在打斷結(jié)束時(shí)返回。選項(xiàng)用 shouldResume 來(lái)指示:另一個(gè)音頻會(huì)話的中斷已結(jié)束,應(yīng)用程序可以恢復(fù)其音頻會(huì)話。
該屬性只在打斷開(kāi)始時(shí)返回。存在于版本iOS 10.3-14.5。
用于確定這次中斷是否由于系統(tǒng)掛起App所致。
獲取到的是一個(gè)NSNumber表示的Bool。為true表示中斷是由于系統(tǒng)掛起,false是被另一音頻打斷。
該屬性只在打斷開(kāi)始時(shí)返回。存在于版本iOS 14.5以后,用來(lái)代替 AVAudioSessionInterruptionWasSuspendedKey 。
default :因?yàn)榱硪粋€(gè)音頻會(huì)話被激活,音頻中斷。(例如后臺(tái)播著音頻,此時(shí)播放微信語(yǔ)音)
appWasSuspended :由于APP被系統(tǒng)掛起,音頻中斷
builtInMicMuted :音頻因內(nèi)置麥克風(fēng)靜音而中斷(例如iPad智能關(guān)閉套【iPad's Smart Folio】合上)
iOS 4開(kāi)始引入的multitask,我們可以實(shí)現(xiàn)像ipod程序那樣在后臺(tái)播放音頻了。如果音頻操作是用蘋(píng)果官方的AVFoundation.framework實(shí)現(xiàn),像用AvAudioPlayer,AvPlayer播放的話,要實(shí)現(xiàn)完美的后臺(tái)音頻播放,依據(jù)app的功能需要,可能需要實(shí)現(xiàn)幾個(gè)關(guān)鍵的功能。
首先,播放音頻之前先要設(shè)置AVAudioSession模式,通常只用來(lái)播放的App可以設(shè)為AVAudioSessionCategoryPlayback即可。模式意義及其他模式請(qǐng)參考文檔。
1 //后臺(tái)播放音頻設(shè)置
2 AVAudioSession *session = [AVAudioSession sharedInstance];
3 [session setActive:YES error:nil];
4 [session setCategory:AVAudioSessionCategoryPlayback error:nil];
1.通知IOS該app支持background audio。缺省情況下,當(dāng)按下home鍵時(shí),當(dāng)前正在運(yùn)行的程序被suspend,狀態(tài)從active變成in-active,也就是說(shuō)如果正在播放音頻,按下HOME后就會(huì)停止。這里需要讓app在按在HOME后,轉(zhuǎn)到后臺(tái)運(yùn)行而非被suspend,解決辦法是在程序的-info.plist中增加required background modes這個(gè)key項(xiàng),并選擇App plays audio or streams audio/video using AirPlay這個(gè)value項(xiàng)(如果用過(guò)Xcode5.0,在TARGETS-Capabilities-Background Modes設(shè)置為ON,勾選Audio and AirPlay選項(xiàng))。
2.如果你在后臺(tái)播放使用的時(shí)加載網(wǎng)絡(luò)音頻,恰巧網(wǎng)速很慢,音頻被停止下來(lái)這時(shí)候程序也隨之suspend,曾經(jīng)有山寨的解決辦法是專門(mén)起一個(gè)player的實(shí)例連續(xù)不停的放同一無(wú)聲音片斷,阻止程序被suspend。這里提供的方法是通過(guò)申請(qǐng)后臺(tái)taskID達(dá)到后臺(tái)切換播放文件的功能。
即使聲明taskID也最多只能在后臺(tái)運(yùn)行600秒鐘。(在ios7sdk中可以使用NSURLSession來(lái)實(shí)現(xiàn)后臺(tái)緩沖)
(一般情況下,按HOME將程序送到后臺(tái),可以有5或10秒時(shí)間可以進(jìn)行一些收尾工作,具體時(shí)間[[UIApplication sharedApplication] backgroundTimeRemaining]返回值,超時(shí)后app會(huì)被suspend。)
3.ipod播放程序在后臺(tái)時(shí),雙擊HOME鍵,會(huì)有個(gè)控制界面,可以對(duì)它進(jìn)行播放控制(暫停開(kāi)始、上一曲、下一曲)。如果您想讓您的app可以像ipod一樣在后臺(tái)也可以方便的通過(guò)雙擊HOME鍵來(lái)控制(在ios7中是使用上拉菜單控制),就要用到遠(yuǎn)程控制事件了。
首先在viewdidload等初始化的地方聲明App接收遠(yuǎn)程控制事件,并在相應(yīng)地方結(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;
}
當(dāng)然也不一定是在viewcontroller中,也可以是在applicationDidEnterBackground:方法中開(kāi)始接受遠(yuǎn)程控制,applicationDidBecomeActive:中結(jié)束接受遠(yuǎn)程控制,但是當(dāng)前的appdelegate中要繼承與UIResponder,因?yàn)樵诩せ钸h(yuǎn)程控制以后要把當(dāng)前類變成第一響應(yīng),重寫(xiě)canBecomeFirstResponder方法。
最后定義?remoteControlReceivedWithEvent,處理具體的播放、暫停、前進(jìn)、后退等具體事件
//重寫(xiě)父類方法,接受外部事件的處理
- (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;
}
}
}
其它外部事件也可通過(guò)這種方式實(shí)現(xiàn),如“搖一搖”響應(yīng)等。
4. 至此,您有播放App已經(jīng)基本完成了,其次插拔耳機(jī)是否響應(yīng)停止播放時(shí)間需要進(jìn)一步研究耳機(jī)檢測(cè)和聲音路由切換的問(wèn)題,再次不詳細(xì)講述。
5. 還有一些開(kāi)發(fā)者可能會(huì)發(fā)現(xiàn),有一些音視頻app在定義的時(shí)候自定一些控件可以調(diào)節(jié)系統(tǒng)的音量大小,不需要用戶調(diào)整音量按鈕。經(jīng)查看相關(guān)的資料總結(jié)出有兩種方法:
一種是調(diào)用控件MPVolumeView在屏幕中創(chuàng)建一個(gè)音量條,拖動(dòng)可以改變系統(tǒng)的音量大小。
另一種是使用MPMusicPlayerController類,可以自定義控件調(diào)整系統(tǒng)音量的大?。ǖ窃趇os7sdk中已經(jīng)被棄用,估計(jì)以后幾個(gè)版本中可能找不到這個(gè)方法了)。
MPMusicPlayerController *mpc = [MPMusicPlayerController applicationMusicPlayer];
mpc.volume = 0;? //0.0~1.0
6. 在一些其他的音樂(lè)播放軟件中如:酷我、qq音樂(lè)等,你會(huì)發(fā)在播放的時(shí)候,當(dāng)設(shè)備鎖屏以后依然可以看到用戶播放的音樂(lè)名稱、演唱者、專輯名稱、音樂(lè)時(shí)長(zhǎng)、專輯圖片等信息。這些就需要在用戶切換完歌去的時(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];
//音樂(lè)剩余時(shí)長(zhǎng)
[dict setObject:[NSNumber numberWithDouble:self.player.duration] forKey:MPMediaItemPropertyPlaybackDuration];
//音樂(lè)當(dāng)前播放時(shí)間 在計(jì)時(shí)器中修改
//[dict setObject:[NSNumber numberWithDouble:0.0] forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime];
//設(shè)置鎖屏狀態(tài)下屏幕顯示播放音樂(lè)信息
[[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:dict];
}
}
上面的if?(NSClassFromString(@”MPNowPlayingInfoCenter”))語(yǔ)句,說(shuō)是為了避免了版本兼容問(wèn)題,這個(gè)API貌似只出現(xiàn)在5里面。
7. 下面就在計(jì)時(shí)器中不斷刷新鎖屏狀態(tài)下的播放進(jìn)度條了。
//計(jì)時(shí)器修改進(jìn)度
- (void)changeProgress:(NSTimer *)sender{
if(self.player){
//當(dāng)前播放時(shí)間
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:[[MPNowPlayingInfoCenter defaultCenter] nowPlayingInfo]];
[dict setObject:[NSNumber numberWithDouble:self.player.currentTime] forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime]; //音樂(lè)當(dāng)前已經(jīng)過(guò)時(shí)間
[[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:dict];
}
}
8. 當(dāng)前的很多常見(jiàn)的播放器都可以在鎖屏狀態(tài)下顯示顯示歌詞,經(jīng)過(guò)一番查找后,終于找到方法(詳情: 點(diǎn)擊查看 ),大致就是根據(jù)播放的時(shí)間和歌詞顯示時(shí)間,利用計(jì)時(shí)器不斷的用歌詞和專輯封面合成圖片,達(dá)到顯示歌詞的效果。還有就是在屏幕變暗停止這一操作、屏幕點(diǎn)亮的時(shí)候開(kāi)始計(jì)時(shí)器,以節(jié)省電量和cpu,有兩種方法可以監(jiān)聽(tīng)上述現(xiàn)象:
一種是監(jiān)聽(tīng)內(nèi)核層DarwinNotification,在Darwin中,有很多的系統(tǒng)事件,但apple的api文檔描述這些api使用有限制,也就是灰色地帶的api,所以能不用則不用;
另一種方法可以通過(guò)notify_get_state來(lái)獲取com.apple.springboard.hasBlankedScreen?的狀態(tài)值,通過(guò)狀態(tài)值我們可以判斷屏幕狀態(tài),屏幕亮或者暗系統(tǒng)會(huì)給出不同狀態(tài)值,然后根據(jù)狀態(tài)值,通過(guò)NotificationCenter發(fā)送消息通知給相應(yīng)的函數(shù)處理。
任何吸引人的游戲都少不了聲音。iOS開(kāi)發(fā)者在游戲中需要使用聲音時(shí)有多種選擇,取決于對(duì)游戲中音頻的控制需求,可以選擇簡(jiǎn)單的內(nèi)置服務(wù),也可以選擇更高級(jí)的API(比如OpenAL)。
通過(guò)音頻API,可以實(shí)現(xiàn)流式音頻,播放簡(jiǎn)短音效,甚至模擬3d空間的音頻。有些游戲可以通過(guò)音軌讓玩家沉浸在特定的心境中玩游戲,設(shè)置鼓勵(lì)用戶使用耳機(jī)來(lái)獲得更完美的體驗(yàn)。
本系列文章中,會(huì)陸續(xù)整理近幾年來(lái)在工作中涉及到的音頻的相關(guān)知識(shí),以算做對(duì)自己知識(shí)體系的一次梳理吧,大體包括Core Audio、OpenAL 以及Cocos2d引擎中的音效部分等三個(gè)方面。
? Core Audio 是什么?
? Core Audio 中提供的音頻服務(wù)
? Core Audio 中的有關(guān)音頻框架
? 有關(guān) Core Audio 的變化及更新
Core Audio 是什么?
Core Audio 是iOS和 MAC 的關(guān)于數(shù)字音頻處理的基礎(chǔ),它提供應(yīng)用程序用來(lái)處理音頻的一組軟件框架,所有關(guān)于IOS音頻開(kāi)發(fā)的接口都是由Core Audio來(lái)提供或者經(jīng)過(guò)它提供的接口來(lái)進(jìn)行封裝的,按照官方的說(shuō)法是集播放、音頻處理、錄制為一體的專業(yè)技術(shù),通過(guò)它我們的程序可以同時(shí)錄制,播放一個(gè)或者多個(gè)音頻流,自動(dòng)適應(yīng)耳機(jī),藍(lán)牙耳機(jī)等硬件,響應(yīng)各種電話中斷,靜音,震動(dòng)等,甚至提供3D效果的音樂(lè)播放。
相關(guān)鏈接:
Core Audio Overview
Audio Video Starting Point
Core Audio Glossary
Core Audio中提供的音頻服務(wù)
Core Audio 本身是一個(gè)很龐大的話題,涉及到多個(gè)領(lǐng)域中的不同服務(wù),為了更方便的使用Core Audio,通常可以將其分割為更小的模塊。圖一展示了根據(jù)應(yīng)用程序服務(wù)層分解的示意圖。構(gòu)建在應(yīng)用程序棧最下面的是底層硬件。接下來(lái)往上是驅(qū)動(dòng)程序?qū)印?gòu)建在驅(qū)動(dòng)層之上的每一層都是蘋(píng)果提供給開(kāi)發(fā)人員的應(yīng)用層服務(wù),包括各類音頻API和框架。
主要的幾類服務(wù):
Audio Unit
Audio Unit 是Core Audio 在應(yīng)用層中最底層的服務(wù)。在使用其他音頻API時(shí),最終在底層都會(huì)調(diào)用到Audio Unit。在所有的API中,Audio Unit 是延遲最短且最靈活的,但代價(jià)就是它的使用相當(dāng)?shù)膹?fù)雜,幸運(yùn)的是在實(shí)際使用中,我們很少直接使用Audio Unit。
相關(guān)鏈接:
Audio Unit Framework Reference
相關(guān)項(xiàng)目工程:
Core Audio Utility Classes
Audio File Service
通過(guò)Audio File Service 提供的API可以打開(kāi)并讀取或者寫(xiě)入磁盤(pán)上存儲(chǔ)的文件。
Audio File Stream Service
它是對(duì)Audio File Service 的擴(kuò)展補(bǔ)充。Audio File Service 對(duì)存儲(chǔ)到磁盤(pán)上的音頻文件進(jìn)行操作,而Audio File Stream Service
并不一定關(guān)聯(lián)到某個(gè)文件上,它更適合基于網(wǎng)絡(luò)的音頻應(yīng)用程序。
Audio Conversion Service
通過(guò)它可以將數(shù)據(jù)轉(zhuǎn)換為PCM格式或者從PCM格式轉(zhuǎn)換成數(shù)據(jù)。
Extended Audio File Service
可以將它理解為Audio File Service 和 Audio File Service 的組合。通過(guò)這種API 可以直接加在并轉(zhuǎn)換音頻文件。
Audio Session Service
和Core Audio中的其他API不同,它的主要用于 iOS 系統(tǒng)中協(xié)調(diào)應(yīng)用程序之間的音頻播放的 API 的。例如,當(dāng)有電話打進(jìn)來(lái)時(shí),音頻的播放就會(huì)被暫停;在用戶啟動(dòng)電影時(shí),音樂(lè)的播放就會(huì)停止。我們需要使用這些 API 來(lái)確保一個(gè)應(yīng)用程序能夠正確響應(yīng)并處理這類事件。
System Sound Service
它是一種允許播放短音效和警告的基本服務(wù),還具有提供振動(dòng)功能的獨(dú)特能力,Core Audio中的其他任何服務(wù)都不能訪問(wèn)振動(dòng)系統(tǒng)。
Audio Queue Service
它可以對(duì)播放音頻進(jìn)行精細(xì)的控制,比如暫停、繼續(xù)、循環(huán)播放和音頻同步等,因此特別適合于播放和錄制持續(xù)時(shí)間很長(zhǎng)的音頻。在游戲中進(jìn)行語(yǔ)音敘述等情景時(shí),需要音樂(lè)或者長(zhǎng)時(shí)間的播放文件,便會(huì)需要它。
AVFoundation
它是Core Audio中唯一基于Objective-C的框架。這個(gè)框架提供了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)的項(xiàng)目工程:
AVCaptureAudioDataOutput To AudioUnit iOS
OpenAL
和其他專用API不同,OpenAL是一個(gè)狂平臺(tái)的用于播放和捕捉音頻的工業(yè)標(biāo)準(zhǔn)。OpenAL更適合播放空間音頻(spatialized sound)或者定位音頻(positional sound)??梢詫⒖臻g音頻理解成3D空間中的聲音,通過(guò)OpanAL可以對(duì)音效添加一些效果,比如位置屬性,這樣會(huì)使遠(yuǎn)程的聲音比近處的聲音聽(tīng)起來(lái)要弱一些。
相關(guān)鏈接:
OpenAL FAQ for iPhone OS
相關(guān)的項(xiàng)目工程:
oalTouch
Core Audio中的有關(guān)音頻框架
Core Audio 中的服務(wù)和框架并沒(méi)有一對(duì)一的對(duì)應(yīng)關(guān)系,應(yīng)用層的服務(wù)實(shí)際上分為5個(gè)不同的框架:Core Audio、Audio Toolbox、Audio Unit、AVFoundtaion、OpenAL。圖二中很好的展示了這些框架和服務(wù)之間的映射關(guān)系。
Audio Unit、AVFoundation和OpenAL的框架非常明了,和他們同名的服務(wù)直接對(duì)應(yīng),其中AVFoundtion有三個(gè)Objective-C類組成:AVAudioPlayer、AVAudioRecorder和AVAudioSession。
Audio Toolbox 框架提供了前面列出的其他剩下的應(yīng)用層服務(wù),包括非常重要的Audio Session Service。
相關(guān)鏈接:
Audio Toolbox Framework Reference
其他相關(guān)框架:
Media Player Framework
它是一個(gè)用于音頻和視頻播放的高層級(jí)接口,它包含了一個(gè)可以在應(yīng)用中直接使用的默認(rèn)的用戶界面,可以使用它來(lái)播放用戶在 iPod 庫(kù)中的項(xiàng)目,或者播放本地文件以及網(wǎng)絡(luò)流。另外,這個(gè)框架也包括了查找用戶媒體庫(kù)中內(nèi)容的 API,同時(shí)還可以配置像是在鎖屏界面或者控制中心里的音頻控件。
相關(guān)鏈接:
Media Player Framework Reference
Core MIDI Framework
提供與MIDI設(shè)備通訊的標(biāo)準(zhǔn)方式,包括硬件鍵盤(pán)和合成器。可以使用這個(gè)框架來(lái)發(fā)送和接收MIDI消息以及與通過(guò)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
強(qiáng)化 Media Player / AV Foundation Framework
棄用 Audio Toolbox framework內(nèi)的Audio Session API
iOS 6.0
新增 Audio UnitのComponent
強(qiáng)化 Media Player / Core Media / AV Foundation Framework
iOS 5.0
新增 Audio UnitのComponent
強(qiáng)化 Media Player / AV Foundation / AudioToolbox Frameworks
iOS 4.3
強(qiáng)化 AV Foundation
強(qiáng)化 Media Player / Audio Unit / Audio Toolbox Frameworks
iOS 4.2
新增 Core MIDI framework
強(qiáng)化 Media Player Framework
新增 AirPlay
iOS 4.1
強(qiáng)化 AV Foundation
iOS 4.0
新增 Core Media Framework
強(qiáng)化 AV Foundation
相關(guān)鏈接:What's New in iOS