How do I connect an AudioFilePlayer AudioUnit to a 3DMixer?
Asked Answered
S

2

7

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;
}
Scabies answered 24/4, 2012 at 15:21 Comment(4)
Love your use of {...} blocks to wrap the intermediate variables and organise the code...Ariminum
Long shot, but I'm having the same issue. What was the acceptable format in the end?Weinstein
thanks for the code. :). btw it works for me. I just added AUGraphStart(graph)Prolongate
what is {...} block concept called? never seen this before!!Prolongate
E
3

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.

Escort answered 24/4, 2012 at 18:52 Comment(0)
I
0

(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.

Iridize answered 4/1, 2013 at 7:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.