this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at vchroot 282 lines 7.8 kB view raw
1#include "AudioUnitBase.h" 2#include "AudioUnitProperties.h" 3#include "AudioUnitRenderer.h" 4#include <CoreServices/MacErrors.h> 5#include <util/debug.h> 6#include <cstring> 7 8AudioUnitComponent::AudioUnitComponent(std::initializer_list<CFStringRef> elements) 9{ 10 m_elementNames.insert(m_elementNames.end(), elements.begin(), elements.end()); 11 m_config.resize(m_elementNames.size()); 12 13 // Default audio params 14 const AudioStreamBasicDescription defaultConfig = AudioStreamBasicDescription { 15 44100.0, kAudioFormatLinearPCM, kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked, 16 4, 1, 4, 2, 16, 0 17 }; 18 19 for (size_t i = 0; i < m_config.size(); i++) 20 { 21 m_config[i] = std::pair<AudioStreamBasicDescription, AudioStreamBasicDescription>(defaultConfig, defaultConfig); 22 } 23 24 memset(&m_inputUnit, 0, sizeof(m_inputUnit)); 25} 26 27AudioUnitComponent::~AudioUnitComponent() 28{ 29 if (m_contextName != nullptr) 30 CFRelease(m_contextName); 31 CloseComponent(m_inputUnit.sourceAudioUnit); 32} 33 34OSStatus AudioUnitComponent::getPropertyInfo(AudioUnitPropertyID prop, AudioUnitScope scope, AudioUnitElement elem, UInt32* dataSize, Boolean* writable) 35{ 36 switch (prop) 37 { 38 case kAudioUnitProperty_StreamFormat: 39 *dataSize = sizeof(AudioStreamBasicDescription); 40 *writable = true; 41 break; 42 case kAudioOutputUnitProperty_EnableIO: 43 *dataSize = sizeof(UInt32); 44 *writable = true; 45 break; 46 case kAudioUnitProperty_SetRenderCallback: 47 *dataSize = sizeof(AURenderCallbackStruct); 48 *writable = true; 49 break; 50 case kAudioUnitProperty_ShouldAllocateBuffer: 51 *dataSize = sizeof(int); 52 *writable = true; 53 break; 54 case kAudioUnitProperty_ElementCount: 55 *dataSize = sizeof(UInt32); 56 *writable = false; 57 break; 58 case kAudioUnitProperty_LastRenderError: // TODO: implement 59 *dataSize = sizeof(OSStatus); 60 *writable = false; 61 break; 62 case kAudioUnitProperty_SampleRate: // TODO: implement 63 *dataSize = sizeof(Float64); 64 *writable = true; // TODO: query itself on kAudioUnitProperty_StreamFormat if writable 65 break; 66 case kAudioUnitProperty_ElementName: 67 *dataSize = sizeof(CFStringRef); 68 *writable = false; 69 break; 70 case kAudioUnitProperty_ContextName: 71 *dataSize = sizeof(CFStringRef); 72 *writable = true; 73 break; 74 default: 75 return kAudioUnitErr_InvalidProperty; 76 } 77 78 return noErr; 79} 80 81OSStatus AudioUnitComponent::setProperty(AudioUnitPropertyID prop, AudioUnitScope scope, AudioUnitElement elem, const void* data, UInt32 dataSize) 82{ 83 TRACE5(prop, scope, elem, data, dataSize); 84 85 switch (prop) 86 { 87 case kAudioUnitProperty_StreamFormat: 88 { 89 const AudioStreamBasicDescription* newConfig = static_cast<const AudioStreamBasicDescription*>(data); 90 91 if (dataSize != sizeof(*newConfig)) 92 return kAudioUnitErr_InvalidParameter; 93 94 if (elem >= m_config.size()) 95 return kAudioUnitErr_InvalidElement; 96 97 // TODO: perform validation 98 99 if (scope == kAudioUnitScope_Output) 100 m_config[elem].second = *newConfig; 101 else if (scope == kAudioUnitScope_Input) 102 m_config[elem].first = *newConfig; 103 else if (scope == kAudioUnitScope_Global) 104 m_config[0].second = *newConfig; 105 else 106 return kAudioUnitErr_InvalidScope; 107 108 return noErr; 109 } 110 case kAudioUnitProperty_SetRenderCallback: 111 { 112 if (dataSize != sizeof(AURenderCallbackStruct)) 113 return kAudioUnitErr_InvalidParameter; 114 //if (scope == kAudioUnitScope_Input) 115 //{ 116 if (elem != 0) 117 return kAudioUnitErr_InvalidElement; 118 119 CloseComponent(m_inputUnit.sourceAudioUnit); // TODO: wrong, we may not own the unit! 120 m_inputUnit.sourceOutputNumber = 0; 121 m_inputUnit.destInputNumber = 0; 122 m_inputUnit.sourceAudioUnit = new AudioUnitRenderer(*(AURenderCallbackStruct*) data); 123 //} 124 //else 125 // return kAudioUnitErr_InvalidScope; 126 127 return noErr; 128 } 129 case kAudioUnitProperty_MakeConnection: 130 { 131 if (dataSize != sizeof(AudioUnitConnection)) 132 return kAudioUnitErr_InvalidParameter; 133 if (scope != kAudioUnitScope_Input) 134 return kAudioUnitErr_InvalidScope; 135 136 // TODO: support multiple units! 137 // TODO: reconfigure input format based on output format 138 139 CloseComponent(m_inputUnit.sourceAudioUnit); // TODO: wrong, we may not own the unit! 140 memcpy(&m_inputUnit, data, sizeof(AudioUnitConnection)); 141 142 return noErr; 143 } 144 case kAudioUnitProperty_ShouldAllocateBuffer: 145 { 146 int* b = (int*) data; 147 if (dataSize < sizeof(int)) 148 return kAudioUnitErr_InvalidParameter; 149 150 m_shouldAllocateBuffer = *b != 0; 151 return noErr; 152 } 153 case kAudioUnitProperty_ContextName: 154 { 155 if (dataSize < sizeof(CFStringRef)) 156 return kAudioUnitErr_InvalidParameter; 157 158 if (data == nullptr) 159 { 160 if (m_contextName != nullptr) 161 { 162 CFRelease(m_contextName); 163 m_contextName = nullptr; 164 } 165 } 166 else 167 { 168 m_contextName = (CFStringRef) data; 169 CFRetain(m_contextName); 170 } 171 return noErr; 172 } 173 default: 174 return kAudioUnitErr_InvalidProperty; 175 } 176} 177 178OSStatus AudioUnitComponent::getProperty(AudioUnitPropertyID prop, AudioUnitScope scope, AudioUnitElement elem, void* data, UInt32* dataSize) 179{ 180 TRACE5(prop, scope, elem, data, dataSize); 181 182 switch (prop) 183 { 184 case kAudioUnitProperty_StreamFormat: 185 { 186 AudioStreamBasicDescription* newConfig = static_cast<AudioStreamBasicDescription*>(data); 187 188 if (*dataSize < sizeof(AudioStreamBasicDescription)) 189 return kAudioUnitErr_InvalidParameter; 190 191 if (elem >= m_config.size()) 192 return kAudioUnitErr_InvalidElement; 193 194 if (scope == kAudioUnitScope_Output) 195 *newConfig = m_config[elem].second; 196 else if (scope == kAudioUnitScope_Input) 197 *newConfig = m_config[elem].first; 198 else if (scope == kAudioUnitScope_Global) 199 *newConfig = m_config[0].second; 200 else 201 return kAudioUnitErr_InvalidScope; 202 203 *dataSize = sizeof(AudioStreamBasicDescription); 204 205 return noErr; 206 } 207 case kAudioUnitProperty_ShouldAllocateBuffer: 208 { 209 int* out = (int*) data; 210 if (*dataSize < sizeof(UInt32)) 211 return kAudioUnitErr_InvalidParameter; 212 213 *out = m_shouldAllocateBuffer; 214 return noErr; 215 } 216 case kAudioUnitProperty_ElementCount: 217 { 218 UInt32* out = (UInt32*) data; 219 if (*dataSize < sizeof(UInt32)) 220 return kAudioUnitErr_InvalidParameter; 221 222 *out = m_config.size(); 223 return noErr; 224 } 225 case kAudioUnitProperty_ElementName: 226 { 227 CFStringRef* out = (CFStringRef*) data; 228 if (*dataSize != sizeof(CFStringRef)) 229 return kAudioUnitErr_InvalidParameter; 230 if (elem >= m_elementNames.size()) 231 return kAudioUnitErr_InvalidElement; 232 233 *out = m_elementNames[elem]; 234 return noErr; 235 } 236 case kAudioUnitProperty_ContextName: 237 { 238 CFStringRef* out = (CFStringRef*) data; 239 if (*dataSize != sizeof(CFStringRef)) 240 return kAudioUnitErr_InvalidParameter; 241 242 *out = m_contextName; 243 return noErr; 244 } 245 default: 246 return kAudioUnitErr_InvalidProperty; 247 } 248} 249 250OSStatus AudioUnitComponent::addRenderNotify(AURenderCallback inProc, void* opaque) 251{ 252 std::lock_guard<std::mutex> guard(m_listenersMutex); 253 254 if (!inProc) 255 return paramErr; 256 m_listeners.insert(std::pair<AURenderCallback,void*>(inProc, opaque)); 257 258 return noErr; 259} 260 261OSStatus AudioUnitComponent::removeRenderNotify(AURenderCallback inProc, void* opaque) 262{ 263 std::lock_guard<std::mutex> guard(m_listenersMutex); 264 m_listeners.erase(std::pair<AURenderCallback,void*>(inProc, opaque)); 265 return noErr; 266} 267 268OSStatus AudioUnitComponent::notifyListeners(AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, 269 UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) 270{ 271 std::lock_guard<std::mutex> guard(m_listenersMutex); 272 OSStatus status = noErr; 273 274 for (auto p : m_listeners) 275 { 276 status = p.first(p.second, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData); 277 if (status != noErr) 278 break; 279 } 280 281 return status; 282}