音频会话(Audio Session)编码向导

概述

概览

  • 音频会话管理音频行为
  • categories 代表音频规则
  • 中断处理通知
  • 通知支持音频路由的更改
  • 音频会话控制设置配置
  • 音频会话保护用户隐私

配置音频会话

  • 音频默认行为
  • 配置音频会话
  • 使用多路径category 扩展选项
  • 启用后台音频

激活音频会话

  • 系统如何解决竞争性音频需求
  • 激活或者取消激活音频会话
  • 检查其他音频是否正在播放

应对中断

  • 中断声明周期
  • 音频中断处理技术
  • 观察音频中断
  • 响应流媒体重置

应对路由的改变

  • 各种音频硬件路由变化
  • 观察音频路由改变

配置设备硬件

  • 选择首选音频硬件值
  • 设置首选音频硬件值
  • 选择和配置麦克风

包含用户隐私

  • 请求录音的权限

昨天翻译了官方文档写了博客多媒体音频播放简单介绍。回头再去看LFLiveKit的音频录制部分,发现能看懂点,但是又不完全懂。因此这里就需要把Audio session 详细学一下。

概述

音频是ios ,tvos和watchos的托管服务。系统通过使用音频会话管理应用程序,应用程序之间和设备基本的音频行为。

音频会话(Audio Session)编码向导_第1张图片

从图中我们能看出,音频会话既可以管理录音,也可以管理播放。

我们可以使用音频会话向系统传递我们打算如何在应用中使用音频。此音频会话充当应用和操作系统之间的中介-进而是底层音频硬件。我们可以使用它来向操作系统传达应用程序音频的性质,而无需详细的说明特定行为或与音频硬件的所需交互。将这些细节的管理委派给音频会话可确保最佳的管理用户的音频体验。

概览

我们可以使用AVAudioSession实例与应用程序的音频会话进行交互:

  • 配置音频会话类别和模式,以便与系统通信我们打算如何在应用中使用音频。
  • 激活应用程序的音频会话以使我们设置的类别和模式配置生效
  • 订阅并响应重要的音频会话通知,例如音频中断和路由更改
  • 执行高级别音频设备配置,例如设置采样率,I/O缓冲持续时间和通道数。
音频会话管理音频行为

音频会话是应用和操作系统之间的中介,用于配置应用的音频行为。启动后,应用程序将自动的提供单一音频会话(单例)。我们可以配置它,让其提供所需的行为并且激活它让该行为生效。

categories 代表音频规则

表达音频行为的主要机制就是音频会话的category。通过设置category,我们可以指示应用程序是输入路径还是输出路径(录音还是播放),是否希望音乐继续与音频一起播放,等等。

AVFoundation定义了许多音频会话category,以及一组覆盖和修改器开关,可以让我们根据应用的个性或者角色定义音频行为。不同的类别支持不同的行为,例如可支持播放,录制或者录制回放。当系统知道我们的app所需要的音频规则时,他会为我们提供对硬件资源的适当访问权限。系统还可以确保设备上的其他音频以适合我们应用的方式运行,并符合用户期望。

通过指定模式我们还可以进一步定制某些category,该模式用于专门给一些category指定行为。例如,当app使用视频录制模式时候,系统可能会选择与使用默认模式时选择的内置麦克风不同的内置麦克风。该系统还可以进行针对视频录制来调整麦克风信号处理。

中断处理通知

音频中断会立即停止音频。当来自app的竞争音频会话被激活并且该会话未被系统category以与我们的会话混合时,就发生中断了。因此我们的应该应该保存状态,更新用户界面等来响应中断。要在音频中断开始和结束时接受通知,我们应该注册通知。类型看AVAudioSessionInterruptionNotification

通知支持音频路由的更改

当用户通过对接或取消对接设备,或者通过插入或者拔出耳机来启动音频路径更改时候,用户会有特别的期望。iOS Human Interface Guidelines 描述这些期望,并提供了如何满足这些期望的指南。我们可以通过注册通知AVAudioSessionRouteChangeNotification 来观察路径的更改。

