【发布时间】:2015-02-03 15:34:10
【问题描述】:
我一直在尝试使用 AVAudioEngine 来安排多个音频文件以完美同步播放,但是在收听输出时,输入节点之间似乎存在非常轻微的延迟。音频引擎使用下图实现:
//
//AVAudioPlayerNode1 -->
//AVAudioPlayerNode2 -->
//AVAudioPlayerNode3 --> AVAudioMixerNode --> AVAudioUnitVarispeed ---> AvAudioOutputNode
//AVAudioPlayerNode4 --> |
//AVAudioPlayerNode5 --> AudioTap
// |
//AVAudioPCMBuffers
//
我正在使用以下代码加载示例并同时安排它们:
- (void)scheduleInitialAudioBlock:(SBScheduledAudioBlock *)block {
for (int i = 0; i < 5; i++) {
NSString *path = [self assetPathForChannel:i trackItem:block.trackItem]; //this fetches the right audio file path to be played
AVAudioPCMBuffer *buffer = [self bufferFromFile:path];
[block.buffers addObject:buffer];
}
AVAudioTime *time = [[AVAudioTime alloc] initWithSampleTime:0 atRate:1.0];
for (int i = 0; i < 5; i++) {
[inputNodes[i] scheduleBuffer:block.buffers[i]
atTime:time
options:AVAudioPlayerNodeBufferInterrupts
completionHandler:nil];
}
}
- (AVAudioPCMBuffer *)bufferFromFile:(NSString *)filePath {
NSURL *fileURl = [NSURL fileURLWithPath:filePath];
NSError *error;
AVAudioFile *audioFile = [[AVAudioFile alloc] initForReading:fileURl commonFormat:AVAudioPCMFormatFloat32 interleaved:NO error:&error];
if (error) {
return nil;
}
AVAudioPCMBuffer *buffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:audioFile.processingFormat frameCapacity:audioFile.length];
[audioFile readIntoBuffer:buffer frameCount:audioFile.length error:&error];
if (error) {
return nil;
}
return buffer;
}
我注意到这个问题只能在设备上感知,我正在使用 iPhone5s 进行测试,但我无法弄清楚为什么音频文件播放不同步,任何帮助将不胜感激。
** 答案**
我们最终使用以下代码对问题进行了排序:
AVAudioTime *startTime = nil;
for (AVAudioPlayerNode *node in inputNodes) {
if(startTime == nil) {
const float kStartDelayTime = 0.1; // sec
AVAudioFormat *outputFormat = [node outputFormatForBus:0];
AVAudioFramePosition startSampleTime = node.lastRenderTime.sampleTime + kStartDelayTime * outputFormat.sampleRate;
startTime = [AVAudioTime timeWithSampleTime:startSampleTime atRate:outputFormat.sampleRate];
}
[node playAtTime:startTime];
}
这给了每个 AVAudioInputNode 足够的时间来加载缓冲区并修复了我们所有的音频同步问题。希望这对其他人有帮助!
【问题讨论】:
-
好吧,你有多个播放器节点,你需要在每个节点上调用
play方法。我的猜测是这个调用立即开始处理并在音频线程中抛出一些东西。由于每个play在不同的时间被调用,它可能会导致这种延迟。我的推理是否正确,是否可以批量启动播放器节点我不知道。我实际上正在使用 Apple 开发人员支持票,其中我提出了类似的问题。如果我得到任何明确的答案,我会回到这个问题。 -
问题根本不在于 playAt: 方法。它恰好用于批量启动。您只需要使用一个具体的锚定时间。请参阅下面的答案...
-
因此,尽管您在 ANSWER 中提供了解决方案,但如果设备需要超过 0.1 秒的时间才能完成操作,您的问题仍然存在。只要您没有正确安排它们,这些都是神奇的数字......
-
嗨,丹尼,我的目标是从指定时间播放 AVAudioPlayerNode。我得到缓冲区,并在时间调度缓冲区,然后调用 playat time 方法。播放器未从指定时间开始播放。而是从头开始播放。
-
每次玩都需要安排缓冲吗?
标签: ios objective-c iphone ipad core-audio