this repo has no description
1
fork

Configure Feed

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

CoreAudio: AUHAL and AudioConverter now working

+254 -75
+126 -52
src/CoreAudio/AudioToolbox/AudioConverterImpl.cpp
··· 23 23 #include <cstring> 24 24 #include <cassert> 25 25 #include <iostream> 26 + #include <sstream> 26 27 #include "stub.h" 27 28 28 29 extern "C" { ··· 30 31 #include <libavutil/opt.h> 31 32 #include <libavutil/mem.h> 32 33 } 34 + 35 + static constexpr int ENCODER_FRAME_SAMPLES = 1024; 33 36 34 37 // http://blinkingblip.wordpress.com/ 35 38 ··· 38 41 avcodec_register_all(); 39 42 } 40 43 44 + static void throwFFMPEGError(int errnum, const char* function) 45 + { 46 + char buf[256]; 47 + std::stringstream ss; 48 + 49 + if (av_strerror(errnum, buf, sizeof(buf)) == 0) 50 + ss << function << ": " << buf; 51 + else 52 + ss << function << ": unknown error"; 53 + 54 + throw std::runtime_error(ss.str()); 55 + } 56 + 41 57 AudioConverter::AudioConverter(const AudioStreamBasicDescription* inSourceFormat, const AudioStreamBasicDescription* inDestinationFormat) 42 58 : m_sourceFormat(*inSourceFormat), m_destinationFormat(*inDestinationFormat), m_decoder(nullptr), m_encoder(nullptr) 43 59 { ··· 92 108 cIn->channels = inSourceFormat->mChannelsPerFrame; 93 109 cIn->sample_rate = inSourceFormat->mSampleRate; 94 110 95 - // LOG << "Converting from PCM with " << cIn->channels << " channels at " << cIn->sample_rate << " Hz\n"; 111 + std::cout << "Converting from PCM with " << cIn->channels << " channels at " << cIn->sample_rate << " Hz\n"; 96 112 } 97 113 98 114 if (avcodec_open2((*out)->m_decoder, codecIn, nullptr) < 0) 99 115 { 100 116 delete *out; 101 - // LOG << "AudioConverter::create(): avcodec_open() failed, format in = " << std::hex << inSourceFormat->mFormatID << ", out = " << inDestinationFormat->mFormatID << std::dec << std::endl; 117 + std::cerr << "AudioConverter::create(): avcodec_open() failed, format in = " << std::hex << inSourceFormat->mFormatID << ", out = " << inDestinationFormat->mFormatID << std::dec << std::endl; 102 118 103 119 return paramErr; 104 120 } ··· 124 140 m_encoder->sample_rate = m_destinationFormat.mSampleRate; 125 141 m_encoder->channel_layout = CAChannelCountToLayout(m_destinationFormat.mChannelsPerFrame); 126 142 m_encoder->sample_fmt = CACodecSampleFormat(&m_destinationFormat); 143 + 144 + #ifdef DEBUG_AUDIOCONVERTER 145 + std::cout << "ENCODER FORMAT:\n"; 146 + std::cout << "\tSample rate: " << m_encoder->sample_rate << std::endl; 147 + std::cout << "\tChannels: " << m_destinationFormat.mChannelsPerFrame << std::endl; 148 + std::cout << "\tFormat: 0x" << std::hex << m_encoder->sample_fmt << std::dec << std::endl; 149 + #endif 127 150 128 151 err = avcodec_open2(m_encoder, m_codecOut, 0); 129 152 if (err < 0) 130 - throw std::runtime_error("avcodec_open2() failed for encoder"); 153 + throwFFMPEGError(err, "avcodec_open2() encoder"); 131 154 132 155 allocateBuffers(); 133 156 m_encoderInitialized = true; ··· 141 164 m_audioFrame = avcodec_alloc_frame(); 142 165 #endif 143 166 144 - m_audioFrame->nb_samples = 4096; 167 + m_audioFrame->nb_samples = ENCODER_FRAME_SAMPLES; 145 168 m_audioFrame->format = m_encoder->sample_fmt; 146 169 m_audioFrame->channel_layout = m_encoder->channel_layout; 147 170 ··· 152 175 if (!audioSampleBuffer) 153 176 { 154 177 std::cerr << "AudioConverter::allocateBuffers(): Failed to allocate sample buffer\n"; 155 - //return paramErr; // TODO 178 + throw std::runtime_error("AudioConverter::allocateBuffers(): Failed to allocate sample buffer"); 156 179 } 157 180 158 181 // Setup the data pointers in the AVFrame 159 - if (avcodec_fill_audio_frame(m_audioFrame, m_encoder->channels, m_encoder->sample_fmt, (const uint8_t*) audioSampleBuffer, audioSampleBuffer_size, 0 ) < 0) 182 + if (int err = avcodec_fill_audio_frame(m_audioFrame, m_encoder->channels, m_encoder->sample_fmt, 183 + (const uint8_t*) audioSampleBuffer, audioSampleBuffer_size, 0 ); err < 0) 160 184 { 161 185 std::cerr << "AudioConverter::allocateBuffers(): Could not set up audio frame\n"; 162 - //return paramErr; // TODO 186 + throw std::runtime_error("AudioConverter::allocateBuffers(): Could not set up audio frame"); 163 187 } 164 188 } 165 189 ··· 282 306 m_avpkt.size = bufferList.mBuffers[0].mDataByteSize; 283 307 m_avpkt.data = (uint8_t*) bufferList.mBuffers[0].mData; 284 308 285 - // LOG << "dataProc() returned " << m_avpkt.size << " bytes of data\n"; 286 - 287 309 return noErr; 288 310 } 289 311 ··· 295 317 throw std::logic_error("Resampler already created"); 296 318 297 319 m_resampler = avresample_alloc_context(); 320 + m_targetFormat = CACodecSampleFormat(&m_destinationFormat); 298 321 299 322 av_opt_set_int(m_resampler, "in_channel_layout", CAChannelCountToLayout(m_sourceFormat.mChannelsPerFrame), 0); 300 323 av_opt_set_int(m_resampler, "out_channel_layout", CAChannelCountToLayout(m_destinationFormat.mChannelsPerFrame), 0); ··· 303 326 av_opt_set_int(m_resampler, "in_sample_rate", frame->sample_rate, 0); 304 327 av_opt_set_int(m_resampler, "out_sample_rate", m_destinationFormat.mSampleRate, 0); 305 328 av_opt_set_int(m_resampler, "in_sample_fmt", frame->format, 0); 306 - av_opt_set_int(m_resampler, "out_sample_fmt", CACodecSampleFormat(&m_destinationFormat), 0); 329 + av_opt_set_int(m_resampler, "out_sample_fmt", m_targetFormat, 0); 330 + 331 + #ifdef DEBUG_AUDIOCONVERTER 332 + std::cout << "RESAMPLER:\n"; 333 + std::cout << "\tInput rate: " << frame->sample_rate << std::endl; 334 + std::cout << "\tInput format: 0x" << std::hex << frame->format << std::dec <<std::endl; 335 + std::cout << "\tOutput rate: " << m_destinationFormat.mSampleRate << std::endl; 336 + std::cout << "\tOutput format: 0x" << std::hex << CACodecSampleFormat(&m_destinationFormat) << std::dec << std::endl; 337 + 338 + m_resamplerInput.open("/tmp/resampler.in.raw", std::ios_base::binary | std::ios_base::out); 339 + m_resamplerOutput.open("/tmp/resampler.out.raw", std::ios_base::binary | std::ios_base::out); 340 + m_encoderOutput.open("/tmp/encoder.out.raw", std::ios_base::binary | std::ios_base::out); 341 + #endif 307 342 308 343 err = avresample_open(m_resampler); 309 344 if (err < 0) 310 - throw std::runtime_error("avresample_open() failed"); 345 + throwFFMPEGError(err, "avresample_open()"); 311 346 } 312 347 313 - OSStatus AudioConverter::fillComplex(AudioConverterComplexInputDataProc dataProc, void* opaque, UInt32* ioOutputDataPacketSize, AudioBufferList *outOutputData, AudioStreamPacketDescription* outPacketDescription) 348 + OSStatus AudioConverter::fillComplex(AudioConverterComplexInputDataProc dataProc, void* opaque, 349 + UInt32* ioOutputDataPacketSize, AudioBufferList *outOutputData, AudioStreamPacketDescription* outPacketDescription) 314 350 { 315 351 AVFrame* srcaudio; 316 352 ··· 335 371 { 336 372 if (m_avpktOutUsed < m_avpktOut.size) 337 373 { 338 - // LOG << "case 1 (used " << m_avpktOutUsed << " from " << m_avpktOut.size << ")\n"; 374 + // std::cout << "case 1 (used " << m_avpktOutUsed << " from " << m_avpktOut.size << ")\n"; 339 375 // Feed output from previous conversion 340 376 while (m_avpktOutUsed < m_avpktOut.size && newSize < origSize) 341 377 { ··· 352 388 av_free_packet(&m_avpktOut); 353 389 } 354 390 } 355 - else if (!m_resampler || avresample_available(m_resampler) == 0) 356 - { 357 - // LOG << "case 2\n"; 358 - feedDecoder(dataProc, opaque, srcaudio); 359 - if (avresample_available(m_resampler) == 0) 360 - goto end; 361 - } 362 391 else 363 392 { 364 - // LOG << "case 3\n"; 365 - feedEncoder(); 393 + while (!feedEncoder()) 394 + { 395 + if (!feedDecoder(dataProc, opaque, srcaudio)) 396 + goto end; 397 + } 366 398 } 367 399 } 368 400 } ··· 376 408 } 377 409 catch (const std::exception& e) 378 410 { 379 - // ERROR() << "Exception: " << e.what(); 411 + std::cerr << "AudioConverter::fillComplex(): Exception: " << e.what(); 380 412 #ifdef HAVE_AV_FRAME_ALLOC 381 413 av_frame_free(&srcaudio); 382 414 #else 383 415 avcodec_free_frame(&srcaudio); 384 416 #endif 417 + return ioErr; 385 418 } 386 419 catch (OSStatus err) 387 420 { 388 - // ERROR() << "OSStatus error: " << err; 421 + std::cerr << "AudioConverter::fillComplex(): OSStatus error: " << err; 389 422 #ifdef HAVE_AV_FRAME_ALLOC 390 423 av_frame_free(&srcaudio); 391 424 #else ··· 397 430 return noErr; 398 431 } 399 432 400 - void AudioConverter::feedDecoder(AudioConverterComplexInputDataProc dataProc, void* opaque, AVFrame* srcaudio) 433 + bool AudioConverter::feedDecoder(AudioConverterComplexInputDataProc dataProc, void* opaque, AVFrame* srcaudio) 401 434 { 402 435 int gotFrame, err; 403 436 ··· 409 442 UInt32 numDataPackets = 0; 410 443 OSStatus err = feedInput(dataProc, opaque, numDataPackets); 411 444 445 + // The documentation says that this may be a temporary condition 412 446 if (err != noErr) 413 - throw err; 447 + return false; 414 448 415 449 if (!m_avpkt.size) // numDataPackets cannot be trusted 416 - break; 450 + return false; 417 451 } 418 452 419 453 err = avcodec_decode_audio4(m_decoder, srcaudio, &gotFrame, &m_avpkt); 420 454 if (err < 0) 421 - throw std::runtime_error("avcodec_decode_audio4() failed"); 455 + throwFFMPEGError(err, "avcodec_decode_audio4()"); 422 456 423 457 m_avpkt.size -= err; 424 458 m_avpkt.data += err; ··· 427 461 { 428 462 if (!m_resampler) 429 463 setupResampler(srcaudio); 464 + 465 + #ifdef DEBUG_AUDIOCONVERTER 466 + m_resamplerInput.write((char*) srcaudio->data, srcaudio->nb_samples * 2 * m_sourceFormat.mChannelsPerFrame); 467 + m_resamplerInput.flush(); 468 + #endif 430 469 431 470 // Resample PCM 432 471 err = avresample_convert(m_resampler, nullptr, 0, 0, srcaudio->data, 0, srcaudio->nb_samples); 433 472 if (err < 0) 434 - throw std::runtime_error("avresample_convert() failed"); 473 + throwFFMPEGError(err, "avresample_convert()"); 435 474 } 436 475 } 437 476 while (!gotFrame); 477 + 478 + return true; 438 479 } 439 480 440 - void AudioConverter::feedEncoder() 481 + bool AudioConverter::feedEncoder() 441 482 { 442 483 int gotFrame = 0, err; 443 484 uint8_t *output; 444 485 int out_linesize; 445 486 int avail; 446 487 488 + if (!m_resampler) 489 + return false; 490 + 447 491 if (!m_encoderInitialized) 448 492 initEncoder(); 449 493 450 494 assert(m_avpktOutUsed == m_avpktOut.size); 451 495 452 - do 496 + const size_t bytesPerSample = m_destinationFormat.mBitsPerChannel / 8; 497 + const size_t bytesPerFrame = m_destinationFormat.mChannelsPerFrame * bytesPerSample; 498 + const size_t requiredBytes = bytesPerFrame * ENCODER_FRAME_SAMPLES; 499 + 500 + while (m_audioFramePrebuf.size() < requiredBytes && (avail = avresample_available(m_resampler)) > 0) 453 501 { 454 - avail = avresample_available(m_resampler); 455 - av_samples_alloc(&output, &out_linesize, m_destinationFormat.mChannelsPerFrame, avail, m_encoder->sample_fmt, 0); 502 + av_samples_alloc(&output, &out_linesize, m_destinationFormat.mChannelsPerFrame, 503 + avail, m_encoder->sample_fmt, 0); 456 504 457 505 if (avresample_read(m_resampler, &output, avail) != avail) 458 - throw std::runtime_error("avresample_read() failed"); 459 - 460 - av_init_packet(&m_avpktOut); 461 - m_avpktOut.data = 0; 462 - m_avpktOut.size = 0; 463 - m_avpktOutUsed = 0; 506 + { 507 + av_freep(&output); 508 + throwFFMPEGError(err, "avresample_read()"); 509 + } 464 510 465 - // LOG << "Got " << avail << " samples\n"; 466 - err = avcodec_fill_audio_frame(m_audioFrame, m_encoder->channels, 467 - m_encoder->sample_fmt, output, avail * m_destinationFormat.mChannelsPerFrame * (m_destinationFormat.mBitsPerChannel / 8), 468 - m_destinationFormat.mChannelsPerFrame * (m_destinationFormat.mBitsPerChannel / 8)); 469 - 470 - if (err < 0) 471 - throw std::runtime_error("avcodec_fill_audio_frame() failed"); 511 + #ifdef DEBUG_AUDIOCONVERTER 512 + m_resamplerOutput.write((char*) output, avail * bytesPerFrame); 513 + m_resamplerOutput.flush(); 514 + #endif 472 515 473 - // Encode PCM data 474 - err = avcodec_encode_audio2(m_encoder, &m_avpktOut, m_audioFrame, &gotFrame); 516 + m_audioFramePrebuf.push(output, avail * bytesPerFrame); 475 517 av_freep(&output); 476 - 477 - if (err < 0) 478 - throw std::runtime_error("avcodec_encode_audio2() failed"); 479 518 } 480 - while(!gotFrame); 519 + 520 + av_init_packet(&m_avpktOut); 521 + m_avpktOut.data = 0; 522 + m_avpktOut.size = 0; 523 + m_avpktOutUsed = 0; 524 + 525 + if (m_audioFramePrebuf.size() >= requiredBytes) 526 + { 527 + try 528 + { 529 + err = avcodec_fill_audio_frame(m_audioFrame, m_destinationFormat.mChannelsPerFrame, 530 + m_targetFormat, m_audioFramePrebuf.data(), requiredBytes, 0); 531 + 532 + if (err < 0) 533 + throwFFMPEGError(err, "avcodec_fill_audio_frame()"); 534 + 535 + err = avcodec_encode_audio2(m_encoder, &m_avpktOut, m_audioFrame, &gotFrame); 536 + if (err < 0) 537 + throwFFMPEGError(err, "avcodec_encode_audio2()"); 538 + 539 + m_audioFramePrebuf.consume(requiredBytes); 540 + 541 + #ifdef DEBUG_AUDIOCONVERTER 542 + if (gotFrame) 543 + m_encoderOutput.write((char*) m_avpktOut.data, m_avpktOut.size); 544 + #endif 545 + } 546 + catch (...) 547 + { 548 + m_audioFramePrebuf.consume(requiredBytes); 549 + throw; 550 + } 551 + 552 + return gotFrame; 553 + } 554 + return false; 481 555 } 482 556 483 557 uint32_t AudioConverter::CAChannelCountToLayout(UInt32 numChannels)
+13 -3
src/CoreAudio/AudioToolbox/AudioConverterImpl.h
··· 1 1 #ifndef AUDIOCONVERTERINTERNAL_H 2 2 #define AUDIOCONVERTERINTERNAL_H 3 3 #include "AudioConverter.h" 4 + #include "ConsumableBuffer.h" 4 5 #include <stdint.h> 6 + #include <fstream> 5 7 6 8 extern "C" { 7 9 #include <libavresample/avresample.h> ··· 37 39 void allocateBuffers(); 38 40 void initEncoder(); 39 41 40 - void feedDecoder(AudioConverterComplexInputDataProc dataProc, void* opaque, AVFrame* srcaudio); 41 - void feedEncoder(); 42 + bool feedDecoder(AudioConverterComplexInputDataProc dataProc, void* opaque, AVFrame* srcaudio); 43 + bool feedEncoder(); 42 44 private: 43 45 AudioStreamBasicDescription m_sourceFormat, m_destinationFormat; 44 46 UInt32 m_inputChannelLayout, m_outputChannelLayout; 47 + AVSampleFormat m_targetFormat; 45 48 AVCodecContext* m_decoder; 46 49 AVCodecContext* m_encoder; 47 50 AVPacket m_avpkt, m_avpktOut; 48 51 UInt32 m_avpktOutUsed = 0; 49 - AVFrame* m_audioFrame; 52 + 53 + AVFrame* m_audioFrame = nullptr; 54 + ConsumableBuffer m_audioFramePrebuf; 55 + 50 56 AVAudioResampleContext* m_resampler = nullptr; 51 57 UInt32 m_outBitRate = 128000; 52 58 bool m_encoderInitialized = false; 53 59 AVCodec* m_codecIn = nullptr; 54 60 AVCodec* m_codecOut = nullptr; 61 + 62 + #ifdef DEBUG_AUDIOCONVERTER 63 + std::ofstream m_resamplerInput, m_resamplerOutput, m_encoderOutput; 64 + #endif 55 65 }; 56 66 57 67 #endif
+55
src/CoreAudio/AudioToolbox/ConsumableBuffer.h
··· 1 + /* 2 + This file is part of Darling. 3 + 4 + Copyright (C) 2020 Lubos Dolezel 5 + 6 + Darling is free software: you can redistribute it and/or modify 7 + it under the terms of the GNU General Public License as published by 8 + the Free Software Foundation, either version 3 of the License, or 9 + (at your option) any later version. 10 + 11 + Darling is distributed in the hope that it will be useful, 12 + but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + GNU General Public License for more details. 15 + 16 + You should have received a copy of the GNU General Public License 17 + along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 + */ 19 + 20 + #ifndef _CA_CONSUMABLE_BUFFER_H 21 + #define _CA_CONSUMABLE_BUFFER_H 22 + #include <vector> 23 + #include <stdexcept> 24 + #include <cstring> 25 + #include <stdint.h> 26 + 27 + class ConsumableBuffer 28 + { 29 + public: 30 + void push(const void* mem, size_t bytes) 31 + { 32 + const uint8_t* ptr = static_cast<const uint8_t*>(mem); 33 + m_data.insert(m_data.end(), ptr, ptr + bytes); 34 + } 35 + size_t size() const 36 + { 37 + return m_data.size(); 38 + } 39 + const uint8_t* data() 40 + { 41 + return m_data.data(); 42 + } 43 + void consume(size_t bytes) 44 + { 45 + if (bytes > size()) 46 + throw std::logic_error("ConsumableBuffer::consume() bytes > size()"); 47 + 48 + std::memmove(m_data.data(), m_data.data() + bytes, m_data.size() - bytes); 49 + m_data.resize(m_data.size() - bytes); 50 + } 51 + private: 52 + std::vector<uint8_t> m_data; 53 + }; 54 + 55 + #endif
+3 -3
src/CoreAudio/CoreAudio/AudioHardwareImpl.cpp
··· 108 108 return kAudioHardwareNotRunningError; 109 109 110 110 AudioHardwareStream* stream = it->second.release(); 111 - stream->stop(^{ 112 - delete stream; 113 - }); 111 + stream->stop(); 112 + 113 + delete stream; 114 114 m_streams.erase(it); 115 115 return noErr; 116 116 }
+3 -1
src/CoreAudio/CoreAudio/AudioHardwareStream.cpp
··· 19 19 20 20 #include "AudioHardwareStream.h" 21 21 #include "AudioHardwareImpl.h" 22 + #include <condition_variable> 23 + #include <mutex> 24 + #include <iostream> 22 25 23 26 AudioHardwareStream::AudioHardwareStream(AudioHardwareImpl* hw, bool needBuffer) 24 27 : m_hw(hw) ··· 35 38 { 36 39 delete m_buffer; 37 40 } 38 -
+2 -1
src/CoreAudio/CoreAudio/AudioHardwareStream.h
··· 29 29 AudioHardwareStream(AudioHardwareImpl* hw, bool needBuffer = true); 30 30 virtual ~AudioHardwareStream(); 31 31 32 - virtual void stop(void(^cbDone)()) = 0; 32 + virtual void stop(/*void(^cbDone)()*/) = 0; 33 + //void stop(); 33 34 protected: 34 35 AudioHardwareImpl* m_hw; 35 36 uint32_t m_bufferSize;
+8 -11
src/CoreAudio/CoreAudio/pulse/AudioHardwareStreamPA.cpp
··· 63 63 pa_stream_unref(m_stream); 64 64 } 65 65 66 - void AudioHardwareStreamPA::stop(void(^cbDone)()) 66 + void AudioHardwareStreamPA::start() 67 67 { 68 - // std::cerr << "AudioHardwareStreamPA::stop()\n"; 69 - m_cbDone = Block_copy(cbDone); 68 + m_running = true; 69 + } 70 70 71 - pa_stream_cork(m_stream, true, [](pa_stream*, int, void* self) { 72 - AudioHardwareStreamPA* This = static_cast<AudioHardwareStreamPA*>(self); 73 - 74 - pa_stream_disconnect(This->m_stream); 75 - This->m_cbDone(); 76 - 77 - Block_release(This->m_cbDone); 78 - }, this); 71 + void AudioHardwareStreamPA::stop() 72 + { 73 + std::unique_lock<std::mutex> l(m_stopMutex); 74 + pa_stream_disconnect(m_stream); 75 + m_running = false; 79 76 } 80 77 81 78 // This function seems to only convert unsigned to signed, but it works both ways in practice
+6 -2
src/CoreAudio/CoreAudio/pulse/AudioHardwareStreamPA.h
··· 24 24 #include <CoreAudio/CoreAudioTypes.h> 25 25 #include <CoreAudio/AudioHardware.h> 26 26 #include "AudioHardwareImplPA.h" 27 + #include <condition_variable> 27 28 28 29 class AudioHardwareStreamPA : public AudioHardwareStream 29 30 { ··· 31 32 AudioHardwareStreamPA(AudioHardwareImplPA* hw, AudioDeviceIOProc callback, void* clientData); 32 33 ~AudioHardwareStreamPA(); 33 34 34 - void stop(void(^cbDone)()) override; 35 + void stop(/*void(^cbDone)()*/) override; 35 36 protected: 36 - virtual void start() = 0; 37 + virtual void start(); 37 38 void transformSignedUnsigned(AudioBufferList* abl) const; 38 39 protected: 39 40 AudioDeviceIOProc m_callback; ··· 41 42 pa_stream* m_stream; 42 43 void(^m_cbDone)(); 43 44 bool m_convertSignedUnsigned = false; 45 + 46 + bool m_running = false; 47 + std::mutex m_stopMutex; 44 48 }; 45 49 46 50 #endif /* AUDIOHARDWARESTREAMPA_H */
+6
src/CoreAudio/CoreAudio/pulse/AudioHardwareStreamPAInput.cpp
··· 32 32 { 33 33 AudioHardwareStreamPAInput* This = static_cast<AudioHardwareStreamPAInput*>(self); 34 34 35 + std::unique_lock<std::mutex> l(This->m_stopMutex); 36 + 37 + if (!This->m_running) 38 + return; 39 + 35 40 AudioTimeStamp fake = {0}; 36 41 AudioBufferList* abl = static_cast<AudioBufferList*>(alloca(sizeof(AudioBufferList) + sizeof(AudioBuffer))); 37 42 std::vector<uint8_t> hole; ··· 98 103 ); 99 104 100 105 // std::cout << "AudioHardwareStreamPAInput::start() rv = " << rv << std::endl; 106 + AudioHardwareStreamPA::start(); 101 107 }
+12 -2
src/CoreAudio/CoreAudio/pulse/AudioHardwareStreamPAOutput.cpp
··· 29 29 30 30 void AudioHardwareStreamPAOutput::paStreamWriteCB(pa_stream* s, size_t length, void* self) 31 31 { 32 - // std::cout << "AudioHardwareStreamPAOutput::paStreamWriteCB()\n"; 33 32 AudioHardwareStreamPAOutput* This = static_cast<AudioHardwareStreamPAOutput*>(self); 33 + std::unique_lock<std::mutex> l(This->m_stopMutex); 34 + 35 + if (!This->m_running) 36 + { 37 + pa_stream_cork(This->m_stream, true, [](pa_stream*, int, void*) {}, nullptr); 38 + return; 39 + } 40 + 41 + // std::cout << "AudioHardwareStreamPAOutput::paStreamWriteCB()\n"; 34 42 35 43 AudioTimeStamp fake = {0}; 36 44 AudioBufferList* abl = static_cast<AudioBufferList*>(alloca(sizeof(AudioBufferList) + sizeof(AudioBuffer))); 37 45 38 46 size_t done = 0; 39 47 40 - while (done < length) 48 + while (done < length && This->m_running) 41 49 { 42 50 // Non-interleaved (planar) audio would have multiple buffers, but PA doesn't even support that AFAIK 43 51 abl->mNumberBuffers = 1; ··· 58 66 // std::cerr << "AudioDeviceIOProc returned " << status << ", corking...\n"; 59 67 60 68 pa_stream_cork(This->m_stream, true, [](pa_stream*, int, void*) {}, nullptr); 69 + break; 61 70 } 62 71 else 63 72 { ··· 97 106 nullptr, nullptr); 98 107 99 108 // pa_stream_cork(m_stream, false, [](pa_stream*, int, void*) {}, nullptr); 109 + AudioHardwareStreamPA::start(); 100 110 } 101 111
+19
src/CoreAudio/CoreAudioComponent/AUHAL.cpp
··· 18 18 */ 19 19 20 20 #include "AUHAL.h" 21 + #include <iostream> 21 22 22 23 #pragma GCC visibility push(default) 23 24 AUDIOCOMPONENT_ENTRY(AUOutputBaseFactory, AUHAL); ··· 34 35 UInt32 propSize = sizeof(AudioDeviceID); 35 36 AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &propSize, &m_outputDevice); 36 37 AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &propSize, &m_inputDevice); 38 + } 39 + 40 + AUHAL::~AUHAL() 41 + { 42 + Stop(); 37 43 } 38 44 39 45 bool AUHAL::CanScheduleParameters() const ··· 75 81 76 82 if (m_enableOutput) 77 83 { 84 + // std::cout << "Output is enabled, starting playback\n"; 78 85 AudioDeviceCreateIOProcID(m_outputDevice, playbackCallback, this, &m_outputProcID); 86 + 87 + // m_auhalData.open("/tmp/auhal.raw", std::ios_base::binary | std::ios_base::out); 79 88 80 89 const CAStreamBasicDescription& desc = GetStreamFormat(kAudioUnitScope_Input, kOutputBus); 81 90 AudioDeviceSetProperty(m_outputDevice, nullptr, 0, false, kAudioDevicePropertyStreamFormat, sizeof(AudioStreamBasicDescription), &desc); ··· 89 98 AudioDeviceStart(m_inputDevice, m_inputProcID); 90 99 } 91 100 101 + m_running = m_enableOutput || m_enableInput; 92 102 return noErr; 93 103 } 94 104 ··· 269 279 270 280 OSStatus AUHAL::doPlayback(const AudioTimeStamp* inNow, AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime) 271 281 { 282 + // std::cout << "AUHAL::DoPlayback()\n"; 272 283 if (!HasInput(0)) 284 + { 285 + // std::cerr << "No connection\n"; 273 286 return kAudioUnitErr_NoConnection; 287 + } 274 288 275 289 OSStatus result = noErr; 276 290 AudioUnitRenderActionFlags flags = kAudioUnitRenderAction_PreRender; ··· 278 292 279 293 UInt32 nFrames = outOutputData->mBuffers[0].mDataByteSize / (desc.mBytesPerFrame / outOutputData->mBuffers[0].mNumberChannels); 280 294 result = GetInput(kOutputBus)->PullInputWithBufferList(flags, *inNow, kOutputBus, nFrames, outOutputData); 295 + 296 + // std::cout << "Pull result: " << result << std::endl; 297 + // std::cout << "Bytes: " << outOutputData->mBuffers[0].mDataByteSize << std::endl; 298 + // m_auhalData.write((char*) outOutputData->mBuffers[0].mData, outOutputData->mBuffers[0].mDataByteSize); 299 + // m_auhalData.flush(); 281 300 282 301 return result; 283 302 }
+1
src/CoreAudio/CoreAudioComponent/AUHAL.h
··· 30 30 { 31 31 public: 32 32 AUHAL(AudioComponentInstance inInstance, bool supportRecording = true); 33 + ~AUHAL(); 33 34 34 35 bool CanScheduleParameters() const override; 35 36 bool StreamFormatWritable(AudioUnitScope scope, AudioUnitElement element) override;