音频会话控制设置配置

app是无法直接控制设备硬件的,但是音频会话为我们提供了请求首先硬件设备的设置的接口。这些接口使我们可以执行高级别音频设备配置,例如设置采样率,I/O缓冲持续时间和音频通道数。

音频会话保护用户隐私

单独或者与视频一起录制音频的app在录制之前需要用户授权。在用户授权之前,app只能静音录制。
AVAudioSession 提供了请求此权限的接口并确定用户的隐私设置。


配置音频会话

音频会话的category是标识app的一组音频行为的key。通过设置category,我们可以向系统指出我们的音频意图。例如,当翻转Ringer/Silent开关时候我们的音频是否应该继续,我们可以通过设置音频会话category 覆盖和修改器开关来定义音频行为。

Category 通过铃声/静音开关或者锁屏是否需要静音 是否中断不可以混合的音频 支持录音和播放
AVAudioSessionCategoryAmbient Yes No Output only
AVAudioSessionCategorySoloAmbient (Default) Yes Yes Output only
AVAudioSessionCategoryPlayback No Yes by default; no by using override switch Output only
AVAudioSessionCategoryRecord No (recording continues with screen locked) Yes Input only
AVAudioSessionCategoryPlayAndRecord No Yes by default; no by using override switch Input and output
AVAudioSessionCategoryMultiRoute No Yes Input and output

注意,为了通过铃声/静音开关设置或者屏幕锁屏的时候能继续播放音乐,我们在info.plist 中添加UIBackgroundModes键。

上表中每一个音频会话category都指定对应一下每个行为的特定响应集:

  • 中断不可以混合的app的音频:如果是yes,那么当您的应用激活其音频会话时,不可混合的应用会被中断。
  • 静音开关静音:如果yes,当用户激活静音开关时,音频静音。
  • 支持音频输入:如果yes,那么则允许应用音频输入(录制)
  • 支持音频暑促:如果yes,那么则允许音频输出(播放)

大多数app应用只需要启动的时候设置一次category,但是我们可以根据需要更改category。我们可以在音频会话在激活状态下更改;但是最好在更改category或者其他会话属性之前停用音频会话。在会话停用时进行这些更改可防止对音频系统进行不必要的重新配置。

下面列举下mode

Mode identifiers Compatible categories
AVAudioSessionModeDefault All
AVAudioSessionModeMoviePlayback AVAudioSessionCategoryPlayback
AVAudioSessionModeVideoRecording AVAudioSessionCategoryPlayAndRecord
AVAudioSessionCategoryRecord
AVAudioSessionModeVoiceChat AVAudioSessionCategoryPlayAndRecord
AVAudioSessionModeGameChat AVAudioSessionCategoryPlayAndRecord
AVAudioSessionModeVideoChat AVAudioSessionCategoryPlayAndRecord
AVAudioSessionModeSpokenAudio AVAudioSessionCategoryPlayback
AVAudioSessionModeMeasurement AVAudioSessionCategoryPlayAndRecord
AVAudioSessionCategoryRecord
AVAudioSessionCategoryPlayback

音频默认行为

所有的ios,tvos和watchos应用程序都有一个默认的音频会话,预先配置如下:

  • 支持音频播放,不允许录音
  • 在ios中,将响铃/静音开关设置为静音模式会使app正在播放的任何音频静音。
  • 在ios中,当设备被锁定时,引用程序的音频会被静音
  • 当app在播放音频时,任何其他的背景音频(例如音乐应用播放的音频)都会被静音。

默认音频会话具有有用的行为,但在大多数情况下,我们应该对其进行自定义已更好的满足应用需求。要更改行为,需要配置app的音频会话。

配置音频会话

配置音频会话的主要方法是设置category,音频会话category定义一组音频行为。每个catergory 相关的行为不是由app设置,而是由操作系统设置。Apple可能会在未来版本的操作系统中改进category行为,因此我们最好的策略是选择最准确描述我们想要的音频行为意图的category。

