2013-03-31 2 views
11

Я использую AVAssetReaderOutput для чтения образцов из AVAsset, выполняю некоторую обработку на них и воспроизвожу результат с помощью RemoteIO AU.Невозможно продолжить чтение с AVAssetReaderOutput после перехода на задний план и обратно на передний план

Проблема заключается в том, что после вызова AudioOutputUnitStop, чтобы приостановить воспроизведение, затем, перейдя на задний план и обратно на передний план, звук не возобновится после вызова AudioOutputUnitStart. Это связано с ошибкой, возвращаемой с помощью метода copyNextSampleBufferAVAssetReaderOutput, который называется частью конвейера рендеринга.

status свойство AVAssetReader после вызова copyNextSampleBuffer является AVAssetReaderStatusFailed, а его свойство error является Error Domain = AVFoundationErrorDomain Code = -11847 "Операция Прерванный" UserInfo = 0x1d8b6100 {NSLocalizedRecoverySuggestion = Прекратить другие операции и повторите попытку., NSLocalizedDescription = Операция Прерванный}

Я ищу решение, которое не заставит меня переинициализировать весь трубопровод после возвращения на первый план - Надеясь, есть такое решение, которое AVAssetReader s может выжить приложение будет фон и назад ...

Примечание

  • Приложение имеет право воспроизводить аудио в фоновом режиме.
  • Я обрабатываю прерывания звука. Установка моего AVAudioSession как активного как на AVAudioSessionDelegate s 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; 
    } 
... 
} 
+0

Это для сжатого типа аудио? Сообщается, что некоторые из аппаратных блоков декомпрессии звука на некоторых моделях устройств не могут быть прерваны без перезапуска. – hotpaw2

+0

Интересно. Он предназначен для чтения «AVAsset», извлеченного из песни «MPMediaItem», из пользовательской библиотеки iTunes. Поэтому mp3/m4a, я считаю, что оба сжаты. Что касается «моделей устройств» - это проблема на iPhone 5. Есть ли доступная ссылка для того, что вы описываете? – Danra

ответ

4

Графики и основы AVReader: не связано/связано вообще. Путаница, возможно, исходит из того, что iOS не будет «фоновым» (спящим) процессом, если видит, что работает звуковой график (потому что тогда аудиоданные не смогут быть сгенерированы). Вот почему, когда вы прекратите звуковой график, через 2-3 минуты iOS заложит ваш процесс (начиная с iOS 9). Предположительно, iOS смотрит на то, что происходит в вашем процессе, и решает, когда ваш процесс должен быть привязан к фону (через beginBackgroundTaskWithName:expirationHandler).

Apple devs решила по какой-либо причине заставить AVReader остановиться при установке в фоновом режиме (мое лучшее предположение - QA). Хорошей новостью является то, что вы можете обнаружить ее и восстановить, когда ваш процесс выходит из фонового режима, но вам нужно снова перезапустить ваш ридер и readerOutput. Во-первых, когда значение copyNextSampleBuffer AVAssetReaderOutput возвращает NULL, проверьте AVAssetReader.error.code на AVErrorOperationInterrupted.

Способ, которым мы получаем безщелезное восстановление здесь, когда мы добираемся до этого момента, сначала вычисляем точное время, которое мы остановили (легко сделать - просто поддерживаем счетчик уже отобранных образцов). Затем вам необходимо перезапустить поток AVAssetReader и AVAssetReaderOutput. Но это не проблема, так как ваши хорошие методы развития инкапсулировали бы это в одну функцию, которая имеет время поиска в качестве аргумента. В этой функции используйте AVAssetReader.timeRange, чтобы найти то время, когда вам нужно возобновить работу и препод!

3

Прежде всего, я хотел бы попробовать:

Не звонил AudioOutputUnitStop? Почему бы вам не оставить график работает и когда звук паузы просто не называют

[self.readerOutput copyNextSampleBuffer] 

Вместо просто заполнить буфер с 0 и/или использовать оказывать действие kAudioUnitRenderAction_OutputIsSilence для буферов. Запуск и остановка графика требует времени и приводит к невосприимчивому графу. Я никогда не останавливаю график во время работы моих приложений. (Если не произойдет какое-то серьезное прерывание). Это может держать читателя активов и радоваться.

Но у меня есть догадка, что, поскольку AVAssetReader напрямую не подключен к звуковому графику (вам просто нужно запросить образцы и поместить их в буфер, предоставленный обратным вызовом рендеринга), проблема заключается не в том, остановился и перезапустился вообще.Итак, следующая строка атаки, которую я постараюсь, это запросить образцы из AVAsset, поместить приложение в фоновый режим и вернуть его на передний план без использования AUGraph вообще. Это определит, связана ли проблема с AUGraph или приложением, входящим в фоновое состояние.

Если что-то случится, что вынудит вас снести ваш AVAssetReader, вам придется снова подключиться к активу. Так как вам нужно написать этот код, другой вариант, на который я бы посмотрел, - это тот, который вы не хотите делать. Подсоединитесь к AVAssetReader, ищите позицию, в которой вы остановились, и продолжайте движение.

+0

На самом деле то, что я делаю прямо сейчас на паузе, точно так же, как вы писали, заполняя буфер 0, и таким образом, когда вы переходите на bg и возвращаетесь в fg и снова начинаете воспроизведение, воспроизведение продолжается правильно. Проблема с этим подходом заключается в том, что значок «play» остается в строке состояния. – Danra

+0

Итак, вы говорите, что AVAssetReader связан с AUGraph? –

+0

Не знаете, что вы подразумеваете под этим? Я прочитал его в обратном вызове воспроизведения AU. – Danra

 Смежные вопросы

  • Нет связанных вопросов^_^