iOS应用叠加播放音频时仅SoundCloud后台播放出现延迟如何解决
针对SoundCloud后台播放时iOS应用叠加音频延迟的解决方案
你遇到的200ms延迟本质是AVAudioSession激活协商开销+音频引擎预启动缺失导致的,SoundCloud的音频会话使用了更高的优先级配置,系统在你触发播放时才进行会话资源协商就会产生额外延迟,可按以下步骤修复:
- 提前配置并激活AVAudioSession,不要在播放触发时才操作
在App启动或音频模块初始化时就完成会话配置,避免播放时才走激活协商流程,示例代码:
同时要监听NSError *sessionError = nil; AVAudioSession *session = [AVAudioSession sharedInstance]; [session setCategory:AVAudioSessionCategoryPlayback mode:AVAudioSessionModeDefault options:AVAudioSessionCategoryOptionMixWithOthers | AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers error:&sessionError]; // 设置更小的IO缓冲时长,降低底层延迟 [session setPreferredIOBufferDuration:0.005 error:&sessionError]; // 提前激活会话 [session setActive:YES error:&sessionError];AVAudioSessionInterruptionNotification通知,当中断结束后立刻重新激活会话,避免下次播放时重新走激活流程。 - 修正AVAudioEngine的预加载逻辑,提前启动引擎
你当前的代码只完成了节点挂载和连接,没有提前启动音频引擎,启动引擎的操作会产生不小的开销,要放到预加载阶段完成,不要放在播放触发时:- (void)prepQuickSound:(Sound *)sound { // 复用全局的audioEngine、playerNode、mixerNode,不要每次预加载都重建 if (!self.audioEngine) { self.audioEngine = [[AVAudioEngine alloc] init]; self.audioMixerNode = [[AVAudioMixerNode alloc] init]; [self.audioEngine attachNode:self.audioMixerNode]; [self.audioEngine connect:self.audioMixerNode to:self.audioEngine.outputNode format:nil]; self.player = [[AVAudioPlayerNode alloc] init]; [self.audioEngine attachNode:self.player]; [self.audioEngine connect:self.player to:self.audioMixerNode format:nil]; // 预启动引擎 NSError *engineError = nil; [self.audioEngine startAndReturnError:&engineError]; } // 提前把音频文件读成PCM buffer存在内存,避免播放时读文件开销 NSURL* pathURL = [NSURL fileURLWithPath:[sound getStoragePath] isDirectory:NO]; NSError *audioLoadError = nil; AVAudioFile *audioFile = [[AVAudioFile alloc] initForReading:pathURL error:&audioLoadError]; AVAudioPCMBuffer *buffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:audioFile.processingFormat frameCapacity:(AVAudioFrameCount)audioFile.length]; [audioFile readIntoBuffer:buffer error:&audioLoadError]; self.preloadedBuffer = buffer; // 提前调度buffer,等待播放 [self.player scheduleBuffer:self.preloadedBuffer atTime:nil options:0 completionHandler:nil]; } - (void)playQuickSound { if (!self.audioEngine.isRunning) { NSError *engineError = nil; [self.audioEngine startAndReturnError:&engineError]; } // 直接重置后播放即可 [self.player stop]; [self.player scheduleBuffer:self.preloadedBuffer atTime:nil options:0 completionHandler:nil]; [self.player playAtTime:[self.audioEngine nextRenderTime]]; } - 避免频繁重建音频相关实例
全局复用AVAudioEngine、AVAudioPlayerNode、AVAudioSession实例,不要每次播放都销毁重建,减少初始化开销。
内容的提问来源于stack exchange,提问作者head in the codes
相关产品推荐
相关产品推荐