category设置app的基本音频行为,我们可以通过设置category的mode来进一步专门话这些行为。例如:IP语音(VoIP)app 将使用AVAudioSessionCategoryPlayAndRecord。通过将音频会话的模式设置为AVAudioSessionModeVoiceChat,这样就可以专门的针对VoIP app使用此类别的行为。该模式可以确保通过系统提供的信号处理为语音优化信号。

某些category通过在会话上设置一个或者多个category选项来支持覆盖器默认行为,可参看AVAudioSessionCategoryOptions。例如,与AVAudioSessionCategoryPlayback category 关联的默认行为是会在会话激活时中断其他系统音频。在大多数情况下,播放app需要次行为。但是,如果我们希望音频与其他系统音频混合,那么可以通过在会话上设置AVAudioSessionCategoryOptionMixWithOthers选项来覆盖此行为。

下列是设置会话category的小例子


-(void)setAudioSessionCategory{
   AVAudioSession * session = [AVAudioSession sharedInstance];
    @try {
        [session setCategory:AVAudioSessionCategoryPlayback error:nil];
        [session setCategory:AVAudioSessionCategoryPlayback mode:AVAudioSessionModeMoviePlayback options:0 error:nil];
    } @catch (NSException *exception) {
        NSLog(@"%@",exception);
    } @finally {
        
    }
}

使用多路径category 扩展选项

多路径category与气体category工作方式略有不同。所有其他category遵循最后设置生效规则。但是,多路由category使app能够使用所有的连接的输出端口,而不是仅仅使用最后的使用的端口。例如:如果我们通过HDMI输出路径收听音频并插入一组耳机,我们的app讲继续通过hdmi输出路径播放音乐,同事还可以通过耳机播放音频。

通过多路径category,我们的app还可以将不同的音频流发送到不同的输出路径上。例如:我们的app可以将一个音频流发送到左耳机,另一个音频流发送到右耳机,第三个发送到HDMI路由。下图展示将多个音频流发送到不同音频路由的示例


音频会话(Audio Session)编码向导_第2张图片

根据设备和任何连接的附件,以下是有效的输出路径组合:

  • USB和耳机
    +HDMI 和耳机
  • lineout 和耳机

多路由category仅支持使用单个输入的端口。

重要事项:仅当没有连接其他符合条件的输出端口(USB,HDMI,LineOut)时,才可以使用内置扬声器。

启用后台音频

ios和tvos app要求在后台启用某些功能。播放app所需的常见功能是播放后台音频。启用此功能,当用户切换到其他app或者锁定其iOS设备时,app的音频可以继续。在ios中启用高级包房功能(例如airlpay流媒体和画中画播放)也需要此功能。

配置这些功能最简单的方式是用xcode。选择target 选择capabiliityies 选项卡。在capabilities选项卡下,将后台模式开关设置为开即可。


音频会话(Audio Session)编码向导_第3张图片

启用此后台模式并使用适当的类别配置音频会话后,我们的应该就可以播放后台音频了。

注意:要允许视频演示的音频部分可以在后台播放,可以参考 中的Media Playback Programming Guide中的Playing Background Audio


激活音频会话

我们通过category mode options 配置好了音频会话。要使配置生效,我们需要激活音频会话。

系统如何解决竞争性音频需求

随着app启动,内置的app(消息,音乐,safiri,手机)可能正在后台运行。这些中的每一个都可以产生音频:一个文本通知到达,10分钟钱开始的播客正在播放等等。

这里比方,我们将设备视为机场,将app表示为滑行飞机,那么系统可以作为控制塔。我们的app可以发出音频请求并少女革命其所需要的优先级,但是对“停机坪上”发生的事情的最终权限来自系统,我们只能使用音频会话与控制塔进行通信。下图说明了一个典型的场景-我们的app请求播放时候使用音频。在这种情况下,我们的app会中断音乐应用。

