AVAudioEngine.connect 时出现 CoreAudio 错误和崩溃
CoreAudio error and crash on AVAudioEngine.connect
我正在尝试将 AVAudioUnitEffect
连接到 AVAudioEngine
的实例,如下所示:
required init(inputFormat: AVAudioFormat, outputFormat: AVAudioFormat, andAVAudioEngine avAudioEngine:AVAudioEngine) {
self.inputFormat = inputFormat
self.outputFormat = outputFormat
self.avAudioEngine = avAudioEngine
self.myAudioUnit = MyAVAudioUnit()
super.init()
avAudioEngine.attach(myAudioUnit)
avAudioEngine.connect(myAudioUnit, to: avAudioEngine.outputNode, format: self.inputFormat)
}
总体 class 只是 NSObject
的子class,MyAudioUnit
是 AVAudioUnitEffect
的子class。
在看似随机的时间,此初始化程序的最后一行(对 connect
的调用)将抛出 SIGABRT 并出现以下错误:com.apple.coreaudio.avfaudio: error -10875
等于kAudioUnitErr_FailedInitialization
。
任何人都可以阐明这个错误以及这里可能发生的事情吗?我认为 MyAVAudioUnit
的初始化程序可能失败了,但它的内部初始化程序 (init(audioComponentDescription: AudioComponentDescription)
) 不会抛出任何错误并且具有非可选的 return 类型。有没有其他人遇到过这个特定错误?
更新
下面是inputFormat
的初始化:
guard let stereoFormat = AVAudioFormat(commonFormat: .pcmFormatFloat32,
sampleRate: 44100,
channels: 2,
interleaved: false) else {
return
}
let numChannels = UInt32(10)
guard let multiChannelLayout = AVAudioChannelLayout(layoutTag: kAudioChannelLayoutTag_Unknown | numChannels) else {
return
}
inputFormat = AVAudioFormat(commonFormat: stereoFormat.commonFormat,
sampleRate: stereoFormat.sampleRate,
interleaved: stereoFormat.isInterleaved,
channelLayout: multiChannelLayout)
MyAVAudioUnit
包含一个额外的自定义参数 (volumeParameter
) 并初始化为:
required override init() {
var componentDescription = AudioComponentDescription()
componentDescription.componentType = kAudioUnitType_Effect
componentDescription.componentSubType = xxxxx
componentDescription.componentManufacturer = xxxxx
componentDescription.componentFlags = 0
componentDescription.componentFlagsMask = 0
AUAudioUnit.registerSubclass(MyAVAudioUnit.self,
as: componentDescription,
name:"MyAVAudioUnit",
version: UInt32.max)
super.init(audioComponentDescription: componentDescription)
guard let paramTree = self.auAudioUnit.parameterTree else { return }
volumeParameter = paramTree.value(forKey: "volumeParameter") as? AUParameter
}
你说这发生在“随机时间”复数。这可能意味着您经常这样做,并且可能在发布或取消初始化单元后不久。请注意,音频单元子系统在不同的完全异步线程中运行,因此在您的应用停止并释放该单元后,该单元可能仍由 OS 使用(短时间)。如果您在任何 stop/release 调用和任何(重新)初始化之间放置足够长的延迟,比如一两秒,它可能会阻止此问题。
这是最终解决此问题的方法。我从崩溃日志中注意到,在尝试连接音频单元之前打印出的音频图显示如下:
“ ________ GraphDescription ________ AVAudioEngineGraph 0x101538ba0: initialized = 1, running = 0, number of nodes = 23 ”
有趣的是,虽然 running
是错误的,但 initialized
是 正确的 。关于这条 initialized
条信息的含义的文档并不多,但我发现它在 AVAudioEngine 之前已启动但 暂停 时显示为真。现在,我并没有从任何地方明确地调用 avAudioEngine.pause()
,但我认为系统可能会启动暂停作为 AVAudioSessionRouteChangeNotification
的一部分(这就是我在这整个系列事件中的响应) .
很多都是猜测,但很明显,在引擎的打印输出显示 initialized = 1
时调用 avAudioEngine.connect()
(或者根据推论,引擎已暂停)会导致此崩溃.
在尝试连接音频单元之前必须完全停止音频引擎。我的问题是我尝试调用 avAudioEngine.stop()
被包裹在 if
语句中,如下所示:
if avAudioEngine.isRunning {
avAudioEngine.stop()
}
当然,这个 if
语句被跳过了,因为音频引擎实际上不是 运行。所以 stop()
从未被调用过。删除 if
语句并调用 stop()
无疑会在引擎上设置 initialized = 0
并允许连接而不会出现此崩溃。
希望这对其他人有帮助。我花了很长时间才解开。
我正在尝试将 AVAudioUnitEffect
连接到 AVAudioEngine
的实例,如下所示:
required init(inputFormat: AVAudioFormat, outputFormat: AVAudioFormat, andAVAudioEngine avAudioEngine:AVAudioEngine) {
self.inputFormat = inputFormat
self.outputFormat = outputFormat
self.avAudioEngine = avAudioEngine
self.myAudioUnit = MyAVAudioUnit()
super.init()
avAudioEngine.attach(myAudioUnit)
avAudioEngine.connect(myAudioUnit, to: avAudioEngine.outputNode, format: self.inputFormat)
}
总体 class 只是 NSObject
的子class,MyAudioUnit
是 AVAudioUnitEffect
的子class。
在看似随机的时间,此初始化程序的最后一行(对 connect
的调用)将抛出 SIGABRT 并出现以下错误:com.apple.coreaudio.avfaudio: error -10875
等于kAudioUnitErr_FailedInitialization
。
任何人都可以阐明这个错误以及这里可能发生的事情吗?我认为 MyAVAudioUnit
的初始化程序可能失败了,但它的内部初始化程序 (init(audioComponentDescription: AudioComponentDescription)
) 不会抛出任何错误并且具有非可选的 return 类型。有没有其他人遇到过这个特定错误?
更新
下面是inputFormat
的初始化:
guard let stereoFormat = AVAudioFormat(commonFormat: .pcmFormatFloat32,
sampleRate: 44100,
channels: 2,
interleaved: false) else {
return
}
let numChannels = UInt32(10)
guard let multiChannelLayout = AVAudioChannelLayout(layoutTag: kAudioChannelLayoutTag_Unknown | numChannels) else {
return
}
inputFormat = AVAudioFormat(commonFormat: stereoFormat.commonFormat,
sampleRate: stereoFormat.sampleRate,
interleaved: stereoFormat.isInterleaved,
channelLayout: multiChannelLayout)
MyAVAudioUnit
包含一个额外的自定义参数 (volumeParameter
) 并初始化为:
required override init() {
var componentDescription = AudioComponentDescription()
componentDescription.componentType = kAudioUnitType_Effect
componentDescription.componentSubType = xxxxx
componentDescription.componentManufacturer = xxxxx
componentDescription.componentFlags = 0
componentDescription.componentFlagsMask = 0
AUAudioUnit.registerSubclass(MyAVAudioUnit.self,
as: componentDescription,
name:"MyAVAudioUnit",
version: UInt32.max)
super.init(audioComponentDescription: componentDescription)
guard let paramTree = self.auAudioUnit.parameterTree else { return }
volumeParameter = paramTree.value(forKey: "volumeParameter") as? AUParameter
}
你说这发生在“随机时间”复数。这可能意味着您经常这样做,并且可能在发布或取消初始化单元后不久。请注意,音频单元子系统在不同的完全异步线程中运行,因此在您的应用停止并释放该单元后,该单元可能仍由 OS 使用(短时间)。如果您在任何 stop/release 调用和任何(重新)初始化之间放置足够长的延迟,比如一两秒,它可能会阻止此问题。
这是最终解决此问题的方法。我从崩溃日志中注意到,在尝试连接音频单元之前打印出的音频图显示如下:
“ ________ GraphDescription ________ AVAudioEngineGraph 0x101538ba0: initialized = 1, running = 0, number of nodes = 23 ”
有趣的是,虽然 running
是错误的,但 initialized
是 正确的 。关于这条 initialized
条信息的含义的文档并不多,但我发现它在 AVAudioEngine 之前已启动但 暂停 时显示为真。现在,我并没有从任何地方明确地调用 avAudioEngine.pause()
,但我认为系统可能会启动暂停作为 AVAudioSessionRouteChangeNotification
的一部分(这就是我在这整个系列事件中的响应) .
很多都是猜测,但很明显,在引擎的打印输出显示 initialized = 1
时调用 avAudioEngine.connect()
(或者根据推论,引擎已暂停)会导致此崩溃.
在尝试连接音频单元之前必须完全停止音频引擎。我的问题是我尝试调用 avAudioEngine.stop()
被包裹在 if
语句中,如下所示:
if avAudioEngine.isRunning {
avAudioEngine.stop()
}
当然,这个 if
语句被跳过了,因为音频引擎实际上不是 运行。所以 stop()
从未被调用过。删除 if
语句并调用 stop()
无疑会在引擎上设置 initialized = 0
并允许连接而不会出现此崩溃。
希望这对其他人有帮助。我花了很长时间才解开。