AudioSession编程指南(一)

官方文档
音频是iOS、tvOS和watchOS中的托管服务。系统通过使用音频会话在应用程序应用程序间设备级别管理音频行为,它属于一个单独的服务,由操作系统进行调度和管理,音频进程的异常中断并不会导致app的crash. 音频会话的结构如下:

上图中AudioSession作为app和操作系统的中介,进而充当音视频硬件的中介,通过AudioSession提供的便利的API完成与操作系统之间的交互。

概览

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

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

音频会话管理音频行为

  • 音频会话是应用程序和操作系统之间的中介,用于配置应用程序的音频行为。启动后,您的应用程序将自动提供单例音频会话。您可以配置它以提供所需的行为,并激活它以将该行为付诸行动。

类别表示音频角色

  • Category: 表达音频行为的主要机制是音频会话类别。通过设置类别,可以指示应用程序是使用输入还是输出路由,是否希望音乐与音频一起继续播放,等等
  • AVFoundation定义了许多音频会话类别,以及一组覆盖和修改开关,允许您根据应用程序的个性或角色自定义音频行为。各种类别支持回放、录音和录音回放。当系统知道你的应用程序的音频角色时,它会为你提供对硬件资源的适当访问。该系统还确保设备上的其他音频以适合你的应用程序的方式运行,并符合用户的期望。
  • 可以通过指定一个模式进一步定制某些类别,该模式用于专门化给定类别的行为。例如,当应用程序使用视频录制模式时,系统可能会选择与使用默认模式不同的内置麦克风。该系统还可能参与麦克风信号处理,针对视频录制用例进行了调整

通知支持中断处理:

  • 音频中断是指停用应用程序的音频会话,它会立即停止您的音频。当来自应用程序的竞争音频会话被激活并且该会话未被系统分类以与您的会话混合时,就会发生中断。应用程序应该通过保存状态、更新用户界面等方式来响应中断。要在音频中断开始和结束时收到通知,请注册以观察AVAudioSessionInterruptionNotification类型的通知。

通知支持音频路由更改处理:

  • 当用户通过对接或断开设备,或通过插入或拔下耳机来启动音频路由更改时,用户有着特殊的期望。iOS人机界面指南描述了这些期望,并提供了如何满足这些期望的指南。通过注册来观察AVAudioSessionRouteChangeNotification类型的通知来处理路由更改。

音频会话控制设备配置

  • 应用程序不能直接控制设备硬件,但音频会话为您提供了请求首选硬件设备设置的接口。此接口允许您执行高级音频设备配置,如设置采样率I/O缓冲区持续时间音频通道数

音频会话保护用户隐私

  • 单独或与视频一起录制音频的应用程序在允许录制之前需要明确的用户权限。在用户授予你的应用程序录制权限之前,应用程序只能录制静默。AVAudioSession提供了请求此权限和确定用户隐私设置的界面。

配置音频会话

音频会话类别是一个键,用于标识应用程序的一组音频行为。通过设置类别,您可以向系统指示您的音频意图,例如当响铃/静音开关被翻转时,您的音频是否应该继续多个音频会话类别,以及一组覆盖和修改开关,允许您自定义应用程序的音频行为
每个音频会话类别都为以下每个行为指定一组特定的响应:

  • Interrupts Nonmixable apps audio: 是否允许和其它的应用的音频混合
  • Silenced by the Silent switch: 通过静音开关静音,支持用户通过静音开关关闭app的音屏播放,一般都要支持,不然就是流氓app了。
  • Supports audio input: 如果是,则允许应用程序音频输入(录制)
  • Supports audio output: 如果是,则允许应用程序音频输出(播放)。

大多数应用程序只需在启动时设置一次类别,但您可以根据需要随时更改类别。您可以在音频会话处于活动状态时更改它;但是,在更改类别或其他会话属性之前,最好先停用音频会话。在禁用会话时进行这些更改可防止不必要的音频系统重新配置。

