我想每秒调用20次installTapOnBus:bufferSize:format:block:

我想从麦克风实时输入波形显示。 我已经使用installTapOnBus:bufferSize:format:block:来实现,这个函数在一秒钟内被调用三次。 我想将此函数设置为每秒调用20次。 我在哪里可以设置?

AVAudioSession *audioSession = [AVAudioSession sharedInstance]; NSError* error = nil; if (audioSession.isInputAvailable) [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:&error]; if(error){ return; } [audioSession setActive:YES error:&error]; if(error){ retur; } self.engine = [[[AVAudioEngine alloc] init] autorelease]; AVAudioMixerNode* mixer = [self.engine mainMixerNode]; AVAudioInputNode* input = [self.engine inputNode]; [self.engine connect:input to:mixer format:[input inputFormatForBus:0]]; // tap ... 1 call in 16537Frames // It does not change even if you change the bufferSize [input installTapOnBus:0 bufferSize:4096 format:[input inputFormatForBus:0] block:^(AVAudioPCMBuffer* buffer, AVAudioTime* when) { for (UInt32 i = 0; i mNumberBuffers; i++) { Float32 *data = buffer.audioBufferList->mBuffers[i].mData; UInt32 frames = buffer.audioBufferList->mBuffers[i].mDataByteSize / sizeof(Float32); // create waveform ... } }]; [self.engine startAndReturnError:&error]; if (error) { return; } 

他们说,Apple支持回复 🙁 2014年9月)

是的,目前我们内部有一个固定的抽头缓冲区大小(0.375s),并且客户端指定的tap的缓冲区大小没有生效。

但有人调整缓冲区大小,并获得40毫秒https://devforums.apple.com/thread/249510?tstart=0

在ObjC中无法检查它:(

UPD它有效! 只是单行:

  [input installTapOnBus:0 bufferSize:1024 format:[mixer outputFormatForBus:0] block:^(AVAudioPCMBuffer *buffer, AVAudioTime *when) { buffer.frameLength = 1024; //here 

AVAudioNode类引用指出实现可能会选择一个缓冲区大小而不是你提供的缓冲区大小,所以据我所知,我们会遇到非常大的缓冲区大小。 这是不幸的,因为AVAudioEngine是一个出色的Core Audio包装器。 由于我也需要使用输入分接头来进行录制以外的其他操作,我正在研究The Amazing Audio Engine,以及Core Audio C API(请参阅iBook Learning Core Audio以获得优秀的教程)作为替代方案。

***更新:事实certificate,您可以访问AVAudioInputNode的AudioUnit并在其上安装渲染回调。 通过AVAudioSession,您可以设置音频会话所需的缓冲区大小(不保证,但肯定比节点点击更好)。 到目前为止,我已经使用这种方法获得了低至64个样本的缓冲区大小。 一旦我有机会测试这个,我会在这里用代码发回。

您可以使用CADisplayLink来实现此目的。 每次屏幕刷新时, CADisplayLink都会给你一个回调,这通常会超过每秒20次(因此可能需要额外的逻辑来限制或限制你的方法在你的情况下执行的次数)。

这显然是一个与音频工作完全不同的解决方案,并且在您需要反映会话的解决方案的范围内,它可能无法正常工作。 但是当我们需要在iOS上频繁重复回调时,这通常是首选方法,所以这是一个想法。

不知道为什么,即使这个有效,只是尝试了一些事情。 但是肯定NSLogs表示一个21毫秒的间隔,每个缓冲区有1024个样本…

  AVAudioEngine* sEngine = NULL; - (void)applicationDidBecomeActive:(UIApplication *)application { /* Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. */ [glView startAnimation]; AVAudioSession *audioSession = [AVAudioSession sharedInstance]; NSError* error = nil; if (audioSession.isInputAvailable) [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:&error]; if(error){ return; } [audioSession setActive:YES error:&error]; if(error){ return; } sEngine = [[AVAudioEngine alloc] init]; AVAudioMixerNode* mixer = [sEngine mainMixerNode]; AVAudioInputNode* input = [sEngine inputNode]; [sEngine connect:input to:mixer format:[input inputFormatForBus:0]]; __block NSTimeInterval start = 0.0; // tap ... 1 call in 16537Frames // It does not change even if you change the bufferSize [input installTapOnBus:0 bufferSize:1024 format:[input inputFormatForBus:0] block:^(AVAudioPCMBuffer* buffer, AVAudioTime* when) { if (start == 0.0) start = [AVAudioTime secondsForHostTime:[when hostTime]]; // why does this work? because perhaps the smaller buffer is reused by the audioengine, with the code to dump new data into the block just using the block size as set here? // I am not sure that this is supported by apple? NSLog(@"buffer frame length %d", (int)buffer.frameLength); buffer.frameLength = 1024; UInt32 frames = 0; for (UInt32 i = 0; i < buffer.audioBufferList->mNumberBuffers; i++) { Float32 *data = buffer.audioBufferList->mBuffers[i].mData; frames = buffer.audioBufferList->mBuffers[i].mDataByteSize / sizeof(Float32); // create waveform /// } NSLog(@"%d frames are sent at %lf", (int) frames, [AVAudioTime secondsForHostTime:[when hostTime]] - start); }]; [sEngine startAndReturnError:&error]; if (error) { return; } }