AVAudioSession

AVAudioSession 是iOS APP中用来设置音频环境,一台手机在不外接设备下,音频相关硬件分别是麦克风,扬声器,听筒。在多个APP都需要用到这些硬件设备时,就需要通过AVAudioSession来统一设置和管理。

AVAudioSession Method

AVAudioSession.h文件非常长,但是里面大部分都是注释和Enum,常用方法不多,下面列举下常用的方法。

- (BOOL)setActive:(BOOL)active error:(NSError **)outError;
- (BOOL)setActive:(BOOL)active withOptions:(AVAudioSessionSetActiveOptions)options error:(NSError **)outError;

这两个方法为激活或者停用APP的音频会话,激活成功后其他APP的音频会话会中断,需要注意的是,两个方法都是同步操作,也就是会阻塞线程,在无其他APP是出于激活状态的时候,激活只需3ms左右,但是如果其他APP已激活了音频会话,自己APP激活会先中断其他APP的会话,调用测试需要约800ms,非常耗时,建议不要频繁操作。在iOS 8 后,如果当前会话正在处理其他IO操作,调用改方法停止音频会话是,会返回code=AVAudioSessionErrorCodeIsBusy的Error。

另外一个方法增加了AVAudioSessionSetActiveOptions属性,这个后面在详细说明。

- (void)activateWithOptions:(AVAudioSessionActivationOptions)options completionHandler:(void (^)(BOOL activated, NSError * _Nullable error))handler;

异步激活会话,和上面的方法类似,不过是异步的,且只有激活操作。

- (BOOL)setCategory:(AVAudioSessionCategory)category error:(NSError **)outError;
- (BOOL)setCategory:(AVAudioSessionCategory)category withOptions:(AVAudioSessionCategoryOptions)options error:(NSError **)outError;
- (BOOL)setCategory:(AVAudioSessionCategory)category mode:(AVAudioSessionMode)mode options:(AVAudioSessionCategoryOptions)options error:(NSError **)outError;//iOS10+
- (BOOL)setCategory:(AVAudioSessionCategory)category mode:(AVAudioSessionMode)mode routeSharingPolicy:(AVAudioSessionRouteSharingPolicy)policy options:(AVAudioSessionCategoryOptions)options error:(NSError **)outError;//iOS11+
- (BOOL)setMode:(AVAudioSessionMode)mode error:(NSError **)outError

这几个方法都是设置音频会话的category、options、mode,随着iOS版本不同,新增了一些参数。

- (void)requestRecordPermission:(PermissionBlock)response

检测是否有录音权限。

- (BOOL)overrideOutputAudioPort:(AVAudioSessionPortOverride)portOverride error:(NSError **)outError;

暂时更改当前的音频端口,AVAudioSessionCategoryPlayAndRecord模式下设置AVAudioSessionPortOverrideSpeaker时,可无视其他设置,使用话筒录音和扬声器播放。

- (BOOL)setPreferredInput:(nullable AVAudioSessionPortDescription *)inPort error:(NSError **)outError;

设置音频路由的首选输入端口。

AVAudioSession方法基本就上门那些,下面看下常用的属性。

Property

@property (readonly) AVAudioSessionCategory category;

AVAudioSessionCategoryAmbient
当前App的播放声音可以和其他app播放的声音共存,当锁屏或按静音时停止。一般用于背景音播放。

AVAudioSessionCategorySoloAmbient
只能播放当前App的声音,其他app的声音会停止,当锁屏或按静音时停止。

AVAudioSessionCategoryPlayback
只能播放当前App的声音,其他app的声音会停止,当锁屏或按静音时不会停止。

AVAudioSessionCategoryRecord
只能用于录音,其他app的声音会停止,当锁屏或按静音时不会停止

AVAudioSessionCategoryPlayAndRecord
在录音的同时播放其他声音,当锁屏或按静音时不会停止

AVAudioSessionCategoryAudioProcessing
使用硬件解码器处理音频,该音频会话使用期间,不能播放或录音,已弃用

AVAudioSessionCategoryMultiRoute
多种音频输入输出,可将不同音频数据流同时路由到不同输出设备的类别

@property (readonly) AVAudioSessionCategoryOptions categoryOptions;

AVAudioSessionCategoryOptionMixWithOthers
适用于AVAudioSessionCategoryPlayAndRecord, AVAudioSessionCategoryPlayback, and AVAudioSessionCategoryMultiRoute, 确定此会话中的音频是否与其他音频应用中的活动会话中的音频混合在一起。

