2012-01-23 80 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 ...