How do I connect an AudioFilePlayer AudioUnit to a

2020-02-26 10:25发布

I am trying to connect an AudioFilePlayer AudioUnit to an AU3DMixerEmbedded Audio Unit, but I'm having no success.

Here's what I'm doing:

  1. create an AUGraph with NewAUGraph()

  2. Open the graph

  3. Initalize the graph

  4. Add 3 nodes:

    • outputNode: kAudioUnitSubType_RemoteIO
    • mixerNode: kAudioUnitSubType_AU3DMixerEmbedded
    • filePlayerNode: kAudioUnitSubType_AudioFilePlayer
  5. Connect the nodes:

    • filePlayerNode -> mixerNode
    • mixerNode -> outputNode
  6. Configure the filePlayer Audio Unit to play the required file

  7. Start the graph

This doesn't work: it balks at AUGraphInitialize with error 10868 (kAudioUnitErr_FormatNotSupported). I think the problem is due to audio format mismatch between the filePlayer and the mixer. I think this because: - If I comment out connecting the filePlayerNode to the mixerNode (AUGraphConnectNodeInput(_graph, filePlayerNode, 0, mixerNode, 0)) and comment out step 6 then no errors are reported. - If I replace step 3 with connecting the filePlayerNode directly to the outputNode (AUGraphConnectNodeInput(_graph, filePlayerNode, 0, outputNode, 0)) then the audio plays.

What steps am I missing in connecting the filePlayerNode to the mixerNode?

Here's the code in full. It's based on Apple's sample code and other samples I've found from the interwebs. (AUGraphStart is called latter):