AVAudioSessionCategoryOptionDuckOthers
适用于AVAudioSessionCategoryAmbient, AVAudioSessionCategoryPlayAndRecord, AVAudioSessionCategoryPlayback, and AVAudioSessionCategoryMultiRoute, 当来自此会话的音频播放时,会导致来自其他会话的音频音量会减小。

AVAudioSessionCategoryOptionAllowBluetooth
适用于AVAudioSessionCategoryRecord and AVAudioSessionCategoryPlayAndRecord, 用于是否支持蓝牙设备耳机等

AVAudioSessionCategoryOptionDefaultToSpeaker
适用于AVAudioSessionCategoryPlayAndRecord ,用于将声音从Speaker播放,外放,即免提

AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers
适用于AVAudioSessionCategoryPlayAndRecord, AVAudioSessionCategoryPlayback, and AVAudioSessionCategoryMultiRoute, 播放此应用的音频内容时,是否暂停来自其他应用的连续语音内容。iOS9 新增。

AVAudioSessionCategoryOptionAllowBluetoothA2DP
适用于AVAudioSessionCategoryPlayAndRecord,蓝牙和a2dp,iOS10 新增。

AVAudioSessionCategoryOptionAllowAirPlay
适用于AVAudioSessionCategoryPlayAndRecord,airplay,iOS10 新增。

@property (readonly) AVAudioSessionMode mode;
@property (readonly) NSArray<AVAudioSessionMode> *availableModes;

AVAudioSessionModeDefault
默认的模式,适用于所有的场景

AVAudioSessionModeVoiceChat
适用类别 AVAudioSessionCategoryPlayAndRecord ,应用场景VoIP,将允许的音频路由数量减少到仅适用于VoIP应用程序的数量,并且可以使用适当的系统提供的信号处理。

AVAudioSessionModeGameChat
适用类别 AVAudioSessionCategoryPlayAndRecord ,应用场景游戏录制,在Game Kit由GKVoiceChat自动设置,无需手动调用。

AVAudioSessionModeVideoRecording
适用类别 AVAudioSessionCategoryPlayAndRecord,AVAudioSessionCategoryRecord 应用场景视频录制

AVAudioSessionModeMoviePlayback
适用类别 AVAudioSessionCategoryPlayBack 应用场景视频播放

AVAudioSessionModeVideoChat
适用类别 AVAudioSessionCategoryPlayAndRecord ,应用场景视频通话

AVAudioSessionModeMeasurement
适用类别AVAudioSessionCategoryPlayAndRecord,AVAudioSessionCategoryRecord,AVAudioSessionCategoryPlayback

AVAudioSessionModeSpokenAudio

@property (readonly) AVAudioSessionRouteSharingPolicy routeSharingPolicy;
//其他APP是否正在播放音频,iOS8后建议使用secondaryAudioShouldBeSilencedHint
@property (readonly, getter=isOtherAudioPlaying) BOOL otherAudioPlaying;
//当前路由的描述,包括零个或多个输入端口以及零个或多个输出端口
//里面包含了AVAudioSessionPortDescription类型inputs和outputs数组
@property (readonly) AVAudioSessionRouteDescription *currentRoute;

AVAudioSession (AVAudioSessionHardwareConfiguration)

AVAudioSessionHardwareConfiguration 主要是用来设置和获取当前路由中音频硬件当前状态的属性集。