音频会话默认行为

  • 所有iOS、tvOS和watchOS应用程序都有一个默认音频会话,其预配置如下:
    • 支持音频播放,但不允许录音。(默认安全,不记录用户会话)
    • 在iOS中,将响铃/静音开关设置为静音模式可使应用程序播放的任何音频静音。(支持静音开关)
    • 在iOS中,当设备被锁定时,应用程序的音频将被静音。(支持锁定暂停)
    • 当你的应用程序播放音频时,音乐应用程序正在播放的任何其他背景音频都将被静音。(不混合)
  • 配置音频会话:

    • 配置音频会话的主要方法是设置其类别。音频会话类别定义了一组音频行为。与每个类别相关联的精确行为不受应用程序控制,而是由操作系统设置。苹果可能会在未来的操作系统版本中改进类别行为,所以你最好的策略是选择最准确地描述你想要的音频行为意图的类别。音频会话类别和模式总结了每个类别的行为详细信息。

      // Access the shared, singleton audio session instance
      let session = AVAudioSession.sharedInstance()
      do {
      // Configure the audio session for movie playback
      try session.setCategory(AVAudioSessionCategoryPlayback,
      mode: AVAudioSessionModeMoviePlayback,
      options: [])
      } catch let error as NSError {
      print("Failed to set the audio session category and mode: \(error.localizedDescription)")
      }

使用“多路径”类别展开选项

  • “多路径”类别的工作方式与其他类别略有不同。所有其他类别都遵循插入输入或输出路由的最后一个设备是主导设备但是,multiroute类别允许应用程序使用所有连接的输出端口,而不是只使用最后一个输入端口。例如,如果您正在通过HDMI输出路径收听音频并插入一组耳机,则您的应用程序将继续通过HDMI输出路径播放音频,同时也通过耳机播放音频。
  • 使用multiroute类别,你的应用程序还可以将不同的音频流发送到不同的输出路由。例如,你的应用程序可以将一个音频流发送到左侧耳机,另一个发送到右侧耳机,第三个发送到HDMI路由。图1-1显示了将多个音频流发送到不同音频路由的示例。
  • 根据设备和任何连接的附件,以下是有效的输出路径组合:
    • 耳机和USB
    • HDMI和耳机
    • 线路输出和耳机
  • multiroute类别支持使用单个输入端口。
    • 注意:仅当未连接其他合格的输出端口(USB、HDMI、LineOut)时,才可使用内置扬声器。

启用背景音频

  • 播放应用程序需要的一个常见功能是播放背景音频。启用此功能后,当用户切换到其他应用程序或锁定其iOS设备时,应用程序的音频可以继续。在iOS中启用AirPlay流媒体和画中画回放等高级播放功能也需要此功能。

激活音频会话
设置完音频会话的类别、选项和模式来配置音频会话。要将配置付诸行动,现在需要激活音频会话。

  • 系统如何解决相互竞争的音频需求: 应用程序可以发出音频请求并声明其所需的优先级
  • 虽然AVFoundation播放和录制类会自动激活音频会话但手动激活它会让您有机会测试激活是否成功。但是,如果你的应用程序有play/pause UI元素,请编写代码,以便用户在激活会话之前必须按play。同样,在更改音频会话的活动/非活动状态时,请检查以确保呼叫成功。编写代码以优雅地处理系统拒绝激活您的会话。 (注意检查激状态)
  • 系统将关闭时钟或日历闹钟或来电的音频会话。当用户解除警报或选择忽略电话呼叫时,系统允许您的会话再次激活。是否在中断结束时重新激活会话取决于应用程序类型
  • 当使用AVFoundation对象(AVPlayer、AVAudioRecorder等)播放或录制音频时,系统会在中断结束时重新激活音频会话。但是,如果注册通知消息并显式重新激活音频会话,则可以验证重新激活是否成功,并且可以更新应用程序的状态和用户界面。
  • 确保VoIP应用程序的音频会话(通常在后台运行)仅在应用程序处理呼叫时处于活动状态。在后台,准备接听电话时,VoIP应用程序的音频会话不应处于活动状态。

  • 确保使用录制类别的应用程序的音频会话仅在录制时处于活动状态在开始录制之前和停止录制时,请确保会话处于非活动状态,以允许播放其他声音,如传入消息警报。

  • 如果应用程序支持后台音频播放或录制,则在进入后台时,如果应用程序未在使用音频(或正在准备使用音频),请停用其音频会话。这样做可以让系统释放音频资源,以便其他进程可以使用它们。它还可以防止应用程序的音频会话在应用程序进程被操作系统挂起时被停用(请参阅avaudiosessioninterruptionwassupendedkey)。

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

  • 当你的应用处于活动状态时,设备上可能已经播放了声音

    • 在应用程序委托的applicationdibecomeactive:方法中,检查音频会话的secondaryAudioShouldBeSilencedHint属性,以确定音频是否已在播放当另一个具有不可混合音频会话的应用程序正在播放音频时,该值为true。应用程序应使用此属性作为提示,使辅助于应用程序功能的音频静音。例如,使用AVAudioSessionCategoryAmbient可以使用此属性来确定是否应在取消静音音效的同时使其音轨静音
    func setupNotifications() {
    NotificationCenter.default.addObserver(self,
    selector: #selector(handleSecondaryAudio),
    name: .AVAudioSessionSilenceSecondaryAudioHint,
    object: AVAudioSession.sharedInstance())
    }
    func handleSecondaryAudio(notification: Notification) {
    // Determine hint type
    guard let userInfo = notification.userInfo,
    let typeValue = userInfo[AVAudioSessionSilenceSecondaryAudioHintTypeKey] as? UInt,
    let type = AVAudioSessionSilenceSecondaryAudioHintType(rawValue: typeValue) else {
    return
    }
    if type == .begin {
    // Other app audio started playing - mute secondary audio
    } else {
    // Other app audio stopped playing - restart secondary audio
    }
    }

