音频单元渲染回调问题(回调未被调用)

3

我目前有一个简单的需求,即编写一个iOS应用程序,使用AudioUnits从音频文件读取并输出到扬声器。不使用高级API的原因是,在某些时候,我需要处理从音频文件传出的样本,并最终将其发送到网络上。

我已经有一个可以工作的代码,它可以读取音频文件并播放到扬声器中。唯一的问题是,回调函数没有起作用。回调函数从未被调用,也没有收到任何注册时的错误提示。非常感谢您的帮助(我是Core Audio的初学者,这是我在stackoverflow上的第一个问题,因此请原谅任何基础性的错误/疏忽)。我用于初始化图形的代码片段已附上。

void createMyAUGraph (MyAUGraphPlayerST *player) {
    // Create a new AUGraph

    CheckError(NewAUGraph(&player->graph), "New AUGraph failed");

    // Generate description for output

    AudioComponentDescription outputcd = {0};
    outputcd.componentType = kAudioUnitType_Output;
    outputcd.componentSubType = kAudioUnitSubType_RemoteIO;
    outputcd.componentManufacturer = kAudioUnitManufacturer_Apple;
    outputcd.componentFlags = 0;
    outputcd.componentFlagsMask = 0;

    // Add new node

    AUNode outputNode;
    CheckError(AUGraphAddNode(player->graph, &outputcd, &outputNode), "Add output node failed");

    // Node for file player

    AudioComponentDescription fileplayercd = {0};
    fileplayercd.componentType = kAudioUnitType_Generator;
    fileplayercd.componentSubType = kAudioUnitSubType_AudioFilePlayer;
    fileplayercd.componentManufacturer = kAudioUnitManufacturer_Apple;

    // Add new node

    AUNode fileNode;
    CheckError(AUGraphAddNode(player->graph, &fileplayercd, &fileNode), "Add file node failed");

    // Open graph

    CheckError(AUGraphOpen(player->graph), "Graph open failed");

    // Retrive AudioUnit

    CheckError(AUGraphNodeInfo(player->graph, outputNode, NULL, &player->outputAU), "file unit retrive failed");
    CheckError(AUGraphNodeInfo(player->graph, fileNode, NULL, &player->fileAU), "file unit retrive failed");

    // connect nodes

    CheckError(AUGraphConnectNodeInput(player->graph, fileNode, 0, outputNode, 0), "failed to connect nodes");

    // some other setup

    UInt32 flag = 1;
    CheckError(AudioUnitSetProperty(player->outputAU,
                                      kAudioOutputUnitProperty_EnableIO,
                                      kAudioUnitScope_Output,
                                      0,
                                      &flag,
                                      sizeof (flag)), "Set io property failed");

    // Register render callback

    AURenderCallbackStruct output_cb;
    output_cb.inputProc = recording_cb;
    output_cb.inputProcRefCon = player;
    CheckError(AudioUnitSetProperty(player->outputAU, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, 0, &output_cb, sizeof (output_cb)), "callback register failed");

    // initialize graph

    CheckError(AUGraphInitialize(player->graph), "graph initialization failed");
}

渲染回调在哪里? - matt
你的音频会话类别是什么? - matt
嗨,马特,我正在尝试在没有AudioSession的情况下使用AudioUnits。我的理解是,从我阅读的一些文档中得知,它们可以独立使用。音频文件的读取和播放按预期工作,但我无法访问样本。我需要设置AudioSession才能使回调起作用吗?渲染回调未被调用,因此我没有在此处包含代码片段。 - Ramakant
1个回答

1

你告诉图形连接你的RemoteIO输入到文件播放器节点,而不是连接到你的渲染回调。然后你初始化了这个图形,它覆盖了你的渲染属性。

如果你想从文件中提取样本进行处理,你的处理函数或渲染回调将需要这样做,而不是从播放器输出到RemoteIO输入的连接。所以不要让图形建立那个连接。

更新后的解答:

在任何近期的iOS版本中,你需要首先使用音频会话API来请求麦克风隐私权限,然后才能启动音频单元,否则你只会从麦克风得到沉默。

要使用音频单元同时记录和播放,试着在RemoteIO的输出和输入上都放置回调函数,然后使用循环缓冲区在两个回调函数之间传递样本数据。在一个或两个回调函数内部,可以根据需要记录或修改样本。请确保在音频上下文内遵守实时限制(无锁或内存管理等)。


你确定要覆盖渲染属性吗?我参考的大多数示例,包括苹果的iPhoneMixerEQGraphTest,似乎都是连接节点,设置渲染回调,然后初始化图形。在代码(iPhoneMixerEQGraphTest应用程序)中的注释写道“//现在我们已经设置好了一切,我们可以初始化图形,这也将验证连接”,同时初始化图形。我需要在设备扬声器上播放来自音频文件的数据包,因此需要从文件到RemoteIO进行连接。 - Ramakant
但与此同时,我也希望通过渲染回调来访问数据包,以便处理并将其发送到网络上。这部分还没有生效,我无法理解在哪里设置回调才能按预期工作。 - Ramakant
我在这个问题上也遇到了同样的困扰,而且我不确定@hotpaw2在这里说了什么。 - AlexW.H.B.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接