有一个音频应用程序通过网络传输文件,一切正常,但有一件事。为了在后台自动播放下一首曲目,在调用AudioQueueStop之后初始化CFReadStream(我可以在日志中看到它),但是从不调用回调(编辑:实际上被调用一次),直到应用程序进入前台。流init的代码片段:
//also tried main runloop just for test, no luck
CFReadStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
有线的是,在队列停止后,应用程序正常运行,正在初始化流,但只有在前台模式下初始化流时才正确调用回调。这是一段回调代码:
CFReadStreamSetClient(stream,
kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered,
MyReadStreamCallBack,
&context);
另一方面,当应用程序在后台并且不是自动触发下一曲目而是使用app-delegate(具有相同功能)时,将调用回调。
我不完全理解这三种情况之间的区别,请帮忙。
编辑。
OSStatus status = AudioFileStreamOpen(self, MyAudioListener ...
调用MyAudioListener回调,而MyReadStreamCallBack只调用 。
编辑2
ReadStream回调通常甚至不被调用一次,一次是我能够看到的最大值。
另一方面,这让我误解了正在发生的事情,在之前的AudioQueue停止并且下一首曲目是本地文件之后,那么打开另一个AudioQueue ,它使用AudioFileReadPackets读取文件,我不必从后台唤醒应用程序以开始下一首曲目播放,因为它在后台播放。< / p>
答案 0 :(得分:1)
在适当的背景模式下,音频队列将继续在后台运行。但一旦停止,似乎音频队列将无法在后台运行。一个回调可能只是填充缓冲区,因此队列可以在被带到前台后立即启动。
我发现的唯一解决方案是在后台不停止上一个音频队列,但以某种方式将新的音频数据提供给左侧运行的旧音频队列,而不会在其间中断任何回调。
答案 1 :(得分:0)
当前的解决方案是添加一个后台作业,等待有数据开始一个新队列(开始队列没有数据给出-50错误,我相信挂起一个hw解码器)。
让我们说在流媒体播放功能中有openNetworkStream函数,如下所示:
// ...whatever we need to be happy
// start the background job
UIDevice* device = [UIDevice currentDevice];
BOOL isBackgroundSupported = NO;
if ([device respondsToSelector:@selector(isMultitaskingSupported)])
isBackgroundSupported = device.multitaskingSupported;
if(isBackgroundSupported && waitForQueueToStartBackgroundTask == UIBackgroundTaskInvalid) {
waitForQueueToStartbackgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:waitForQueueToStartBackgroundTask];
waitForQueueToStartBackgroundTask = UIBackgroundTaskInvalid;
}];
}
// Open the stream
if (!CFReadStreamOpen(stream)) {
你应该在某个地方有一个AudioQueueStart调用,对我来说,StreamEnqueueBuffer函数用于处理下载的数据片段,因为缓冲区已经准备好播放或者文件结束了(AudioQueueEnqueueBuffer),这个函数也是我们需要填充缓冲区以启动它,因此是AudioQueue的初始启动程序。我的解决方案是在队列启动时结束已初始化的启动后台作业:
OSStatus StreamEnqueueBuffer(AudioNetworkStreamer* aStreamer)
// wahtever you need to be happy with a filled buffer
if (!aStreamer->didStart) { // start the queue if it has not been started already
aStreamer->isBuffering = NO;
[aStreamer startQueue];
UIDevice* device = [UIDevice currentDevice];
BOOL isBackgroundSupported = NO;
if ([device respondsToSelector:@selector(isMultitaskingSupported)])
isBackgroundSupported = device.multitaskingSupported;
if(isBackgroundSupported && aStreamer->waitForQueueToStartBackgroundTask == UIBackgroundTaskInvalid) {
[[UIApplication sharedApplication] endBackgroundTask:aStreamer->waitForQueueToStartBackgroundTask];
aStreamer->waitForQueueToStartBackgroundTask = UIBackgroundTaskInvalid;
}
}
// nandle mutexes, flags ...