应对AudioSession的中断处理

  • 添加音频会话代码来处理中断可以确保当电话到达、时钟或日历闹钟响起或其他应用程序激活其音频会话时,应用程序的音频继续正常运行。
  • 音频中断是指停用应用程序的音频会话,它会立即停止您的音频。当来自应用程序的竞争音频会话被激活并且该会话未被系统分类以与您的会话混合时,就会发生中断。会话变为非活动状态后,系统将发送一条“您被中断了”消息,您可以通过保存状态、更新用户界面等来响应该消息。
  • 中断后,你的应用可能会暂停。当用户接听电话时会发生这种情况。如果用户忽略一个呼叫,或者解除警报,系统将发出“中断结束”消息,你的应用程序将继续运行。要恢复音频,必须重新激活音频会话
  • 中断事件在本例中,FaceTime请求的到达如下所示。编号的步骤与图中的数字相对应

    • 你的应用程序处于活动状态,正在播放音频。
    • FaceTime请求到达。系统激活FaceTime应用程序的音频会话。
    • 系统将停用您的音频会话。此时,应用程序中的播放已停止。
    • 系统会发布一个通知,指示您的会话已停用。
    • 通知处理程序将采取适当的操作。例如,它可以更新用户界面并保存在停止播放时恢复播放所需的信息。
    • 如果用户忽略传入的FaceTime请求而取消中断,则系统将发布一个通知,指示中断已结束。
    • 通知处理程序在中断结束时采取适当的操作。例如,它可能更新用户界面,重新激活音频会话,然后继续播放。
    • 图中未显示)如果用户没有在步骤6中取消中断,而是接受了一个电话呼叫,则您的应用程序将被挂起。
  • 音频中断处理技术

    • 通过注册来观察AVAudioSession发布的中断通知来处理中断。在中断代码中执行的操作取决于您使用的音频技术以及您在播放、录制、音频格式转换、读取流式音频包等方面使用的技术。一般来说,从用户的角度来看,您需要确保尽可能少的中断,以及最优雅的恢复。
    • 表3-1总结了中断期间适当的音频会话行为。如果使用AVFoundation回放或录制对象,系统会自动处理其中一些步骤
    • 基于音频技术的音频中断处理技术:
      • AVFoundation framework:
        • 系统会在中断时自动暂停播放或录制,并在您恢复播放或录制时重新激活音频会话。
        • 如果要在应用程序启动之间保存和恢复播放位置,请在中断时和应用程序退出时保存播放位置
      • Audio Queue Services, I/O audio unit: 这些技术可以让你的应用程序控制中断的处理。您负责保存播放或录制位置,并在中断结束后重新激活音频会话
      • System Sound Services: 当中断开始时,使用系统声音服务播放的声音将静音。如果中断结束,这些声音可以再次播放。*应用程序无法影响使用此播放技术的声音的中断行为。
  • 处理来自Siri的中断

    • 当Siri中断应用程序的播放时,您必须在音频会话处于中断状态时跟踪Siri发出的任何远程控制命令在中断期间,跟踪Siri发出的任何命令,并在中断结束时做出相应的响应。例如,在中断期间,用户要求Siri暂停应用程序的音频播放。当您的应用程序收到中断已结束的通知时,它不应自动恢复播放。相反,应用程序的用户界面应该指示应用程序处于暂停状态。

