···11-/*
22-This file is part of Darling.
33-44-Copyright (C) 2020 Lubos Dolezel
55-66-Darling is free software: you can redistribute it and/or modify
77-it under the terms of the GNU General Public License as published by
88-the Free Software Foundation, either version 3 of the License, or
99-(at your option) any later version.
1010-1111-Darling is distributed in the hope that it will be useful,
1212-but WITHOUT ANY WARRANTY; without even the implied warranty of
1313-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1414-GNU General Public License for more details.
1515-1616-You should have received a copy of the GNU General Public License
1717-along with Darling. If not, see <http://www.gnu.org/licenses/>.
1818-*/
1919-2020-#include "AudioHardwareImplPA.h"
2121-#include "stub.h"
2222-2323-AudioHardwareImplPA::AudioHardwareImplPA()
2424-{
2525- m_name = CFSTR("PulseAudio");
2626- m_manufacturer = CFSTR("PulseAudio");
2727- m_uid = CFSTR("100");
2828-}
2929-3030-OSStatus AudioHardwareImplPA::getPropertyData(const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize,
3131- const void* inQualifierData, UInt32* ioDataSize, void* outData)
3232-{
3333- switch (inAddress->mSelector)
3434- {
3535- // BEGIN kAudioObjectSystemObject properties
3636- case kAudioHardwarePropertyDefaultInputDevice: // returns AudioDeviceID
3737- if (AudioDeviceID* devId = static_cast<AudioDeviceID*>(outData); devId && *ioDataSize >= sizeof(AudioDeviceID))
3838- {
3939- // We're doing a bit of an abuse here, which works only for PA where we have a single virtual device.
4040- // For ALSA, we could do kAudioObjectSystemObject + INDEX of device.
4141- *devId = kAudioObjectSystemObject;
4242- }
4343- *ioDataSize = sizeof(AudioDeviceID);
4444- return kAudioHardwareNoError;
4545- case kAudioHardwarePropertyDefaultOutputDevice: // returns AudioDeviceID
4646- if (AudioDeviceID* devId = static_cast<AudioDeviceID*>(outData); devId && *ioDataSize >= sizeof(AudioDeviceID))
4747- {
4848- *devId = kAudioObjectSystemObject;
4949- }
5050- *ioDataSize = sizeof(AudioDeviceID);
5151- return kAudioHardwareNoError;
5252- case kAudioHardwarePropertyDevices:
5353- {
5454- if (AudioDeviceID* devId = static_cast<AudioDeviceID*>(outData); devId && *ioDataSize >= sizeof(AudioDeviceID))
5555- {
5656- devId[0] = kAudioObjectSystemObject;
5757- }
5858- *ioDataSize = sizeof(AudioDeviceID) * 1;
5959- return kAudioHardwareNoError;
6060- }
6161- // END kAudioObjectSystemObject properties
6262-6363- // BEGIN properties of a specific audio device (in case of PA, it is kAudioObjectSystemObject as well)
6464- case kAudioDevicePropertyStreamConfiguration: // returns AudioBufferList
6565- {
6666- const size_t size = sizeof(AudioBufferList) + 1* sizeof(AudioBuffer);
6767-6868- // Number of returned buffers is the number of channels
6969- // check inAddress->mScope. If it equals kAudioDevicePropertyScopeInput, the caller cares about input only.
7070- if (AudioBufferList* abl = static_cast<AudioBufferList*>(outData); abl && *ioDataSize >= size)
7171- {
7272- abl->mNumberBuffers = 1;
7373- abl->mBuffers[0].mNumberChannels = 2;
7474-7575- // TODO: Is the below stuff ever used? How?
7676- abl->mBuffers[0].mData = nullptr;
7777- abl->mBuffers[0].mDataByteSize = 0;
7878- }
7979-8080- *ioDataSize = size;
8181- return kAudioHardwareNoError;
8282- }
8383-8484- }
8585-8686- return AudioHardwareImpl::getPropertyData(inAddress, inQualifierDataSize, inQualifierData, ioDataSize, outData);
8787-}
8888-8989-OSStatus AudioHardwareImplPA::setPropertyData(const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize,
9090- const void* inQualifierData, UInt32 inDataSize, const void* inData)
9191-{
9292- return AudioHardwareImpl::setPropertyData(inAddress, inQualifierDataSize, inQualifierData, inDataSize, inData);
9393-}
9494-9595-AudioHardwareStream* AudioHardwareImplPA::createStream(AudioDeviceIOProcID procID)
9696-{
9797- // TODO
9898- STUB();
9999- return nullptr;
100100-}
···11+/*
22+This file is part of Darling.
33+44+Copyright (C) 2020 Lubos Dolezel
55+66+Darling is free software: you can redistribute it and/or modify
77+it under the terms of the GNU General Public License as published by
88+the Free Software Foundation, either version 3 of the License, or
99+(at your option) any later version.
1010+1111+Darling is distributed in the hope that it will be useful,
1212+but WITHOUT ANY WARRANTY; without even the implied warranty of
1313+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1414+GNU General Public License for more details.
1515+1616+You should have received a copy of the GNU General Public License
1717+along with Darling. If not, see <http://www.gnu.org/licenses/>.
1818+*/
1919+2020+#include "AudioHardwareImplPAOutput.h"
2121+#include "AudioHardwareStreamPAOutput.h"
2222+2323+AudioHardwareImplPAOutput::AudioHardwareImplPAOutput()
2424+{
2525+ m_uid = CFSTR("PulseAudio:Output");
2626+}
2727+2828+AudioHardwareImplPAOutput::~AudioHardwareImplPAOutput()
2929+{
3030+}
3131+3232+OSStatus AudioHardwareImplPAOutput::getPropertyData(const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize,
3333+ const void* inQualifierData, UInt32* ioDataSize, void* outData)
3434+{
3535+ if (inAddress->mSelector == kAudioDevicePropertyStreamConfiguration)
3636+ {
3737+ size_t size = sizeof(AudioBufferList);
3838+3939+ if (inAddress->mScope == kAudioDevicePropertyScopeOutput)
4040+ size += 1* sizeof(AudioBuffer);
4141+4242+ // Number of returned buffers is the number of channels
4343+ if (AudioBufferList* abl = static_cast<AudioBufferList*>(outData); abl && *ioDataSize >= size)
4444+ {
4545+ if (inAddress->mScope == kAudioDevicePropertyScopeOutput)
4646+ {
4747+ abl->mNumberBuffers = 1;
4848+ abl->mBuffers[0].mNumberChannels = 2;
4949+5050+ // TODO: Is the below stuff ever used? How?
5151+ abl->mBuffers[0].mData = nullptr;
5252+ abl->mBuffers[0].mDataByteSize = 0;
5353+ }
5454+ else
5555+ abl->mNumberBuffers = 0;
5656+ }
5757+5858+ *ioDataSize = size;
5959+ return kAudioHardwareNoError;
6060+ }
6161+6262+ return AudioHardwareImplPA::getPropertyData(inAddress, inQualifierDataSize, inQualifierData, ioDataSize, outData);
6363+}
6464+6565+OSStatus AudioHardwareImplPAOutput::setPropertyData(const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize,
6666+ const void* inQualifierData, UInt32 inDataSize, const void* inData)
6767+{
6868+ return AudioHardwareImplPA::setPropertyData(inAddress, inQualifierDataSize, inQualifierData, inDataSize, inData);
6969+}
7070+7171+AudioHardwareStream* AudioHardwareImplPAOutput::createStream(AudioDeviceIOProc callback, void* clientData)
7272+{
7373+ return new AudioHardwareStreamPAOutput(callback, clientData);
7474+}
···11+/*
22+This file is part of Darling.
33+44+Copyright (C) 2020 Lubos Dolezel
55+66+Darling is free software: you can redistribute it and/or modify
77+it under the terms of the GNU General Public License as published by
88+the Free Software Foundation, either version 3 of the License, or
99+(at your option) any later version.
1010+1111+Darling is distributed in the hope that it will be useful,
1212+but WITHOUT ANY WARRANTY; without even the implied warranty of
1313+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1414+GNU General Public License for more details.
1515+1616+You should have received a copy of the GNU General Public License
1717+along with Darling. If not, see <http://www.gnu.org/licenses/>.
1818+*/
1919+2020+#ifndef AUDIOHARDWAREIMPLPAOUTPUT_H
2121+#define AUDIOHARDWAREIMPLPAOUTPUT_H
2222+#include "AudioHardwareImplPA.h"
2323+2424+class AudioHardwareImplPAOutput : public AudioHardwareImplPA
2525+{
2626+public:
2727+ AudioHardwareImplPAOutput();
2828+ ~AudioHardwareImplPAOutput();
2929+3030+ OSStatus getPropertyData(const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize,
3131+ const void* inQualifierData, UInt32* ioDataSize, void* outData) override;
3232+3333+ OSStatus setPropertyData(const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize,
3434+ const void* inQualifierData, UInt32 inDataSize, const void* inData) override;
3535+protected:
3636+ AudioHardwareStream* createStream(AudioDeviceIOProc callback, void* clientData) override;
3737+};
3838+3939+#endif
4040+
···11+/*
22+This file is part of Darling.
33+44+Copyright (C) 2020 Lubos Dolezel
55+66+Darling is free software: you can redistribute it and/or modify
77+it under the terms of the GNU General Public License as published by
88+the Free Software Foundation, either version 3 of the License, or
99+(at your option) any later version.
1010+1111+Darling is distributed in the hope that it will be useful,
1212+but WITHOUT ANY WARRANTY; without even the implied warranty of
1313+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1414+GNU General Public License for more details.
1515+1616+You should have received a copy of the GNU General Public License
1717+along with Darling. If not, see <http://www.gnu.org/licenses/>.
1818+*/
1919+2020+#include "AudioHardwareStreamPA.h"
2121+2222+AudioHardwareStreamPA::AudioHardwareStreamPA(AudioDeviceIOProc callback, void* clientData)
2323+: m_callback(callback), m_clientData(clientData)
2424+{
2525+2626+}
2727+2828+AudioHardwareStreamPA::~AudioHardwareStreamPA()
2929+{
3030+3131+}
···11+/*
22+This file is part of Darling.
33+44+Copyright (C) 2020 Lubos Dolezel
55+66+Darling is free software: you can redistribute it and/or modify
77+it under the terms of the GNU General Public License as published by
88+the Free Software Foundation, either version 3 of the License, or
99+(at your option) any later version.
1010+1111+Darling is distributed in the hope that it will be useful,
1212+but WITHOUT ANY WARRANTY; without even the implied warranty of
1313+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1414+GNU General Public License for more details.
1515+1616+You should have received a copy of the GNU General Public License
1717+along with Darling. If not, see <http://www.gnu.org/licenses/>.
1818+*/
1919+2020+#ifndef AUDIOHARDWARESTREAMPA_H
2121+#define AUDIOHARDWARESTREAMPA_H
2222+#include "../AudioHardwareStream.h"
2323+#include <pulse/pulseaudio.h>
2424+#include <CoreAudio/CoreAudioTypes.h>
2525+#include <CoreAudio/AudioHardware.h>
2626+2727+class AudioHardwareStreamPA : public AudioHardwareStream
2828+{
2929+public:
3030+ AudioHardwareStreamPA(AudioDeviceIOProc callback, void* clientData);
3131+ ~AudioHardwareStreamPA();
3232+protected:
3333+ AudioDeviceIOProc m_callback;
3434+ void* m_clientData;
3535+};
3636+3737+#endif /* AUDIOHARDWARESTREAMPA_H */
3838+
···11+/*
22+This file is part of Darling.
33+44+Copyright (C) 2020 Lubos Dolezel
55+66+Darling is free software: you can redistribute it and/or modify
77+it under the terms of the GNU General Public License as published by
88+the Free Software Foundation, either version 3 of the License, or
99+(at your option) any later version.
1010+1111+Darling is distributed in the hope that it will be useful,
1212+but WITHOUT ANY WARRANTY; without even the implied warranty of
1313+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1414+GNU General Public License for more details.
1515+1616+You should have received a copy of the GNU General Public License
1717+along with Darling. If not, see <http://www.gnu.org/licenses/>.
1818+*/
1919+2020+#include "AudioHardwareStreamPAOutput.h"
2121+#include "AudioHardwareImplPA.h"
2222+#include <iostream>
2323+2424+AudioHardwareStreamPAOutput::AudioHardwareStreamPAOutput(AudioDeviceIOProc callback, void* clientData)
2525+: AudioHardwareStreamPA(callback, clientData)
2626+{
2727+ AudioHardwareImplPA::getPAContext(^(pa_context* context) {
2828+ if (!context)
2929+ {
3030+ std::cerr << "Failed to get PulseAudio context\n";
3131+ return;
3232+ }
3333+3434+ pa_sample_spec spec;
3535+3636+ spec.rate = 44100;
3737+ spec.channels = 2;
3838+#if defined(__BIG_ENDIAN__)
3939+ spec.format = PA_SAMPLE_FLOAT32BE;
4040+#elif defined(__LITTLE_ENDIAN__)
4141+ spec.format = PA_SAMPLE_FLOAT32LE;
4242+#else
4343+# error Unknown endianess!
4444+#endif
4545+ if (!pa_sample_spec_valid(&spec))
4646+ {
4747+ std::cerr << "Failed to create a valid pa_sample_spec\n";
4848+ return;
4949+ }
5050+5151+ m_stream = pa_stream_new(context, "CoreAudio", &spec, nullptr);
5252+5353+ // pa_stream_set_state_callback(m_stream, paStreamStateCB, this);
5454+ pa_stream_set_write_callback(m_stream, paStreamWriteCB, this);
5555+5656+ start();
5757+ });
5858+}
5959+6060+AudioHardwareStreamPAOutput::~AudioHardwareStreamPAOutput()
6161+{
6262+ if (m_stream)
6363+ pa_stream_unref(m_stream);
6464+}
6565+6666+void AudioHardwareStreamPAOutput::paStreamWriteCB(pa_stream* s, size_t length, void* self)
6767+{
6868+ AudioHardwareStreamPAOutput* This = static_cast<AudioHardwareStreamPAOutput*>(self);
6969+7070+ // TODO: call the client for more data
7171+ // pa_stream_write(m_stream, ...);
7272+}
7373+7474+void AudioHardwareStreamPAOutput::start()
7575+{
7676+ pa_stream_connect_playback(m_stream, nullptr, nullptr, (pa_stream_flags_t) 0 /* PA_STREAM_START_CORKED */,
7777+ nullptr, nullptr);
7878+7979+ // pa_stream_cork(m_stream, false, [](pa_stream*, int, void*) {}, nullptr);
8080+}
8181+8282+void AudioHardwareStreamPAOutput::stop(void(^cbDone)())
8383+{
8484+ m_cbDone = Block_copy(cbDone);
8585+8686+ pa_stream_cork(m_stream, true, [](pa_stream*, int, void* self) {
8787+ AudioHardwareStreamPAOutput* This = static_cast<AudioHardwareStreamPAOutput*>(self);
8888+8989+ pa_stream_disconnect(This->m_stream);
9090+ This->m_cbDone();
9191+9292+ Block_release(This->m_cbDone);
9393+ }, this);
9494+}
···11+/*
22+This file is part of Darling.
33+44+Copyright (C) 2020 Lubos Dolezel
55+66+Darling is free software: you can redistribute it and/or modify
77+it under the terms of the GNU General Public License as published by
88+the Free Software Foundation, either version 3 of the License, or
99+(at your option) any later version.
1010+1111+Darling is distributed in the hope that it will be useful,
1212+but WITHOUT ANY WARRANTY; without even the implied warranty of
1313+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1414+GNU General Public License for more details.
1515+1616+You should have received a copy of the GNU General Public License
1717+along with Darling. If not, see <http://www.gnu.org/licenses/>.
1818+*/
1919+2020+#ifndef AUDIOHARDWARESTREAMPAOUTPUT_H
2121+#define AUDIOHARDWARESTREAMPAOUTPUT_H
2222+#include "AudioHardwareStreamPA.h"
2323+2424+class AudioHardwareStreamPAOutput : public AudioHardwareStreamPA
2525+{
2626+public:
2727+ AudioHardwareStreamPAOutput(AudioDeviceIOProc callback, void* clientData);
2828+ ~AudioHardwareStreamPAOutput();
2929+3030+ void stop(void(^cbDone)()) override;
3131+private:
3232+ void start();
3333+ static void paStreamWriteCB(pa_stream* s, size_t length, void* self);
3434+private:
3535+ pa_stream* m_stream;
3636+ void(^m_cbDone)();
3737+};
3838+3939+#endif /* AUDIOHARDWARESTREAMPA_H */
4040+
···11+/*
22+This file is part of Darling.
33+44+Copyright (C) 2020 Lubos Dolezel
55+66+Darling is free software: you can redistribute it and/or modify
77+it under the terms of the GNU General Public License as published by
88+the Free Software Foundation, either version 3 of the License, or
99+(at your option) any later version.
1010+1111+Darling is distributed in the hope that it will be useful,
1212+but WITHOUT ANY WARRANTY; without even the implied warranty of
1313+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1414+GNU General Public License for more details.
1515+1616+You should have received a copy of the GNU General Public License
1717+along with Darling. If not, see <http://www.gnu.org/licenses/>.
1818+*/
1919+2020+#ifndef PAGCDMAINLOOP_H
2121+#define PAGCDMAINLOOP_H
2222+#include <dispatch/dispatch.h>
2323+#include <pulse/pulseaudio.h>
2424+2525+class PADispatchMainLoop
2626+{
2727+private:
2828+ PADispatchMainLoop();
2929+public:
3030+ static PADispatchMainLoop* instance();
3131+ static pa_mainloop_api* getAPI();
3232+private:
3333+ static pa_io_event* io_new(pa_mainloop_api *a, int fd, pa_io_event_flags_t events, pa_io_event_cb_t cb, void *userdata);
3434+ static void io_enable(pa_io_event *e, pa_io_event_flags_t events);
3535+ static void io_free(pa_io_event *e);
3636+ static void io_set_destroy(pa_io_event *e, pa_io_event_destroy_cb_t cb);
3737+3838+ static pa_time_event *time_new(pa_mainloop_api *a, const struct timeval *tv, pa_time_event_cb_t cb, void *userdata);
3939+ static void time_restart(pa_time_event *e, const struct timeval *tv);
4040+ static void time_set_destroy(pa_time_event *e, pa_time_event_destroy_cb_t cb);
4141+ static void time_free(pa_time_event *e);
4242+4343+ static pa_defer_event *defer_new(pa_mainloop_api *a, pa_defer_event_cb_t cb, void *userdata);
4444+ static void defer_set_destroy(pa_defer_event *e, pa_defer_event_destroy_cb_t cb);
4545+ static void defer_enable(pa_defer_event *e, int b);
4646+ static void defer_free(pa_defer_event *e);
4747+ static void defer_event_fire(void* context);
4848+private:
4949+ dispatch_queue_t m_queue;
5050+};
5151+5252+#endif