我一直致力于使用AudioQueueNewOutput
的Objective-C中的应用程序。我有其他声音库的经验,所以回调机制很熟悉。但是,我遇到的一个问题是inUserData
指针。当您调用AudioQueueStop
时,即使立即设置为true,回调也可以再次运行。这使得在调用AudioQueueStop
的同时解除分配用户指针中的任何内容是不合适的。
这是kAudioQueueProperty_IsRunning
的目的吗?该侦听器的回调是否保证不会再次调用队列回调,并且可以安全地释放用户指针?
如果这不是正确的机制,那么我很难想到会发生什么。回调可能会尝试同步它在调用AudioQueueStop
后认为剩余的缓冲区数,但这似乎很脆弱。我想避免在这么多秒之后解除分配或者泄漏记忆之类的黑客攻击。
答案 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,则不会再次调用回调,您可以安全地取消分配。