观察音频中断

  • 注册AVAudioSessionInterruptionNotification通知
  • 处理通知:
func handleInterruption(_ notification: Notification) {
    guard let info = notification.userInfo,
        let typeValue = info[AVAudioSessionInterruptionTypeKey] as? UInt,
        let type = AVAudioSessionInterruptionType(rawValue: typeValue) else {
            return
    }
    if type == .began {
        // Interruption began, take appropriate actions (save state, update user interface)
    }
    else if type == .ended {
        guard let optionsValue =
            userInfo[AVAudioSessionInterruptionOptionKey] as? UInt else {
                return
        }
        let options = AVAudioSessionInterruptionOptions(rawValue: optionsValue)
        if options.contains(.shouldResume) {
            // Interruption Ended - playback should resume
        }
    }
}
- userInfo字典可能包含**AVAudioSessionInterruptionOptions**值。**AVAudioSessionInterruptionOptionShouldResume**的选项值是一个提示,指示如果应用程序在被中断时一直在播放,是否应该自动恢复播放。
- 注意: 系统并不能保证开始中断会有相应的结束中断。你的应用程序需要知道一个切换到前台运行状态或用户按下播放按钮。**无论哪种情况,都要确定你的应用程序是否应该重新激活它的音频会话。**
- 响应媒体服务器重置:
    - 媒体服务器通过共享服务器进程提供音频和其他多媒体功能。虽然很少见,但在应用程序处于活动状态时,媒体服务器可能会重置。注册**AvaudiosessionMediaServicesResetNotification**通知以监视媒体服务器重置。收到通知后,你的应用程序需要执行以下操作:
    - **处理孤立的音频对象(如播放器、录音机、转换器或音频队列)并创建新对**象
    - **重置正在跟踪的所有内部音频状态,包括音频会话的所有属性**
    - **在适当的时候,使用setActive:错误:方法**

响应路线更改

  • 当你的应用程序运行时,用户可能会插入或拔下耳机,或使用带音频连接的扩展底座。iOS人机界面指南描述了应用程序应如何响应此类事件。要实现这些建议,请编写音频会话代码来处理音频硬件路由更改。某些类型的应用程序,比如游戏,并不总是需要对路由更改做出响应。然而,其他类型的应用程序,如媒体播放器,必须对所有的路由更改做出响应。
  • 各种音频硬件路由变化

    • 音频硬件路由是音频信号的有线电子路径。当设备的用户插入或拔出耳机时,系统会自动更改音频硬件路径。如果您注册以观察AVAudioSessionRouteChangeNotification类型的通知,则您的应用程序可以收到此类更改的通知。
    • 图4-1描述了记录和回放过程中各种路由更改的事件序列。图的底部显示了四种可能的结果,它们是由您编写的属性侦听器回调函数执行的操作产生的。
    • 如图所示,在应用启动后,系统会首先确定音频路由。它会在应用程序运行时继续监视活动路由。首先考虑用户点击应用程序中的录制按钮的情况,该按钮由图左侧的“录制开始”框表示。
    • 在录音过程中,用户可以插入或拔下耳机,在图的左下角看到菱形的决策元素。作为响应,系统发送一个路由更改通知,其中包含更改的原因和以前的路由。你的应用程序应该停止录制。
    • 回放的情况类似,但结果不同,如图右侧所示。如果用户在播放过程中拔下耳机插头,你的应用程序应该暂停音频。如果用户在播放过程中插入耳机,你的应用程序应该只允许继续播放。

      func setupNotifications() {
      NotificationCenter.default.addObserver(self,
      selector: #selector(handleRouteChange),
      name: .AVAudioSessionRouteChange,
      object: AVAudioSession.sharedInstance())
      }
      func handleRouteChange(notification: NSNotification) {
      guard let userInfo = notification.userInfo,
      let reasonValue = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt,
      let reason = AVAudioSessionRouteChangeReason(rawValue:reasonValue) else {
      return
      }
      switch reason {
      case .newDeviceAvailable:
      let session = AVAudioSession.sharedInstance()
      for output in session.currentRoute.outputs where output.portType == AVAudioSessionPortHeadphones {
      headphonesConnected = true
      }
      case .oldDeviceUnavailable:
      if let previousRoute =
      userInfo[AVAudioSessionRouteChangePreviousRouteKey] as? AVAudioSessionRouteDescription {
      for output in previousRoute.outputs where output.portType == AVAudioSessionPortHeadphones {
      headphonesConnected = false
      }
      }
      default: ()
      }
      }

      注意: 音频路由更改也可能导致音频会话的采样率、I/O缓冲区持续时间、通道计数或其他硬件相关值的更改。如果这些值对您的应用程序很重要,请在更改路由后查询它们,以查看它们的值是否已更改。