音频会话(Audio Session)编码向导_第4张图片
  • 第一步,我们的应用请求激活其音频会话。例如,我们可以在应用启动时候提出此类请求,也可以响应用户点击音频录制和播放应用中的“播放按钮”。
  • 第二步,系统考虑激活请求。具体来说,他会考虑为我们的音频会话分配category。如图2,我们的app使用了一个要求其他音频静音的category。
  • 第三步和第四步,系统停用其他app的音频会话,停止其音频播放。
  • 第五步,系统激活app的音频会话开始播放。

激活或者取消激活音频会话

最热AVFoundation播放和录制类会自动激活音频会话,但是手动激活它会让我们有机会测试激活是否成功。但是,如果我们的app具有播放和暂停功能,我们需要编写代码,以便用户必须在激活会话之前按播放。同样,在更改音频会话的激活非激活状态时,需要检查以确保是否成功。我们应该编写代码优雅的处理系统拒绝激活会话的情况。

当时钟或者日历闹钟或者来电激活时会取消音频会话。当用户解除警报或者选择电话呼叫时,系统会允许我们再次激活音频会话。是否在中断结束后重新激活会话取决于app的类型,该类型是在Audio Guidelines By App Type描述的。


-(void)setAudioSessionCategory{
   AVAudioSession * session = [AVAudioSession sharedInstance];
    @try {
        [session setCategory:AVAudioSessionCategoryPlayback error:nil];
        [session setCategory:AVAudioSessionCategoryPlayback mode:AVAudioSessionModeMoviePlayback options:0 error:nil];
        [session setActive:YES error:nil];

    } @catch (NSException *exception) {
        NSLog(@"%@",exception);
    } @finally {
    }
}

取消激活音频会话传入false即可。

使用AVFoundation对象(AVPlayer,AVAudioRecoder等)播放或者录制音频时,系统会在中断结束时处理音频会话重新激活。但是,如果我们注册通知消息并明确重新激活音频会话,那么可以验证重新激活是否成功,并且可以更新应用诚信度状态和用户界面。

  • 对于VoIP app的音频会话确保仅在app处理呼叫时才处于激活状态。在后台,准备好接听电话,VoIPapp的音频会话不应该是活动的。
  • 使用录制category的app的音频会话确保在录制时是处于激活状态。在录制开始之前和结束的时候,需要确保音频会话处于非活动状态,以允许播放其他声音,例如,传入消息警报。
  • 如果app支持后台播放和录制,那么app在未主动使用音频(或者使用音频)时,在进入后台时停用其音频会话。这样做让系统释放音频资源,以便其他进程可以使用它们。当操作系统暂停app的进程时,它还会阻止app的音频会话被停用(app都干掉了,音频会话肯定要干掉啦)。可以看这里 AVAudioSessionInterruptionWasSuspendedKey。

检查其他音频是否正在播放

当我们的app处于活动状态时,设备上可能已经在播放声音了。例如,当用户启动app时候,音乐app可能正在播放歌曲。如果我们的app是游戏,了解其他音频是否正在播放很重要。许多游戏都有音乐声道和音效。在iOS Human Interface Guidelines中音频建议假设用户在玩游戏的时候期望其他音频以及游戏的声音效果继续播放。

在app的applicationDidBecomeActive:方法中,检查音频会话的secondaryAudioShouldBeSilencedHint属性以确定音频是否在播放。当具有不可混合音频会话的另一个app正在播放音频时,该值是true。应用程序使用此属性作为提示,以消除应用程序运行的次要的音频。例如,AVAudioSessionCategoryAmbient类的游戏可以使用此属性来确定是否应将其音轨静音,同时保持其静音效果。

我们还可以订阅AVAudioSessionSilenceSecondaryAudioHintNotification类型通知,以确保在可选的辅助音频经验开始或者结束时通知app。该通知仅发送给当前位于前台并且具有活动音频会话的已注册监听器。

具体代码

