问题是在调用AudioOutputUnitStop暂停播放之后,在进入后台并返回到前台之后,在调用AudioOutputUnitStart之后,音频将不会再次启动.这是由于AVAssetReaderOutput的copyNextSampleBuffer方法返回的错误,它被称为渲染管道的一部分.
调用copyNextSampleBuffer之后,AVAssetReader的status属性为AVAssetReaderStatusFailed,其错误属性为Error Domain = AVFoundationErrorDomain Code = -11847“Operation Interrupted”UserInfo = 0x1d8b6100 {NSLocalizedRecoverySuggestion =停止其他操作,再次尝试,NSLocalizedDescription =操作中断}
我正在寻找一个解决方案,不会强制我重新初始化整个管道回到前台 – 希望有一个这样的解决方案,AVAssetReaders可以生存的应用程序到背景和背面…
笔记
>该应用程序有权在后台播放音频.
>我正在处理音频中断 – 将AVAudioSession设置为AVAudioSessionDelegates 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,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,&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在进入后台模式时停止(我最好的猜测是QA).好消息是,当您的进程退出后台模式时,您可以检测并恢复,但是您需要重新启动读卡器和readerOutput.首先,当AVAssetReaderOutput的copyNextSampleBuffer返回NULL时,请检查AVErrorOperationInterrupted的AVAssetReader.error.code.
我们在这方面取消无缝恢复的方式是,当我们到达这一点时,我们首先计算出我们停留的确切时间(容易做 – 只保持已经输出的总样本的计数器).然后,您将需要重新启动AVAssetReader和AVAssetReaderOutput流程.但这是没有问题的,因为您的良好开发实践将封装在具有寻求时间作为参数的单个功能中.在那个功能中,使用AVAssetReader.timeRange来寻找那个时候你需要恢复和预先安装!