如何在 iOS 11 中正确停止和删除音频处理器

2024-01-12

我正在使用类似于的audioTapProcessor苹果的 audioTap 示例 https://developer.apple.com/library/content/samplecode/AudioTapProcessor/Introduction/Intro.html.

基本上,audioTapProcessor 被创建并添加到 audioMix 中:

MTAudioProcessingTapRef audioProcessingTap;
if (noErr == MTAudioProcessingTapCreate(kCFAllocatorDefault, &callbacks,     kMTAudioProcessingTapCreationFlag_PreEffects, &audioProcessingTap))
{
    audioMixInputParameters.audioTapProcessor = audioProcessingTap;

    CFRelease(audioProcessingTap);

    audioMix.inputParameters = @[audioMixInputParameters];

    _audioMix = audioMix;
}

当创建audioMix时,它被添加到avPlayer的currentItem中:

self.avPlayer.currentItem.audioMix = audioMix;

当我完成audioTapProcessor 后,我清除了对audioTapProcessor 和audioMix 的引用:

if (self.avPlayer.currentItem.audioMix){

    for (AVMutableAudioMixInputParameters *inputParameter in player.currentItem.audioMix.inputParameters) {
        inputParameter.audioTapProcessor = nil;

    }

    player.currentItem.audioMix = nil;
}

这会触发tap_UnprepareCallbacktap_FinalizeCallback函数,并且 audioTapProcessor 对象被释放。

在 iOS11 几天前发布之前,这一切都没有任何问题。

在 iOS11 设备上,我有时会在 ClientProcessingTapManager 线程上收到 EXC_BAD_ACCESS 错误。错误发生在AVFoundation的其中一个类中,所以我无法调试。该错误发生在 ClientProcessingTap::PerformTap 中的某个位置。

我已将日志记录添加到audioTap 回调中,看起来只有tap_ProcessCallBack 在ClientProcessingTapManager 线程上执行。

我认为有时audioTapProcessor 的tap_ProcessCallback 方法会在此线程上触发,而实际的audioTapProcessor 已在另一个线程上释放。

我的问题是:如何正确停止 audioTapProcessor 并将其从内存中删除?


这是一些输出日志记录示例:

2017-09-22 12:49:26:171 xx[1261:780894] cleaning up audioMix of AvPlayer
2017-09-22 12:49:26:213 xx[1261:781173] into tap_ProcessCallback. thread: ClientProcessingTapManager
2017-09-22 12:49:26:213 xx[1261:781173] end of tap_ProcessCallback
2017-09-22 12:49:26:217 xx[1261:781127] into tap_UnprepareCallback. 
2017-09-22 12:49:26:218 xx[1261:781127] end of tap_UnprepareCallback
2017-09-22 12:49:26:218 xx[1261:781127] into tap_FinalizeCallback. 
2017-09-22 12:49:26:218 Tunify[1261:781127] end of tap_FinalizeCallback
2017-09-22 12:49:26:218 Tunify[1261:781127] into MYAudioTapProcessor dealloc.
(lldb) 

很高兴知道:

我正在使用 avPlayers 池,因此我正在重用这些对象。当我不清除 avPlayers 的 audioMix 时,我不会遇到此错误。如果不清理audioMix对象,只有当我重用avPlayer并将新的audioMix分配给avPlayer时,audioTapProcessors才会被释放。


我找到了一个相关问题 https://stackoverflow.com/questions/19202306/how-do-you-release-an-mtaudioprocessingtap,但我已经触发了清理功能。那里的解决方案在 iOS11 设备上给出了相同的错误


这是iOS 11下AVFoundation的一个bug。在iOS 12中已修复。 针对该问题的雷达雷达://34977000 http://rdar://34977000

一个可能的解决方法是在释放 AVPlayer / AVPlayerItem 之前调用prepareReleaseAudioMix:

+ (void)prepareReleaseAudioMix:(AVAudioMix*)audioMix {
    if ( @available(iOS 11.0, *) ) {
        // Starting with iOS 11, it is not required to manually nil audioTapProcessor,
        // but we need to retain the audioMix for a bit to make sure the processing callback
        // will not be called after we release (this is due to a bug in iOS 11 which calls the release
        // callback but still calls the processing callback afterwards - it also releases internal data
        // on release, so simply checking for release in the processing block is not enough)
        // rdar://34977000
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [self _prepareReleaseAudioMixNow:audioMix];
        });
    } else {
        // Prior to iOS 11 we need to manually nil the audioTapProcessor
        [self _prepareReleaseAudioMixNow:audioMix];
    }
}