-(void)setNotifation{
    
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(notification:) name:AVAudioSessionSilenceSecondaryAudioHintNotification object:[AVAudioSession sharedInstance]];
}


-(void) notification:(NSNotification *) notification{
    // Determine hint type
    id  userInfo = notification.userInfo;
    NSNumber *  typeValue = userInfo[AVAudioSessionSilenceSecondaryAudioHintTypeKey];

    if (typeValue.intValue == AVAudioSessionSilenceSecondaryAudioHintTypeBegin) {
        
    }
}

应对中断

增加音频会话中断代码可以让app在接收到电话呼叫,日历闹钟时钟响起或者其他应用程序激活音频会话时可以正常运行。

音频中断会让音频停止。当来自app的竞争音频会话被激活并且该会话未被系统category以与我们的app混合时,就会发生中断(通俗的说,就是人家想独自搞,不要我们就把我们暂停了)。会话变成非激活状态后,系统会发送中断通知,我们这个时候可以保存状态,更新用户界面等来响应该通知。

app 可能在中断后就暂停了。当用户接听电话就能发生这种情况。如果用户忽略了呼叫或者取消了警报,系统会发出中断结束消息,并且我们的app将继续运行。要恢复音频,我们必须重新激活音频会话。

中断声明周期

下图说明播放app的音频会话中断之前,期间和之后的事件序列。


音频会话(Audio Session)编码向导_第5张图片
  • 1.激活app,播放音频
  • 2.一个FaceTime 请求到达。系统激活FaceTime的音频会话
  • 3.系统取消我们app的音频会话,这时候,app播放已经停止了。
  • 4.系统发送通知,告知我们的app音频会话被取消掉了
  • 5.app处理这个终端,例如,包括更新用户界面等操作
  • 6.如果用户从facetime取消了音频会话,那么,系统发送一个通知告诉我们app音频中断结束了
  • 7.我们的app处理这个音频中断结束事件。例如恢复播放,更新用户界面。
  • 8.点击暂停播放。

音频中断处理技术

通过通知来处理中断。我们在中断代码中执行的操作取决于我们使用的音频技术以及用于播放,录制,音频格式转换,读取六十音频数据包等的内容。一般来说,从用户角度来看,我们需要确保尽可能的少的中断,以及最优雅的可能恢复。

下表总结了中断期间石洞的音频会话行为。如果使用AVFoundation播放或者录制对象,系统会自动处理其中的一些步骤

After interruption starts Save state and context
Update user interface
After interruption ends Restore state and context
Update user interface
Reactivate audio session, if appropriate for the app

下表总结了如何根据技术处理音频中断。

Audio technology How interruptions work
AVFoundation framework 系统会在中断时自动暂停播放和录制,并在恢复播放和录制时重新激活音频会话
如果要在app启动之间保存和恢复播放位置,需要在中断和app退出时保存播放位置
Audio Queue Services, I/O audio unit 这些技术使沃恩的app可以控制处理中断。我们需要保存播放或者录制的位置,并在中断结束后重新激活音频会话
System Sound Services 使用系统声音服务播放的声音在中断开始时保存静音。如果中断结束,那么声音会再次播放。应用无法影响使用次播放技术的声音的中断行为

观察音频中断

这里只是贴下代码,重复内容

-(void)setNotifation{
    
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(notification:) name:AVAudioSessionSilenceSecondaryAudioHintNotification object:[AVAudioSession sharedInstance]];
}


-(void) notification:(NSNotification *) notification{
    // Determine hint type
    id  userInfo = notification.userInfo;
    NSNumber *  typeValue = userInfo[AVAudioSessionSilenceSecondaryAudioHintTypeKey];

    if (typeValue.intValue == AVAudioSessionSilenceSecondaryAudioHintTypeBegin) {
        
    }
}

响应流媒体重置

