Re: Steps to Display A Microphone's Input Level
Re: Steps to Display A Microphone's Input Level
- Subject: Re: Steps to Display A Microphone's Input Level
- From: Simon Wolf <email@hidden>
- Date: Tue, 25 Jan 2011 16:47:06 +0000
As a follow-up to my own message, I decided to use an AUGraph containing two AudioUnits, a HAL output and a multi channel mixer. I think that I have it all set up properly but I only ever get -120.0 returned as the decibel value of the kMultiChannelMixerParam_PreAveragePower parameter of the mixer.
When I call CAShow for my AUGraph once I've configured it I get:
AudioUnitGraph 0x11169000:
Member Nodes:
node 1: 'auou' 'ahal' 'appl', instance 0x810000 O I
node 2: 'aumx' 'mcmx' 'appl', instance 0x810001 O I
Connections:
node 1 bus 1 => node 2 bus 0 [1 ch, 44100 Hz]
CurrentState:
mLastUpdateError=0, eventsToProcess=F, isRunning=F
Here's how I'm setting up the AUGraph:
In the header file I have:
AUGraph mGraph;
AudioUnit mAUHAL;
AudioUnit mMixer;
AudioStreamBasicDescription mSourceDeviceFormat;
AudioStreamBasicDescription mCustomisedDeviceFormat;
In the implementation file I use this method to set the graph up:
- (BOOL)initializeAUGraph
{
AUNode inputNode;
AUNode mixerNode;
OSStatus result = noErr;
UInt32 size;
// create a new AUGraph
result = NewAUGraph(&mGraph);
if (result) { printf("NewAUGraph result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }
// input unit
AudioComponentDescription inputDesc;
inputDesc.componentType = kAudioUnitType_Output;
inputDesc.componentSubType = kAudioUnitSubType_HALOutput;
inputDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
inputDesc.componentFlags = 0;
inputDesc.componentFlagsMask = 0;
// multichannel mixer unit
AudioComponentDescription mixerDesc;
mixerDesc.componentType = kAudioUnitType_Mixer;
mixerDesc.componentSubType = kAudioUnitSubType_MultiChannelMixer;
mixerDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
mixerDesc.componentFlags = 0;
mixerDesc.componentFlagsMask = 0;
// create a node in the graph that is an AudioUnit, using the supplied component description to find and open that unit
result = AUGraphAddNode(mGraph, &inputDesc, &inputNode);
if (result) { printf("AUGraphAddNode AUHAL result %lu %4.4s\n", (unsigned long)result, (char *)&result); return NO; }
result = AUGraphAddNode(mGraph, &mixerDesc, &mixerNode);
if (result) { printf("AUGraphAddNode mixer result %lu %4.4s\n", (unsigned long)result, (char*)&result); return NO; }
// open the graph -- AudioUnits are open but not initialized (no resource allocation occurs here)
result = AUGraphOpen(mGraph);
if (result) { printf("AUGraphOpen result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }
// grab audio unit instances from the nodes
result = AUGraphNodeInfo(mGraph, inputNode, NULL, &mAUHAL);
if (result) { printf("AUGraphNodeInfo AUHAL result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }
result = AUGraphNodeInfo(mGraph, mixerNode, NULL, &mMixer);
if (result) { printf("AUGraphNodeInfo mixer result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }
// enable input, diable output
UInt32 enableIO = 1;
result = AudioUnitSetProperty(mAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO));
if (result) { printf("AudioUnitSetProperty result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }
enableIO = 0;
result = AudioUnitSetProperty(mAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO));
if (result) { printf("AudioUnitSetProperty result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }
// get the current device
AudioDeviceID inputDevice;
size = sizeof(inputDevice);
AudioObjectPropertyAddress theAddress;
theAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice;
theAddress.mScope = kAudioObjectPropertyScopeGlobal;
theAddress.mElement = kAudioObjectPropertyElementMaster;
result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &theAddress, 0, NULL, &size, &inputDevice);
if (result) { printf("AudioObjectGetPropertyData DefaultInputDevice result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }
// set the current device as the AUHAL device
result = AudioUnitSetProperty(mAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Input, 1, &inputDevice, sizeof(inputDevice));
if (result) { printf("AudioUnitSetProperty result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }
// set mixer's input bus count
UInt32 numbuses = 1;
result = AudioUnitSetProperty(mMixer, kAudioUnitProperty_ElementCount, kAudioUnitScope_Input, 0, &numbuses, sizeof(numbuses));
if (result) { printf("AudioUnitSetProperty result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }
// enable metering
UInt32 onValue = 1;
printf("enable metering for input bus 0\n");
result = AudioUnitSetProperty(mMixer, kAudioUnitProperty_MeteringMode, kAudioUnitScope_Input, 0, &onValue, sizeof(onValue));
if (result) { printf("AudioUnitSetProperty result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }
// retrieve the ASBD of the input
size = sizeof(AudioStreamBasicDescription);
//AudioStreamBasicDescription sourceStreamFormat;
result = AudioUnitGetProperty(mAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &mSourceDeviceFormat, &size);
if (result) { printf("AudioUnitGetProperty result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }
// set the stream format
UInt32 audioChannels;
audioChannels = MAX(mSourceDeviceFormat.mChannelsPerFrame, 2);
int bytesPerSample = sizeof(AudioUnitSampleType);
//AudioStreamBasicDescription actualOutputFormat = {0};
mCustomisedDeviceFormat.mChannelsPerFrame = 1;
mCustomisedDeviceFormat.mSampleRate = mSourceDeviceFormat.mSampleRate;
mCustomisedDeviceFormat.mFormatID = kAudioFormatLinearPCM;
mCustomisedDeviceFormat.mFormatFlags = kAudioFormatFlagsAudioUnitCanonical;
mCustomisedDeviceFormat.mBitsPerChannel = 8 * bytesPerSample;
mCustomisedDeviceFormat.mBytesPerFrame = bytesPerSample;
mCustomisedDeviceFormat.mFramesPerPacket = 1;
mCustomisedDeviceFormat.mBytesPerPacket = bytesPerSample;
// Set the AudioOutputUnit output data format
result = AudioUnitSetProperty(mAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &mCustomisedDeviceFormat, sizeof(AudioStreamBasicDescription));
if (result) { printf("AudioUnitSetProperty result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }
// result = AudioUnitSetProperty(mMixer, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &actualOutputFormat, sizeof(AudioStreamBasicDescription));
// if (result) { printf("AudioUnitSetProperty result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }
result = AudioUnitSetProperty(mMixer, kAudioUnitProperty_SampleRate, kAudioUnitScope_Output, 0, &mSourceDeviceFormat.mSampleRate, sizeof(mSourceDeviceFormat.mSampleRate));
if (result) { printf("AudioUnitSetProperty result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }
// connect the outputs to the inputs
result = AUGraphConnectNodeInput(mGraph, inputNode, 1, mixerNode, 0);
if (result) { printf("AUGraphConnectNodeInput AUHAL result %lu %4.4s\n", (unsigned long)result, (char*)&result); return NO; }
// result = AUGraphConnectNodeInput(mGraph, mixerNode, 0, inputNode, 0);
// if (result) { printf("AUGraphConnectNodeInput mixer result %lu %4.4s\n", (unsigned long)result, (char*)&result); return NO; }
// now that we've set everything up we can initialize the graph, this will also validate the connections
result = AUGraphInitialize(mGraph);
if (result) { printf("AUGraphInitialize result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }
// get the number of frames in the IO buffer(s)
size = sizeof(UInt32);
result = AudioUnitGetProperty(mAUHAL, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global, 0, &mAudioSamples, &size);
if (result) { printf("AudioUnitGetProperty result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }
// allocate the audio buffers
mAudioBuffer = [self allocateAudioBufferListWithNumChannels:mCustomisedDeviceFormat.mChannelsPerFrame size:mAudioSamples * mCustomisedDeviceFormat.mBytesPerFrame];
if (mAudioBuffer == NULL) {
printf("AudioBufferAllocationFailed.\n");
return NO;
}
// set up the callback
AURenderCallbackStruct rcbs;
rcbs.inputProc = renderMixerOutput;
rcbs.inputProcRefCon = self;
result = AudioUnitSetProperty(mAUHAL, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Output, 0, &rcbs, sizeof(AURenderCallbackStruct));
if (result) { printf("AudioUnitSetProperty result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }
CAShow(mGraph);
return YES;
}
I try to retrieve the mixer level via a method invoked by a timer:
- (CGFloat)getMeterLevel
{
OSStatus result = noErr;
Float32 value = 0.0;
result = AudioUnitGetParameter(mMixer, kMultiChannelMixerParam_PreAveragePower, kAudioUnitScope_Input, 0, &value);
if (result) { printf("AudioUnitGetParameter kMultiChannelMixerParam_PostAveragePower Input result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); }
return value;
}
Possible things to note:
1. I have a callback defined for the AUHAL's AudioUnit which I will use to write the audio out to a file.
2. I have both explicitly set the output stream format of the AUHAL AudioUnit and also just tried setting the sample rate. At the moment the latter is the version used in the above code.
3. I have tried connecting the mixer node's output back into the AUHAL node's output but this is currently commented out in the code.
I'm not getting any errors or warnings so I'm now very confused. I'm wondering if it is something to do with having my AUHAL's output disabled (I've done this because I don't want to feed the input from a microphone back out through the speakers and also because most microphones are not duplex devices.
Any pointers or suggestions someone can give would be really, really appreciated because I've now been struggling with this for a few days,
Many thanks,
Simon
On 17 Jan 2011, at 13:07, Simon Wolf wrote:
> Hi. I'm a complete newcomer to Core Audio and as such I'm learning a lot and scratching my head in equal measures. I've created a test application which records audio from an input source (and allows the source to be selected) using AUHAL. What I'd like to do next is display the input level of the input device but I'm at a loss as to the best way of doing this so I'm hoping that someone can give me a pointer in the right direction, essentially a rough outline of what I need to set up.
>
> I have a feeling that I may have set off at too low a level and would be better off using an audio queue to do the recording but before I start over I wanted to see if anyone could give me some advice on where I should be focusing my investigations.
>
> This is all being done on OS X 10.6.
>
> Many thanks.
>
> Simon Wolf
>
> Website: http://www.ottersoftware.com
> Twitter: http://www.twitter.com/sgaw
> iChat: email@hidden _______________________________________________
> Do not post admin requests to the list. They will be ignored.
> Coreaudio-api mailing list (email@hidden)
> Help/Unsubscribe/Update your Subscription:
>
> This email sent to email@hidden
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Coreaudio-api mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden