this repo has no description
1
fork

Configure Feed

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

CoreAudio: Untested AUHAL implementation

+398 -15
+314
src/CoreAudio/CoreAudioComponent/AUHAL.cpp
··· 1 + /* 2 + This file is part of Darling. 3 + 4 + Copyright (C) 2020 Lubos Dolezel 5 + 6 + Darling is free software: you can redistribute it and/or modify 7 + it under the terms of the GNU General Public License as published by 8 + the Free Software Foundation, either version 3 of the License, or 9 + (at your option) any later version. 10 + 11 + Darling is distributed in the hope that it will be useful, 12 + but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + GNU General Public License for more details. 15 + 16 + You should have received a copy of the GNU General Public License 17 + along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 + */ 19 + 20 + #include "AUHAL.h" 21 + 22 + #pragma GCC visibility push(default) 23 + AUDIOCOMPONENT_ENTRY(AUBaseFactory, AUHAL); 24 + #pragma GCC visibility pop 25 + 26 + enum { 27 + kOutputBus = 0, 28 + kInputBus 29 + }; 30 + 31 + AUHAL::AUHAL(AudioComponentInstance inInstance) 32 + : AUBase(inInstance, 1, 1) 33 + { 34 + UInt32 propSize = sizeof(AudioDeviceID); 35 + AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &propSize, &m_outputDevice); 36 + AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &propSize, &m_inputDevice); 37 + } 38 + 39 + bool AUHAL::CanScheduleParameters() const 40 + { 41 + return true; 42 + } 43 + 44 + bool AUHAL::StreamFormatWritable(AudioUnitScope scope, AudioUnitElement element) 45 + { 46 + return !m_running; 47 + } 48 + 49 + OSStatus AUHAL::Version() 50 + { 51 + return 1; 52 + } 53 + 54 + // Provide data from the microphone 55 + OSStatus AUHAL::Render(AudioUnitRenderActionFlags& ioActionFlags, const AudioTimeStamp& inTimeStamp, UInt32 inNumberFrames) 56 + { 57 + std::unique_lock<std::mutex> lk(m_dataAvailableMutex); 58 + 59 + m_dataAvailableCV.wait(lk, [=]{ return m_dataAvailable; }); 60 + 61 + AudioBufferList& abl = GetOutput(kInputBus)->GetBufferList(); 62 + 63 + // TODO: Prepare for non-interleaved audio 64 + UInt32 howMuch = std::min<UInt32>(abl.mBuffers[0].mDataByteSize, m_bufferUsed); 65 + memcpy(abl.mBuffers[0].mData, m_buffer.get(), howMuch); 66 + abl.mBuffers[0].mDataByteSize = howMuch; 67 + 68 + return noErr; 69 + } 70 + 71 + OSStatus AUHAL::Start() 72 + { 73 + if (m_running) 74 + return noErr; 75 + 76 + if (m_enableOutput) 77 + { 78 + AudioDeviceCreateIOProcID(m_outputDevice, playbackCallback, this, &m_outputProcID); 79 + 80 + const CAStreamBasicDescription& desc = GetStreamFormat(kAudioUnitScope_Input, kOutputBus); 81 + AudioDeviceSetProperty(m_outputDevice, nullptr, 0, false, kAudioDevicePropertyStreamFormat, sizeof(AudioStreamBasicDescription), &desc); 82 + AudioDeviceStart(m_outputDevice, m_outputProcID); 83 + } 84 + if (m_enableInput) 85 + { 86 + AudioDeviceCreateIOProcID(m_inputDevice, recordCallback, this, &m_inputProcID); 87 + const CAStreamBasicDescription& desc = GetStreamFormat(kAudioUnitScope_Output, kInputBus); 88 + AudioDeviceSetProperty(m_inputDevice, nullptr, 0, true, kAudioDevicePropertyStreamFormat, sizeof(AudioStreamBasicDescription), &desc); 89 + AudioDeviceStart(m_inputDevice, m_inputProcID); 90 + } 91 + 92 + return noErr; 93 + } 94 + 95 + OSStatus AUHAL::Stop() 96 + { 97 + if (!m_running) 98 + return noErr; 99 + 100 + if (m_outputProcID) 101 + { 102 + AudioDeviceStop(m_outputDevice, m_outputProcID); 103 + AudioDeviceDestroyIOProcID(m_outputDevice, m_outputProcID); 104 + } 105 + if (m_inputProcID) 106 + { 107 + AudioDeviceStop(m_inputDevice, m_inputProcID); 108 + AudioDeviceDestroyIOProcID(m_inputDevice, m_inputProcID); 109 + } 110 + 111 + return noErr; 112 + } 113 + 114 + OSStatus AUHAL::SetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, const void* inData, UInt32 inDataSize) 115 + { 116 + switch (inID) 117 + { 118 + case kAudioOutputUnitProperty_SetInputCallback: 119 + { 120 + ca_require(inDataSize == sizeof(AURenderCallbackStruct), InvalidPropertyValue); 121 + const AURenderCallbackStruct* cb = static_cast<const AURenderCallbackStruct*>(inData); 122 + 123 + m_outputAvailableCb = *cb; 124 + 125 + PropertyChanged(inID, inScope, inElement); 126 + return noErr; 127 + } 128 + case kAudioOutputUnitProperty_EnableIO: 129 + { 130 + ca_require(inDataSize == sizeof(UInt32), InvalidPropertyValue); 131 + 132 + const bool enable = *((const UInt32*) inData); 133 + 134 + if (inElement == kOutputBus) 135 + { 136 + m_enableOutput = enable; 137 + PropertyChanged(inID, inScope, inElement); 138 + } 139 + else if (inElement == kInputBus) 140 + { 141 + m_enableInput = enable; 142 + PropertyChanged(inID, inScope, inElement); 143 + } 144 + else 145 + return kAudioUnitErr_InvalidElement; 146 + 147 + return noErr; 148 + } 149 + case kAudioOutputUnitProperty_CurrentDevice: 150 + { 151 + ca_require(inDataSize == sizeof(AudioDeviceID), InvalidPropertyValue); 152 + const AudioDeviceID* dev = static_cast<const AudioDeviceID*>(inData); 153 + 154 + if (inElement == kOutputBus) 155 + { 156 + m_outputDevice = *dev; 157 + PropertyChanged(inID, inScope, inElement); 158 + } 159 + else if (inElement == kInputBus) 160 + { 161 + m_inputDevice = *dev; 162 + PropertyChanged(inID, inScope, inElement); 163 + } 164 + else 165 + return kAudioUnitErr_InvalidElement; 166 + return noErr; 167 + } 168 + } 169 + return AUBase::SetProperty(inID, inScope, inElement, inData, inDataSize); 170 + InvalidPropertyValue: 171 + return kAudioUnitErr_InvalidPropertyValue; 172 + } 173 + 174 + OSStatus AUHAL::GetPropertyInfo(AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, UInt32& outDataSize, Boolean& outWritable) 175 + { 176 + switch (inID) 177 + { 178 + case kAudioOutputUnitProperty_SetInputCallback: 179 + { 180 + outDataSize = sizeof(AURenderCallbackStruct); 181 + outWritable = true; 182 + break; 183 + } 184 + case kAudioOutputUnitProperty_EnableIO: 185 + { 186 + outDataSize = sizeof(UInt32); 187 + outWritable = true; 188 + return noErr; 189 + } 190 + case kAudioOutputUnitProperty_HasIO: 191 + { 192 + outDataSize = sizeof(UInt32); 193 + outWritable = false; 194 + return noErr; 195 + } 196 + case kAudioOutputUnitProperty_CurrentDevice: 197 + { 198 + outDataSize = sizeof(AudioDeviceID); 199 + outWritable = true; 200 + return noErr; 201 + } 202 + } 203 + return AUBase::GetPropertyInfo(inID, inScope, inElement, outDataSize, outWritable); 204 + } 205 + 206 + OSStatus AUHAL::GetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, void* outData) 207 + { 208 + switch (inID) 209 + { 210 + case kAudioOutputUnitProperty_SetInputCallback: 211 + { 212 + memcpy(outData, &m_outputAvailableCb, sizeof(m_outputAvailableCb)); 213 + return noErr; 214 + } 215 + case kAudioOutputUnitProperty_EnableIO: 216 + case kAudioOutputUnitProperty_HasIO: 217 + { 218 + if (inElement == kOutputBus) 219 + { 220 + UInt32 value = m_enableOutput; 221 + memcpy(&outData, &value, sizeof(value)); 222 + } 223 + else if (inElement == kInputBus) 224 + { 225 + UInt32 value = m_enableInput; 226 + memcpy(&outData, &value, sizeof(value)); 227 + } 228 + else 229 + return kAudioUnitErr_InvalidElement; 230 + return noErr; 231 + } 232 + case kAudioOutputUnitProperty_CurrentDevice: 233 + { 234 + if (inElement == kOutputBus) 235 + { 236 + memcpy(outData, &m_outputDevice, sizeof(m_outputDevice)); 237 + } 238 + else if (inElement == kInputBus) 239 + { 240 + memcpy(outData, &m_inputDevice, sizeof(m_inputDevice)); 241 + } 242 + else 243 + return kAudioUnitErr_InvalidElement; 244 + return noErr; 245 + } 246 + } 247 + return AUBase::GetProperty(inID, inScope, inElement, outData); 248 + } 249 + 250 + OSStatus AUHAL::playbackCallback(AudioObjectID inObjectID, 251 + const AudioTimeStamp* inNow, const AudioBufferList* inInputData, 252 + const AudioTimeStamp* inInputTime, 253 + AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, 254 + void* inClientData) 255 + { 256 + AUHAL* This = static_cast<AUHAL*>(inClientData); 257 + return This->doPlayback(inNow, outOutputData, inOutputTime); 258 + } 259 + 260 + OSStatus AUHAL::recordCallback(AudioObjectID inObjectID, 261 + const AudioTimeStamp* inNow, const AudioBufferList* inInputData, 262 + const AudioTimeStamp* inInputTime, 263 + AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, 264 + void* inClientData) 265 + { 266 + AUHAL* This = static_cast<AUHAL*>(inClientData); 267 + return This->doRecord(inNow, inInputData, inInputTime); 268 + } 269 + 270 + OSStatus AUHAL::doPlayback(const AudioTimeStamp* inNow, AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime) 271 + { 272 + if (!HasInput(0)) 273 + return kAudioUnitErr_NoConnection; 274 + 275 + OSStatus result = noErr; 276 + AudioUnitRenderActionFlags flags = kAudioUnitRenderAction_PreRender; 277 + const CAStreamBasicDescription& desc = GetStreamFormat(kAudioUnitScope_Input, kOutputBus); 278 + 279 + UInt32 nFrames = outOutputData->mBuffers[0].mDataByteSize / (desc.mBytesPerFrame / outOutputData->mBuffers[0].mNumberChannels); 280 + result = GetInput(kOutputBus)->PullInputWithBufferList(flags, *inNow, kOutputBus, nFrames, outOutputData); 281 + 282 + return result; 283 + } 284 + 285 + OSStatus AUHAL::doRecord(const AudioTimeStamp* inNow, const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime) 286 + { 287 + // TODO: Prepare for non-interleaved audio 288 + std::unique_lock<std::mutex> lk(m_dataAvailableMutex); 289 + 290 + if (m_bufferSize < inInputData->mBuffers[0].mDataByteSize) 291 + { 292 + m_buffer.reset(new uint8_t[inInputData->mBuffers[0].mDataByteSize]); 293 + m_bufferSize = inInputData->mBuffers[0].mDataByteSize; 294 + } 295 + 296 + m_bufferUsed = inInputData->mBuffers[0].mDataByteSize; 297 + memcpy(m_buffer.get(), inInputData->mBuffers[0].mData, m_bufferUsed); 298 + 299 + m_dataAvailable = true; 300 + 301 + lk.unlock(); 302 + m_dataAvailableCV.notify_one(); 303 + 304 + if (m_outputAvailableCb.inputProc) 305 + { 306 + AudioUnitRenderActionFlags flags = kAudioUnitRenderAction_PostRender; 307 + const CAStreamBasicDescription& desc = GetStreamFormat(kAudioUnitScope_Output, kInputBus); 308 + UInt32 numFrames = m_bufferUsed / desc.mBytesPerFrame; 309 + 310 + m_outputAvailableCb.inputProc(m_outputAvailableCb.inputProcRefCon, &flags, inInputTime, kInputBus, numFrames, nullptr); 311 + } 312 + 313 + return noErr; 314 + }
+79
src/CoreAudio/CoreAudioComponent/AUHAL.h
··· 1 + /* 2 + This file is part of Darling. 3 + 4 + Copyright (C) 2020 Lubos Dolezel 5 + 6 + Darling is free software: you can redistribute it and/or modify 7 + it under the terms of the GNU General Public License as published by 8 + the Free Software Foundation, either version 3 of the License, or 9 + (at your option) any later version. 10 + 11 + Darling is distributed in the hope that it will be useful, 12 + but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + GNU General Public License for more details. 15 + 16 + You should have received a copy of the GNU General Public License 17 + along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 + */ 19 + 20 + #ifndef CAC_AUHAL_H 21 + #define CAC_AUHAL_H 22 + #include "AUBase.h" 23 + #include <CoreAudio/AudioHardware.h> 24 + #include <condition_variable> 25 + #include <mutex> 26 + #include <memory> 27 + #include <stdint.h> 28 + 29 + class AUHAL : public AUBase 30 + { 31 + public: 32 + AUHAL(AudioComponentInstance inInstance); 33 + 34 + bool CanScheduleParameters() const override; 35 + bool StreamFormatWritable(AudioUnitScope scope, AudioUnitElement element) override; 36 + OSStatus Version() override; 37 + 38 + OSStatus Start() override; 39 + OSStatus Stop() override; 40 + 41 + OSStatus SetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, const void* inData, UInt32 inDataSize) override; 42 + OSStatus GetPropertyInfo(AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, UInt32& outDataSize, Boolean& outWritable) override; 43 + OSStatus GetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, void* outData) override; 44 + 45 + OSStatus Render(AudioUnitRenderActionFlags& ioActionFlags, const AudioTimeStamp& inTimeStamp, UInt32 inNumberFrames) override; 46 + private: 47 + static OSStatus playbackCallback(AudioObjectID inObjectID, 48 + const AudioTimeStamp* inNow, const AudioBufferList* inInputData, 49 + const AudioTimeStamp* inInputTime, 50 + AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, 51 + void* inClientData); 52 + static OSStatus recordCallback(AudioObjectID inObjectID, 53 + const AudioTimeStamp* inNow, const AudioBufferList* inInputData, 54 + const AudioTimeStamp* inInputTime, 55 + AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, 56 + void* inClientData); 57 + 58 + OSStatus doPlayback(const AudioTimeStamp* inNow, AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime); 59 + OSStatus doRecord(const AudioTimeStamp* inNow, const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime); 60 + 61 + private: 62 + AURenderCallbackStruct m_outputAvailableCb = { 0 }; 63 + bool m_enableOutput = true, m_enableInput = false; 64 + bool m_running = false; 65 + 66 + AudioDeviceID m_outputDevice, m_inputDevice; 67 + AudioDeviceIOProcID m_outputProcID = 0, m_inputProcID = 0; 68 + 69 + bool m_dataAvailable = false; 70 + std::condition_variable m_dataAvailableCV; 71 + std::mutex m_dataAvailableMutex; 72 + 73 + // TODO: Prepare for non-interleaved audio 74 + std::unique_ptr<uint8_t[]> m_buffer; 75 + size_t m_bufferSize = 0, m_bufferUsed = 0; 76 + }; 77 + 78 + #endif 79 +
+2 -1
src/CoreAudio/CoreAudioComponent/CMakeLists.txt
··· 27 27 PublicUtility/CAStreamBasicDescription.cpp 28 28 PublicUtility/CAHostTimeBase.cpp 29 29 PublicUtility/CAVectorUnit.cpp 30 + AUHAL.cpp 30 31 ) 31 32 32 33 add_darling_bundle(CoreAudioComponent "" ${component_sources}) ··· 37 38 system 38 39 CoreFoundation 39 40 ) 40 - set_target_properties(CoreAudioComponent PROPERTIES OUTPUT_NAME "CoreAudio") 41 + set_target_properties(CoreAudioComponent PROPERTIES OUTPUT_NAME "CoreAudio" PREFIX "" SUFFIX "") 41 42 install(TARGETS CoreAudioComponent DESTINATION libexec/darling/System/Library/Components/CoreAudio.component/Contents/MacOS) 42 43 install(FILES Info.plist DESTINATION libexec/darling/System/Library/Components/CoreAudio.component/Contents)
+2 -2
src/CoreAudio/CoreAudioComponent/Info.plist
··· 56 56 <key>manufacturer</key> 57 57 <string>appl</string> 58 58 <key>name</key> 59 - <string>Apple: SystemOutputUnit</string> 59 + <string>Darling: SystemOutputUnit</string> 60 60 <key>sandboxSafe</key> 61 61 <true/> 62 62 <key>subtype</key> ··· 68 68 <key>type</key> 69 69 <string>auou</string> 70 70 <key>version</key> 71 - <integer>67072</integer> 71 + <integer>1</integer> 72 72 </dict> 73 73 </array> 74 74 <key>CFBundleExecutable</key>
+1
src/CoreAudio/include/AudioUnit
··· 1 + AudioToolbox
-12
src/CoreAudio/include/AudioUnit/AudioUnit.h
··· 1 - #ifndef AUDIOUNIT_H 2 - #define AUDIOUNIT_H 3 - 4 - #include <AudioToolbox/AudioComponent.h> 5 - #include <AudioToolbox/AUComponent.h> 6 - #include <AudioToolbox/AudioUnit.h> 7 - #include <AudioToolbox/AudioOutputUnit.h> 8 - #include <AudioToolbox/AudioUnitProperties.h> 9 - // TODO: More headers 10 - 11 - #endif 12 -