- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我一直在我的项目中使用 MTAudioProcessingTapRef,以便在播放流式音频时实时分析缓冲区数据。问题是当我需要它时,我无法让 tap 处理器正确解除分配。
我有一个 AudioViewController swift 类,它引用了我的 AudioTapProcessor objective-C 类,swift 类负责告诉处理器开始和停止对 AVPlayerItem 的处理。处理器还有一个委托(delegate)(在本例中为 View Controller )来通知处理时缓冲区的变化。
我的问题是,如果我将处理器委托(delegate)声明为弱(应该如此),处理器将随机崩溃以尝试通知已解除分配的委托(delegate),因为 tap 处理器的处理方法在停止处理后执行了几次称呼。我发现解决此问题的唯一方法是将 tap 处理器委托(delegate)声明为强属性,这显然会导致保留周期,并且我的 AudioViewControllers 将永远不会被释放。
下面的一些代码可以帮助您了解相关情况:
AudioTapProcessor.h
@interface AudioTapProcessor : NSObject
@property (nonatomic, strong) AVPlayerItem *item;
@property (nonatomic, strong) id<AudioProcessorDelegate> delegate;
- (instancetype)initWithDelegate:(id<AudioProcessorDelegate>)delegate
item:(AVPlayerItem *)item;
- (void)startProcessing;
- (void)stopProcessing;
@end
AudioTapProcessor.m
void init(MTAudioProcessingTapRef tap, void *clientInfo, void
**tapStorageOut) {
*tapStorageOut = clientInfo;
}
void finalize(MTAudioProcessingTapRef tap) {}
void prepare(
MTAudioProcessingTapRef tap,
CMItemCount maxFrames,
const AudioStreamBasicDescription *processingFormat
) {}
void unprepare(MTAudioProcessingTapRef tap) {}
void process(
MTAudioProcessingTapRef tap,
CMItemCount numberFrames,
MTAudioProcessingTapFlags flags,
AudioBufferList *bufferListInOut,
CMItemCount *numberFramesOut,
MTAudioProcessingTapFlags *flagsOut
) {
//Random crashes here if I declare the delegate weak
//Something like AUDeferredRenderer-0x7ff8f448ef (364): EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
AudioTapProcessor *processor = (__bridge AudioTapProcessor *)MTAudioProcessingTapGetStorage(tap);
OSStatus err = MTAudioProcessingTapGetSourceAudio(tap, numberFrames, bufferListInOut, flagsOut, NULL, numberFramesOut);
AudioBuffer *pBuffer = &bufferListInOut->mBuffers[0];
UInt32 frameLength = pBuffer->mDataByteSize / sizeof(float);
float *pData = (float *)pBuffer->mData;
if (err == noErr && processor) {
if ([processor.delegate
respondsToSelector:@selector(updateWith:withSize:)]) {
[processor.delegate updateWith:pData withSize:frameLength];
}
}
}
- (void)stopProcessing
{
[self.item removeObserver:self forKeyPath:@"status"];
AVMutableAudioMixInputParameters *params =
(AVMutableAudioMixInputParameters *) _item.audioMix.inputParameters[0];
MTAudioProcessingTapRef tap = params.audioTapProcessor;
self.item.audioMix = nil;
CFRelease(tap);
//By doing this the tap processor does call its unprepare and finalize methods, so it is being deallocated fine.
}
然后在我的 AudioViewController.swift 中我有:
var processor: AudioTapProcessor!
override func prepareForPlayback() {
super.prepareForPlayback()
if processor == nil {
processor = AudioTapProcessor(delegate: self, item: item)
processor.startProcessing()
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
player.pause()
}
deinit {
//I tried to do this early in the lifecycle(viewWillDissapear) and it is the same thing.
processor.stopProcessing()
}
任何提示将不胜感激,我对此感到疯狂。谢谢
最佳答案
适用于所有 iOS 版本
⇨ 了解根本原因
1.AudioTapProcessor.m初始化
callbacks.clientInfo 持有指向 self 的指针。这不是弱引用或强引用,只是一个 C 指针。所以如果 self 被释放,我们 context->self 指向一个错误的内存地址
- (AVAudioMix *)audioMix {
if (!_audioMix) {
AVMutableAudioMix *audioMix = [AVMutableAudioMix audioMix];
if (audioMix) {
AVMutableAudioMixInputParameters *audioMixInputParameters = [AVMutableAudioMixInputParameters audioMixInputParametersWithTrack:self.audioAssetTrack];
if (audioMixInputParameters) {
MTAudioProcessingTapCallbacks callbacks;
...
callbacks.clientInfo = (__bridge void *)self;
...
}
}
}
}
2.AudioTapProcessor.m processCallback
每次调用 processCallback 时都会进行安全检查以查看 self 是否正在被释放,但请记住在步骤 1 中。上面即使 self 被释放 context->self 也不是 nil 而是指向一个错误的内存地址导致EXC_BAD_ACCESS。
static void tap_ProcessCallback(MTAudioProcessingTapRef tap, CMItemCount numberFrames, MTAudioProcessingTapFlags flags, AudioBufferList *bufferListInOut, CMItemCount *numberFramesOut, MTAudioProcessingTapFlags *flagsOut) {
...
MYAudioTapProcessor *self = ((__bridge MYAudioTapProcessor *)context->self);
if (!self) {
NSLog(@"AudioTapProcessor - processCallback CANCELLED (self is nil)");
return;
}
NSLog(@"AudioTapProcessor - processCallback PROCESSING");
}
⇨ 现在,如何解决这个问题?
1.ViewController.swift 或 audioTapProcessor 的拥有者
deinit {
print("ViewController - Dealloc")
audioTapProcessor.stopProcessing()
}
2.AudioTapProcessor.m
我们需要一种方法来告诉我们的 audioTapProcessor 停止 processCallback。最简单自然的方法是使用上面 processCallback 中已有的检查 if (!self) return;
所以停止 audioTapProcessor 只是将 context->self 正确设置为 NULL。
- (void)stopProcessing {
NSLog(@"AudioTapProcessor - stopProcessing");
AVMutableAudioMixInputParameters *params = (AVMutableAudioMixInputParameters *)_audioMix.inputParameters[0];
MTAudioProcessingTapRef audioProcessingTap = params.audioTapProcessor;
AVAudioTapProcessorContext *context = (AVAudioTapProcessorContext *)MTAudioProcessingTapGetStorage(audioProcessingTap);
// nils out the pointer so that we know in tapProcessorCallbacks that self will be dealloc'ed
context->self = NULL;
}
⇨ 因此生命周期得到纠正
代替这个
我们明白了
关于objective-c - 在 swift3.2/4 中正确解除分配 MTAudioProcessingTapRef,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46890403/
我需要将文本放在 中在一个 Div 中,在另一个 Div 中,在另一个 Div 中。所以这是它的样子: #document Change PIN
奇怪的事情发生了。 我有一个基本的 html 代码。 html,头部, body 。(因为我收到了一些反对票,这里是完整的代码) 这是我的CSS: html { backgroun
我正在尝试将 Assets 中的一组图像加载到 UICollectionview 中存在的 ImageView 中,但每当我运行应用程序时它都会显示错误。而且也没有显示图像。 我在ViewDidLoa
我需要根据带参数的 perl 脚本的输出更改一些环境变量。在 tcsh 中,我可以使用别名命令来评估 perl 脚本的输出。 tcsh: alias setsdk 'eval `/localhome/
我使用 Windows 身份验证创建了一个新的 Blazor(服务器端)应用程序,并使用 IIS Express 运行它。它将显示一条消息“Hello Domain\User!”来自右上方的以下 Ra
这是我的方法 void login(Event event);我想知道 Kotlin 中应该如何 最佳答案 在 Kotlin 中通配符运算符是 * 。它指示编译器它是未知的,但一旦知道,就不会有其他类
看下面的代码 for story in book if story.title.length < 140 - var story
我正在尝试用 C 语言学习字符串处理。我写了一个程序,它存储了一些音乐轨道,并帮助用户检查他/她想到的歌曲是否存在于存储的轨道中。这是通过要求用户输入一串字符来完成的。然后程序使用 strstr()
我正在学习 sscanf 并遇到如下格式字符串: sscanf("%[^:]:%[^*=]%*[*=]%n",a,b,&c); 我理解 %[^:] 部分意味着扫描直到遇到 ':' 并将其分配给 a。:
def char_check(x,y): if (str(x) in y or x.find(y) > -1) or (str(y) in x or y.find(x) > -1):
我有一种情况,我想将文本文件中的现有行包含到一个新 block 中。 line 1 line 2 line in block line 3 line 4 应该变成 line 1 line 2 line
我有一个新项目,我正在尝试设置 Django 调试工具栏。首先,我尝试了快速设置,它只涉及将 'debug_toolbar' 添加到我的已安装应用程序列表中。有了这个,当我转到我的根 URL 时,调试
在 Matlab 中,如果我有一个函数 f,例如签名是 f(a,b,c),我可以创建一个只有一个变量 b 的函数,它将使用固定的 a=a1 和 c=c1 调用 f: g = @(b) f(a1, b,
我不明白为什么 ForEach 中的元素之间有多余的垂直间距在 VStack 里面在 ScrollView 里面使用 GeometryReader 时渲染自定义水平分隔线。 Scrol
我想知道,是否有关于何时使用 session 和 cookie 的指南或最佳实践? 什么应该和什么不应该存储在其中?谢谢! 最佳答案 这些文档很好地了解了 session cookie 的安全问题以及
我在 scipy/numpy 中有一个 Nx3 矩阵,我想用它制作一个 3 维条形图,其中 X 轴和 Y 轴由矩阵的第一列和第二列的值、高度确定每个条形的 是矩阵中的第三列,条形的数量由 N 确定。
假设我用两种不同的方式初始化信号量 sem_init(&randomsem,0,1) sem_init(&randomsem,0,0) 现在, sem_wait(&randomsem) 在这两种情况下
我怀疑该值如何存储在“WORD”中,因为 PStr 包含实际输出。? 既然Pstr中存储的是小写到大写的字母,那么在printf中如何将其给出为“WORD”。有人可以吗?解释一下? #include
我有一个 3x3 数组: var my_array = [[0,1,2], [3,4,5], [6,7,8]]; 并想获得它的第一个 2
我意识到您可以使用如下方式轻松检查焦点: var hasFocus = true; $(window).blur(function(){ hasFocus = false; }); $(win
我是一名优秀的程序员,十分优秀!