- (id)init
{
    self = [super init];
    if (self != nil)
    {
        {
            //create a new AUGraph
            CheckError(NewAUGraph(&_graph), "NewAUGraph failed");        
            // opening the graph opens all contained audio units but does not allocate any resources yet            
            CheckError(AUGraphOpen(_graph), "AUGraphOpen failed");                
            // now initialize the graph (causes resources to be allocated) 
            CheckError(AUGraphInitialize(_graph), "AUGraphInitialize failed");                    
        }

        AUNode outputNode;
        {
            AudioComponentDescription outputAudioDesc = {0};
            outputAudioDesc.componentManufacturer = kAudioUnitManufacturer_Apple;            
            outputAudioDesc.componentType = kAudioUnitType_Output;
            outputAudioDesc.componentSubType = kAudioUnitSubType_RemoteIO;
            // adds a node with above description to the graph
            CheckError(AUGraphAddNode(_graph, &outputAudioDesc, &outputNode), "AUGraphAddNode[kAudioUnitSubType_DefaultOutput] failed");
        }

        AUNode mixerNode;
        {
            AudioComponentDescription mixerAudioDesc = {0};
            mixerAudioDesc.componentManufacturer = kAudioUnitManufacturer_Apple;                                
            mixerAudioDesc.componentType = kAudioUnitType_Mixer;
            mixerAudioDesc.componentSubType = kAudioUnitSubType_AU3DMixerEmbedded;
            mixerAudioDesc.componentFlags = 0;
            mixerAudioDesc.componentFlagsMask = 0;
            // adds a node with above description to the graph
            CheckError(AUGraphAddNode(_graph, &mixerAudioDesc, &mixerNode), "AUGraphAddNode[kAudioUnitSubType_AU3DMixerEmbedded] failed");            
        }

        AUNode filePlayerNode;            
        {
            AudioComponentDescription fileplayerAudioDesc = {0};            
            fileplayerAudioDesc.componentType = kAudioUnitType_Generator;
            fileplayerAudioDesc.componentSubType = kAudioUnitSubType_AudioFilePlayer;
            fileplayerAudioDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
            // adds a node with above description to the graph
            CheckError(AUGraphAddNode(_graph, &fileplayerAudioDesc, &filePlayerNode), "AUGraphAddNode[kAudioUnitSubType_AudioFilePlayer] failed");
        }

        //Connect the nodes
        {
            // connect the output source of the file player AU to the input source of the output node            
//            CheckError(AUGraphConnectNodeInput(_graph, filePlayerNode, 0, outputNode, 0), "AUGraphConnectNodeInput");                        

            CheckError(AUGraphConnectNodeInput(_graph, filePlayerNode, 0, mixerNode, 0), "AUGraphConnectNodeInput");
            CheckError(AUGraphConnectNodeInput(_graph, mixerNode, 0, outputNode, 0), "AUGraphConnectNodeInput");                                    
        }



        // configure the file player
        // tell the file player unit to load the file we want to play
        {
            //?????
            AudioStreamBasicDescription inputFormat; // input file's data stream description
            AudioFileID inputFile; // reference to your input file            

            // open the input audio file and store the AU ref in _player
            CFURLRef songURL = (__bridge CFURLRef)[[NSBundle mainBundle] URLForResource:@"monoVoice" withExtension:@"aif"];
            CheckError(AudioFileOpenURL(songURL, kAudioFileReadPermission, 0, &inputFile), "AudioFileOpenURL failed");

            //create an empty MyAUGraphPlayer struct
            AudioUnit fileAU;

            // get the reference to the AudioUnit object for the file player graph node
            CheckError(AUGraphNodeInfo(_graph, filePlayerNode, NULL, &fileAU), "AUGraphNodeInfo failed");

            // get and store the audio data format from the file
            UInt32 propSize = sizeof(inputFormat);
            CheckError(AudioFileGetProperty(inputFile, kAudioFilePropertyDataFormat, &propSize, &inputFormat), "couldn't get file's data format");            

            CheckError(AudioUnitSetProperty(fileAU, kAudioUnitProperty_ScheduledFileIDs, kAudioUnitScope_Global, 0, &(inputFile), sizeof((inputFile))), "AudioUnitSetProperty[kAudioUnitProperty_ScheduledFileIDs] failed");

            UInt64 nPackets;
            UInt32 propsize = sizeof(nPackets);
            CheckError(AudioFileGetProperty(inputFile, kAudioFilePropertyAudioDataPacketCount, &propsize, &nPackets), "AudioFileGetProperty[kAudioFilePropertyAudioDataPacketCount] failed");

            // tell the file player AU to play the entire file
            ScheduledAudioFileRegion rgn;
            memset (&rgn.mTimeStamp, 0, sizeof(rgn.mTimeStamp));
            rgn.mTimeStamp.mFlags = kAudioTimeStampSampleTimeValid;
            rgn.mTimeStamp.mSampleTime = 0;
            rgn.mCompletionProc = NULL;
            rgn.mCompletionProcUserData = NULL;
            rgn.mAudioFile = inputFile;
            rgn.mLoopCount = 1;
            rgn.mStartFrame = 0;
            rgn.mFramesToPlay = nPackets * inputFormat.mFramesPerPacket;

            CheckError(AudioUnitSetProperty(fileAU, kAudioUnitProperty_ScheduledFileRegion, kAudioUnitScope_Global, 0,&rgn, sizeof(rgn)), "AudioUnitSetProperty[kAudioUnitProperty_ScheduledFileRegion] failed");

            // prime the file player AU with default values
            UInt32 defaultVal = 0;
            CheckError(AudioUnitSetProperty(fileAU, kAudioUnitProperty_ScheduledFilePrime, kAudioUnitScope_Global, 0, &defaultVal, sizeof(defaultVal)), "AudioUnitSetProperty[kAudioUnitProperty_ScheduledFilePrime] failed");

            // tell the file player AU when to start playing (-1 sample time means next render cycle)
            AudioTimeStamp startTime;
            memset (&startTime, 0, sizeof(startTime));
            startTime.mFlags = kAudioTimeStampSampleTimeValid;
            startTime.mSampleTime = -1;
            CheckError(AudioUnitSetProperty(fileAU, kAudioUnitProperty_ScheduleStartTimeStamp, kAudioUnitScope_Global, 0, &startTime, sizeof(startTime)), "AudioUnitSetProperty[kAudioUnitProperty_ScheduleStartTimeStamp]");

            // file duration
            //double duration = (nPackets * _player.inputFormat.mFramesPerPacket) / _player.inputFormat.mSampleRate;
        }            


    }
    return self;
}

2条回答
劫难
2楼-- · 2020-02-26 10:52

I don't see in your code where you set the appropriate kAudioUnitProperty_StreamFormat for the audio units. You will also have to check the error result codes to see if the stream format setting you choose is actually supported by the audio unit being configured. If not, try another format.

查看更多
叼着烟拽天下
3楼-- · 2020-02-26 10:58

(AUGraphConnectNodeInput(_graph, filePlayerNode, 0, mixerNode, 0)) (AUGraphConnectNodeInput(_graph, mixerNode, 0, outputNode, 0))

Try doing this way if it can help.Just for information the left node is input in the right node. so in first line the player node is input to the mixer node, now mixer node contains both player and mixer so add mixer node to output node.

查看更多
登录 后发表回答