//设置首选的采样率
- (BOOL)setPreferredSampleRate:(double)sampleRate error:(NSError **)outError;
//首选的采样率
@property (readonly) double preferredSampleRate
//设置首选I/O缓冲时间,I/O缓冲时间是指单音频输入/输出周期的时长。
//比如说I/O缓冲时间为0.005s,那么在每一个音频I/O周期里,在获取输入时,会收到0.005s的音频,在输出时,必须提供0.005s的音频。
//通常来说I/O缓冲时间的范围是0.005s至0.93s
- (BOOL)setPreferredIOBufferDuration:(NSTimeInterval)duration error:(NSError **)outError;
//I/O缓冲时间
@property (readonly) NSTimeInterval preferredIOBufferDuration
//设置首选的音频输入信道数
//只能在设置Audio Session的Category和mode,并在激活session后调用
- (BOOL)setPreferredInputNumberOfChannels:(NSInteger)count error:(NSError **)outError;
//首选的音频输入信道数
@property (readonly) NSInteger preferredInputNumberOfChannels
//设置首选的音频输出信道数
- (BOOL)setPreferredOutputNumberOfChannels:(NSInteger)count error:(NSError **)outError;
//首选的音频输出信道数
@property (readonly) NSInteger preferredOutputNumberOfChannels
//设置输入设备音量增益
- (BOOL)setInputGain:(float)gain error:(NSError **)outError;
//当前音量增益
@property (readonly) float inputGain; /* value in range [0.0, 1.0] */
//是否设置了音量增益
@property (readonly, getter=isInputGainSettable) BOOL inputGainSettable;
//输入设备是否支持音量增益
@property (readonly, getter=isInputAvailable) BOOL inputAvailable
//当前可用输入数据源列表
//此功能仅在某些设备和外接设备上受支持 - 例如,在配备有前置和后置麦克风的iPhone上。
@property (readonly, nullable) NSArray<AVAudioSessionDataSourceDescription *> *inputDataSources;
//当前输入数据源
@property (readonly, nullable) AVAudioSessionDataSourceDescription *inputDataSource;
//设置输入数据源
- (BOOL)setInputDataSource:(nullable AVAudioSessionDataSourceDescription *)dataSource error:(NSError **)outError;
//当前可用输出数据源列表
//部分外接USB配件时支持此功能。
@property (readonly, nullable) NSArray<AVAudioSessionDataSourceDescription *> *outputDataSources;
//当前输出数据源
@property (readonly, nullable) AVAudioSessionDataSourceDescription *outputDataSource;
//设置输出数据源
- (BOOL)setOutputDataSource:(nullable AVAudioSessionDataSourceDescription *)dataSource error:(NSError **)outError;
- (BOOL)setAggregatedIOPreference:(AVAudioSessionIOType)inIOType error:(NSError **)outError;

AVAudioSessionDataSourceDescription

AVAudioSessionDataSourceDescription定义音频输入或输出的数据源(设备)的描述,提供源的名称,位置和方向等信息。

//系统分配的ID
@property (readonly) NSNumber *dataSourceID;
//名称
@property (readonly) NSString *dataSourceName;
//位置和方向可用于区分属于单个端口的多个数据源。 
//例如,对于AVAudioSessionPortBuiltInMic类型的端口,可以使用这些属性来区分上部/前部麦克风和下部/底部麦克风
@property (readonly, nullable) AVAudioSessionLocation location;
//对于设备自然方向指向的方向。
@property (readonly, nullable) AVAudioSessionOrientation orientation;
//支持的麦克风单一指向性
@property (readonly, nullable) NSArray<AVAudioSessionPolarPattern> *supportedPolarPatterns;
//选中的单一指向性
@property (readonly, nullable) AVAudioSessionPolarPattern selectedPolarPattern;
//首先的单一指向性
@property (readonly, nullable) AVAudioSessionPolarPattern preferredPolarPattern;
//设置单一指向性
- (BOOL)setPreferredPolarPattern:(nullable AVAudioSessionPolarPattern)pattern error:(NSError **)outError;
//设备上数据源的位置,相对于设备的自然方向。
AVAudioSessionLocationUpper
AVAudioSessionLocationLower
//对于设备自然方向指向的方向
AVAudioSessionOrientationTop        //上方
AVAudioSessionOrientationBottom     //下方
AVAudioSessionOrientationFront      //前方
AVAudioSessionOrientationBack       //后方
AVAudioSessionOrientationLeft       //左方
AVAudioSessionOrientationRight;     //右方
//麦克风单一指向性
AVAudioSessionPolarPatternOmnidirectional   //全指向
AVAudioSessionPolarPatternCardioid              //单指向 心型
AVAudioSessionPolarPatternSubcardioid;      //

AVAudioSessionPortDescription

有关端口功能及其支持的硬件通道的信息,端口指的就是内置麦克风,扬声器,外接耳机等等。

//AVAudioSessionPort类型
@property (readonly) AVAudioSessionPort portType;
//设备端口名
@property (readonly) NSString *portName;
//端口ID
@property (readonly) NSString *UID;
//设备是否具备内置的语音通话处理功能
//比如AVAudioSessionPortBluetoothHFP和AVAudioSessionPortCarAudio类型的端口
@property (readonly) BOOL hasHardwareVoiceCallProcessing;
//设备通道描述集合
@property (readonly, nullable) NSArray<AVAudioSessionChannelDescription *> *channels;
//设备数据源描述集合
@property (readonly, nullable) NSArray<AVAudioSessionDataSourceDescription *> *dataSources;
//选择的数据源
@property (readonly, nullable) AVAudioSessionDataSourceDescription *selectedDataSource;
//优先的数据源
@property (readonly, nullable) AVAudioSessionDataSourceDescription *preferredDataSource;
//输入端口
AVAudioSessionPortLineIn; /* Line level input on a dock connector */
AVAudioSessionPortBuiltInMic; /* 内置麦克风 */
AVAudioSessionPortHeadsetMic; /* 耳机麦克风 */

