bcl*_*mer 5 core-audio ios avcapturesession avaudiosession avaudioengine
TL;DR -AVAudioSession将AVAudioSessionMediaServicesWereLostNotification在指定蓝牙端口时触发,AVAudioSession.setPreferredInput并且该设备在使用AVCaptureSession或主动读取输入时断开连接AVAudioEngine。示例项目在这里。
https://openradar.appspot.com/FB8921592
通过我认为的“快乐路径”,或者至少应该得到 Apple 支持的路径,我可以始终如一AVAudioSession地触发它AVAudioSessionMediaServicesWereLostNotification和AVAudioSessionMediaServicesWereResetNotification通知。
在这两个通知之间,您的应用无法执行任何音频或视频 I/O 或处理(编码或解码)。这是一个总的媒体服务关闭 1 到 2 秒。
这仅在使用时发生AVAudioSession.setPreferredInput,其中您设置的端口是蓝牙设备。从该端口主动录制时,您关闭蓝牙设备。
发生这种情况时,在服务丢失之前不会触发来自AVAudioSession、AVAudioEngine或 的其他通知AVCaptureSession,因此无法抢先处理这种情况。用户可以随时关闭耳机,导致服务全面失败。
首先我设置了音频会话
try! AVAudioSession.sharedInstance().setCategory(.record, mode: .videoRecording, options: .allowBluetooth)
try! AVAudioSession.sharedInstance().setActive(true)
Run Code Online (Sandbox Code Playgroud)
然后指定正确的端口
let bluetoothPort = AVAudioSession.sharedInstance().availableInputs?
.first(where: { $0.portType == .bluetoothHFP })
guard let validPort = newPort else {
print("Couldn't find a valid bluetooth port")
return
}
print("Swapping \(AVAudioSession.sharedInstance().currentRoute.inputs.first!.portName) for \(validPort.portName)")
try! AVAudioSession.sharedInstance().setPreferredInput(newPort)
Run Code Online (Sandbox Code Playgroud)
最后设置 AVCaptureSession
let cap = AVCaptureSession()
cap.automaticallyConfiguresApplicationAudioSession = false
let device = AVCaptureDevice.default(for: .audio)!
let input = try! AVCaptureDeviceInput(device: device)
let output = AVCaptureAudioDataOutput()
output.setSampleBufferDelegate(self, queue: DispatchQueue(label: "test-queue"))
cap.beginConfiguration()
cap.addInput(input)
cap.addOutput(output)
cap.commitConfiguration()
cap.startRunning()
Run Code Online (Sandbox Code Playgroud)
或者 AVAudioEngine
let engine = AVAudioEngine()
let inputNode = engine.inputNode
let bus = 0
inputNode.installTap(onBus: bus, bufferSize: 1024, format: inputNode.inputFormat(forBus: 0)) { (buffer, time) in
// anything really
}
engine.prepare()
try! engine.start()
Run Code Online (Sandbox Code Playgroud)
我确实有一个存储库,可以使用AVAudioEngine或来演示问题AVCaptureSession,您可以在此处找到它 - https://github.com/bclymer/ios-preferredinput-crash。README 中有更明确的重现步骤。
我的以下设备受到影响(全部都是)
?????????????????????????????
? Device Name ? iOS Version ?
?????????????????????????????
? iPhone 7 ? iOS 14.2 ?
? iPhone Xr ? iOS 14.0.1 ?
? iPad Air 2 ? iOS 13.7 ?
?????????????????????????????
Run Code Online (Sandbox Code Playgroud)
有没有办法在从突然断开连接的外部设备读取 I/O 时不重置服务?
我知道但不可接受的一个解决方案是依赖 Apple 的“最后在”音频路由方法。连接蓝牙设备时,如果 ,它会自动成为默认路由AVAudioSession.preferredInput == nil。但是,我需要能够在任意数量的外部设备之间进行明确选择。使用隐式路由对我不起作用。
| 归档时间: |
|
| 查看次数: |
400 次 |
| 最近记录: |