Objective c AudioQueue回调和inUserData指针生存期

Objective c AudioQueue回调和inUserData指针生存期,objective-c,callback,core-audio,Objective C,Callback,Core Audio,我一直在用Objective-C开发一个应用程序,它使用AudioQueueNewOutput。我有其他声音库的经验,所以回调机制很熟悉。然而,我遇到的一个问题是inUserData指针。调用AudioQueueStop时,即使immediate设置为true,回调也可以再次运行。这使得在调用AudioQueueStop的同时取消分配用户指针中的内容是不合适的 这是运行kaudioqueproperty\u的目的吗?该侦听器的回调是否保证不会再次调用队列回调,并且可以安全地释放用户指针 如果这不

我一直在用Objective-C开发一个应用程序,它使用
AudioQueueNewOutput
。我有其他声音库的经验,所以回调机制很熟悉。然而,我遇到的一个问题是
inUserData
指针。调用
AudioQueueStop
时,即使immediate设置为true,回调也可以再次运行。这使得在调用
AudioQueueStop
的同时取消分配用户指针中的内容是不合适的

这是运行
kaudioqueproperty\u的目的吗?该侦听器的回调是否保证不会再次调用队列回调,并且可以安全地释放用户指针


如果这不是正确的机制,那么我很难想象会是什么。回调可以尝试同步调用
AudioQueueStop
后它认为剩下的缓冲区数量,但这似乎很脆弱。我希望避免像在这么多秒后释放或内存泄漏这样的黑客行为。

根据苹果公司的说法,任何类型的内存管理都不应该在音频上下文回调中进行。在启动音频单元或队列之前,应在回调外部预先分配或保留回调所需的所有内存。因此,在任何音频回调中,retain状态都应该是无关紧要的

为了最大限度地谨慎,我不会在应用程序终止之前释放音频缓冲区(如果有调用)。与应用程序的总内存占用相比,音频缓冲区通常非常小。我没有泄漏,而是把它们放在水池里,直到需要时再放(如果有的话)


如果您真的想取消分配,因为您知道采样率和缓冲区的大小,您可以估计所有活动缓冲区清空需要多长时间。四倍于此(考虑到潜在的操作系统双缓冲),估计应该是相当安全的。

事实证明,您可以使用属性侦听器安全地执行此操作。特别是,
kaudioqueproperty\u正在运行
。您的对象可以保留自身的引用,然后在队列停止运行时
nil
it

例如,

@interface Foo : NSObject
@end

@implementation Foo {
  AudioQueueRef queue;
  Foo *inUse;
}

static void listener_callback(void *user_data, AudioQueueRef queue,
                              AudioQueuePropertyID prop) {
  Foo *p = (__bridge id)user_data;
  UInt32 res;
  UInt32 resSize = sizeof(res);
  AudioQueueGetProperty(queue, kAudioQueueProperty_IsRunning, &res, &resSize);
  if (resSize == sizeof(UInt32) && res == 0) {
    p->inUse = nil;
  }
}

- (id)init {
  // ... set up self and audio queue
  // create some kind of playback callback
  inUse = self;
  AudioQueueAddPropertyListener(queue, kAudioQueueProperty_IsRunning,
                                listener_callback,
                                (__bridge void *_Nullable)self);
  AudioQueueStart(queue, NULL);
  return self;
}
@end

只有在队列启动和停止时才调用属性侦听器回调。如果
AudioQueueGetProperty
对此属性产生0,则不会再次调用回调,您可以安全地解除分配。

我就是这样做的。这似乎总是很老套,但这是解决问题的务实办法。只需从dealloc中释放dispatch_after块中的渲染内存。要清楚,我希望释放的不仅仅是缓冲区,尽管我也想释放缓冲区。在我的例子中,给回调的用户指针想要取消分配,但它不能,因为回调可能仍在使用它。因此,那里的内存使用量更大一些。