簡體   English   中英

轉到后台並返回前台后無法繼續從AVAssetReaderOutput讀取

[英]Can't continue reading from AVAssetReaderOutput after going to background and back to foreground

我使用的是AVAssetReaderOutput閱讀從樣品AVAsset ,做他們一些處理,並使用RemoteIO玩AU的結果。

問題是在調用AudioOutputUnitStop暫停播放后,在轉到后台並返回前台后,調用AudioOutputUnitStart后音頻將不會再次啟動。 這是由於從返回錯誤copyNextSampleBuffer的方法AVAssetReaderOutput ,其被稱作渲染流水線的一部分。

調用AVAssetReadercopyNextSampleBufferstatus屬性為AVAssetReaderStatusFailed ,其error屬性為Error Domain = AVFoundationErrorDomain Code = -11847“Operation Interrupted”UserInfo = 0x1d8b6100 {NSLocalizedRecoverySuggestion =停止其他操作並再試一次。,NSLocalizedDescription = Operation Interrupted}

我正在尋找一種解決方案,它不會強迫我在回到前台后重新初始化整個管道 - 希望有這樣一個解決方案, AVAssetReader可以在應用程序進入后台並返回...

筆記

  • 該應用程序有權在后台播放音頻。
  • 我在處理音頻中斷-設置我的AVAudioSession作為活動的一個或兩個AVAudioSessionDelegate小號endInterruptionWithFlags:事件,每當應用程序被激活。 無論我是否這樣做都沒有區別,得到同樣的錯誤。

一些代碼:

AudioPlayer

@implementation AudioPlayer
    ...
// Audio Unit Setup
AudioComponentDescription desc;
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_RemoteIO;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;

AudioComponent defaultOutput = AudioComponentFindNext(NULL, &desc);

AudioComponentInstanceNew(defaultOutput, &_audioUnit);

AudioStreamBasicDescription audioFormat;
    FillOutASBDForLPCM(audioFormat, 44100, 2, 16, 16, false, false);

AudioUnitSetProperty(self.audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &audioFormat, sizeof(audioFormat));

AURenderCallbackStruct callbackStruct;
callbackStruct.inputProc = RenderCallback;
callbackStruct.inputProcRefCon = (__bridge void*)self;
AudioUnitSetProperty(self.audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callbackStruct, sizeof(callbackStruct));

AudioUnitInitialize(self.audioUnit);

AudioReader設置

@implementation AudioReader
    ...
NSError* error = nil;
self.reader = [AVAssetReader assetReaderWithAsset:self.asset error:&error];
NSDictionary *outputSettings = ...
self.readerOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:[self.asset.tracks objectAtIndex:0] outputSettings:outputSettings];
[self.reader addOutput:self.readerOutput];
[self.reader startReading];

AudioReader渲染方法,最終由RenderCallback函數調用

-(BOOL)readChunkIntoBuffer
{
     CMSampleBufferRef sampleBuffer = [self.readerOutput copyNextSampleBuffer];
     if ( sampleBuffer == NULL )
     {
         NSLog(@"Couldn't copy next sample buffer, reader status=%d error=%@, self.reader.status, self.reader.error);
         return NO;
     }
 ...
}

圖形和AVReader基礎沒有任何連接/鏈接。 混淆可能來自iOS如果看到音頻圖形正在運行(因為那時無法生成音頻數據),它將不會“背景”(休眠)一個過程。 這就是為什么當您停止音頻圖表時,2-3分鍾后,iOS將為您的流程提供背景(從iOS 9開始)。 據推測,iOS會查看流程中發生的情況,並決定何時應將流程強制為后台(通過beginBackgroundTaskWithName:expirationHandler )。

無論出於什么原因,Apple開發者決定讓AVReader在進入后台模式時停止(我最好的猜測是QA)。 好消息是,當您的進程退出后台模式時,您可以檢測到並恢復,但您需要重新啟動閱讀器和readerOutput。 首先,當AVAssetReaderOutput的copyNextSampleBuffer返回NULL時,檢查AVAssetReader.error.code是否存在AVErrorOperationInterrupted

我們在這里實現無間隙恢復的方式是當我們到達那一點時,我們首先計算我們離開的確切時間(容易做到 - 只保持已經輸出的總樣本的計數器)。 然后,您將需要重新啟動AVAssetReaderAVAssetReaderOutput流。 但這沒有問題,因為您的良好開發實踐會將其封裝在一個以尋道時間為參數的單個函數中。 在該函數中,使用AVAssetReader.timeRange來尋找你需要恢復的時間和presto!

首先我要嘗試的是:

不調用AudioOutputUnitStop 為什么不讓圖表繼續運行?當音頻暫停時根本不打電話

[self.readerOutput copyNextSampleBuffer]

而是僅使用0填充緩沖區和/或對緩沖區使用kAudioUnitRenderAction_OutputIsSilence的渲染操作。 啟動和停止圖表需要花費時間並導致圖表無響應。 我的應用程序運行時,我從不停止圖表。 (除非發生一些嚴重的中斷)這可能讓資產讀者保持愉快。

但我有一種預感,因為AVAssetReader沒有直接連接到音頻圖形(你碰巧請求樣本並將它們放在渲染回調提供的緩沖區中),問題不在於音頻圖形被停止並重新啟動所有。 因此,我要嘗試的下一行攻擊是從AVAsset請求樣本,將應用程序放入后台並將其恢復到前台而根本不使用AUGraph 這將確定問題是否與AUGraph或應用程序進入后台狀態有關。

如果發生某些事情迫使您拆除AVAssetReader ,則必須重新連接到資產。 因此,當你必須編寫另一個代碼時,我會看到的是你不想做的選項。 重新連接到AVAssetReader ,尋找你離開的位置並繼續前進。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM