Skip to content

Instantly share code, notes, and snippets.

@AlexanderBollbach
Created January 15, 2016 00:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AlexanderBollbach/3b862db17adf240928f8 to your computer and use it in GitHub Desktop.
Save AlexanderBollbach/3b862db17adf240928f8 to your computer and use it in GitHub Desktop.
#include <AudioToolbox/AudioToolbox.h>
typedef struct MyAUGraphPlayer
{
AudioStreamBasicDescription streamFormat;
AudioUnit inputUnit;
AudioBufferList *inputBuffer;
ExtAudioFileRef recordFile;
SInt64 startingByte;
} MyAUGraphPlayer;
OSStatus InputRenderProc(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList * ioData);
#pragma mark - render proc -
OSStatus InputRenderProc(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList * ioData)
{
// printf ("InputRenderProc!\n");
MyAUGraphPlayer *player = (MyAUGraphPlayer*) inRefCon;
// render into our buffer
OSStatus inputProcErr = noErr;
inputProcErr = AudioUnitRender(player->inputUnit,
ioActionFlags,
inTimeStamp,
inBusNumber,
inNumberFrames,
player->inputBuffer);
Float32 someDataL = *(Float32*)(player->inputBuffer->mBuffers[0].mData);
printf("L2 input: % 1.7f \n",someDataL);
UInt32 numOfBytes = 4096*player->streamFormat.mBytesPerFrame;
// ExtAudioFileWriteAsync(player->recordFile, 4096, player->inputBuffer);
player->startingByte += numOfBytes;
return inputProcErr;
}
#pragma mark - utility functions -
// generic error handler - if err is nonzero, prints error message and exits program.
static void CheckError(OSStatus error, const char *operation)
{
if (error == noErr) return;
char str[20];
// see if it appears to be a 4-char-code
*(UInt32 *)(str + 1) = CFSwapInt32HostToBig(error);
if (isprint(str[1]) && isprint(str[2]) && isprint(str[3]) && isprint(str[4])) {
str[0] = str[5] = '\'';
str[6] = '\0';
} else
// no, format it as an integer
sprintf(str, "%d", (int)error);
fprintf(stderr, "Error: %s (%s)\n", operation, str);
exit(1);
}
void CreateInputUnit (MyAUGraphPlayer *player) {
// generate description that will match audio HAL
AudioComponentDescription inputcd = {0};
inputcd.componentType = kAudioUnitType_Output;
inputcd.componentSubType = kAudioUnitSubType_HALOutput;
inputcd.componentManufacturer = kAudioUnitManufacturer_Apple;
AudioComponent comp = AudioComponentFindNext(NULL, &inputcd);
if (comp == NULL) {
printf ("can't get output unit");
exit (-1);
}
CheckError(AudioComponentInstanceNew(comp, &player->inputUnit), "Couldn't open component for inputUnit");
UInt32 disableFlag = 0, enableFlag = 1;
AudioUnitScope outputBus = 0, inputBus = 1;
CheckError(AudioUnitSetProperty(player->inputUnit,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Input,
inputBus,
&enableFlag,
sizeof(enableFlag)), "Couldn't enable input on I/O unit");
CheckError (AudioUnitSetProperty(player->inputUnit,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Output,
outputBus,
&disableFlag,
sizeof(enableFlag)), "Couldn't disable output on I/O unit");
AudioDeviceID defaultDevice = kAudioObjectUnknown;
UInt32 propertySize = sizeof(defaultDevice);
AudioObjectPropertyAddress defaultDeviceProperty;
defaultDeviceProperty.mSelector = kAudioHardwarePropertyDefaultInputDevice;
defaultDeviceProperty.mScope = kAudioObjectPropertyScopeGlobal;
defaultDeviceProperty.mElement = kAudioObjectPropertyElementMaster;
CheckError (AudioObjectGetPropertyData(kAudioObjectSystemObject,
&defaultDeviceProperty,
0,
NULL,
&propertySize,
&defaultDevice), "Couldn't get default input device");
UInt32 bufferProp = 2048;
AudioObjectPropertyAddress defaultDeviceProperty2;
defaultDeviceProperty2.mSelector = kAudioDevicePropertyBufferFrameSize;
defaultDeviceProperty2.mScope = kAudioObjectPropertyScopeGlobal;
defaultDeviceProperty2.mElement = kAudioObjectPropertyElementMaster;
AudioObjectSetPropertyData(defaultDevice,
&defaultDeviceProperty2,
NULL,
NULL,
sizeof(bufferProp),
&bufferProp);
CheckError(AudioUnitSetProperty(player->inputUnit,
kAudioOutputUnitProperty_CurrentDevice,
kAudioUnitScope_Global,
outputBus,
&defaultDevice,
sizeof(defaultDevice)),"Couldn't set default device on I/O unit");
propertySize = sizeof (AudioStreamBasicDescription);
CheckError(AudioUnitGetProperty(player->inputUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
inputBus,
&player->streamFormat,
&propertySize), "Couldn't get ASBD from input unit");
AudioStreamBasicDescription deviceFormat;
CheckError(AudioUnitGetProperty(player->inputUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
inputBus,
&deviceFormat,
&propertySize), "Couldn't get ASBD from input unit");
printf ("Device rate %f, graph rate %f\n", deviceFormat.mSampleRate, player->streamFormat.mSampleRate);
player->streamFormat.mSampleRate = deviceFormat.mSampleRate;
propertySize = sizeof (AudioStreamBasicDescription);
CheckError(AudioUnitSetProperty(player->inputUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
inputBus,
&player->streamFormat,
propertySize), "Couldn't set ASBD on input unit");
UInt32 bufferSizeFrames = 0;
propertySize = sizeof(UInt32);
CheckError (AudioUnitGetProperty(player->inputUnit,
kAudioDevicePropertyBufferFrameSize,
kAudioUnitScope_Global,
0,
&bufferSizeFrames,
&propertySize), "Couldn't get buffer frame size from input unit");
UInt32 bufferSizeBytes = bufferSizeFrames * sizeof(Float32);
printf("buffer num of frames %i", bufferSizeFrames);
if (player->streamFormat.mFormatFlags & kAudioFormatFlagIsNonInterleaved) {
int offset = offsetof(AudioBufferList, mBuffers[0]);
int sizeOfAB = sizeof(AudioBuffer);
int chNum = player->streamFormat.mChannelsPerFrame;
int inputBufferSize = offset + sizeOfAB * chNum;
//malloc buffer lists
player->inputBuffer = (AudioBufferList *)malloc(inputBufferSize);
player->inputBuffer->mNumberBuffers = chNum;
for (UInt32 i = 0; i < chNum ; i++) {
player->inputBuffer->mBuffers[i].mNumberChannels = 1;
player->inputBuffer->mBuffers[i].mDataByteSize = bufferSizeBytes;
player->inputBuffer->mBuffers[i].mData = malloc(bufferSizeBytes);
}
}
AURenderCallbackStruct callbackStruct;
callbackStruct.inputProc = InputRenderProc;
callbackStruct.inputProcRefCon = player;
CheckError(AudioUnitSetProperty(player->inputUnit,
kAudioOutputUnitProperty_SetInputCallback,
kAudioUnitScope_Global,
0,
&callbackStruct,
sizeof(callbackStruct)), "Couldn't set input callback");
CheckError(AudioUnitInitialize(player->inputUnit), "Couldn't initialize input unit");
}
int main(void) {
MyAUGraphPlayer player = {0};
player.startingByte = 0;
memset (&player, 0, sizeof (player));
CreateInputUnit(&player);
CFURLRef myFileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, CFSTR("./test23.wav"), kCFURLPOSIXPathStyle, false);
CheckError (AudioOutputUnitStart(player.inputUnit), "AudioOutputUnitStart failed");
CheckError(ExtAudioFileCreateWithURL(myFileURL, kAudioFileWAVEType, &player.streamFormat, NULL, kAudioFileFlags_EraseFile, &player.recordFile),"create file");
// UInt32 size = sizeof(AudioStreamBasicDescription);
//
// CheckError(ExtAudioFileSetProperty(player.recordFile, kExtAudioFileProperty_ClientDataFormat, size, &player.streamFormat), "set prop on file");
// CheckError(ExtAudioFileWriteAsync(player.recordFile, 0, NULL), "audio file write bytes first");
// and wait
printf("Capturing, press <return> to stop:\n");
getchar();
CheckError(AudioOutputUnitStop(player.inputUnit), "stop");
ExtAudioFileDispose(player.recordFile);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment