代码之家  ›  专栏  ›  技术社区  ›  Brian Armstrong

AudioQueue回调和inUserData指针生存期

  •  2
  • Brian Armstrong  · 技术社区  · 8 年前

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

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

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

    2 回复  |  直到 8 年前
        1
  •  2
  •   hotpaw2    8 年前

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

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

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

        2
  •  1
  •   Brian Armstrong    8 年前

    事实证明,您可以使用属性侦听器安全地执行此操作。特别地, 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,则不会再次调用回调,您可以安全地取消分配。