核心音频:文件播放渲染回调函数 [英] Core audio: file playback render callback function

查看:966
本文介绍了核心音频:文件播放渲染回调函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 RemoteIO音频单元在我的应用程序中使用 kAudioUnitProperty_ScheduledFileIDs 播放音频。
音频文件采用 PCM 格式。如何为这种情况实现render回调函数,以便我可以手动修改缓冲区样本?

这是我的代码:

I am using RemoteIO Audio Unit for audio playback in my app with kAudioUnitProperty_ScheduledFileIDs. Audio files are in PCM format. How can I implement a render callback function for this case, so I could manually modify buffer samples?
Here is my 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, &desc);

CheckError(AudioComponentInstanceNew(comp, &audioUnit), "error AudioComponentInstanceNew");


NSURL *playerFile = [[NSBundle mainBundle] URLForResource:@"short" 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)");

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

AURenderCallbackStruct callbackStruct;
callbackStruct.inputProc = MyCallback;
callbackStruct.inputProcRefCon = (__bridge void * _Nullable)(self);

CheckError(AudioUnitSetProperty(audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &callbackStruct, sizeof(callbackStruct)), "error AudioUnitSetProperty[kAudioUnitProperty_setRenderCallback]");

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

回调函数:

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

    printf("my callback");  
    return noErr;
}

音频单元按下按钮时开始播放: / p>

Audio Unit start playback on button press:

- (IBAction)playSound:(id)sender {

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

}

此代码在使用 kAudioUnitErr_InvalidProperty ( - 10879)错误。目标是修改从 AudioFileID 读取的缓冲区样本,并将结果发送给扬声器。

This code fails during compiling with kAudioUnitErr_InvalidProperty(-10879) error. The goal is to modify buffer samples that has been read from the AudioFileID and send the result to the speakers.

推荐答案

看到你刚刚熟悉核心音频,我建议你首先让你的remoteIO回调独立于你的文件播放器工作。

Seeing as how you are just getting familiar with core audio, I suggest you first get your remoteIO callback working independently of your file player. Just remove all of your file player related code and try to get that working first.

然后,一旦你有了这个工作,就继续合并你的文件播放器。

Then, once you have that working, move on to incorporating your file player.

据我所见,这是错误的,我想你是混淆音频文件服务API与音频单元。这个API用于读取一个文件到一个缓冲区,你可以手动输入到remoteIO,如果你想去这个路由,使用扩展音频文件服务API,它更容易。 kAudioUnitProperty_ScheduledFileRegion 属性应该在文件播放器音频单元上调用。要获得其中一个,您需要创建它与remmoteIO相同的方式,除了AudioComponentDescription的componentSubType和componentType kAudioUnitSubType_AudioFilePlayer kAudioUnitType_Generator 。然后,一旦你有了这个单元,你将需要使用 kAudioUnitProperty_MakeConnection 属性连接到remoteIO。

As far as what I can see that's wrong, I think you are confusing the Audio File Services API with an audio unit. This API is used to read a file into a buffer which you would manually feed to to remoteIO, if you do want to go this route, use the Extended Audio File Services API, it's a LOT easier. The kAudioUnitProperty_ScheduledFileRegion property is supposed to be called on a file player audio unit. To get one of those, you would need to create it the same way as your remmoteIO with the exception that AudioComponentDescription's componentSubType and componentType are kAudioUnitSubType_AudioFilePlayer and kAudioUnitType_Generator respectively. Then, once you have that unit you would need to connect it to the remoteIO using the kAudioUnitProperty_MakeConnection property.

但是认真,开始只是让你的remoteIO回调工作,然后尝试做一个文件播放器音频单元并连接它(没有回调),然后从那里去。

But seriously, start with just getting your remoteIO callback working, then try making a file player audio unit and connecting it (without the callback), then go from there.

独立地提出关于每个步骤的特定问题,发布您尝试过的代码不起作用,您将获得大量的帮助。

Ask very specific questions about each of these steps independently, posting code you have tried that's not working, and you'll get a ton of help.

这篇关于核心音频:文件播放渲染回调函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