在 AudioUnit 播放回调中从 AudioBuffer->mdata 播放音频

Posted

技术标签:

【中文标题】在 AudioUnit 播放回调中从 AudioBuffer->mdata 播放音频【英文标题】:Playing audio from AudioBuffer->mdata in AudioUnit playback callback 【发布时间】:2016-08-22 14:23:01 【问题描述】:

一整天以来,我一直在寻找并尝试解决以下问题。还没有成功

好的,所以我一直在使用苹果示例代码项目名称 WiTap 使用 NSInputStreamsNSOutputStreams 通过 wifi 与两个设备进行黑白通信我已经能够传输数据(音频数据)黑白设备成功。

但是在目标设备上我接收数据并将其填充到音频缓冲区中,如下所示:

bytesRead = [self.inputStream read:anAudioBuffer.mData maxLength:anAudioBuffer.mDataByteSize];

anAudioBuffer本身声明如下

anAudioBuffer.mNumberChannels = 1;
anAudioBuffer.mDataByteSize = 512 * 2;
anAudioBuffer.mData = malloc( 512 * 2 );

现在我在 Apple 示例代码的 AudioUnit 回调中以 someObject.anAudioBuffer 的身份访问此音频缓冲区

如下

static OSStatus playbackCallback(void *inRefCon, 
                                 AudioUnitRenderActionFlags *ioActionFlags, 
                                 const AudioTimeStamp *inTimeStamp, 
                                 UInt32 inBusNumber, 
                                 UInt32 inNumberFrames, 
                                 AudioBufferList *ioData)     
    // Notes: ioData contains buffers (may be more than one!)
    // Fill them up as much as you can. Remember to set the size value in each buffer to match how
    // much data is in the buffer.

    for (int i=0; i < ioData->mNumberBuffers; i++)  // in practice we will only ever have 1 buffer, since audio format is mono
        AudioBuffer buffer = ioData->mBuffers[i];

        // copy temporary buffer data to output buffer
        UInt32 size = min(buffer.mDataByteSize, someObject.anAudioBuffer.mDataByteSize); // dont copy more data then we have, or then fits
        memcpy(buffer.mData, someObject.anAudioBuffer.mData, size);
        buffer.mDataByteSize = size; // indicate how much data we wrote in the buffer

        // uncomment to hear random noise
        /*
        UInt16 *frameBuffer = buffer.mData;
        for (int j = 0; j < inNumberFrames; j++) 
            frameBuffer[j] = arc4random();
        
        */

    

    return noErr;

现在我想播放从someObject.anAudioBuffer 复制的字节到本地变量buffer

我确实注意到这部分代码与播放音频有关

/*
 UInt16 *frameBuffer = buffer.mData;
 for (int j = 0; j < inNumberFrames; j++) 
    frameBuffer[j] = arc4random();
 
*/

现在arc4random 用于播放静态噪音。尽我最大的努力并在整个互联网上搜索,我无法弄清楚如何播放我自己的字节以及这段代码 b/w /* */

例如,这条线的目的是什么?

UInt16 *frameBuffer = buffer.mData;

我如何用我自己的数据填充这个frameBuffer 来播放。

谁能指导我。我有太多时间浪费在这个看似微不足道的问题上。

如果需要,我可以提供更多详细信息。

期待中……

【问题讨论】:

【参考方案1】:

您必须将 mBuffer.mData[0] 指向的内存(或数组)完全填充为 inNumberFrames 个音频样本帧(无论您是否有这些样本可用)。您可以在噪声生成器中执行此操作,而不是在您的 memcopy 代码中。

同样保持 mDataByteSize 不变,因为它是回调的输入,而不是输入输出。音频回调是一种需求,而不是可选的请求。

【讨论】:

我的源数据填写在someObject.anAudioBuffersomeObject.anAudioBuffer你能指导我如何完成填写任务,即填写frameBuffer[j] 与您在 for 循环中所做的相同,除了使用来自 someObject 而不是 rnd() 的数据。 对不起,如果我听起来太新手,但我收集到你在循环中建议这个 frameBuffer[j] = someObject.anAudioBuffer.mData 如果是这样的话,我仍然不成功 您是否要复制 = ...mData[j] 中的样本? as frameBuffer = buffer.mData; 所以我们需要在 frameBuffer[j] 中写入音频数据,不是吗?我在someObject.anAudioBuffer.mData 中有我的数据作为字节【参考方案2】:

所以我找到了答案

这很简单,但我不知道读取 C 指针数组。我所要做的就是:

 UInt16 *frameBuffer = buffer.mData;
 for (int j = 0; j < inNumberFrames; j++) 
    frameBuffer[j] = *(frameBuffer + j);
 

虽然这个UInt16 *frameBuffer = buffer.mData; 使frameBuffer 指向buffer.mData 的起始索引,但以下

*(frameBuffer + j);是C读取next指针的方式。

在写完frameBuffer[j] = *(frameBuffer + j); 之后,我的流中的音频播放起来就像一个魅力。

很高兴知道这是否对其他人也有帮助。

从 here 找到 C 指针数组信息

【讨论】:

确实有帮助。起初对我来说没有意义,仍然不清楚发生了什么以及我是如何让它工作的。对我来说,当我把它切换到这个时它起作用了。帧缓冲[j] = 帧缓冲[+j];谢谢!

以上是关于在 AudioUnit 播放回调中从 AudioBuffer->mdata 播放音频的主要内容,如果未能解决你的问题,请参考以下文章

启动 AVAssetReader 停止对远程 I/O AudioUnit 的回调

AudioUnit播放PCM问题

如何使用 AudioUnit (iOS) 播放信号?

AudioUnit Render 回调中的 Objective-C/Swift 用法

将 AudioUnit 回调与 NSOutputStream 同步

MacOS Catalina 10.15.7 AudioUnit 麦克风通知回调未调用