夜深時動筆ios
前面一篇文章寫了視頻播放的幾種基本的方式,算是給這個系列開了一個頭,這裏面最想說和探究的就是AVFoundation框架,很想把這個框架不敢說是徹底理解,但至少想把它弄明白它裏面到底有什麼,這個過程須要一些時間,既然是不明白的東西就得花時間來總結學習。白天工做的時候都要忙着項目的事,只能等晚上或者哪天上班沒其餘事打擾或者週末去花時間來作這些了,畢業這麼些年,有時候仍是會想起之前在學校時候,那時候只顧着長身體追求個人女神和電競夢,其實就是什麼都沒作成。也真是浪費了太多的時間,要是再有學校那時的時光環境,那時的咱們又不會有工做、生活上的壓力,要是把時間放在本身如今才發覺這是本身喜歡作的事上結果不知道會是什麼樣子,不知道有沒有還在學校的朋友會看到這些文章,無論有沒有仍是想說一句,放棄掉那些不會有結果的事,好好的去作一些你想作的!工做了不少事就不是你想不想了,與其說是身不禁己,不如說是有心無力!回正題,總結AVFoundation。git
我準備在這個系列當中總結一下AVFoundation這個框架,從最基本的入手,一點點的學習這個框架裏面的每個類,爭取把這個框架裏面的基本的類都有一個涉及到。我也是看着《AVFoundation 開發祕籍》開始學習這個框架。github
下面咱們一個一個的一遍看書中的內容,按照框架裏面的類分別一個一個總結。macos
這個系列的幾篇文章的Demo都在 (點擊下載Demo)後面文章的Demo也在這裏,須要的能夠一塊兒下載看看。微信
AVFoundation網絡
凡是對這個框架有想過了解的同窗確定也見過下面這張圖:session
這張圖仍是挺好理解的,咱們大概的總結一下:app
在《AVFoundation開發祕籍》書中有這樣一段描述,AVFoundation是蘋果在iOS和OS X系統中用於處理基於時間的媒體數據的框架。這句話也就說明了它的一個基本的做用,在項目中你嵌入H5也照樣能播放視頻,但涉及到視頻的採集(好比說微信的短視頻拍攝)時候你就只能乖乖的去利用AVFoundation了。框架
AVFoundation是封裝在 Core Avdio 、Core Media 、Core Animition 等這些個層次之上的,它裏面還包括一個音頻類,在上層就是咱們經常使用的UIKit了,再往上層圖上面寫的是media Play其實就是咱們熟悉的AVKit層,AVKit及方便的簡化了媒體應用建立的過程 。AVKit 這個視頻播放的部分相信你們都比較熟悉了,咱們就不在這裏多說了,在前面咱們說過一部分關於它,咱們在後面重點說說它其餘的方面。ide
咱們再說說它下面的三層都作了些什麼事:
一、 Core Avdio 處理全部音頻事件,爲全部音頻以及MIDI(Musical Instrument Digital Interface 樂器數字接口)內容的錄製、播放等提供了接口。設置能夠針對音頻信號進行徹底控制,並經過Audio Units來構建一些複雜的音頻處理,它是由多個框架整合在一塊兒的。看着這麼多內容感受這個框架咱們都能學習一大堆東西,咱們接着往下總結先。
二、Core Media 是提供音頻樣本和視頻幀處理等的API
三、Core Animition 動畫相關框架, 封裝了支持OpenGL和OpenGL ES功能的ObjC各類類.。AVFoundation能夠利用CoreAnimation讓開發者可以在視頻的編輯和播放過程當中添加動畫和圖片效果。
AVSpeechSynthesizer
在書中最開始的時候簡單的介紹了一下AVSpeechSynthesizer,它能夠很方便的在iOS應用中添加「文本到語音」的功能,咱們在Demo中在你開始錄製視頻的時候有一個語音的提示,就是用它處理的,咱們簡單的看看它的代碼,整理的一些基本的用法以及一些屬性的意義都在代碼的註釋中:
// 簡單的語音測試 -(void)speakHintMessage{ // 這樣子能夠簡單的播放一段語音 AVSpeechSynthesizer * synthesizer = [[AVSpeechSynthesizer alloc]init]; // Utterance 表達方式 AVSpeechSynthesisVoice * voice = [AVSpeechSynthesisVoice voiceWithLanguage:@"zh-CN"]; AVSpeechUtterance * utterance = [[AVSpeechUtterance alloc]initWithString:@"準備了豬,開始錄製視頻了"]; utterance.rate = 1.5; // 這個是播放速率 默認1.0 utterance.voice = voice; utterance.pitchMultiplier = 0.8; // 可在播放待定語句時候改變聲調 utterance.postUtteranceDelay = 0.1; // 語音合成器在播放下一條語句的時候有短暫的停頓 這個屬性指定停頓的時間 [synthesizer speakUtterance:utterance]; /* "[AVSpeechSynthesisVoice 0x978a0b0] Language: th-TH", "[AVSpeechSynthesisVoice 0x977a450] Language: pt-BR", "[AVSpeechSynthesisVoice 0x977a480] Language: sk-SK", "[AVSpeechSynthesisVoice 0x978ad50] Language: fr-CA", "[AVSpeechSynthesisVoice 0x978ada0] Language: ro-RO", "[AVSpeechSynthesisVoice 0x97823f0] Language: no-NO", "[AVSpeechSynthesisVoice 0x978e7b0] Language: fi-FI", "[AVSpeechSynthesisVoice 0x978af50] Language: pl-PL", "[AVSpeechSynthesisVoice 0x978afa0] Language: de-DE", "[AVSpeechSynthesisVoice 0x978e390] Language: nl-NL", "[AVSpeechSynthesisVoice 0x978b030] Language: id-ID", "[AVSpeechSynthesisVoice 0x978b080] Language: tr-TR", "[AVSpeechSynthesisVoice 0x978b0d0] Language: it-IT", "[AVSpeechSynthesisVoice 0x978b120] Language: pt-PT", "[AVSpeechSynthesisVoice 0x978b170] Language: fr-FR", "[AVSpeechSynthesisVoice 0x978b1c0] Language: ru-RU", "[AVSpeechSynthesisVoice 0x978b210] Language: es-MX", "[AVSpeechSynthesisVoice 0x978b2d0] Language: zh-HK", "[AVSpeechSynthesisVoice 0x978b320] Language: sv-SE", "[AVSpeechSynthesisVoice 0x978b010] Language: hu-HU", "[AVSpeechSynthesisVoice 0x978b440] Language: zh-TW", "[AVSpeechSynthesisVoice 0x978b490] Language: es-ES", "[AVSpeechSynthesisVoice 0x978b4e0] Language: zh-CN", "[AVSpeechSynthesisVoice 0x978b530] Language: nl-BE", "[AVSpeechSynthesisVoice 0x978b580] Language: en-GB", "[AVSpeechSynthesisVoice 0x978b5d0] Language: ar-SA", "[AVSpeechSynthesisVoice 0x978b620] Language: ko-KR", "[AVSpeechSynthesisVoice 0x978b670] Language: cs-CZ", "[AVSpeechSynthesisVoice 0x978b6c0] Language: en-ZA", "[AVSpeechSynthesisVoice 0x978aed0] Language: en-AU", "[AVSpeechSynthesisVoice 0x978af20] Language: da-DK", "[AVSpeechSynthesisVoice 0x978b810] Language: en-US", "[AVSpeechSynthesisVoice 0x978b860] Language: en-IE", "[AVSpeechSynthesisVoice 0x978b8b0] Language: hi-IN", "[AVSpeechSynthesisVoice 0x978b900] Language: el-GR", "[AVSpeechSynthesisVoice 0x978b950] Language: ja-JP" ) */ // 經過這個方法能夠看到整個支持的會話的列表,信息如上輸出 NSLog(@"目前支持的語音列表:%@",[AVSpeechSynthesisVoice speechVoices]); }
AVAudioPlayer
AVAudioPlayer也是在咱們要說的 AV Foundation 框架裏面,這個類的實例提供了簡單的從文本或者是內存中播放一音頻的功能,雖然API很簡單,可是它提供的功能倒是很強大的,而且在MAC合做和是iOS系統中常常被做爲實現音頻播放的最佳的選擇。
AVAudioPlayer構建與CoreServices中的C-based Audio Queue Services 的最頂層,因此他能夠提供你在 Audio Queue Services 中所能找到的核心功能,好比播放。循環甚至是音頻的計量,使用的時候它提供了很是友好的OC的接口,除非你須要從網絡流中播放音頻,須要訪問原始音頻樣本或者須要很是低的延時,不然AVAudioPlayer都能勝任。
下面看看AVAudioPlayer的一些具體的屬性以及方法,咱們解釋一下這些屬性或者方法:
/* AVAudioPlayer 基本方法以及屬性 基本的初始化方法 - (nullable instancetype)initWithContentsOfURL:(NSURL *)url error:(NSError **)outError; - (nullable instancetype)initWithData:(NSData *)data error:(NSError **)outError; - (nullable instancetype)initWithContentsOfURL:(NSURL *)url fileTypeHint:(NSString * __nullable)utiString error:(NSError **)outError NS_AVAILABLE(10_9, 7_0); - (nullable instancetype)initWithData:(NSData *)data fileTypeHint:(NSString * __nullable)utiString error:(NSError **)outError NS_AVAILABLE(10_9, 7_0); // 準備播放,這個方法能夠不執行,但執行的話能夠下降播放器play方法和你聽到聲音之間的延時 - (BOOL)prepareToPlay; // 播放 - (BOOL)play; // play a sound some time in the future. time is an absolute time based on and greater than deviceCurrentTime. // 跳轉到某一個時間點播放 - (BOOL)playAtTime:(NSTimeInterval)time NS_AVAILABLE(10_7, 4_0); // 暫停 pauses playback, but remains ready to play - (void)pause; // 中止 // 它和上面的暫停的方法是在底層stop會撤銷掉prepareToPlay時所做的設置,可是調用暫停不會 - (void)stop; properties // 是否在播放 @property(readonly, getter=isPlaying) BOOL playing // 音頻聲道數,只讀 @property(readonly) NSUInteger numberOfChannels // 音長 @property(readonly) NSTimeInterval duration //the delegate will be sent messages from the AVAudioPlayerDelegate protocol @property(assign, nullable) id<AVAudioPlayerDelegate> delegate; // 下面兩個是獲取到的你初始化傳入的相應的值 @property(readonly, nullable) NSURL *url @property(readonly, nullable) NSData *data // set panning. -1.0 is left, 0.0 is center, 1.0 is right. NS_AVAILABLE(10_7, 4_0) // 容許使用立體聲播放聲音 若是爲-1.0則徹底左聲道,若是0.0則左右聲道平衡,若是爲1.0則徹底爲右聲道 @property float pan // 音量 The volume for the sound. The nominal range is from 0.0 to 1.0. @property float volume // set音量逐漸減弱在時間間隔內 - (void)setVolume:(float)volume fadeDuration:(NSTimeInterval)duration NS_AVAILABLE(10_12, 10_0); // 是否能設置rate屬性,只有這個屬性設置成YES了才能設置rate屬性,而且這些屬性都設置在prepareToPlay方法調用以前 @property BOOL enableRate NS_AVAILABLE(10_8, 5_0); @property float rate NS_AVAILABLE(10_8, 5_0); // 當前播放的時間,利用定時器去觀察這個屬性能夠讀取到音頻播放的時間點 須要注意的是這個時間在你暫停播放以後是不會再改變的 @property NSTimeInterval currentTime; // 輸出設備播放音頻的時間,注意若是播放中被暫停此時間也會繼續累加 @property(readonly) NSTimeInterval deviceCurrentTime NS_AVAILABLE(10_7, 4_0); // 這個屬性實現循環播放, 設置一個大於0的數值,能夠實現循環播放N次,要是設置-1,就會無限的循環播放 @property NSInteger numberOfLoops; // 音頻播放設置信息,只讀 @property(readonly) NSDictionary<NSString *, id> *settings NS_AVAILABLE(10_7, 4_0); // 10.0以後的屬性 @property(readonly) AVAudioFormat * format NS_AVAILABLE(10_12, 10_0); @property(getter=isMeteringEnabled) BOOL meteringEnabled; // 更新音頻測量值,注意若是要更新音頻測量值必須設置meteringEnabled爲YES,經過音頻測量值能夠即時得到音頻分貝等信息 - (void)updateMeters // 得到指定聲道的分貝峯值,注意若是要得到分貝峯值必須在此以前調用updateMeters方法 - (float)peakPowerForChannel:(NSUInteger)channelNumber // 得到指定聲道的分貝平均值,注意若是要得到分貝平均值必須在此以前調用updateMeters方法 - (float)averagePowerForChannel:(NSUInteger)channelNumber @property(nonatomic, copy, nullable) NSArray<AVAudioSessionChannelDescription *> *channelAssignments AVAudioPlayerDelegate 播放代理 @optional // 成功播放到結束 - (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag; // if an error occurs while decoding it will be reported to the delegate. // 看上面的解釋在音頻解碼出錯的時候就會走這個方法 - (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError * __nullable)error; // 注意下面的一行解釋,下面的代理方法在8.0以後被棄用了,轉用AVAudioSession來代替了 AVAudioPlayer INTERRUPTION NOTIFICATIONS ARE DEPRECATED - Use AVAudioSession instead. // audioPlayerBeginInterruption: is called when the audio session has been interrupted while the player was playing. The player will have been paused. // Interruption 中斷 聲音播放被中斷的時候就會進這個代理方法 - (void)audioPlayerBeginInterruption:(AVAudioPlayer *)player NS_DEPRECATED_IOS(2_2, 8_0); // audioPlayerEndInterruption:withOptions: is called when the audio session interruption has ended and this player had been interrupted while playing. // 中斷結束進這裏代理 - (void)audioPlayerEndInterruption:(AVAudioPlayer *)player withOptions:(NSUInteger)flags NS_DEPRECATED_IOS(6_0, 8_0); - (void)audioPlayerEndInterruption:(AVAudioPlayer *)player withFlags:(NSUInteger)flags NS_DEPRECATED_IOS(4_0, 6_0); // audioPlayerEndInterruption: is called when the preferred method, audioPlayerEndInterruption:withFlags:, is not implemented. - (void)audioPlayerEndInterruption:(AVAudioPlayer *)player NS_DEPRECATED_IOS(2_2, 6_0); */
在Demo中,也是簡單的把AVAudioPlayer的使用總結了一下,用它來播放咱們本地的音頻,固然你也能夠用它播放網絡音頻,檢測它的播放進度以及檢測它的分貝值,下面是Demo的效果圖,這份部分的代碼你能夠在Demo中的AVAudioPlayerController中找到。
AVAudioRecorder
前面說了咱們的AVAudioPlayer,它是用來播放音頻的話,那下面咱們要總結的AVAudioRecorder就是負責來錄音的類,和前面介紹AVAudioPlayer相似,咱們先看看這個類的源碼中都有那些方法,咱們仍是先介紹一個它的屬性和方法,都寫在代碼註釋中,你們仔細的看下面的代碼就能瞭解它,等了解完以後咱們在模仿一個咱們錄製十秒語音的簡單的例子。
/* @interface AVAudioRecorder : NSObject { // 私有的 @private void *_impl; } // 下面兩個是初始化的方法,和咱們前面說的AVAudioPlayer大體相似,咱們再也不解釋 The file type to create can be set through the corresponding settings key. If not set, it will be inferred from the file extension. Will overwrite a file at the specified url if a file exists. - (nullable instancetype)initWithURL:(NSURL *)url settings:(NSDictionary<NSString *, id> *)settings error:(NSError **)outError; The file type to create can be set through the corresponding settings key. If not set, it will be inferred from the file extension. Will overwrite a file at the specified url if a file exists. - (nullable instancetype)initWithURL:(NSURL *)url format:(AVAudioFormat *)format error:(NSError **)outError API_AVAILABLE(macos(10.12), ios(10.0), watchos(4.0)) API_UNAVAILABLE(tvos); // prepareToRecord 準備去記錄,它的做用和前面AVAudioPlayer的也是相似的,能夠看看前面的註釋 methods that return BOOL return YES on success and NO on failure. - (BOOL)prepareToRecord; creates the file and gets ready to record. happens automatically on record. // 開始記錄 相似與AVAudioPlayer的play方法 - (BOOL)record; start or resume recording to file. // 在未來的某個特殊的你設置的時間點開始記錄 - (BOOL)recordAtTime:(NSTimeInterval)time NS_AVAILABLE_IOS(6_0); start recording at specified time in the future. time is an absolute time based on and greater than deviceCurrentTime. // 在某一段時間以後開始記錄 - (BOOL)recordForDuration:(NSTimeInterval) duration; record a file of a specified duration. the recorder will stop when it has recorded this length of audio // 在某一個時間點的某一段時間以後開始記錄 - (BOOL)recordAtTime:(NSTimeInterval)time forDuration:(NSTimeInterval) duration NS_AVAILABLE_IOS(6_0); record a file of a specified duration starting at specified time. time is an absolute time based on and greater than deviceCurrentTime. // 下面是暫停和中止的方法,這兩個比較好理解 - (void)pause; pause recording - (void)stop; stops recording. closes the file. // 刪除記錄,調用這個方法以前必須保證 recorder 是 stop 狀態 - (BOOL)deleteRecording; delete the recorded file. recorder must be stopped. returns NO on failure. // 下面是一些屬性 properties // 是否在記錄 @property(readonly, getter=isRecording) BOOL recording; is it recording or not? // 保存記錄音頻文件的URL @property(readonly) NSURL *url; URL of the recorded file // these settings are fully valid only when prepareToRecord has been called @property(readonly) NSDictionary<NSString *, id> *settings; //10.0以後的屬性, AVAudioFormat 音頻格式注意是隻讀 this object is fully valid only when prepareToRecord has been called @property(readonly) AVAudioFormat *format API_AVAILABLE(macos(10.12), ios(10.0), watchos(4.0)) API_UNAVAILABLE(tvos); // 代理 the delegate will be sent messages from the AVAudioRecorderDelegate protocol @property(assign, nullable) id<AVAudioRecorderDelegate> delegate; // 下面的currentTime和deviceCurrentTime在前面也是解釋過,按照理解AVAudioPlayer的理解就沒問題 get the current time of the recording - only valid while recording @property(readonly) NSTimeInterval currentTime; get the device current time - always valid @property(readonly) NSTimeInterval deviceCurrentTime NS_AVAILABLE_IOS(6_0); // meteringEnabled 也是和AVAudioPlayer相同 // 須要注意的前面也有提過,注意這個屬性以及下面兩個方法之間的必要關係。 至於方法是幹什麼的咱們不在解釋,前面AVAudioPlayer也有 @property(getter=isMeteringEnabled) BOOL meteringEnabled; turns level metering on or off. default is off. - (void)updateMeters; call to refresh meter values - (float)peakPowerForChannel:(NSUInteger)channelNumber; returns peak power in decibels for a given channel - (float)averagePowerForChannel:(NSUInteger)channelNumber; returns average power in decibels for a given channel The channels property lets you assign the output to record specific channels as described by AVAudioSession's channels property This property is nil valued until set. The array must have the same number of channels as returned by the numberOfChannels property. @property(nonatomic, copy, nullable) NSArray<AVAudioSessionChannelDescription *> *channelAssignments NS_AVAILABLE(10_9, 7_0); Array of AVAudioSessionChannelDescription objects // 代理 代理須要注意的地方咱們再也不說了。這個代理和前面AVAudioPlayer的徹底相似 注意點也是相似,有不理解的能夠往前面翻 @protocol AVAudioRecorderDelegate <NSObject> @optional audioRecorderDidFinishRecording:successfully: is called when a recording has been finished or stopped. This method is NOT called if the recorder is stopped due to an interruption. - (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag; if an error occurs while encoding it will be reported to the delegate. - (void)audioRecorderEncodeErrorDidOccur:(AVAudioRecorder *)recorder error:(NSError * __nullable)error; #if TARGET_OS_IPHONE // 下面的方法也是被AVAudioSession替換掉,這個咱們在下面的介紹中會說AVAudioSession這個類 AVAudioRecorder INTERRUPTION NOTIFICATIONS ARE DEPRECATED - Use AVAudioSession instead. audioRecorderBeginInterruption: is called when the audio session has been interrupted while the recorder was recording. The recorded file will be closed. - (void)audioRecorderBeginInterruption:(AVAudioRecorder *)recorder NS_DEPRECATED_IOS(2_2, 8_0); audioRecorderEndInterruption:withOptions: is called when the audio session interruption has ended and this recorder had been interrupted while recording. Currently the only flag is AVAudioSessionInterruptionFlags_ShouldResume. - (void)audioRecorderEndInterruption:(AVAudioRecorder *)recorder withOptions:(NSUInteger)flags NS_DEPRECATED_IOS(6_0, 8_0); - (void)audioRecorderEndInterruption:(AVAudioRecorder *)recorder withFlags:(NSUInteger)flags NS_DEPRECATED_IOS(4_0, 6_0); audioRecorderEndInterruption: is called when the preferred method, audioRecorderEndInterruption:withFlags:, is not implemented. - (void)audioRecorderEndInterruption:(AVAudioRecorder *)recorder NS_DEPRECATED_IOS(2_2, 6_0); */
咱們和前面同樣,也在寫一個Demo出來,整理一下AVAudioRecorder的使用,具體的使用你們能夠看代碼,在我寫Demo的時候感受有兩點是須要你們注意一下的,把這兩點也說一下:
一、有看到有些人說的聲音小的問題,這個主要是在上面AVAudioPlayer
二、錄音功能的前提想正常使用也是須要AVAudioSession
三、還有一點就是有人不理解兩個分貝有什麼用,這裏提一點,這個值能夠用做的地方太多太多了,咱們看到只要是隨着聲音大小改變的UI和這兩個值都緊密的關係,利用這兩個值加動畫就會有咱們想要的效果。
上面的這兩個問題就成功的引出了咱們下面還要說的類AVAudioSession。具體的代碼的寫法咱們在這裏就不在說,Demo裏面是有的,固然下面總結它的時候咱們也會把問題說清楚。咱們接着往下在看:
AVAudioSession
AVAudioSession 咱們也是須要了解的,經過它能夠實現對App當前上下文音頻資源的控制,好比插拔耳機、接電話、是否和其餘音頻數據混音等,常常咱們遇到的一些問題,好比下面的這些:
一、是進行錄音仍是播放?
二、當系統靜音鍵按下時該如何表現?
三、是從揚聲器仍是從聽筒裏面播放聲音?
四、插拔耳機後如何表現?
五、來電話/鬧鐘響了後如何表現?
六、其餘音頻App啓動後如何表現?
帶着這些問題,咱們來看看AVAudioSession。
一:首先AVAudioSession它是被寫成了一個單例的
/* returns singleton instance */ + (AVAudioSession*)sharedInstance;
二:激活這個AVAudioSession
- (BOOL)setActive:(BOOL)active error:(NSError * _Nullable *)outError;
經過上面這個方法咱們就能夠激活AVAudioSession,固然是設置YES激活,錯誤的話能夠經過error的localizedDescription屬性去查看。由於AVAudioSession會影響其餘App的表現,當本身App的Session被激活,其餘App的就會解除激活,那就有這樣一個問題,如何要讓本身的Session解除激活後恢復其餘App Session的激活狀態呢?下面這個方法能解決咱們的問題:
- (BOOL)setActive:(BOOL)active withOptions:(AVAudioSessionSetActiveOptions)options error:(NSError **)outError
這裏的options傳入AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation
便可。固然,你也能夠經過otherAudioPlaying這個只讀屬性
來提早判斷當前是否有其餘App在播放音頻。
三: category
在AVAudioSession源碼中你能夠看到這個屬性:
/* get session category. Examples: AVAudioSessionCategoryRecord, AVAudioSessionCategoryPlayAndRecord, etc. */ @property(readonly) NSString *category;
這個只讀屬性能夠幫助咱們獲取到AVAudioSession的category,你首先不要給咱們的AVAudioSession去設置category的時候,你獲取一下category你就能夠看到默認的category是:AVAudioSessionCategorySoloAmbien
AVAudioSession主要能控制App的哪些表現以及如何控制的呢?首先AVAudioSession將使用音頻的場景分紅七大類,經過設置Session爲不一樣的類別,能夠控制,下面是同行整理的這個七個category針對下面這幾點作的總結,先看看是針對那些個方面總結的:
一、是否支持播放
二、是否支持錄音
三、當設置「靜音」或者「鎖屏」的時候是否「靜音」
四、當App激活Session的時候,是否會打斷其餘不支持混音的App聲音
瞭解了上面說的category,咱們就能夠給咱們的session設置category了,固然在設置以前咱們仍是有必要看一看咱們的設備到底支持哪些category類型,經過下面這個只讀屬性就能夠知道咱們的設置支持哪些類型了:
@property(readonly) NSArray<NSString *> *availableCategories;
知道了咱們的設備支持哪些類型的category以後,咱們須要作的就是去設置了:
/* set session category */ - (BOOL)setCategory:(NSString *)category error:(NSError **)outError; /* set session category with options */ - (BOOL)setCategory:(NSString *)category withOptions:(AVAudioSessionCategoryOptions)options error:(NSError **)outError NS_AVAILABLE_IOS(6_0); /* set session category and mode with options */ - (BOOL)setCategory:(NSString *)category mode:(NSString *)mode options:(AVAudioSessionCategoryOptions)options error:(NSError **)outError NS_AVAILABLE_IOS(10_0);
四: AVAudioSessionCategoryOptions
爲何這個咱們單獨拿出來講說呢,由於這個CategoryOptions的內容有點和category殊途同歸的感受,點擊進入看一下這個:AVAudioSessionCategoryOptions 源碼以下:
typedef NS_OPTIONS(NSUInteger, AVAudioSessionCategoryOptions) { /* MixWithOthers is only valid with AVAudioSessionCategoryPlayAndRecord, AVAudioSessionCategoryPlayback, and AVAudioSessionCategoryMultiRoute */ AVAudioSessionCategoryOptionMixWithOthers = 0x1, /* DuckOthers is only valid with AVAudioSessionCategoryAmbient, AVAudioSessionCategoryPlayAndRecord, AVAudioSessionCategoryPlayback, and AVAudioSessionCategoryMultiRoute */ AVAudioSessionCategoryOptionDuckOthers = 0x2 , /* AllowBluetooth is only valid with AVAudioSessionCategoryRecord and AVAudioSessionCategoryPlayAndRecord */ AVAudioSessionCategoryOptionAllowBluetooth __TVOS_PROHIBITED __WATCHOS_PROHIBITED = 0x4, /* DefaultToSpeaker is only valid with AVAudioSessionCategoryPlayAndRecord */ AVAudioSessionCategoryOptionDefaultToSpeaker __TVOS_PROHIBITED __WATCHOS_PROHIBITED = 0x8, /* InterruptSpokenAudioAndMixWithOthers is only valid with AVAudioSessionCategoryPlayAndRecord, AVAudioSessionCategoryPlayback, and AVAudioSessionCategoryMultiRoute */ AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers NS_AVAILABLE_IOS(9_0) = 0x11, /* AllowBluetoothA2DP is only valid with AVAudioSessionCategoryPlayAndRecord */ AVAudioSessionCategoryOptionAllowBluetoothA2DP NS_AVAILABLE_IOS(10_0) = 0x20, /* AllowAirPlay is only valid with AVAudioSessionCategoryPlayAndRecord */ AVAudioSessionCategoryOptionAllowAirPlay NS_AVAILABLE_IOS(10_0) __WATCHOS_PROHIBITED = 0x40, } NS_AVAILABLE_IOS(6_0);
會不會看的有點眼花繚亂的感受,咱們這裏簡單的把它們之間作一個簡單的總結概括:
一、AVAudioSessionCategoryOptionMixWithOthers : 若是確實用的AVAudioSessionCategoryPlayback實現的一個背景音,可是呢,又想和QQ音樂並存,那麼能夠在AVAudioSessionCategoryPlayback類別下在設置這個選項,就能夠實現共存了。
二、AVAudioSessionCategoryOptionDuckOthers:在實時通話的場景,好比QQ音樂,當進行視頻通話的時候,會發現QQ音樂自動聲音下降了,此時就是經過設置這個選項來對其餘音樂App進行了壓制。
三、AVAudioSessionCategoryOptionAllowBluetooth:若是要支持藍牙耳機電話,則須要設置這個選項。
四、AVAudioSessionCategoryOptionDefaultToSpeaker: 若是在VoIP模式下,但願默認打開免提功能,須要設置這個選項。
五、AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers也是在9.0以後添加的。
六、AVAudioSessionCategoryOptionAllowBluetoothA2DP、AVAudioSessionCategoryOptionAllowAirPlay是10以後新加的,用
來支持藍牙A2DP耳機和AirPlay。
五:模式
經過上面的描述,基本上的設置是能知足咱們的需求了,你再回過頭去看一下咱們上面說的三個設置category的方法,你會發現第三個方法裏面有一個NSString類型的mode參數,有沒有想過這個mode是什麼?其實它又是另外的一個大的設置內容,哇,是否是以爲太多東西了,我也以爲,哈哈,這個mode的具體內容也有同行幫咱們總結過了,表示感謝,咱們看看下面內容:
固然設置這個模式的時候,你也能夠作預判:
@property(readonly) NSArray<NSString *> *availableModes;
看你的設備具體支持那些mode,對mode咱們也是作一個說明吧,說說有那些:
一、AVAudioSessionModeDefault 每種類別默認的就是這個模式,全部要想還原的話,就設置成這個模式。
二、AVAudioSessionModeVoiceChat 主要用於VoIP場景,此時系統會選擇最佳的輸入設備,好比插上耳機就使用耳機上的麥克風進行採集。此時有個反作用,他會設置類別的選項爲"AVAudioSessionCategoryOptionAllowBluetooth"從而支持藍牙耳機。
三、AVAudioSessionModeVideoChat 主要用於視頻通話,好比QQ視頻、FaceTime。時系統也會選擇最佳的輸入設備,好比插上耳機就使用耳機上的麥克風進行採集而且會設置類別的選項爲"AVAudioSessionCategoryOptionAllowBluetooth" 和 "AVAudioSessionCategoryOptionDefaultToSpeaker"。
四、AVAudioSessionModeGameChat 適用於遊戲App的採集和播放,好比「GKVoiceChat」對象,通常不須要手動設置
另外幾種和音頻APP關係不大,通常咱們只須要關注VoIP或者視頻通話便可。設置mode能夠在咱們前面說的設置category的時候一塊兒設置,也能夠利用下面的方法單獨的設置:
- (BOOL)setMode:(NSString *)mode error:(NSError **)outError
六:處理中斷事件
咱們要是作音視頻相關的App,這個中斷事件的處理就必須是咱們要考慮的事情了。
AVAudioSession提供了多種Notifications來進行此類情況的通知。其中未來電話、鬧鈴響等都歸結爲通常性的中斷,用AVAudioSessionInterruptionNotification來通知,其回調回來的userInfo主要包含兩個鍵:
一、AVAudioSessionInterruptionTypeKey: 取值爲AVAudioSessionInterruptionTypeBegan表示中斷開始,咱們應該暫停播放和採集,取值爲AVAudioSessionInterruptionTypeEnded表示中斷結束,咱們能夠繼續播放和採集。
二、AVAudioSessionInterruptionOptionKey: 當前只有一種值AVAudioSessionInterruptionOptionShouldResume表示此時也應該恢復繼續播放和採集。
而將其餘App佔據AudioSession的時候用AVAudioSessionSilenceSecondaryAudioHintNotification來進行通知。其回調回來的userInfo鍵爲:AVAudioSessionSilenceSecondaryAudioHintTypeKey 可能包含的值以下:
一、AVAudioSessionSilenceSecondaryAudioHintTypeBegin: 表示其餘App開始佔據Session
二、AVAudioSessionSilenceSecondaryAudioHintTypeEnd: 表示其餘App開始釋放Session
七:對線路改變的響應
在iOS設備上天啊及或者是移除音頻輸出後者輸入線路時候,就會引發線路改變,有多重緣由會致使線路的改變,好比用戶插入或者拔出耳機時候就有線路的改變發生,一樣的AVAudioSession會廣播一個描述該變化的通知。
AVAudioSessionRouteChangeNotification 就是咱們前面說的線路改變時候發出的通知。咱們最後就把這個通知裏面info參數AVAudioSessionRouteChangeReasonKey對應的值列舉出來,也就是把改變的緣由列舉出來:
經過上面的這些內容,咱們就對AVFoundation有了一個基本的瞭解,基礎的東西也是《AV Foundation 開發祕籍》第一二章的大體內容就總結完了,後面的內容咱們會再接着總結。
第二篇也差很少總結完了,爭取這兩天發出來,有問題歡迎討論!
個人博客即將同步至騰訊雲+社區,邀請你們一同入駐。