夜深时动笔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 开发秘籍》第一二章的大体内容就总结完了,后面的内容咱们会再接着总结。
第二篇也差很少总结完了,争取这两天发出来,有问题欢迎讨论!
个人博客即将同步至腾讯云+社区,邀请你们一同入驻。