2012-01-23 46 views
0

有它通过网络流文件的音频应用程序,一切工作正常,但一两件事。要在后台自动播放下一首曲目,在调用AudioQueueStop之后,CFReadStream被初始化(我可以在日志中看到它),但回调永远不会被调用(编辑:实际被调用一次),直到应用程序进入前景。这段代码为流初始化:CFReadStream - 在后台启动

//also tried main runloop just for test, no luck 
CFReadStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); 

有线的事情是,应用程序是功能性的队列停止后,流正在初始化,但只有当流在前台模式初始化的回调是正常调用。这里是回调的一段代码:

CFReadStreamSetClient(stream, 
         kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered, 
         MyReadStreamCallBack, 
         &context); 

在另一方面,当应用程序在后台和下轨被自动触发不能不与应用程序,委托(具有相同的回调被称为功能)。

我不完全理解这三种情况之间有区别,请大家帮忙。

编辑。而MyReadStreamCallBack被称为只是一次

OSStatus status = AudioFileStreamOpen(self, MyAudioListener ... 

MyAudioListener回调被调用。

编辑2

的ReadStream回调是最经常不会被调用甚至一度,一个时间是最大的什么,我能看到。

在另一方面,这驱使我发生了什么事的误解,后,以前的AudioQueue停止和下轨是本地文件,然后另一AudioQueue打开,它读取文件与AudioFileReadPackets和我没有从后台唤醒应用程序启动下一个轨迹回放为它起着本身的背景。

回答

1

的音频队列将继续在后台运行,给出的approprate背景模式。但一旦停止,似乎音频队列将不会开始在后台运行。一次回调可能只是为了填充缓冲区,所以队列可以在被带到前台后立即启动。

我发现的唯一解决方案是在后台不停止先前的音频队列,但以某种方式将新的音频数据馈送到左侧运行的旧音频队列,而不会下溢之间的任何回调。

+0

这是非常有帮助的,为什么AudioQueue开始,并在后台运行的任何评论但如果下一曲目存储在本地并使用另一个流器(它不会等待网络回调,而是使用递归的AudioFileReadPackets)? –

+0

只是一个猜测,但如果下一首曲目的音频数据立即可用,并且在AQ真正完全停止(而不是被要求停止)之前可用,它可能并不真正停止。 – hotpaw2

+0

的确有很大的帮助,我终于为网络流式传输器添加了后台任务,直到回调接收到足够的数据以填充其中一个缓冲区并启动了AudioQueue(它并未真正启动 - AudioQueueStart尚未作为没有数据可以播放)。一个代码方案将遵循所有感兴趣的人。 –

0

目前的解决办法是添加一个后台作业要等到有开始新的队列(开始排队W/O数据给出-50错误,我相信挂着硬件解码器)中的数据。

让我们在流光播放功能说有像这样的东西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调用某个地方,对我来说这是用来hanlde数据的下载件为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 ...