ios Core audio: AudioFilePlayer Unit render callback

岁酱吖の 提交于 2019-12-12 03:38:02

问题


I am trying to create a render callback for my AudioFilePlayer Unit.
I created two audio units:

static AudioComponentInstance audioUnit;   // AudioFilePlayer
static AudioComponentInstance rioUnit;     // RemoteIO Unit

Audio units init code:

AudioComponentDescription filePlayerDesc;
filePlayerDesc.componentType = kAudioUnitType_Generator;
filePlayerDesc.componentSubType = kAudioUnitSubType_AudioFilePlayer;
filePlayerDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
filePlayerDesc.componentFlags = 0;
filePlayerDesc.componentFlagsMask = 0;

AudioComponent filePlayerComponent = AudioComponentFindNext(NULL, &filePlayerDesc);

if(filePlayerComponent == NULL) printf("Can not get component for AudioPlayer Unit");

CheckError(AudioComponentInstanceNew(filePlayerComponent, &audioUnit), "error AudioComponentInstanceNew[filePlayerComonent]");

AudioComponentDescription desc;
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_RemoteIO;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;

AudioComponent comp = AudioComponentFindNext(NULL, &desc);

if(comp == NULL) printf("Can not get component for RIO Unit");

CheckError(AudioComponentInstanceNew(comp, &rioUnit), "error AudioComponentInstanceNew[RIO component]");

Audio Units connection:

AudioUnitConnection connection;
connection.sourceAudioUnit    = audioUnit;
connection.sourceOutputNumber = 0;
connection.destInputNumber    = 0;
CheckError(AudioUnitSetProperty(rioUnit, kAudioUnitProperty_MakeConnection, kAudioUnitScope_Input, 0, &connection, sizeof(connection)), "error making connection");

Then audio file playback configuration, using kAudioUnitProperty_ScheduledFileRegion

NSURL *playerFile = [[NSBundle mainBundle] URLForResource:@"long" withExtension:@"wav"];

AudioFileID audioFileID;

CheckError(AudioFileOpenURL((__bridge CFURLRef)playerFile, kAudioFileReadPermission, 0, &audioFileID), "error AudioFileOpenURL");

// Determine file properties
UInt64 packetCount;
UInt32 size = sizeof(packetCount);
CheckError(AudioFileGetProperty(audioFileID, kAudioFilePropertyAudioDataPacketCount, &size, &packetCount),
                "AudioFileGetProperty(kAudioFilePropertyAudioDataPacketCount)");

AudioStreamBasicDescription dataFormat;
size = sizeof(dataFormat);
CheckError(AudioFileGetProperty(audioFileID, kAudioFilePropertyDataFormat, &size, &dataFormat),
                "AudioFileGetProperty(kAudioFilePropertyDataFormat)");

CheckError(AudioUnitInitialize(audioUnit), "error AudioUnitInitialize");

// Set the file to play
CheckError(AudioUnitSetProperty(audioUnit, kAudioUnitProperty_ScheduledFileIDs, kAudioUnitScope_Global, 0, &audioFileID, sizeof(audioFileID)),
                "AudioUnitSetProperty(kAudioUnitProperty_ScheduledFileIDs)");

// Assign the region to play
ScheduledAudioFileRegion region;
memset (&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;
NSLog(@"Frames to play: %u", (unsigned int)region.mFramesToPlay);
CheckError(AudioUnitSetProperty(audioUnit, kAudioUnitProperty_ScheduledFileRegion, kAudioUnitScope_Global, 0, &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, &defaultNumberOfFrames, sizeof(defaultNumberOfFrames)),
                "AudioUnitSetProperty(kAudioUnitProperty_ScheduledFilePrime)");


AudioTimeStamp startTime;
memset (&startTime, 0, sizeof(startTime));
startTime.mFlags = kAudioTimeStampSampleTimeValid;
startTime.mSampleTime = -1;
CheckError(AudioUnitSetProperty(audioUnit, kAudioUnitProperty_ScheduleStartTimeStamp, kAudioUnitScope_Global, 0, &startTime, sizeof(startTime)),
           "AudioUnitSetProperty(kAudioUnitProperty_ScheduleStartTimeStamp)");

CheckError(AudioUnitInitialize(rioUnit), "error AudioUnitInitialize");

With this code sound is playing fine. What I am trying to accomplish is to add render callback to AudioFilePlayer Unit to modify samples, before sound reaches RemoteIO Unit.
This code added before AudioUnitInitialize(rioUnit) is called:

AURenderCallbackStruct callbackStruct;
callbackStruct.inputProc = MyCallback;
callbackStruct.inputProcRefCon = (__bridge void * _Nullable)(self);
CheckError(AudioUnitSetProperty(audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, 0, &callbackStruct, sizeof(callbackStruct)), "error AudioUnitSetProperty[kAudioUnitProperty_setRenderCallback]");

This is MyCallback function:

static OSStatus MyCallback(void *inRefCon,
                             AudioUnitRenderActionFlags *ioFlags,
                             const AudioTimeStamp *inTimeStamp,
                             UInt32 inBusNumber,
                             UInt32 inNumberFrames,
                             AudioBufferList *ioData){
printf("callback");

return noErr;
}

I got error -10877(kAudioUnitErr_InvalidElement) during code compilation on the line where I set kAudioUnitProperty_SetRenderCallback property.
What is the right way to set this up?

来源:https://stackoverflow.com/questions/37870051/ios-core-audio-audiofileplayer-unit-render-callback

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!