this repo has no description
1
fork

Configure Feed

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

CoreAudio: work on PulseAudio integration

+963 -126
+22 -14
src/CoreAudio/CoreAudio/AudioHardware.cpp
··· 1 1 /* 2 2 This file is part of Darling. 3 3 4 - Copyright (C) 2015-2016 Lubos Dolezel 4 + Copyright (C) 2015-2020 Lubos Dolezel 5 5 6 6 Darling is free software: you can redistribute it and/or modify 7 7 it under the terms of the GNU General Public License as published by ··· 19 19 20 20 #include <CoreAudio/AudioHardware.h> 21 21 #include "AudioHardwareImpl.h" 22 - #include "AudioHardwareImplPA.h" 22 + #include "pulse/AudioHardwareImplPA.h" 23 + #include "pulse/AudioHardwareImplPAOutput.h" 23 24 #include <CoreServices/MacErrors.h> 24 25 #include <dispatch/dispatch.h> 25 26 #include <memory> 27 + #include <unordered_map> 26 28 #include "stub.h" 27 29 28 - static std::unique_ptr<AudioHardwareImpl> g_systemObject; 30 + static std::unordered_map<AudioObjectID, std::unique_ptr<AudioHardwareImpl>> g_objects; 29 31 30 - static AudioHardwareImpl* GetSystemObject() 32 + static void initObjects() 31 33 { 32 34 static dispatch_once_t once; 33 35 dispatch_once(&once, ^{ 34 36 // TODO: Or ALSA 35 - g_systemObject.reset(new AudioHardwareImplPA); 37 + g_objects.insert(std::make_pair(kAudioObjectSystemObject, std::make_unique<AudioHardwareImplPA>())); 38 + g_objects.insert(std::make_pair(kAudioObjectSystemObject + 1, std::make_unique<AudioHardwareImplPAOutput>())); 39 + // TODO: PA input 36 40 }); 37 - 38 - return g_systemObject.get(); 39 41 } 40 42 41 43 static AudioHardwareImpl* GetObject(AudioObjectID objID) 42 44 { 43 - if (objID == kAudioObjectSystemObject) 44 - return GetSystemObject(); 45 + initObjects(); 45 46 46 - // TODO: For ALSA, support more objects for every device 47 - 48 - return nullptr; 47 + auto it = g_objects.find(objID); 48 + if (it == g_objects.end()) 49 + return nullptr; 50 + 51 + return it->second.get(); 52 + } 53 + 54 + static AudioHardwareImpl* GetSystemObject() 55 + { 56 + return GetObject(kAudioObjectSystemObject); 49 57 } 50 58 51 59 void AudioObjectShow(AudioObjectID inObjectID) ··· 165 173 { 166 174 AudioObjectPropertyAddress aopa = { 167 175 inPropertyID, 168 - kAudioObjectPropertyScopeGlobal, 176 + isInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput, // kAudioObjectPropertyScopeGlobal 169 177 kAudioObjectPropertyElementMaster 170 178 }; 171 179 ··· 176 184 { 177 185 AudioObjectPropertyAddress aopa = { 178 186 inPropertyID, 179 - kAudioObjectPropertyScopeGlobal, 187 + isInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput, // kAudioObjectPropertyScopeGlobal 180 188 kAudioObjectPropertyElementMaster 181 189 }; 182 190
+62 -5
src/CoreAudio/CoreAudio/AudioHardwareImpl.cpp
··· 72 72 AudioTimeStamp* ioRequestedStartTime, UInt32 inFlags) 73 73 { 74 74 AudioHardwareStream* stream; 75 + std::lock_guard<std::mutex> guard(m_procMutex); 75 76 76 77 if (m_streams.find(inProcID) != m_streams.end()) 77 78 return paramErr; 79 + 80 + auto it = m_proc.find(inProcID); 78 81 79 - stream = createStream(inProcID); 82 + if (it == m_proc.end()) 83 + return paramErr; 84 + 85 + stream = createStream(it->second.first, it->second.second); 80 86 if (!stream) 81 87 return kAudioHardwareBadStreamError; 82 88 m_streams.emplace(std::make_pair(inProcID, std::unique_ptr<AudioHardwareStream>(stream))); ··· 92 98 if (it == m_streams.end()) 93 99 return kAudioHardwareNotRunningError; 94 100 101 + AudioHardwareStream* stream = it->second.release(); 102 + stream->stop(^{ 103 + delete stream; 104 + }); 95 105 m_streams.erase(it); 96 106 return noErr; 97 107 } ··· 111 121 112 122 OSStatus AudioHardwareImpl::isPropertySettable(const AudioObjectPropertyAddress* inAddress, Boolean* outIsSettable) 113 123 { 124 + switch (inAddress->mSelector) 125 + { 126 + case kAudioDevicePropertyVolumeScalar: 127 + *outIsSettable = true; 128 + return kAudioHardwareNoError; 129 + } 130 + 114 131 *outIsSettable = false; 115 132 return kAudioHardwareUnknownPropertyError; 116 133 } ··· 144 161 return getPropertyString(m_manufacturer, ioDataSize, outData); 145 162 case kAudioDevicePropertyDeviceManufacturerCFString: 146 163 return getPropertyCFString(m_manufacturer, ioDataSize, outData); 164 + // NOTE: This is related to [NSSound setPlaybackDeviceIdentifier] 147 165 case kAudioDevicePropertyDeviceUID: // returns CFStringRef 148 166 return getPropertyCFString(m_uid, ioDataSize, outData); 167 + case kAudioDevicePropertyModelUID: 168 + return getPropertyCFString(m_modelUid, ioDataSize, outData); 149 169 case kAudioDevicePropertyDeviceNameCFString: 150 170 return getPropertyCFString(m_name, ioDataSize, outData); 151 171 case kAudioDevicePropertyDeviceName: // return char[] ··· 168 188 *ioDataSize = sizeof(AudioValueRange) * 1; 169 189 return kAudioHardwareNoError; 170 190 } 171 - 191 + case kAudioDevicePropertyDeviceIsAlive: // int 192 + case kAudioDevicePropertyDeviceIsRunning: 193 + { 194 + if (int* b = static_cast<int*>(outData); outData && *ioDataSize >= sizeof(int)) 195 + *b = 1; 196 + *ioDataSize = sizeof(int); 197 + return kAudioHardwareNoError; 198 + } 199 + case kAudioDevicePropertyIsHidden: 200 + { 201 + if (int* b = static_cast<int*>(outData); outData && *ioDataSize >= sizeof(int)) 202 + *b = 0; 203 + *ioDataSize = sizeof(int); 204 + return kAudioHardwareNoError; 205 + } 206 + case kAudioDevicePropertyPreferredChannelsForStereo: 207 + { 208 + if (UInt32* b = static_cast<UInt32*>(outData); outData && *ioDataSize >= sizeof(UInt32)*2) 209 + { 210 + b[0] = 0; 211 + b[1] = 1; 212 + } 213 + *ioDataSize = sizeof(UInt32)*2; 214 + return kAudioHardwareNoError; 215 + } 216 + case kAudioDevicePropertyVolumeScalar: 217 + { 218 + if (Float32* v = static_cast<Float32*>(outData); outData && *ioDataSize >= sizeof(Float32)) 219 + *v = 1.0f; // TODO: Ask for real volume from PulseAudio 220 + *ioDataSize = sizeof(Float32); 221 + return kAudioHardwareNoError; 222 + } 172 223 } 173 224 return kAudioHardwareUnknownPropertyError; 174 225 } ··· 177 228 { 178 229 if (CFStringRef* ref = static_cast<CFStringRef*>(outData); ref && *ioDataSize >= sizeof(CFStringRef)) 179 230 { 180 - *ref = str; 231 + *ref = (CFStringRef) CFRetain(str); 181 232 } 182 233 *ioDataSize = sizeof(CFStringRef); 183 234 return noErr; ··· 201 252 { 202 253 return setBufferSize(*static_cast<const uint32_t*>(inData)); 203 254 } 255 + case kAudioDevicePropertyVolumeScalar: 256 + { 257 + // TODO: Implement setting the volume 258 + // Note: qualifier contains the channel ID (from kAudioDevicePropertyPreferredChannelsForStereo) 259 + return kAudioHardwareNoError; 260 + } 204 261 // These make sense only for ALSA, but I find it ridiculous that these properties can be set... 205 262 case kAudioHardwarePropertyDefaultOutputDevice: 206 - return noErr; 263 + return kAudioHardwareNoError; 207 264 case kAudioHardwarePropertyDefaultInputDevice: 208 - return noErr; 265 + return kAudioHardwareNoError; 209 266 } 210 267 return kAudioHardwareUnknownPropertyError; 211 268 }
+2 -2
src/CoreAudio/CoreAudio/AudioHardwareImpl.h
··· 70 70 static OSStatus getPropertyCFString(CFStringRef str, UInt32* ioDataSize, void* outData); 71 71 static OSStatus getPropertyString(CFStringRef str, UInt32* ioDataSize, void* outData); 72 72 protected: 73 - virtual AudioHardwareStream* createStream(AudioDeviceIOProcID procID) = 0; 73 + virtual AudioHardwareStream* createStream(AudioDeviceIOProc callback, void* clientData) = 0; 74 74 protected: 75 75 std::mutex m_procMutex; 76 76 std::map<AudioDeviceIOProcID, std::pair<AudioDeviceIOProc, void*>> m_proc; ··· 79 79 std::map<AudioDeviceIOProcID, std::unique_ptr<AudioHardwareStream>> m_streams; 80 80 uint32_t m_bufferSize = 8192; 81 81 82 - CFStringRef m_name = CFSTR("unknown"), m_uid = CFSTR("unknown"), m_manufacturer = CFSTR("unknown"); 82 + CFStringRef m_name = CFSTR("unknown"), m_uid = CFSTR("unknown"), m_manufacturer = CFSTR("unknown"), m_modelUid = CFSTR("unknown"); 83 83 }; 84 84 85 85 #endif /* AUDIOHARDWAREIMPL_H */
-100
src/CoreAudio/CoreAudio/AudioHardwareImplPA.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 "AudioHardwareImplPA.h" 21 - #include "stub.h" 22 - 23 - AudioHardwareImplPA::AudioHardwareImplPA() 24 - { 25 - m_name = CFSTR("PulseAudio"); 26 - m_manufacturer = CFSTR("PulseAudio"); 27 - m_uid = CFSTR("100"); 28 - } 29 - 30 - OSStatus AudioHardwareImplPA::getPropertyData(const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, 31 - const void* inQualifierData, UInt32* ioDataSize, void* outData) 32 - { 33 - switch (inAddress->mSelector) 34 - { 35 - // BEGIN kAudioObjectSystemObject properties 36 - case kAudioHardwarePropertyDefaultInputDevice: // returns AudioDeviceID 37 - if (AudioDeviceID* devId = static_cast<AudioDeviceID*>(outData); devId && *ioDataSize >= sizeof(AudioDeviceID)) 38 - { 39 - // We're doing a bit of an abuse here, which works only for PA where we have a single virtual device. 40 - // For ALSA, we could do kAudioObjectSystemObject + INDEX of device. 41 - *devId = kAudioObjectSystemObject; 42 - } 43 - *ioDataSize = sizeof(AudioDeviceID); 44 - return kAudioHardwareNoError; 45 - case kAudioHardwarePropertyDefaultOutputDevice: // returns AudioDeviceID 46 - if (AudioDeviceID* devId = static_cast<AudioDeviceID*>(outData); devId && *ioDataSize >= sizeof(AudioDeviceID)) 47 - { 48 - *devId = kAudioObjectSystemObject; 49 - } 50 - *ioDataSize = sizeof(AudioDeviceID); 51 - return kAudioHardwareNoError; 52 - case kAudioHardwarePropertyDevices: 53 - { 54 - if (AudioDeviceID* devId = static_cast<AudioDeviceID*>(outData); devId && *ioDataSize >= sizeof(AudioDeviceID)) 55 - { 56 - devId[0] = kAudioObjectSystemObject; 57 - } 58 - *ioDataSize = sizeof(AudioDeviceID) * 1; 59 - return kAudioHardwareNoError; 60 - } 61 - // END kAudioObjectSystemObject properties 62 - 63 - // BEGIN properties of a specific audio device (in case of PA, it is kAudioObjectSystemObject as well) 64 - case kAudioDevicePropertyStreamConfiguration: // returns AudioBufferList 65 - { 66 - const size_t size = sizeof(AudioBufferList) + 1* sizeof(AudioBuffer); 67 - 68 - // Number of returned buffers is the number of channels 69 - // check inAddress->mScope. If it equals kAudioDevicePropertyScopeInput, the caller cares about input only. 70 - if (AudioBufferList* abl = static_cast<AudioBufferList*>(outData); abl && *ioDataSize >= size) 71 - { 72 - abl->mNumberBuffers = 1; 73 - abl->mBuffers[0].mNumberChannels = 2; 74 - 75 - // TODO: Is the below stuff ever used? How? 76 - abl->mBuffers[0].mData = nullptr; 77 - abl->mBuffers[0].mDataByteSize = 0; 78 - } 79 - 80 - *ioDataSize = size; 81 - return kAudioHardwareNoError; 82 - } 83 - 84 - } 85 - 86 - return AudioHardwareImpl::getPropertyData(inAddress, inQualifierDataSize, inQualifierData, ioDataSize, outData); 87 - } 88 - 89 - OSStatus AudioHardwareImplPA::setPropertyData(const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, 90 - const void* inQualifierData, UInt32 inDataSize, const void* inData) 91 - { 92 - return AudioHardwareImpl::setPropertyData(inAddress, inQualifierDataSize, inQualifierData, inDataSize, inData); 93 - } 94 - 95 - AudioHardwareStream* AudioHardwareImplPA::createStream(AudioDeviceIOProcID procID) 96 - { 97 - // TODO 98 - STUB(); 99 - return nullptr; 100 - }
+7 -2
src/CoreAudio/CoreAudio/AudioHardwareImplPA.h src/CoreAudio/CoreAudio/pulse/AudioHardwareImplPA.h
··· 19 19 20 20 #ifndef AUDIOHARDWAREIMPLPA_H 21 21 #define AUDIOHARDWAREIMPLPA_H 22 - #include "AudioHardwareImpl.h" 22 + #include "../AudioHardwareImpl.h" 23 + #include <pulse/pulseaudio.h> 23 24 24 25 class AudioHardwareImplPA : public AudioHardwareImpl 25 26 { ··· 31 32 32 33 OSStatus setPropertyData(const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, 33 34 const void* inQualifierData, UInt32 inDataSize, const void* inData) override; 35 + 36 + static void getPAContext(void (^cb)(pa_context*)); 34 37 protected: 35 - AudioHardwareStream* createStream(AudioDeviceIOProcID procID) override; 38 + AudioHardwareStream* createStream(AudioDeviceIOProc callback, void* clientData) override; 39 + private: 40 + static pa_context* m_context; 36 41 }; 37 42 38 43 #endif
+2
src/CoreAudio/CoreAudio/AudioHardwareStream.h
··· 25 25 public: 26 26 AudioHardwareStream(); 27 27 virtual ~AudioHardwareStream(); 28 + 29 + virtual void stop(void(^cbDone)()) = 0; 28 30 private: 29 31 30 32 };
+8 -3
src/CoreAudio/CoreAudio/CMakeLists.txt
··· 7 7 set(coreaudio_sources 8 8 AudioHardware.cpp 9 9 AudioHardwareImpl.cpp 10 - AudioHardwareImplPA.cpp 11 - AudioHardwareStream.cpp 10 + pulse/AudioHardwareImplPA.cpp 11 + pulse/AudioHardwareImplPAOutput.cpp 12 + AudioHardwareStream.cpp 13 + pulse/AudioHardwareStreamPA.cpp 14 + pulse/AudioHardwareStreamPAOutput.cpp 15 + pulse/PADispatchMainLoop.cpp 12 16 ) 13 17 14 18 add_framework(CoreAudio ··· 22 26 DEPENDENCIES 23 27 system 24 28 cxx 25 - CoreFoundation 29 + CoreFoundation 30 + pulse 26 31 )
+172
src/CoreAudio/CoreAudio/pulse/AudioHardwareImplPA.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 "AudioHardwareImplPA.h" 21 + #include "../stub.h" 22 + #include "AudioHardwareStreamPA.h" 23 + #include "PADispatchMainLoop.h" 24 + #include <CoreFoundation/CFBundle.h> 25 + #include <CoreFoundation/CFString.h> 26 + #include <mutex> 27 + 28 + pa_context* AudioHardwareImplPA::m_context; 29 + 30 + AudioHardwareImplPA::AudioHardwareImplPA() 31 + { 32 + m_name = CFSTR("PulseAudio"); 33 + m_manufacturer = CFSTR("PulseAudio"); 34 + m_uid = CFSTR("PulseAudio:SystemObject"); 35 + } 36 + 37 + OSStatus AudioHardwareImplPA::getPropertyData(const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, 38 + const void* inQualifierData, UInt32* ioDataSize, void* outData) 39 + { 40 + switch (inAddress->mSelector) 41 + { 42 + // BEGIN kAudioObjectSystemObject properties 43 + case kAudioHardwarePropertyDefaultInputDevice: // returns AudioDeviceID 44 + if (AudioDeviceID* devId = static_cast<AudioDeviceID*>(outData); devId && *ioDataSize >= sizeof(AudioDeviceID)) 45 + { 46 + *devId = kAudioObjectSystemObject + 2; 47 + } 48 + *ioDataSize = sizeof(AudioDeviceID); 49 + return kAudioHardwareNoError; 50 + case kAudioHardwarePropertyDefaultOutputDevice: // returns AudioDeviceID 51 + if (AudioDeviceID* devId = static_cast<AudioDeviceID*>(outData); devId && *ioDataSize >= sizeof(AudioDeviceID)) 52 + { 53 + *devId = kAudioObjectSystemObject + 1; 54 + } 55 + *ioDataSize = sizeof(AudioDeviceID); 56 + return kAudioHardwareNoError; 57 + case kAudioHardwarePropertyDevices: 58 + { 59 + if (AudioDeviceID* devId = static_cast<AudioDeviceID*>(outData); devId && *ioDataSize >= 2*sizeof(AudioDeviceID)) 60 + { 61 + devId[0] = kAudioObjectSystemObject + 1; // output 62 + devId[1] = kAudioObjectSystemObject + 2; // input 63 + } 64 + *ioDataSize = sizeof(AudioDeviceID) * 2; 65 + return kAudioHardwareNoError; 66 + } 67 + 68 + } 69 + 70 + return AudioHardwareImpl::getPropertyData(inAddress, inQualifierDataSize, inQualifierData, ioDataSize, outData); 71 + } 72 + 73 + OSStatus AudioHardwareImplPA::setPropertyData(const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, 74 + const void* inQualifierData, UInt32 inDataSize, const void* inData) 75 + { 76 + return AudioHardwareImpl::setPropertyData(inAddress, inQualifierDataSize, inQualifierData, inDataSize, inData); 77 + } 78 + 79 + AudioHardwareStream* AudioHardwareImplPA::createStream(AudioDeviceIOProc callback, void* clientData) 80 + { 81 + // Must be called on a subclass instance 82 + return nullptr; 83 + } 84 + 85 + extern "C" char ***_NSGetArgv(void); 86 + 87 + static void paContextStateCB(pa_context* c, void* priv) 88 + { 89 + void (^cb)(pa_context*) = (void (^)(pa_context*)) priv; 90 + 91 + pa_context_state_t state = pa_context_get_state(c); 92 + if (state == PA_CONTEXT_READY) 93 + { 94 + cb(c); 95 + Block_release(cb); 96 + 97 + // FIXME: We won't be notified about later disconnects... 98 + pa_context_set_state_callback(c, nullptr, nullptr); 99 + } 100 + else if (state == PA_CONTEXT_FAILED) 101 + { 102 + cb(nullptr); 103 + Block_release(cb); 104 + pa_context_set_state_callback(c, nullptr, nullptr); 105 + } 106 + } 107 + 108 + void AudioHardwareImplPA::getPAContext(void (^cb)(pa_context*)) 109 + { 110 + // TODO: destruction 111 + static std::mutex mutex; 112 + 113 + if (m_context == nullptr) 114 + { 115 + std::unique_lock<std::mutex> l(mutex); 116 + 117 + if (m_context == nullptr) 118 + { 119 + const char* appname = (*_NSGetArgv())[0]; 120 + const char* appid = "org.darlinghq.some-app"; 121 + 122 + pa_proplist* proplist = pa_proplist_new(); 123 + 124 + // Try to find a better application name & id from the bundle 125 + CFBundleRef mainBundle = CFBundleGetMainBundle(); 126 + if (mainBundle) 127 + { 128 + CFStringRef ident = CFBundleGetIdentifier(mainBundle); 129 + if (ident) 130 + appid = CFStringGetCStringPtr(ident, kCFStringEncodingUTF8); 131 + 132 + CFDictionaryRef infoDict = CFBundleGetLocalInfoDictionary(mainBundle); 133 + if (!infoDict) 134 + infoDict = CFBundleGetInfoDictionary(mainBundle); 135 + 136 + if (infoDict) 137 + { 138 + CFStringRef name = (CFStringRef) CFDictionaryGetValue(infoDict, CFSTR("CFBundleDisplayName")); 139 + if (!name) 140 + name = (CFStringRef) CFDictionaryGetValue(infoDict, CFSTR("CFBundleName")); 141 + if (name) 142 + appname = CFStringGetCStringPtr(name, kCFStringEncodingUTF8); 143 + } 144 + } 145 + 146 + pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, appname); 147 + pa_proplist_sets(proplist, PA_PROP_APPLICATION_ID, appid); 148 + // pa_proplist_sets(proplist, PA_PROP_APPLICATION_ICON_NAME, "icon-name"); 149 + // pa_proplist_sets(proplist, PA_PROP_MEDIA_ROLE, "game"); 150 + 151 + m_context = pa_context_new_with_proplist(PADispatchMainLoop::getAPI(), appname, proplist); 152 + pa_proplist_free(proplist); 153 + 154 + if (!m_context) 155 + { 156 + cb(nullptr); 157 + return; 158 + } 159 + 160 + pa_context_set_state_callback(m_context, paContextStateCB, Block_copy(cb)); 161 + 162 + if (pa_context_connect(m_context, nullptr, pa_context_flags_t(0), nullptr) < 0) 163 + { 164 + pa_context_set_state_callback(m_context, nullptr, nullptr); 165 + cb(nullptr); 166 + return; 167 + } 168 + } 169 + } 170 + 171 + cb(m_context); 172 + }
+74
src/CoreAudio/CoreAudio/pulse/AudioHardwareImplPAOutput.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 "AudioHardwareImplPAOutput.h" 21 + #include "AudioHardwareStreamPAOutput.h" 22 + 23 + AudioHardwareImplPAOutput::AudioHardwareImplPAOutput() 24 + { 25 + m_uid = CFSTR("PulseAudio:Output"); 26 + } 27 + 28 + AudioHardwareImplPAOutput::~AudioHardwareImplPAOutput() 29 + { 30 + } 31 + 32 + OSStatus AudioHardwareImplPAOutput::getPropertyData(const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, 33 + const void* inQualifierData, UInt32* ioDataSize, void* outData) 34 + { 35 + if (inAddress->mSelector == kAudioDevicePropertyStreamConfiguration) 36 + { 37 + size_t size = sizeof(AudioBufferList); 38 + 39 + if (inAddress->mScope == kAudioDevicePropertyScopeOutput) 40 + size += 1* sizeof(AudioBuffer); 41 + 42 + // Number of returned buffers is the number of channels 43 + if (AudioBufferList* abl = static_cast<AudioBufferList*>(outData); abl && *ioDataSize >= size) 44 + { 45 + if (inAddress->mScope == kAudioDevicePropertyScopeOutput) 46 + { 47 + abl->mNumberBuffers = 1; 48 + abl->mBuffers[0].mNumberChannels = 2; 49 + 50 + // TODO: Is the below stuff ever used? How? 51 + abl->mBuffers[0].mData = nullptr; 52 + abl->mBuffers[0].mDataByteSize = 0; 53 + } 54 + else 55 + abl->mNumberBuffers = 0; 56 + } 57 + 58 + *ioDataSize = size; 59 + return kAudioHardwareNoError; 60 + } 61 + 62 + return AudioHardwareImplPA::getPropertyData(inAddress, inQualifierDataSize, inQualifierData, ioDataSize, outData); 63 + } 64 + 65 + OSStatus AudioHardwareImplPAOutput::setPropertyData(const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, 66 + const void* inQualifierData, UInt32 inDataSize, const void* inData) 67 + { 68 + return AudioHardwareImplPA::setPropertyData(inAddress, inQualifierDataSize, inQualifierData, inDataSize, inData); 69 + } 70 + 71 + AudioHardwareStream* AudioHardwareImplPAOutput::createStream(AudioDeviceIOProc callback, void* clientData) 72 + { 73 + return new AudioHardwareStreamPAOutput(callback, clientData); 74 + }
+40
src/CoreAudio/CoreAudio/pulse/AudioHardwareImplPAOutput.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 AUDIOHARDWAREIMPLPAOUTPUT_H 21 + #define AUDIOHARDWAREIMPLPAOUTPUT_H 22 + #include "AudioHardwareImplPA.h" 23 + 24 + class AudioHardwareImplPAOutput : public AudioHardwareImplPA 25 + { 26 + public: 27 + AudioHardwareImplPAOutput(); 28 + ~AudioHardwareImplPAOutput(); 29 + 30 + OSStatus getPropertyData(const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, 31 + const void* inQualifierData, UInt32* ioDataSize, void* outData) override; 32 + 33 + OSStatus setPropertyData(const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, 34 + const void* inQualifierData, UInt32 inDataSize, const void* inData) override; 35 + protected: 36 + AudioHardwareStream* createStream(AudioDeviceIOProc callback, void* clientData) override; 37 + }; 38 + 39 + #endif 40 +
+31
src/CoreAudio/CoreAudio/pulse/AudioHardwareStreamPA.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 "AudioHardwareStreamPA.h" 21 + 22 + AudioHardwareStreamPA::AudioHardwareStreamPA(AudioDeviceIOProc callback, void* clientData) 23 + : m_callback(callback), m_clientData(clientData) 24 + { 25 + 26 + } 27 + 28 + AudioHardwareStreamPA::~AudioHardwareStreamPA() 29 + { 30 + 31 + }
+38
src/CoreAudio/CoreAudio/pulse/AudioHardwareStreamPA.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 AUDIOHARDWARESTREAMPA_H 21 + #define AUDIOHARDWARESTREAMPA_H 22 + #include "../AudioHardwareStream.h" 23 + #include <pulse/pulseaudio.h> 24 + #include <CoreAudio/CoreAudioTypes.h> 25 + #include <CoreAudio/AudioHardware.h> 26 + 27 + class AudioHardwareStreamPA : public AudioHardwareStream 28 + { 29 + public: 30 + AudioHardwareStreamPA(AudioDeviceIOProc callback, void* clientData); 31 + ~AudioHardwareStreamPA(); 32 + protected: 33 + AudioDeviceIOProc m_callback; 34 + void* m_clientData; 35 + }; 36 + 37 + #endif /* AUDIOHARDWARESTREAMPA_H */ 38 +
+94
src/CoreAudio/CoreAudio/pulse/AudioHardwareStreamPAOutput.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 "AudioHardwareStreamPAOutput.h" 21 + #include "AudioHardwareImplPA.h" 22 + #include <iostream> 23 + 24 + AudioHardwareStreamPAOutput::AudioHardwareStreamPAOutput(AudioDeviceIOProc callback, void* clientData) 25 + : AudioHardwareStreamPA(callback, clientData) 26 + { 27 + AudioHardwareImplPA::getPAContext(^(pa_context* context) { 28 + if (!context) 29 + { 30 + std::cerr << "Failed to get PulseAudio context\n"; 31 + return; 32 + } 33 + 34 + pa_sample_spec spec; 35 + 36 + spec.rate = 44100; 37 + spec.channels = 2; 38 + #if defined(__BIG_ENDIAN__) 39 + spec.format = PA_SAMPLE_FLOAT32BE; 40 + #elif defined(__LITTLE_ENDIAN__) 41 + spec.format = PA_SAMPLE_FLOAT32LE; 42 + #else 43 + # error Unknown endianess! 44 + #endif 45 + if (!pa_sample_spec_valid(&spec)) 46 + { 47 + std::cerr << "Failed to create a valid pa_sample_spec\n"; 48 + return; 49 + } 50 + 51 + m_stream = pa_stream_new(context, "CoreAudio", &spec, nullptr); 52 + 53 + // pa_stream_set_state_callback(m_stream, paStreamStateCB, this); 54 + pa_stream_set_write_callback(m_stream, paStreamWriteCB, this); 55 + 56 + start(); 57 + }); 58 + } 59 + 60 + AudioHardwareStreamPAOutput::~AudioHardwareStreamPAOutput() 61 + { 62 + if (m_stream) 63 + pa_stream_unref(m_stream); 64 + } 65 + 66 + void AudioHardwareStreamPAOutput::paStreamWriteCB(pa_stream* s, size_t length, void* self) 67 + { 68 + AudioHardwareStreamPAOutput* This = static_cast<AudioHardwareStreamPAOutput*>(self); 69 + 70 + // TODO: call the client for more data 71 + // pa_stream_write(m_stream, ...); 72 + } 73 + 74 + void AudioHardwareStreamPAOutput::start() 75 + { 76 + pa_stream_connect_playback(m_stream, nullptr, nullptr, (pa_stream_flags_t) 0 /* PA_STREAM_START_CORKED */, 77 + nullptr, nullptr); 78 + 79 + // pa_stream_cork(m_stream, false, [](pa_stream*, int, void*) {}, nullptr); 80 + } 81 + 82 + void AudioHardwareStreamPAOutput::stop(void(^cbDone)()) 83 + { 84 + m_cbDone = Block_copy(cbDone); 85 + 86 + pa_stream_cork(m_stream, true, [](pa_stream*, int, void* self) { 87 + AudioHardwareStreamPAOutput* This = static_cast<AudioHardwareStreamPAOutput*>(self); 88 + 89 + pa_stream_disconnect(This->m_stream); 90 + This->m_cbDone(); 91 + 92 + Block_release(This->m_cbDone); 93 + }, this); 94 + }
+40
src/CoreAudio/CoreAudio/pulse/AudioHardwareStreamPAOutput.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 AUDIOHARDWARESTREAMPAOUTPUT_H 21 + #define AUDIOHARDWARESTREAMPAOUTPUT_H 22 + #include "AudioHardwareStreamPA.h" 23 + 24 + class AudioHardwareStreamPAOutput : public AudioHardwareStreamPA 25 + { 26 + public: 27 + AudioHardwareStreamPAOutput(AudioDeviceIOProc callback, void* clientData); 28 + ~AudioHardwareStreamPAOutput(); 29 + 30 + void stop(void(^cbDone)()) override; 31 + private: 32 + void start(); 33 + static void paStreamWriteCB(pa_stream* s, size_t length, void* self); 34 + private: 35 + pa_stream* m_stream; 36 + void(^m_cbDone)(); 37 + }; 38 + 39 + #endif /* AUDIOHARDWARESTREAMPA_H */ 40 +
+308
src/CoreAudio/CoreAudio/pulse/PADispatchMainLoop.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 + #include "PADispatchMainLoop.h" 20 + 21 + PADispatchMainLoop::PADispatchMainLoop() 22 + { 23 + // Create GCD queue 24 + m_queue = dispatch_queue_create("org.darlinghq.coreaudio.pulseaudio", nullptr); 25 + } 26 + 27 + PADispatchMainLoop* PADispatchMainLoop::instance() 28 + { 29 + static PADispatchMainLoop inst; 30 + return &inst; 31 + } 32 + 33 + pa_mainloop_api* PADispatchMainLoop::getAPI() 34 + { 35 + static pa_mainloop_api api; 36 + 37 + if (!api.userdata) 38 + { 39 + api.io_new = io_new; 40 + api.io_enable = io_enable; 41 + api.io_free = io_free; 42 + api.io_set_destroy = io_set_destroy; 43 + 44 + api.time_new = time_new; 45 + api.time_restart = time_restart; 46 + api.time_set_destroy = time_set_destroy; 47 + api.time_free = time_free; 48 + 49 + api.defer_new = defer_new; 50 + api.defer_set_destroy = defer_set_destroy; 51 + api.defer_enable = defer_enable; 52 + api.defer_free = defer_free; 53 + 54 + api.userdata = instance(); 55 + } 56 + 57 + return &api; 58 + } 59 + 60 + struct dual_source 61 + { 62 + dispatch_source_t sourceRead, sourceWrite; 63 + bool readResumed, writeResumed; 64 + pa_io_event_cb_t callback; 65 + pa_io_event_destroy_cb_t destroy = nullptr; 66 + pa_io_event_flags_t events; 67 + void* userdata; 68 + }; 69 + 70 + pa_io_event* PADispatchMainLoop::io_new(pa_mainloop_api *a, int fd, pa_io_event_flags_t events, pa_io_event_cb_t cb, void *userdata) 71 + { 72 + dispatch_queue_t q = static_cast<PADispatchMainLoop*>(a->userdata)->m_queue; 73 + 74 + dual_source* dual = new dual_source; 75 + 76 + dual->callback = cb; 77 + dual->events = events; 78 + dual->userdata = userdata; 79 + dual->sourceRead = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, q); 80 + dual->sourceWrite = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, fd, 0, q); 81 + 82 + dispatch_source_set_event_handler(dual->sourceRead, ^{ 83 + dual->callback(getAPI(), reinterpret_cast<pa_io_event*>(dual), fd, PA_IO_EVENT_INPUT, dual->userdata); 84 + }); 85 + 86 + dispatch_source_set_event_handler(dual->sourceWrite, ^{ 87 + dual->callback(getAPI(), reinterpret_cast<pa_io_event*>(dual), fd, PA_IO_EVENT_OUTPUT, dual->userdata); 88 + }); 89 + 90 + dispatch_source_set_cancel_handler(dual->sourceWrite, ^{ 91 + if (dual->destroy) 92 + { 93 + dual->destroy(getAPI(), reinterpret_cast<pa_io_event*>(dual), dual->userdata); 94 + dual->destroy = nullptr; 95 + } 96 + delete dual; 97 + }); 98 + 99 + if (events & (PA_IO_EVENT_INPUT | PA_IO_EVENT_ERROR | PA_IO_EVENT_HANGUP)) 100 + { 101 + dispatch_resume(dual->sourceRead); 102 + dual->readResumed = true; 103 + } 104 + else 105 + dual->readResumed = false; 106 + 107 + if (events & (PA_IO_EVENT_OUTPUT)) 108 + { 109 + dispatch_resume(dual->sourceWrite); 110 + dual->writeResumed = true; 111 + } 112 + else 113 + dual->writeResumed = false; 114 + 115 + return reinterpret_cast<pa_io_event*>(dual); 116 + } 117 + 118 + void PADispatchMainLoop::io_enable(pa_io_event *e, pa_io_event_flags_t events) 119 + { 120 + dual_source* dual = reinterpret_cast<dual_source*>(e); 121 + 122 + if (events & (PA_IO_EVENT_INPUT | PA_IO_EVENT_ERROR | PA_IO_EVENT_HANGUP)) 123 + { 124 + if (!dual->readResumed) 125 + { 126 + dispatch_resume(dual->sourceRead); 127 + dual->readResumed = true; 128 + } 129 + } 130 + else if (dual->readResumed) 131 + { 132 + dispatch_suspend(dual->sourceRead); 133 + dual->readResumed = false; 134 + } 135 + 136 + if (events & (PA_IO_EVENT_OUTPUT)) 137 + { 138 + if (!dual->writeResumed) 139 + { 140 + dispatch_resume(dual->sourceWrite); 141 + dual->writeResumed = true; 142 + } 143 + } 144 + else if (dual->writeResumed) 145 + { 146 + dispatch_suspend(dual->sourceWrite); 147 + dual->writeResumed = false; 148 + } 149 + } 150 + 151 + void PADispatchMainLoop::io_free(pa_io_event *e) 152 + { 153 + dual_source* dual = reinterpret_cast<dual_source*>(e); 154 + 155 + if (!dual->readResumed) 156 + dispatch_resume(dual->sourceRead); 157 + dispatch_source_cancel(dual->sourceRead); 158 + dispatch_release(dual->sourceRead); 159 + 160 + if (!dual->writeResumed) 161 + dispatch_resume(dual->sourceWrite); 162 + dispatch_source_cancel(dual->sourceWrite); 163 + dispatch_release(dual->sourceWrite); 164 + 165 + // dual is freed in the cancel handler 166 + } 167 + 168 + void PADispatchMainLoop::io_set_destroy(pa_io_event *e, pa_io_event_destroy_cb_t cb) 169 + { 170 + dual_source* dual = reinterpret_cast<dual_source*>(e); 171 + dual->destroy = cb; 172 + } 173 + 174 + struct linux_timeval 175 + { 176 + unsigned long tv_sec; 177 + long tv_usec; 178 + }; 179 + 180 + struct pa_timer 181 + { 182 + dispatch_source_t source; 183 + void* userdata; 184 + struct timespec when; 185 + struct linux_timeval tv; 186 + pa_time_event_destroy_cb_t destroy = nullptr; 187 + }; 188 + 189 + pa_time_event *PADispatchMainLoop::time_new(pa_mainloop_api *a, const struct timeval *tv, pa_time_event_cb_t cb, void *userdata) 190 + { 191 + const linux_timeval* real_tv = reinterpret_cast<const linux_timeval*>(tv); 192 + dispatch_queue_t q = static_cast<PADispatchMainLoop*>(a->userdata)->m_queue; 193 + 194 + pa_timer* timer = new pa_timer; 195 + 196 + timer->userdata = userdata; 197 + 198 + timer->source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, q); 199 + 200 + timer->when.tv_sec = real_tv->tv_sec; 201 + timer->when.tv_nsec = real_tv->tv_usec * 1000; // convert to ns 202 + timer->tv = *real_tv; 203 + 204 + dispatch_source_set_timer(timer->source, dispatch_walltime(&timer->when, 0), 0, 0); 205 + 206 + dispatch_source_set_event_handler(timer->source, ^{ 207 + cb(getAPI(), reinterpret_cast<pa_time_event*>(timer), reinterpret_cast<const struct timeval *>(&timer->tv), timer->userdata); 208 + }); 209 + dispatch_source_set_cancel_handler(timer->source, ^{ 210 + if (timer->destroy) 211 + timer->destroy(getAPI(), reinterpret_cast<pa_time_event*>(timer), timer->userdata); 212 + delete timer; 213 + }); 214 + 215 + dispatch_resume(timer->source); 216 + 217 + return reinterpret_cast<pa_time_event*>(timer); 218 + } 219 + 220 + void PADispatchMainLoop::time_restart(pa_time_event *e, const struct timeval *tv) 221 + { 222 + const linux_timeval* real_tv = reinterpret_cast<const linux_timeval*>(tv); 223 + pa_timer* timer = reinterpret_cast<pa_timer*>(e); 224 + 225 + timer->when.tv_sec = real_tv->tv_sec; 226 + timer->when.tv_nsec = real_tv->tv_usec * 1000; // convert to ns 227 + timer->tv = *real_tv; 228 + 229 + dispatch_source_set_timer(timer->source, dispatch_walltime(&timer->when, 0), 0, 0); 230 + } 231 + 232 + void PADispatchMainLoop::time_set_destroy(pa_time_event *e, pa_time_event_destroy_cb_t cb) 233 + { 234 + pa_timer* timer = reinterpret_cast<pa_timer*>(e); 235 + 236 + timer->destroy = cb; 237 + } 238 + 239 + void PADispatchMainLoop::time_free(pa_time_event *e) 240 + { 241 + pa_timer* timer = reinterpret_cast<pa_timer*>(e); 242 + 243 + dispatch_source_cancel(timer->source); 244 + dispatch_release(timer->source); 245 + } 246 + 247 + struct defer_event 248 + { 249 + bool active = true; 250 + void* userdata; 251 + pa_defer_event_cb_t callback; 252 + pa_defer_event_destroy_cb_t destroy; 253 + }; 254 + 255 + void PADispatchMainLoop::defer_event_fire(void* context) 256 + { 257 + defer_event* ev = static_cast<defer_event*>(context); 258 + if (ev->active) 259 + { 260 + pa_mainloop_api* a = getAPI(); 261 + dispatch_queue_t q = static_cast<PADispatchMainLoop*>(a->userdata)->m_queue; 262 + 263 + ev->callback(a, static_cast<pa_defer_event*>(context), ev->userdata); 264 + 265 + if (ev->active) 266 + dispatch_async_f(q, context, defer_event_fire); 267 + } 268 + } 269 + 270 + pa_defer_event *PADispatchMainLoop::defer_new(pa_mainloop_api *a, pa_defer_event_cb_t cb, void *userdata) 271 + { 272 + dispatch_queue_t q = static_cast<PADispatchMainLoop*>(a->userdata)->m_queue; 273 + defer_event* e = new defer_event; 274 + 275 + e->userdata = userdata; 276 + e->callback = cb; 277 + 278 + return reinterpret_cast<pa_defer_event*>(e); 279 + } 280 + 281 + void PADispatchMainLoop::defer_set_destroy(pa_defer_event *e, pa_defer_event_destroy_cb_t cb) 282 + { 283 + defer_event* ev = reinterpret_cast<defer_event*>(e); 284 + 285 + ev->destroy = cb; 286 + } 287 + 288 + void PADispatchMainLoop::defer_enable(pa_defer_event *e, int b) 289 + { 290 + dispatch_queue_t q = instance()->m_queue; 291 + defer_event* ev = reinterpret_cast<defer_event*>(e); 292 + 293 + ev->active = !!b; 294 + if (ev->active) 295 + dispatch_async_f(q, e, defer_event_fire); 296 + } 297 + 298 + void PADispatchMainLoop::defer_free(pa_defer_event *e) 299 + { 300 + dispatch_queue_t q = instance()->m_queue; 301 + defer_event* ev = reinterpret_cast<defer_event*>(e); 302 + 303 + dispatch_async(q, ^{ 304 + if (ev->destroy) 305 + ev->destroy(getAPI(), e, ev->userdata); 306 + delete ev; 307 + }); 308 + }
+52
src/CoreAudio/CoreAudio/pulse/PADispatchMainLoop.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 PAGCDMAINLOOP_H 21 + #define PAGCDMAINLOOP_H 22 + #include <dispatch/dispatch.h> 23 + #include <pulse/pulseaudio.h> 24 + 25 + class PADispatchMainLoop 26 + { 27 + private: 28 + PADispatchMainLoop(); 29 + public: 30 + static PADispatchMainLoop* instance(); 31 + static pa_mainloop_api* getAPI(); 32 + private: 33 + static pa_io_event* io_new(pa_mainloop_api *a, int fd, pa_io_event_flags_t events, pa_io_event_cb_t cb, void *userdata); 34 + static void io_enable(pa_io_event *e, pa_io_event_flags_t events); 35 + static void io_free(pa_io_event *e); 36 + static void io_set_destroy(pa_io_event *e, pa_io_event_destroy_cb_t cb); 37 + 38 + static pa_time_event *time_new(pa_mainloop_api *a, const struct timeval *tv, pa_time_event_cb_t cb, void *userdata); 39 + static void time_restart(pa_time_event *e, const struct timeval *tv); 40 + static void time_set_destroy(pa_time_event *e, pa_time_event_destroy_cb_t cb); 41 + static void time_free(pa_time_event *e); 42 + 43 + static pa_defer_event *defer_new(pa_mainloop_api *a, pa_defer_event_cb_t cb, void *userdata); 44 + static void defer_set_destroy(pa_defer_event *e, pa_defer_event_destroy_cb_t cb); 45 + static void defer_enable(pa_defer_event *e, int b); 46 + static void defer_free(pa_defer_event *e); 47 + static void defer_event_fire(void* context); 48 + private: 49 + dispatch_queue_t m_queue; 50 + }; 51 + 52 + #endif
+11
src/CoreAudio/include/CoreAudio/AudioHardware.h
··· 116 116 kAudioDevicePropertyClockDevice = 'apcd' 117 117 }; 118 118 119 + enum { 120 + kAudioDevicePropertyScopeInput = kAudioObjectPropertyScopeInput, 121 + kAudioDevicePropertyScopeOutput = kAudioObjectPropertyScopeOutput, 122 + kAudioDevicePropertyScopePlayThrough = kAudioObjectPropertyScopePlayThrough, 123 + }; 124 + 125 + enum { 126 + kAudioDevicePropertyVolumeScalar = 'volm', 127 + kAudioDevicePropertyMute = 'mute', 128 + }; 129 + 119 130 typedef AudioObjectPropertySelector AudioHardwarePropertyID; 120 131 typedef AudioObjectPropertySelector AudioDevicePropertyID; 121 132