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

Mel*_*box 10 objective-c audio-recording avfoundation ios ios8

我希望从麦克风实时输入波形显示.我已经使用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 < buffer.audioBufferList->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;
}
Run Code Online (Sandbox Code Playgroud)

djd*_*nce 14

他们说,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
Run Code Online (Sandbox Code Playgroud)


Jas*_*sey 6

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

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


小智 5

从 2019 年的 iOS 13 开始,有 AVAudioSinkNode,它可能会更好地完成您的需求。虽然您也可以创建一个常规的 AVAudioUnit / Node 并将其附加到输入/输出,但与 AVAudioSinkNode 的区别在于不需要输出。这使它更像是一个水龙头,并避免了使用常规音频单元/节点时可能出现的不完整链的问题。

想要查询更多的信息:

相关的 Swift 代码位于会话 PDF 的第 10 页(下面更正了一个小错误)。

// Create Engine
let engine = AVAudioEngine()
// Create and Attach AVAudioSinkNode
let sinkNode = AVAudioSinkNode() { (timeStamp, frames, audioBufferList) ->
OSStatus in
 …
}
engine.attach(sinkNode) 
Run Code Online (Sandbox Code Playgroud)

我想您在使用它时仍然必须遵循典型的实时音频规则(例如,没有分配/释放内存、没有 ObjC 调用、没有锁定或等待锁定等)。环形缓冲区在这里可能仍然有用。