#include #include #include #ifndef __IPHONE_OS_VERSION_MIN_REQUIRED #include #include #endif #include "device_coreaudio.h" #include "debug.h" #define kOutputBus 0 #define kInputBus 1 namespace audiere { CAAudioDevice* CAAudioDevice::create(const ParameterList& parameters) { OSStatus result = noErr; AudioStreamBasicDescription desc; // Setup a AudioStreamBasicDescription with the requested format memset(&desc, 0, sizeof(desc)); desc.mFormatID = kAudioFormatLinearPCM; desc.mFormatFlags = kLinearPCMFormatFlagIsPacked; desc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger; desc.mSampleRate = 44100; desc.mChannelsPerFrame = 2; desc.mBitsPerChannel = 16; desc.mFramesPerPacket = 1; desc.mBytesPerFrame = desc.mBitsPerChannel * desc.mChannelsPerFrame / 8; desc.mBytesPerPacket = desc.mBytesPerFrame * desc.mFramesPerPacket; #ifndef __IPHONE_OS_VERSION_MIN_REQUIRED // Locate the default output audio unit AudioDeviceID devid = 0; UInt32 size = 0; UInt32 alive = 0; pid_t pid = 0; size = sizeof(AudioDeviceID); const AudioHardwarePropertyID propid = kAudioHardwarePropertyDefaultOutputDevice; result = AudioHardwareGetProperty(propid, &size, &devid); if (result != noErr) return 0; size = sizeof(alive); result = AudioDeviceGetProperty(devid, 0, false, kAudioDevicePropertyDeviceIsAlive, &size, &alive); if (result != noErr) { ADR_LOG("CoreAudio: requested device exists, but isn't alive."); return 0; } size = sizeof(pid); result = AudioDeviceGetProperty(devid, 0, false, kAudioDevicePropertyHogMode, &size, &pid); /* some devices don't support this property, so errors are fine here. */ if ((result == noErr) && (pid != -1)) { ADR_LOG("CoreAudio: requested device is being hogged."); return 0; } #endif AudioUnit unit; #ifndef __IPHONE_OS_VERSION_MIN_REQUIRED Component comp; ComponentDescription compDesc; memset(&compDesc, 0, sizeof(ComponentDescription)); compDesc.componentType = kAudioUnitType_Output; compDesc.componentSubType = kAudioUnitSubType_DefaultOutput; compDesc.componentManufacturer = kAudioUnitManufacturer_Apple; comp = FindNextComponent(NULL, &compDesc); if (!comp) { ADR_LOG("CoreAudio: Couldn't find requested CoreAudio component."); return 0; } /* Open & initialize the audio unit */ result = OpenAComponent(comp, &unit); if (result != noErr) { ADR_LOG("CoreAudio: Couldn't open a audio unit.\n"); return 0; } result = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &devid, sizeof(AudioDeviceID)); if (result != noErr) { ADR_LOG ("CoreAudio: Couldn't set current device."); CloseComponent(unit); return 0; } #else AudioComponent comp; AudioComponentDescription compDesc; memset(&compDesc, 0, sizeof(AudioComponentDescription)); compDesc.componentType = kAudioUnitType_Output; compDesc.componentSubType = kAudioUnitSubType_RemoteIO; compDesc.componentManufacturer = kAudioUnitManufacturer_Apple; comp = AudioComponentFindNext(NULL, &compDesc); if (!comp) { ADR_LOG("CoreAudio: Couldn't find requested CoreAudio component"); return 0; } /* Open & initialize the audio unit */ result = AudioComponentInstanceNew(comp, &unit); if (result != noErr) { ADR_LOG("CoreAudio: Couldn't open a audio unit.\n"); return 0; } UInt32 enableIO = 0; result = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &enableIO, sizeof(enableIO)); if (result != noErr) { ADR_LOG("CoreAudio: Couldn't disable input for the audio unit.\n"); return 0; } enableIO = 1; result = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, kOutputBus, &enableIO, sizeof(enableIO)); if (result != noErr) { ADR_LOG("CoreAudio: Couldn't enable output for the audio unit.\n"); return 0; } #endif // Set the input format of the audio unit. result = AudioUnitSetProperty(unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &desc, sizeof(desc)); if (result != noErr) { ADR_LOG ("CoreAudio: Couldn't to set stream format."); #ifndef __IPHONE_OS_VERSION_MIN_REQUIRED CloseComponent(unit); #endif return 0; } result = AudioUnitInitialize(unit); if (result != noErr) { ADR_LOG ("CoreAudio: Couldn't initialize the audio unit."); #ifndef __IPHONE_OS_VERSION_MIN_REQUIRED CloseComponent(unit); #endif return 0; } return new CAAudioDevice(unit); } CAAudioDevice::CAAudioDevice(AudioUnit audio_unit) : MixerDevice(44100), m_unit (audio_unit) { OSStatus result; // Set the audio callback struct AURenderCallbackStruct callback; memset(&callback, 0, sizeof(AURenderCallbackStruct)); callback.inputProc = fillInput; callback.inputProcRefCon = this; result = AudioUnitSetProperty(m_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callback, sizeof(callback)); if (result != noErr) ADR_LOG("CoreAudio: Couldn't set render callback.\n"); result = AudioOutputUnitStart(m_unit); if (result != noErr) ADR_LOG("CoreAudio: Couldn't start the audio unit.\n"); } CAAudioDevice::~CAAudioDevice() { ADR_GUARD("CAAudioDevice::~CAAudioDevice"); OSStatus result; struct AURenderCallbackStruct callback; result = AudioOutputUnitStop(m_unit); memset(&callback, 0, sizeof(AURenderCallbackStruct)); result = AudioUnitSetProperty(m_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callback, sizeof(callback)); #ifndef __IPHONE_OS_VERSION_MIN_REQUIRED result = CloseComponent(m_unit); #else result = AudioUnitUninitialize(m_unit); #endif } void CAAudioDevice::pause() { ADR_GUARD("CAAudioDevice::~CAAudioDevice"); AudioOutputUnitStop(m_unit); } void CAAudioDevice::resume() { ADR_GUARD("CAAudioDevice::~CAAudioDevice"); AudioOutputUnitStart(m_unit); } OSStatus CAAudioDevice::fillInput(void *inRefCon, AudioUnitRenderActionFlags * ioActionFlags, const AudioTimeStamp * inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList * ioData) { CAAudioDevice* device = static_cast(inRefCon); ADR_LOG("fillInput\n"); for (UInt32 i = 0; i < ioData->mNumberBuffers; i++) { ::AudioBuffer *abuf; UInt32 remaining, len; void* ptr; abuf = &ioData->mBuffers[i]; remaining = abuf->mDataByteSize; ptr = abuf->mData; while (remaining > 0) { if (device) { len = device->read(remaining / 4, ptr); } else { len = remaining / 4; memset(ptr, 0, remaining); } ptr = (char *)ptr + len; remaining -= len * 4; } } return noErr; } void ADR_CALL CAAudioDevice::update() { AI_Sleep (20); } const char* ADR_CALL CAAudioDevice::getName() { return "coreaudio"; } }