媒体服务器通过共享服务器进程提供音频和其他多媒体功能。虽然很少见,但是当您的应用处于活动状态的时候,媒体服务器可能会重置。注册AVAudioSessionMediaServicesWereResetNotification通知来监视介质服务器重置。收到通知后,我们的app需要执行以下操作:

  • 处理孤立的音频对象(如播放器,录音机,转换器或者音频队列)并创建新的音频对象。
  • 重置正在跟踪的所有内部音频状态,包括AVAudioSession的所有属性。
  • 在适当的时候,使用setActive:error: 方法重新激活AVAudioSession实例。

重要提示:app无需要重新注册任何AVAudioSession的通知或者AVAudioSession属性上的键值观察器。

如果您想知道媒体服务器何时首次变的不可以用,那么我们需要注册AVAudioSessionMediaServicesWereLostNotification通知。但是大多数应用只需要响应重置通知。仅当应用程序必须响应介质服务器丢失后但在重置介质服务器之前发生的用户事件,才使用该通知。

我们可以通过从设置中开发人员菜单中选择“重置媒体服务触发”来触发媒体服务。 使用这个可以让app轻松的重置媒体服务触发通知。


应对路由的改变

当app在运行时,用户可能会插入耳机或者拔出耳机,或者使用带有音频连接的扩展台。iOS Human Interface Guidelines 中描述了app如何响应此类事件。想要实现这些建议,请编写音频会话代码来处理路由的改变。有些app(如游戏)并不总是必须响应路径的改变。但是剩下的app(媒体播放器)必须响应所有路径的改变。

各种音频硬件路由变化

音频硬件路由是用于音频信号的有线电子路径。当设备的用户插入或者拔出耳机的时候,系统会自动更改音频硬件路由。如果我们注册通知AVAudioSessionRouteChangeNotification,则可以通知app此类更改。

下图描述了录制和播放过程中各种路由路径变化的事件顺序。图中底部显示的四种可能结果来自我们编写的属性侦听器回到函数所采取的操作

音频会话(Audio Session)编码向导_第6张图片

如图所示,系统最初确定应用后的音频路径。当app运行期间,他会继续监控活动路线。首先考虑用户点击应用中的“录制”按钮的情况,由图左侧的“录制开始”框开始。

在录制期间,用户可以插入或者拔出耳机-看到图中左下方的菱形决策元素。作为相应,系统发送包含改变原因和先前路由的路径改变通知。我们的应该应该停止录制。

播放的情况类似,但结果不同,如图右侧所示。如果用户在播放期间拔下耳机,那么应该暂停音频。如果用户在播放期间插入耳机,我们的app应该继续播放。

观察音频路由改变

音频路由改变的原因有很多,包括用户插入耳机,连接蓝牙LE耳机或者拔掉USB音频接口。了解这些改变何时发生对app很重要,我们可以根据这些改变来更新用户界面活更改其内部状态。通过注册通知AVAudioSessionRouteChangeNotification来获取路由的更改。

-(void)setRouteNotifation{
    
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(routeNotification:) name:AVAudioSessionRouteChangeNotification object:[AVAudioSession sharedInstance]];
}

-(void)routeNotification:(NSNotification * )notification{
    // Determine hint type
    id  userInfo = notification.userInfo;
    NSNumber *  typeValue = userInfo[AVAudioSessionRouteChangeReasonKey];
    if (typeValue.intValue == AVAudioSessionRouteChangeReasonNewDeviceAvailable) {
        AVAudioSession * session = [AVAudioSession sharedInstance];
        for (AVAudioSessionPortDescription * output in session.currentRoute.outputs) {
            if (output.portType == AVAudioSessionPortHeadphones) {
                
            }
        }  
    }
}

路由改变发送的通知信息都在userinfo字典中,提供路过更改的详细信息。我们可以通过userinfo字典中检索AVAudioSessionRouteChangeReason来确定此更改的原因。连接新设备时,原因是AVAudioSessionRouteChangeReasonNewDeviceAvailable,删除一个设备,它是AVAudioSessionRouteChangeReasonOldDeviceUnavailable。

