diff --git a/src/CoreAudio/AudioHardware.cpp b/src/CoreAudio/AudioHardware.cpp new file mode 100644 index 000000000..1363f333a --- /dev/null +++ b/src/CoreAudio/AudioHardware.cpp @@ -0,0 +1,231 @@ +/* +This file is part of Darling. + +Copyright (C) 2015-2016 Lubos Dolezel + +Darling is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Darling is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Darling. If not, see . +*/ + +#include "AudioHardware.h" +#include "AudioHardwareImpl.h" +#include +#include + +static std::unique_ptr g_systemObject; + +static AudioHardwareImpl* GetSystemObject() +{ + if (!g_systemObject) + { + static std::mutex singleLock; + singleLock.lock(); + + if (!g_systemObject) + g_systemObject.reset(nullptr); // TODO: create ALSA or PA here + + singleLock.unlock(); + } + + return g_systemObject.get(); +} + +static AudioHardwareImpl* GetObject(AudioObjectID objID) +{ + if (objID == kAudioObjectSystemObject) + return GetSystemObject(); + + return nullptr; +} + +void AudioObjectShow(AudioObjectID inObjectID) +{ + AudioHardwareImpl* obj = GetObject(inObjectID); + if (obj) + obj->show(); +} + +Boolean AudioObjectHasProperty(AudioObjectID inObjectID, + const AudioObjectPropertyAddress* inAddress) +{ + AudioHardwareImpl* obj = GetObject(inObjectID); + if (!obj) + return kAudioHardwareBadObjectError; + + return obj->hasProperty(inAddress); +} + +OSStatus AudioObjectIsPropertySettable(AudioObjectID inObjectID, + const AudioObjectPropertyAddress* inAddress, Boolean* outIsSettable) +{ + AudioHardwareImpl* obj = GetObject(inObjectID); + if (!obj) + return kAudioHardwareBadObjectError; + + return obj->isPropertySettable(inAddress, outIsSettable); +} + +OSStatus AudioObjectGetPropertyDataSize(AudioObjectID inObjectID, + const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, + const void* inQualifierData, UInt32* outDataSize) +{ + AudioHardwareImpl* obj = GetObject(inObjectID); + if (!obj) + return kAudioHardwareBadObjectError; + + return obj->getPropertyDataSize(inAddress, inQualifierDataSize, + inQualifierData, outDataSize); +} + +OSStatus AudioObjectGetPropertyData(AudioObjectID inObjectID, + const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, + const void* inQualifierData, UInt32* ioDataSize, void* outData) +{ + AudioHardwareImpl* obj = GetObject(inObjectID); + if (!obj) + return kAudioHardwareBadObjectError; + + return obj->getPropertyData(inAddress, inQualifierDataSize, inQualifierData, + ioDataSize, outData); +} + +OSStatus AudioObjectSetPropertyData(AudioObjectID inObjectID, + const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, + const void* inQualifierData, UInt32 inDataSize, const void* inData) +{ + AudioHardwareImpl* obj = GetObject(inObjectID); + if (!obj) + return kAudioHardwareBadObjectError; + + return obj->setPropertyData(inAddress, inQualifierDataSize, inQualifierData, + inDataSize, inData); +} + +OSStatus AudioObjectAddPropertyListener(AudioObjectID inObjectID, + const AudioObjectPropertyAddress* inAddress, + AudioObjectPropertyListenerProc inListener, void* inClientData) +{ + AudioHardwareImpl* obj = GetObject(inObjectID); + if (!obj) + return kAudioHardwareBadObjectError; + + return obj->addPropertyListener(inAddress, inListener, inClientData); +} + +OSStatus AudioObjectRemovePropertyListener(AudioObjectID inObjectID, + const AudioObjectPropertyAddress* inAddress, + AudioObjectPropertyListenerProc inListener, void* inClientData) +{ + AudioHardwareImpl* obj = GetObject(inObjectID); + if (!obj) + return kAudioHardwareBadObjectError; + + return obj->removePropertyListener(inAddress, inListener, inClientData); +} + +OSStatus AudioHardwareUnload(void) +{ + g_systemObject.reset(nullptr); + return noErr; +} + +OSStatus AudioHardwareCreateAggregateDevice(CFDictionaryRef, AudioObjectID* outDeviceID) +{ + if (outDeviceID) + *outDeviceID = 0; + + return unimpErr; +} + +OSStatus AudioHardwareDestroyAggregateDevice(AudioObjectID inDeviceID) +{ + return unimpErr; +} + +OSStatus AudioDeviceCreateIOProcID(AudioObjectID inDevice, + AudioDeviceIOProc inProc, void* inClientData, + AudioDeviceIOProcID* outIOProcID) +{ + AudioHardwareImpl* obj = GetObject(inDevice); + if (!obj) + return kAudioHardwareBadObjectError; + + return obj->createIOProcID(inProc, inClientData, outIOProcID); +} + +OSStatus AudioDeviceDestroyIOProcID(AudioObjectID inDevice, + AudioDeviceIOProcID inIOProcID) +{ + AudioHardwareImpl* obj = GetObject(inDevice); + if (!obj) + return kAudioHardwareBadObjectError; + + return obj->destroyIOProcID(inIOProcID); +} + +OSStatus AudioDeviceStart(AudioObjectID inDevice, AudioDeviceIOProcID inProcID) +{ + AudioHardwareImpl* obj = GetObject(inDevice); + if (!obj) + return kAudioHardwareBadObjectError; + + return obj->start(inProcID, nullptr, 0); +} + +OSStatus AudioDeviceStartAtTime(AudioObjectID inDevice, AudioDeviceIOProcID inProcID, + AudioTimeStamp* ioRequestedStartTime, UInt32 inFlags) +{ + AudioHardwareImpl* obj = GetObject(inDevice); + if (!obj) + return kAudioHardwareBadObjectError; + + return obj->start(inProcID, ioRequestedStartTime, inFlags); +} + +OSStatus AudioDeviceStop(AudioObjectID inDevice, AudioDeviceIOProcID inProcID) +{ + AudioHardwareImpl* obj = GetObject(inDevice); + if (!obj) + return kAudioHardwareBadObjectError; + + return obj->stop(inProcID); +} + +OSStatus AudioDeviceGetCurrentTime(AudioObjectID inDevice, AudioTimeStamp* outTime) +{ + AudioHardwareImpl* obj = GetObject(inDevice); + if (!obj) + return kAudioHardwareBadObjectError; + + return obj->getCurrentTime(outTime); +} + +OSStatus AudioDeviceTranslateTime(AudioObjectID inDevice, const AudioTimeStamp* inTime, + AudioTimeStamp* outTime) +{ + AudioHardwareImpl* obj = GetObject(inDevice); + if (!obj) + return kAudioHardwareBadObjectError; + + return obj->translateTime(inTime, outTime); +} + +OSStatus AudioDeviceGetNearestStartTime(AudioObjectID inDevice, + AudioTimeStamp* ioRequestedStartTime, UInt32 inFlags) +{ + AudioHardwareImpl* obj = GetObject(inDevice); + if (!obj) + return kAudioHardwareBadObjectError; + + return obj->getNearestStartTime(ioRequestedStartTime, inFlags); +} diff --git a/src/CoreAudio/AudioHardwareBase.h b/src/CoreAudio/AudioHardwareBase.h index 28492f6ed..cba62a3f9 100644 --- a/src/CoreAudio/AudioHardwareBase.h +++ b/src/CoreAudio/AudioHardwareBase.h @@ -20,6 +20,50 @@ struct AudioObjectPropertyAddress AudioObjectPropertyElement mElement; }; +enum +{ + kAudioHardwareNoError = 0, + kAudioHardwareNotRunningError = 'stop', + kAudioHardwareUnspecifiedError = 'what', + kAudioHardwareUnknownPropertyError = 'who?', + kAudioHardwareBadPropertySizeError = '!siz', + kAudioHardwareIllegalOperationError = 'nope', + kAudioHardwareBadObjectError = '!obj', + kAudioHardwareBadDeviceError = '!dev', + kAudioHardwareBadStreamError = '!str', + kAudioHardwareUnsupportedOperationError = 'unop', + kAudioDeviceUnsupportedFormatError = '!dat', + kAudioDevicePermissionsError = '!hog', +}; + +enum +{ + kAudioObjectPropertyScopeGlobal = 'glob', + kAudioObjectPropertyScopeInput = 'inpt', + kAudioObjectPropertyScopeOutput = 'outp', + kAudioObjectPropertyScopePlayThrough = 'ptru', + kAudioObjectPropertyElementMaster = 0, +}; + +enum +{ + kAudioObjectPropertyBaseClass = 'bcls', + kAudioObjectPropertyClass = 'clas', + kAudioObjectPropertyOwner = 'stdv', + kAudioObjectPropertyName = 'lnam', + kAudioObjectPropertyModelName = 'lmod', + kAudioObjectPropertyManufacturer = 'lmak', + kAudioObjectPropertyElementName = 'lchn', + kAudioObjectPropertyElementCategoryName = 'lccn', + kAudioObjectPropertyElementNumberName = 'lcnn', + kAudioObjectPropertyOwnedObjects = 'ownd', + kAudioObjectPropertyIdentify = 'iden', + kAudioObjectPropertySerialNumber = 'snum', + kAudioObjectPropertyFirmwareVersion = 'fwvn', +}; + +// TODO: A lot more is missing + #ifdef __cplusplus } #endif diff --git a/src/CoreAudio/AudioHardwareImpl.cpp b/src/CoreAudio/AudioHardwareImpl.cpp new file mode 100644 index 000000000..0960211d0 --- /dev/null +++ b/src/CoreAudio/AudioHardwareImpl.cpp @@ -0,0 +1,88 @@ +/* +This file is part of Darling. + +Copyright (C) 2015-2016 Lubos Dolezel + +Darling is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Darling is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Darling. If not, see . +*/ + +#include "AudioHardwareImpl.h" +#include +#include + +AudioHardwareImpl::AudioHardwareImpl() +{ +} + + +AudioHardwareImpl::~AudioHardwareImpl() +{ +} + +void AudioHardwareImpl::show() +{ + std::cout << typeid(*this).name() << std::endl; +} + +OSStatus AudioHardwareImpl::createIOProcID(AudioDeviceIOProc inProc, void* inClientData, + AudioDeviceIOProcID* outIOProcID) +{ + std::lock_guard guard(m_procMutex); + + if (!outIOProcID || !inProc) + return paramErr; + + *outIOProcID = reinterpret_cast(m_nextProcId++); + m_proc[*outIOProcID] = std::pair(inProc, inClientData); + + return noErr; +} + +OSStatus AudioHardwareImpl::destroyIOProcID(AudioDeviceIOProcID inIOProcID) +{ + std::lock_guard guard(m_procMutex); + auto it = m_proc.find(inIOProcID); + + if (it == m_proc.end()) + return paramErr; + + m_proc.erase(it); + return noErr; +} + +OSStatus AudioHardwareImpl::start(AudioDeviceIOProcID inProcID, + AudioTimeStamp* ioRequestedStartTime, UInt32 inFlags) +{ + AudioHardwareStream* stream; + + if (m_streams.find(inProcID) != m_streams.end()) + return noErr; + + stream = createStream(inProcID); + m_streams[inProcID] = stream; + + // TODO: time + + return stream; +} + +OSStatus AudioHardwareImpl::stop(AudioDeviceIOProcID inProcID) +{ + auto it = m_streams.find(inProcID); + if (it == m_streams.end()) + return kAudioHardwareNotRunningError; + + m_streams.erase(it); + return noErr; +} diff --git a/src/CoreAudio/AudioHardwareImpl.h b/src/CoreAudio/AudioHardwareImpl.h new file mode 100644 index 000000000..47a4cde6d --- /dev/null +++ b/src/CoreAudio/AudioHardwareImpl.h @@ -0,0 +1,78 @@ +/* +This file is part of Darling. + +Copyright (C) 2015-2016 Lubos Dolezel + +Darling is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Darling is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Darling. If not, see . +*/ + +#ifndef AUDIOHARDWAREIMPL_H +#define AUDIOHARDWAREIMPL_H +#include +#include +#include +#include "AudioHardwareStream.h" + +class AudioHardwareImpl +{ +public: + AudioHardwareImpl(); + virtual ~AudioHardwareImpl(); + + virtual void show(); + virtual bool hasProperty(const AudioObjectPropertyAddress* address); + virtual OSStatus getPropertyDataSize(const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, + const void* inQualifierData, UInt32* outDataSize); + + virtual OSStatus isPropertySettable(const AudioObjectPropertyAddress* inAddress, Boolean* outIsSettable); + + virtual OSStatus getPropertyData(const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, + const void* inQualifierData, UInt32* ioDataSize, void* outData); + + virtual OSStatus setPropertyData(const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, + const void* inQualifierData, UInt32 inDataSize, const void* inData); + + virtual OSStatus addPropertyListener(const AudioObjectPropertyAddress* inAddress, + AudioObjectPropertyListenerProc inListener, void* inClientData); + + virtual OSStatus removePropertyListener(const AudioObjectPropertyAddress* inAddress, + AudioObjectPropertyListenerProc inListener, void* inClientData); + + OSStatus createIOProcID(AudioDeviceIOProc inProc, void* inClientData, + AudioDeviceIOProcID* outIOProcID); + OSStatus destroyIOProcID(AudioDeviceIOProcID inIOProcID); + + virtual OSStatus start(AudioDeviceIOProcID inProcID, + AudioTimeStamp* ioRequestedStartTime, UInt32 inFlags); + virtual OSStatus stop(AudioDeviceIOProcID inProcID); + + virtual OSStatus getCurrentTime(AudioTimeStamp* outTime) = 0; + + virtual OSStatus translateTime(const AudioTimeStamp* inTime, + AudioTimeStamp* outTime) = 0; + + virtual OSStatus getNearestStartTime(AudioTimeStamp* ioRequestedStartTime, + UInt32 inFlags) = 0; +protected: + virtual AudioHardwareStream* createStream(AudioDeviceIOProcID procID) = 0; +protected: + std::mutex m_procMutex; + std::map> m_proc; + int m_nextProcId = 1; + + std::map m_streams; +}; + +#endif /* AUDIOHARDWAREIMPL_H */ + diff --git a/src/CoreAudio/AudioHardwareStream.cpp b/src/CoreAudio/AudioHardwareStream.cpp new file mode 100644 index 000000000..9d3b1d6ca --- /dev/null +++ b/src/CoreAudio/AudioHardwareStream.cpp @@ -0,0 +1,29 @@ +/* +This file is part of Darling. + +Copyright (C) 2015-2016 Lubos Dolezel + +Darling is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Darling is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Darling. If not, see . +*/ + +#include "AudioHardwareStream.h" + +AudioHardwareStream::AudioHardwareStream() +{ +} + +AudioHardwareStream::~AudioHardwareStream() +{ +} + diff --git a/src/CoreAudio/AudioHardwareStream.h b/src/CoreAudio/AudioHardwareStream.h new file mode 100644 index 000000000..dc4509c41 --- /dev/null +++ b/src/CoreAudio/AudioHardwareStream.h @@ -0,0 +1,33 @@ +/* +This file is part of Darling. + +Copyright (C) 2015-2016 Lubos Dolezel + +Darling is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Darling is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Darling. If not, see . +*/ + +#ifndef AUDIOHARDWARESTREAM_H +#define AUDIOHARDWARESTREAM_H + +class AudioHardwareStream +{ +public: + AudioHardwareStream(); + virtual ~AudioHardwareStream(); +private: + +}; + +#endif /* AUDIOHARDWARESTREAM_H */ +