title: Core audio: file playback render callback function
body: <p>I am using <strong>RemoteIO Audio Unit</strong> for audio playback in my app with <code>kAudioUnitProperty_ScheduledFileIDs</code>.
  Audio files are in <strong>PCM</strong> format. How can I implement a render callback function for this case, so I could manually modify buffer samples?<br>
  <em>Here is my code:</em><br></p>
  
  <pre><code>static AudioComponentInstance audioUnit;
  
  AudioComponentDescription desc;
  
  desc.componentType = kAudioUnitType_Output;
  desc.componentSubType = kAudioUnitSubType_RemoteIO;
  desc.componentManufacturer = kAudioUnitManufacturer_Apple;
  desc.componentFlags = 0;
  desc.componentFlagsMask = 0;
  
  AudioComponent comp = AudioComponentFindNext(NULL, &amp;desc);
  
  CheckError(AudioComponentInstanceNew(comp, &amp;audioUnit), "error AudioComponentInstanceNew");
  
  
  NSURL *playerFile = [[NSBundle mainBundle] URLForResource:@"short" withExtension:@"wav"];
  
  AudioFileID audioFileID;
  
  CheckError(AudioFileOpenURL((__bridge CFURLRef)playerFile, kAudioFileReadPermission, 0, &amp;audioFileID), "error AudioFileOpenURL");
  
  // Determine file properties
  UInt64 packetCount;
  UInt32 size = sizeof(packetCount);
  CheckError(AudioFileGetProperty(audioFileID, kAudioFilePropertyAudioDataPacketCount, &amp;size, &amp;packetCount),
                  "AudioFileGetProperty(kAudioFilePropertyAudioDataPacketCount)");
  
  AudioStreamBasicDescription dataFormat;
  size = sizeof(dataFormat);
  CheckError(AudioFileGetProperty(audioFileID, kAudioFilePropertyDataFormat, &amp;size, &amp;dataFormat),
                  "AudioFileGetProperty(kAudioFilePropertyDataFormat)");
  
  // Assign the region to play
  ScheduledAudioFileRegion region;
  memset (&amp;region.mTimeStamp, 0, sizeof(region.mTimeStamp));
  region.mTimeStamp.mFlags = kAudioTimeStampSampleTimeValid;
  region.mTimeStamp.mSampleTime = 0;
  region.mCompletionProc = NULL;
  region.mCompletionProcUserData = NULL;
  region.mAudioFile = audioFileID;
  region.mLoopCount = 0;
  region.mStartFrame = 0;
  region.mFramesToPlay = (UInt32)packetCount * dataFormat.mFramesPerPacket;
  CheckError(AudioUnitSetProperty(audioUnit, kAudioUnitProperty_ScheduledFileRegion, kAudioUnitScope_Global, 0, &amp;region, sizeof(region)),
                  "AudioUnitSetProperty(kAudioUnitProperty_ScheduledFileRegion)");
  
  // Prime the player by reading some frames from disk
  UInt32 defaultNumberOfFrames = 0;
  CheckError(AudioUnitSetProperty(audioUnit, kAudioUnitProperty_ScheduledFilePrime, kAudioUnitScope_Global, 0, &amp;defaultNumberOfFrames, sizeof(defaultNumberOfFrames)),
                  "AudioUnitSetProperty(kAudioUnitProperty_ScheduledFilePrime)");
  
  AURenderCallbackStruct callbackStruct;
  callbackStruct.inputProc = MyCallback;
  callbackStruct.inputProcRefCon = (__bridge void * _Nullable)(self);
  
  CheckError(AudioUnitSetProperty(audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &amp;callbackStruct, sizeof(callbackStruct)), "error AudioUnitSetProperty[kAudioUnitProperty_setRenderCallback]");
  
  CheckError(AudioUnitInitialize(audioUnit), "error AudioUnitInitialize");
  </code></pre>
  
  <p><em>Callback function:</em></p>
  
  <pre><code>static OSStatus MyCallback(void *inRefCon,
                               AudioUnitRenderActionFlags *ioFlags,
                               const AudioTimeStamp *inTimeStamp,
                               UInt32 inBusNumber,
                               UInt32 inNumberFrames,
                               AudioBufferList *ioData){
  
      printf("my callback");  
      return noErr;
  }
  </code></pre>
  
  <p><em>Audio Unit start playback on button press:</em></p>
  
  <pre><code>- (IBAction)playSound:(id)sender {
  
   CheckError(AudioOutputUnitStart(audioUnit), "error AudioOutputUnitStart");
  
  }
  </code></pre>
  
  <p>This code fails during compiling with <strong>kAudioUnitErr_InvalidProperty</strong>(-10879) error. The goal is to modify buffer samples that has been read from the <strong>AudioFileID</strong> and send the result to the speakers.</p>