Advertisement
cblomert

Audio Units - RemoteIO/MultiChannelMixer

Aug 13th, 2012
80
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //this class takes care of setting up an AudioUnit environment and makes use of RemoteIO and a multiChannelMixer to output 16 bit signed integer 2 channel PCM
  2. //written by Christian Blomert - use freely for whatever ;)
  3. ------------
  4. AudioIO.h
  5. ------------
  6. #import <Foundation/Foundation.h>
  7. #include <AudioToolbox/AudioToolbox.h>
  8. @interface AudioIO : NSObject
  9. {
  10.     AUGraph graph;
  11.     AudioUnit masterMixer;
  12.     AudioUnit output;
  13. }
  14. @property (nonatomic) AUGraph graph;
  15. @property (nonatomic) AudioUnit masterMixer;
  16. @property (nonatomic) AudioUnit output;
  17. @end
  18.  
  19. ------------
  20. AudioIO.m
  21. ------------
  22. #import "AudioIO.h"
  23. @implementation AudioIO
  24. @synthesize output;
  25. @synthesize graph;
  26. @synthesize masterMixer;
  27.  
  28. static OSStatus sampleCallback(void *inRefCon,
  29.                                AudioUnitRenderActionFlags *ioActionFlags,
  30.                                const AudioTimeStamp *inTimeStamp,
  31.                                UInt32 inBusNumber,
  32.                                UInt32 inNumberFrames,
  33.                                AudioBufferList *ioData)
  34. {
  35.     //get a pointer to self
  36.     AudioIO *audio = (AudioIO *)inRefCon;
  37.    
  38.  
  39.     //one buffer for SInt32s - 2 if using floats (one for each channel)
  40.     for (int i = 0 ; i < ioData->mNumberBuffers; i++)
  41.     {
  42.         //get the bufferStruct
  43.         AudioBuffer buffer = ioData->mBuffers[i];
  44.        
  45.         //get the bufferpointer
  46.         UInt32 *frameBuffer = buffer.mData;
  47.        
  48.         //fill the frames
  49.         for (int j = 0; j < inNumberFrames; j++){
  50.             // getPacket returns a 32 bit value, one frame. - 16bit for each channel
  51.             frameBuffer[j] = [audio getPacket];
  52.         }
  53.     }
  54.     return noErr;
  55.    
  56. }
  57.  
  58. static OSStatus outputCallback(void *inRefCon,
  59.                                AudioUnitRenderActionFlags *ioActionFlags,
  60.                                const AudioTimeStamp *inTimeStamp,
  61.                                UInt32 inBusNumber,
  62.                                UInt32 inNumberFrames,
  63.                                AudioBufferList *ioData)
  64. {
  65.    
  66.    //get self
  67.     AudioIO *audio = (AudioIO *)inRefCon;
  68.    OSStatus err = 0;
  69.    
  70.     //render audio using masterMixer unit
  71.     err = AudioUnitRender(audio.masterMixer, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData);
  72.    
  73.    
  74.     if (err != noErr) {
  75.         NSLog(@"erroutputCallback: %ld", err);
  76.     }
  77.     return err;
  78. }
  79.  
  80. void propListener(  void *                  inClientData,
  81.                   AudioSessionPropertyID    inID,
  82.                   UInt32                  inDataSize,
  83.                   const void *            inData)
  84. {
  85.     printf("property listener\n");
  86.     if (inID == kAudioSessionProperty_AudioRouteChange){
  87.     }
  88. }
  89.  
  90. void rioInterruptionListener(void *inClientData, UInt32 inInterruption)
  91. {
  92.     printf("Session interrupted! --- %s ---", inInterruption == kAudioSessionBeginInterruption ? "Begin Interruption" : "End Interruption");
  93.    
  94.     if (inInterruption == kAudioSessionEndInterruption) {
  95.         // make sure we are again the active session
  96.         AudioSessionSetActive(true);
  97.         NSLog(@"end of interruption");
  98.        
  99.         //AudioOutputUnitStart(THIS->audioUnit);
  100.     }
  101.     if (inInterruption == kAudioSessionBeginInterruption) {
  102.         NSLog(@"begin of interruption");
  103.         //AudioOutputUnitStop(THIS->audioUnit);
  104.     }
  105. }
  106.  
  107. //init ------------------------------------------------------------------------ //
  108.  
  109. -(id)init {
  110.    
  111.     self = [super init];
  112.     if (self) {
  113.        
  114.         [self initAudio];
  115.     }
  116.     return self;
  117. }
  118.  
  119.  
  120. -(void)initAudio{
  121.    
  122.    
  123.     // Initialize and configure the audio session, and add an interuption listener
  124.     AudioSessionInitialize(NULL, NULL, rioInterruptionListener, self);
  125.    
  126.     //set the audio category
  127.     UInt32 audioCategory = kAudioSessionCategory_LiveAudio;
  128.     AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(audioCategory), &audioCategory);
  129.    
  130.     UInt32 getAudioCategory = sizeof(audioCategory);
  131.     AudioSessionGetProperty(kAudioSessionProperty_AudioCategory, &getAudioCategory, &getAudioCategory);
  132.    
  133.     if(getAudioCategory == kAudioSessionCategory_LiveAudio){
  134.         NSLog(@"kAudioSessionCategory_LiveAudio");
  135.     }
  136.     else{
  137.         NSLog(@"Could not get kAudioSessionCategory_LiveAudio");
  138.     }
  139.    
  140.    
  141.     //add a property lisistener
  142.     AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange, propListener, self);
  143.    
  144.     //set the buffer size as small as w can
  145.     Float32 preferredBufferSize = 128.0/44100.0;
  146.     AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration, sizeof(preferredBufferSize), &preferredBufferSize);
  147.    
  148.     UInt32 size = sizeof(preferredBufferSize);
  149.     AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareIOBufferDuration, &size,
  150.                             &preferredBufferSize);
  151.     NSLog(@"Buffersize: %f", preferredBufferSize*44100);
  152.    
  153.    
  154.     //set the audio session active
  155.     AudioSessionSetActive(YES);
  156.    
  157.     //the descriptions for the components
  158.     AudioComponentDescription masterDescription, outputDescription;
  159.    
  160.     //the AUNodes
  161.     AUNode masterMixerNode;
  162.     AUNode outputNode;
  163.    
  164.    
  165.     //the graph
  166.     OSErr err = noErr;
  167.     err = NewAUGraph(&graph);
  168.     if (err !=noErr) {
  169.         NSLog(@"Error creating graph: %d", err);
  170.     }
  171.    
  172.     //the output
  173.     outputDescription.componentFlags = 0;
  174.     outputDescription.componentFlagsMask = 0;
  175.     outputDescription.componentType = kAudioUnitType_Output;
  176.     outputDescription.componentSubType = kAudioUnitSubType_RemoteIO;
  177.     outputDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
  178.     err = AUGraphAddNode(graph, &outputDescription, &outputNode);
  179.     if (err !=noErr) {
  180.         NSLog(@"Error creating output node: %d", err);
  181.     }
  182.    
  183.    
  184.     //the master mixer
  185.     masterDescription = 0;
  186.     masterDescription = 0;
  187.     masterDescription = kAudioUnitType_Mixer;
  188.     masterDescription = kAudioUnitSubType_MultiChannelMixer;
  189.     masterDescription = kAudioUnitManufacturer_Apple;
  190.     err = AUGraphAddNode(graph, & masterDescription, &masterMixerNode);
  191.     if (err !=noErr) {
  192.         NSLog(@"Error creating mixer node: %d", err);
  193.     }
  194.    
  195.    
  196.    
  197.     err = AUGraphOpen(graph);
  198.     if (err !=noErr) {
  199.         NSLog(@"Error opening graph: %d", err);
  200.     }
  201.    
  202.    
  203.    
  204.     //get the master mixer info
  205.     err = AUGraphNodeInfo(graph, masterMixerNode, &masterDescription, &masterMixer);
  206.     if (err !=noErr) {
  207.         NSLog(@"masterMixer  doesnt work!!!");
  208.     }
  209.     t
  210.     err = AUGraphNodeInfo(graph, outputNode, &outputDescription, &output);
  211.     if (err !=noErr) {
  212.         NSLog(@"AHA!!!");
  213.     }
  214.    
  215.     // set up the rio unit for playback
  216.     UInt32 oneFlag = 1;
  217.     err =
  218.     AudioUnitSetProperty (output,
  219.                           kAudioOutputUnitProperty_EnableIO,
  220.                           kAudioUnitScope_Output,
  221.                           0,
  222.                           &oneFlag,
  223.                           sizeof(oneFlag));
  224.     if (err != noErr) {
  225.         NSLog(@"Couldn't enable RIO output : %d", err);
  226.     }
  227.    
  228.    
  229.    
  230.    
  231.     // enable rio input
  232.     err = AudioUnitSetProperty(output,
  233.                                kAudioOutputUnitProperty_EnableIO,
  234.                                kAudioUnitScope_Input,
  235.                                1,
  236.                                &oneFlag,
  237.                                sizeof(oneFlag));
  238.     if (err != noErr) {
  239.         NSLog(@"couldn't enable rio input : %d", err);
  240.     }
  241.    
  242.    
  243.     // Set up the mixers input callbacks
  244.     AURenderCallbackStruct sampleCallbackStruct;
  245.     sampleCallbackStruct = sampleCallback;
  246.     sampleCallbackStruct = self;
  247.    
  248.    
  249.         AURenderCallbackStruct masterCallbackStruct;
  250.     masterCallbackStruct.inputProc = outputCallback;
  251.     masterCallbackStruct.inputProcRefCon = self;
  252.    
  253.    
  254.    
  255.    
  256.     //connect nodes to callbacks
  257.    
  258.     //connect outputNode to masterCallbackStruct
  259.     err = AUGraphSetNodeInputCallback(graph, outputNode, 0, &masterCallbackStruct);
  260.     if (err != noErr) {
  261.         NSLog(@"Couldn't connect outputNode output 0 to rio masterCallbackStruct 0 : %d", err);
  262.     }
  263.     //connect mixer input 1 to callbackStruct
  264.     err = AUGraphSetNodeInputCallback(graph, masterMixerNode, 0, & sampleCallbackStruct);
  265.     if (err != noErr) {
  266.         NSLog(@"Error setting masterMixerNode input sampleCallbackStruct A : %d", err);
  267.     }
  268.    
  269.    
  270.     // Describe format
  271.     //SInts
  272.     AudioStreamBasicDescription audioFormat = {0};
  273.     audioFormat.mSampleRate         = 44100.00;
  274.     audioFormat.mFormatID           = kAudioFormatLinearPCM;
  275.     audioFormat.mFormatFlags        = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
  276.     audioFormat.mFramesPerPacket        = 1;
  277.     audioFormat.mChannelsPerFrame       = 2;
  278.     audioFormat.mBitsPerChannel     = 16;
  279.     audioFormat.mBytesPerPacket     = 4;
  280.     audioFormat.mBytesPerFrame      = 4;
  281.    
  282.     /*
  283.      //Floats:
  284.      audioFormat.mSampleRate            = 44100.00;
  285.      audioFormat.mFormatID          = kAudioFormatLinearPCM;
  286.      audioFormat.mFormatFlags       = kAudioFormatFlagIsNonInterleaved | kAudioFormatFlagIsFloat;
  287.      audioFormat.mFramesPerPacket   = 1;
  288.      audioFormat.mChannelsPerFrame  = 2;
  289.      audioFormat.mBitsPerChannel        = 32;
  290.      audioFormat.mBytesPerPacket        = 4;
  291.      audioFormat.mBytesPerFrame     = 4;
  292.      */
  293.    
  294.     //set the rio input properties
  295.     err = AudioUnitSetProperty(output,
  296.                                kAudioUnitProperty_StreamFormat,
  297.                                kAudioUnitScope_Input,
  298.                                0,
  299.                                &audioFormat,
  300.                                sizeof(audioFormat));
  301.     if (err != noErr) {
  302.         NSLog(@"Error setting RIO input property : %d", err);
  303.     }
  304.    
  305.     //set the rio output properties
  306.     err = AudioUnitSetProperty(output,
  307.                                kAudioUnitProperty_StreamFormat,
  308.                                kAudioUnitScope_Output,
  309.                                1,
  310.                                &audioFormat,
  311.                                sizeof(audioFormat));
  312.     if (err != noErr) {
  313.         NSLog(@"Error setting RIO output property : %d", err);
  314.     }
  315.    
  316.     //set the master fader output properties
  317.     err = AudioUnitSetProperty(masterMixer,
  318.                                kAudioUnitProperty_StreamFormat,
  319.                                kAudioUnitScope_Output,
  320.                                0,
  321.                                &audioFormat,
  322.                                sizeof(audioFormat));
  323.     if (err != noErr) {
  324.         NSLog(@"Error setting master output property : %d", err);
  325.     }
  326.    
  327.     //set the master fader input properties
  328.     err = AudioUnitSetProperty(masterMixer,
  329.                                kAudioUnitProperty_StreamFormat,
  330.                                kAudioUnitScope_Input,
  331.                                0,
  332.                                &audioFormat,
  333.                                sizeof(audioFormat));
  334.     if (err != noErr) {
  335.         NSLog(@"Error setting master input1 property : %d", err);
  336.     }
  337.    
  338.    
  339.    
  340.     //initialize Graph
  341.     err = AUGraphInitialize(graph);
  342.     if (err != noErr) {
  343.         NSLog(@"Error initializing graph - error code: %d", err);
  344.     }
  345.    
  346.     CAShow(graph);
  347.    
  348.     err = AUGraphStart(graph);
  349.     if (err != noErr) {
  350.         NSLog(@"Error starting graph. - error code: %d", err);
  351.     }
  352. }
  353. @end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement