AudioQueue回调和inUserData指针生存期

时间:2017-12-25 22:15:40

标签: objective-c callback core-audio

我一直致力于使用AudioQueueNewOutput的Objective-C中的应用程序。我有其他声音库的经验,所以回调机制很熟悉。但是,我遇到的一个问题是inUserData指针。当您调用AudioQueueStop时,即使立即设置为true,回调也可以再次运行。这使得在调用AudioQueueStop的同时解除分配用户指针中的任何内容是不合适的。

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

如果这不是正确的机制,那么我很难想到会发生什么。回调可能会尝试同步它在调用AudioQueueStop后认为剩余的缓冲区数,但这似乎很脆弱。我想避免在这么多秒之后解除分配或者泄漏记忆之类的黑客攻击。

2 个答案:

答案 0 :(得分:2)

根据Apple的说法,任何类型的内存管理都不应该在Audio上下文回调中完成。在启动音频单元或队列之前,应该在回调之外预先分配或保留回调所需的所有内存。因此,在任何音频回调中,保留状态应该没什么意义。

为了最大限度地谨慎,我不会释放音频缓冲区,直到app终止(如果有人调用)。与应用程序的总内存占用量相比,音频缓冲区通常非常小。我只是将它们留在池中,直到再次需要(如果有的话)。而不是泄漏。

如果您真的想要解除分配,因为您知道采样率和缓冲区的大小,您可以估计所有实时缓冲区清空所需的时间。四倍(考虑到潜在的OS双缓冲)并且估计应该是相当安全的。

答案 1 :(得分:0)

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

举个例子,

@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,则不会再次调用回调,您可以安全地取消分配。