转到后台并返回前台后无法继续从AVAssetReaderOutput读取

时间:2013-03-31 13:16:04

标签: ios core-audio audiounit avassetreader

我正在使用AVAssetReaderOutputAVAsset读取样本,对它们进行一些处理,并使用RemoteIO AU播放结果。

问题是在调用AudioOutputUnitStop暂停播放后,在转到后台并返回前台后,调用AudioOutputUnitStart后音频将不会再次启动。这是由copyNextSampleBuffer AVAssetReaderOutput方法返回的错误引起的,该方法被称为渲染管道的一部分。

调用statusAVAssetReader的{​​{1}}属性为copyNextSampleBuffer,其AVAssetReaderStatusFailed属性为错误域= AVFoundationErrorDomain代码= -11847 “操作中断”UserInfo = 0x1d8b6100 {NSLocalizedRecoverySuggestion =停止其他操作并再试一次。,NSLocalizedDescription =操作中断}

我正在寻找一种解决方案,它不会强迫我在回到前台后重新初始化整个管道 - 希望有这样的解决方案,error s可以在应用程序转到后台并且回来......

注释

  • 该应用有权在后台播放音频。
  • 我正在处理音频中断 - 在AVAssetReader AVAudioSession事件和应用变为活动状态时,将AVAudioSessionDelegate设置为活动状态。不论我是否这样做都没有区别,得到同样的错误。

一些代码:

AudioPlayer

endInterruptionWithFlags:

AudioReader设置

@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渲染方法,最终由RenderCallback函数调用

@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];

2 个答案:

答案 0 :(得分:4)

图形和AVReader基础连接/链接。这种困惑可能来自iOS赢得了背景" (休眠)一个进程,如果它看到音频图运行(因为那时音频数据将无法生成)。这就是为什么当您停止音频图表时,2-3分钟后,iOS将为您的流程提供背景(从iOS 9开始)。据推测,iOS会查看您流程中的内容,并决定何时应将您的流程强制为后台(通过beginBackgroundTaskWithName:expirationHandler)。

Apple开发者无论出于什么原因决定让AVReader在进入后台模式时停止(我最好的猜测是QA)。好消息是,当您的进程退出后台模式时,您可以检测到并恢复,但您需要重新启动阅读器和readerOutput。首先,当AVAssetReaderOutput' s copyNextSampleBuffer返回NULL时,请检查AVAssetReader.error.code AVErrorOperationInterrupted

我们在这里实现无间隙恢复的方式是当我们到达那一点时,我们首先计算我们离开的确切时间(容易做到 - 只保持已经输出的总样本的计数器)。然后,您需要重新启动AVAssetReaderAVAssetReaderOutput流程。但这没有问题,因为你的良好开发实践会将这个问题封装在一个以寻道时间为参数的单一函数中。在该功能中,使用AVAssetReader.timeRange寻找您需要恢复的时间和地点!

答案 1 :(得分:3)

首先我要尝试的是:

不打电话给AudioOutputUnitStop?为什么不让图表继续运行?当音频暂停时根本不调用

[self.readerOutput copyNextSampleBuffer]

而是仅使用0填充缓冲区和/或对缓冲区使用kAudioUnitRenderAction_OutputIsSilence的渲染操作。启动和停止图表需要花费时间并导致图表无响应。我的应用程序运行时,我从不停止图表。 (除非发生一些严重的中断)这可能会让资产读者保持健康。

但我有预感,因为AVAssetReader没有直接连接到音频图(你碰巧请求样本并将它们放在渲染回调提供的缓冲区中),问题不在于音频图表被停止并重新启动。因此,我要尝试的下一行攻击是从AVAsset请求样本,将应用程序放入后台并将其带回前台而不使用AUGraph 。这将确定问题是否与AUGraph或应用程序进入后台状态有关。

如果发生某些事情迫使您拆除AVAssetReader,则必须重新连接资产。因此,当你必须编写另一个代码时,我会看到的是你不想做的选项。重新连接到AVAssetReader,寻找你离开的位置并继续前进。