配置设备硬件

  • 使用音频会话属性,您可以在运行时为设备硬件优化应用程序的音频行为。这样做可以使代码适应运行它的设备的特性,以及应用程序运行时用户所做的更改(例如插入耳机或固定设备)。
    • 指定采样率和I/O缓冲区持续时间的首选硬件设置
    • 查询许多硬件特性,例如输入和输出延迟输入和输出通道计数硬件采样率硬件音量设置以及音频输入的可用性
  • 选择首选音频硬件值

    • 使用音频会话可指定首选的设备设置,例如采样率和硬件I/O缓冲区持续时间。表5-1描述了这些偏好的收益和成本。
    • 例如,如果音频质量在应用程序中非常重要,并且大文件或缓冲区大小不是重要问题,则可以指定高采样率的首选项。
  • 设置首选音频硬件值

    • 在激活音频会话之前设置首选硬件值。如果您已经在运行音频会话,请将其停用。对首选值的更改在音频会话激活后生效,此时您可以验证更改。清单5-1显示了如何设置首选硬件值以及如何验证它们。
    let session = AVAudioSession.sharedInstance()
    

// Configure category and mode
do {
try session.setCategory(AVAudioSessionCategoryRecord, mode: AVAudioSessionModeDefault)
} catch let error as NSError {
print("Unable to set category: (error.localizedDescription)")
}

// Set preferred sample rate
do {
try session.setPreferredSampleRate(44_100)
} catch let error as NSError {
print("Unable to set preferred sample rate: (error.localizedDescription)")
}

// Set preferred I/O buffer duration
do {
try session.setPreferredIOBufferDuration(0.005)
} catch let error as NSError {
print("Unable to set preferred I/O buffer duration: (error.localizedDescription)")
}

// Activate the audio session
do {
try session.setActive(true)
} catch let error as NSError {
print("Unable to activate session. (error.localizedDescription)")
}

// Query the audio session's ioBufferDuration and sampleRate properties
// to determine if the preferred values were set
print("Audio Session ioBufferDuration: (session.ioBufferDuration), sampleRate: (session.sampleRate)")

   
- 选择和配置麦克风:

```
// Preferred Mic = Front, Preferred Polar Pattern = Cardioid
let preferredMicOrientation = AVAudioSessionOrientationFront
let preferredPolarPattern = AVAudioSessionPolarPatternCardioid
 
// Retrieve your configured and activated audio session
let session = AVAudioSession.sharedInstance()
 
// Get available inputs
guard let inputs = session.availableInputs else { return }
 
// Find built-in mic
guard let builtInMic = inputs.first(where: {
    $0.portType == AVAudioSessionPortBuiltInMic
}) else { return }
 
// Find the data source at the specified orientation
guard let dataSource = builtInMic.dataSources?.first (where: {
    $0.orientation == preferredMicOrientation
}) else { return }
 
// Set data source's polar pattern
do {
    try dataSource.setPreferredPolarPattern(preferredPolarPattern)
} catch let error as NSError {
    print("Unable to preferred polar pattern: \(error.localizedDescription)")
}
 
// Set the data source as the input's preferred data source
do {
    try builtInMic.setPreferredDataSource(dataSource)
} catch let error as NSError {
    print("Unable to preferred dataSource: \(error.localizedDescription)")
}
 
// Set the built-in mic as the preferred input
// This call will be a no-op if already selected
do {
    try session.setPreferredInput(builtInMic)
} catch let error as NSError {
    print("Unable to preferred input: \(error.localizedDescription)")
}
 
// Print Active Configuration
session.currentRoute.inputs.forEach { portDesc in
    print("Port: \(portDesc.portType)")
    if let ds = portDesc.selectedDataSource {
        print("Name: \(ds.dataSourceName)")
        print("Polar Pattern: \(ds.selectedPolarPattern ?? "[none]")")
    }
}
```

