我正在尝试从AVAudioSession.sharedInstance().availableInputs
更改所有可用设备之间的音频输入(麦克风)。我使用AVAudioSession.routeChangeNotification
来获取自动路由更改时,设备连接/断开,并更改首选输入与setPreferredInput
,然后我重新启动我的audioEngine,它工作正常。
但当我尝试以编程方式更改首选输入时,它不会更改音频捕获inputNode。但保留最后连接的设备和捕获。
即使AVAudioSession.sharedInstance().currentRoute.inputs
发生了变化,但audioEngine?.inputNode
不会更改为setPreferredInput
调用。
WhatsApp似乎没有任何问题。
任何建议或线索都非常感谢。谢谢
这是一些相关的代码段。enableMic
编程是一个问题。
private var audioEngine: AVAudioEngine?
private var inputNode: AVAudioNode!
private func setupAudioSession() {
do {
let session = AVAudioSession.sharedInstance()
try session.setCategory(.playAndRecord, options: [.defaultToSpeaker, .allowBluetooth])
try session.setActive(true)
} catch {
print(error)
}
}
func setupAudioEngine() {
audioEngine?.stop()
audioEngine?.reset()
setupAudioSession()
audioEngine = AVAudioEngine()
inputNode = audioEngine?.inputNode
guard let hardwareSampleRate = audioEngine?.inputNode.inputFormat(forBus: 0).sampleRate else { return }
let format = AVAudioFormat(standardFormatWithSampleRate: hardwareSampleRate, channels: 1)
let requiredBufferSize: AVAudioFrameCount = 4800
inputNode.installTap(onBus: 0,
bufferSize: requiredBufferSize,
format: format
) { [self] (buffer: AVAudioPCMBuffer, _: AVAudioTime) in
// process the buffer
}
audioEngine?.prepare()
}
func startRecording() {
do {
try audioEngine?.start()
} catch {
print("Could not start audioEngine: \(error)")
}
}
private func observeRouteChanges() {
NotificationCenter.default.addObserver(self,
selector: #selector(handleRouteChange),
name: AVAudioSession.routeChangeNotification,
object: nil)
}
@objc func handleRouteChange(notification: Notification) {
guard let userInfo = notification.userInfo,
let reasonValue = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt,
let reason = AVAudioSession.RouteChangeReason(rawValue: reasonValue) else {
return
}
switch reason {
case .newDeviceAvailable, .oldDeviceUnavailable:
// enableMic with current route AVAudioSession.sharedInstance().currentRoute.inputs.first
default: ()
}
}
private func enableMic(mic: AVAudioSessionPortDescription?) {
let session = AVAudioSession.sharedInstance()
do {
try session.setPreferredInput(mic)
// re-setup the audio engine and start
} catch {
print(error)
}
}
1条答案
按热度按时间c3frrgcw1#
也是AVFoundation的新增功能。对于你的问题
以编程方式更改音频输入不会更改音频引擎输入AVFoundation?是的,即使您以编程方式更改输入设备,它也不会更改
inputNode
属性。请查看Apple关于此属性的文档:
inputNode不会改变。这是预期的。
AVAudioEngine
的inputNode
属性是一个计算属性,在第一次访问它时,它会被惰性地(按需)计算。首次访问inputNode属性时,AVAudioEngine将使用AVAudioEngine的默认AVAudioNode渲染格式创建AVAudioInputNode类的单例示例,以表示硬件的音频输入连接。此示例在音频引擎的处理图中处理音频输入,音频输入格式由音频硬件的属性自动确定。
一旦创建了节点,对输入节点的后续调用将返回相同的示例。
为了证明我写了一个演示应用程序,我想你已经尝试过了。看看这个方法,它是用来开始点击输入节点:
如果您尝试在
AVAudioEngineConfigurationChange
通知之后调用此方法,您会发现应用程序在audioEngine.inputNode.installTap(onBus:, bufferSize:,format:)
处崩溃,特别是当您在AirPods和内置麦克风之间切换时。这是因为inputNode
在输入设备发生物理变化时不会更新。就像文档中说的那样,“它是在第一次访问时按需创建的”。我希望这能澄清懒惰示例化如何为AVAudioEngine的inputNode属性工作。如果你还有什么问题就告诉我。
顺便说一句,这里是演示仓库link。该演示都有自动音频输入切换和手动音频输入切换。