如何将AudioFilePlayer AudioUnit连接到3DMixer?
我正尝试将AudioFilePlayer AudioUnit连接到AU3DMixerEmbedded Audio Unit,但我没有成功。如何将AudioFilePlayer AudioUnit连接到3DMixer?
下面是我在做什么:
创建
AUGraph
与NewAUGraph()
打开图形
Initalize图
-
添加三个节点:
- outputNode:
kAudioUnitSubType_RemoteIO
- mixerNode:
kAudioUnitSubType_AU3DMixerEmbedded
- filePlayerNode:
kAudioUnitSubType_AudioFilePlayer
- outputNode:
-
连接节点:
- filePlayerNode - > mixerNode
- mixerNode - > outputNode
配置filePlayer音频单元发挥所需的文件
启动图形
这不起作用:它不太愿意AUGraphInitialize错误10868(kAudioUnitErr_FormatNotSupported)。我认为这个问题是由于filePlayer和调音台之间的音频格式不匹配造成的。我认为这是因为: - 如果我注释掉将filePlayerNode连接到mixerNode(AUGraphConnectNodeInput(_graph, filePlayerNode, 0, mixerNode, 0)
)并注释掉第6步,则不会报告任何错误。 - 如果将filePlayerNode直接连接到outputNode(AUGraphConnectNodeInput(_graph, filePlayerNode, 0, outputNode, 0)
),则替换第3步,然后播放音频。
我在将filePlayerNode连接到mixerNode时缺少哪些步骤?
下面是完整的代码。它基于苹果公司的示例代码和我从互联网上找到的其他样本。 (AUGraphStart
被称为后者):
- (id)init
{
self = [super init];
if (self != nil)
{
{
//create a new AUGraph
CheckError(NewAUGraph(&_graph), "NewAUGraph failed");
// opening the graph opens all contained audio units but does not allocate any resources yet
CheckError(AUGraphOpen(_graph), "AUGraphOpen failed");
// now initialize the graph (causes resources to be allocated)
CheckError(AUGraphInitialize(_graph), "AUGraphInitialize failed");
}
AUNode outputNode;
{
AudioComponentDescription outputAudioDesc = {0};
outputAudioDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
outputAudioDesc.componentType = kAudioUnitType_Output;
outputAudioDesc.componentSubType = kAudioUnitSubType_RemoteIO;
// adds a node with above description to the graph
CheckError(AUGraphAddNode(_graph, &outputAudioDesc, &outputNode), "AUGraphAddNode[kAudioUnitSubType_DefaultOutput] failed");
}
AUNode mixerNode;
{
AudioComponentDescription mixerAudioDesc = {0};
mixerAudioDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
mixerAudioDesc.componentType = kAudioUnitType_Mixer;
mixerAudioDesc.componentSubType = kAudioUnitSubType_AU3DMixerEmbedded;
mixerAudioDesc.componentFlags = 0;
mixerAudioDesc.componentFlagsMask = 0;
// adds a node with above description to the graph
CheckError(AUGraphAddNode(_graph, &mixerAudioDesc, &mixerNode), "AUGraphAddNode[kAudioUnitSubType_AU3DMixerEmbedded] failed");
}
AUNode filePlayerNode;
{
AudioComponentDescription fileplayerAudioDesc = {0};
fileplayerAudioDesc.componentType = kAudioUnitType_Generator;
fileplayerAudioDesc.componentSubType = kAudioUnitSubType_AudioFilePlayer;
fileplayerAudioDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
// adds a node with above description to the graph
CheckError(AUGraphAddNode(_graph, &fileplayerAudioDesc, &filePlayerNode), "AUGraphAddNode[kAudioUnitSubType_AudioFilePlayer] failed");
}
//Connect the nodes
{
// connect the output source of the file player AU to the input source of the output node
// CheckError(AUGraphConnectNodeInput(_graph, filePlayerNode, 0, outputNode, 0), "AUGraphConnectNodeInput");
CheckError(AUGraphConnectNodeInput(_graph, filePlayerNode, 0, mixerNode, 0), "AUGraphConnectNodeInput");
CheckError(AUGraphConnectNodeInput(_graph, mixerNode, 0, outputNode, 0), "AUGraphConnectNodeInput");
}
// configure the file player
// tell the file player unit to load the file we want to play
{
//?????
AudioStreamBasicDescription inputFormat; // input file's data stream description
AudioFileID inputFile; // reference to your input file
// open the input audio file and store the AU ref in _player
CFURLRef songURL = (__bridge CFURLRef)[[NSBundle mainBundle] URLForResource:@"monoVoice" withExtension:@"aif"];
CheckError(AudioFileOpenURL(songURL, kAudioFileReadPermission, 0, &inputFile), "AudioFileOpenURL failed");
//create an empty MyAUGraphPlayer struct
AudioUnit fileAU;
// get the reference to the AudioUnit object for the file player graph node
CheckError(AUGraphNodeInfo(_graph, filePlayerNode, NULL, &fileAU), "AUGraphNodeInfo failed");
// get and store the audio data format from the file
UInt32 propSize = sizeof(inputFormat);
CheckError(AudioFileGetProperty(inputFile, kAudioFilePropertyDataFormat, &propSize, &inputFormat), "couldn't get file's data format");
CheckError(AudioUnitSetProperty(fileAU, kAudioUnitProperty_ScheduledFileIDs, kAudioUnitScope_Global, 0, &(inputFile), sizeof((inputFile))), "AudioUnitSetProperty[kAudioUnitProperty_ScheduledFileIDs] failed");
UInt64 nPackets;
UInt32 propsize = sizeof(nPackets);
CheckError(AudioFileGetProperty(inputFile, kAudioFilePropertyAudioDataPacketCount, &propsize, &nPackets), "AudioFileGetProperty[kAudioFilePropertyAudioDataPacketCount] failed");
// tell the file player AU to play the entire file
ScheduledAudioFileRegion rgn;
memset (&rgn.mTimeStamp, 0, sizeof(rgn.mTimeStamp));
rgn.mTimeStamp.mFlags = kAudioTimeStampSampleTimeValid;
rgn.mTimeStamp.mSampleTime = 0;
rgn.mCompletionProc = NULL;
rgn.mCompletionProcUserData = NULL;
rgn.mAudioFile = inputFile;
rgn.mLoopCount = 1;
rgn.mStartFrame = 0;
rgn.mFramesToPlay = nPackets * inputFormat.mFramesPerPacket;
CheckError(AudioUnitSetProperty(fileAU, kAudioUnitProperty_ScheduledFileRegion, kAudioUnitScope_Global, 0,&rgn, sizeof(rgn)), "AudioUnitSetProperty[kAudioUnitProperty_ScheduledFileRegion] failed");
// prime the file player AU with default values
UInt32 defaultVal = 0;
CheckError(AudioUnitSetProperty(fileAU, kAudioUnitProperty_ScheduledFilePrime, kAudioUnitScope_Global, 0, &defaultVal, sizeof(defaultVal)), "AudioUnitSetProperty[kAudioUnitProperty_ScheduledFilePrime] failed");
// tell the file player AU when to start playing (-1 sample time means next render cycle)
AudioTimeStamp startTime;
memset (&startTime, 0, sizeof(startTime));
startTime.mFlags = kAudioTimeStampSampleTimeValid;
startTime.mSampleTime = -1;
CheckError(AudioUnitSetProperty(fileAU, kAudioUnitProperty_ScheduleStartTimeStamp, kAudioUnitScope_Global, 0, &startTime, sizeof(startTime)), "AudioUnitSetProperty[kAudioUnitProperty_ScheduleStartTimeStamp]");
// file duration
//double duration = (nPackets * _player.inputFormat.mFramesPerPacket)/_player.inputFormat.mSampleRate;
}
}
return self;
}
我没有在你的代码看到你设置相应的kAudioUnitProperty_StreamFormat的音频单元。您还必须检查错误结果代码,以确定您选择的流格式设置是否实际上由正在配置的音频设备支持。如果不是,请尝试其他格式。
(AUGraphConnectNodeInput(_graph,filePlayerNode,0,mixerNode,0))(AUGraphConnectNodeInput(_graph,mixerNode,0,outputNode,0))
尝试这样的方式,如果它可以help.Just信息左节点被输入到正确的节点中。所以在第一行中,播放器节点被输入到混合器节点,现在混合器节点包含播放器和混合器,因此将混合器节点添加到输出节点。
喜欢使用'{...}'块来包装中间变量并组织代码... – 2012-08-14 17:36:32
远射,但我遇到同样的问题。最终的可接受格式是什么? – 2012-12-09 03:38:09
感谢您的代码。 :)。顺便说一句,它适用于我。我刚添加AUGraphStart(图) – 2014-08-17 12:22:57