当新设备可用时候,我们可以查询音频会话的currentRoute属性来确定当前路由音频输出的位置。这将返回一个AVAudioSessionRouteDescription对象,该对象列出了所有的音频会话的输入和输出。删除设备后,我们将从userInfo字典中检索上一个路由的AVAudioSessionRouteDescription对象。这两种情况下,我们都可以的查询AVAudioSessionRouteDescription 的outputs属性,该属性返回AVAudioSessionPortDescription对象的数组,提供音频输出路径的详细信息。

重要提示:如果路径更改原因是AVAudioSessionRouteChangeReasonOldDeviceUnavailable,那么媒体播放应用应该暂停播放,但是如果是AVAudioSessionRouteChangeReasonOverride,则不应该暂停播放。

音频路由更改还可能导致音频会话的采样率,I/O缓冲区持续时间,通道计数活其他与硬件有关的值发生变化。如果这些值对我们很重要,那么请在路由更改后查询他们已查看其值是否已更改。


配置设备硬件

使用音频会话属性,我们可以在运行时优化应用程序的设备硬件音频行为。这样做可以让我们的代码适应其运行设备的特性,以及用户在app运行时所作的改变。

使用AVAudioSession

  • 指定采样率和I/O 缓存区持续时间首选硬件设置
  • 查询硬件特性,例如输入和输出延迟,输入和输出通道数,硬件采样率,硬件音量设置和音频输入的可用性

选择首选音频硬件值

用音频会话指定首选设备设置,例如采样率和硬件I/O缓存持续时间。下表描述这些首选项的好处和成本

Setting Preferred sample rate Preferred I/O buffer duration
High value Example: 48 kHz
+ High audio quality
– Large file or buffer size
Example: 500 mS
+ Less-frequent file access
– Longer latency
Low value Example: 8 kHz
+ Small file or buffer size
– Low audio quality
Example: 5 mS
+ Low latency
– Frequent file access

例如,如果音频质量很重要,并且大文件和缓冲区大小不是很重要,则可以指定高采样率的首选项。

注意:默认音频I/O 缓冲持续时间(44.1KHz)音频约0.02秒可以为大多数应用提供足够的响应速度。我们可以为延迟关键型应用设置较低的I/O持续时间,例如现场乐器监控,一般情况下不需要修改此设置。

设置首选音频硬件值

在激活音频会话之前设置首选硬件值。如果我们已经在运行音频会话,需要将其停用。激活音频会话后,首先值的更改会生效,我们可以在此时验证更改。下列代码显示了如何设置首选硬件值以及如何验他们。


-(void)setSession{
    AVAudioSession * session = [AVAudioSession sharedInstance];
    @try {
        [session setCategory:AVAudioSessionCategoryRecord mode:AVAudioSessionModeDefault options:0 error:nil];
    } @catch (NSException *exception) {
        NSLog(@"%@",exception);
    } @finally {
        
    }
    
    @try {
        [session setPreferredSampleRate:44100 error:nil];
    } @catch (NSException *exception) {
        NSLog(@"%@",exception);
    } @finally {
        
    }
    
    @try {
        [session setPreferredIOBufferDuration:0.005 error:nil];
    } @catch (NSException *exception) {
        NSLog(@"%@",exception);
    } @finally {
        
    }
    @try {
        [session setActive:YES error:nil];
    } @catch (NSException *exception) {
        NSLog(@"%@",exception);
    } @finally {
        
    }
}

注意:当竞争音频会话设置首选硬件值时,系统会优先考虑不可混合的会话。 使用AVAudioSessionCategoryAmbient类别或AVAudioSessionCategoryOptionMixWithOthers选项的音频会话不太可能具有其首选的硬件设置。

选择和配置麦克风

在具有两个或更多内置麦克风的设备上,ios会通过使用音频会话模式自动旋转麦克风。模式指定用于输入的数字信号(DSP)和可能的路由。输入和路由针对每种模式的用例进行了优化。设置模式也可能影响正在使用的路由的其他方面。

重要:在使用任何输入选择功能之前,请为app设置会话类别和模式并激活音频会话

