this repo has no description
1
fork

Configure Feed

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

CoreAudio: continued work on playback

+206 -70
+2 -2
src/CoreAudio/CoreAudio/AudioHardware.cpp
··· 34 34 static dispatch_once_t once; 35 35 dispatch_once(&once, ^{ 36 36 // TODO: Or ALSA 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>())); 37 + g_objects.insert(std::make_pair(kAudioObjectSystemObject, std::make_unique<AudioHardwareImplPA>(kAudioObjectSystemObject))); 38 + g_objects.insert(std::make_pair(kAudioObjectSystemObject + 1, std::make_unique<AudioHardwareImplPAOutput>(kAudioObjectSystemObject + 1))); 39 39 // TODO: PA input 40 40 }); 41 41 }
+11 -1
src/CoreAudio/CoreAudio/AudioHardwareImpl.cpp
··· 23 23 #include <cstring> 24 24 #include <CoreServices/MacErrors.h> 25 25 26 - AudioHardwareImpl::AudioHardwareImpl() 26 + AudioHardwareImpl::AudioHardwareImpl(AudioObjectID myId) 27 + : m_myId(myId) 27 28 { 28 29 } 29 30 ··· 124 125 switch (inAddress->mSelector) 125 126 { 126 127 case kAudioDevicePropertyVolumeScalar: 128 + case kAudioDevicePropertyVolumeDecibels: 127 129 *outIsSettable = true; 128 130 return kAudioHardwareNoError; 129 131 } ··· 220 222 *ioDataSize = sizeof(Float32); 221 223 return kAudioHardwareNoError; 222 224 } 225 + case kAudioDevicePropertyVolumeDecibels: 226 + { 227 + return kAudioHardwareNoError; 228 + } 223 229 } 224 230 return kAudioHardwareUnknownPropertyError; 225 231 } ··· 256 262 { 257 263 // TODO: Implement setting the volume 258 264 // Note: qualifier contains the channel ID (from kAudioDevicePropertyPreferredChannelsForStereo) 265 + return kAudioHardwareNoError; 266 + } 267 + case kAudioDevicePropertyVolumeDecibels: 268 + { 259 269 return kAudioHardwareNoError; 260 270 } 261 271 // These make sense only for ALSA, but I find it ridiculous that these properties can be set...
+5 -1
src/CoreAudio/CoreAudio/AudioHardwareImpl.h
··· 28 28 class AudioHardwareImpl 29 29 { 30 30 public: 31 - AudioHardwareImpl(); 31 + AudioHardwareImpl(AudioObjectID myId); 32 32 virtual ~AudioHardwareImpl(); 33 33 34 34 virtual void show(); ··· 66 66 virtual OSStatus getNearestStartTime(AudioTimeStamp* ioRequestedStartTime, 67 67 UInt32 inFlags); 68 68 virtual OSStatus setBufferSize(uint32_t bufferSize); 69 + uint32_t bufferSize() const { return m_bufferSize; } 70 + 71 + AudioObjectID id() const { return m_myId; } 69 72 private: 70 73 static OSStatus getPropertyCFString(CFStringRef str, UInt32* ioDataSize, void* outData); 71 74 static OSStatus getPropertyString(CFStringRef str, UInt32* ioDataSize, void* outData); 72 75 protected: 73 76 virtual AudioHardwareStream* createStream(AudioDeviceIOProc callback, void* clientData) = 0; 74 77 protected: 78 + AudioObjectID m_myId; 75 79 std::mutex m_procMutex; 76 80 std::map<AudioDeviceIOProcID, std::pair<AudioDeviceIOProc, void*>> m_proc; 77 81 int m_nextProcId = 1;
+7 -2
src/CoreAudio/CoreAudio/AudioHardwareStream.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 ··· 18 18 */ 19 19 20 20 #include "AudioHardwareStream.h" 21 + #include "AudioHardwareImpl.h" 21 22 22 - AudioHardwareStream::AudioHardwareStream() 23 + AudioHardwareStream::AudioHardwareStream(AudioHardwareImpl* hw) 24 + : m_hw(hw) 23 25 { 26 + m_bufferSize = hw->bufferSize(); 27 + m_buffer = new uint8_t[m_bufferSize]; 24 28 } 25 29 26 30 AudioHardwareStream::~AudioHardwareStream() 27 31 { 32 + delete m_buffer; 28 33 } 29 34
+9 -4
src/CoreAudio/CoreAudio/AudioHardwareStream.h
··· 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 #ifndef AUDIOHARDWARESTREAM_H 21 21 #define AUDIOHARDWARESTREAM_H 22 + #include <stdint.h> 23 + 24 + class AudioHardwareImpl; 22 25 23 26 class AudioHardwareStream 24 27 { 25 28 public: 26 - AudioHardwareStream(); 29 + AudioHardwareStream(AudioHardwareImpl* hw); 27 30 virtual ~AudioHardwareStream(); 28 31 29 32 virtual void stop(void(^cbDone)()) = 0; 30 - private: 31 - 33 + protected: 34 + AudioHardwareImpl* m_hw; 35 + uint32_t m_bufferSize; 36 + uint8_t* m_buffer; 32 37 }; 33 38 34 39 #endif /* AUDIOHARDWARESTREAM_H */
+49 -7
src/CoreAudio/CoreAudio/pulse/AudioHardwareImplPA.cpp
··· 23 23 #include "PADispatchMainLoop.h" 24 24 #include <CoreFoundation/CFBundle.h> 25 25 #include <CoreFoundation/CFString.h> 26 + #include <iostream> 26 27 #include <mutex> 27 28 28 29 pa_context* AudioHardwareImplPA::m_context; 30 + std::unique_ptr<PADispatchMainLoop> AudioHardwareImplPA::m_loop; 29 31 30 - AudioHardwareImplPA::AudioHardwareImplPA() 32 + AudioHardwareImplPA::AudioHardwareImplPA(AudioObjectID myId) 33 + : AudioHardwareImpl(myId) 31 34 { 32 35 m_name = CFSTR("PulseAudio"); 33 36 m_manufacturer = CFSTR("PulseAudio"); ··· 64 67 *ioDataSize = sizeof(AudioDeviceID) * 2; 65 68 return kAudioHardwareNoError; 66 69 } 67 - 70 + case kAudioDevicePropertyVolumeDecibelsToScalar: 71 + { 72 + if (Float32* vol = static_cast<Float32*>(outData); vol && *ioDataSize == sizeof(Float32)) 73 + { 74 + *vol = pa_sw_volume_to_linear(pa_sw_volume_from_dB(*vol)); 75 + } 76 + *ioDataSize = sizeof(Float32); 77 + return kAudioHardwareNoError; 78 + } 79 + case kAudioDevicePropertyVolumeScalarToDecibels: 80 + { 81 + if (Float32* vol = static_cast<Float32*>(outData); vol && *ioDataSize == sizeof(Float32)) 82 + { 83 + *vol = pa_sw_volume_to_dB(pa_sw_volume_from_linear(*vol)); 84 + } 85 + *ioDataSize = sizeof(Float32); 86 + return kAudioHardwareNoError; 87 + } 68 88 } 69 89 70 90 return AudioHardwareImpl::getPropertyData(inAddress, inQualifierDataSize, inQualifierData, ioDataSize, outData); ··· 91 111 pa_context_state_t state = pa_context_get_state(c); 92 112 if (state == PA_CONTEXT_READY) 93 113 { 114 + std::cout << "PA_CONTEXT_READY\n"; 115 + 94 116 cb(c); 95 117 Block_release(cb); 96 118 ··· 99 121 } 100 122 else if (state == PA_CONTEXT_FAILED) 101 123 { 124 + std::cout << "PA_CONTEXT_FAILED\n"; 125 + 102 126 cb(nullptr); 103 127 Block_release(cb); 104 128 pa_context_set_state_callback(c, nullptr, nullptr); 105 129 } 106 130 } 107 131 132 + static const char* appNameFromExecutable() 133 + { 134 + const char* name = (*_NSGetArgv())[0]; 135 + const char* p = std::strrchr(name, '/'); 136 + 137 + if (p && *(p+1)) 138 + return p+1; 139 + return name; 140 + } 141 + 108 142 void AudioHardwareImplPA::getPAContext(void (^cb)(pa_context*)) 109 143 { 110 144 // TODO: destruction ··· 116 150 117 151 if (m_context == nullptr) 118 152 { 119 - const char* appname = (*_NSGetArgv())[0]; 153 + const char* appname = appNameFromExecutable(); 120 154 const char* appid = "org.darlinghq.some-app"; 121 155 122 156 pa_proplist* proplist = pa_proplist_new(); ··· 148 182 // pa_proplist_sets(proplist, PA_PROP_APPLICATION_ICON_NAME, "icon-name"); 149 183 // pa_proplist_sets(proplist, PA_PROP_MEDIA_ROLE, "game"); 150 184 151 - m_context = pa_context_new_with_proplist(PADispatchMainLoop::getAPI(), appname, proplist); 185 + //pa_mainloop *mainloop = pa_mainloop_new (); 186 + 187 + m_loop.reset(new PADispatchMainLoop); 188 + 189 + m_context = pa_context_new_with_proplist(m_loop->getAPI() /*pa_mainloop_get_api(mainloop)*/, appname, proplist); 152 190 pa_proplist_free(proplist); 153 191 154 192 if (!m_context) ··· 159 197 160 198 pa_context_set_state_callback(m_context, paContextStateCB, Block_copy(cb)); 161 199 162 - if (pa_context_connect(m_context, nullptr, pa_context_flags_t(0), nullptr) < 0) 200 + if (pa_context_connect(m_context, nullptr, PA_CONTEXT_NOFLAGS, nullptr) < 0) 163 201 { 202 + std::cerr << "pa_context_connect() returned an error\n"; 164 203 pa_context_set_state_callback(m_context, nullptr, nullptr); 165 204 cb(nullptr); 166 205 return; 167 206 } 207 + 208 + // pa_mainloop_run (mainloop, NULL); 209 + m_loop->resume(); 168 210 } 169 211 } 170 - 171 - cb(m_context); 212 + else 213 + cb(m_context); 172 214 }
+6 -2
src/CoreAudio/CoreAudio/pulse/AudioHardwareImplPA.h
··· 20 20 #ifndef AUDIOHARDWAREIMPLPA_H 21 21 #define AUDIOHARDWAREIMPLPA_H 22 22 #include "../AudioHardwareImpl.h" 23 - #include <pulse/pulseaudio.h> 23 + #include "PADispatchMainLoop.h" 24 + #include <memory> 25 + 26 + class PADispatchMainLoop; 24 27 25 28 class AudioHardwareImplPA : public AudioHardwareImpl 26 29 { 27 30 public: 28 - AudioHardwareImplPA(); 31 + AudioHardwareImplPA(AudioObjectID myId); 29 32 30 33 OSStatus getPropertyData(const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, 31 34 const void* inQualifierData, UInt32* ioDataSize, void* outData) override; ··· 38 41 AudioHardwareStream* createStream(AudioDeviceIOProc callback, void* clientData) override; 39 42 private: 40 43 static pa_context* m_context; 44 + static std::unique_ptr<PADispatchMainLoop> m_loop; 41 45 }; 42 46 43 47 #endif
+3 -2
src/CoreAudio/CoreAudio/pulse/AudioHardwareImplPAOutput.cpp
··· 20 20 #include "AudioHardwareImplPAOutput.h" 21 21 #include "AudioHardwareStreamPAOutput.h" 22 22 23 - AudioHardwareImplPAOutput::AudioHardwareImplPAOutput() 23 + AudioHardwareImplPAOutput::AudioHardwareImplPAOutput(AudioObjectID myId) 24 + : AudioHardwareImplPA(myId) 24 25 { 25 26 m_uid = CFSTR("PulseAudio:Output"); 26 27 } ··· 70 71 71 72 AudioHardwareStream* AudioHardwareImplPAOutput::createStream(AudioDeviceIOProc callback, void* clientData) 72 73 { 73 - return new AudioHardwareStreamPAOutput(callback, clientData); 74 + return new AudioHardwareStreamPAOutput(this, callback, clientData); 74 75 }
+1 -1
src/CoreAudio/CoreAudio/pulse/AudioHardwareImplPAOutput.h
··· 24 24 class AudioHardwareImplPAOutput : public AudioHardwareImplPA 25 25 { 26 26 public: 27 - AudioHardwareImplPAOutput(); 27 + AudioHardwareImplPAOutput(AudioObjectID myId); 28 28 ~AudioHardwareImplPAOutput(); 29 29 30 30 OSStatus getPropertyData(const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize,
+2 -2
src/CoreAudio/CoreAudio/pulse/AudioHardwareStreamPA.cpp
··· 19 19 20 20 #include "AudioHardwareStreamPA.h" 21 21 22 - AudioHardwareStreamPA::AudioHardwareStreamPA(AudioDeviceIOProc callback, void* clientData) 23 - : m_callback(callback), m_clientData(clientData) 22 + AudioHardwareStreamPA::AudioHardwareStreamPA(AudioHardwareImpl* hw, AudioDeviceIOProc callback, void* clientData) 23 + : AudioHardwareStream(hw), m_callback(callback), m_clientData(clientData) 24 24 { 25 25 26 26 }
+1 -1
src/CoreAudio/CoreAudio/pulse/AudioHardwareStreamPA.h
··· 27 27 class AudioHardwareStreamPA : public AudioHardwareStream 28 28 { 29 29 public: 30 - AudioHardwareStreamPA(AudioDeviceIOProc callback, void* clientData); 30 + AudioHardwareStreamPA(AudioHardwareImpl* hw, AudioDeviceIOProc callback, void* clientData); 31 31 ~AudioHardwareStreamPA(); 32 32 protected: 33 33 AudioDeviceIOProc m_callback;
+31 -5
src/CoreAudio/CoreAudio/pulse/AudioHardwareStreamPAOutput.cpp
··· 20 20 #include "AudioHardwareStreamPAOutput.h" 21 21 #include "AudioHardwareImplPA.h" 22 22 #include <iostream> 23 + #include <algorithm> 23 24 24 - AudioHardwareStreamPAOutput::AudioHardwareStreamPAOutput(AudioDeviceIOProc callback, void* clientData) 25 - : AudioHardwareStreamPA(callback, clientData) 25 + AudioHardwareStreamPAOutput::AudioHardwareStreamPAOutput(AudioHardwareImpl* hw, AudioDeviceIOProc callback, void* clientData) 26 + : AudioHardwareStreamPA(hw, callback, clientData) 26 27 { 28 + // TODO: Abstract this into our superclass 27 29 AudioHardwareImplPA::getPAContext(^(pa_context* context) { 28 30 if (!context) 29 31 { ··· 65 67 66 68 void AudioHardwareStreamPAOutput::paStreamWriteCB(pa_stream* s, size_t length, void* self) 67 69 { 70 + std::cout << "AudioHardwareStreamPAOutput::paStreamWriteCB()\n"; 68 71 AudioHardwareStreamPAOutput* This = static_cast<AudioHardwareStreamPAOutput*>(self); 69 72 70 - // TODO: call the client for more data 71 - // pa_stream_write(m_stream, ...); 73 + AudioTimeStamp fake = {0}; 74 + AudioBufferList* abl = static_cast<AudioBufferList*>(alloca(sizeof(AudioBufferList) + sizeof(AudioBuffer))); 75 + 76 + // Non-interleaved (planar) audio would have multiple buffers, but PA doesn't even support that AFAIK 77 + abl->mNumberBuffers = 1; 78 + 79 + abl->mBuffers[0].mNumberChannels = 2; 80 + abl->mBuffers[0].mData = This->m_buffer; 81 + abl->mBuffers[0].mDataByteSize = std::min<UInt32>(This->m_bufferSize, length); 82 + 83 + // Call the client for more data 84 + OSStatus status = This->m_callback(This->m_hw->id(), &fake, nullptr, nullptr, abl, &fake, This->m_clientData); 85 + if (status != noErr) 86 + { 87 + std::cerr << "AudioDeviceIOProc returned " << status << ", corking...\n"; 88 + 89 + pa_stream_cork(This->m_stream, true, [](pa_stream*, int, void*) {}, nullptr); 90 + } 91 + else 92 + { 93 + std::cout << "AudioHardwareStreamPAOutput::paStreamWriteCB(): got " << abl->mBuffers[0].mDataByteSize << " bytes\n"; 94 + int rv = pa_stream_write(This->m_stream, abl->mBuffers[0].mData, abl->mBuffers[0].mDataByteSize, nullptr, 0, PA_SEEK_RELATIVE); 95 + if (rv != 0) 96 + std::cerr << "pa_stream_write() failed\n"; 97 + } 72 98 } 73 99 74 100 void AudioHardwareStreamPAOutput::start() 75 101 { 76 - pa_stream_connect_playback(m_stream, nullptr, nullptr, (pa_stream_flags_t) 0 /* PA_STREAM_START_CORKED */, 102 + pa_stream_connect_playback(m_stream, nullptr, nullptr, PA_STREAM_NOFLAGS /* PA_STREAM_START_CORKED */, 77 103 nullptr, nullptr); 78 104 79 105 // pa_stream_cork(m_stream, false, [](pa_stream*, int, void*) {}, nullptr);
+1 -1
src/CoreAudio/CoreAudio/pulse/AudioHardwareStreamPAOutput.h
··· 24 24 class AudioHardwareStreamPAOutput : public AudioHardwareStreamPA 25 25 { 26 26 public: 27 - AudioHardwareStreamPAOutput(AudioDeviceIOProc callback, void* clientData); 27 + AudioHardwareStreamPAOutput(AudioHardwareImpl* hw, AudioDeviceIOProc callback, void* clientData); 28 28 ~AudioHardwareStreamPAOutput(); 29 29 30 30 void stop(void(^cbDone)()) override;
+66 -35
src/CoreAudio/CoreAudio/pulse/PADispatchMainLoop.cpp
··· 17 17 along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 18 */ 19 19 #include "PADispatchMainLoop.h" 20 + #include <iostream> 20 21 21 22 PADispatchMainLoop::PADispatchMainLoop() 22 23 { 23 24 // Create GCD queue 24 25 m_queue = dispatch_queue_create("org.darlinghq.coreaudio.pulseaudio", nullptr); 26 + 27 + // PulseAudio expects the event loop to be suspended while we're creating the context. 28 + // I couldn't find any mention of this in the documentation, but figured it out the hard way. 29 + dispatch_suspend(m_queue); 25 30 } 26 31 27 - PADispatchMainLoop* PADispatchMainLoop::instance() 32 + PADispatchMainLoop::~PADispatchMainLoop() 33 + { 34 + resume(); 35 + dispatch_release(m_queue); 36 + } 37 + 38 + void PADispatchMainLoop::suspend() 28 39 { 29 - static PADispatchMainLoop inst; 30 - return &inst; 40 + if (!m_suspended) 41 + { 42 + dispatch_suspend(m_queue); 43 + m_suspended = true; 44 + } 45 + } 46 + 47 + void PADispatchMainLoop::resume() 48 + { 49 + if (m_suspended) 50 + { 51 + dispatch_resume(m_queue); 52 + m_suspended = false; 53 + } 31 54 } 32 55 33 56 pa_mainloop_api* PADispatchMainLoop::getAPI() 34 57 { 35 - static pa_mainloop_api api; 36 - 37 - if (!api.userdata) 58 + if (!m_api.userdata) 38 59 { 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; 60 + m_api.io_new = io_new; 61 + m_api.io_enable = io_enable; 62 + m_api.io_free = io_free; 63 + m_api.io_set_destroy = io_set_destroy; 43 64 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; 65 + m_api.time_new = time_new; 66 + m_api.time_restart = time_restart; 67 + m_api.time_set_destroy = time_set_destroy; 68 + m_api.time_free = time_free; 48 69 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; 70 + m_api.defer_new = defer_new; 71 + m_api.defer_set_destroy = defer_set_destroy; 72 + m_api.defer_enable = defer_enable; 73 + m_api.defer_free = defer_free; 53 74 54 - api.userdata = instance(); 75 + m_api.userdata = this; 55 76 } 56 77 57 - return &api; 78 + return &m_api; 58 79 } 59 80 60 81 struct dual_source ··· 69 90 70 91 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 92 { 72 - dispatch_queue_t q = static_cast<PADispatchMainLoop*>(a->userdata)->m_queue; 93 + PADispatchMainLoop* This = static_cast<PADispatchMainLoop*>(a->userdata); 94 + dispatch_queue_t q = This->m_queue; 73 95 74 96 dual_source* dual = new dual_source; 75 97 ··· 80 102 dual->sourceWrite = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, fd, 0, q); 81 103 82 104 dispatch_source_set_event_handler(dual->sourceRead, ^{ 83 - dual->callback(getAPI(), reinterpret_cast<pa_io_event*>(dual), fd, PA_IO_EVENT_INPUT, dual->userdata); 105 + dual->callback(This->getAPI(), reinterpret_cast<pa_io_event*>(dual), fd, PA_IO_EVENT_INPUT, dual->userdata); 84 106 }); 85 107 86 108 dispatch_source_set_event_handler(dual->sourceWrite, ^{ 87 - dual->callback(getAPI(), reinterpret_cast<pa_io_event*>(dual), fd, PA_IO_EVENT_OUTPUT, dual->userdata); 109 + std::cout << "PADispatchMainLoop::io_new(): write event\n"; 110 + dual->callback(This->getAPI(), reinterpret_cast<pa_io_event*>(dual), fd, PA_IO_EVENT_OUTPUT, dual->userdata); 88 111 }); 89 112 90 113 dispatch_source_set_cancel_handler(dual->sourceWrite, ^{ 91 114 if (dual->destroy) 92 115 { 93 - dual->destroy(getAPI(), reinterpret_cast<pa_io_event*>(dual), dual->userdata); 116 + dual->destroy(This->getAPI(), reinterpret_cast<pa_io_event*>(dual), dual->userdata); 94 117 dual->destroy = nullptr; 95 118 } 96 119 delete dual; ··· 189 212 pa_time_event *PADispatchMainLoop::time_new(pa_mainloop_api *a, const struct timeval *tv, pa_time_event_cb_t cb, void *userdata) 190 213 { 191 214 const linux_timeval* real_tv = reinterpret_cast<const linux_timeval*>(tv); 192 - dispatch_queue_t q = static_cast<PADispatchMainLoop*>(a->userdata)->m_queue; 215 + PADispatchMainLoop* This = static_cast<PADispatchMainLoop*>(a->userdata); 216 + dispatch_queue_t q = This->m_queue; 193 217 194 218 pa_timer* timer = new pa_timer; 195 219 ··· 204 228 dispatch_source_set_timer(timer->source, dispatch_walltime(&timer->when, 0), 0, 0); 205 229 206 230 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); 231 + cb(This->getAPI(), reinterpret_cast<pa_time_event*>(timer), reinterpret_cast<const struct timeval *>(&timer->tv), timer->userdata); 208 232 }); 209 233 dispatch_source_set_cancel_handler(timer->source, ^{ 210 234 if (timer->destroy) 211 - timer->destroy(getAPI(), reinterpret_cast<pa_time_event*>(timer), timer->userdata); 235 + timer->destroy(This->getAPI(), reinterpret_cast<pa_time_event*>(timer), timer->userdata); 212 236 delete timer; 213 237 }); 214 238 ··· 249 273 bool active = true; 250 274 void* userdata; 251 275 pa_defer_event_cb_t callback; 252 - pa_defer_event_destroy_cb_t destroy; 276 + pa_defer_event_destroy_cb_t destroy = nullptr; 277 + PADispatchMainLoop* loop; 253 278 }; 254 279 255 280 void PADispatchMainLoop::defer_event_fire(void* context) ··· 257 282 defer_event* ev = static_cast<defer_event*>(context); 258 283 if (ev->active) 259 284 { 260 - pa_mainloop_api* a = getAPI(); 285 + pa_mainloop_api* a = ev->loop->getAPI(); 261 286 dispatch_queue_t q = static_cast<PADispatchMainLoop*>(a->userdata)->m_queue; 262 287 263 288 ev->callback(a, static_cast<pa_defer_event*>(context), ev->userdata); ··· 269 294 270 295 pa_defer_event *PADispatchMainLoop::defer_new(pa_mainloop_api *a, pa_defer_event_cb_t cb, void *userdata) 271 296 { 272 - dispatch_queue_t q = static_cast<PADispatchMainLoop*>(a->userdata)->m_queue; 297 + PADispatchMainLoop* This = static_cast<PADispatchMainLoop*>(a->userdata); 298 + dispatch_queue_t q = This->m_queue; 273 299 defer_event* e = new defer_event; 274 300 301 + e->loop = This; 275 302 e->userdata = userdata; 276 303 e->callback = cb; 304 + 305 + dispatch_async_f(q, e, defer_event_fire); 277 306 278 307 return reinterpret_cast<pa_defer_event*>(e); 279 308 } ··· 287 316 288 317 void PADispatchMainLoop::defer_enable(pa_defer_event *e, int b) 289 318 { 290 - dispatch_queue_t q = instance()->m_queue; 291 319 defer_event* ev = reinterpret_cast<defer_event*>(e); 320 + dispatch_queue_t q = ev->loop->m_queue; 292 321 293 - ev->active = !!b; 294 - if (ev->active) 322 + if (!ev->active && b) 295 323 dispatch_async_f(q, e, defer_event_fire); 324 + ev->active = !!b; 296 325 } 297 326 298 327 void PADispatchMainLoop::defer_free(pa_defer_event *e) 299 328 { 300 - dispatch_queue_t q = instance()->m_queue; 301 329 defer_event* ev = reinterpret_cast<defer_event*>(e); 330 + dispatch_queue_t q = ev->loop->m_queue; 331 + 332 + ev->active = false; 302 333 303 334 dispatch_async(q, ^{ 304 335 if (ev->destroy) 305 - ev->destroy(getAPI(), e, ev->userdata); 336 + ev->destroy(ev->loop->getAPI(), e, ev->userdata); 306 337 delete ev; 307 338 }); 308 339 }
+9 -4
src/CoreAudio/CoreAudio/pulse/PADispatchMainLoop.h
··· 24 24 25 25 class PADispatchMainLoop 26 26 { 27 - private: 27 + public: 28 28 PADispatchMainLoop(); 29 - public: 30 - static PADispatchMainLoop* instance(); 31 - static pa_mainloop_api* getAPI(); 29 + ~PADispatchMainLoop(); 30 + 31 + void suspend(); 32 + void resume(); 33 + 34 + pa_mainloop_api* getAPI(); 32 35 private: 33 36 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 37 static void io_enable(pa_io_event *e, pa_io_event_flags_t events); ··· 47 50 static void defer_event_fire(void* context); 48 51 private: 49 52 dispatch_queue_t m_queue; 53 + pa_mainloop_api m_api = {0}; 54 + bool m_suspended = true; 50 55 }; 51 56 52 57 #endif
+3
src/CoreAudio/include/CoreAudio/AudioHardware.h
··· 124 124 125 125 enum { 126 126 kAudioDevicePropertyVolumeScalar = 'volm', 127 + kAudioDevicePropertyVolumeDecibels = 'vold', 128 + kAudioDevicePropertyVolumeDecibelsToScalar = 'db2v', 129 + kAudioDevicePropertyVolumeScalarToDecibels = 'v2db', 127 130 kAudioDevicePropertyMute = 'mute', 128 131 }; 129 132