Something went wrong. Try again.
Cider Isn't Darwin Emulation, Really
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283#include "AudioUnitBase.h"#include "AudioUnitProperties.h"#include "AudioUnitRenderer.h"#include <CoreServices/MacErrors.h>#include <util/debug.h>#include <cstring>
AudioUnitComponent::AudioUnitComponent(std::initializer_list<CFStringRef> elements){ m_elementNames.insert(m_elementNames.end(), elements.begin(), elements.end()); m_config.resize(m_elementNames.size()); // Default audio params const AudioStreamBasicDescription defaultConfig = AudioStreamBasicDescription { 44100.0, kAudioFormatLinearPCM, kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked, 4, 1, 4, 2, 16, 0 }; for (size_t i = 0; i < m_config.size(); i++) { m_config[i] = std::pair<AudioStreamBasicDescription, AudioStreamBasicDescription>(defaultConfig, defaultConfig); } memset(&m_inputUnit, 0, sizeof(m_inputUnit));}
AudioUnitComponent::~AudioUnitComponent(){ if (m_contextName != nullptr) CFRelease(m_contextName); CloseComponent(m_inputUnit.sourceAudioUnit);}
OSStatus AudioUnitComponent::getPropertyInfo(AudioUnitPropertyID prop, AudioUnitScope scope, AudioUnitElement elem, UInt32* dataSize, Boolean* writable){ switch (prop) { case kAudioUnitProperty_StreamFormat: *dataSize = sizeof(AudioStreamBasicDescription); *writable = true; break; case kAudioOutputUnitProperty_EnableIO: *dataSize = sizeof(UInt32); *writable = true; break; case kAudioUnitProperty_SetRenderCallback: *dataSize = sizeof(AURenderCallbackStruct); *writable = true; break; case kAudioUnitProperty_ShouldAllocateBuffer: *dataSize = sizeof(int); *writable = true; break; case kAudioUnitProperty_ElementCount: *dataSize = sizeof(UInt32); *writable = false; break; case kAudioUnitProperty_LastRenderError: // TODO: implement *dataSize = sizeof(OSStatus); *writable = false; break; case kAudioUnitProperty_SampleRate: // TODO: implement *dataSize = sizeof(Float64); *writable = true; // TODO: query itself on kAudioUnitProperty_StreamFormat if writable break; case kAudioUnitProperty_ElementName: *dataSize = sizeof(CFStringRef); *writable = false; break; case kAudioUnitProperty_ContextName: *dataSize = sizeof(CFStringRef); *writable = true; break; default: return kAudioUnitErr_InvalidProperty; }
return noErr;}
OSStatus AudioUnitComponent::setProperty(AudioUnitPropertyID prop, AudioUnitScope scope, AudioUnitElement elem, const void* data, UInt32 dataSize){ TRACE5(prop, scope, elem, data, dataSize);
switch (prop) { case kAudioUnitProperty_StreamFormat: { const AudioStreamBasicDescription* newConfig = static_cast<const AudioStreamBasicDescription*>(data); if (dataSize != sizeof(*newConfig)) return kAudioUnitErr_InvalidParameter; if (elem >= m_config.size()) return kAudioUnitErr_InvalidElement;
// TODO: perform validation
if (scope == kAudioUnitScope_Output) m_config[elem].second = *newConfig; else if (scope == kAudioUnitScope_Input) m_config[elem].first = *newConfig; else if (scope == kAudioUnitScope_Global) m_config[0].second = *newConfig; else return kAudioUnitErr_InvalidScope;
return noErr; } case kAudioUnitProperty_SetRenderCallback: { if (dataSize != sizeof(AURenderCallbackStruct)) return kAudioUnitErr_InvalidParameter; //if (scope == kAudioUnitScope_Input) //{ if (elem != 0) return kAudioUnitErr_InvalidElement; CloseComponent(m_inputUnit.sourceAudioUnit); // TODO: wrong, we may not own the unit! m_inputUnit.sourceOutputNumber = 0; m_inputUnit.destInputNumber = 0; m_inputUnit.sourceAudioUnit = new AudioUnitRenderer(*(AURenderCallbackStruct*) data); //} //else // return kAudioUnitErr_InvalidScope; return noErr; } case kAudioUnitProperty_MakeConnection: { if (dataSize != sizeof(AudioUnitConnection)) return kAudioUnitErr_InvalidParameter; if (scope != kAudioUnitScope_Input) return kAudioUnitErr_InvalidScope; // TODO: support multiple units! // TODO: reconfigure input format based on output format CloseComponent(m_inputUnit.sourceAudioUnit); // TODO: wrong, we may not own the unit! memcpy(&m_inputUnit, data, sizeof(AudioUnitConnection)); return noErr; } case kAudioUnitProperty_ShouldAllocateBuffer: { int* b = (int*) data; if (dataSize < sizeof(int)) return kAudioUnitErr_InvalidParameter; m_shouldAllocateBuffer = *b != 0; return noErr; } case kAudioUnitProperty_ContextName: { if (dataSize < sizeof(CFStringRef)) return kAudioUnitErr_InvalidParameter; if (data == nullptr) { if (m_contextName != nullptr) { CFRelease(m_contextName); m_contextName = nullptr; } } else { m_contextName = (CFStringRef) data; CFRetain(m_contextName); } return noErr; } default: return kAudioUnitErr_InvalidProperty; }}
OSStatus AudioUnitComponent::getProperty(AudioUnitPropertyID prop, AudioUnitScope scope, AudioUnitElement elem, void* data, UInt32* dataSize){ TRACE5(prop, scope, elem, data, dataSize);
switch (prop) { case kAudioUnitProperty_StreamFormat: { AudioStreamBasicDescription* newConfig = static_cast<AudioStreamBasicDescription*>(data); if (*dataSize < sizeof(AudioStreamBasicDescription)) return kAudioUnitErr_InvalidParameter; if (elem >= m_config.size()) return kAudioUnitErr_InvalidElement;
if (scope == kAudioUnitScope_Output) *newConfig = m_config[elem].second; else if (scope == kAudioUnitScope_Input) *newConfig = m_config[elem].first; else if (scope == kAudioUnitScope_Global) *newConfig = m_config[0].second; else return kAudioUnitErr_InvalidScope;
*dataSize = sizeof(AudioStreamBasicDescription);
return noErr; } case kAudioUnitProperty_ShouldAllocateBuffer: { int* out = (int*) data; if (*dataSize < sizeof(UInt32)) return kAudioUnitErr_InvalidParameter; *out = m_shouldAllocateBuffer; return noErr; } case kAudioUnitProperty_ElementCount: { UInt32* out = (UInt32*) data; if (*dataSize < sizeof(UInt32)) return kAudioUnitErr_InvalidParameter; *out = m_config.size(); return noErr; } case kAudioUnitProperty_ElementName: { CFStringRef* out = (CFStringRef*) data; if (*dataSize != sizeof(CFStringRef)) return kAudioUnitErr_InvalidParameter; if (elem >= m_elementNames.size()) return kAudioUnitErr_InvalidElement; *out = m_elementNames[elem]; return noErr; } case kAudioUnitProperty_ContextName: { CFStringRef* out = (CFStringRef*) data; if (*dataSize != sizeof(CFStringRef)) return kAudioUnitErr_InvalidParameter; *out = m_contextName; return noErr; } default: return kAudioUnitErr_InvalidProperty; }}
OSStatus AudioUnitComponent::addRenderNotify(AURenderCallback inProc, void* opaque){ std::lock_guard<std::mutex> guard(m_listenersMutex); if (!inProc) return paramErr; m_listeners.insert(std::pair<AURenderCallback,void*>(inProc, opaque)); return noErr;}
OSStatus AudioUnitComponent::removeRenderNotify(AURenderCallback inProc, void* opaque){ std::lock_guard<std::mutex> guard(m_listenersMutex); m_listeners.erase(std::pair<AURenderCallback,void*>(inProc, opaque)); return noErr;}
OSStatus AudioUnitComponent::notifyListeners(AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData){ std::lock_guard<std::mutex> guard(m_listenersMutex); OSStatus status = noErr; for (auto p : m_listeners) { status = p.first(p.second, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData); if (status != noErr) break; } return status;}