Something went wrong. Try again.
Cider Isn't Darwin Emulation, Really
Something went wrong. Try again.
11 kB · 414 lines
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415/*This file is part of Darling.
Copyright (C) 2020 Lubos Dolezel
Darling is free software: you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.
You should have received a copy of the GNU General Public Licensealong with Darling. If not, see <http://www.gnu.org/licenses/>.*/#include "AudioComponentManager.h"#include <cstdlib>#include <CoreFoundation/CoreFoundation.h>#include <CarbonCore/MacErrors.h>
AudioComponentManager::AudioComponentManager(){ discoverComponents();}
void AudioComponentManager::discoverComponents(){ discoverComponents("/System/Library/Components"); discoverComponents("/Library/Components");
const char* home = ::getenv("HOME"); if (home != NULL) { std::string userPath = home; userPath += "/Library/Audio/Plug-Ins/Components";
discoverComponents(userPath.c_str()); }}
void AudioComponentManager::discoverComponents(const char* dir){ CFArrayRef componentBundles; CFURLRef urlDir; CFStringRef strDir;
strDir = CFStringCreateWithCStringNoCopy(nullptr, dir, kCFStringEncodingUTF8, kCFAllocatorNull); urlDir = CFURLCreateWithFileSystemPath(nullptr, strDir, kCFURLPOSIXPathStyle, true); CFRelease(strDir);
componentBundles = CFBundleCreateBundlesFromDirectory(nullptr, urlDir, CFSTR("component"));
CFRelease(urlDir);
for (CFIndex i = 0; i < CFArrayGetCount(componentBundles); i++) { CFBundleRef bundle = (CFBundleRef) CFArrayGetValueAtIndex(componentBundles, i); analyzeComponent(bundle); CFRelease(bundle); }
CFRelease(componentBundles);}
static bool isString(CFStringRef str){ if (!str) return false; if (CFGetTypeID(str) != CFStringGetTypeID()) return false; return true;}
static UInt32 stringToFourCC(CFStringRef str){ union { char chars[5]; // CFStringGetCString requires space for the NUL character uint32_t code; } cc;
if (CFStringGetLength(str) != 4) return 0; if (!CFStringGetCString(str, cc.chars, 5, kCFStringEncodingUTF8)) return 0;
#if __LITTLE_ENDIAN__ cc.code = __builtin_bswap32(cc.code);#endif
return cc.code;}
void AudioComponentManager::analyzeComponent(CFBundleRef bundle){ CFDictionaryRef dict = CFBundleGetInfoDictionary(bundle); CFArrayRef components = (CFArrayRef) CFDictionaryGetValue(dict, CFSTR("AudioComponents"));
if (!components || CFGetTypeID(components) != CFArrayGetTypeID()) return;
for (CFIndex i = 0; i < CFArrayGetCount(components); i++) { CFDictionaryRef props = (CFDictionaryRef) CFArrayGetValueAtIndex(components, i); if (!props || CFGetTypeID(props) != CFDictionaryGetTypeID()) continue;
CFStringRef name, manufacturer, type, subtype, factoryFunction; CFNumberRef version; CFBooleanRef sandboxSafe;
name = (CFStringRef) CFDictionaryGetValue(props, CFSTR("name")); manufacturer = (CFStringRef) CFDictionaryGetValue(props, CFSTR("manufacturer")); type = (CFStringRef) CFDictionaryGetValue(props, CFSTR("type")); subtype = (CFStringRef) CFDictionaryGetValue(props, CFSTR("subtype")); factoryFunction = (CFStringRef) CFDictionaryGetValue(props, CFSTR("factoryFunction"));
if (!isString(name) || !isString(manufacturer) || !isString(type) || !isString(subtype) || !isString(factoryFunction)) continue;
version = (CFNumberRef) CFDictionaryGetValue(props, CFSTR("version")); sandboxSafe = (CFBooleanRef) CFDictionaryGetValue(props, CFSTR("sandboxSafe"));
if (version && CFGetTypeID(version) != CFNumberGetTypeID()) version = nullptr;
if (!sandboxSafe) sandboxSafe = kCFBooleanFalse;
CFURLRef bundleUrl = CFBundleCopyBundleURL(bundle); CFStringRef bundlePath = CFURLCopyFileSystemPath(bundleUrl, kCFURLPOSIXPathStyle); CFRelease(bundleUrl);
AudioComponentDescription desc; desc.componentType = stringToFourCC(type); desc.componentSubType = stringToFourCC(subtype); desc.componentManufacturer = stringToFourCC(manufacturer); desc.componentFlags = 0; desc.componentFlagsMask = 0;
AudioComponentFlags flags = 0; if (sandboxSafe == kCFBooleanTrue) flags |= kAudioComponentFlag_SandboxSafe;
UInt32 versionValue = 0; if (version) CFNumberGetValue(version, kCFNumberSInt32Type, &versionValue);
registerComponent(&desc, CFStringGetCStringPtr(name, kCFStringEncodingUTF8), versionValue, CFStringGetCStringPtr(bundlePath, kCFStringEncodingUTF8), CFStringGetCStringPtr(factoryFunction, kCFStringEncodingUTF8), flags);
CFRelease(bundlePath); }}
AudioComponentManager* AudioComponentManager::instance(){ static AudioComponentManager inst; return &inst;}
bool AudioComponentManager::isOurInstance(AudioComponentInstance instance){ uint32_t v = uint32_t(uintptr_t(instance)); return v & 0x80000000;}
bool AudioComponentManager::isOurInstance(AudioComponent component){ return isOurInstance(AudioComponentInstance(component));}
/*AudioComponentInstance AudioComponentManager::audioUnitToInstance(AudioUnit unit){ uint32_t v = uint32_t(uintptr_t(unit)); if (v & 0x80000000) { v &= 0x7fffffff; return AudioComponentInstance(uintptr_t(v)); } return nullptr;}*/
std::vector<AudioComponent> AudioComponentManager::findMatching(const AudioComponentDescription* cd){ std::vector<AudioComponent> rv; std::unique_lock<std::recursive_mutex> l(m_componentsMutex);
for (auto const& [componentId, d] : m_components) { if (!cd->componentManufacturer || cd->componentManufacturer == d.desc.componentManufacturer) { if (!cd->componentSubType || cd->componentSubType == d.desc.componentSubType) { if (!cd->componentType || cd->componentType == d.desc.componentType) { if (d.flags & kAudioComponentFlag_Unsearchable) { if (!cd->componentManufacturer || !cd->componentSubType || !cd->componentType) continue; } rv.push_back(d.id); } } } }
return rv;}
AudioComponent AudioComponentManager::registerComponent(const AudioComponentDescription* desc, const char* name, uint32_t version, AudioComponentFactoryFunction factory){ std::unique_lock<std::recursive_mutex> l(m_componentsMutex);
RegisteredComponent rc; rc.desc = *desc; rc.name = name; rc.version = version; rc.factory = factory; rc.id = (AudioComponent) uintptr_t(m_nextComponentId++);
m_components.insert({ rc.id, rc });
return rc.id;}
AudioComponent AudioComponentManager::registerComponent(const AudioComponentDescription* desc, const char* name, uint32_t version, const char* bundlePath, const char* entryPointName, AudioComponentFlags flags){ std::unique_lock<std::recursive_mutex> l(m_componentsMutex);
RegisteredComponent rc; rc.desc = *desc; rc.name = name; rc.version = version; rc.factory = nullptr; rc.bundlePath = bundlePath; rc.entryPointName = entryPointName; rc.id = (AudioComponent) uintptr_t(m_nextComponentId++); rc.flags = flags;
m_components.insert({ rc.id, rc });
return rc.id;}
CFBundleRef AudioComponentManager::bundleFromPath(const char* path){ CFStringRef cfpath = CFStringCreateWithCString(nullptr, path, kCFStringEncodingUTF8);
CFURLRef url = CFURLCreateWithFileSystemPath(nullptr, cfpath, kCFURLPOSIXPathStyle, true); CFRelease(cfpath);
CFBundleRef bundle = CFBundleCreate(nullptr, url); CFRelease(url);
return bundle;}
OSStatus AudioComponentManager::instantiate(AudioComponent c, AudioComponentInstance* out){ std::unique_lock<std::recursive_mutex> l(m_componentsMutex);
*out = nullptr;
auto it = m_components.find(c); if (it == m_components.end()) return invalidComponentID;
RegisteredComponent& regd = it->second; if (!regd.factory) { // Load the bundle CFBundleRef bundle = bundleFromPath(regd.bundlePath.c_str());
if (!bundle) return invalidComponentID;
CFStringRef factoryName = CFStringCreateWithCString(nullptr, regd.entryPointName.c_str(), kCFStringEncodingUTF8); regd.factory = (AudioComponentFactoryFunction) CFBundleGetFunctionPointerForName(bundle, factoryName); CFRelease(factoryName);
if (!regd.factory) { CFRelease(bundle); return invalidComponentID; }
regd.loadedBundle = bundle; }
std::unique_lock<std::recursive_mutex> l2(m_componentInstancesMutex);
ComponentInstanceData cid; *out = (AudioComponentInstance) uintptr_t(m_nextComponentInstanceId++);
cid.component = c; cid.object = regd.factory(®d.desc);
if (!cid.object) return invalidComponentID;
m_componentInstances.insert({ *out, cid });
OSStatus status = cid.object->Open(cid.object, *out); if (status != noErr) { dispose(*out); *out = nullptr; return status; } regd.instances++;
return status;}
OSStatus AudioComponentManager::dispose(AudioComponentInstance instance){ std::unique_lock<std::recursive_mutex> l2(m_componentInstancesMutex); auto it = m_componentInstances.find(instance); if (it == m_componentInstances.end()) return badComponentInstance;
ComponentInstanceData& cid = it->second; OSStatus status = cid.object->Close(cid.object);
std::unique_lock<std::recursive_mutex> l(m_componentsMutex); auto itComp = m_components.find(cid.component); if (itComp != m_components.end()) { RegisteredComponent& regd = itComp->second; regd.instances--;
if (regd.instances == 0 && regd.loadedBundle != nullptr) { CFRelease(regd.loadedBundle); regd.loadedBundle = nullptr; regd.factory = nullptr; } }
m_componentInstances.erase(it); return status;}
AudioComponentPlugInInterface* AudioComponentManager::instanceInterface(AudioComponentInstance instance){ std::unique_lock<std::recursive_mutex> l2(m_componentInstancesMutex); auto it = m_componentInstances.find(instance); if (it == m_componentInstances.end()) return nullptr;
return it->second.object;}
AudioComponentManager::RegisteredComponent* AudioComponentManager::getById(AudioComponent component){ auto itComp = m_components.find(component); if (itComp != m_components.end()) return &itComp->second; return nullptr;}
OSStatus AudioComponentManager::getDescription(AudioComponent c, AudioComponentDescription* out){ std::unique_lock<std::recursive_mutex> l(m_componentsMutex); RegisteredComponent* regd = getById(c);
if (!regd) return invalidComponentID;
*out = regd->desc; return noErr;}
OSStatus AudioComponentManager::getName(AudioComponent c, const char** name){ std::unique_lock<std::recursive_mutex> l(m_componentsMutex); RegisteredComponent* regd = getById(c);
if (!regd) return invalidComponentID;
*name = regd->name.c_str(); return noErr;}
OSStatus AudioComponentManager::getVersion(AudioComponent c, uint32_t* version){ std::unique_lock<std::recursive_mutex> l(m_componentsMutex); RegisteredComponent* regd = getById(c);
if (!regd) return invalidComponentID;
*version = regd->version; return noErr;}
AudioComponent AudioComponentManager::getComponent(AudioComponentInstance instance){ std::unique_lock<std::recursive_mutex> l2(m_componentInstancesMutex); auto it = m_componentInstances.find(instance); if (it == m_componentInstances.end()) return nullptr;
return it->second.component;}