ios Core音频:AudioFilePlayer单元渲染回调

时间:2016-06-16 22:00:05

标签: ios callback core-audio audiounit

我正在尝试为 AudioFilePlayer 单元创建渲染回调。
我创建了两个音频单元:

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

音频单元初始化代码:

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]");

音频单元连接:

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");

然后使用 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");

使用此代码声音播放正常。我想要完成的是在声音到达RemoteIO Unit之前向 AudioFilePlayer 单元添加渲染回调以修改样本。
AudioUnitInitialize(rioUnit)之前添加此代码:

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]");

这是MyCallback功能:

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

return noErr;
}

我在设置 kAudioUnitProperty_SetRenderCallback 属性的行上进行代码编译时遇到错误 -10877 kAudioUnitErr_InvalidElement )。
设置它的正确方法是什么?

0 个答案:

没有答案