ios - 用户切换耳机时如何更改 AVAudioPlayerNode 格式
问题描述
我需要播放基于输出设备的采样率生成的任意音调。用户需要连接有线或无线耳机才能收听音频。
由于现代耳机可以具有 44100 或 48000 的原生采样率,我需要以某种方式重新初始化我AVAudioPlayerNode
的不同AVAudioFormat
. 不做任何事情,音频开始听起来失真。但是,在尝试attach
、或. 有时它会在我第一次尝试切换耳机时锁定执行(我同时连接了 2 个耳机,一个 SR 为 44100 的通用耳机和 SR 为 48000 的 Airpods),并且很少会在第二个时冻结尝试。detach
connect
disconnectNodeOutput
这是我的代码:
private let engine = AVAudioEngine()
private let audioUnit = MyAudioUnit()
init() {
let audioSession = AVAudioSession.sharedInstance()
let sampleRate = audioSession.sampleRate
format = AVAudioFormat(
commonFormat: .pcmFormatFloat32,
sampleRate: sampleRate,
channels: AVAudioChannelCount(audioSession.outputNumberOfChannels),
interleaved: false
)!
engine.attach(audioUnit)
engine.connect(
audioUnit,
to: engine.mainMixerNode,
format: format
)
NotificationCenter.default.addObserver(
self,
selector: #selector(self.handleInterruption),
name: Notification.Name.AVAudioEngineConfigurationChange,
object: engine
)
}
@objc
private func handleInterruption(_ notification: Notification) {
DispatchQueue.main.async {
let audioSession = AVAudioSession.sharedInstance()
let sampleRate = audioSession.sampleRate
self.format = AVAudioFormat(
commonFormat: .pcmFormatFloat32,
sampleRate: sampleRate,
channels: AVAudioChannelCount(audioSession.outputNumberOfChannels),
interleaved: false
)!
self.engine.detach(self.audioUnit)
self.engine.attach(self.audioUnit)
self.engine.connect(
self.audioUnit,
to: self.engine.mainMixerNode,
format: self.format
)
}
}
// method called on main thread only
// BTW, using audioUnit.stop() instead of pause() would also introduce a deadlock
func setActive(_ active: Bool) {
...
if active {
try! engine.start()
audioUnit.play()
} else {
audioUnit.pause()
engine.stop()
engine.reset()
}
}
我已经尝试了许多“重新连接”的变体,AVAudioEngine
但它们都陷入了以下僵局:
我也试过把它放在后台线程上,但这没关系。一旦应用程序尝试AVAudioEngine
再次使用,一切都会卡住。
那么,是否有适当的方法重新连接AVAudioPlayerNode
以更新采样率?或者也许可以不依赖耳机的原生采样率,而让音频正常地以静态采样率发声?提前致谢!
解决方案
使用您当前的设置,当音频路由和采样率发生变化时,您不需要做任何事情。
您当前的设置如下:
+------+ +-----+ +------+
|player| -> |mixer| -> |output|
+------+ +-----+ +------+
在播放器和输出节点之间安装混音器的好处之一是混音器将为您进行采样率转换。因此,即使扬声器的采样率为 48000Hz,您的播放器也可以输出 44100Hz。
还有一点需要注意的是,在将播放器连接到混音器时,format
参数应该是播放器节点输出的格式。不过,这应该可以通过设置为 来推断format
,nil
如下所示:
engine.connect(player, to: engine.mainMixerNode, format: nil)
推荐阅读
- awk - 当其中一个是管道字符时使用多个分隔符
- node.js - NodeJS rest api在使用参数时发送状态404怎么办?
- tensorflow - 专用 GPU 内存无法清除
- php - 通过 PHP 的 sql 查询总是跳过第一行
- java - 如果没有附加自定义目标,Maven 验证阶段是否会作为生命周期的一部分执行?
- javascript - request.body 回来了 undefined
- python - 在这个 TensorFlow 模型中,哪些模型参数从一个时期到下一个时期发生了变化?
- java - Getter 和 Setter 仅适用于创建的最后一个对象
- java - 无法将 Java 项目与 MySQL Workbench 连接(TIMEZONE 错误)
- asp.net - 我如何使用 ASP linq gridview 从一个表中的两个外键读取不同的数据名称