this repo has no description
at fixPythonPipStalling 414 lines 11 kB view raw
1/* 2This file is part of Darling. 3 4Copyright (C) 2020 Lubos Dolezel 5 6Darling is free software: you can redistribute it and/or modify 7it under the terms of the GNU General Public License as published by 8the Free Software Foundation, either version 3 of the License, or 9(at your option) any later version. 10 11Darling is distributed in the hope that it will be useful, 12but WITHOUT ANY WARRANTY; without even the implied warranty of 13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14GNU General Public License for more details. 15 16You should have received a copy of the GNU General Public License 17along with Darling. If not, see <http://www.gnu.org/licenses/>. 18*/ 19#include "AudioComponentManager.h" 20#include <cstdlib> 21#include <CoreFoundation/CoreFoundation.h> 22#include <CarbonCore/MacErrors.h> 23 24AudioComponentManager::AudioComponentManager() 25{ 26 discoverComponents(); 27} 28 29void AudioComponentManager::discoverComponents() 30{ 31 discoverComponents("/System/Library/Components"); 32 discoverComponents("/Library/Components"); 33 34 const char* home = ::getenv("HOME"); 35 if (home != NULL) 36 { 37 std::string userPath = home; 38 userPath += "/Library/Audio/Plug-Ins/Components"; 39 40 discoverComponents(userPath.c_str()); 41 } 42} 43 44void AudioComponentManager::discoverComponents(const char* dir) 45{ 46 CFArrayRef componentBundles; 47 CFURLRef urlDir; 48 CFStringRef strDir; 49 50 strDir = CFStringCreateWithCStringNoCopy(nullptr, dir, kCFStringEncodingUTF8, kCFAllocatorNull); 51 urlDir = CFURLCreateWithFileSystemPath(nullptr, strDir, kCFURLPOSIXPathStyle, true); 52 CFRelease(strDir); 53 54 componentBundles = CFBundleCreateBundlesFromDirectory(nullptr, urlDir, CFSTR("component")); 55 56 CFRelease(urlDir); 57 58 for (CFIndex i = 0; i < CFArrayGetCount(componentBundles); i++) 59 { 60 CFBundleRef bundle = (CFBundleRef) CFArrayGetValueAtIndex(componentBundles, i); 61 analyzeComponent(bundle); 62 CFRelease(bundle); 63 } 64 65 CFRelease(componentBundles); 66} 67 68static bool isString(CFStringRef str) 69{ 70 if (!str) 71 return false; 72 if (CFGetTypeID(str) != CFStringGetTypeID()) 73 return false; 74 return true; 75} 76 77static UInt32 stringToFourCC(CFStringRef str) 78{ 79 union { 80 char chars[5]; // CFStringGetCString requires space for the NUL character 81 uint32_t code; 82 } cc; 83 84 if (CFStringGetLength(str) != 4) 85 return 0; 86 if (!CFStringGetCString(str, cc.chars, 5, kCFStringEncodingUTF8)) 87 return 0; 88 89#if __LITTLE_ENDIAN__ 90 cc.code = __builtin_bswap32(cc.code); 91#endif 92 93 return cc.code; 94} 95 96void AudioComponentManager::analyzeComponent(CFBundleRef bundle) 97{ 98 CFDictionaryRef dict = CFBundleGetInfoDictionary(bundle); 99 CFArrayRef components = (CFArrayRef) CFDictionaryGetValue(dict, CFSTR("AudioComponents")); 100 101 if (!components || CFGetTypeID(components) != CFArrayGetTypeID()) 102 return; 103 104 for (CFIndex i = 0; i < CFArrayGetCount(components); i++) 105 { 106 CFDictionaryRef props = (CFDictionaryRef) CFArrayGetValueAtIndex(components, i); 107 if (!props || CFGetTypeID(props) != CFDictionaryGetTypeID()) 108 continue; 109 110 CFStringRef name, manufacturer, type, subtype, factoryFunction; 111 CFNumberRef version; 112 CFBooleanRef sandboxSafe; 113 114 name = (CFStringRef) CFDictionaryGetValue(props, CFSTR("name")); 115 manufacturer = (CFStringRef) CFDictionaryGetValue(props, CFSTR("manufacturer")); 116 type = (CFStringRef) CFDictionaryGetValue(props, CFSTR("type")); 117 subtype = (CFStringRef) CFDictionaryGetValue(props, CFSTR("subtype")); 118 factoryFunction = (CFStringRef) CFDictionaryGetValue(props, CFSTR("factoryFunction")); 119 120 if (!isString(name) || !isString(manufacturer) || !isString(type) || !isString(subtype) || !isString(factoryFunction)) 121 continue; 122 123 version = (CFNumberRef) CFDictionaryGetValue(props, CFSTR("version")); 124 sandboxSafe = (CFBooleanRef) CFDictionaryGetValue(props, CFSTR("sandboxSafe")); 125 126 if (version && CFGetTypeID(version) != CFNumberGetTypeID()) 127 version = nullptr; 128 129 if (!sandboxSafe) 130 sandboxSafe = kCFBooleanFalse; 131 132 CFURLRef bundleUrl = CFBundleCopyBundleURL(bundle); 133 CFStringRef bundlePath = CFURLCopyFileSystemPath(bundleUrl, kCFURLPOSIXPathStyle); 134 CFRelease(bundleUrl); 135 136 AudioComponentDescription desc; 137 desc.componentType = stringToFourCC(type); 138 desc.componentSubType = stringToFourCC(subtype); 139 desc.componentManufacturer = stringToFourCC(manufacturer); 140 desc.componentFlags = 0; 141 desc.componentFlagsMask = 0; 142 143 AudioComponentFlags flags = 0; 144 if (sandboxSafe == kCFBooleanTrue) 145 flags |= kAudioComponentFlag_SandboxSafe; 146 147 UInt32 versionValue = 0; 148 if (version) 149 CFNumberGetValue(version, kCFNumberSInt32Type, &versionValue); 150 151 registerComponent(&desc, CFStringGetCStringPtr(name, kCFStringEncodingUTF8), versionValue, 152 CFStringGetCStringPtr(bundlePath, kCFStringEncodingUTF8), CFStringGetCStringPtr(factoryFunction, kCFStringEncodingUTF8), 153 flags); 154 155 CFRelease(bundlePath); 156 } 157} 158 159AudioComponentManager* AudioComponentManager::instance() 160{ 161 static AudioComponentManager inst; 162 return &inst; 163} 164 165bool AudioComponentManager::isOurInstance(AudioComponentInstance instance) 166{ 167 uint32_t v = uint32_t(uintptr_t(instance)); 168 return v & 0x80000000; 169} 170 171bool AudioComponentManager::isOurInstance(AudioComponent component) 172{ 173 return isOurInstance(AudioComponentInstance(component)); 174} 175 176/* 177AudioComponentInstance AudioComponentManager::audioUnitToInstance(AudioUnit unit) 178{ 179 uint32_t v = uint32_t(uintptr_t(unit)); 180 if (v & 0x80000000) 181 { 182 v &= 0x7fffffff; 183 return AudioComponentInstance(uintptr_t(v)); 184 } 185 return nullptr; 186} 187*/ 188 189std::vector<AudioComponent> AudioComponentManager::findMatching(const AudioComponentDescription* cd) 190{ 191 std::vector<AudioComponent> rv; 192 std::unique_lock<std::recursive_mutex> l(m_componentsMutex); 193 194 for (auto const& [componentId, d] : m_components) 195 { 196 if (!cd->componentManufacturer || cd->componentManufacturer == d.desc.componentManufacturer) 197 { 198 if (!cd->componentSubType || cd->componentSubType == d.desc.componentSubType) 199 { 200 if (!cd->componentType || cd->componentType == d.desc.componentType) 201 { 202 if (d.flags & kAudioComponentFlag_Unsearchable) 203 { 204 if (!cd->componentManufacturer || !cd->componentSubType || !cd->componentType) 205 continue; 206 } 207 rv.push_back(d.id); 208 } 209 } 210 } 211 } 212 213 return rv; 214} 215 216AudioComponent AudioComponentManager::registerComponent(const AudioComponentDescription* desc, const char* name, 217 uint32_t version, AudioComponentFactoryFunction factory) 218{ 219 std::unique_lock<std::recursive_mutex> l(m_componentsMutex); 220 221 RegisteredComponent rc; 222 rc.desc = *desc; 223 rc.name = name; 224 rc.version = version; 225 rc.factory = factory; 226 rc.id = (AudioComponent) uintptr_t(m_nextComponentId++); 227 228 m_components.insert({ rc.id, rc }); 229 230 return rc.id; 231} 232 233AudioComponent AudioComponentManager::registerComponent(const AudioComponentDescription* desc, const char* name, 234 uint32_t version, const char* bundlePath, const char* entryPointName, AudioComponentFlags flags) 235{ 236 std::unique_lock<std::recursive_mutex> l(m_componentsMutex); 237 238 RegisteredComponent rc; 239 rc.desc = *desc; 240 rc.name = name; 241 rc.version = version; 242 rc.factory = nullptr; 243 rc.bundlePath = bundlePath; 244 rc.entryPointName = entryPointName; 245 rc.id = (AudioComponent) uintptr_t(m_nextComponentId++); 246 rc.flags = flags; 247 248 m_components.insert({ rc.id, rc }); 249 250 return rc.id; 251} 252 253CFBundleRef AudioComponentManager::bundleFromPath(const char* path) 254{ 255 CFStringRef cfpath = CFStringCreateWithCString(nullptr, path, kCFStringEncodingUTF8); 256 257 CFURLRef url = CFURLCreateWithFileSystemPath(nullptr, cfpath, kCFURLPOSIXPathStyle, true); 258 CFRelease(cfpath); 259 260 CFBundleRef bundle = CFBundleCreate(nullptr, url); 261 CFRelease(url); 262 263 return bundle; 264} 265 266OSStatus AudioComponentManager::instantiate(AudioComponent c, AudioComponentInstance* out) 267{ 268 std::unique_lock<std::recursive_mutex> l(m_componentsMutex); 269 270 *out = nullptr; 271 272 auto it = m_components.find(c); 273 if (it == m_components.end()) 274 return invalidComponentID; 275 276 RegisteredComponent& regd = it->second; 277 if (!regd.factory) 278 { 279 // Load the bundle 280 CFBundleRef bundle = bundleFromPath(regd.bundlePath.c_str()); 281 282 if (!bundle) 283 return invalidComponentID; 284 285 CFStringRef factoryName = CFStringCreateWithCString(nullptr, regd.entryPointName.c_str(), kCFStringEncodingUTF8); 286 regd.factory = (AudioComponentFactoryFunction) CFBundleGetFunctionPointerForName(bundle, factoryName); 287 CFRelease(factoryName); 288 289 if (!regd.factory) 290 { 291 CFRelease(bundle); 292 return invalidComponentID; 293 } 294 295 regd.loadedBundle = bundle; 296 } 297 298 std::unique_lock<std::recursive_mutex> l2(m_componentInstancesMutex); 299 300 ComponentInstanceData cid; 301 *out = (AudioComponentInstance) uintptr_t(m_nextComponentInstanceId++); 302 303 cid.component = c; 304 cid.object = regd.factory(&regd.desc); 305 306 if (!cid.object) 307 return invalidComponentID; 308 309 m_componentInstances.insert({ *out, cid }); 310 311 OSStatus status = cid.object->Open(cid.object, *out); 312 if (status != noErr) 313 { 314 dispose(*out); 315 *out = nullptr; 316 return status; 317 } 318 regd.instances++; 319 320 return status; 321} 322 323OSStatus AudioComponentManager::dispose(AudioComponentInstance instance) 324{ 325 std::unique_lock<std::recursive_mutex> l2(m_componentInstancesMutex); 326 auto it = m_componentInstances.find(instance); 327 if (it == m_componentInstances.end()) 328 return badComponentInstance; 329 330 ComponentInstanceData& cid = it->second; 331 OSStatus status = cid.object->Close(cid.object); 332 333 std::unique_lock<std::recursive_mutex> l(m_componentsMutex); 334 auto itComp = m_components.find(cid.component); 335 if (itComp != m_components.end()) 336 { 337 RegisteredComponent& regd = itComp->second; 338 regd.instances--; 339 340 if (regd.instances == 0 && regd.loadedBundle != nullptr) 341 { 342 CFRelease(regd.loadedBundle); 343 regd.loadedBundle = nullptr; 344 regd.factory = nullptr; 345 } 346 } 347 348 m_componentInstances.erase(it); 349 return status; 350} 351 352AudioComponentPlugInInterface* AudioComponentManager::instanceInterface(AudioComponentInstance instance) 353{ 354 std::unique_lock<std::recursive_mutex> l2(m_componentInstancesMutex); 355 auto it = m_componentInstances.find(instance); 356 if (it == m_componentInstances.end()) 357 return nullptr; 358 359 return it->second.object; 360} 361 362AudioComponentManager::RegisteredComponent* AudioComponentManager::getById(AudioComponent component) 363{ 364 auto itComp = m_components.find(component); 365 if (itComp != m_components.end()) 366 return &itComp->second; 367 return nullptr; 368} 369 370OSStatus AudioComponentManager::getDescription(AudioComponent c, AudioComponentDescription* out) 371{ 372 std::unique_lock<std::recursive_mutex> l(m_componentsMutex); 373 RegisteredComponent* regd = getById(c); 374 375 if (!regd) 376 return invalidComponentID; 377 378 *out = regd->desc; 379 return noErr; 380} 381 382OSStatus AudioComponentManager::getName(AudioComponent c, const char** name) 383{ 384 std::unique_lock<std::recursive_mutex> l(m_componentsMutex); 385 RegisteredComponent* regd = getById(c); 386 387 if (!regd) 388 return invalidComponentID; 389 390 *name = regd->name.c_str(); 391 return noErr; 392} 393 394OSStatus AudioComponentManager::getVersion(AudioComponent c, uint32_t* version) 395{ 396 std::unique_lock<std::recursive_mutex> l(m_componentsMutex); 397 RegisteredComponent* regd = getById(c); 398 399 if (!regd) 400 return invalidComponentID; 401 402 *version = regd->version; 403 return noErr; 404} 405 406AudioComponent AudioComponentManager::getComponent(AudioComponentInstance instance) 407{ 408 std::unique_lock<std::recursive_mutex> l2(m_componentInstancesMutex); 409 auto it = m_componentInstances.find(instance); 410 if (it == m_componentInstances.end()) 411 return nullptr; 412 413 return it->second.component; 414}