发布 iOS 音频单元

Posted

技术标签:

【中文标题】发布 iOS 音频单元【英文标题】:Publishing iOS Audio Unit 【发布时间】:2016-02-18 14:49:39 【问题描述】:

我正在尝试制作一个应用程序间音频 ios 应用程序,看起来我在使用 AudioOutputUnitPublish 方法时遇到了问题。方法如下:

- (void)publishOutputAudioUnit 
    AudioComponentDescription desc = kAudioUnitType_RemoteInstrument, 
                                     'iasp','rfoo', 0, 1;
    OSStatus result = AudioOutputUnitPublish(&desc, CFSTR("MyMusicApp"), 
                                             1, outputUnit);
    if (result != noErr) 
        NSLog(@"AudioOutputUnitPublish instrument result: %d", (int)result);

    desc =  kAudioUnitType_RemoteGenerator, 'iasp', 'rfoo', 0, 1 ;
    result = AudioOutputUnitPublish(&desc, CFSTR("MyMusicApp"), 1, outputUnit);
    if (result != noErr) 
        NSLog(@"AudioOutputUnitPublish generator result: %d", (int)result);

这是我的 plist 信息:

<key>AudioComponents</key>
<array>
    <dict>
        <key>manufacturer</key>
        <string>rfoo</string>
        <key>name</key>
        <string>MyMusicApp</string>
        <key>subtype</key>
        <string>iasp</string>
        <key>type</key>
        <string>aurg</string>
        <key>version</key>
        <integer>1</integer>
    </dict>
    <dict>
        <key>manufacturer</key>
        <string>rfoo</string>
        <key>name</key>
        <string>MyMusicApp</string>
        <key>subtype</key>
        <string>iasp</string>
        <key>type</key>
        <string>auri</string>
        <key>version</key>
        <integer>1</integer>
    </dict>
</array>

这是我得到的结果:

AudioOutputUnitPublish instrument result: -50
AudioOutputUnitPublish generator result: -50

我知道 OSStatus 代码 -50 表示存在无效参数...但我似乎无法确定哪个参数无效。谁能帮我在这里调试?谢谢!


编辑:

只是想发布更多代码,以便其他人可以帮助我更多:

我有两个音频单元,希望还有第三个 - MIDISynth(目前处于非活动状态)、MultiChannelMixer 和 RemoteIO 音频单元。我有一个渲染回调附加到混音器音频单元。我猜我在我的 AUGraph 中连接了一些错误(我见过的所有示例都没有将音频渲染回调附加到音频单元,所以这可能是我做错的地方)。希望有人能发现我做错了什么!

代码如下:

