aboutsummaryrefslogtreecommitdiffstats
path: root/Alc/backends
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2018-12-27 23:37:24 -0800
committerChris Robinson <[email protected]>2018-12-27 23:37:24 -0800
commitaff58265cb458b2ac2c42fef96383e9751d094d1 (patch)
tree04b66022abdad34fe8bbad8de222206b09dce176 /Alc/backends
parent28308226e76f8378dc74db12b085d50bb97b11cb (diff)
Make more methods into member functions
Diffstat (limited to 'Alc/backends')
-rw-r--r--Alc/backends/oss.cpp104
-rw-r--r--Alc/backends/portaudio.cpp88
-rw-r--r--Alc/backends/pulseaudio.cpp475
3 files changed, 316 insertions, 351 deletions
diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp
index c35c7247..54d7e0af 100644
--- a/Alc/backends/oss.cpp
+++ b/Alc/backends/oss.cpp
@@ -242,18 +242,19 @@ int log2i(ALCuint x)
struct ALCplaybackOSS final : public ALCbackend {
+ ALCplaybackOSS(ALCdevice *device) noexcept : ALCbackend{device} { }
+ ~ALCplaybackOSS() override;
+
+ int mixerProc();
+
int mFd{-1};
al::vector<ALubyte> mMixData;
std::atomic<ALenum> mKillNow{AL_TRUE};
std::thread mThread;
-
- ALCplaybackOSS(ALCdevice *device) noexcept : ALCbackend{device} { }
};
-int ALCplaybackOSS_mixerProc(ALCplaybackOSS *self);
-
void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device);
void ALCplaybackOSS_Destruct(ALCplaybackOSS *self);
ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name);
@@ -276,41 +277,40 @@ void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device)
}
void ALCplaybackOSS_Destruct(ALCplaybackOSS *self)
-{
- if(self->mFd != -1)
- close(self->mFd);
- self->mFd = -1;
+{ self->~ALCplaybackOSS(); }
- self->~ALCplaybackOSS();
+ALCplaybackOSS::~ALCplaybackOSS()
+{
+ if(mFd != -1)
+ close(mFd);
+ mFd = -1;
}
-int ALCplaybackOSS_mixerProc(ALCplaybackOSS *self)
+int ALCplaybackOSS::mixerProc()
{
- ALCdevice *device{self->mDevice};
-
SetRTPriority();
althrd_setname(MIXER_THREAD_NAME);
- const int frame_size{device->frameSizeFromFmt()};
+ const int frame_size{mDevice->frameSizeFromFmt()};
- ALCplaybackOSS_lock(self);
- while(!self->mKillNow.load(std::memory_order_acquire) &&
- device->Connected.load(std::memory_order_acquire))
+ ALCplaybackOSS_lock(this);
+ while(!mKillNow.load(std::memory_order_acquire) &&
+ mDevice->Connected.load(std::memory_order_acquire))
{
pollfd pollitem{};
- pollitem.fd = self->mFd;
+ pollitem.fd = mFd;
pollitem.events = POLLOUT;
- ALCplaybackOSS_unlock(self);
+ ALCplaybackOSS_unlock(this);
int pret{poll(&pollitem, 1, 1000)};
- ALCplaybackOSS_lock(self);
+ ALCplaybackOSS_lock(this);
if(pret < 0)
{
if(errno == EINTR || errno == EAGAIN)
continue;
ERR("poll failed: %s\n", strerror(errno));
- aluHandleDisconnect(device, "Failed waiting for playback buffer: %s", strerror(errno));
+ aluHandleDisconnect(mDevice, "Failed waiting for playback buffer: %s", strerror(errno));
break;
}
else if(pret == 0)
@@ -319,18 +319,18 @@ int ALCplaybackOSS_mixerProc(ALCplaybackOSS *self)
continue;
}
- ALubyte *write_ptr{self->mMixData.data()};
- size_t to_write{self->mMixData.size()};
- aluMixData(device, write_ptr, to_write/frame_size);
- while(to_write > 0 && !self->mKillNow.load())
+ ALubyte *write_ptr{mMixData.data()};
+ size_t to_write{mMixData.size()};
+ aluMixData(mDevice, write_ptr, to_write/frame_size);
+ while(to_write > 0 && !mKillNow.load(std::memory_order_acquire))
{
- ssize_t wrote{write(self->mFd, write_ptr, to_write)};
+ ssize_t wrote{write(mFd, write_ptr, to_write)};
if(wrote < 0)
{
if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
continue;
ERR("write failed: %s\n", strerror(errno));
- aluHandleDisconnect(device, "Failed writing playback samples: %s",
+ aluHandleDisconnect(mDevice, "Failed writing playback samples: %s",
strerror(errno));
break;
}
@@ -339,7 +339,7 @@ int ALCplaybackOSS_mixerProc(ALCplaybackOSS *self)
write_ptr += wrote;
}
}
- ALCplaybackOSS_unlock(self);
+ ALCplaybackOSS_unlock(this);
return 0;
}
@@ -467,7 +467,7 @@ ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self)
self->mMixData.resize(device->UpdateSize * device->frameSizeFromFmt());
self->mKillNow.store(AL_FALSE);
- self->mThread = std::thread(ALCplaybackOSS_mixerProc, self);
+ self->mThread = std::thread{std::mem_fn(&ALCplaybackOSS::mixerProc), self};
return ALC_TRUE;
}
catch(std::exception& e) {
@@ -492,18 +492,19 @@ void ALCplaybackOSS_stop(ALCplaybackOSS *self)
struct ALCcaptureOSS final : public ALCbackend {
+ ALCcaptureOSS(ALCdevice *device) noexcept : ALCbackend{device} { }
+ ~ALCcaptureOSS() override;
+
+ int recordProc();
+
int mFd{-1};
RingBufferPtr mRing{nullptr};
std::atomic<ALenum> mKillNow{AL_TRUE};
std::thread mThread;
-
- ALCcaptureOSS(ALCdevice *device) noexcept : ALCbackend{device} { }
};
-int ALCcaptureOSS_recordProc(ALCcaptureOSS *self);
-
void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device);
void ALCcaptureOSS_Destruct(ALCcaptureOSS *self);
ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name);
@@ -526,28 +527,26 @@ void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device)
}
void ALCcaptureOSS_Destruct(ALCcaptureOSS *self)
-{
- if(self->mFd != -1)
- close(self->mFd);
- self->mFd = -1;
+{ self->~ALCcaptureOSS(); }
- self->~ALCcaptureOSS();
+ALCcaptureOSS::~ALCcaptureOSS()
+{
+ if(mFd != -1)
+ close(mFd);
+ mFd = -1;
}
-int ALCcaptureOSS_recordProc(ALCcaptureOSS *self)
+int ALCcaptureOSS::recordProc()
{
- ALCdevice *device{self->mDevice};
- RingBuffer *ring{self->mRing.get()};
-
SetRTPriority();
althrd_setname(RECORD_THREAD_NAME);
- const int frame_size{device->frameSizeFromFmt()};
- while(!self->mKillNow.load())
+ const int frame_size{mDevice->frameSizeFromFmt()};
+ while(!mKillNow.load(std::memory_order_acquire))
{
pollfd pollitem{};
- pollitem.fd = self->mFd;
+ pollitem.fd = mFd;
pollitem.events = POLLIN;
int sret{poll(&pollitem, 1, 1000)};
@@ -556,7 +555,7 @@ int ALCcaptureOSS_recordProc(ALCcaptureOSS *self)
if(errno == EINTR || errno == EAGAIN)
continue;
ERR("poll failed: %s\n", strerror(errno));
- aluHandleDisconnect(device, "Failed to check capture samples: %s", strerror(errno));
+ aluHandleDisconnect(mDevice, "Failed to check capture samples: %s", strerror(errno));
break;
}
else if(sret == 0)
@@ -565,19 +564,20 @@ int ALCcaptureOSS_recordProc(ALCcaptureOSS *self)
continue;
}
- auto vec = ring->getWriteVector();
+ auto vec = mRing->getWriteVector();
if(vec.first.len > 0)
{
- ssize_t amt{read(self->mFd, vec.first.buf, vec.first.len*frame_size)};
+ ssize_t amt{read(mFd, vec.first.buf, vec.first.len*frame_size)};
if(amt < 0)
{
ERR("read failed: %s\n", strerror(errno));
- ALCcaptureOSS_lock(self);
- aluHandleDisconnect(device, "Failed reading capture samples: %s", strerror(errno));
- ALCcaptureOSS_unlock(self);
+ ALCcaptureOSS_lock(this);
+ aluHandleDisconnect(mDevice, "Failed reading capture samples: %s",
+ strerror(errno));
+ ALCcaptureOSS_unlock(this);
break;
}
- ring->writeAdvance(amt/frame_size);
+ mRing->writeAdvance(amt/frame_size);
}
}
@@ -700,7 +700,7 @@ ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self)
{
try {
self->mKillNow.store(AL_FALSE);
- self->mThread = std::thread(ALCcaptureOSS_recordProc, self);
+ self->mThread = std::thread{std::mem_fn(&ALCcaptureOSS::recordProc), self};
return ALC_TRUE;
}
catch(std::exception& e) {
diff --git a/Alc/backends/portaudio.cpp b/Alc/backends/portaudio.cpp
index 10c9079b..44ffd9bd 100644
--- a/Alc/backends/portaudio.cpp
+++ b/Alc/backends/portaudio.cpp
@@ -131,17 +131,20 @@ bool pa_load(void)
struct ALCportPlayback final : public ALCbackend {
+ ALCportPlayback(ALCdevice *device) noexcept : ALCbackend{device} { }
+ ~ALCportPlayback() override;
+
+ static int writeCallbackC(const void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
+ const PaStreamCallbackFlags statusFlags, void *userData);
+ int writeCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer,
+ const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags);
+
PaStream *mStream{nullptr};
PaStreamParameters mParams{};
ALuint mUpdateSize{0u};
-
- ALCportPlayback(ALCdevice *device) noexcept : ALCbackend{device} { }
};
-int ALCportPlayback_WriteCallback(const void *inputBuffer, void *outputBuffer,
- unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
- const PaStreamCallbackFlags statusFlags, void *userData);
-
void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device);
void ALCportPlayback_Destruct(ALCportPlayback *self);
ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name);
@@ -165,25 +168,32 @@ void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device)
}
void ALCportPlayback_Destruct(ALCportPlayback *self)
+{ self->~ALCportPlayback(); }
+
+ALCportPlayback::~ALCportPlayback()
{
- PaError err = self->mStream ? Pa_CloseStream(self->mStream) : paNoError;
+ PaError err{mStream ? Pa_CloseStream(mStream) : paNoError};
if(err != paNoError)
ERR("Error closing stream: %s\n", Pa_GetErrorText(err));
- self->mStream = nullptr;
-
- self->~ALCportPlayback();
+ mStream = nullptr;
}
-int ALCportPlayback_WriteCallback(const void *UNUSED(inputBuffer), void *outputBuffer,
- unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo),
- const PaStreamCallbackFlags UNUSED(statusFlags), void *userData)
+int ALCportPlayback::writeCallbackC(const void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
+ const PaStreamCallbackFlags statusFlags, void *userData)
{
- auto self = static_cast<ALCportPlayback*>(userData);
+ return static_cast<ALCportPlayback*>(userData)->writeCallback(inputBuffer, outputBuffer,
+ framesPerBuffer, timeInfo, statusFlags);
+}
- ALCportPlayback_lock(self);
- aluMixData(self->mDevice, outputBuffer, framesPerBuffer);
- ALCportPlayback_unlock(self);
+int ALCportPlayback::writeCallback(const void* UNUSED(inputBuffer), void *outputBuffer,
+ unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* UNUSED(timeInfo),
+ const PaStreamCallbackFlags UNUSED(statusFlags))
+{
+ ALCportPlayback_lock(this);
+ aluMixData(mDevice, outputBuffer, framesPerBuffer);
+ ALCportPlayback_unlock(this);
return 0;
}
@@ -236,7 +246,7 @@ ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name)
retry_open:
err = Pa_OpenStream(&self->mStream, nullptr, &self->mParams,
device->Frequency, device->UpdateSize, paNoFlag,
- ALCportPlayback_WriteCallback, self
+ &ALCportPlayback::writeCallbackC, self
);
if(err != paNoError)
{
@@ -312,18 +322,21 @@ void ALCportPlayback_stop(ALCportPlayback *self)
struct ALCportCapture final : public ALCbackend {
+ ALCportCapture(ALCdevice *device) noexcept : ALCbackend{device} { }
+ ~ALCportCapture() override;
+
+ static int readCallbackC(const void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
+ const PaStreamCallbackFlags statusFlags, void *userData);
+ int readCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer,
+ const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags);
+
PaStream *mStream{nullptr};
PaStreamParameters mParams;
RingBufferPtr mRing{nullptr};
-
- ALCportCapture(ALCdevice *device) noexcept : ALCbackend{device} { }
};
-int ALCportCapture_ReadCallback(const void *inputBuffer, void *outputBuffer,
- unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
- const PaStreamCallbackFlags statusFlags, void *userData);
-
void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device);
void ALCportCapture_Destruct(ALCportCapture *self);
ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name);
@@ -347,23 +360,30 @@ void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device)
}
void ALCportCapture_Destruct(ALCportCapture *self)
+{ self->~ALCportCapture(); }
+
+ALCportCapture::~ALCportCapture()
{
- PaError err = self->mStream ? Pa_CloseStream(self->mStream) : paNoError;
+ PaError err{mStream ? Pa_CloseStream(mStream) : paNoError};
if(err != paNoError)
ERR("Error closing stream: %s\n", Pa_GetErrorText(err));
- self->mStream = nullptr;
-
- self->~ALCportCapture();
+ mStream = nullptr;
}
-int ALCportCapture_ReadCallback(const void *inputBuffer, void *UNUSED(outputBuffer),
+int ALCportCapture::readCallbackC(const void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
+ const PaStreamCallbackFlags statusFlags, void* userData)
+{
+ return static_cast<ALCportCapture*>(userData)->readCallback(inputBuffer, outputBuffer,
+ framesPerBuffer, timeInfo, statusFlags);
+}
+
+int ALCportCapture::readCallback(const void *inputBuffer, void *UNUSED(outputBuffer),
unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo),
- const PaStreamCallbackFlags UNUSED(statusFlags), void *userData)
+ const PaStreamCallbackFlags UNUSED(statusFlags))
{
- auto self = static_cast<ALCportCapture*>(userData);
- RingBuffer *ring{self->mRing.get()};
- ring->write(inputBuffer, framesPerBuffer);
+ mRing->write(inputBuffer, framesPerBuffer);
return 0;
}
@@ -419,7 +439,7 @@ ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name)
err = Pa_OpenStream(&self->mStream, &self->mParams, nullptr,
device->Frequency, paFramesPerBufferUnspecified, paNoFlag,
- ALCportCapture_ReadCallback, self
+ &ALCportCapture::readCallbackC, self
);
if(err != paNoError)
{
diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp
index 6e5e07b8..3130df19 100644
--- a/Alc/backends/pulseaudio.cpp
+++ b/Alc/backends/pulseaudio.cpp
@@ -522,74 +522,132 @@ al::vector<DevMap> PlaybackDevices;
al::vector<DevMap> CaptureDevices;
-struct PulsePlayback final : public ALCbackend {
- std::string mDeviceName;
+pa_stream *pulse_connect_stream(const char *device_name, pa_threaded_mainloop *loop,
+ pa_context *context, pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec,
+ pa_channel_map *chanmap, ALCbackend_Type type)
+{
+ pa_stream *stream{pa_stream_new_with_proplist(context,
+ (type==ALCbackend_Playback) ? "Playback Stream" : "Capture Stream", spec, chanmap,
+ prop_filter)};
+ if(!stream)
+ {
+ ERR("pa_stream_new_with_proplist() failed: %s\n", pa_strerror(pa_context_errno(context)));
+ return nullptr;
+ }
- pa_buffer_attr mAttr;
- pa_sample_spec mSpec;
+ pa_stream_set_state_callback(stream, stream_state_callback, loop);
- pa_threaded_mainloop *mLoop{nullptr};
+ int err{(type==ALCbackend_Playback) ?
+ pa_stream_connect_playback(stream, device_name, attr, flags, nullptr, nullptr) :
+ pa_stream_connect_record(stream, device_name, attr, flags)};
+ if(err < 0)
+ {
+ ERR("Stream did not connect: %s\n", pa_strerror(err));
+ pa_stream_unref(stream);
+ return nullptr;
+ }
- pa_stream *mStream{nullptr};
- pa_context *mContext{nullptr};
+ pa_stream_state_t state;
+ while((state=pa_stream_get_state(stream)) != PA_STREAM_READY)
+ {
+ if(!PA_STREAM_IS_GOOD(state))
+ {
+ ERR("Stream did not get ready: %s\n", pa_strerror(pa_context_errno(context)));
+ pa_stream_unref(stream);
+ return nullptr;
+ }
- ALuint mBufferSize{0u};
- ALuint mFrameSize{0u};
+ pa_threaded_mainloop_wait(loop);
+ }
+ pa_stream_set_state_callback(stream, nullptr, nullptr);
- PulsePlayback(ALCdevice *device) noexcept : ALCbackend{device} { }
-};
+ return stream;
+}
-void PulsePlayback_deviceCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata);
-void PulsePlayback_probeDevices(void);
-void PulsePlayback_bufferAttrCallback(pa_stream *stream, void *pdata);
-void PulsePlayback_contextStateCallback(pa_context *context, void *pdata);
-void PulsePlayback_streamStateCallback(pa_stream *stream, void *pdata);
-void PulsePlayback_streamWriteCallback(pa_stream *p, size_t nbytes, void *userdata);
-void PulsePlayback_sinkInfoCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata);
-void PulsePlayback_sinkNameCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata);
-void PulsePlayback_streamMovedCallback(pa_stream *stream, void *pdata);
-pa_stream *PulsePlayback_connectStream(const char *device_name, pa_threaded_mainloop *loop,
- pa_context *context, pa_stream_flags_t flags,
- pa_buffer_attr *attr, pa_sample_spec *spec,
- pa_channel_map *chanmap);
+void device_sink_callback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata)
+{
+ auto loop = static_cast<pa_threaded_mainloop*>(pdata);
-void PulsePlayback_Construct(PulsePlayback *self, ALCdevice *device);
-void PulsePlayback_Destruct(PulsePlayback *self);
-ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name);
-ALCboolean PulsePlayback_reset(PulsePlayback *self);
-ALCboolean PulsePlayback_start(PulsePlayback *self);
-void PulsePlayback_stop(PulsePlayback *self);
-DECLARE_FORWARD2(PulsePlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint)
-DECLARE_FORWARD(PulsePlayback, ALCbackend, ALCuint, availableSamples)
-ClockLatency PulsePlayback_getClockLatency(PulsePlayback *self);
-void PulsePlayback_lock(PulsePlayback *self);
-void PulsePlayback_unlock(PulsePlayback *self);
-DECLARE_DEFAULT_ALLOCATORS(PulsePlayback)
+ if(eol)
+ {
+ pa_threaded_mainloop_signal(loop, 0);
+ return;
+ }
-DEFINE_ALCBACKEND_VTABLE(PulsePlayback);
+ /* Skip this device is if it's already in the list. */
+ if(std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(),
+ [info](const DevMap &entry) -> bool
+ { return entry.device_name == info->name; }
+ ) != PlaybackDevices.cend())
+ return;
+ /* Make sure the display name (description) is unique. Append a number
+ * counter as needed.
+ */
+ int count{1};
+ std::string newname{info->description};
+ while(checkName(PlaybackDevices, newname))
+ {
+ newname = info->description;
+ newname += " #";
+ newname += std::to_string(++count);
+ }
+ PlaybackDevices.emplace_back(std::move(newname), info->name);
+ DevMap &newentry = PlaybackDevices.back();
-void PulsePlayback_Construct(PulsePlayback *self, ALCdevice *device)
-{
- new (self) PulsePlayback{device};
- SET_VTABLE2(PulsePlayback, ALCbackend, self);
+ TRACE("Got device \"%s\", \"%s\"\n", newentry.name.c_str(), newentry.device_name.c_str());
}
-void PulsePlayback_Destruct(PulsePlayback *self)
+void probePlaybackDevices(void)
{
- if(self->mLoop)
+ PlaybackDevices.clear();
+
+ pa_threaded_mainloop *loop{pa_threaded_mainloop_new()};
+ if(loop && pa_threaded_mainloop_start(loop) >= 0)
{
- pulse_close(self->mLoop, self->mContext, self->mStream);
- self->mLoop = nullptr;
- self->mContext = nullptr;
- self->mStream = nullptr;
+ unique_palock palock{loop};
+
+ pa_context *context{connect_context(loop, AL_FALSE)};
+ if(context)
+ {
+ pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE |
+ PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE};
+
+ pa_sample_spec spec;
+ spec.format = PA_SAMPLE_S16NE;
+ spec.rate = 44100;
+ spec.channels = 2;
+
+ pa_stream *stream{pulse_connect_stream(nullptr, loop, context, flags, nullptr, &spec,
+ nullptr, ALCbackend_Playback)};
+ if(stream)
+ {
+ pa_operation *op{pa_context_get_sink_info_by_name(context,
+ pa_stream_get_device_name(stream), device_sink_callback, loop)};
+ wait_for_operation(op, loop);
+
+ pa_stream_disconnect(stream);
+ pa_stream_unref(stream);
+ stream = nullptr;
+ }
+
+ pa_operation *op{pa_context_get_sink_info_list(context,
+ device_sink_callback, loop)};
+ wait_for_operation(op, loop);
+
+ pa_context_disconnect(context);
+ pa_context_unref(context);
+ }
+ palock = unique_palock{};
+ pa_threaded_mainloop_stop(loop);
}
- self->~PulsePlayback();
+ if(loop)
+ pa_threaded_mainloop_free(loop);
}
-void PulsePlayback_deviceCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata)
+void device_source_callback(pa_context *UNUSED(context), const pa_source_info *info, int eol, void *pdata)
{
auto loop = static_cast<pa_threaded_mainloop*>(pdata);
@@ -600,10 +658,10 @@ void PulsePlayback_deviceCallback(pa_context *UNUSED(context), const pa_sink_inf
}
/* Skip this device is if it's already in the list. */
- if(std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(),
+ if(std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(),
[info](const DevMap &entry) -> bool
{ return entry.device_name == info->name; }
- ) != PlaybackDevices.cend())
+ ) != CaptureDevices.cend())
return;
/* Make sure the display name (description) is unique. Append a number
@@ -611,21 +669,21 @@ void PulsePlayback_deviceCallback(pa_context *UNUSED(context), const pa_sink_inf
*/
int count{1};
std::string newname{info->description};
- while(checkName(PlaybackDevices, newname))
+ while(checkName(CaptureDevices, newname))
{
newname = info->description;
newname += " #";
newname += std::to_string(++count);
}
- PlaybackDevices.emplace_back(std::move(newname), info->name);
- DevMap &newentry = PlaybackDevices.back();
+ CaptureDevices.emplace_back(std::move(newname), info->name);
+ DevMap &newentry = CaptureDevices.back();
TRACE("Got device \"%s\", \"%s\"\n", newentry.name.c_str(), newentry.device_name.c_str());
}
-void PulsePlayback_probeDevices(void)
+void probeCaptureDevices(void)
{
- PlaybackDevices.clear();
+ CaptureDevices.clear();
pa_threaded_mainloop *loop{pa_threaded_mainloop_new()};
if(loop && pa_threaded_mainloop_start(loop) >= 0)
@@ -641,16 +699,14 @@ void PulsePlayback_probeDevices(void)
pa_sample_spec spec;
spec.format = PA_SAMPLE_S16NE;
spec.rate = 44100;
- spec.channels = 2;
+ spec.channels = 1;
- pa_stream *stream{PulsePlayback_connectStream(nullptr,
- loop, context, flags, nullptr, &spec, nullptr
- )};
+ pa_stream *stream{pulse_connect_stream(nullptr, loop, context, flags, nullptr, &spec,
+ nullptr, ALCbackend_Capture)};
if(stream)
{
- pa_operation *op{pa_context_get_sink_info_by_name(context,
- pa_stream_get_device_name(stream), PulsePlayback_deviceCallback, loop
- )};
+ pa_operation *op{pa_context_get_source_info_by_name(context,
+ pa_stream_get_device_name(stream), device_source_callback, loop)};
wait_for_operation(op, loop);
pa_stream_disconnect(stream);
@@ -658,15 +714,14 @@ void PulsePlayback_probeDevices(void)
stream = nullptr;
}
- pa_operation *op{pa_context_get_sink_info_list(context,
- PulsePlayback_deviceCallback, loop
- )};
+ pa_operation *op{pa_context_get_source_info_list(context,
+ device_source_callback, loop)};
wait_for_operation(op, loop);
pa_context_disconnect(context);
pa_context_unref(context);
}
- palock = unique_palock{};
+ palock.unlock();
pa_threaded_mainloop_stop(loop);
}
if(loop)
@@ -674,6 +729,69 @@ void PulsePlayback_probeDevices(void)
}
+struct PulsePlayback final : public ALCbackend {
+ PulsePlayback(ALCdevice *device) noexcept : ALCbackend{device} { }
+ ~PulsePlayback() override;
+
+ std::string mDeviceName;
+
+ pa_buffer_attr mAttr;
+ pa_sample_spec mSpec;
+
+ pa_threaded_mainloop *mLoop{nullptr};
+
+ pa_stream *mStream{nullptr};
+ pa_context *mContext{nullptr};
+
+ ALuint mBufferSize{0u};
+ ALuint mFrameSize{0u};
+};
+
+void PulsePlayback_bufferAttrCallback(pa_stream *stream, void *pdata);
+void PulsePlayback_contextStateCallback(pa_context *context, void *pdata);
+void PulsePlayback_streamStateCallback(pa_stream *stream, void *pdata);
+void PulsePlayback_streamWriteCallback(pa_stream *p, size_t nbytes, void *userdata);
+void PulsePlayback_sinkInfoCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata);
+void PulsePlayback_sinkNameCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata);
+void PulsePlayback_streamMovedCallback(pa_stream *stream, void *pdata);
+
+void PulsePlayback_Construct(PulsePlayback *self, ALCdevice *device);
+void PulsePlayback_Destruct(PulsePlayback *self);
+ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name);
+ALCboolean PulsePlayback_reset(PulsePlayback *self);
+ALCboolean PulsePlayback_start(PulsePlayback *self);
+void PulsePlayback_stop(PulsePlayback *self);
+DECLARE_FORWARD2(PulsePlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint)
+DECLARE_FORWARD(PulsePlayback, ALCbackend, ALCuint, availableSamples)
+ClockLatency PulsePlayback_getClockLatency(PulsePlayback *self);
+void PulsePlayback_lock(PulsePlayback *self);
+void PulsePlayback_unlock(PulsePlayback *self);
+DECLARE_DEFAULT_ALLOCATORS(PulsePlayback)
+
+DEFINE_ALCBACKEND_VTABLE(PulsePlayback);
+
+
+void PulsePlayback_Construct(PulsePlayback *self, ALCdevice *device)
+{
+ new (self) PulsePlayback{device};
+ SET_VTABLE2(PulsePlayback, ALCbackend, self);
+}
+
+void PulsePlayback_Destruct(PulsePlayback *self)
+{ self->~PulsePlayback(); }
+
+PulsePlayback::~PulsePlayback()
+{
+ if(!mLoop)
+ return;
+
+ pulse_close(mLoop, mContext, mStream);
+ mLoop = nullptr;
+ mContext = nullptr;
+ mStream = nullptr;
+}
+
+
void PulsePlayback_bufferAttrCallback(pa_stream *stream, void *pdata)
{
auto self = static_cast<PulsePlayback*>(pdata);
@@ -826,53 +944,6 @@ void PulsePlayback_streamMovedCallback(pa_stream *stream, void *pdata)
}
-pa_stream *PulsePlayback_connectStream(const char *device_name,
- pa_threaded_mainloop *loop, pa_context *context,
- pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec,
- pa_channel_map *chanmap)
-{
- if(!device_name)
- {
- device_name = getenv("ALSOFT_PULSE_DEFAULT");
- if(device_name && !device_name[0])
- device_name = nullptr;
- }
-
- pa_stream *stream{pa_stream_new_with_proplist(context,
- "Playback Stream", spec, chanmap, prop_filter)};
- if(!stream)
- {
- ERR("pa_stream_new_with_proplist() failed: %s\n", pa_strerror(pa_context_errno(context)));
- return nullptr;
- }
-
- pa_stream_set_state_callback(stream, stream_state_callback, loop);
-
- if(pa_stream_connect_playback(stream, device_name, attr, flags, nullptr, nullptr) < 0)
- {
- ERR("Stream did not connect: %s\n", pa_strerror(pa_context_errno(context)));
- pa_stream_unref(stream);
- return nullptr;
- }
-
- pa_stream_state_t state;
- while((state=pa_stream_get_state(stream)) != PA_STREAM_READY)
- {
- if(!PA_STREAM_IS_GOOD(state))
- {
- ERR("Stream did not get ready: %s\n", pa_strerror(pa_context_errno(context)));
- pa_stream_unref(stream);
- return nullptr;
- }
-
- pa_threaded_mainloop_wait(loop);
- }
- pa_stream_set_state_callback(stream, nullptr, nullptr);
-
- return stream;
-}
-
-
ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name)
{
const char *pulse_name{nullptr};
@@ -881,7 +952,7 @@ ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name)
if(name)
{
if(PlaybackDevices.empty())
- PulsePlayback_probeDevices();
+ probePlaybackDevices();
auto iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(),
[name](const DevMap &entry) -> bool
@@ -909,8 +980,13 @@ ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name)
spec.channels = 2;
TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)");
- self->mStream = PulsePlayback_connectStream(pulse_name, self->mLoop, self->mContext, flags,
- nullptr, &spec, nullptr);
+ if(!pulse_name)
+ {
+ pulse_name = getenv("ALSOFT_PULSE_DEFAULT");
+ if(pulse_name && !pulse_name[0]) pulse_name = nullptr;
+ }
+ self->mStream = pulse_connect_stream(pulse_name, self->mLoop, self->mContext, flags, nullptr,
+ &spec, nullptr, ALCbackend_Playback);
if(!self->mStream)
{
palock = unique_palock{};
@@ -1044,8 +1120,8 @@ ALCboolean PulsePlayback_reset(PulsePlayback *self)
self->mAttr.minreq = period_size;
self->mAttr.fragsize = -1;
- self->mStream = PulsePlayback_connectStream(self->mDeviceName.c_str(), self->mLoop,
- self->mContext, flags, &self->mAttr, &self->mSpec, &chanmap);
+ self->mStream = pulse_connect_stream(self->mDeviceName.c_str(), self->mLoop, self->mContext,
+ flags, &self->mAttr, &self->mSpec, &chanmap, ALCbackend_Playback);
if(!self->mStream) return ALC_FALSE;
pa_stream_set_state_callback(self->mStream, PulsePlayback_streamStateCallback, self);
@@ -1167,6 +1243,9 @@ void PulsePlayback_unlock(PulsePlayback *self)
struct PulseCapture final : public ALCbackend {
+ PulseCapture(ALCdevice *device) noexcept : ALCbackend{device} { }
+ ~PulseCapture() override;
+
std::string mDeviceName;
const void *mCapStore{nullptr};
@@ -1182,21 +1261,12 @@ struct PulseCapture final : public ALCbackend {
pa_stream *mStream{nullptr};
pa_context *mContext{nullptr};
-
- PulseCapture(ALCdevice *device) noexcept : ALCbackend{device} { }
};
-void PulseCapture_deviceCallback(pa_context *context, const pa_source_info *info, int eol, void *pdata);
-void PulseCapture_probeDevices(void);
-
void PulseCapture_contextStateCallback(pa_context *context, void *pdata);
void PulseCapture_streamStateCallback(pa_stream *stream, void *pdata);
void PulseCapture_sourceNameCallback(pa_context *context, const pa_source_info *info, int eol, void *pdata);
void PulseCapture_streamMovedCallback(pa_stream *stream, void *pdata);
-pa_stream *PulseCapture_connectStream(const char *device_name,
- pa_threaded_mainloop *loop, pa_context *context,
- pa_stream_flags_t flags, pa_buffer_attr *attr,
- pa_sample_spec *spec, pa_channel_map *chanmap);
void PulseCapture_Construct(PulseCapture *self, ALCdevice *device);
void PulseCapture_Destruct(PulseCapture *self);
@@ -1221,100 +1291,16 @@ void PulseCapture_Construct(PulseCapture *self, ALCdevice *device)
}
void PulseCapture_Destruct(PulseCapture *self)
-{
- if(self->mLoop)
- {
- pulse_close(self->mLoop, self->mContext, self->mStream);
- self->mLoop = nullptr;
- self->mContext = nullptr;
- self->mStream = nullptr;
- }
- self->~PulseCapture();
-}
-
+{ self->~PulseCapture(); }
-void PulseCapture_deviceCallback(pa_context *UNUSED(context), const pa_source_info *info, int eol, void *pdata)
+PulseCapture::~PulseCapture()
{
- auto loop = static_cast<pa_threaded_mainloop*>(pdata);
-
- if(eol)
- {
- pa_threaded_mainloop_signal(loop, 0);
+ if(!mLoop)
return;
- }
-
- /* Skip this device is if it's already in the list. */
- if(std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(),
- [info](const DevMap &entry) -> bool
- { return entry.device_name == info->name; }
- ) != CaptureDevices.cend())
- return;
-
- /* Make sure the display name (description) is unique. Append a number
- * counter as needed.
- */
- int count{1};
- std::string newname{info->description};
- while(checkName(CaptureDevices, newname))
- {
- newname = info->description;
- newname += " #";
- newname += std::to_string(++count);
- }
- CaptureDevices.emplace_back(std::move(newname), info->name);
- DevMap &newentry = CaptureDevices.back();
-
- TRACE("Got device \"%s\", \"%s\"\n", newentry.name.c_str(), newentry.device_name.c_str());
-}
-
-void PulseCapture_probeDevices(void)
-{
- CaptureDevices.clear();
-
- pa_threaded_mainloop *loop{pa_threaded_mainloop_new()};
- if(loop && pa_threaded_mainloop_start(loop) >= 0)
- {
- unique_palock palock{loop};
-
- pa_context *context{connect_context(loop, AL_FALSE)};
- if(context)
- {
- pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE |
- PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE};
-
- pa_sample_spec spec;
- spec.format = PA_SAMPLE_S16NE;
- spec.rate = 44100;
- spec.channels = 1;
-
- pa_stream *stream{PulseCapture_connectStream(nullptr,
- loop, context, flags, nullptr, &spec, nullptr
- )};
- if(stream)
- {
- pa_operation *op{pa_context_get_source_info_by_name(context,
- pa_stream_get_device_name(stream), PulseCapture_deviceCallback, loop
- )};
- wait_for_operation(op, loop);
-
- pa_stream_disconnect(stream);
- pa_stream_unref(stream);
- stream = nullptr;
- }
-
- pa_operation *op{pa_context_get_source_info_list(context,
- PulseCapture_deviceCallback, loop
- )};
- wait_for_operation(op, loop);
-
- pa_context_disconnect(context);
- pa_context_unref(context);
- }
- palock.unlock();
- pa_threaded_mainloop_stop(loop);
- }
- if(loop)
- pa_threaded_mainloop_free(loop);
+ pulse_close(mLoop, mContext, mStream);
+ mLoop = nullptr;
+ mContext = nullptr;
+ mStream = nullptr;
}
@@ -1366,47 +1352,6 @@ void PulseCapture_streamMovedCallback(pa_stream *stream, void *pdata)
}
-pa_stream *PulseCapture_connectStream(const char *device_name,
- pa_threaded_mainloop *loop, pa_context *context,
- pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec,
- pa_channel_map *chanmap)
-{
- pa_stream *stream{pa_stream_new_with_proplist(context,
- "Capture Stream", spec, chanmap, prop_filter
- )};
- if(!stream)
- {
- ERR("pa_stream_new_with_proplist() failed: %s\n", pa_strerror(pa_context_errno(context)));
- return nullptr;
- }
-
- pa_stream_set_state_callback(stream, stream_state_callback, loop);
-
- if(pa_stream_connect_record(stream, device_name, attr, flags) < 0)
- {
- ERR("Stream did not connect: %s\n", pa_strerror(pa_context_errno(context)));
- pa_stream_unref(stream);
- return nullptr;
- }
-
- pa_stream_state_t state;
- while((state=pa_stream_get_state(stream)) != PA_STREAM_READY)
- {
- if(!PA_STREAM_IS_GOOD(state))
- {
- ERR("Stream did not get ready: %s\n", pa_strerror(pa_context_errno(context)));
- pa_stream_unref(stream);
- return nullptr;
- }
-
- pa_threaded_mainloop_wait(loop);
- }
- pa_stream_set_state_callback(stream, nullptr, nullptr);
-
- return stream;
-}
-
-
ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name)
{
ALCdevice *device{self->mDevice};
@@ -1415,7 +1360,7 @@ ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name)
if(name)
{
if(CaptureDevices.empty())
- PulseCapture_probeDevices();
+ probeCaptureDevices();
auto iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(),
[name](const DevMap &entry) -> bool
@@ -1518,8 +1463,8 @@ ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name)
flags |= PA_STREAM_DONT_MOVE;
TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)");
- self->mStream = PulseCapture_connectStream(pulse_name, self->mLoop, self->mContext, flags,
- &self->mAttr, &self->mSpec, &chanmap);
+ self->mStream = pulse_connect_stream(pulse_name, self->mLoop, self->mContext, flags,
+ &self->mAttr, &self->mSpec, &chanmap, ALCbackend_Capture);
if(!self->mStream) return ALC_INVALID_VALUE;
pa_stream_set_moved_callback(self->mStream, PulseCapture_streamMovedCallback, self);
@@ -1739,12 +1684,12 @@ void PulseBackendFactory::probe(DevProbe type, std::string *outnames)
switch(type)
{
case ALL_DEVICE_PROBE:
- PulsePlayback_probeDevices();
+ probePlaybackDevices();
std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device);
break;
case CAPTURE_DEVICE_PROBE:
- PulseCapture_probeDevices();
+ probeCaptureDevices();
std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device);
break;
}