iOS_AVAudioSession详解

Session默认行为

  • 可以进行播放,但是不能进行录制。
  • 当用户将手机上的静音拨片拨到“静音”状态时,此时如果正在播放音频,那么播放内容会被静音。
  • 当用户按了手机的锁屏键或者手机自动锁屏了,此时如果正在播放音频,那么播放会静音并被暂停。
  • 如果你的App在开始播放的时候,此时QQ音乐等其他App正在播放,那么其他播放器会被静音并暂停。

AVAudioSession激活

1
2
3
4
5
6
7
8
9
//AVAudioSession以一个单例实体的形式存在,通过类方法:
+ (AVAudioSession *)sharedInstance;
//虽然系统会在App启动的时候,激活这个唯一的AVAudioSession,
//但是最好还是在自己ViewController的viewDidLoad里面再次进行激活:
- (BOOL)setActive:(BOOL)active error:(NSError * _Nullable *)outError;
//因为AVAudioSession会影响其他App的表现,当自己App的Session被激活,其他App的就会被解除激活,
//如何要让自己的Session解除激活后恢复其他App Session的激活状态呢?
//这里的options传AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation 即可。
- (BOOL)setActive:(BOOL)active withOptions:(AVAudioSessionSetActiveOptions)options error:(NSError * _Nullable *)outError;

七大Category(七种主场景)

  • 如何设置

    1
    - (BOOL)setCategory:(NSString *)category error:(NSError **)outError;
  • 输出、输入、静音状态

    会话类型 说明 是否要求输入 是否要求输出 是否遵从静音键
    Ambient 混音播放,可以与其他音频应用同时播放
    SoloAmbient 独占播放
    Playback 后台播放,独占
    Record 录音模式
    PlayAndRecord 播放和录音,此时可以录音也可以播放
    AudioProcessing 硬件解码音频,此时不能播放和录制
    MultiRoute 多种输入输出,例如可以耳机、USB设备同时播放
  • 具体应用

    • Ambient : 只用于播放音乐时,并且可以和QQ音乐同时播放,比如玩游戏的时候还想听QQ音乐的歌,那么把游戏播放背景音就设置成这种类别。同时,当用户锁屏或者静音时也会随着静音,这种类别基本使用所有App的背景场景。
    • SoloAmbient: 也是只用于播放,但是和"AVAudioSessionCategoryAmbient"不同的是,用了它就别想听QQ音乐了,比如不希望QQ音乐干扰的App,类似节奏大师。同样当用户锁屏或者静音时也会随着静音,锁屏了就玩不了节奏大师了。
    • Playback: 如果锁屏了还想听声音怎么办?用这个类别,比如App本身就是播放器,同时当App播放时,其他类似QQ音乐就不能播放了。所以这种类别一般用于播放器类App
    • Record: 有了播放器,肯定要录音机,比如微信语音的录制,就要用到这个类别,既然要安静的录音,肯定不希望有QQ音乐了,所以其他播放声音会中断。想想微信语音的场景,就知道什么时候用他了。
    • PlayAndRecord: 如果既想播放又想录制该用什么模式呢?比如VoIP,打电话这种场景,PlayAndRecord就是专门为这样的场景设计的 。
    • MultiRoute: 想象一个DJ用的App,手机连着HDMI到扬声器播放当前的音乐,然后耳机里面播放下一曲,这种常人不理解的场景,这个类别可以支持多个设备输入输出。
    • AudioProcessing: 主要用于音频格式处理,一般可以配合AudioUnit进行使用

categoryOptions(微调场景)

  • 如何设置

    1
    - (BOOL)setCategory:(NSString *)category withOptions:(AVAudioSessionCategoryOptions)options error:(NSError **)outError
  • 适用category、作用

    选项 适用Category 作用
    MixWithOthers PlayAndRecord,Playback,MultiRoute 是否可以和其他后台App进行混音
    DuckOthers Ambient,PlayAndRecord,Playback,MultiRoute 是否压低其他App声音
    AllowBluetooth Record,PlayAndRecord 是否支持蓝牙耳机
    DefaultToSpeaker PlayAndRecord 是否默认用免提声音
    InterruptSpokenAudioAndMixWithOthers(iOS9+) PlayAndRecord,Playback,MultiRoute 偶尔的语音
    AllowBluetoothA2DP(iOS10+) PlayAndRecord 蓝牙和a2dp
    AllowAirPlay(iOS10) PlayAndRecord airplay
  • 具体应用

    • MixWithOthers : 如果确实用的AVAudioSessionCategoryPlayback实现的一个背景音,但是呢,又想和QQ音乐并存,那么可以在AVAudioSessionCategoryPlayback类别下在设置这个选项,就可以实现共存了。
    • DuckOthers:在实时通话的场景,比如QQ音乐,当进行视频通话的时候,会发现QQ音乐自动声音降低了,此时就是通过设置这个选项来对其他音乐App进行了压制。
    • AllowBluetooth:如果要支持蓝牙耳机电话,则需要设置这个选项
    • DefaultToSpeaker: 如果在VoIP模式下,希望默认打开免提功能,需要设置这个选项

