Reputation: 4023
I'm trying to play 8000hz samples and pass them through an effect.
I aim to boost the audio volume (sample code doesn't do it, yet).
I figured I needed an effect audio unit, chained to the remote audio unit.
I also read about the effect unit being very strict with the format it can handle, mainly requiring 44.1khz samples, floating point and 32 bit samples (.
So, I added a convertor unit.
Also, since I figure (not sure though) iOS can't play 32 bit samples (thanks @hotpaw2 !) - I added another conversion back to 16 bits.
The problem is, I always get error -10868 while initializing the audio graph.
I get it without the last conversion unit as well.
If I connect the convert unit to the output (no effect unit), everything works fine (8k samples play just fine).
What's going on?
/* Must use play & record category, for reasons beyond the scope of this question */
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionDuckOthers | AVAudioSessionCategoryOptionDefaultToSpeaker | AVAudioSessionCategoryOptionAllowBluetooth error:nil];
NSError* err = nil;
if (![[AVAudioSession sharedInstance] setPreferredSampleRate:44100 error:&err]){
NSLog(@"%@",err);
}
AudioUnit effect,convert,output,oconvert;
AUNode neffect,nconvert,noutput,noconvert;
AUGraph graph;
AudioComponentDescription deffect,dconvert,doutput;
AudioStreamBasicDescription in_format,out_format,effect_format;
// Formats
memset(&in_format,0,sizeof(in_format));
memset(&out_format, 0, sizeof(out_format));
memset(&effect_format, 0, sizeof(effect_format));
in_format.mSampleRate = 8000;
in_format.mChannelsPerFrame = 1;
in_format.mFormatID = kAudioFormatLinearPCM;
in_format.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
in_format.mBitsPerChannel = 16;
in_format.mFramesPerPacket = 1;
in_format.mBytesPerFrame = in_format.mChannelsPerFrame * (in_format.mBitsPerChannel / 8);
in_format.mBytesPerPacket = in_format.mBytesPerFrame * in_format.mFramesPerPacket;
out_format.mSampleRate = 44100;
out_format.mChannelsPerFrame = 1;
out_format.mFormatID = kAudioFormatLinearPCM;
out_format.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
out_format.mBitsPerChannel = 16;
out_format.mFramesPerPacket = 1;
out_format.mBytesPerFrame = out_format.mChannelsPerFrame * (out_format.mBitsPerChannel / 8);
out_format.mBytesPerPacket = out_format.mBytesPerFrame * out_format.mFramesPerPacket;
effect_format.mSampleRate = 44100;
effect_format.mChannelsPerFrame = 1;
effect_format.mFormatID = kAudioFormatLinearPCM;
effect_format.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
effect_format.mBitsPerChannel = 32;
effect_format.mFramesPerPacket = 1;
effect_format.mBytesPerFrame = effect_format.mChannelsPerFrame * (effect_format.mBitsPerChannel / 8);
effect_format.mBytesPerPacket = effect_format.mBytesPerFrame * effect_format.mFramesPerPacket;
// Descriptions
memset(&doutput, 0, sizeof(doutput));
memset(&deffect, 0, sizeof(deffect));
memset(&dconvert, 0, sizeof(dconvert));
doutput.componentType = kAudioUnitType_Output;
doutput.componentSubType = kAudioUnitSubType_RemoteIO;
doutput.componentManufacturer = deffect.componentManufacturer = dconvert.componentManufacturer = kAudioUnitManufacturer_Apple;
dconvert.componentType = kAudioUnitType_FormatConverter;
dconvert.componentSubType = kAudioUnitSubType_AUConverter;
deffect.componentType = kAudioUnitType_Effect;
deffect.componentSubType = kAudioUnitSubType_DynamicsProcessor;
// Create graph
SdCheck(NewAUGraph(&graph));
// Create nodes;
SdCheck(AUGraphAddNode(graph, &deffect, &neffect));
SdCheck(AUGraphAddNode(graph, &doutput, &noutput));
SdCheck(AUGraphAddNode(graph, &dconvert, &nconvert));
SdCheck(AUGraphAddNode(graph, &dconvert, &noconvert));
// Open graph
SdCheck(AUGraphOpen(graph));
// Get units
SdCheck(AUGraphNodeInfo(graph, neffect,NULL, &effect));
SdCheck(AUGraphNodeInfo(graph, noutput,NULL, &output));
SdCheck(AUGraphNodeInfo(graph, nconvert,NULL, &convert));
SdCheck(AUGraphNodeInfo(graph, noconvert,NULL, &oconvert));
// Set formats
SdCheck(AudioUnitSetProperty (output,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
0,
&out_format,
sizeof(out_format)));
SdCheck(AudioUnitSetProperty (convert,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
0,
&effect_format,
sizeof(effect_format)));
SdCheck(AudioUnitSetProperty (convert,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
0,
&in_format,
sizeof(in_format)));
SdCheck(AudioUnitSetProperty (effect,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
0,
&effect_format,
sizeof(effect_format)));
SdCheck(AudioUnitSetProperty (effect,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
0,
&effect_format,
sizeof(effect_format)));
SdCheck(AudioUnitSetProperty (oconvert,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
0,
&out_format,
sizeof(out_format)));
SdCheck(AudioUnitSetProperty (oconvert,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
0,
&effect_format,
sizeof(effect_format)));
// Connect nodes
SdCheck(AUGraphConnectNodeInput(graph, nconvert, 0, neffect, 0));
SdCheck(AUGraphConnectNodeInput(graph, neffect, 0, noconvert, 0));
SdCheck(AUGraphConnectNodeInput(graph, noconvert, 0, noutput, 0));
// Set render callback
AURenderCallbackStruct input;
memset(&input, 0, sizeof(input));
input.inputProc = SdInputProc;
input.inputProcRefCon = (__bridge void*)self;
SdCheck(AUGraphSetNodeInputCallback(graph, nconvert, 0, &input));
// Initialize graph
/*** The following fails with error -10868 (unsupported format) ***/
SdCheck(AUGraphInitialize(graph));
Upvotes: 1
Views: 1159
Reputation: 70743
Most effect Audio Units on iOS require that a 32-bit floating point format be used on their input and output connections. Your example code attempts to configure an effect unit with 16-bit integer I/O, which won't work.
Upvotes: 1