## 权限隐私保护
- 请求和配置权限
  ```Objective-C
  AVAudioSession.sharedInstance().requestRecordPermission { granted in
    if granted {
        // User granted access. Present recording interface.
    } else {
        // Present message to user indicating that recording
        // can't be performed until they change their preference
        // under Settings -> Privacy -> Microphone
    }
}
  ```
  ![](media/16053829119165/16053888781471.jpg)

## 按应用类型划分的音频指南(重要)
- **大多数游戏需要用户交互才能在游戏中发生任何事情**。在设计游戏时使用AVAudioSessionCategoryAmbient或AVAudioSessionCategorySoloAmbient类别。当用户打开另一个应用程序或锁定屏幕时,他们不希望该应用程序继续播放。**通常希望其他应用程序的音频在游戏应用程序播放时继续播放。**
- 以下是一些建议指南:
    - 在应用程序代理的`applicationDidBecomeActive:`:方法中激活音频会话。
    - 播放应用程序音效,同时允许播放其他应用程序的音频。
    - 在其他音频未播放时播放应用程序音轨音频,否则允许播放以前的音频.
    - 在结束中断事件后,始终尝试重新激活和恢复音效播放。
    - 查询音频会话的**secondaryAudioShouldBeSilencedHint**属性,以确定是否应继续播放游戏的音轨。
    - 忽略所有路由更改,除非应用程序特别需要注意它们。
    - 在应用程序启动时显示视频启动前设置音频类别。

- 用户控制播放和录制应用程序的音频指南:
    - 录音应用和播放应用程序也有类似的指导原则。这些类型的应用程序使用**AVAudioSessionCategoryRecord**、**AVAudioSessionCategoryPlayAndRecord**或**AVAudioSessionCategoryPlayback**类别,**通常在激活它们的音频会话时中断其他系统音频**。用户界面将包括播放/暂停按钮或录制/暂停按钮。
    - 以下是一些建议指南: 
    - 当其他系统的音频会话被激活时,中断其他系统音频。用户界面将包括播放/暂停按钮或录制/暂停按钮。  
    
建议指南:
- 当应用程序进入前台时,等待用户按下播放或录制按钮,然后激活音频会话。
- 当应用程序处于前台时,请保持音频会话处于活动状态,除非它被中断。
- **如果应用程序在转换到后台时没有在活动地播放或录制音频,请停用其音频会话**。这可以**防止它的音频会话被另一个不可混合的应用程序或系统在应用程序被挂起时中断。**
- 更新UI以指示播放或录制在中断时已暂停。不要停用音频会话。
- 观察**AVAudioSessionInterruptionNotification**类型的通知,以通知音频会话中断。**当中断结束时,不要再次开始播放或录制音频,除非应用程序在中断之前已经开始播放或录制音频。**
- 如果**路由更改是由拔出事件引起的,请暂停播放或录制,但保持音频会话处于活动状态。**
- 假设应用程序的音频会话在从挂起状态过渡到前台状态时处于非活动状态。当用户按下播放或录制按钮时重新激活音频会话。
- **确保设置了audio UIBackgroundModes标志**。
- 注册远程控制事件(请参阅**MPRemoteCommandCenter**)并为您的媒体提供适当的正在播放的信息(请参阅**MPNowPlayingInfoCenter**)。锁频播放界面提示
- 使用MPVolumeView对象显示系统卷滑块和路由选择器。
- **使用后台任务而不是流式静默来防止应用程序被挂起。**
- 使用**requestRecordPermission**:方法向用户请求记录输入的权限。不要依赖操作系统来提示用户。
- 对于录制应用程序,请使用**AVAudioSessionCategoryRecord**类别,而不是**AVAudioSessionCategoryRecord**类别。“仅录制”类别实际上会使所有系统输出静音,并且对大多数应用程序来说限制太大。

更多涉及到其它场景的音视频会话配置指南请参照[Audio Guidelines](https://developer.apple.com/library/archive/documentation/Audio/Conceptual/AudioSessionProgrammingGuide/AudioGuidelinesByAppType/AudioGuidelinesByAppType.html#//apple_ref/doc/uid/TP40007875-CH11-SW1)
posted @ 2020-11-15 14:37  阿甘左  阅读(1028)  评论(0编辑  收藏  举报