/* This file is part of Darling. Copyright (C) 2020 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 #include #include #include #include #include "AudioComponentManager.h" #include AudioComponent AudioComponentRegister(const AudioComponentDescription *inDesc, CFStringRef inName, UInt32 inVersion, AudioComponentFactoryFunction inFactory) { if (!inDesc || !inName || !inFactory) return nullptr; const char* name = CFStringGetCStringPtr(inName, kCFStringEncodingUTF8); return AudioComponentManager::instance()->registerComponent(inDesc, name, inVersion, inFactory); } AudioComponent AudioComponentFindNext(AudioComponent inComponent, const AudioComponentDescription* desc) { auto matching = AudioComponentManager::instance()->findMatching(desc); if (!matching.empty()) { if (!inComponent) return matching[0]; for (size_t i = 0; i < matching.size()-1; i++) { if (matching[i] == inComponent) { return matching[i+1]; } } } return (AudioComponent) ::FindNextComponent(Component(inComponent), (ComponentDescription*) desc); } UInt32 AudioComponentCount(const AudioComponentDescription* desc) { const UInt32 carbonComponents = ::CountComponents((ComponentDescription*) desc); UInt32 numDuplicates = 0; Component carbonComponent = nullptr; while ((carbonComponent = ::FindNextComponent(carbonComponent, (ComponentDescription*) desc)) != nullptr) { ComponentDescription cd; ::GetComponentInfo(carbonComponent, &cd, nullptr, nullptr, nullptr); if (::AudioComponentFindNext(nullptr, (AudioComponentDescription*) &cd) != nullptr) numDuplicates++; } return AudioComponentManager::instance()->findMatching(desc).size() + carbonComponents - numDuplicates; } OSStatus AudioComponentCopyName(AudioComponent component, CFStringRef* outName) { if (AudioComponentManager::isOurInstance(component)) { const char* name; OSStatus status = AudioComponentManager::instance()->getName(component, &name); if (status == noErr) *outName = CFStringCreateWithCString(nullptr, name, kCFStringEncodingUTF8); else *outName = nullptr; return status; } else { Handle handle = ::NewEmptyHandle(); OSStatus status = ::GetComponentInfo(Component(component), nullptr, handle, nullptr, nullptr); if (status != noErr) { ::DisposeHandle(handle); *outName = nullptr; return status; } else { *outName = ::CFStringCreateWithPascalString(nullptr, ConstStr255Param(*handle), kCFStringEncodingMacRoman); ::DisposeHandle(handle); return noErr; } } } OSStatus AudioComponentGetDescription(AudioComponent component, AudioComponentDescription* outDesc) { if (AudioComponentManager::isOurInstance(component)) { return AudioComponentManager::instance()->getDescription(component, outDesc); } else { return ::GetComponentInfo(Component(component), (ComponentDescription*) outDesc, nullptr, nullptr, nullptr); } } #pragma pack(push, 1) struct PlatformInfo { uint32_t ComponentFlags; uint32_t CodeType; uint16_t CodeId; uint16_t PlatformType; }; struct CarbonThng { uint32_t Type; uint32_t Subtype; uint32_t Manufacturer; uint32_t ComponentFlags; uint32_t ComponentFlagsMask; uint32_t CodeType; uint16_t CodeId; uint32_t NameType; uint16_t NameId; uint32_t InfoType; uint16_t InfoId; uint32_t IconType; uint16_t IconId; uint32_t ComponentVersion; uint32_t RegistrationFlags; uint16_t IconFamilyId; uint32_t PlatformInfoCount; PlatformInfo PlatformInfos[]; }; #pragma pack(pop) #ifdef __LITTLE_ENDIAN__ # define SWAP(x) x = _bswap(x) static inline uint16_t _bswap(uint16_t v) { return __builtin_bswap16(v); } static inline int16_t _bswap(int16_t v) { return __builtin_bswap16(v); } static inline uint32_t _bswap(uint32_t v) { return __builtin_bswap32(v); } #else # define SWAP(x) #endif OSStatus AudioComponentGetVersion(AudioComponent component, UInt32* outVersion) { if (AudioComponentManager::isOurInstance(component)) { return AudioComponentManager::instance()->getVersion(component, (uint32_t*) outVersion); } else { ResFileRefNum resFile, oldFile; AudioComponentDescription desc; OSStatus status; status = ::AudioComponentGetDescription(component, &desc); if (status != noErr) return status; status = ::OpenAComponentResFile(Component(component), &resFile); if (status != noErr) return status; oldFile = ::CurResFile(); ::UseResFile(resFile); const ResourceCount count = ::Count1Resources('thng'); bool found = false; for (int i = 1; i <= count; i++) { Handle handle = ::Get1IndResource('thng', i); if (handle && ::GetHandleSize(handle) >= sizeof(CarbonThng)) { CarbonThng thng = *((CarbonThng*) *handle); SWAP(thng.Type); SWAP(thng.Subtype); SWAP(thng.Manufacturer); if (thng.Type == desc.componentType && thng.Subtype == desc.componentSubType && thng.Manufacturer == desc.componentManufacturer) { SWAP(thng.ComponentVersion); *outVersion = thng.ComponentVersion; found = true; break; } } } ::UseResFile(oldFile); ::CloseComponentResFile(resFile); return found ? noErr : invalidComponentID; } } #if !TARGET_OS_IPHONE NSImage* AudioComponentGetIcon(AudioComponent component) { return nullptr; } #else UIImage* AudioComponentGetIcon(AudioComponent component, float desiredPointSize) { return nullptr; } #endif OSStatus AudioComponentInstanceNew(AudioComponent component, AudioComponentInstance* outInstance) { if (AudioComponentManager::isOurInstance(component)) { return AudioComponentManager::instance()->instantiate(component, outInstance); } else { return ::OpenAComponent(Component(component), (ComponentInstance*) outInstance); } } void AudioComponentInstantiate(AudioComponent component, AudioComponentInstantiationOptions opts, void(^handler)(AudioComponentInstance, OSStatus)) { std::cerr << "AudioComponentInstantiate(): NOT IMPLEMENTED\n"; } OSStatus AudioComponentInstanceDispose(AudioComponentInstance inst) { if (AudioComponentManager::isOurInstance(inst)) { return AudioComponentManager::instance()->dispose(inst); } else { return ::CloseComponent(inst); } } AudioComponent AudioComponentInstanceGetComponent(AudioComponentInstance inst) { if (AudioComponentManager::isOurInstance(inst)) { return AudioComponentManager::instance()->getComponent(inst); } else { return (AudioComponent) ::GetComponentIDFromComponentInstance(inst); } } Boolean AudioComponentInstanceCanDo(AudioComponentInstance inst, SInt16 sel) { if (AudioComponentManager::isOurInstance(inst)) { AudioComponentPlugInInterface* iface = AudioComponentManager::instance()->instanceInterface(inst); return iface->Lookup(sel) != nullptr; } else { return ::CallComponentCanDo(inst, sel); } } OSStatus AudioComponentCopyConfigurationInfo(AudioComponent component, CFDictionaryRef* outInfo) { std::cerr << "AudioComponentCopyConfigurationInfo(): NOT IMPLEMENTED\n"; *outInfo = CFDictionaryCreate(nullptr, nullptr, nullptr, 0, nullptr, nullptr); return noErr; } OSStatus AudioComponentValidate(AudioComponent component, CFDictionaryRef validationParams, AudioComponentValidationResult* result) { *result = kAudioComponentValidationResult_Passed; return noErr; }