设置首选输入

要发现内置或者链接的输入端口,使用音频会话的availableInputs属性,该属性返回AVAudioSessionPortDescription对象数组,用于描述设备的可用输入的端口。端口可以通过其portType属性进行标识。要设置首选输入端口(内置麦克风,有线麦克风,USBB输入等),请使用音频会话的setPreferredInput:error: 方法。

设置首选数据源

一些端口例如内置麦克风和一些USB配件,支持数据源。app可以通过查询端口描述的dataSources属性来发现可用的数据源。在内置麦克风的情况下,返回的数据源描述对象代表每个单独的麦克风。不同的设备为内置麦克风返回不同的值。例如,iPhone 4和iPhone 4S有两个麦克风:底部和顶部。 iPhone 5有三个麦克风:底部,正面和背面。

可以通过数据源描述的位置属性(上,下)和方向属性(前后等)的组合来识别各个内置麦克风。app使用setPreferredDataSource:error:方法设置首选数据源。

设置首选极坐标图案

一些ios设备支持配置为某些内置麦克风配置麦克风的极性模式。麦克风的极性模式定义了其对声音相对于声源方向的灵敏度。当前的iphone支持为前置和后置麦克风设置首选极性模式。使用数据源对象的supportedPolarPatterns属性返回可用模式。此属性返回数据源支持的极性模式数组(如心形或者全向),或者在没有可选模式返回nil。如果数据源具有许多支持的极坐标模式,则可以使用数据源描述的setPreferredPolarPattern:error方法设置首选极坐标模式

以上知识总结代码实例

代码如下

-(void)mic{
    AVAudioSession * session = [AVAudioSession sharedInstance];
  NSArray * inputs =  session.availableInputs;
    if (inputs.count<=0) {
        return;
    }
    AVAudioSessionPortDescription * builtInmic;
  
    for (AVAudioSessionPortDescription * item in inputs) {
        if (item.portType==AVAudioSessionPortBuiltInMic) {
            builtInmic = item;
            break;
        }
    }
    AVAudioSessionDataSourceDescription * dataSource ;
    for (AVAudioSessionDataSourceDescription * item in builtInmic.dataSources) {
        if (item.orientation == AVAudioSessionOrientationFront) {
            dataSource = item;
            break;
        }
    }
    
    @try {
        [dataSource setPreferredPolarPattern:AVAudioSessionPolarPatternCardioid error:nil];
    } @catch (NSException *exception) {
        
    } @finally {
        
    }
    
    @try {
        [builtInmic setPreferredDataSource:dataSource error:nil];
    } @catch (NSException *exception) {
        
    } @finally {
        
    }
    
    @try {
        [session setPreferredInput:builtInmic error:nil];
    } @catch (NSException *exception) {
        
    } @finally {
        
    }
    
  NSArray * array=   session.currentRoute.inputs;
    for (AVAudioSessionPortDescription * portDesc in array) {
        NSLog(@"port: %@",portDesc.portType);
      AVAudioSessionDataSourceDescription* ds =  portDesc.selectedDataSource;
        if (ds) {
            NSLog(@"name: %@",ds.dataSourceName);
            NSLog(@"polar pattern: %@",ds.selectedPolarPattern?:@"none");
        }
    }
}

包含用户隐私

为了保护用户隐私,app必须在录制音频之前询问并获得用户许可才行。如果用户未授权,则只能记录静音。当我们使用支持录制的catergory并且app尝试使用输入路径时,系统会自动提示用户授权。

请求录音的权限

代码如下

-(void)requtst{
    AVAudioSession * session = [AVAudioSession sharedInstance];
    [session requestRecordPermission:^(BOOL granted) {
        if (granted==YES) {
            //用户授权
        }
    }];
}

在ios 10.0 以后,必须在info.plist 中添加NSMicrophoneUsageDescription字段


Core Audio Overview
audio session programming guide

你可能感兴趣的:(音频会话(Audio Session)编码向导)