+ (void)_prepareReleaseAudioMixNow:(AVAudioMix*)audioMix {
    for ( AVMutableAudioMixInputParameters *parameters in audioMix.inputParameters ) {
        if ( ![parameters isKindOfClass:[AVMutableAudioMixInputParameters class]] )
            continue;
        parameters.audioTapProcessor = nil;
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 iOS 11 中正确停止和删除音频处理器 的相关文章

随机推荐

  • 如何在 Symfony 中从编译器传递注入共享服务

    我正在尝试通过旨在替换 FOSRestBundle 中的服务之一的编译器通道注入令牌存储服务
  • R Shiny:如何在执行反应语句之前更新输入对象

    我正在基于很棒的 R Shiny 包构建一个探索性视觉应用程序 该应用程序要做的一件事是读取实值 测量 列并显示这些测量值的箱线图 此外 还有一个可选的selectInput小部件 允许用户选择group要深入研究的变量 这group变量基
  • 如何在 springboot 应用程序中启用 Cassandra CqlSession Metrics

    我想启用 cassandra cqlsession 指标 当尝试注册 cqlsession 指标时 它在 springboot 应用程序中提供了 optional empty 这里使用 cassandra datastax java 驱动程
  • 在 std::function 上递归应用 std::bind 的问题

    给定一个函数f x y z 我们可以绑定x到 0 得到一个函数g y z f 0 y z 我们可以继续这样做并得到h f 0 1 2 在 C 语法中 这将是 include
  • ScheduledThreadPoolExecutor 和 corePoolSize 0?

    我想要一个ScheduledThreadPoolExecutor如果没有工作要做 它还会停止最后一个线程 如果有新任务 它还会创建线程 并使线程保持活动状态一段时间 但是一旦没有更多的工作要做 它应该再次丢弃所有线程 我天真地将其创建为ne
  • 如何使用双浮点?

    我正在努力弄清楚如何告诉 Lisp 我想使用双浮点值 假设我有 let x 1 format t A x 3 0 这使 0 33333334 如果我想使用双浮点数 我尝试了以下方法 let x 1 declare type double f
  • 无法将 Google 帐户添加到 Android 模拟器

    我有一个将我的 Android 模拟器连接到 Gmail 时出现问题 即使我可以浏览网页 我也无法添加我的 Gmail 帐户 我去Accounts and Sync add account google sign in 然后输入我的gmai
  • Service Worker 和透明缓存更新

    我正在尝试为一个简单但旧的 Django Web 应用程序安装 ServiceWorker 我开始使用这个例子Chrome 团队的通读缓存示例 https googlechrome github io samples service wor
  • 如何从 Python 控制 Windows 应用程序

    我在 Windows PC 上安装了该应用程序 我想使用 python 启动该应用程序并选择下拉选项并在该应用程序中执行一些其他活动 我能够使用以下命令启动该应用程序os system命令 但我无法继续进行 我希望我的程序能够执行以下操作
  • WCF、ASMX 基本 HTTP 绑定和 IIS

    我一直在使用 WCF 自 托管应用程序进行大量工作 最近 我被要求编写一个 Web 服务 其中调用客户端是一个名为 WGET 的基于 Linux 的程序 我想使用 WCF 而不是传统的 ASMX Web 服务 Web 服务正在返回标准 XM
  • 将大型 Pandas 数据帧分块写入 CSV 文件

    如何将大数据文件分块写入 CSV 文件 我有一组大型数据文件 1M 行 x 20 列 然而 我只对数据文件中大约 5 列感兴趣 我想通过仅使用感兴趣的列来制作这些文件的副本 从而使事情变得更容易 这样我就可以使用较小的文件进行后期处理 所以
  • 错误:(3, 0) 原因:org/apache/commons/lang3/StringUtils

    我收到以下错误 错误 3 0 原因 org apache commons lang3 StringUtils 当我尝试在我的 Android 项目中添加数据绑定时 我的依赖项包括 Top level build file where you
  • 为什么删除 @font-face 中的 woff2 可以解决 IE11 问题

    这些天我在 font face 上遇到了麻烦 我的字体未在 IE11 中显示 但在所有其他版本中显示 事实证明 删除 woff2 字体解决了我的问题 字体显示正常 我现在的问题是 为什么这可以成为解决方案 IE11 的想法是什么 删除一个简
  • 通过brew和dmg安装cuda

    尝试按照以下指南在 MAC 上安装 nvidia 工具包后 http docs nvidia com cuda cuda installation guide mac os x index html axzz4FPTBCf7X http d
  • C++ 装饰 basic_iostream 类

    我想做一些像下面的代码所示的事情 class foo private std fstream m stream public foo std fstream stream m stream stream foo write char con
  • 可见性:隐藏在 Angular 2 中

    在角度 2 中实现元素不可见的建议方法是什么 visibility hidden不显示元素但保持其空间占用 它有一个 hide 指令 但它似乎类似于display none 您可以设置visibility样式属性与样式绑定 https v2
  • 2s补码是一种存储负数的方法吗?

    我读过很多文章和答案来理解2s complement 他们给了我很多帮助 然而 我心中却没有多少疑问2s complement 1 Is 2s complement一种存储负数以便于操作的方法或者还有其他一些应用程序 2 2s comple
  • 如何缩小文本块中的字体大小以适应内容的宽度并保持字体纵横比

    事情是这样的 我有这行 XAML
  • Python 中相当基本的字符串扩展?

    例如 我正在尝试创建一个将采用 压缩 字符串的函数 a12b3c 并返回其 扩展 形式 在本例中为 aaaaaaaaaaaabbbc 每个字符应该重复与后面的数字一样多的次数 或者如果该字符后面没有数字则只重复一次 我已经能够创建一个函数
  • 如何在 iOS 11 中正确停止和删除音频处理器

    我正在使用类似于的audioTapProcessor苹果的 audioTap 示例 https developer apple com library content samplecode AudioTapProcessor Introdu