首页 > 解决方案 > iOS 14.2 中引入 AudioToolback 崩溃

问题描述

我在 iOS 14.2 中引入的应用程序中遇到了非常一致的崩溃。我们正在使用 Crashlytics 跟踪崩溃,并且可以确认 100% 的这些新崩溃发生在 14.2 及更高版本上。我还能够在 14.2 和 14.3 的当前第二个 beta 版本上重新创建

我无法在 14.1 上重新创建它。此外,这些功能已经存在了很长一段时间,并且在最近的几个 iOS 主要/次要版本中没有对这些功能本身进行任何更改。

具体错误是:

error: memory read failed for 0x0:

com.apple.audio.toolbox.AUScheduledParameterRefresher (20): EXC_BAD_ACCESS (code=1, address=0x0)

崩溃的要点:

• 我在我们的应用程序中有一个回放/记录机制。这可以是播放单个音轨或一次播放多个音轨。

• 只有当我在轨道上启用了音频效果(即混响、压缩等)时,才会发生这种情况。我正在使用 AVAudioUnitEffect 库来实现正在播放的曲目上的音频效果。

• 当用户操作效果的设置(即音量或增益)然后尝试执行另一操作时,就会发生这种情况。

我找不到关于 AUScheduledParameterRefresher 的任何文档。我还扩展了我在 XCode 中的搜索范围,以包括整个 14.2 SDK,但其中也没有对它的引用。

基于 EXC_BAD_ACCESS 错误,我的猜测是进程的某些部分从内存中释放,并且当代码更改音频效果的设置时,它不再存在。我打开了 Zombies 以尝试在 Instruments 中捕获任何已释放的对象,但没有任何结果。

我还下载了 iOS 14.1 SDK 并对音频框架(AudioToolbox、AVFoundation 等)进行了比较,以查看是否有任何重大变化,但它并没有出现,因此它甚至可能比这些库低一点。


我们创建了一个最小的应用程序并将其发布到 GitHub 以显示问题: https ://github.com/audiobridge/iOSCrashDemo

这被简化为仅构建效果和参数,当您点击初始化它的按钮时应用程序崩溃。

使用该应用程序似乎可以推断出问题在于 AVAudioUnitEQ。如果您从链中删除它,则错误/崩溃就消失了。在函数已经破坏效果之后,似乎有些东西被安排在“未来”引用 AVAudioUnitEQ,因为它不再需要了。


我很难深入研究这个问题。任何帮助将不胜感激。谢谢!

作为参考,这里是 Crashlytics 在发生崩溃的线程上的堆栈跟踪:

Crashed: com.apple.audio.toolbox.AUScheduledParameterRefresher
EXC_BAD_ACCESS KERN_PROTECTION_FAILURE 0x00000001dd778040

0   ??? 0x1dd778040 (Missing)
1   AudioToolboxCore 0x196846638 AudioUnitGetParameter + 52
2   AudioToolboxCore 0x1967d8200 43-[AUAudioUnitV2Bridge _createParameterTree]_block_invoke.125 + 112
3   AudioToolboxCore 0x196788284 -[AUParameter _internalValue] + 252
4   AudioToolboxCore 0x19678ba28 20-[AUParameter value]_block_invoke + 32
5   libdispatch.dylib 0x186bce280 _dispatch_client_callout + 16
6   libdispatch.dylib 0x186bb10ec _dispatch_lane_barrier_sync_invoke_and_complete + 56
7   AudioToolboxCore 0x196788408 -[AUParameter value] + 244
8   AudioToolboxCore 0x1967daea0 parameterNodesEqual(AUParameterNode*, AUParameterNode*, std::1::vector<unsigned long long, std::1::allocator<unsigned long long> >&) + 1180
9   AudioToolboxCore 0x1967dac94 parameterNodesEqual(AUParameterNode*, AUParameterNode*, std::1::vector<unsigned long long, std::1::allocator<unsigned long long> >&) + 656
10 AudioToolboxCore 0x1967dac94 parameterNodesEqual(AUParameterNode*, AUParameterNode*, std::1::vector<unsigned long long, std::1::allocator<unsigned long long> >&) + 656
11 AudioToolboxCore 0x1967da9dc invocation function for block in void applesauce::dispatch::v1::sync_impl<-[AUAudioUnitV2Bridge _buildNewParameterTree]::$_0>(NSObject<OS_dispatch_queue>*, -[AUAudioUnitV2Bridge _buildNewParameterTree]::$_0&&, std::1::integral_constant<bool, true>) + 104
12 libdispatch.dylib 0x186bce280 _dispatch_client_callout + 16
13 libdispatch.dylib 0x186bb10ec _dispatch_lane_barrier_sync_invoke_and_complete + 56
14 AudioToolboxCore 0x1967d4034 -[AUAudioUnitV2Bridge _buildNewParameterTree] + 140
15 AudioToolboxCore 0x1967d4238 -[AUAudioUnitV2Bridge _invalidateParameterTree:] + 124
16 AudioToolboxCore 0x1967da820 caulk::concurrent::details::message_call<ParameterListPropertyListener(void*, OpaqueAudioComponentInstance*, unsigned int, unsigned int, unsigned int)::$_5>::perform() + 52
17 AudioToolboxCore 0x1967da7bc caulk::concurrent::details::rt_message_call<ParameterListPropertyListener(void*, OpaqueAudioComponentInstance*, unsigned int, unsigned int, unsigned int)::$_5>::perform() + 24
18 caulk 0x1c89c2280 caulk::concurrent::details::messenger_servicer::check_dequeue() + 104
19 caulk 0x1c89c1f34 caulk::concurrent::details::worker_thread::run() + 56
20 caulk 0x1c89c20bc void* caulk::thread_proxy<std::1::tuple<caulk::thread::attributes, void (caulk::concurrent::details::worker_thread::*)(), std::__1::tuple<caulk::concurrent::details::worker_thread*> > >(void*) + 56
21 libsystem_pthread.dylib 0x1cd5a0b3c _pthread_start + 288
22 libsystem_pthread.dylib 0x1cd5a5880 thread_start + 8

标签: iosswiftios14audiounitaudiotoolbox

解决方案


根据您的示例代码项目,可以通过将 eqEffect 的定义移动到类属性来防止崩溃……</p>

class ViewController: UIViewController {

    let eqEffect = AVAudioUnitEQ(numberOfBands: 3)

…并更新所有createEffects指向该点的引用。比如……</p>

let lowFilterParams = self.eqEffect.bands[0]

但是,虽然这将防止崩溃(这可能是由于 AVAudioUnitEQ 在配置它的方法完成时被释放),但我不确定这是否会导致您在实际应用程序中期望的行为,因为我不不知道 AVAudioUnitEQ 是否有可能在仍在使用时发布。(它作为示例代码中视图控制器的属性存在意味着它始终可用。)


推荐阅读