/* 输出端口 */
AVAudioSessionPortLineOut; /* Line level output on a dock connector */
AVAudioSessionPortHeadphones; /* 耳机输出 */
AVAudioSessionPortBluetoothA2DP; /* 蓝牙A2DP设备输出 */
AVAudioSessionPortBuiltInReceiver; /* 听筒 */
AVAudioSessionPortBuiltInSpeaker; /* 内置扬声器 */
AVAudioSessionPortHDMI; /* HDMI输出 */
AVAudioSessionPortAirPlay; /* 远程Air Play设备上的输出 */
AVAudioSessionPortBluetoothLE; /* 低功耗蓝牙的输出 */

/* 有输入或输出的类型*/
AVAudioSessionPortBluetoothHFP; /* 蓝牙免提配置文件设备上的输入或输出 */
AVAudioSessionPortUSBAudio; /* 通用USB设备上的输入或输出 */
AVAudioSessionPortCarAudio; /* 通过汽车音响输入或输出 */

AVAudioSessionChannelDescription

//通道名
@property(readonly) NSString *          channelName;
//端口对应的UID
@property(readonly) NSString *          owningPortUID;
//index
@property(readonly) NSUInteger          channelNumber;
//描叙通道的物理位置
@property(readonly) AudioChannelLabel   channelLabel;

Notification

AVAudioSessionInterruptionNotification
中断是iOS用户体验的常见部分。 例如在视频应用中观看电影并且接到电话或FaceTime请求,音频中断时触发此通知,此通知的userInfo字典包含AVAudioSessionInterruptionTypeKey键。
如果中断类型为AVAudioSessionInterruptionTypeBegan,则应用程序的音频会话已中断且不再处于活动状态。 如果中断类型是AVAudioSessionInterruptionTypeEnded,则此字典还包含AVAudioSessionInterruptionOptionKey键,表示是否恢复中断。
注:iOS10以后,如果APP进程进入suspended状态时,系统会先中断音频会话,只有在APP恢复运行时才收到此通知,且还将包含AVAudioSessionInterruptionWasSuspendedKey键,值为YES。
AVPlayer播放器默认注册并处理这个事件。

AVAudioSessionRouteChangeNotification
将音频输入或输出添加到iOS设备或从iOS设备中删除时,会发生路由更改,变化时触发此通知,此通知的userInfo字典包含AVAudioSessionRouteChangeReasonKey和AVAudioSessionRouteChangePreviousRouteKey键,它们提供有关路由更改后和更改前的信息。

AVAudioSessionRouteChangeReasonUnknown = 0 //未知
AVAudioSessionRouteChangeReasonNewDeviceAvailable = 1 //连接了新设备,比如耳机
AVAudioSessionRouteChangeReasonOldDeviceUnavailable = 2 //断开了设备,比如耳机
AVAudioSessionRouteChangeReasonCategoryChange = 3//Category修改了
AVAudioSessionRouteChangeReasonOverride = 4//复写output route,比如PlayAndRecord下从receiver(听筒)改为speaker(扬声器)
AVAudioSessionRouteChangeReasonWakeFromSleep = 6 //从休眠中唤醒
AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory = 7 //该Category没有合适的线路
AVAudioSessionRouteChangeReasonRouteConfigurationChange = 8 //input and output ports没变,但是配置变了,比如port的selectedDataSource

AVAudioSessionMediaServicesWereLostNotification
媒体服务器被杀时,触发此通知,在极少数情况下,系统会终止并重启媒体服务,一般很少这个通知,可用来提示。

AVAudioSessionMediaServicesWereResetNotification
媒体服务器重启时,触发此通知,在极少数情况下,系统会终止并重启媒体服务,收到此通知后需重新对音频会话做初始化设置等。但是不需要重新监听Notification和KVO等,开发者模式下,设置-开发者-重置媒体服务,可主动触发此通知。

AVAudioSessionSilenceSecondaryAudioHintNotification
当来自其他应用程序的主音频开始和停止触发此通知,此通知仅发送给位于前台且具有活动音频会话的APP,即正在前台使用时,后台其他APP有音频播放的情况。
UserInfo带有AVAudioSessionSilenceSecondaryAudioHintTypeKey,值为AVAudioSessionSilenceSecondaryAudioHintTypeBegin代表其他APP开始音频播放,AVAudioSessionSilenceSecondaryAudioHintTypeEnd代表其他APP结束音频播放。