- (AUGraph)createAUGraphWithSynth:(AudioUnit *)sUnit mixUnit:(AudioUnit *)mixUnit remoteUnit:(AudioUnit *)remUnit 
    // Initializations
    AUGraph graph = 0;
    OSStatus result = noErr;
    // Create graph nodes
    AUNode mixerNode, ioNode;

    // Create Component Descriptor
    AudioComponentDescription cd;
    cd.componentManufacturer    = kAudioUnitManufacturer_Apple;
    cd.componentFlags           = 0;
    cd.componentFlagsMask       = 0;

    // Init AUGraph
    Check(result = NewAUGraph(&graph));

    // Init Mixer unit
    cd.componentType    = kAudioUnitType_Mixer;
    cd.componentSubType = kAudioUnitSubType_MultiChannelMixer;
    Check(result = AUGraphAddNode(graph, &cd, &mixerNode));

    // Init io Unit
    cd.componentType    = kAudioUnitType_Output;
    cd.componentSubType = kAudioUnitSubType_RemoteIO;
    Check(result = AUGraphAddNode(graph, &cd, &ioNode));

    // Open AUGraph
    Check(AUGraphOpen(graph));

    // Get mixer unit
    Check(AUGraphNodeInfo(graph, mixerNode, NULL, mixUnit));

    // Get io unit
    Check(AUGraphNodeInfo(graph, ioNode, NULL, remUnit));

    // Set number of input busses
    UInt32 numBuses = 1;
    UInt32 size = sizeof(numBuses);
    Check(AudioUnitSetProperty(*mixUnit,
                               kAudioUnitProperty_ElementCount,
                               kAudioUnitScope_Input,
                               0, &numBuses, size));

    AudioStreamBasicDescription desc;
    const int four_bytes_per_float = 4;
    const int eight_bits_per_byte = 8;

    for (int i = 0; i < numBuses; ++i) 
        AURenderCallbackStruct callbackStruct;
        callbackStruct.inputProc        = outputCallback;
        callbackStruct.inputProcRefCon  = (__bridge void *)self;
    
        Check(AUGraphSetNodeInputCallback(graph, mixerNode, i, &callbackStruct));

        UInt32 size = sizeof(desc);
        Check(AudioUnitGetProperty(*mixUnit,
                                   kAudioUnitProperty_StreamFormat,
                                   kAudioUnitScope_Input,
                                   0, &desc, &size));
    
        memset(&desc, 0, sizeof(desc));
    

        desc.mSampleRate        = SAMPLE_RATE;
        desc.mFormatID          = kAudioFormatLinearPCM;
        desc.mFormatFlags       = kAudioFormatFlagsNativeFloatPacked 
                                | kAudioFormatFlagIsNonInterleaved;
        desc.mBytesPerPacket    = four_bytes_per_float;
        desc.mFramesPerPacket   = 1;
        desc.mBytesPerFrame     = four_bytes_per_float;
        desc.mBitsPerChannel    = four_bytes_per_float * eight_bits_per_byte;
        desc.mChannelsPerFrame  = 2;
        Check(AudioUnitSetProperty(*remUnit,
                                   kAudioUnitProperty_StreamFormat,
                                   kAudioUnitScope_Input,
                                   0, &desc, sizeof(desc)));

    

    Check(AudioUnitSetProperty(*mixUnit,
                               kAudioUnitProperty_StreamFormat,
                               kAudioUnitScope_Output,
                               0, &desc, sizeof(desc)));

    Check(AudioUnitGetProperty(*mixUnit,
                               kAudioUnitProperty_StreamFormat,
                               kAudioUnitScope_Output,
                               0, &desc, &size));

    memset(&desc, 0, sizeof(desc));

    desc.mSampleRate        = SAMPLE_RATE;
    desc.mFormatID          = kAudioFormatLinearPCM;
    desc.mFormatFlags       = kAudioFormatFlagsNativeFloatPacked 
                            | kAudioFormatFlagIsNonInterleaved;
    desc.mBytesPerPacket    = four_bytes_per_float;
    desc.mFramesPerPacket   = 1;
    desc.mBytesPerFrame     = four_bytes_per_float;
    desc.mBitsPerChannel    = four_bytes_per_float * eight_bits_per_byte;
    desc.mChannelsPerFrame  = 2;
     
    Check(AudioUnitSetProperty(*mixUnit,
                               kAudioUnitProperty_StreamFormat,
                               kAudioUnitScope_Output,
                               0, &desc, sizeof(desc)));

    // Must configure remote io unit:
    Check(AudioUnitSetProperty(*remUnit,
                               kAudioUnitProperty_StreamFormat,
                               kAudioUnitScope_Output,
                               1, &desc, sizeof(desc)));

     // Connect nodes (synth->output)
     Check(AUGraphConnectNodeInput(graph, mixerNode, 0, ioNode, 0));

     return graph;
 

【问题讨论】:

【参考方案1】:

AudioComponentDescription 中的最后一个字段 componentFlagsMask 应该是 0,而不是 1。(请参阅 documentation。看起来至少有一个 tutorial 将该字段误识别为组件版本。)

我不确定这是否是问题的唯一原因。其余代码看起来不错,但我想项目中的其他地方可能存在问题,例如。与能力。

【讨论】:

您好 walkytalky,感谢您回复我。我将它设置为 0,但我仍然收到相同的 -50 错误 :( - 我已经为音频启用了应用间音频和背景模式...还有什么我遗漏的吗? 在这种情况下,我猜outputUnit 没有正确初始化。这是否意味着通过图形创建方法中的remUnit 参数进行设置?如果你一步一步来,那真的会发生吗? 是的,我好像贴错了,等我修好后再回复你... 我显然没有所有设置 - 我没有在我的 plist 中设置捆绑显示名称。我花了很长时间才知道,但现在它正在出版!感谢您的帮助。

以上是关于发布 iOS 音频单元的主要内容,如果未能解决你的问题,请参考以下文章

iOS 11 + Xcode 9.0 = 无音频单元

直接调用音频单元而不是回调 iOS

在IOS核心音频中,如何找到文件播放器音频单元的真实当前播放头位置?

如何消除来自使用 iOS 中音频单元的套接字的音频中的噪音?

iOS 音频单元:啥时候需要使用 AUGraph?

AEC ios 多音频单元图