this repo has no description
1
fork

Configure Feed

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

CoreServices: use malloc_size() in MacMemory

+299 -1565
+10 -54
src/CoreAudio/AudioToolbox/AUComponent.cpp
··· 1 1 #include "darling-config.h" 2 2 #include "AUComponent.h" 3 - #include "AudioUnitALSA.h" 4 - #include "AudioUnitPA.h" 3 + #include "AudioUnitCA.h" 5 4 #include <alsa/asoundlib.h> 6 5 #include <CoreServices/MacErrors.h> 7 6 #include "stub.h" 8 7 9 8 AudioComponent AudioComponentFindNext(AudioComponent inAComponent, AudioComponentDescription *inDesc) 10 9 { 11 - int index = -1; 12 - 13 - if (inDesc->componentType != kAudioUnitType_Output && inDesc->componentType != kAudioUnitType_Mixer) 14 - return nullptr; 15 - 16 - if (inAComponent != nullptr) 17 - index = GetComponentIndex(inAComponent); 18 - 19 - #if defined(ENABLE_ALSA) 20 - if (snd_card_next(&index) || index == -1) 21 - return nullptr; 22 - #endif 23 - 24 - return CreateComponent(kComponentTypeAudioUnit, index); 10 + // TODO 11 + return nullptr; 25 12 } 26 13 27 14 OSStatus AudioComponentGetDescription(AudioComponent inComponent, AudioComponentDescription *outDesc) ··· 54 41 55 42 AudioComponent AudioComponentInstanceGetComponent(AudioComponentInstance inInstance) 56 43 { 57 - return CreateComponent(kComponentTypeAudioUnit, static_cast<AudioOutputUnitComponent*>(inInstance)->cardIndex()); 44 + // return CreateComponent(kComponentTypeAudioUnit, static_cast<AudioOutputUnitComponent*>(inInstance)->cardIndex()); 45 + return nullptr; 58 46 } 59 47 60 48 OSStatus AudioComponentInstanceNew(AudioComponent inComponent, AudioComponentInstance *outInstance) 61 49 { 62 - #if defined(ENABLE_PULSEAUDIO) 63 - *outInstance = new AudioUnitPA; 64 - #elif defined(ENABLE_ALSA) 65 - *outInstance = AudioUnitALSA::create(GetComponentIndex(inComponent)); 66 - #else 67 - *outInstance = nullptr; 68 - return unimpErr; 69 - #endif 70 - return *outInstance ? noErr : paramErr; 50 + // TODO: pass inComponent to specify which audio device to use? 51 + //*outInstance = new AudioUnitCA; 52 + //return *outInstance ? noErr : paramErr; 53 + return noErr; 71 54 } 72 55 73 56 OSStatus AudioComponentCopyName(AudioComponent inComponent, CFStringRef *outName) 74 57 { 75 - int index = GetComponentIndex(inComponent); 76 - char* name; 77 - 78 - if (!outName) 79 - return paramErr; 80 - 81 - #if defined(ENABLE_ALSA) 82 - if (snd_card_get_longname(index, &name)) 83 - return paramErr; 84 - #elif defined(ENABLE_PULSEAUDIO) 85 - name = strdup("PulseAudio"); 86 - #endif 87 - 88 - *outName = CFStringCreateWithCString(nullptr, name, kCFStringEncodingUTF8); 89 - free(name); 58 + // TODO 90 59 91 60 return noErr; 92 61 } ··· 95 64 { 96 65 UInt32 count = 0; 97 66 98 - #if defined(ENABLE_ALSA) 99 - int index = -1; 100 - 101 - // Is there a better way? 102 - do 103 - { 104 - snd_card_next(&index); 105 - if (index != -1) 106 - count++; 107 - } 108 - while (index != -1); 109 - #elif defined(ENABLE_PULSEAUDIO) 110 67 count = 1; 111 - #endif 112 68 113 69 return count; 114 70 }
-1
src/CoreAudio/AudioToolbox/AudioUnit.cpp
··· 1 1 #include "darling-config.h" 2 2 #include "AudioUnit.h" 3 3 #include "AudioOutputUnitComponent.h" 4 - #include "AudioUnitALSA.h" 5 4 #include "stub.h" 6 5 #include <CoreServices/MacErrors.h> 7 6
-770
src/CoreAudio/AudioToolbox/AudioUnitALSA.cpp
··· 1 - #include <iostream> 2 - #include "AudioUnitALSA.h" 3 - #include "AudioUnitProperties.h" 4 - #include <CoreServices/MacErrors.h> 5 - #include "stub.h" 6 - #include <sstream> 7 - #include <stdexcept> 8 - #include <memory> 9 - #include <cstdio> 10 - #include <dispatch/dispatch.h> 11 - 12 - #define SAMPLE_PERIOD 4096 13 - 14 - static dispatch_queue_t g_audioQueue; 15 - 16 - AudioUnitALSA::AudioUnitALSA(int cardIndex, char* cardName) 17 - : m_cardIndex(cardIndex), m_cardName(cardName), m_pcmOutput(nullptr), m_pcmInput(nullptr) 18 - { 19 - static dispatch_once_t pred; 20 - dispatch_once(&pred, ^{ 21 - g_audioQueue = dispatch_queue_create("org.darlinghq.audiounit", nullptr); 22 - }); 23 - } 24 - 25 - static void throwAlsaError(const std::string& msg, int errCode) 26 - { 27 - std::stringstream ss; 28 - ss << msg << ": " << snd_strerror(errCode); 29 - throw std::runtime_error(ss.str()); 30 - } 31 - 32 - static snd_pcm_format_t alsaFormatForASBD(const AudioStreamBasicDescription& asbd) 33 - { 34 - bool isFloat = asbd.mFormatFlags & kAudioFormatFlagIsFloat; 35 - bool isSigned = asbd.mFormatFlags & kAudioFormatFlagIsSignedInteger; 36 - bool isBE = asbd.mFormatFlags & kAudioFormatFlagIsBigEndian; 37 - 38 - if (asbd.mFormatID == kAudioFormatLinearPCM) 39 - { 40 - if (isFloat) 41 - return isBE ? SND_PCM_FORMAT_FLOAT_BE : SND_PCM_FORMAT_FLOAT_LE; 42 - 43 - switch (asbd.mBitsPerChannel) 44 - { 45 - case 8: 46 - if (isSigned) 47 - return SND_PCM_FORMAT_S8; 48 - else 49 - return SND_PCM_FORMAT_U8; 50 - case 16: 51 - if (isSigned) 52 - return isBE ? SND_PCM_FORMAT_S16_BE : SND_PCM_FORMAT_S16_LE; 53 - else 54 - return isBE ? SND_PCM_FORMAT_U16_BE : SND_PCM_FORMAT_U16_LE; 55 - case 24: 56 - if (isSigned) 57 - return isBE ? SND_PCM_FORMAT_S24_BE : SND_PCM_FORMAT_S24_LE; 58 - else 59 - return isBE ? SND_PCM_FORMAT_U24_BE : SND_PCM_FORMAT_U24_LE; 60 - case 32: 61 - if (isSigned) 62 - return isBE ? SND_PCM_FORMAT_S32_BE : SND_PCM_FORMAT_S32_LE; 63 - else 64 - return isBE ? SND_PCM_FORMAT_U32_BE : SND_PCM_FORMAT_U32_LE; 65 - default: 66 - throw std::runtime_error("Invalid mBitsPerChannel value"); 67 - } 68 - } 69 - else 70 - throw std::runtime_error("Unsupported mFormatID value"); 71 - } 72 - 73 - AudioUnitComponent* AudioUnitALSA::create(int cardIndex) 74 - { 75 - char* name; 76 - 77 - if (cardIndex > 0) 78 - { 79 - if (snd_card_get_name(cardIndex, &name)) 80 - return nullptr; 81 - } 82 - else 83 - { 84 - name = strdup("default" /*"plughw:0"*/); 85 - } 86 - 87 - return new AudioUnitALSA(cardIndex, name); 88 - } 89 - 90 - AudioUnitALSA::~AudioUnitALSA() 91 - { 92 - deinit(); 93 - free(m_cardName); 94 - } 95 - 96 - OSStatus AudioUnitALSA::reset(AudioUnitScope inScope, AudioUnitElement inElement) 97 - { 98 - STUB(); 99 - return unimpErr; 100 - } 101 - 102 - void AudioUnitALSA::initOutput() 103 - { 104 - snd_pcm_hw_params_t* hw_params = nullptr; 105 - snd_pcm_sw_params_t* sw_params = nullptr; 106 - 107 - try 108 - { 109 - // Configure ALSA based on m_configOutputPlayback 110 - int err; 111 - const AudioStreamBasicDescription& alsaConfig = m_config[kOutputBus].second; 112 - unsigned int rate = alsaConfig.mSampleRate; 113 - 114 - //if (memcmp(&m_config[kOutputBus].second, &m_config[kOutputBus].first, sizeof(AudioStreamBasicDescription)) != 0) 115 - // throw std::runtime_error("Different input and HW config not implemented yet"); 116 - 117 - // Let ALSA do the conversion on its own 118 - m_config[kOutputBus].second = m_config[kOutputBus].first; 119 - 120 - err = snd_pcm_open(&m_pcmOutput, m_cardName, SND_PCM_STREAM_PLAYBACK, 0); 121 - if (err < 0) 122 - throwAlsaError("Failed to initialize playback PCM", err); 123 - 124 - err = snd_pcm_hw_params_malloc(&hw_params); 125 - if (err < 0) 126 - throwAlsaError("Failed to alloc hw params", err); 127 - 128 - err = snd_pcm_hw_params_any(m_pcmOutput, hw_params); 129 - if (err < 0) 130 - throwAlsaError("Failed to init hw params", err); 131 - 132 - if (isOutputPlanar()) 133 - err = snd_pcm_hw_params_set_access(m_pcmOutput, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED); 134 - else 135 - err = snd_pcm_hw_params_set_access(m_pcmOutput, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); 136 - 137 - if (err < 0) 138 - throwAlsaError("Failed to set interleaved access", err); 139 - 140 - err = snd_pcm_hw_params_set_format(m_pcmOutput, hw_params, alsaFormatForASBD(alsaConfig)); 141 - if (err < 0) 142 - throwAlsaError("Failed to set format", err); 143 - 144 - err = snd_pcm_hw_params_set_rate_near(m_pcmOutput, hw_params, &rate, 0); 145 - if (err < 0) 146 - throwAlsaError("Failed to set sample rate", err); 147 - 148 - // LOG << "Channel count: " << int(alsaConfig.mChannelsPerFrame) << std::endl; 149 - err = snd_pcm_hw_params_set_channels(m_pcmOutput, hw_params, alsaConfig.mChannelsPerFrame); 150 - if (err < 0) 151 - throwAlsaError("Failed to set channel count", err); 152 - 153 - err = snd_pcm_hw_params(m_pcmOutput, hw_params); 154 - if (err < 0) 155 - throwAlsaError("Failed to set HW parameters", err); 156 - 157 - snd_pcm_hw_params_free(hw_params); 158 - hw_params = nullptr; 159 - 160 - err = snd_pcm_sw_params_malloc(&sw_params); 161 - if (err < 0) 162 - throwAlsaError("Failed to alloc sw params", err); 163 - 164 - err = snd_pcm_sw_params_current(m_pcmOutput, sw_params); 165 - if (err < 0) 166 - throwAlsaError("Failed to init sw params", err); 167 - 168 - err = snd_pcm_sw_params_set_avail_min(m_pcmOutput, sw_params, SAMPLE_PERIOD); 169 - if (err < 0) 170 - throwAlsaError("snd_pcm_sw_params_set_avail_min() failed", err); 171 - 172 - err = snd_pcm_sw_params_set_start_threshold(m_pcmOutput, sw_params, 0U); 173 - if (err < 0) 174 - throwAlsaError("snd_pcm_sw_params_set_start_threshold() failed", err); 175 - 176 - err = snd_pcm_sw_params_set_tstamp_mode(m_pcmOutput, sw_params, SND_PCM_TSTAMP_ENABLE); 177 - if (err < 0) 178 - throwAlsaError("snd_pcm_sw_params_set_tstamp_mode() failed", err); 179 - 180 - err = snd_pcm_sw_params(m_pcmOutput, sw_params); 181 - if (err < 0) 182 - throwAlsaError("Failed to set SW parameters", err); 183 - 184 - snd_pcm_sw_params_free(sw_params); 185 - sw_params = nullptr; 186 - } 187 - catch (...) 188 - { 189 - if (hw_params != nullptr) 190 - snd_pcm_hw_params_free(hw_params); 191 - if (sw_params != nullptr) 192 - snd_pcm_sw_params_free(sw_params); 193 - 194 - throw; 195 - } 196 - } 197 - 198 - void AudioUnitALSA::initInput() 199 - { 200 - STUB(); 201 - 202 - try 203 - { 204 - //if (memcmp(&m_config[kInputBus].second, &m_config[kInputBus].first, sizeof(AudioStreamBasicDescription)) != 0) 205 - // throw std::runtime_error("Different input and HW config not implemented yet"); 206 - 207 - // Let ALSA do the conversion on its own 208 - m_config[kInputBus].first = m_config[kInputBus].second; 209 - 210 - // TODO: support recording 211 - } 212 - catch (...) 213 - { 214 - throw; 215 - } 216 - } 217 - 218 - OSStatus AudioUnitALSA::init() 219 - { 220 - try 221 - { 222 - if (m_pcmOutput || m_pcmInput) 223 - return kAudioUnitErr_Initialized; 224 - 225 - /*if (m_enableInput && snd_pcm_open(&m_pcmInput, m_cardName, SND_PCM_STREAM_CAPTURE, 0)) 226 - { 227 - deinit(); 228 - 229 - LOG << "Failed to initialize capture PCM " << m_cardName << std::endl; 230 - return kAudioUnitErr_FailedInitialization; 231 - }*/ 232 - 233 - if (m_enableOutput) 234 - initOutput(); 235 - if (m_enableInput) 236 - initInput(); 237 - } 238 - catch (const std::exception& e) 239 - { 240 - // ERROR() << e.what(); 241 - 242 - deinit(); 243 - return kAudioUnitErr_FailedInitialization; 244 - } 245 - 246 - return noErr; 247 - } 248 - 249 - OSStatus AudioUnitALSA::deinit() 250 - { 251 - if (m_pcmOutput) 252 - { 253 - snd_pcm_close(m_pcmOutput); 254 - m_pcmOutput = nullptr; 255 - } 256 - if (m_pcmInput) 257 - { 258 - snd_pcm_close(m_pcmInput); 259 - m_pcmInput = nullptr; 260 - } 261 - return noErr; 262 - } 263 - 264 - void AudioUnitALSA::processAudioEvent(struct pollfd origPoll, int event) 265 - { 266 - struct pollfd pfd = origPoll; 267 - unsigned short revents; 268 - int err; 269 - 270 - TRACE1(event); 271 - 272 - pfd.revents = event; 273 - 274 - err = snd_pcm_poll_descriptors_revents(m_pcmOutput, &pfd, 1, &revents); 275 - // if (err < 0) 276 - // ERROR() << "snd_pcm_poll_descriptors_revents() failed: " << snd_strerror(err); 277 - 278 - if (revents & POLLIN) 279 - pushDataFromInput(); 280 - 281 - if (revents & POLLOUT) 282 - requestDataForPlayback(); 283 - } 284 - 285 - void AudioUnitALSA::requestDataForPlayback() 286 - { 287 - AudioUnitRenderActionFlags flags; 288 - AudioTimeStamp ts; 289 - AudioBufferList* bufs; 290 - OSStatus err; 291 - std::unique_ptr<uint8_t[]> data; 292 - snd_pcm_uframes_t availFrames; 293 - snd_htimestamp_t alsaTimestamp; 294 - const AudioStreamBasicDescription& config = m_config[kOutputBus].first; 295 - UInt32 cc = config.mChannelsPerFrame; 296 - 297 - // TRACE(); 298 - 299 - memset(&ts, 0, sizeof(ts)); 300 - 301 - if (isOutputPlanar()) 302 - { 303 - bufs = (AudioBufferList*) operator new(sizeof(AudioBufferList) + (cc-1)*sizeof(AudioBuffer)); 304 - bufs->mNumberBuffers = cc; 305 - } 306 - else 307 - { 308 - bufs = (AudioBufferList*) operator new(sizeof(AudioBufferList)); 309 - bufs->mNumberBuffers = 1; 310 - } 311 - 312 - if (m_shouldAllocateBuffer) 313 - { 314 - if (isOutputPlanar()) 315 - { 316 - UInt32 bytesPerChannel = config.mBytesPerFrame * SAMPLE_PERIOD; 317 - 318 - data.reset(new uint8_t[cc*bytesPerChannel]); 319 - 320 - for (UInt32 i = 0; i < cc; i++) 321 - { 322 - bufs->mBuffers[i].mNumberChannels = 1; 323 - bufs->mBuffers[i].mDataByteSize = bytesPerChannel; 324 - bufs->mBuffers[i].mData = data.get() + i*bytesPerChannel; 325 - } 326 - } 327 - else 328 - { 329 - bufs->mBuffers[0].mNumberChannels = cc; 330 - bufs->mBuffers[0].mDataByteSize = config.mBytesPerFrame * SAMPLE_PERIOD; 331 - 332 - data.reset(new uint8_t[bufs->mBuffers[0].mDataByteSize]); 333 - bufs->mBuffers[0].mData = data.get(); 334 - } 335 - } 336 - else 337 - { 338 - if (isOutputPlanar()) 339 - { 340 - for (UInt32 i = 0; i < cc; i++) 341 - { 342 - bufs->mBuffers[i].mDataByteSize = 0; 343 - bufs->mBuffers[i].mData = nullptr; 344 - } 345 - } 346 - else 347 - { 348 - bufs->mBuffers[0].mDataByteSize = 0; 349 - bufs->mBuffers[0].mData = nullptr; 350 - } 351 - } 352 - 353 - snd_pcm_htimestamp(m_pcmOutput, &availFrames, &alsaTimestamp); 354 - 355 - // TODO: fill in AudioTimeStamp based on alsaTimestamp 356 - 357 - err = AudioUnitRender(m_inputUnit.sourceAudioUnit, &flags, &ts, kOutputBus, SAMPLE_PERIOD, bufs); 358 - 359 - if (err != noErr) 360 - { 361 - // ERROR() << "Render callback failed with error " << err; 362 - 363 - // Fill with silence, the error may be temporary 364 - UInt32 bytes = config.mBytesPerFrame * SAMPLE_PERIOD; 365 - 366 - if (!m_shouldAllocateBuffer) 367 - { 368 - if (isOutputPlanar()) 369 - { 370 - data.reset(new uint8_t[bytes*cc]); 371 - memset(data.get(), 0, bytes*cc); 372 - } 373 - else 374 - { 375 - data.reset(new uint8_t[bytes]); 376 - memset(data.get(), 0, bytes); 377 - } 378 - } 379 - 380 - if (isOutputPlanar()) 381 - { 382 - for (UInt32 i = 0; i < cc; i++) 383 - { 384 - bufs->mBuffers[i].mData = data.get() + bytes*i; 385 - bufs->mBuffers[i].mDataByteSize = bytes; 386 - } 387 - } 388 - else 389 - { 390 - bufs->mBuffers[0].mData = data.get(); 391 - bufs->mBuffers[0].mDataByteSize = bytes; 392 - } 393 - } 394 - 395 - m_lastRenderError = AudioUnitRender(this, &flags, &ts, kOutputBus, SAMPLE_PERIOD, bufs); 396 - 397 - operator delete(bufs); 398 - } 399 - 400 - void AudioUnitALSA::pushDataFromInput() 401 - { 402 - AudioUnitRenderActionFlags flags; 403 - AudioTimeStamp ts; 404 - AudioBufferList* bufs; 405 - OSStatus err; 406 - std::unique_ptr<uint8_t[]> data; 407 - snd_pcm_uframes_t availFrames; 408 - snd_htimestamp_t alsaTimestamp; 409 - const AudioStreamBasicDescription& config = m_config[kInputBus].second; 410 - 411 - TRACE(); 412 - 413 - memset(&ts, 0, sizeof(ts)); 414 - 415 - if (m_shouldAllocateBuffer) 416 - { 417 - if (isInputPlanar()) 418 - { 419 - UInt32 cc = config.mChannelsPerFrame; 420 - bufs = (AudioBufferList*) operator new(sizeof(AudioBufferList) + (cc-1)*sizeof(AudioBuffer)); 421 - bufs->mNumberBuffers = cc; 422 - } 423 - else 424 - { 425 - bufs = (AudioBufferList*) operator new(sizeof(AudioBufferList)); 426 - bufs->mNumberBuffers = 1; 427 - } 428 - 429 - if (isInputPlanar()) 430 - { 431 - UInt32 cc = config.mChannelsPerFrame; 432 - UInt32 bytesPerChannel = config.mBytesPerFrame * SAMPLE_PERIOD; 433 - 434 - data.reset(new uint8_t[cc*bytesPerChannel]); 435 - 436 - for (UInt32 i = 0; i < cc; i++) 437 - { 438 - bufs->mBuffers[i].mNumberChannels = 1; 439 - bufs->mBuffers[i].mDataByteSize = bytesPerChannel; 440 - bufs->mBuffers[i].mData = data.get() + i*bytesPerChannel; 441 - } 442 - } 443 - else 444 - { 445 - bufs->mBuffers[0].mNumberChannels = config.mChannelsPerFrame; 446 - bufs->mBuffers[0].mDataByteSize = config.mBytesPerFrame * SAMPLE_PERIOD; 447 - 448 - data.reset(new uint8_t[bufs->mBuffers[0].mDataByteSize]); 449 - bufs->mBuffers[0].mData = data.get(); 450 - } 451 - 452 - //render(&flags, &ts, kInputBus, SAMPLE_PERIOD, bufs); 453 - } 454 - else 455 - bufs = nullptr; 456 - 457 - // TODO: fill in AudioTimeStamp based on alsaTimestamp 458 - snd_pcm_htimestamp(m_pcmOutput, &availFrames, &alsaTimestamp); 459 - 460 - m_outputCallback.inputProc(m_outputCallback.inputProcRefCon, &flags, &ts, kInputBus, SAMPLE_PERIOD, bufs); 461 - 462 - operator delete(bufs); 463 - } 464 - 465 - OSStatus AudioUnitALSA::render(AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) 466 - { 467 - if (inBusNumber == kOutputBus) 468 - return renderOutput(ioActionFlags, inTimeStamp, inNumberFrames, ioData); 469 - else if (inBusNumber == kInputBus) 470 - return renderInput(ioActionFlags, inTimeStamp, inNumberFrames, ioData); 471 - else 472 - return paramErr; 473 - } 474 - 475 - OSStatus AudioUnitALSA::renderOutput(AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inNumberFrames, AudioBufferList *ioData) 476 - { 477 - if (!isOutputPlanar()) 478 - return renderInterleavedOutput(ioActionFlags, inTimeStamp, inNumberFrames, ioData); 479 - else 480 - return renderPlanarOutput(ioActionFlags, inTimeStamp, inNumberFrames, ioData); 481 - } 482 - 483 - OSStatus AudioUnitALSA::renderInterleavedOutput(AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inNumberFrames, AudioBufferList *ioData) 484 - { 485 - int wr, sampleCount; 486 - const AudioStreamBasicDescription& config = m_config[kOutputBus].first; 487 - UInt32 framesSoFar = 0; 488 - 489 - for (UInt32 i = 0; i < ioData->mNumberBuffers; i++) 490 - { 491 - // LOG << "Writing " << ioData->mBuffers[i].mDataByteSize << " bytes into sound card\n"; 492 - 493 - sampleCount = std::min<UInt32>(ioData->mBuffers[i].mDataByteSize / config.mBytesPerFrame, inNumberFrames - framesSoFar); 494 - framesSoFar += sampleCount; 495 - 496 - if (!sampleCount) 497 - break; 498 - 499 - do_write: 500 - wr = snd_pcm_writei(m_pcmOutput, ioData->mBuffers[i].mData, sampleCount); 501 - if (wr < 0) 502 - { 503 - if (wr == -EINTR || wr == -EPIPE) 504 - { 505 - // LOG << "Recovering PCM\n"; 506 - snd_pcm_recover(m_pcmOutput, wr, false); 507 - goto do_write; 508 - } 509 - else 510 - { 511 - // ERROR() << "snd_pcm_writei() failed: " << snd_strerror(wr); 512 - return kAudioUnitErr_NoConnection; 513 - } 514 - } 515 - else if (wr < sampleCount) 516 - ;// ERROR() << "snd_pcm_writei(): not all data written?"; 517 - } 518 - 519 - return noErr; 520 - } 521 - 522 - OSStatus AudioUnitALSA::renderPlanarOutput(AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inNumberFrames, AudioBufferList *ioData) 523 - { 524 - std::unique_ptr<void*[]> bufferPointers (new void*[ioData->mNumberBuffers]); 525 - int size, sampleCount, wr; 526 - const AudioStreamBasicDescription& config = m_config[kOutputBus].first; 527 - 528 - if (ioData->mNumberBuffers != config.mChannelsPerFrame) 529 - { 530 - // ERROR() << "Incorrect buffer count for planar audio, only " << ioData->mNumberBuffers; 531 - return paramErr; 532 - } 533 - 534 - size = ioData->mBuffers[0].mDataByteSize; 535 - for (UInt32 i = 1; i < ioData->mNumberBuffers; i++) 536 - { 537 - if (size != ioData->mBuffers[i].mDataByteSize) 538 - { 539 - // ERROR() << "Bad buffer size in buffer " << i; 540 - return paramErr; 541 - } 542 - } 543 - 544 - for (UInt32 i = 0; i < ioData->mNumberBuffers; i++) 545 - bufferPointers[i] = ioData->mBuffers[i].mData; 546 - 547 - sampleCount = size / config.mBytesPerFrame; 548 - 549 - do_write: 550 - wr = snd_pcm_writen(m_pcmOutput, bufferPointers.get(), sampleCount); 551 - if (wr < 0) 552 - { 553 - if (wr == -EINTR || wr == -EPIPE) 554 - { 555 - // LOG << "Recovering PCM\n"; 556 - snd_pcm_recover(m_pcmOutput, wr, false); 557 - goto do_write; 558 - } 559 - else 560 - { 561 - // ERROR() << "snd_pcm_writen() failed: " << snd_strerror(wr); 562 - return kAudioUnitErr_NoConnection; 563 - } 564 - } 565 - else if (wr < sampleCount) 566 - ;// ERROR() << "snd_pcm_writen(): not all data written?"; 567 - 568 - return noErr; 569 - } 570 - 571 - OSStatus AudioUnitALSA::renderInput(AudioUnitRenderActionFlags *ioActionFlags,const AudioTimeStamp *inTimeStamp, UInt32 inNumberFrames, AudioBufferList *ioData) 572 - { 573 - if (!m_outputCallback.inputProc) 574 - return noErr; // We don't push, we should be polled 575 - 576 - if (!isInputPlanar()) 577 - return renderInterleavedInput(ioActionFlags, inTimeStamp, inNumberFrames, ioData); 578 - else 579 - return renderPlanarInput(ioActionFlags, inTimeStamp, inNumberFrames, ioData); 580 - } 581 - 582 - OSStatus AudioUnitALSA::renderInterleavedInput(AudioUnitRenderActionFlags *ioActionFlags,const AudioTimeStamp *inTimeStamp, UInt32 inNumberFrames, AudioBufferList *ioData) 583 - { 584 - int wr, sampleCount; 585 - const AudioStreamBasicDescription& config = m_config[kInputBus].second; 586 - 587 - for (UInt32 i = 0; i < ioData->mNumberBuffers; i++) 588 - { 589 - // LOG << "Reading up to " << ioData->mBuffers[i].mDataByteSize << " bytes from sound card\n"; 590 - 591 - sampleCount = ioData->mBuffers[i].mDataByteSize / config.mBytesPerFrame; 592 - 593 - do_write: 594 - wr = snd_pcm_writei(m_pcmOutput, ioData->mBuffers[i].mData, sampleCount); 595 - if (wr < 0) 596 - { 597 - if (wr == -EINTR || wr == -EPIPE) 598 - { 599 - snd_pcm_recover(m_pcmOutput, wr, false); 600 - goto do_write; 601 - } 602 - else 603 - { 604 - // ERROR() << "snd_pcm_writei() failed: " << snd_strerror(wr); 605 - return kAudioUnitErr_NoConnection; 606 - } 607 - } 608 - 609 - ioData->mBuffers[i].mDataByteSize = wr * config.mBytesPerFrame; 610 - } 611 - 612 - return noErr; 613 - } 614 - 615 - OSStatus AudioUnitALSA::renderPlanarInput(AudioUnitRenderActionFlags *ioActionFlags,const AudioTimeStamp *inTimeStamp, UInt32 inNumberFrames, AudioBufferList *ioData) 616 - { 617 - std::unique_ptr<void*[]> bufferPointers (new void*[ioData->mNumberBuffers]); 618 - int size, sampleCount, wr; 619 - const AudioStreamBasicDescription& config = m_config[kInputBus].second; 620 - 621 - if (ioData->mNumberBuffers != config.mChannelsPerFrame) 622 - { 623 - // ERROR() << "Incorrect buffer count for planar audio, only " << ioData->mNumberBuffers; 624 - return paramErr; 625 - } 626 - 627 - size = ioData->mBuffers[0].mDataByteSize; 628 - for (UInt32 i = 1; i < ioData->mNumberBuffers; i++) 629 - { 630 - if (size != ioData->mBuffers[i].mDataByteSize) 631 - { 632 - // ERROR() << "Bad buffer size in buffer " << i; 633 - return paramErr; 634 - } 635 - } 636 - 637 - for (UInt32 i = 0; i < ioData->mNumberBuffers; i++) 638 - bufferPointers[i] = ioData->mBuffers[i].mData; 639 - 640 - sampleCount = size / config.mBytesPerFrame; 641 - 642 - do_write: 643 - wr = snd_pcm_readn(m_pcmInput, bufferPointers.get(), sampleCount); 644 - if (wr < 0) 645 - { 646 - if (wr == -EINTR || wr == -EPIPE) 647 - { 648 - snd_pcm_recover(m_pcmInput, wr, false); 649 - goto do_write; 650 - } 651 - else 652 - { 653 - // ERROR() << "snd_pcm_writen() failed: " << snd_strerror(wr); 654 - return kAudioUnitErr_NoConnection; 655 - } 656 - } 657 - 658 - for (UInt32 i = 0; i < ioData->mNumberBuffers; i++) 659 - ioData->mBuffers[i].mDataByteSize = sampleCount * config.mBytesPerFrame; 660 - 661 - return noErr; 662 - } 663 - 664 - void AudioUnitALSA::startOutput() 665 - { 666 - std::unique_ptr<struct pollfd[]> pollfds; 667 - int count, err; 668 - 669 - if (!m_inputUnit.sourceAudioUnit) 670 - throw std::runtime_error("No input unit set"); 671 - 672 - err = snd_pcm_prepare(m_pcmOutput); 673 - if (err != 0) 674 - throwAlsaError("snd_pcm_prepare() failed", err); 675 - 676 - count = snd_pcm_poll_descriptors_count(m_pcmOutput); 677 - pollfds.reset(new struct pollfd[count]); 678 - 679 - if (snd_pcm_poll_descriptors(m_pcmOutput, pollfds.get(), count) != count) 680 - throw std::runtime_error("snd_pcm_poll_descriptors() failed"); 681 - 682 - // LOG << "ALSA descriptor count: " << count << std::endl; 683 - startDescriptors(pollfds.get(), count); 684 - } 685 - 686 - void AudioUnitALSA::startDescriptors(const struct pollfd* pollfds, int count) 687 - { 688 - for (int i = 0; i < count; i++) 689 - { 690 - dispatch_source_t source; 691 - const struct pollfd& cur = pollfds[i]; 692 - 693 - if (cur.events & POLLIN) 694 - { 695 - source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, cur.fd, 0, g_audioQueue); 696 - dispatch_source_set_event_handler(source, ^{ 697 - processAudioEvent(cur, POLLIN); 698 - }); 699 - dispatch_resume(source); 700 - m_sources.push_back(source); 701 - } 702 - 703 - if (cur.events & POLLOUT) 704 - { 705 - source = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, cur.fd, 0, g_audioQueue); 706 - dispatch_source_set_event_handler(source, ^{ 707 - processAudioEvent(cur, POLLOUT); 708 - }); 709 - dispatch_resume(source); 710 - m_sources.push_back(source); 711 - } 712 - 713 - } 714 - } 715 - 716 - void AudioUnitALSA::startInput() 717 - { 718 - int err; 719 - 720 - STUB(); 721 - 722 - err = snd_pcm_prepare(m_pcmInput); 723 - if (err != 0) 724 - throwAlsaError("snd_pcm_prepare() failed", err); 725 - } 726 - 727 - OSStatus AudioUnitALSA::start() 728 - { 729 - int err; 730 - 731 - // TRACE(); 732 - 733 - try 734 - { 735 - if (m_pcmInput) 736 - startInput(); 737 - 738 - if (m_pcmOutput) 739 - startOutput(); 740 - 741 - } 742 - catch (const std::exception& e) 743 - { 744 - if (m_pcmInput) 745 - snd_pcm_drop(m_pcmInput); 746 - if (m_pcmOutput) 747 - snd_pcm_drop(m_pcmOutput); 748 - 749 - // ERROR() << e.what(); 750 - return kAudioUnitErr_FailedInitialization; 751 - } 752 - 753 - return noErr; 754 - } 755 - 756 - OSStatus AudioUnitALSA::stop() 757 - { 758 - TRACE(); 759 - 760 - for (dispatch_source_t src : m_sources) 761 - dispatch_source_cancel(src); 762 - m_sources.clear(); 763 - 764 - if (m_pcmInput) 765 - snd_pcm_drop(m_pcmInput); 766 - if (m_pcmOutput) 767 - snd_pcm_drop(m_pcmOutput); 768 - return noErr; 769 - } 770 -
-64
src/CoreAudio/AudioToolbox/AudioUnitALSA.h
··· 1 - #ifndef AUCOMPONENTINTERNAL_H 2 - #define AUCOMPONENTINTERNAL_H 3 - #include "AudioUnit.h" 4 - #include <CoreServices/ComponentsInternal.h> 5 - #include <alsa/asoundlib.h> 6 - #include <dispatch/dispatch.h> 7 - #include <vector> 8 - #include "AudioOutputUnitComponent.h" 9 - 10 - #ifndef kOutputBus 11 - # define kOutputBus 0 // playback 12 - # define kInputBus 1 // recording 13 - #endif 14 - 15 - class AudioUnitALSA : public AudioOutputUnitComponent 16 - { 17 - private: 18 - AudioUnitALSA(int cardIndex, char* cardName); 19 - public: 20 - static AudioUnitComponent* create(int cardIndex); 21 - virtual ~AudioUnitALSA(); 22 - 23 - int cardIndex() const override { return m_cardIndex; } 24 - 25 - OSStatus init() override; 26 - OSStatus deinit() override; 27 - 28 - OSStatus start() override; 29 - OSStatus stop() override; 30 - 31 - OSStatus reset(AudioUnitScope inScope, AudioUnitElement inElement) override; 32 - 33 - OSStatus render(AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) override; 34 - private: 35 - void initOutput(); 36 - void initInput(); 37 - 38 - void startOutput(); 39 - void startInput(); 40 - void startDescriptors(const struct pollfd* fds, int count); 41 - 42 - void processAudioEvent(struct pollfd origPoll, int event); 43 - void requestDataForPlayback(); 44 - void pushDataFromInput(); 45 - 46 - OSStatus renderOutput(AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inNumberFrames, AudioBufferList *ioData); 47 - OSStatus renderInterleavedOutput(AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inNumberFrames, AudioBufferList *ioData); 48 - OSStatus renderPlanarOutput(AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inNumberFrames, AudioBufferList *ioData); 49 - 50 - OSStatus renderInput(AudioUnitRenderActionFlags *ioActionFlags,const AudioTimeStamp *inTimeStamp, UInt32 inNumberFrames, AudioBufferList *ioData); 51 - OSStatus renderInterleavedInput(AudioUnitRenderActionFlags *ioActionFlags,const AudioTimeStamp *inTimeStamp, UInt32 inNumberFrames, AudioBufferList *ioData); 52 - OSStatus renderPlanarInput(AudioUnitRenderActionFlags *ioActionFlags,const AudioTimeStamp *inTimeStamp, UInt32 inNumberFrames, AudioBufferList *ioData); 53 - 54 - inline bool isOutputPlanar() const { return m_config[kOutputBus].second.mFormatFlags & kAudioFormatFlagIsNonInterleaved; } 55 - inline bool isInputPlanar() const { return m_config[kInputBus].first.mFormatFlags & kAudioFormatFlagIsNonInterleaved; } 56 - private: 57 - int m_cardIndex; 58 - char* m_cardName; 59 - snd_pcm_t *m_pcmOutput, *m_pcmInput; 60 - std::vector<dispatch_source_t> m_sources; 61 - }; 62 - 63 - #endif 64 -
+18 -6
src/CoreAudio/AudioToolbox/AudioUnitBase.cpp
··· 7 7 8 8 AudioUnitComponent::AudioUnitComponent(std::initializer_list<CFStringRef> elements) 9 9 { 10 + m_inputRenderer.reset(new AudioUnitRenderer); 10 11 m_elementNames.insert(m_elementNames.end(), elements.begin(), elements.end()); 11 12 m_config.resize(m_elementNames.size()); 12 13 ··· 96 97 97 98 // TODO: perform validation 98 99 99 - if (scope == kAudioUnitScope_Output) 100 + if (scope == kAudioUnitScope_Output) // playback 100 101 m_config[elem].second = *newConfig; 101 - else if (scope == kAudioUnitScope_Input) 102 + else if (scope == kAudioUnitScope_Input) // recording 102 103 m_config[elem].first = *newConfig; 103 104 else if (scope == kAudioUnitScope_Global) 104 105 m_config[0].second = *newConfig; ··· 107 108 108 109 return noErr; 109 110 } 111 + case 7: // kAudioUnitProperty_SetInputCallback (do not mistake with kAudioOutputUnitProperty_SetInputCallback) 110 112 case kAudioUnitProperty_SetRenderCallback: 111 113 { 112 114 if (dataSize != sizeof(AURenderCallbackStruct)) 113 115 return kAudioUnitErr_InvalidParameter; 114 116 //if (scope == kAudioUnitScope_Input) 115 117 //{ 116 - if (elem != 0) 118 + if (elem != kOutputBus) 117 119 return kAudioUnitErr_InvalidElement; 118 120 119 - CloseComponent(m_inputUnit.sourceAudioUnit); // TODO: wrong, we may not own the unit! 121 + *m_inputRenderer = *(AURenderCallbackStruct*) data; 120 122 m_inputUnit.sourceOutputNumber = 0; 121 123 m_inputUnit.destInputNumber = 0; 122 - m_inputUnit.sourceAudioUnit = new AudioUnitRenderer(*(AURenderCallbackStruct*) data); 124 + m_inputUnit.sourceAudioUnit = m_inputRenderer.get(); 123 125 //} 124 126 //else 125 127 // return kAudioUnitErr_InvalidScope; 126 128 127 129 return noErr; 128 130 } 131 + case kAudioOutputUnitProperty_SetInputCallback: 132 + { 133 + // For audio recording 134 + 135 + if (elem != kInputBus) 136 + return kAudioUnitErr_InvalidElement; 137 + 138 + // Notification callback - the recipient needs to call AudioUnitRender to obtain microphone data 139 + m_outputCallback = *(AURenderCallbackStruct*) data; 140 + return noErr; 141 + } 129 142 case kAudioUnitProperty_MakeConnection: 130 143 { 131 144 if (dataSize != sizeof(AudioUnitConnection)) ··· 136 149 // TODO: support multiple units! 137 150 // TODO: reconfigure input format based on output format 138 151 139 - CloseComponent(m_inputUnit.sourceAudioUnit); // TODO: wrong, we may not own the unit! 140 152 memcpy(&m_inputUnit, data, sizeof(AudioUnitConnection)); 141 153 142 154 return noErr;
+18 -2
src/CoreAudio/AudioToolbox/AudioUnitBase.h
··· 6 6 #include <vector> 7 7 #include <set> 8 8 #include <mutex> 9 + #include <memory> 9 10 #include <CoreFoundation/CFString.h> 10 - #include <CoreServices/ComponentsInternal.h> 11 + 12 + #ifndef kOutputBus 13 + # define kOutputBus 0 // playback 14 + # define kInputBus 1 // recording 15 + #endif 16 + 17 + class AudioUnitRenderer; 11 18 12 - class AudioUnitComponent : public CarbonComponent 19 + class AudioUnitComponent 13 20 { 14 21 protected: 15 22 AudioUnitComponent(std::initializer_list<CFStringRef> elements); ··· 34 41 std::vector<CFStringRef> m_elementNames; 35 42 std::vector<std::pair<AudioStreamBasicDescription, AudioStreamBasicDescription>> m_config; 36 43 //AudioStreamBasicDescription m_configOutputPlayback, m_configInputPlayback, m_configInputCapture, m_configOutputCapture; 44 + 45 + // We're simplifying things here - instead of having generic sets of input/output busses 46 + // and associated connections/callbacks, we have just this. 47 + // For kOutputBus only 37 48 AudioUnitConnection m_inputUnit; 49 + std::unique_ptr<AudioUnitRenderer> m_inputRenderer; 50 + 51 + // For kInputBus only 52 + AURenderCallbackStruct m_outputCallback; 53 + 38 54 bool m_shouldAllocateBuffer = true; 39 55 OSStatus m_lastRenderError = 0; 40 56 CFStringRef m_contextName = nullptr;
-544
src/CoreAudio/AudioToolbox/AudioUnitPA.cpp
··· 1 - #include "AudioUnitPA.h" 2 - #include <CoreServices/MacErrors.h> 3 - #include <CoreFoundation/CFString.h> 4 - #include <mutex> 5 - #include <condition_variable> 6 - #include <stdexcept> 7 - #include <sstream> 8 - #include <memory> 9 - #include <cstring> 10 - #include "stub.h" 11 - #include <objc/runtime.h> 12 - 13 - extern "C" char*** _NSGetArgv(void); 14 - 15 - pa_mainloop* AudioUnitPA::m_mainloop = nullptr; 16 - pa_context* AudioUnitPA::m_context = nullptr; 17 - std::thread* AudioUnitPA::m_mainloopThread; 18 - 19 - AudioUnitPA::AudioUnitPA() 20 - { 21 - } 22 - 23 - AudioUnitPA::~AudioUnitPA() 24 - { 25 - deinit(); 26 - } 27 - 28 - static std::string CFStringToStdString(CFStringRef str) 29 - { 30 - CFIndex length, maxSize; 31 - std::unique_ptr<char[]> buffer; 32 - 33 - length = CFStringGetLength(str); 34 - maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1; 35 - buffer.reset(new char[maxSize]); 36 - 37 - if (CFStringGetCString(str, buffer.get(), maxSize, kCFStringEncodingUTF8)) 38 - return std::string(buffer.get()); 39 - else 40 - return std::string(); 41 - } 42 - 43 - OSStatus AudioUnitPA::init() 44 - { 45 - static std::once_flag once; 46 - OSStatus ret; 47 - 48 - std::call_once(once, initializePA); 49 - if (m_context == nullptr) 50 - return kAudioUnitErr_FailedInitialization; 51 - 52 - if (m_enableOutput) 53 - ret = initOutput(); 54 - 55 - // TODO: support recording 56 - return ret; 57 - } 58 - 59 - OSStatus AudioUnitPA::initOutput() 60 - { 61 - std::string streamName; 62 - pa_sample_spec spec; 63 - 64 - if (m_contextName != nullptr) 65 - streamName = CFStringToStdString(m_contextName); 66 - else 67 - streamName = "AudioUnit"; 68 - 69 - spec = paSampleSpecForASBD(m_config[kOutputBus].second); 70 - m_stream = pa_stream_new(m_context, streamName.c_str(), &spec, nullptr); 71 - 72 - if (m_stream == nullptr) 73 - { 74 - // ERROR() << "pa_stream_new() failed"; 75 - return kAudioUnitErr_FailedInitialization; 76 - } 77 - 78 - // TODO: support recording 79 - pa_stream_set_state_callback(m_stream, paStreamStateCB, this); 80 - pa_stream_set_write_callback(m_stream, paStreamWriteCB, this); 81 - 82 - pa_stream_connect_playback(m_stream, nullptr, nullptr, PA_STREAM_START_CORKED /*(pa_stream_flags_t) 0*/, 83 - nullptr, nullptr); 84 - 85 - return noErr; 86 - } 87 - 88 - int AudioUnitPA::cardIndex() const 89 - { 90 - return 0; 91 - } 92 - 93 - void AudioUnitPA::paStreamStateCB(pa_stream* s, void*) 94 - { 95 - int state = pa_stream_get_state(s); 96 - //TRACE() << "state=" << state; 97 - 98 - switch (state) 99 - { 100 - case PA_STREAM_FAILED: 101 - //ERROR() << "PA stream error: " << pa_strerror(pa_context_errno(pa_stream_get_context(s))); 102 - break; 103 - case PA_STREAM_READY: 104 - //LOG << "PA stream is ready\n"; 105 - break; 106 - } 107 - } 108 - 109 - void AudioUnitPA::paStreamWriteCB(pa_stream* s, size_t length, void* self) 110 - { 111 - AudioUnitPA* This = static_cast<AudioUnitPA*>(self); 112 - This->requestDataForPlayback(length); 113 - } 114 - 115 - void AudioUnitPA::requestDataForPlayback(size_t length) 116 - { 117 - AudioUnitRenderActionFlags flags; 118 - AudioTimeStamp ts; 119 - AudioBufferList* bufs; 120 - OSStatus err; 121 - std::unique_ptr<uint8_t[]> data; 122 - const AudioStreamBasicDescription& config = m_config[kOutputBus].first; 123 - const UInt32 cc = config.mChannelsPerFrame; 124 - 125 - if (!m_stream) 126 - { 127 - // std::cerr << "No stream?!\n"; 128 - return; 129 - } 130 - 131 - //TRACE() << "m_started=" << m_started; 132 - 133 - if (!m_started) 134 - { 135 - std::unique_ptr<char[]> empty; 136 - size_t len; 137 - int ret; 138 - 139 - len = config.mBytesPerFrame * (config.mSampleRate / 10); 140 - empty.reset(new char[len]); 141 - 142 - memset(empty.get(), 0, len); 143 - 144 - ret = pa_stream_write(m_stream, empty.get(), len, 145 - nullptr, 0, PA_SEEK_RELATIVE); 146 - 147 - // pa_stream_cork(m_stream, true, [](pa_stream*, int, void*) {}, nullptr); 148 - return; 149 - } 150 - 151 - memset(&ts, 0, sizeof(ts)); 152 - 153 - if (isOutputPlanar()) 154 - { 155 - bufs = (AudioBufferList*) operator new(sizeof(AudioBufferList) + (cc-1)*sizeof(AudioBuffer)); 156 - bufs->mNumberBuffers = cc; 157 - } 158 - else 159 - { 160 - bufs = (AudioBufferList*) operator new(sizeof(AudioBufferList)); 161 - bufs->mNumberBuffers = 1; 162 - } 163 - 164 - if (m_shouldAllocateBuffer) 165 - { 166 - if (isOutputPlanar()) 167 - { 168 - UInt32 bytesPerChannel = length / cc; 169 - 170 - data.reset(new uint8_t[cc*bytesPerChannel]); 171 - 172 - for (UInt32 i = 0; i < cc; i++) 173 - { 174 - bufs->mBuffers[i].mNumberChannels = 1; 175 - bufs->mBuffers[i].mDataByteSize = bytesPerChannel; 176 - bufs->mBuffers[i].mData = data.get() + i*bytesPerChannel; 177 - } 178 - } 179 - else 180 - { 181 - bufs->mBuffers[0].mNumberChannels = cc; 182 - bufs->mBuffers[0].mDataByteSize = length; 183 - 184 - data.reset(new uint8_t[bufs->mBuffers[0].mDataByteSize]); 185 - bufs->mBuffers[0].mData = data.get(); 186 - } 187 - } 188 - else 189 - { 190 - if (isOutputPlanar()) 191 - { 192 - for (UInt32 i = 0; i < cc; i++) 193 - { 194 - bufs->mBuffers[i].mDataByteSize = 0; 195 - bufs->mBuffers[i].mData = nullptr; 196 - } 197 - } 198 - else 199 - { 200 - bufs->mBuffers[0].mDataByteSize = 0; 201 - bufs->mBuffers[0].mData = nullptr; 202 - } 203 - } 204 - 205 - // snd_pcm_htimestamp(m_pcmOutput, &availFrames, &alsaTimestamp); 206 - 207 - // TODO: fill in AudioTimeStamp based on some PA timestamp 208 - 209 - err = AudioUnitRender(m_inputUnit.sourceAudioUnit, &flags, &ts, kOutputBus, length / config.mBytesPerFrame, bufs); 210 - 211 - if (err != noErr || bufs->mBuffers[0].mDataByteSize == 0) 212 - { 213 - // ERROR() << "Render callback failed with error " << err; 214 - 215 - // Fill with silence, the error may be temporary 216 - UInt32 bytes = length; 217 - 218 - if (!m_shouldAllocateBuffer) 219 - { 220 - if (isOutputPlanar()) 221 - { 222 - data.reset(new uint8_t[bytes*cc]); 223 - memset(data.get(), 0, bytes*cc); 224 - } 225 - else 226 - { 227 - data.reset(new uint8_t[bytes]); 228 - memset(data.get(), 0, bytes); 229 - } 230 - } 231 - 232 - if (isOutputPlanar()) 233 - { 234 - for (UInt32 i = 0; i < cc; i++) 235 - { 236 - bufs->mBuffers[i].mData = data.get() + bytes*i; 237 - bufs->mBuffers[i].mDataByteSize = bytes; 238 - } 239 - } 240 - else 241 - { 242 - bufs->mBuffers[0].mData = data.get(); 243 - bufs->mBuffers[0].mDataByteSize = bytes; 244 - } 245 - } 246 - 247 - //LOG << "Rendering...\n"; 248 - m_lastRenderError = AudioUnitRender(this, &flags, &ts, kOutputBus, length / config.mBytesPerFrame, bufs); 249 - 250 - operator delete(bufs); 251 - } 252 - 253 - OSStatus AudioUnitPA::render(AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) 254 - { 255 - if (inBusNumber == kOutputBus) 256 - return renderOutput(ioActionFlags, inTimeStamp, inNumberFrames, ioData); 257 - else if (inBusNumber == kInputBus) 258 - return renderInput(ioActionFlags, inTimeStamp, inNumberFrames, ioData); 259 - else 260 - return paramErr; 261 - } 262 - 263 - OSStatus AudioUnitPA::renderOutput(AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inNumberFrames, AudioBufferList *ioData) 264 - { 265 - if (!isOutputPlanar()) 266 - return renderInterleavedOutput(ioActionFlags, inTimeStamp, inNumberFrames, ioData); 267 - else 268 - return renderPlanarOutput(ioActionFlags, inTimeStamp, inNumberFrames, ioData); 269 - } 270 - 271 - OSStatus AudioUnitPA::renderInterleavedOutput(AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inNumberFrames, AudioBufferList *ioData) 272 - { 273 - const AudioStreamBasicDescription& config = m_config[kOutputBus].first; 274 - UInt32 framesSoFar = 0; 275 - 276 - for (UInt32 i = 0; i < ioData->mNumberBuffers; i++) 277 - { 278 - size_t bytes = std::min<size_t>((inNumberFrames - framesSoFar) * config.mBytesPerFrame, ioData->mBuffers[i].mDataByteSize); 279 - 280 - if (!bytes) 281 - break; 282 - 283 - //LOG << "AudioUnitPA::renderInterleavedOutput(): data=" << ioData->mBuffers[i].mData << ", bytes=" << bytes << std::endl; 284 - pa_stream_write(m_stream, ((char*) ioData->mBuffers[i].mData) + framesSoFar * config.mBytesPerFrame, bytes, 285 - nullptr, 0, PA_SEEK_RELATIVE); 286 - 287 - framesSoFar += ioData->mBuffers[i].mDataByteSize / config.mBytesPerFrame; 288 - } 289 - 290 - return noErr; 291 - } 292 - 293 - OSStatus AudioUnitPA::renderPlanarOutput(AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inNumberFrames, AudioBufferList *ioData) 294 - { 295 - // PulseAudio doesn't support planar audio, we have to perform conversion 296 - return unimpErr; 297 - } 298 - 299 - OSStatus AudioUnitPA::renderInput(AudioUnitRenderActionFlags *ioActionFlags,const AudioTimeStamp *inTimeStamp, UInt32 inNumberFrames, AudioBufferList *ioData) 300 - { 301 - if (!m_outputCallback.inputProc) 302 - return noErr; // We don't push, we should be polled 303 - 304 - if (!isInputPlanar()) 305 - return renderInterleavedInput(ioActionFlags, inTimeStamp, inNumberFrames, ioData); 306 - else 307 - return renderPlanarInput(ioActionFlags, inTimeStamp, inNumberFrames, ioData); 308 - } 309 - 310 - OSStatus AudioUnitPA::renderInterleavedInput(AudioUnitRenderActionFlags *ioActionFlags,const AudioTimeStamp *inTimeStamp, UInt32 inNumberFrames, AudioBufferList *ioData) 311 - { 312 - STUB(); 313 - return unimpErr; 314 - } 315 - 316 - OSStatus AudioUnitPA::renderPlanarInput(AudioUnitRenderActionFlags *ioActionFlags,const AudioTimeStamp *inTimeStamp, UInt32 inNumberFrames, AudioBufferList *ioData) 317 - { 318 - STUB(); 319 - return unimpErr; 320 - } 321 - 322 - pa_sample_spec AudioUnitPA::paSampleSpecForASBD(const AudioStreamBasicDescription& asbd) 323 - { 324 - const bool isFloat = asbd.mFormatFlags & kAudioFormatFlagIsFloat; 325 - const bool isSigned = asbd.mFormatFlags & kAudioFormatFlagIsSignedInteger; 326 - const bool isBE = asbd.mFormatFlags & kAudioFormatFlagIsBigEndian; 327 - 328 - pa_sample_spec spec; 329 - 330 - spec.rate = asbd.mSampleRate; 331 - spec.channels = asbd.mChannelsPerFrame; 332 - 333 - if (asbd.mFormatID == kAudioFormatLinearPCM) 334 - { 335 - if (isFloat) 336 - spec.format = isBE ? PA_SAMPLE_FLOAT32BE : PA_SAMPLE_FLOAT32LE; 337 - else 338 - { 339 - switch (asbd.mBitsPerChannel) 340 - { 341 - case 8: 342 - m_convertUnsignedSigned = isSigned; 343 - spec.format = PA_SAMPLE_U8; 344 - break; 345 - case 16: 346 - m_convertUnsignedSigned = !isSigned; 347 - 348 - spec.format = isBE ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE; 349 - break; 350 - case 24: 351 - m_convertUnsignedSigned = !isSigned; 352 - 353 - spec.format = isBE ? PA_SAMPLE_S24BE : PA_SAMPLE_S24LE; 354 - break; 355 - case 32: 356 - m_convertUnsignedSigned = !isSigned; 357 - 358 - spec.format = isBE ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE; 359 - break; 360 - } 361 - } 362 - } 363 - else 364 - throw std::runtime_error("Unsupported mFormatID value"); 365 - 366 - if (!pa_sample_spec_valid(&spec)) 367 - throw std::logic_error("Invalid pa_sample_spec constructed"); 368 - 369 - return spec; 370 - } 371 - 372 - OSStatus AudioUnitPA::reset(AudioUnitScope inScope, AudioUnitElement inElement) 373 - { 374 - STUB(); 375 - return unimpErr; 376 - } 377 - 378 - OSStatus AudioUnitPA::deinit() 379 - { 380 - TRACE(); 381 - if (!m_stream) 382 - return kAudioUnitErr_Uninitialized; 383 - 384 - pa_stream_disconnect(m_stream); 385 - pa_stream_unref(m_stream); 386 - m_stream = nullptr; 387 - 388 - return noErr; 389 - } 390 - 391 - OSStatus AudioUnitPA::start() 392 - { 393 - TRACE(); 394 - if (!m_stream) 395 - return kAudioUnitErr_Uninitialized; 396 - 397 - if (pa_stream_is_corked(m_stream)) 398 - { 399 - m_started = true; 400 - 401 - // const AudioStreamBasicDescription& config = m_config[kOutputBus].first; 402 - pa_stream_cork(m_stream, 0, [](pa_stream*, int, void*) {}, nullptr); 403 - // requestDataForPlayback(config.mSampleRate / 10 * config.mBytesPerFrame); 404 - } 405 - 406 - return noErr; 407 - } 408 - 409 - OSStatus AudioUnitPA::stop() 410 - { 411 - TRACE(); 412 - if (!m_stream) 413 - return kAudioUnitErr_Uninitialized; 414 - 415 - if (pa_stream_is_corked(m_stream)) 416 - pa_stream_cork(m_stream, 1, [](pa_stream*, int, void*) {}, nullptr); 417 - 418 - m_started = false; 419 - return noErr; 420 - } 421 - 422 - struct Completion 423 - { 424 - std::condition_variable cond; 425 - std::mutex mutex; 426 - bool complete = false; 427 - }; 428 - 429 - void AudioUnitPA::initializePA() 430 - { 431 - try 432 - { 433 - pa_mainloop_api* mainloopApi; 434 - const char* appName; 435 - Completion comp; 436 - static int retval; 437 - 438 - if ((m_mainloop = pa_mainloop_new()) == nullptr) 439 - throw std::runtime_error("Failed to create PA mainloop"); 440 - 441 - mainloopApi = pa_mainloop_get_api(m_mainloop); 442 - 443 - // TODO: Detect if this is an app in a bundle and get a nice app name 444 - appName = (*_NSGetArgv())[0]; 445 - 446 - if ((m_context = pa_context_new(mainloopApi, appName)) == nullptr) 447 - throw std::runtime_error("Failed to create PA context"); 448 - 449 - pa_context_set_state_callback(m_context, paContextStateCB, &comp); 450 - 451 - if (pa_context_connect(m_context, nullptr, pa_context_flags_t(0), nullptr) < 0) 452 - { 453 - std::stringstream ss; 454 - ss << "pa_context_connect() failed: " << pa_strerror(pa_context_errno(m_context)); 455 - throw std::runtime_error(ss.str()); 456 - } 457 - 458 - m_mainloopThread = new std::thread(pa_mainloop_run, m_mainloop, &retval); 459 - 460 - std::unique_lock<std::mutex> lk(comp.mutex); 461 - comp.cond.wait(lk, [&]{ return comp.complete; }); 462 - 463 - if (m_context == nullptr) 464 - throw std::runtime_error("Failed to connect context"); 465 - } 466 - catch (const std::exception& e) 467 - { 468 - pa_mainloop_free(m_mainloop); 469 - m_mainloop = nullptr; 470 - 471 - // ERROR() << e.what(); 472 - } 473 - } 474 - 475 - std::string AudioUnitPA::getAppName() 476 - { 477 - Class classBundle; 478 - std::string name; 479 - size_t pos; 480 - 481 - classBundle = (Class) objc_getClass("NSBundle"); 482 - 483 - if (classBundle != nullptr) 484 - { 485 - // TODO: get a nice app name 486 - } 487 - 488 - name = (*_NSGetArgv())[0]; 489 - pos = name.rfind('/'); 490 - 491 - if (pos != std::string::npos) 492 - name = name.substr(pos+1); 493 - 494 - return name; 495 - } 496 - 497 - void AudioUnitPA::deinitializePA() 498 - { 499 - if (m_context != nullptr) 500 - { 501 - pa_context_unref(m_context); 502 - m_context = nullptr; 503 - } 504 - if (m_mainloop != nullptr) 505 - { 506 - pa_mainloop_api* mainloopApi; 507 - 508 - mainloopApi = pa_mainloop_get_api(m_mainloop); 509 - mainloopApi->quit(mainloopApi, 0); 510 - 511 - m_mainloopThread->join(); 512 - delete m_mainloopThread; 513 - 514 - pa_mainloop_free(m_mainloop); 515 - } 516 - } 517 - 518 - void AudioUnitPA::paContextStateCB(pa_context* c, void* priv) 519 - { 520 - Completion* comp = static_cast<Completion*>(priv); 521 - 522 - // TRACE() << pa_context_get_state(c); 523 - switch (pa_context_get_state(c)) 524 - { 525 - case PA_CONTEXT_READY: 526 - { 527 - std::unique_lock<std::mutex> lk(comp->mutex); 528 - comp->complete = true; 529 - comp->cond.notify_one(); 530 - break; 531 - } 532 - 533 - case PA_CONTEXT_FAILED: 534 - // Indicate failure 535 - pa_context_unref(m_context); 536 - m_context = nullptr; 537 - 538 - comp->complete = true; 539 - comp->cond.notify_one(); 540 - break; 541 - default: 542 - break; 543 - } 544 - }
-66
src/CoreAudio/AudioToolbox/AudioUnitPA.h
··· 1 - #ifndef AUDIOUNITPA_H 2 - #define AUDIOUNITPA_H 3 - #include "AudioOutputUnitComponent.h" 4 - #include <pulse/pulseaudio.h> 5 - #include <thread> 6 - 7 - #ifndef kOutputBus 8 - # define kOutputBus 0 // playback 9 - # define kInputBus 1 // recording 10 - #endif 11 - 12 - class AudioUnitPA : public AudioOutputUnitComponent 13 - { 14 - public: 15 - AudioUnitPA(); 16 - virtual ~AudioUnitPA(); 17 - 18 - OSStatus init() override; 19 - OSStatus deinit() override; 20 - 21 - OSStatus start() override; 22 - OSStatus stop() override; 23 - 24 - OSStatus reset(AudioUnitScope inScope, AudioUnitElement inElement) override; 25 - 26 - OSStatus render(AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) override; 27 - 28 - int cardIndex() const override; 29 - private: 30 - OSStatus initOutput(); 31 - private: 32 - static void initializePA(); 33 - static void deinitializePA(); 34 - static void paContextStateCB(pa_context* c, void*); 35 - static void paStreamStateCB(pa_stream* s, void*); 36 - static void paStreamWriteCB(pa_stream* s, size_t length, void*); 37 - static std::string getAppName(); 38 - pa_sample_spec paSampleSpecForASBD(const AudioStreamBasicDescription& asbd); 39 - 40 - void requestDataForPlayback(size_t length); 41 - 42 - inline bool isOutputPlanar() const { return m_config[kOutputBus].second.mFormatFlags & kAudioFormatFlagIsNonInterleaved; } 43 - inline bool isInputPlanar() const { return m_config[kInputBus].first.mFormatFlags & kAudioFormatFlagIsNonInterleaved; } 44 - 45 - OSStatus renderOutput(AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inNumberFrames, AudioBufferList *ioData); 46 - OSStatus renderInterleavedOutput(AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inNumberFrames, AudioBufferList *ioData); 47 - OSStatus renderPlanarOutput(AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inNumberFrames, AudioBufferList *ioData); 48 - 49 - OSStatus renderInput(AudioUnitRenderActionFlags *ioActionFlags,const AudioTimeStamp *inTimeStamp, UInt32 inNumberFrames, AudioBufferList *ioData); 50 - OSStatus renderInterleavedInput(AudioUnitRenderActionFlags *ioActionFlags,const AudioTimeStamp *inTimeStamp, UInt32 inNumberFrames, AudioBufferList *ioData); 51 - OSStatus renderPlanarInput(AudioUnitRenderActionFlags *ioActionFlags,const AudioTimeStamp *inTimeStamp, UInt32 inNumberFrames, AudioBufferList *ioData); 52 - private: 53 - static pa_mainloop* m_mainloop; 54 - static pa_context* m_context; 55 - static std::thread* m_mainloopThread; 56 - private: 57 - pa_stream* m_stream; 58 - 59 - // PulseAudio supports only unsigned 8-bit PCM and only signed >8-bit PCM. 60 - // We need to perform conversion of samples if input/output differs. 61 - bool m_convertUnsignedSigned = false; 62 - bool m_started = false; 63 - }; 64 - 65 - #endif /* AUDIOUNITPA_H */ 66 -
+5
src/CoreAudio/AudioToolbox/AudioUnitRenderer.cpp
··· 6 6 { 7 7 } 8 8 9 + AudioUnitRenderer::AudioUnitRenderer() 10 + : AudioUnitComponent({ CFSTR("Fake") }), m_renderCallback({0}) 11 + { 12 + } 13 + 9 14 OSStatus AudioUnitRenderer::init() 10 15 { 11 16 return noErr;
+3
src/CoreAudio/AudioToolbox/AudioUnitRenderer.h
··· 7 7 { 8 8 public: 9 9 AudioUnitRenderer(const AURenderCallbackStruct& cb); 10 + AudioUnitRenderer(); 11 + 12 + AudioUnitRenderer& operator=(const AURenderCallbackStruct& cb) { m_renderCallback = cb; return *this; } 10 13 OSStatus init() override; 11 14 OSStatus deinit() override; 12 15
+3 -7
src/CoreAudio/AudioToolbox/CMakeLists.txt
··· 6 6 ${CMAKE_CURRENT_SOURCE_DIR}/../include/AudioToolbox 7 7 ) 8 8 9 - add_definitions(-DENABLE_PULSEAUDIO=1) 10 - 11 9 set(audiotoolbox_sources 12 10 AUComponent.cpp 13 11 AudioConverter.cpp ··· 17 15 AudioQueueBase.cpp 18 16 AudioQueue.cpp 19 17 AudioQueueOutput.cpp 20 - # AudioUnitALSA.cpp 21 - AudioUnitBase.cpp 22 - AudioUnit.cpp 23 - AudioUnitPA.cpp 18 + #AudioUnitBase.cpp 19 + #AudioUnit.cpp 20 + #AudioUnitCA.cpp 24 21 AudioUnitRenderer.cpp 25 22 AUGraph.cpp 26 23 ) ··· 44 41 avresample 45 42 avcodec 46 43 avutil 47 - pulse # This should go away in favor of abstraction inside CoreAudio 48 44 ) 49 45 50 46 # TODO: Add AudioUnit.framework
+1 -1
src/CoreAudio/CMakeLists.txt
··· 20 20 wrap_elf(pulse libpulse.so) 21 21 22 22 add_subdirectory(CoreAudio) 23 - add_subdirectory(AudioToolbox) 23 + #add_subdirectory(AudioToolbox)
+27 -8
src/CoreAudio/CoreAudio/AudioHardwareImpl.cpp
··· 26 26 AudioHardwareImpl::AudioHardwareImpl(AudioObjectID myId) 27 27 : m_myId(myId) 28 28 { 29 + // These are the standard values macOS applications have learned to expect 30 + m_asbd.mChannelsPerFrame = 2; 31 + m_asbd.mSampleRate = 44100; 32 + m_asbd.mBitsPerChannel = 32; 33 + m_asbd.mFormatID = kAudioFormatLinearPCM; 34 + m_asbd.mFormatFlags = kLinearPCMFormatFlagIsFloat | kAudioFormatFlagsNativeEndian; 35 + m_asbd.mFramesPerPacket = 1; 36 + m_asbd.mBytesPerFrame = UInt32(m_asbd.mBytesPerPacket = m_asbd.mChannelsPerFrame * m_asbd.mSampleRate * m_asbd.mBitsPerChannel / 8); 29 37 } 30 38 31 39 ··· 147 155 { 148 156 if (AudioStreamBasicDescription* asbd = static_cast<AudioStreamBasicDescription*>(outData); asbd && *ioDataSize >= sizeof(AudioStreamBasicDescription)) 149 157 { 150 - // These are standard values macOS applications have learned to expect 151 - asbd->mChannelsPerFrame = 2; 152 - asbd->mSampleRate = 44100; 153 - asbd->mBitsPerChannel = 32; 154 - asbd->mFormatID = kAudioFormatLinearPCM; 155 - asbd->mFormatFlags = kLinearPCMFormatFlagIsFloat; 156 - asbd->mFramesPerPacket = 1; 157 - asbd->mBytesPerFrame = UInt32(asbd->mBytesPerPacket = asbd->mChannelsPerFrame * asbd->mSampleRate * asbd->mBitsPerChannel / 8); 158 + memcpy(asbd, &m_asbd, sizeof(m_asbd)); 158 159 } 159 160 *ioDataSize = sizeof(AudioStreamBasicDescription); 160 161 return kAudioHardwareNoError; ··· 266 267 } 267 268 case kAudioDevicePropertyVolumeDecibels: 268 269 { 270 + return kAudioHardwareNoError; 271 + } 272 + case kAudioDevicePropertyStreamFormat: 273 + { 274 + if (inDataSize != sizeof(m_asbd)) 275 + return kAudioHardwareBadPropertySizeError; 276 + 277 + const AudioStreamBasicDescription* setting = static_cast<const AudioStreamBasicDescription*>(inData); 278 + if (setting->mFormatID != kAudioFormatLinearPCM) 279 + return kAudioDeviceUnsupportedFormatError; 280 + if (!validateFormat(setting)) 281 + return kAudioDeviceUnsupportedFormatError; 282 + 283 + memcpy(&m_asbd, setting, sizeof(m_asbd)); 284 + 285 + m_asbd.mFramesPerPacket = 1; 286 + m_asbd.mBytesPerFrame = UInt32(m_asbd.mBytesPerPacket = m_asbd.mChannelsPerFrame * m_asbd.mSampleRate * m_asbd.mBitsPerChannel / 8); 287 + 269 288 return kAudioHardwareNoError; 270 289 } 271 290 // These make sense only for ALSA, but I find it ridiculous that these properties can be set...
+3
src/CoreAudio/CoreAudio/AudioHardwareImpl.h
··· 69 69 uint32_t bufferSize() const { return m_bufferSize; } 70 70 71 71 AudioObjectID id() const { return m_myId; } 72 + const AudioStreamBasicDescription& asbd() const { return m_asbd; } 72 73 private: 73 74 static OSStatus getPropertyCFString(CFStringRef str, UInt32* ioDataSize, void* outData); 74 75 static OSStatus getPropertyString(CFStringRef str, UInt32* ioDataSize, void* outData); 75 76 protected: 76 77 virtual AudioHardwareStream* createStream(AudioDeviceIOProc callback, void* clientData) = 0; 78 + virtual bool validateFormat(const AudioStreamBasicDescription* absd) const { return true; } 77 79 protected: 78 80 AudioObjectID m_myId; 79 81 std::mutex m_procMutex; ··· 84 86 uint32_t m_bufferSize = 8192; 85 87 86 88 CFStringRef m_name = CFSTR("unknown"), m_uid = CFSTR("unknown"), m_manufacturer = CFSTR("unknown"), m_modelUid = CFSTR("unknown"); 89 + AudioStreamBasicDescription m_asbd; 87 90 }; 88 91 89 92 #endif /* AUDIOHARDWAREIMPL_H */
+62
src/CoreAudio/CoreAudio/pulse/AudioHardwareImplPA.cpp
··· 210 210 else 211 211 cb(m_context); 212 212 } 213 + 214 + pa_sample_spec AudioHardwareImplPA::paSampleSpecForASBD(const AudioStreamBasicDescription& asbd, bool* convertSignedUnsigned) 215 + { 216 + const bool isFloat = asbd.mFormatFlags & kAudioFormatFlagIsFloat; 217 + const bool isSigned = asbd.mFormatFlags & kAudioFormatFlagIsSignedInteger; 218 + const bool isBE = asbd.mFormatFlags & kAudioFormatFlagIsBigEndian; 219 + 220 + pa_sample_spec spec; 221 + 222 + spec.rate = asbd.mSampleRate; 223 + spec.channels = asbd.mChannelsPerFrame; 224 + spec.format = PA_SAMPLE_INVALID; 225 + 226 + if (convertSignedUnsigned) 227 + *convertSignedUnsigned = false; 228 + 229 + if (asbd.mFormatID == kAudioFormatLinearPCM) 230 + { 231 + if (isFloat) 232 + spec.format = isBE ? PA_SAMPLE_FLOAT32BE : PA_SAMPLE_FLOAT32LE; 233 + else 234 + { 235 + switch (asbd.mBitsPerChannel) 236 + { 237 + case 8: 238 + if (convertSignedUnsigned) 239 + *convertSignedUnsigned = isSigned; 240 + spec.format = PA_SAMPLE_U8; 241 + break; 242 + case 16: 243 + if (convertSignedUnsigned) 244 + *convertSignedUnsigned = !isSigned; 245 + 246 + spec.format = isBE ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE; 247 + break; 248 + case 24: 249 + if (convertSignedUnsigned) 250 + *convertSignedUnsigned = !isSigned; 251 + 252 + if (asbd.mFormatFlags & kAudioFormatFlagIsPacked) 253 + spec.format = isBE ? PA_SAMPLE_S24BE : PA_SAMPLE_S24LE; 254 + else 255 + spec.format = isBE ? PA_SAMPLE_S24_32BE : PA_SAMPLE_S24_32LE; 256 + break; 257 + case 32: 258 + if (convertSignedUnsigned) 259 + *convertSignedUnsigned = !isSigned; 260 + 261 + spec.format = isBE ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE; 262 + break; 263 + } 264 + } 265 + } 266 + 267 + return spec; 268 + } 269 + 270 + bool AudioHardwareImplPA::validateFormat(const AudioStreamBasicDescription* asbd) const 271 + { 272 + pa_sample_spec spec = paSampleSpecForASBD(*asbd); 273 + return pa_sample_spec_valid(&spec); 274 + }
+2
src/CoreAudio/CoreAudio/pulse/AudioHardwareImplPA.h
··· 37 37 const void* inQualifierData, UInt32 inDataSize, const void* inData) override; 38 38 39 39 static void getPAContext(void (^cb)(pa_context*)); 40 + static pa_sample_spec paSampleSpecForASBD(const AudioStreamBasicDescription& asbd, bool* convertSignedUnsigned = nullptr); 40 41 protected: 41 42 AudioHardwareStream* createStream(AudioDeviceIOProc callback, void* clientData) override; 43 + bool validateFormat(const AudioStreamBasicDescription* asbd) const override; 42 44 private: 43 45 static pa_context* m_context; 44 46 static std::unique_ptr<PADispatchMainLoop> m_loop;
+85 -12
src/CoreAudio/CoreAudio/pulse/AudioHardwareStreamPA.cpp
··· 20 20 #include "AudioHardwareStreamPA.h" 21 21 #include "AudioHardwareImplPA.h" 22 22 #include <iostream> 23 + #include <type_traits> 24 + #include <limits> 23 25 24 26 AudioHardwareStreamPA::AudioHardwareStreamPA(AudioHardwareImpl* hw, AudioDeviceIOProc callback, void* clientData) 25 27 : AudioHardwareStream(hw, false), m_callback(callback), m_clientData(clientData) ··· 30 32 std::cerr << "Failed to get PulseAudio context\n"; 31 33 return; 32 34 } 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 35 + 36 + pa_sample_spec spec = AudioHardwareImplPA::paSampleSpecForASBD(hw->asbd(), &m_convertSignedUnsigned); 37 + 45 38 if (!pa_sample_spec_valid(&spec)) 46 39 { 47 40 std::cerr << "Failed to create a valid pa_sample_spec\n"; ··· 85 78 }, this); 86 79 } 87 80 81 + // This function seems to only convert unsigned to signed, but it works both ways in practice 82 + template <typename T> 83 + void transform(typename std::make_unsigned<T>::type* data) 84 + { 85 + typedef typename std::make_signed<T>::type signed_type; 86 + signed_type* s = reinterpret_cast<signed_type*>(data); 87 + 88 + *s = *data + std::numeric_limits<signed_type>::min(); 89 + } 90 + 91 + void AudioHardwareStreamPA::transformSignedUnsigned(AudioBufferList* abl) const 92 + { 93 + const AudioStreamBasicDescription& asbd = m_hw->asbd(); 94 + const bool revEndian = (asbd.mFormatFlags & kAudioFormatFlagIsBigEndian) != (asbd.mFormatFlags & kAudioFormatFlagsNativeEndian); 95 + 96 + for (int i = 0; i < abl->mNumberBuffers; i++) 97 + { 98 + AudioBuffer* buf = &abl->mBuffers[i]; 99 + 100 + switch (asbd.mBitsPerChannel) 101 + { 102 + case 8: 103 + for (int j = 0; j < buf->mDataByteSize; j++) 104 + transform<uint8_t>(reinterpret_cast<uint8_t*>(buf->mData) + j); 105 + break; 106 + case 16: 107 + if (!revEndian) 108 + { 109 + for (int j = 0; j < buf->mDataByteSize / sizeof(uint16_t); j++) 110 + transform<uint16_t>(reinterpret_cast<uint16_t*>(buf->mData) + j); 111 + } 112 + else 113 + { 114 + for (int j = 0; j < buf->mDataByteSize / sizeof(uint16_t); j++) 115 + { 116 + uint16_t v = __builtin_bswap16(*(reinterpret_cast<uint16_t*>(buf->mData) + j)); 117 + transform<uint16_t>(&v); 118 + *(reinterpret_cast<uint16_t*>(buf->mData) + j) = __builtin_bswap16(v); 119 + } 120 + } 121 + break; 122 + case 24: 123 + for (int j = 0; j < buf->mDataByteSize / sizeof(uint32_t); j++) 124 + { 125 + uint32_t v = *(reinterpret_cast<uint32_t*>(buf->mData) + j); 126 + if (revEndian) 127 + v = __builtin_bswap32(v); 128 + 129 + // sign extend 130 + if (v & 0x800000) 131 + v |= 0xff000000; 132 + 133 + transform<uint32_t>(&v); 134 + 135 + v &= 0xffffff; 136 + if (revEndian) 137 + v = __builtin_bswap32(v); 138 + 139 + *(reinterpret_cast<uint32_t*>(buf->mData) + j) = v; 140 + } 141 + break; 142 + case 32: 143 + if (!revEndian) 144 + { 145 + for (int j = 0; j < buf->mDataByteSize / sizeof(uint32_t); j++) 146 + transform<uint32_t>(reinterpret_cast<uint32_t*>(buf->mData) + j); 147 + } 148 + else 149 + { 150 + for (int j = 0; j < buf->mDataByteSize / sizeof(uint32_t); j++) 151 + { 152 + uint32_t v = __builtin_bswap32(*(reinterpret_cast<uint32_t*>(buf->mData) + j)); 153 + transform<uint32_t>(&v); 154 + *(reinterpret_cast<uint32_t*>(buf->mData) + j) = __builtin_bswap32(v); 155 + } 156 + } 157 + break; 158 + } 159 + } 160 + }
+2
src/CoreAudio/CoreAudio/pulse/AudioHardwareStreamPA.h
··· 33 33 void stop(void(^cbDone)()) override; 34 34 protected: 35 35 virtual void start() = 0; 36 + void transformSignedUnsigned(AudioBufferList* abl) const; 36 37 protected: 37 38 AudioDeviceIOProc m_callback; 38 39 void* m_clientData; 39 40 pa_stream* m_stream; 40 41 void(^m_cbDone)(); 42 + bool m_convertSignedUnsigned = false; 41 43 }; 42 44 43 45 #endif /* AUDIOHARDWARESTREAMPA_H */
+2
src/CoreAudio/CoreAudio/pulse/AudioHardwareStreamPAInput.cpp
··· 63 63 64 64 // This->m_dump.write((char*) abl->mBuffers[0].mData, nbytes); 65 65 // This->m_dump.flush(); 66 + if (This->m_convertSignedUnsigned) 67 + This->transformSignedUnsigned(abl); 66 68 67 69 // std::cout << "AudioHardwareStreamPAInput::paStreamReadCB(): bytes=" << nbytes << std::endl; 68 70 OSStatus status = This->m_callback(This->m_hw->id(), &fake, abl, &fake, nullptr, nullptr, This->m_clientData);
+3
src/CoreAudio/CoreAudio/pulse/AudioHardwareStreamPAOutput.cpp
··· 61 61 } 62 62 else 63 63 { 64 + if (This->m_convertSignedUnsigned) 65 + This->transformSignedUnsigned(abl); 66 + 64 67 // std::cout << "AudioHardwareStreamPAOutput::paStreamWriteCB(): got " << abl->mBuffers[0].mDataByteSize << " bytes\n"; 65 68 int rv = pa_stream_write(This->m_stream, abl->mBuffers[0].mData, abl->mBuffers[0].mDataByteSize, nullptr, 0, PA_SEEK_RELATIVE); 66 69 if (rv != 0)
+5 -1
src/CoreAudio/include/CoreAudio/CoreAudioTypes.h
··· 111 111 112 112 enum 113 113 { 114 - kAudioFormatFlagsNativeEndian = 0, 115 114 kAudioFormatFlagIsFloat = (1 << 0), // 0x1 116 115 kAudioFormatFlagIsBigEndian = (1 << 1), // 0x2 117 116 kAudioFormatFlagIsSignedInteger = (1 << 2), // 0x4 ··· 120 119 kAudioFormatFlagIsNonInterleaved = (1 << 5), // 0x20 121 120 kAudioFormatFlagIsNonMixable = (1 << 6), // 0x40 122 121 kAudioFormatFlagsAreAllClear = (1 << 31), 122 + #if defined(__BIG_ENDIAN__) 123 + kAudioFormatFlagsNativeEndian = kAudioFormatFlagIsBigEndian, 124 + #else 125 + kAudioFormatFlagsNativeEndian = 0, 126 + #endif 123 127 kAudioFormatFlagsCanonical = kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked, 124 128 kAudioFormatFlagsNativeFloatPacked = kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked, 125 129
+8 -24
src/frameworks/CoreServices/MacMemory.cpp
··· 21 21 #include <cstring> 22 22 #include <stdint.h> 23 23 #include <cstdlib> 24 - 25 - struct PtrInternal 26 - { 27 - uintptr_t size; 28 - uint8_t data[]; 29 - }; 24 + #include <malloc/malloc.h> 30 25 31 26 void BlockMove(const void* src, void* dst, size_t count) 32 27 { ··· 60 55 61 56 Ptr NewPtr(long len) 62 57 { 63 - PtrInternal* ptr = (PtrInternal*) malloc(len + sizeof(uintptr_t)); 64 - ptr->size = len; 65 - return (Ptr) ptr->data; 58 + return (Ptr) malloc(len); 66 59 } 67 60 68 61 Ptr NewPtrClear(long len) 69 62 { 70 - PtrInternal* ptr = (PtrInternal*) calloc(1, len + sizeof(uintptr_t)); 71 - ptr->size = len; 72 - return (Ptr) ptr->data; 63 + return (Ptr) calloc(1, len); 73 64 } 74 65 75 66 void DisposePtr(Ptr p) 76 67 { 77 - free(((uint8_t*)p) - sizeof(uintptr_t)); 68 + free(p); 78 69 } 79 70 80 71 void DisposeHandle(Handle handle) ··· 136 127 137 128 long GetPtrSize(Ptr ptr) 138 129 { 139 - PtrInternal* internal = (PtrInternal*)(((char*) ptr) - sizeof(uintptr_t)); 140 - return internal->size; 130 + return malloc_size(ptr); 141 131 } 142 132 143 133 void SetPtrSize(Ptr ptr, long newSize) 144 134 { 145 - PtrInternal* internal = (PtrInternal*)(((char*) ptr) - sizeof(uintptr_t)); 146 - if (newSize < internal->size) 147 - internal->size = newSize; 135 + if (newSize < malloc_size(ptr)) 136 + realloc(ptr, newSize); // Let's hope this never changes the ptr, but the whole SetPtrSize() call is idiotic 148 137 else 149 138 { 150 139 // This is not possible with a non-relocatable block ··· 162 151 } 163 152 else 164 153 { 165 - PtrInternal* internal = (PtrInternal*)(((char*) *h) - sizeof(uintptr_t)); 166 - 167 - internal = (PtrInternal*) realloc(internal, newSize + sizeof(uintptr_t)); 168 - internal->size = newSize; 169 - 170 - *h = (Ptr) internal->data; 154 + *h = (Ptr) realloc(*h, newSize); 171 155 } 172 156 } 173 157
+9 -2
src/kernel/emulation/linux/signal/sigaction.h
··· 47 47 int si_signo; 48 48 int si_errno; 49 49 int si_code; 50 - int si_pid; 51 - int si_uid; 50 + union 51 + { 52 + struct 53 + { 54 + int si_pid; 55 + int si_uid; 56 + }; 57 + void* si_addr; 58 + }; 52 59 53 60 union 54 61 {
+33 -3
src/kernel/emulation/linux/signal/sigexc.c
··· 30 30 void sigrt_handler(int signum, struct linux_siginfo* info, void* ctxt); 31 31 32 32 #define SIGEXC_TSD_KEY 102 33 + #define SIGEXC_CONTEXT_TSD_KEY 103 33 34 static char sigexc_altstack[8192]; 34 35 static struct bsd_stack orig_stack; 35 36 ··· 44 45 static void thread_state_to_mcontext(const x86_thread_state32_t* s, struct linux_gregset* regs); 45 46 static void float_state_to_mcontext(const x86_float_state32_t* s, linux_fpregset_t fx); 46 47 #endif 48 + 49 + static void state_to_kernel(struct linux_ucontext* ctxt, thread_t thread); 47 50 48 51 #define DEBUG_SIGEXC 49 52 #ifdef DEBUG_SIGEXC ··· 173 176 int sig = info->si_value; 174 177 if (sig == SIGNAL_THREAD_SUSPEND) 175 178 { 176 - kern_printf("sigexc: SIGNAL_THREAD_SUSPEND"); 177 - sigexc_fake_suspend(ctxt); 179 + kern_printf("sigexc: SIGNAL_THREAD_SUSPEND\n"); 180 + if (_pthread_getspecific_direct(SIGEXC_TSD_KEY) == 0) 181 + sigexc_fake_suspend(ctxt); 182 + else 183 + { 184 + kern_printf("sigexc: already suspended\n"); 185 + void* ctxt = _pthread_getspecific_direct(SIGEXC_CONTEXT_TSD_KEY); 186 + 187 + if (ctxt) 188 + { 189 + thread_t thread = mach_thread_self(); 190 + state_to_kernel(ctxt, thread); 191 + kern_printf("sigexc: state_to_kernel complete\n"); 192 + } 193 + } 178 194 } 179 195 else if (sig == SIGNAL_THREAD_RESUME) 180 196 { 181 - kern_printf("sigexc: SIGNAL_THREAD_RESUME"); 197 + kern_printf("sigexc: SIGNAL_THREAD_RESUME\n"); 182 198 } 183 199 else if (sig < 0) 184 200 { ··· 310 326 memset(&fstate, 0, sizeof(fstate)); 311 327 } 312 328 329 + __simple_kprintf("sigexc: Telling kernel our RIP is %p\n", tstate.__rip); 330 + 313 331 thread_set_state(thread, x86_THREAD_STATE64, (thread_state_t) &tstate, x86_THREAD_STATE64_COUNT); 314 332 thread_set_state(thread, x86_FLOAT_STATE64, (thread_state_t) &fstate, x86_FLOAT_STATE64_COUNT); 315 333 #elif defined(__i386__) ··· 420 438 return; 421 439 } 422 440 441 + if (linux_signum == 11) 442 + { 443 + kern_printf("sigexc: faulting address: %p, code: %d\n", info->si_addr, info->si_code); 444 + } 445 + 423 446 // SIGSEGV + SIGBUS -> EXC_BAD_ACCESS 424 447 // SIGTRAP -> EXC_BREAKPOINT 425 448 // SIGILL -> EXC_BAD_INSTRUCTION ··· 485 508 if (port != 0) 486 509 { 487 510 _pthread_setspecific_direct(SIGEXC_TSD_KEY, bsd_signum); 511 + _pthread_setspecific_direct(SIGEXC_CONTEXT_TSD_KEY, ctxt); 488 512 489 513 kern_return_t ret; 490 514 ··· 552 576 handler_linux_to_bsd(linux_signum, info, ctxt); 553 577 } 554 578 } 579 + 580 + kern_printf("sigexc: handler (%d) returning\n", linux_signum); 555 581 } 556 582 557 583 #if defined(__x86_64__) ··· 578 604 s->__cs = regs->cs; 579 605 s->__fs = regs->fs; 580 606 s->__gs = regs->gs; 607 + 608 + kern_printf("sigexc: saving to kernel: RIP %p, eflags 0x%x\n", regs->rip, regs->efl); 581 609 } 582 610 583 611 void mcontext_to_float_state(const linux_fpregset_t fx, x86_float_state64_t* s) ··· 622 650 regs->cs = s->__cs; 623 651 regs->fs = s->__fs; 624 652 regs->gs = s->__gs; 653 + 654 + kern_printf("sigexc: Next RIP will be %p, eflags: 0x%x\n", regs->rip, regs->efl); // single step trace bit is 0x100 625 655 } 626 656 627 657 void float_state_to_mcontext(const x86_float_state64_t* s, linux_fpregset_t fx)