1. AVAudioSession 概述
最近在做vivo耳机的快捷操作学习模块。和音频打交道,必须要弄清楚
AVAudioSession。
先看下苹果的官方图:
可以看到AVAudioSession就是用来管理多个APP对音频硬件设备(麦克风,扬声器)的资源使用。
举例一下AVAudioSession可以做这些事情
- 设置自己的APP是否和其他APP音频同时存在,还是中断其他APP声音
- 在手机调到静音模式下或者锁屏情况下,自己的APP音频是否可以播放出声音
- 电话或者其他APP中断自己APP的音频的事件处理
- 指定音频输入和输出的设备(比如是听筒输出声音,还是扬声器输出声音)
- 是否支持录音,录音同时是否支持音频播放
2. AVAudioSession Category
AVAudioSession的接口比较简单。APP启动的时候会自动帮激活AVAudioSession,当然我们可以手动激活代码如下。
ruby
//导入头文件 #import <AVFoundation/AVFoundation.h> //AVAudioSession是一个单例类 AVAudioSession *session = [AVAudioSession sharedInstance]; //AVAudioSessionCategorySoloAmbient是系统默认的category [session setCategory:AVAudioSessionCategorySoloAmbient error:nil]; //激活AVAudioSession [session setActive:YES error:nil];
可以看到设置session这里有两个参数,category和options
Category iOS下目前有七种,每种Category都对应是否支持下面四种能力
developer.apple.com/documentati...
- Interrupts non-mixable apps audio:是否打断不支持混音播放的APP
- Silenced by the Silent switch:是否会响应手机静音键开关
- Supports audio input:是否支持音频录制
- Supports audio output:是否支持音频播放
- 是否压低别的app的音频声音
下面用图表来直观的看下每种category具体的能力集
Category | 是否允许音频播放/录音 | 是否打断其他不支持混音APP | 是否会被静音键或锁屏键静音 |
AVAudioSessionCategoryAmbient | 只支持播放 | 否 | 是 |
AVAudioSessionCategoryMultiRoute | 支持播放,支持录制 | 是 | 否 |
AVAudioSessionCategoryPlayAndRecord | 支持播放,支持录制 | 默认YES,可以重写为NO | 否 |
AVAudioSessionCategoryPlayback | 只支持播放 | 默认YES,可以重写为NO | 否 |
AVAudioSessionCategoryRecord | 只支持录制 | 是 | 否(锁屏下仍可录制) |
AVAudioSessionCategorySoloAmbient | 只支持播放 | 是 | 是 |
- AVAudioSessionCategoryAmbient,只支持音频播放。这个 Category,音频会被静音键和锁屏键静音。并且不会打断其他应用的音频播放。
- AVAudioSessionCategorySoloAmbient,这个是系统默认使用的 Category,只支持音频播放。音频会被静音键和锁屏键静音。和AVAudioSessionCategoryAmbient不同的是,这个会打断其他应用的音频播放
- AVAudioSessionCategoryPlayback,只支持音频播放。你的音频不会被静音键和锁屏键静音。适用于音频是主要功能的APP,像网易云这些音乐app,锁屏后依然可以播放。
需要注意一下,选择支持在静音键切到静音状态以及锁屏键切到锁屏状态下仍然可以播放音频 Category 时,必须在应用中开启支持后台音频功能,详见 UIBackgroundModes。
- AVAudioSessionCategoryRecord,只支持音频录制。不支持播放。
- AVAudioSessionCategoryPlayAndRecord,支持音频播放和录制。音频的输入和输出不需要同步进行,也可以同步进行。需要音频通话类应用,可以使用这个 Category。
- AVAudioSessionCategoryMultiRoute,支持音频播放和录制。允许多条音频流的同步输入和输出。(比如USB连接外部扬声器输出音频,蓝牙耳机同时播放另一路音频这种特殊需求)
我们也可以通过AVAudioSession的属性来读取当前设备支持的Category
@property(readonly) NSArray<NSString *> *availableCategories;
这样可以保证设备兼容性。
设置Category的代码示例如下
objectivec
NSError *setCategoryError = nil; BOOL isSuccess = [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:&setCategoryError]; if (!success) { //这里可以读取setCategoryError.localizedDescription查看错误原因 }
3. AVAudioSession Mode&&Options
刚刚介绍的Category定义了七种主场景,实际开发需求中有时候需要对Category进行微调整,我们发现这个接口还有两个参数Mode和Options。
css
/* set session category and mode with options */ - (BOOL)setCategory:(NSString *)category mode:(NSString *)mode options:(AVAudioSessionCategoryOptions)options error:(NSError **)outError API_AVAILABLE(ios(10.0), watchos(3.0), tvos(10.0));
AVAudioSession Mode
我们通过读取下面这条属性获取当前设备支持的Mode
@property(readonly) NSArray<NSString *> *availableModes;
iOS下有七种mode来定制我们的Category行为
developer.apple.com/documentati...
模式 | 兼容的 Category | 场景 |
AVAudioSessionModeDefault | All | 默认模式 |
AVAudioSessionModeVoiceChat | AVAudioSessionCategoryPlayAndRecord | VoIP |
AVAudioSessionModeGameChat | AVAudioSessionCategoryPlayAndRecord | 游戏录制,GKVoiceChat自动设置 |
AVAudioSessionModeVideoRecording | AVAudioSessionCategoryPlayAndRecord AVAudioSessionCategoryRecord | 录制视频 |
AVAudioSessionModeMoviePlayback | AVAudioSessionCategoryPlayback | 视频播放 |
AVAudioSessionModeMeasurement | AVAudioSessionCategoryPlayAndRecord AVAudioSessionCategoryRecord AVAudioSessionCategoryPlayback | 最小系统 |
AVAudioSessionModeSpokenAudio | AVAudioSessionCategorySoloAmbient、AVAudioSessionCategoryPlayback、AVAudioSessionCategoryPlayAndRecord、AVAudioSessionCategoryMultiRoute | 有声读物 |
AVAudioSessionModeVoicePrompt | 语音提示 | |
AVAudioSessionModeVideoChat | AVAudioSessionCategoryPlayAndRecord | 视频通话 |
下面逐一介绍下每个Mode
- AVAudioSessionModeDefault,默认模式,与所有的 Category 兼容
- AVAudioSessionModeVoiceChat,适用于VoIP 类型的应用。只能是 AVAudioSessionCategoryPlayAndRecord Category下。在这个模式系统会自动配置AVAudioSessionCategoryOptionAllowBluetooth 这个选项。系统会自动选择最佳的内置麦克风组合支持语音聊天。
- AVAudioSessionModeVideoChat,用于视频聊天类型应用,只能是 AVAudioSessionCategoryPlayAndRecord Category下。适在这个模式系统会自动配置 AVAudioSessionCategoryOptionAllowBluetooth 和 AVAudioSessionCategoryOptionDefaultToSpeaker 选项。系统会自动选择最佳的内置麦克风组合支持视频聊天。
- AVAudioSessionModeGameChat,适用于游戏类应用。使用 GKVoiceChat 对象的应用会自动设置这个模式和 AVAudioSessionCategoryPlayAndRecord Category。实际参数和AVAudioSessionModeVideoChat一致,游戏语音聊天
- AVAudioSessionModeVideoRecording,适用于使用摄像头采集视频的应用。只能是 AVAudioSessionCategoryPlayAndRecord 和 AVAudioSessionCategoryRecord 这两个 Category下。这个模式搭配 AVCaptureSession API 结合来用可以更好地控制音视频的输入输出路径。(例如,设置 automaticallyConfiguresApplicationAudioSession 属性,系统会自动选择最佳输出路径。
- AVAudioSessionModeMeasurement,最小化系统,适用于希望将系统提供的用于输入和/或输出音频信号的信号处理的影响最小化的应用。只用于 AVAudioSessionCategoryPlayAndRecord、AVAudioSessionCategoryRecord、AVAudioSessionCategoryPlayback 这几种 Category。
- AVAudioSessionModeMoviePlayback,适用于播放视频的应用。只用于 AVAudioSessionCategoryPlayback 这个Category。
- AVAudioSessionModeSpokenAudio 模式的音频会话;只要会话处于活动状态,它就会暂停来自其他应用程序的音频。音频会话失活后,系统恢复被中断的应用程序的音频。
- AVAudioSessionModeVoicePrompt 当程序内音频为简单的语音提示时使用。适用于导航中的播报
AVAudioSession Options
我们还可以使用options去微调Category行为,如下表
Option | Option功能说明 | 兼容的 Category |
AVAudioSessionCategoryOptionMixWithOthers | 支持和其他APP音频 mix | AVAudioSessionCategoryPlayAndRecord AVAudioSessionCategoryPlayback AVAudioSessionCategoryMultiRouteAVAudioSessionCategoryAmbient |
AVAudioSessionCategoryOptionDuckOthers | 系统智能调低其他APP音频音量 | AVAudioSessionCategoryPlayAndRecord AVAudioSessionCategoryPlayback AVAudioSessionCategoryMultiRoute |
AVAudioSessionCategoryOptionAllowBluetooth | 支持蓝牙音频输入 | AVAudioSessionCategoryRecord AVAudioSessionCategoryPlayAndRecord |
AVAudioSessionCategoryOptionDefaultToSpeaker | 设置默认输出音频到扬声器 | AVAudioSessionCategoryPlayAndRecord |
AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers | 音频播放过程中,支持中断其他应用 | AVAudioSessionCategoryPlayback AVAudioSessionCategoryPlayAndRecord AVAudioSessionCategoryMultiRoute |
AVAudioSessionCategoryOptionAllowBluetoothA2DP | 支持立体声蓝牙 | AVAudioSessionCategoryAmbientAVAudioSessionCategorySoloAmbientAVAudioSessionCategoryPlaybackAVAudioSessionCategoryPlayAndRecord |
AVAudioSessionCategoryOptionAllowAirPlay | 支持远程AirPlay | AVAudioSessionCategoryPlayAndRecord |
- AVAudioSessionCategoryOptionMixWithOthers:AVAudioSessionCategoryPlayAndRecord 、AVAudioSessionCategoryMultiRoute默认不设置,若设置后,当程序同时启动音频输入输出时,允许程序后台运行;AVAudioSessionCategoryPlayback默认不设置,若设置后,无论是铃声还是在静音模式下,仍然能够播放
- AVAudioSessionCategoryOptionDuckOthers:当前session处于active时,其他音频就是回避状态(压低声音) AVAudioSessionCategoryPlayAndRecord、AVAudioSessionCategoryPlayback、AVAudioSessionCategoryMultiRoute 默认不混音,不回避
- AVAudioSessionCategoryOptionAllowBluetooth:允许将蓝牙作为可用途径。支持AVAudioSessionCategoryPlayAndRecord、AVAudioSessionCategoryRecord
- AVAudioSessionCategoryOptionDefaultToSpeaker:允许改变音频session默认选择内置扬声器(免提);仅支持AVAudioSessionCategoryPlayAndRecord
- AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers:如果设置了这个选项,系统就会将你的音频与其他音频会话混合,但是会中断(并停止)使用AVAudioSessionModeSpokenAudio模式的音频会话;只要会话处于活动状态,它就会暂停来自其他应用程序的音频。音频会话失活后,系统恢复被中断的应用程序的音频。
- AVAudioSessionCategoryOptionAllowBluetoothA2DP:A2DP是一种立体声、仅输出的配置文件用于更高带宽的音频。如果使用AVAudioSessionCategoryAmbient、AVAudioSessionCategorySoloAmbient或AVAudioSessionCategoryPlayback类别,系统会自动路由到A2DP端口;从iOS 10.0开始,使用AVAudioSessionCategoryPlayAndRecord类别的应用程序也可以将输出路由到配对的蓝牙A2DP设备。要启用此行为,请在设置音频会话的类别时传递此类别选项。
- AVAudioSessionCategoryOptionAllowAirPlay:设置此选项可使音频会话将音频输出路由到AirPlay设备。设置为AVAudioSessionCategoryPlayAndRecord,则只能显式地设置此选项。对于大多数其他音频会话类别,系统隐式地设置此选项。
注意: 如果应用中使用到MPNowPlayingInfoCenter,最好避免设置AVAudioSessionCategoryOptionMixWithOthers;因为一旦设置了这个值之后,那么MPNowPlayingInfoCenter就不能正常显示信息
调优我们的Category
通过Category和合适的Mode和Options的搭配我们可以调优出我们的效果,下面举两个应用场景:
用过高德地图的都知道,在后台播放QQ音乐的时候,如果导航语音出来,QQ音乐不会停止,而是被智能压低和混音,等导航语音播报完后,QQ音乐正常播放,这里我们需要后台播放音乐,所以Category使用AVAudioSessionCategoryPlayback,需要混音和智能压低其他APP音量,所以Options选用 AVAudioSessionCategoryOptionMixWithOthers和AVAudioSessionCategoryOptionDuckOthers
代码示例如下
objectivec
BOOL isSuccess = [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers | AVAudioSessionCategoryOptionDuckOthers error:&setCategoryError];
又或者我希望AVAudioSessionCategoryPlayAndRecord这个Category默认的音频由扬声器播放,那么可以调用这个接口去调整Category
- (BOOL)setCategory:(NSString *)category withOptions:(AVAudioSessionCategoryOptions)options error:(NSError **)outError
通过选择合适和Category,mode和options,就可以调优音频的输入输出,来满足日常开发需求(需要注意的是Category,mode,option是搭配使用的,而不是简单组合,也就是说某种Category支持某些mode和option,从上面的表中也可以看出这一点)
4.AVAudioSessionRouteSharingPolicy
音频路由是指 app 在播放音频时使用的音频输出设备。移动端常见的音频路由有听筒、扬声器、有线耳机和蓝牙耳机。
路由策略:
- AVAudioSessionRouteSharingPolicyDefault 遵循正常的规则路由音频输出
- AVAudioSessionRouteSharingPolicyLongFormAudio 将输出路由到共享的长格式音频输出
- AVAudioSessionRouteSharingPolicyLongForm 已废弃
- AVAudioSessionRouteSharingPolicyIndependent 应用程序不应试图直接设置此值。在iOS上,当路由选择器UI用于将视频定向到无线路由时,系统将设置此值。
- AVAudioSessionRouteSharingPolicyLongFormVideo 将输出路由到共享的长格式视频输出(使用此策略的应用程序在其Info.plist中设置AVInitialRouteSharingPolicy键)
关于路由可以看官方这篇文章 developer.apple.com/documentati...
路由的应用,AVPlayer监控您的应用程序的音频会话并适当地响应路由更改。当用户连接耳机时,播放会按预期继续。当他们断开耳机时,播放会自动暂停。
5.AVAudioSessionNotification
AVAudioSession有以下多个通知来提示用户事件;
- AVAudioSessionInterruptionNotification:系统中断响应通知
- AVAudioSessionRouteChangeNotification 系统路由改变通知
- AVAudioSessionSilenceSecondaryAudioHintNotification:其他应用音频状态提示通知
AVAudioSessionInterruptionNotification
当App内音频被中断,系统会将AudioSession置为失活状态,音频也会因此立即停止。当一个别的App的AudioSession被激活并且它的类别未设置与系统类别或你应用程序类别混合时,中断就会发生。你的应用程序在收到中断通知后应该保存当时的状态,以及更新用户界面等相关操作。通过注册AVAudioSessionInterruptionNotification通知,可以处理中断的开始和结束。
/* keys for AVAudioSessionInterruptionNotification / / Value is an NSNumber representing an AVAudioSessionInterruptionType / AVAudioSessionInterruptionTypeKey typedef NS_ENUM(NSUInteger, AVAudioSessionInterruptionType) { AVAudioSessionInterruptionTypeBegan = 1, / the system has interrupted your audio session / AVAudioSessionInterruptionTypeEnded = 0, / the interruption has ended / }; / Only present for end interruption events. Value is of type AVAudioSessionInterruptionOptions.*/ AVAudioSessionInterruptionOptionKey typedef NS_OPTIONS(NSUInteger, AVAudioSessionInterruptionOptions) { AVAudioSessionInterruptionOptionShouldResume = 1 };
提示:这里的通知的中断开始和中断结束不一定都会出现(苹果文档中有提到)
选择不同的音频播放技术,处理中断方式也有差别,具体如下:
- System Sound Services:使用 System Sound Services 播发音频,系统会自动处理,不受APP控制,当中断发生时,音频播放会静音,当中断结束后,音频播放会恢复。
- AV Foundation framework:AVAudioPlayer 类和 AVAudioRecorder 类提供了中断开始和结束的 Delegate 回调方法来处理中断。中断发生,系统会自动停止播放,需要做的是记录播放时间等状态,更新用户界面,等中断结束后,再次调用播放方法,系统会自动激活session。
- Audio Queue Services, I/O audio unit:使用aduio unit这些技术需要处理中断,需要做的是记录播放或者录制的位置,中断结束后自己恢复audio session。
- OpenAL:使用 OpenAL 播放时,同样需要自己监听中断。管理 OpenAL上下文,用户中断结束后恢复audio session。
AVAudioSessionRouteChangeNotification
当用户连接或者断开音频输入,输出设备时(插拔耳机、或者蓝牙耳机的断开、连接),音频线路发生变更,通过注册AVAudioSessionRouteChangeNotification通知,可以在音频线路发生变更时做出相应处理。
/* keys for AVAudioSessionRouteChangeNotification / / value is an NSNumber representing an AVAudioSessionRouteChangeReason */ AVAudioSessionRouteChangeReasonKey typedef NS_ENUM(NSUInteger, AVAudioSessionRouteChangeReason) { AVAudioSessionRouteChangeReasonUnknown = 0, AVAudioSessionRouteChangeReasonNewDeviceAvailable = 1, //设备可用(耳机插好) AVAudioSessionRouteChangeReasonOldDeviceUnavailable = 2, //设备不可用(耳机被拔下) AVAudioSessionRouteChangeReasonCategoryChange = 3, // 设置的分类被改变 AVAudioSessionRouteChangeReasonOverride = 4, // 路由被覆盖 AVAudioSessionRouteChangeReasonWakeFromSleep = 6, // 设备被激活 AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory = 7, //当前类别没有路由时返回 AVAudioSessionRouteChangeReasonRouteConfigurationChange = 8 // added in iOS 7 };
AVAudioSessionSilenceSecondaryAudioHintNotification
当来自其他应用的主音频启动,或者停止时,通过注册AVAudioSessionSilenceSecondaryAudioHintNotification通知,前台应用可以作为启动或者禁用次要音频的提示;
/* keys for AVAudioSessionSilenceSecondaryAudioHintNotification / / value is an NSNumber representing an AVAudioSessionSilenceSecondaryAudioHintType / AVAudioSessionSilenceSecondaryAudioHintTypeKey typedef NS_ENUM(NSUInteger, AVAudioSessionSilenceSecondaryAudioHintType) { AVAudioSessionSilenceSecondaryAudioHintTypeBegin = 1, / the system is indicating that another application's primary audio has started / AVAudioSessionSilenceSecondaryAudioHintTypeEnd = 0, / the system is indicating that another application's primary audio has stopped */ };
AVAudioSession 常用音频建议
使用AVAudioSessionCategoryRecord,AVAudioSessionCategoryPlayAndRecord,AVAudioSessionCategoryPlayback类别的APP,苹果建议的准则如下:
- 当应用程序进入前台时,请等待用户按下"播放"或"录制"按钮,然后再激活音频会话。
- 当应用程序处于前台时,除非中断,否则请保持音频会话处于活动状态。
- 如果应用程序在过渡到后台时没有活跃的播放或录制音频,请停用其音频会话。这样可以防止其音频会话被另一个不可混合的应用程序中断,或者在应用程序被系统挂起时响应中断其音频会话。
- 在被中断后更新用户界面的播放或录制到暂停。请勿停用音频会话。
- 观察AVAudioSessionInterruptionNotification有关音频会话中断的通知类型。中断结束后,请勿再次开始播放或录制音频,除非该应用在中断之前就已经开始了。
- 如果路由更改是由拔出事件引起的,则暂停播放或录制,但请保持音频会话处于活动状态。
- 假设应用程序的音频会话从挂起状态转换为前台状态时处于失活状态。当用户按下"播放"或"录制"按钮时,重新激活音频会话。
- 确保UIBackgroundModes已设置音频标志。
- 注册远程控制事件(请参阅参考资料MPRemoteCommandCenter),并为您的媒体提供适当的"正在播放"信息(请参阅参考资料MPNowPlayingInfoCenter)。
- 使用一个MPVolumeView对象显示系统音量滑块和路线选择器。
- 使用后台任务而不是静默播放流,以防止应用程序被暂停。
- 要求用户许可使用该requestRecordPermission:方法记录输入。不要依靠操作系统来提示用户。
- 对于录制应用程序,请使用AVAudioSessionCategoryPlayAndRecord类别而不是AVAudioSessionCategoryRecord类别。"仅记录"类别几乎使所有系统输出静音,并且通常对于大多数应用程序而言过于严格。详情可以参照苹果指南
AVAudioSession 声音常用处理
- 播放应用内的音频时暂停外部音乐
css
[[AudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:0 error:&error]; [[AudioSession sharedInstance] setActive:YES error:&error]; [[AudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers error:&error];
- 混音播放外部音频,同时插播一条应用内的语音(播放语音时,外部音频降低音量,播放语音完毕后,外部音频恢复音量)
css
/* start */ [[AudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionDuckOthers error:&error]; /* end */ [[AudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers error:&error];
- 唤起其他App播放
css
[[AudioSession sharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:&error];
项目开发中遇到的问题:
AVAudioSessionInterruptionNotification的使用
来电 闹钟等被打断通知 来电的时候,app不退到后台,InterruptionTypeEnded key无法收到通知 详情看www.jb51.cc/iOS/337680....
objectivec
[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(audioSessionInterruptionNotification:) name:AVAudioSessionInterruptionNotification object:nil];
然后发现CallKit官方库下的CXCallObserver和CXCall两个类有方法可以监听挂断电话的操作
python
//挂断电话监听 这个为AVAudioSessionInterruptionNotification通知的一个补充吧 弥补InterruptionTypeEnded无法收到通知的缺陷 if (@available(iOS 10.0, *)) { self.callObserver = [CXCallObserver new]; [self.callObserver setDelegate:self queue:dispatch_get_main_queue()]; } 代理方法 - (void)callObserver:(CXCallObserver *)callObserver callChanged:(CXCall *)call { NSLog(@"outgoing :%d onHold :%d hasConnected :%d hasEnded :%d",call.outgoing,call.onHold,call.hasConnected,call.hasEnded); /* 拨打: outgoing :1 onHold :0 hasConnected :0 hasEnded :0 拒绝: outgoing :1 onHold :0 hasConnected :0 hasEnded :1 链接: outgoing :1 onHold :0 hasConnected :1 hasEnded :0 挂断: outgoing :1 onHold :0 hasConnected :1 hasEnded :1 对方未接听时挂断: outgoing :1 onHold :0 hasConnected :0 hasEnded :1 新来电话: outgoing :0 onHold :0 hasConnected :0 hasEnded :0 保留并接听: outgoing :1 onHold :1 hasConnected :1 hasEnded :0 另一个挂掉: outgoing :0 onHold :0 hasConnected :1 hasEnded :0 保持链接: outgoing :1 onHold :0 hasConnected :1 hasEnded :1 对方挂掉: outgoing :0 onHold :0 hasConnected :1 hasEnded :1 */ if (call.outgoing == 0 && call.onHold == 0 && (call.hasConnected == 0 || call.hasConnected == 1) && call.hasEnded == 1) {//挂断 NSLog(@"callChanged"); self.isLearnOperationMusicStop = NO; if (self.isAlert) { // [self continuelearningWithOtherAbnormal]; return; } self.isAlert = YES; [VEAlertViewController showAlertWithTitle:VML(vml_common_reminder) message:VML(vml_ear_learn_whether_continue) buttonTitles:@[VML(vml_common_cancel),VML(vml_common_go_on)] clickBlock:^(NSUInteger index) { self.isAlert = NO; if (index == 1) { self.isLearnOperationMusicStop = NO; [self continuelearningWithOtherAbnormal]; } else { [self popCurrentController]; } }]; } }
但是因为这个类iOS10以上才能使用,所以无奈放弃
当页面有视频播放时,其他app的音频会被占据
设置混音状态
#pragma mark - 播放无音频的视频,需要设置成混音,不影响其他APP音频播放
objectivec
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient withOptions:AVAudioSessionCategoryOptionMixWithOthers|AVAudioSessionCategoryOptionDefaultToSpeaker error:nil]; [[AVAudioSession sharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
取消混音状态
[[AVAudioSession sharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil]; //取消混音的目的是让其他app音频继续播放所以用AVAudioSessionCategoryAmbient options是0,但是用AVAudioSessionCategorySoloAmbient的话其他app音频将不会播放 [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient withOptions:0 error:nil];
抢占音频
objectivec
[[AVAudioSession sharedInstance] setActive:YES withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil]; [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategorySoloAmbient withOptions:AVAudioSessionCategoryOptionMixWithOthers error:nil];
恢复其他音频播放
objectivec
[[AVAudioSession sharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
实际开发中用AVPlayer去播放音频文件,开始播放会有预加载环节,这样在循环播放的时候,播放结束再开始中间会有1秒多的空隙,用以下这种通知监听播放结束的方法仍无法完美解决,只好用了两个AVPlayer去交替循环播放
objectivec
[[NSNotificationCenterdefaultCenter] addObserver:selfselector:@selector(moviePlayDidEnd:) name:AVPlayerItemDidPlayToEndTimeNotificationobject:self.player.currentItem]; - (void)moviePlayDidEnd:(NSNotification*)notification{ AVPlayerItem*item = [notification object]; [item seekToTime:kCMTimeZero]; [self.player play]; }
这样就产生一个问题,当尝试用以下代码去恢复其他音频播放的时候,发现恢复不了了.猜测是AVAudioSession调度音频会话也是在不同的AVPlayer去调度,当你用两个AVPlayer时.AVAudioSession调度就会出错,目前还没找到
objectivec
[[AVAudioSession sharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];