My AUHAL AudioUnit Objective-C wrapper does not work with stereo line in
My AUHAL AudioUnit Objective-C wrapper does not work with stereo line in
- Subject: My AUHAL AudioUnit Objective-C wrapper does not work with stereo line in
- From: Marco Frisan <email@hidden>
- Date: Tue, 14 Jun 2011 00:07:11 +0200
Hello all,
and thanks, in advance, for any help I will receive.
I am developing a wrapper for AUHAL AudioUnits. It is written in Objective-C.
Actually I had some problems to learn Core Audio, so there could be more errors then I can see. Documentation is not enough to really understand Core Audio and all examples are written in C++ (that does not help me) and use Core Audio SDK Public Utilities to achieve many tasks. But Core Audio SDK Public Utilities are not documented and poorly commented, therefore, to fully understand them is a really big job.
Though, I have been able to code this wrapper, that works with my LED Cinema Display microphone (apparently, a monophonic microphone, right?).
The problem is that it does not work with the Mac Pro jack line in (apparently, a stereophonic source, right?).
At this point, I don't know where to look for the cause of this problem.
What I can guess, is that the cause should not be a device/unit setup problem, since I check all the errors eventually produced by Core Audio calls and the wrapper should not initialize (neither starts rendering) if anything goes wrong.
But, when using line in jack, left and right buffer amplitudes are all zero. The buffer where I render is the _renderBuf member variable of the class.
This is the code (I pasted both header and source files here):
// Header file
#import <Foundation/Foundation.h>
#import <AudioUnit/AudioUnit.h>
@interface SpectreAUHALFromInputWrapper : NSObject {
@private
AudioUnit _au;
AudioStreamBasicDescription _in_format;
AudioStreamBasicDescription _out_format;
AudioBufferList * _renderBuf;
UInt32 _framesNum;
}
@property (readonly) AudioUnit audioUnit;
@property (readonly) AudioStreamBasicDescription inputFormat;
@property (readonly) AudioStreamBasicDescription outputFormat;
- (OSStatus)start;
- (OSStatus)stop;
- (OSStatus)renderWithActionFlags:(AudioUnitRenderActionFlags *)flags
timeStamp:(const AudioTimeStamp *)ts
bus:(UInt32)bus
framesNumber:(UInt32)framesNum;
- (OSStatus)readBuffer:(AudioBufferList **)bufList;
- (OSStatus)numberOfFrames:(UInt32 *)num;
@end
// Source file
#import "SpectreAUHALFromInputWrapper.h"
#import "SpectreMacros.h"
@interface SpectreAUHALFromInputWrapper (SpectreAUHALFromInputWrapperPrivate)
- (OSStatus)createAUHAL;
- (OSStatus)enableIO;
- (OSStatus)setDeviceTo:(AudioDeviceID)devID;
- (OSStatus)setAudioFormat;
- (OSStatus)setupCallback;
- (OSStatus)getInputFormat:(AudioStreamBasicDescription *)desc;
- (OSStatus)getOutputFormat:(AudioStreamBasicDescription *)desc;
- (BOOL)isRunning;
- (OSStatus)setupRenderBuffer;
@end
OSStatus SpectreInputProc(void * inRefCon,
AudioUnitRenderActionFlags * ioActionFlags,
const AudioTimeStamp * inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList * ioData)
{
OSStatus err = noErr;
SpectreAUHALFromInputWrapper * wrapper = (SpectreAUHALFromInputWrapper *)inRefCon;
err = [wrapper renderWithActionFlags:ioActionFlags
timeStamp:inTimeStamp
bus:inBusNumber
framesNumber:inNumberFrames];
return err;
}
@implementation SpectreAUHALFromInputWrapper
@synthesize audioUnit = _au;
@synthesize inputFormat = _in_format;
@synthesize outputFormat = _out_format;
- (id)init {
self = [super init];
if (self) {
OSStatus err = noErr;
err = [self createAUHAL];
spectreTestError2(err);
}
return self;
}
- (void)dealloc {
[super dealloc];
}
- (OSStatus)start {
OSStatus err = noErr;
if (![self isRunning]) {
err = AudioOutputUnitStart(_au);
spectreTestError(err);
}
return err;
}
- (OSStatus)stop {
OSStatus err = noErr;
if ([self isRunning]) {
err = AudioOutputUnitStop(_au);
spectreTestError(err);
}
return err;
}
- (BOOL)isRunning {
OSStatus err = noErr;
UInt32 isRunning = 0;
UInt32 size = 0;
size = sizeof(isRunning);
if (_au) {
err = AudioUnitGetProperty(_au,
kAudioOutputUnitProperty_IsRunning,
kAudioUnitScope_Global,
0,
&isRunning,
&size);
}
return isRunning;
}
- (OSStatus)createAUHAL {
OSStatus err = noErr;
AudioComponent comp;
AudioComponentDescription desc;
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_HALOutput;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
comp = AudioComponentFindNext(NULL, &desc);
if (!comp) {
NSLog(@"No AudioComponent found for the AUHAL unit description.");
return -1;
}
err = AudioComponentInstanceNew(comp, &_au);
spectreTestError(err);
err = AudioUnitInitialize(_au);
spectreTestError(err);
err = [self enableIO];
spectreTestError(err);
err = [self setDeviceTo:kAudioDeviceUnknown];
spectreTestError(err);
err = [self setupCallback];
spectreTestError(err);
err = [self getInputFormat:&_in_format];
spectreTestError(err);
err = [self getOutputFormat:&_out_format];
spectreTestError(err);
err = [self setAudioFormat];
spectreTestError(err);
err = [self setupRenderBuffer];
spectreTestError(err);
err = AudioUnitInitialize(_au);
return err;
}
- (OSStatus)enableIO {
OSStatus err = noErr;
UInt32 enableIO = 1;
err = AudioUnitSetProperty(_au,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Input,
kSpectreInputBus, // input element
&enableIO,
sizeof(enableIO));
spectreTestError(err);
enableIO = 0;
err = AudioUnitSetProperty(_au,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Output,
kSpectreOutputBus, //output element
&enableIO,
sizeof(enableIO));
return err;
}
- (OSStatus)setDeviceTo:(AudioDeviceID)devID {
OSStatus err = noErr;
UInt32 size = sizeof(AudioDeviceID);
if(devID == kAudioDeviceUnknown) {
err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice,
&size,
&devID);
spectreTestError(err);
}
/* ================================ DEBUG =============================== */
err = AudioDeviceGetPropertyInfo(devID, 0, YES, kAudioDevicePropertyDeviceName, &size, NULL);
spectreTestError(err);
char * name = (char *)malloc(size);
err = AudioDeviceGetProperty(devID, 0, YES, kAudioDevicePropertyDeviceName, &size, name);
spectreTestError(err);
NSLog(@"Input device name: %s", name);
/* ================================ DEBUG =============================== */
err = AudioUnitSetProperty(_au,
kAudioOutputUnitProperty_CurrentDevice,
kAudioUnitScope_Global,
0,
&devID,
sizeof(devID));
return err;
}
- (OSStatus)setupCallback {
OSStatus err = noErr;
AURenderCallbackStruct cbs;
cbs.inputProc = SpectreInputProc;
cbs.inputProcRefCon = self;
// Setup the input callback.
err = AudioUnitSetProperty(_au,
kAudioOutputUnitProperty_SetInputCallback,
kAudioUnitScope_Global,
0,
&cbs,
sizeof(cbs));
return err;
}
- (OSStatus)getInputFormat:(AudioStreamBasicDescription *)desc {
OSStatus err = noErr;
UInt32 size = sizeof(AudioStreamBasicDescription);
err = AudioUnitGetProperty(_au,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
kSpectreInputBus,
desc,
&size);
return err;
}
- (OSStatus)getOutputFormat:(AudioStreamBasicDescription *)desc {
OSStatus err = noErr;
UInt32 size = sizeof(AudioStreamBasicDescription);
err = AudioUnitGetProperty(_au,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
kSpectreInputBus,
desc,
&size);
return err;
}
- (OSStatus)renderWithActionFlags:(AudioUnitRenderActionFlags *)flags
timeStamp:(const AudioTimeStamp *)ts
bus:(UInt32)bus
framesNumber:(UInt32)framesNum
{
//NSLog(@"Render input audio with time stamp: %f; bus number: %u; number of frames: %u", ts->mSampleTime, bus, framesNum);
OSStatus err = noErr;
@synchronized(self) {
err = AudioUnitRender(_au,
flags,
ts,
bus,
framesNum,
_renderBuf);
_framesNum = framesNum;
}
return err;
}
- (OSStatus)readBuffer:(AudioBufferList **)bufList {
// NSLog(@"\tnumber of buffers = %u", _renderBuf->mNumberBuffers);
// for (UInt32 i = 0; i < _renderBuf->mNumberBuffers; i++) {
// NSLog(@"\tbuffer %u = (number of channels = %u; bytes number = %u)", i, _renderBuf->mBuffers[i].mNumberChannels, _renderBuf->mBuffers[i].mDataByteSize);
//
// Float32 * data = (Float32 *)_renderBuf->mBuffers[i].mData;
// NSMutableString * seq = [NSMutableString string];
// //for (UInt32 f = 0; f < _framesNum; f++) {
// [seq appendFormat:@"%f ", data[0]];
// //}
// NSLog(@"\t\tdata = %@", seq);
// }
OSStatus err = noErr;
@synchronized(self) {
if (_renderBuf) {
if (*bufList)
free(bufList);
size_t bufListSize;
bufListSize = offsetof(AudioBufferList, mBuffers[0]) + (sizeof(AudioBuffer) * _renderBuf->mNumberBuffers);
*bufList = (AudioBufferList *)malloc(bufListSize);
(*bufList)->mNumberBuffers = _renderBuf->mNumberBuffers;
for (UInt32 i = 0; i < _renderBuf->mNumberBuffers; i++) {
(*bufList)->mBuffers[i].mNumberChannels = _renderBuf->mBuffers[i].mNumberChannels;
(*bufList)->mBuffers[i].mDataByteSize = _renderBuf->mBuffers[i].mDataByteSize;
(*bufList)->mBuffers[i].mData = malloc((*bufList)->mBuffers[i].mDataByteSize);
memcpy((*bufList)->mBuffers[i].mData, _renderBuf->mBuffers[i].mData, (*bufList)->mBuffers[i].mDataByteSize);
}
}
}
return err;
}
- (OSStatus)numberOfFrames:(UInt32 *)num {
OSStatus err = noErr;
@synchronized(self) {
*num = _framesNum;
}
return err;
}
- (OSStatus)setAudioFormat {
OSStatus err = noErr;
_out_format = _in_format;
err = AudioUnitSetProperty(_au,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
kSpectreInputBus,
&_out_format,
sizeof(_out_format));
return err;
}
- (OSStatus)setupRenderBuffer {
OSStatus err = noErr;
UInt32 size;
UInt32 bufFrameNum;
UInt32 bufSize;
size = offsetof(AudioBufferList, mBuffers[0]) + (sizeof(AudioBuffer) * _in_format.mChannelsPerFrame);
_renderBuf = (AudioBufferList *)malloc(size);
_renderBuf->mNumberBuffers = _in_format.mChannelsPerFrame;
size = sizeof(UInt32);
err = AudioUnitGetProperty(_au,
kAudioDevicePropertyBufferFrameSize,
kAudioUnitScope_Global,
0,
&bufFrameNum,
&size);
spectreTestError(err);
bufSize = bufFrameNum * sizeof(Float32);
for(UInt32 i = 0; i < _renderBuf->mNumberBuffers; i++) {
_renderBuf->mBuffers[i].mNumberChannels = 1;
_renderBuf->mBuffers[i].mDataByteSize = bufSize;
_renderBuf->mBuffers[i].mData = malloc(bufSize);
}
return err;
}
@end
_______________________________________________
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