七大模式

  • 如何设置

    1
    2
    3
    4
    - (BOOL)setMode:(NSString *)mode error:(NSError **)outError
    //在iOS10中还是可以微调的。通过接口:
    - (BOOL)setCategory:(NSString *)category mode:(NSString *)mode options:(AVAudioSessionCategoryOptions)options error:(NSError **)outError
    //iOS9及以下就只能在Category上调了,其实本质是一样的,可以认为是个API糖,接口封装。
  • 适用category、场景

    模式 适用的category 场景
    Default 所有category 默认的模式
    VoiceChat PlayAndRecord VoIP
    GameChat PlayAndRecord 游戏录制,由GKVoiceChat自动设置,无需手动调用
    VideoRecording PlayAndRecord ,Record 录制视频时
    MoviePlayback Playback 视频播放
    Measurement PlayAndRecord ,Record ,Playback 最小系统
    VideoChat PlayAndRecord 视频通话
  • 具体应用

    • Default : 默认值

    • VoiceChat : 执行双向语音通信(如使用网际协议语音VoIP)则使用此模式。此模式适用于IP语音,并且只能与AVAudioSessionCategoryPlayAndRecord类别一起使用。使用此模式时,该设备的音调君合针对语音进行了优化,并且允许路线组仅缩小为适用于语音聊天的路线。此模式同时会启用AVAudioSessionCategoryOptionAllowBluetooth 类别选项支持蓝牙耳机。如果应用程序未将其模式设置为其中一个聊天模式(语音,视频或游戏),则AVAudioSessionModeVoiceChat模式将被隐式设置。另一方面,如果应用程序先前已将其类别设置为AVAudioSessionCategoryPlayAndRecord并将其模式设置为AVAudioSessionModeVideoChat或AVAudioSessionModeGameChat,则实例化语音处理I / O音频单元不会导致模式发生更改。

    • VideoChat : 在线视频会议,选定此模式。只能与AVAudioSessionCategoryPlayAndRecord或AVAudioSessionCategoryRecord类别一起使用。使用此模式时,设备的音调均衡针对语音进行了优化,并且允许的音频路由组仅缩减为适合视频聊天的设置。此模式同时会启用AVAudioSessionCategoryOptionAllowBluetooth类别选线支持蓝牙耳机。

    • GameChat : 该模式由Game Kit代表使用Game Kit的语音聊天服务的应用程序设置。此模式仅适用于AVAudioSessionCategoryPlayAndRecord音频会话类别。不要直接设置此模式。 如果需要类似的行为并且未使用GKVoiceChat对象,请改为使用AVAudioSessionModeVoiceChat或AVAudioSessionModeVideoChat。

    • VideoRecording : 适用于视频录制情景。此模式仅适用于 AVAudioSessionCategoryRecord和AVAudioSessionCategoryPlayAndRecord音频会话类别。在具有多个内置麦克风的设备上,使用距摄像头最近的麦克风。此模式会导致系统提供适当的音频信号处理。将AVCaptureSession 与视频录制模式结合使用。可以很好的控制输入和输出路径。(设置自动配置应用音频会话属性会根据使用的设备和摄像机自动选择最佳输入路由。)

    • Measurement : 如果应用正在执行音频输入或输出的测试。此模式适用于需要将输入和输出信号的系统提供的信号处理量将至最低的应用程序。如果在具有多个内置麦克风的设备上录制,则使用主麦克风。用于AVAudioSessionCategoryPlayback,AVAudioSessionCategoryRecord或AVAudioSessionCategoryPlayAndRecord音频会话类别。

    • MoviePlayback : 如果应用正在播放电影内容,请指定此模式。使用此模式时,将采用信号处理来增强某些音频路由(如内置扬声器或耳机)的电影播放。 只能在AVAudioSessionCategoryPlayback音频会话类别中使用此模式。

    • SpokenAudio : 当想要在另一个应用播放短语音频时暂停当前音频时,用于持续说话音频的模式。在iOS 8和更低版本以及iOS 9中,如果不设置此模式,偶尔从导航和应用程序中听到的语音与音频混合在一起,或造成两种音频的混淆。 此模式通过为中断应用程序使用AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers音频会话类别选项来避免此问题。 中断应用程序的音频结束后,可以恢复中断的语音。

AVAudioSession提供的通知

  • 系统中断响应通知(电话、闹铃等)AVAudioSessionInterruptionNotification

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    //添加通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleInterrupt:) name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]];

    //中断处理
    - (void)handleInterrupt:(NSNotification *)notification {
    NSDictionary *info = notification.userInfo;
    AVAudioSessionInterruptionType type = [info[AVAudioSessionInterruptionTypeKey] unsignedIntegerValue];

    if (type == AVAudioSessionInterruptionTypeBegan) {
    // 中断开始(更新UI状态 暂停播放)我们应该暂停播放和采集

    } else {
    // 中断结束 我们可以继续播放和采集
    AVAudioSessionInterruptionOptions option = [info[AVAudioSessionInterruptionOptionKey] unsignedIntegerValue];
    if (option == AVAudioSessionInterruptionOptionShouldResume) {

    // 是否再次播放
    }

    }
    }
  • 外设改变通知(插入拔出耳机)AVAudioSessionRouteChangeNotification
    音频播放过程中,插入耳机等会导致播放渠道的更改。插入耳机,音频正常播放,但是Apple规定,耳机内播放的内容可能是隐私信息。因此,拔掉耳机,音频应该是暂停状态。整个过程系统会发送AVAudioSessionRouteChangeNotification通知,供应用处理。具体参数参考苹果官网

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    //添加通知
    [[NSNotificationCenter defaultCenter] addObserver:self
    selector:@selector(handleRouteChange:)
    name:AVAudioSessionRouteChangeNotification
    object:[AVAudioSession sharedInstance]];
    //处理事件
    - (void)handleRouteChange:(NSNotification *)notification {
    NSDictionary *info = notification.userInfo;
    AVAudioSessionRouteChangeReason reason =
    [info[AVAudioSessionRouteChangeReasonKey] unsignedIntValue];

    if (reason == AVAudioSessionRouteChangeReasonOldDeviceUnavailable) {
    // 耳机断开事件
    // 获取前一个channel信息
    AVAudioSessionRouteDescription *previousRoute =
    info[AVAudioSessionRouteChangePreviousRouteKey];
    AVAudioSessionPortDescription *previousOutput = previousRoute.outputs[0];
    NSString *portType = previousOutput.portType;
    if ([portType isEqualToString:AVAudioSessionPortHeadphones]) {
    // 前一个channel输出是耳机类型,暂停播放
    }
    }
    }
  • 其他通知

    • AVAudioSessionMediaServicesWereLostNotification
      当媒体服务终止时通知主线程
      将该通知作为提示来在重新启动服务之前做相关处理
      此notification不包含userInfo

    • AVAudioSessionMediaServicesWereResetNotification
      媒体服务重新启动时通知主线程
      不包含userInfo

    • AVAudioSessionSilenceSecondaryAudioHintNotification
      当其他app的首要音频开始播放或者停止时通知主线程
      userInfo中AVAudioSessionSilenceSecondaryAudioHintTypeKey的值为AVAudioSessionSilenceSecondaryAudioHintType类型

扬声器和听筒的切换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//方法一 切换这个方法会自动切换设备 耳机的插拔会自动切换
if (_isSpeakerMode) {//扬声器模式
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker error:nil];
}else{
//在PlayAndRecord这个category下,听筒会成为默认的输出设备
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:0 error:nil];
}

//方法二 切换这个方法会自动切换设备 耳机需要自己判断
if ([self hasHeadset]) {
[[AVAudioSession sharedInstance] overrideOutputAudioPort:AVAudioSessionPortOverrideNone error:nil];
} else{
[[AVAudioSession sharedInstance] overrideOutputAudioPort:_isSpeakerMode?AVAudioSessionPortOverrideSpeaker: AVAudioSessionPortOverrideNone error:nil];
}

参考文章

苹果官网
iOS - AVAudioSession详解
AVAudioSession - Category、Model、Options、Error参数详解