aboutsummaryrefslogtreecommitdiffstats
path: root/Alc/backends/alsa.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Alc/backends/alsa.cpp')
-rw-r--r--Alc/backends/alsa.cpp413
1 files changed, 182 insertions, 231 deletions
diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp
index 17af2364..c5d75fe3 100644
--- a/Alc/backends/alsa.cpp
+++ b/Alc/backends/alsa.cpp
@@ -422,46 +422,32 @@ int verify_state(snd_pcm_t *handle)
}
-struct ALCplaybackAlsa final : public ALCbackend {
- ALCplaybackAlsa(ALCdevice *device) noexcept : ALCbackend{device} { }
- ~ALCplaybackAlsa() override;
+struct AlsaPlayback final : public BackendBase {
+ AlsaPlayback(ALCdevice *device) noexcept : BackendBase{device} { }
+ ~AlsaPlayback() override;
int mixerProc();
int mixerNoMMapProc();
+ ALCenum open(const ALCchar *name) override;
+ ALCboolean reset() override;
+ ALCboolean start() override;
+ void stop() override;
+
+ ClockLatency getClockLatency() override;
+
snd_pcm_t *mPcmHandle{nullptr};
al::vector<char> mBuffer;
std::atomic<ALenum> mKillNow{AL_TRUE};
std::thread mThread;
-};
-void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device);
-void ALCplaybackAlsa_Destruct(ALCplaybackAlsa *self);
-ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name);
-ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self);
-ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self);
-void ALCplaybackAlsa_stop(ALCplaybackAlsa *self);
-DECLARE_FORWARD2(ALCplaybackAlsa, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
-DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, ALCuint, availableSamples)
-ClockLatency ALCplaybackAlsa_getClockLatency(ALCplaybackAlsa *self);
-DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, void, lock)
-DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, void, unlock)
-DECLARE_DEFAULT_ALLOCATORS(ALCplaybackAlsa)
-DEFINE_ALCBACKEND_VTABLE(ALCplaybackAlsa);
-
-
-void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device)
-{
- new (self) ALCplaybackAlsa{device};
- SET_VTABLE2(ALCplaybackAlsa, ALCbackend, self);
-}
-
-void ALCplaybackAlsa_Destruct(ALCplaybackAlsa *self)
-{ self->~ALCplaybackAlsa(); }
+ static constexpr inline const char *CurrentPrefix() noexcept { return "AlsaPlayback::"; }
+ DEF_NEWDEL(AlsaPlayback)
+};
-ALCplaybackAlsa::~ALCplaybackAlsa()
+AlsaPlayback::~AlsaPlayback()
{
if(mPcmHandle)
snd_pcm_close(mPcmHandle);
@@ -469,7 +455,7 @@ ALCplaybackAlsa::~ALCplaybackAlsa()
}
-int ALCplaybackAlsa::mixerProc()
+int AlsaPlayback::mixerProc()
{
SetRTPriority();
althrd_setname(MIXER_THREAD_NAME);
@@ -482,9 +468,9 @@ int ALCplaybackAlsa::mixerProc()
if(state < 0)
{
ERR("Invalid state detected: %s\n", snd_strerror(state));
- ALCplaybackAlsa_lock(this);
+ lock();
aluHandleDisconnect(mDevice, "Bad state: %s", snd_strerror(state));
- ALCplaybackAlsa_unlock(this);
+ unlock();
break;
}
@@ -521,7 +507,7 @@ int ALCplaybackAlsa::mixerProc()
avail -= avail%update_size;
// it is possible that contiguous areas are smaller, thus we use a loop
- ALCplaybackAlsa_lock(this);
+ lock();
while(avail > 0)
{
snd_pcm_uframes_t frames{static_cast<snd_pcm_uframes_t>(avail)};
@@ -548,13 +534,13 @@ int ALCplaybackAlsa::mixerProc()
avail -= frames;
}
- ALCplaybackAlsa_unlock(this);
+ unlock();
}
return 0;
}
-int ALCplaybackAlsa::mixerNoMMapProc()
+int AlsaPlayback::mixerNoMMapProc()
{
SetRTPriority();
althrd_setname(MIXER_THREAD_NAME);
@@ -567,9 +553,9 @@ int ALCplaybackAlsa::mixerNoMMapProc()
if(state < 0)
{
ERR("Invalid state detected: %s\n", snd_strerror(state));
- ALCplaybackAlsa_lock(this);
+ lock();
aluHandleDisconnect(mDevice, "Bad state: %s", snd_strerror(state));
- ALCplaybackAlsa_unlock(this);
+ unlock();
break;
}
@@ -603,7 +589,7 @@ int ALCplaybackAlsa::mixerNoMMapProc()
continue;
}
- ALCplaybackAlsa_lock(this);
+ lock();
char *WritePtr{mBuffer.data()};
avail = snd_pcm_bytes_to_frames(mPcmHandle, mBuffer.size());
aluMixData(mDevice, WritePtr, avail);
@@ -637,14 +623,14 @@ int ALCplaybackAlsa::mixerNoMMapProc()
if(ret < 0) break;
}
}
- ALCplaybackAlsa_unlock(this);
+ unlock();
}
return 0;
}
-ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name)
+ALCenum AlsaPlayback::open(const ALCchar *name)
{
const char *driver{};
if(name)
@@ -667,7 +653,7 @@ ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name)
}
TRACE("Opening device \"%s\"\n", driver);
- int err{snd_pcm_open(&self->mPcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)};
+ int err{snd_pcm_open(&mPcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)};
if(err < 0)
{
ERR("Could not open playback device '%s': %s\n", driver, snd_strerror(err));
@@ -677,18 +663,15 @@ ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name)
/* Free alsa's global config tree. Otherwise valgrind reports a ton of leaks. */
snd_config_update_free_global();
- ALCdevice *device = self->mDevice;
- device->DeviceName = name;
+ mDevice->DeviceName = name;
return ALC_NO_ERROR;
}
-ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self)
+ALCboolean AlsaPlayback::reset()
{
- ALCdevice *device{self->mDevice};
-
snd_pcm_format_t format{SND_PCM_FORMAT_UNKNOWN};
- switch(device->FmtType)
+ switch(mDevice->FmtType)
{
case DevFmtByte:
format = SND_PCM_FORMAT_S8;
@@ -713,11 +696,11 @@ ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self)
break;
}
- bool allowmmap{!!GetConfigValueBool(device->DeviceName.c_str(), "alsa", "mmap", 1)};
- ALuint periods{device->NumUpdates};
- ALuint periodLen{static_cast<ALuint>(device->UpdateSize * U64(1000000) / device->Frequency)};
+ bool allowmmap{!!GetConfigValueBool(mDevice->DeviceName.c_str(), "alsa", "mmap", 1)};
+ ALuint periods{mDevice->NumUpdates};
+ ALuint periodLen{static_cast<ALuint>(mDevice->UpdateSize * U64(1000000) / mDevice->Frequency)};
ALuint bufferLen{periodLen * periods};
- ALuint rate{device->Frequency};
+ ALuint rate{mDevice->Frequency};
snd_pcm_uframes_t periodSizeInFrames;
snd_pcm_sw_params_t *sp{};
@@ -727,15 +710,15 @@ ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self)
int dir, err;
snd_pcm_hw_params_malloc(&hp);
#define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error
- CHECK(snd_pcm_hw_params_any(self->mPcmHandle, hp));
+ CHECK(snd_pcm_hw_params_any(mPcmHandle, hp));
/* set interleaved access */
- if(!allowmmap || snd_pcm_hw_params_set_access(self->mPcmHandle, hp, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0)
+ if(!allowmmap || snd_pcm_hw_params_set_access(mPcmHandle, hp, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0)
{
/* No mmap */
- CHECK(snd_pcm_hw_params_set_access(self->mPcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED));
+ CHECK(snd_pcm_hw_params_set_access(mPcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED));
}
/* test and set format (implicitly sets sample bits) */
- if(snd_pcm_hw_params_test_format(self->mPcmHandle, hp, format) < 0)
+ if(snd_pcm_hw_params_test_format(mPcmHandle, hp, format) < 0)
{
static const struct {
snd_pcm_format_t format;
@@ -753,16 +736,16 @@ ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self)
for(const auto &fmt : formatlist)
{
format = fmt.format;
- if(snd_pcm_hw_params_test_format(self->mPcmHandle, hp, format) >= 0)
+ if(snd_pcm_hw_params_test_format(mPcmHandle, hp, format) >= 0)
{
- device->FmtType = fmt.fmttype;
+ mDevice->FmtType = fmt.fmttype;
break;
}
}
}
- CHECK(snd_pcm_hw_params_set_format(self->mPcmHandle, hp, format));
+ CHECK(snd_pcm_hw_params_set_format(mPcmHandle, hp, format));
/* test and set channels (implicitly sets frame bits) */
- if(snd_pcm_hw_params_test_channels(self->mPcmHandle, hp, device->channelsFromFmt()) < 0)
+ if(snd_pcm_hw_params_test_channels(mPcmHandle, hp, mDevice->channelsFromFmt()) < 0)
{
static const DevFmtChannels channellist[] = {
DevFmtStereo,
@@ -774,33 +757,33 @@ ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self)
for(const auto &chan : channellist)
{
- if(snd_pcm_hw_params_test_channels(self->mPcmHandle, hp, ChannelsFromDevFmt(chan, 0)) >= 0)
+ if(snd_pcm_hw_params_test_channels(mPcmHandle, hp, ChannelsFromDevFmt(chan, 0)) >= 0)
{
- device->FmtChans = chan;
- device->mAmbiOrder = 0;
+ mDevice->FmtChans = chan;
+ mDevice->mAmbiOrder = 0;
break;
}
}
}
- CHECK(snd_pcm_hw_params_set_channels(self->mPcmHandle, hp, device->channelsFromFmt()));
+ CHECK(snd_pcm_hw_params_set_channels(mPcmHandle, hp, mDevice->channelsFromFmt()));
/* set rate (implicitly constrains period/buffer parameters) */
- if(!GetConfigValueBool(device->DeviceName.c_str(), "alsa", "allow-resampler", 0) ||
- !(device->Flags&DEVICE_FREQUENCY_REQUEST))
+ if(!GetConfigValueBool(mDevice->DeviceName.c_str(), "alsa", "allow-resampler", 0) ||
+ !(mDevice->Flags&DEVICE_FREQUENCY_REQUEST))
{
- if(snd_pcm_hw_params_set_rate_resample(self->mPcmHandle, hp, 0) < 0)
+ if(snd_pcm_hw_params_set_rate_resample(mPcmHandle, hp, 0) < 0)
ERR("Failed to disable ALSA resampler\n");
}
- else if(snd_pcm_hw_params_set_rate_resample(self->mPcmHandle, hp, 1) < 0)
+ else if(snd_pcm_hw_params_set_rate_resample(mPcmHandle, hp, 1) < 0)
ERR("Failed to enable ALSA resampler\n");
- CHECK(snd_pcm_hw_params_set_rate_near(self->mPcmHandle, hp, &rate, nullptr));
+ CHECK(snd_pcm_hw_params_set_rate_near(mPcmHandle, hp, &rate, nullptr));
/* set buffer time (implicitly constrains period/buffer parameters) */
- if((err=snd_pcm_hw_params_set_buffer_time_near(self->mPcmHandle, hp, &bufferLen, nullptr)) < 0)
+ if((err=snd_pcm_hw_params_set_buffer_time_near(mPcmHandle, hp, &bufferLen, nullptr)) < 0)
ERR("snd_pcm_hw_params_set_buffer_time_near failed: %s\n", snd_strerror(err));
/* set period time (implicitly sets buffer size/bytes/time and period size/bytes) */
- if((err=snd_pcm_hw_params_set_period_time_near(self->mPcmHandle, hp, &periodLen, nullptr)) < 0)
+ if((err=snd_pcm_hw_params_set_period_time_near(mPcmHandle, hp, &periodLen, nullptr)) < 0)
ERR("snd_pcm_hw_params_set_period_time_near failed: %s\n", snd_strerror(err));
/* install and prepare hardware configuration */
- CHECK(snd_pcm_hw_params(self->mPcmHandle, hp));
+ CHECK(snd_pcm_hw_params(mPcmHandle, hp));
/* retrieve configuration info */
CHECK(snd_pcm_hw_params_get_access(hp, &access));
@@ -812,19 +795,19 @@ ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self)
hp = nullptr;
snd_pcm_sw_params_malloc(&sp);
- CHECK(snd_pcm_sw_params_current(self->mPcmHandle, sp));
- CHECK(snd_pcm_sw_params_set_avail_min(self->mPcmHandle, sp, periodSizeInFrames));
- CHECK(snd_pcm_sw_params_set_stop_threshold(self->mPcmHandle, sp, periodSizeInFrames*periods));
- CHECK(snd_pcm_sw_params(self->mPcmHandle, sp));
+ CHECK(snd_pcm_sw_params_current(mPcmHandle, sp));
+ CHECK(snd_pcm_sw_params_set_avail_min(mPcmHandle, sp, periodSizeInFrames));
+ CHECK(snd_pcm_sw_params_set_stop_threshold(mPcmHandle, sp, periodSizeInFrames*periods));
+ CHECK(snd_pcm_sw_params(mPcmHandle, sp));
#undef CHECK
snd_pcm_sw_params_free(sp);
sp = nullptr;
- device->NumUpdates = periods;
- device->UpdateSize = periodSizeInFrames;
- device->Frequency = rate;
+ mDevice->NumUpdates = periods;
+ mDevice->UpdateSize = periodSizeInFrames;
+ mDevice->Frequency = rate;
- SetDefaultChannelOrder(device);
+ SetDefaultChannelOrder(mDevice);
return ALC_TRUE;
@@ -835,9 +818,8 @@ error:
return ALC_FALSE;
}
-ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self)
+ALCboolean AlsaPlayback::start()
{
- ALCdevice *device{self->mDevice};
snd_pcm_hw_params_t *hp{};
snd_pcm_access_t access;
const char *funcerr;
@@ -845,7 +827,7 @@ ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self)
snd_pcm_hw_params_malloc(&hp);
#define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error
- CHECK(snd_pcm_hw_params_current(self->mPcmHandle, hp));
+ CHECK(snd_pcm_hw_params_current(mPcmHandle, hp));
/* retrieve configuration info */
CHECK(snd_pcm_hw_params_get_access(hp, &access));
#undef CHECK
@@ -859,26 +841,26 @@ ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self)
snd_pcm_hw_params_free(hp);
hp = nullptr;
- int (ALCplaybackAlsa::*thread_func)(){};
+ int (AlsaPlayback::*thread_func)(){};
if(access == SND_PCM_ACCESS_RW_INTERLEAVED)
{
- self->mBuffer.resize(snd_pcm_frames_to_bytes(self->mPcmHandle, device->UpdateSize));
- thread_func = &ALCplaybackAlsa::mixerNoMMapProc;
+ mBuffer.resize(snd_pcm_frames_to_bytes(mPcmHandle, mDevice->UpdateSize));
+ thread_func = &AlsaPlayback::mixerNoMMapProc;
}
else
{
- err = snd_pcm_prepare(self->mPcmHandle);
+ err = snd_pcm_prepare(mPcmHandle);
if(err < 0)
{
ERR("snd_pcm_prepare(data->mPcmHandle) failed: %s\n", snd_strerror(err));
return ALC_FALSE;
}
- thread_func = &ALCplaybackAlsa::mixerProc;
+ thread_func = &AlsaPlayback::mixerProc;
}
try {
- self->mKillNow.store(AL_FALSE, std::memory_order_release);
- self->mThread = std::thread{std::mem_fn(thread_func), self};
+ mKillNow.store(AL_FALSE, std::memory_order_release);
+ mThread = std::thread{std::mem_fn(thread_func), this};
return ALC_TRUE;
}
catch(std::exception& e) {
@@ -886,45 +868,50 @@ ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self)
}
catch(...) {
}
- self->mBuffer.clear();
+ mBuffer.clear();
return ALC_FALSE;
}
-void ALCplaybackAlsa_stop(ALCplaybackAlsa *self)
+void AlsaPlayback::stop()
{
- if(self->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !self->mThread.joinable())
+ if(mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !mThread.joinable())
return;
+ mThread.join();
- self->mThread.join();
-
- self->mBuffer.clear();
+ mBuffer.clear();
}
-ClockLatency ALCplaybackAlsa_getClockLatency(ALCplaybackAlsa *self)
+ClockLatency AlsaPlayback::getClockLatency()
{
- ALCdevice *device{self->mDevice};
ClockLatency ret;
- ALCplaybackAlsa_lock(self);
- ret.ClockTime = GetDeviceClockTime(device);
+ lock();
+ ret.ClockTime = GetDeviceClockTime(mDevice);
snd_pcm_sframes_t delay{};
- int err{snd_pcm_delay(self->mPcmHandle, &delay)};
+ int err{snd_pcm_delay(mPcmHandle, &delay)};
if(err < 0)
{
ERR("Failed to get pcm delay: %s\n", snd_strerror(err));
delay = 0;
}
ret.Latency = std::chrono::seconds{std::max<snd_pcm_sframes_t>(0, delay)};
- ret.Latency /= device->Frequency;
- ALCplaybackAlsa_unlock(self);
+ ret.Latency /= mDevice->Frequency;
+ unlock();
return ret;
}
-struct ALCcaptureAlsa final : public ALCbackend {
- ALCcaptureAlsa(ALCdevice *device) noexcept : ALCbackend{device} { }
- ~ALCcaptureAlsa() override;
+struct AlsaCapture final : public BackendBase {
+ AlsaCapture(ALCdevice *device) noexcept : BackendBase{device} { }
+ ~AlsaCapture() override;
+
+ ALCenum open(const ALCchar *name) override;
+ ALCboolean start() override;
+ void stop() override;
+ ALCenum captureSamples(ALCvoid *buffer, ALCuint samples) override;
+ ALCuint availableSamples() override;
+ ClockLatency getClockLatency() override;
snd_pcm_t *mPcmHandle{nullptr};
@@ -934,34 +921,12 @@ struct ALCcaptureAlsa final : public ALCbackend {
RingBufferPtr mRing{nullptr};
snd_pcm_sframes_t mLastAvail{0};
-};
-
-void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device);
-void ALCcaptureAlsa_Destruct(ALCcaptureAlsa *self);
-ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name);
-DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, ALCboolean, reset)
-ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self);
-void ALCcaptureAlsa_stop(ALCcaptureAlsa *self);
-ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buffer, ALCuint samples);
-ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self);
-ClockLatency ALCcaptureAlsa_getClockLatency(ALCcaptureAlsa *self);
-DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, void, lock)
-DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, void, unlock)
-DECLARE_DEFAULT_ALLOCATORS(ALCcaptureAlsa)
-
-DEFINE_ALCBACKEND_VTABLE(ALCcaptureAlsa);
-
-void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device)
-{
- new (self) ALCcaptureAlsa{device};
- SET_VTABLE2(ALCcaptureAlsa, ALCbackend, self);
-}
-
-void ALCcaptureAlsa_Destruct(ALCcaptureAlsa *self)
-{ self->~ALCcaptureAlsa(); }
+ static constexpr inline const char *CurrentPrefix() noexcept { return "AlsaCapture::"; }
+ DEF_NEWDEL(AlsaCapture)
+};
-ALCcaptureAlsa::~ALCcaptureAlsa()
+AlsaCapture::~AlsaCapture()
{
if(mPcmHandle)
snd_pcm_close(mPcmHandle);
@@ -969,9 +934,8 @@ ALCcaptureAlsa::~ALCcaptureAlsa()
}
-ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name)
+ALCenum AlsaCapture::open(const ALCchar *name)
{
- ALCdevice *device{self->mDevice};
const char *driver{};
if(name)
{
@@ -993,7 +957,7 @@ ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name)
}
TRACE("Opening device \"%s\"\n", driver);
- int err{snd_pcm_open(&self->mPcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)};
+ int err{snd_pcm_open(&mPcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)};
if(err < 0)
{
ERR("Could not open capture device '%s': %s\n", driver, snd_strerror(err));
@@ -1004,7 +968,7 @@ ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name)
snd_config_update_free_global();
snd_pcm_format_t format{SND_PCM_FORMAT_UNKNOWN};
- switch(device->FmtType)
+ switch(mDevice->FmtType)
{
case DevFmtByte:
format = SND_PCM_FORMAT_S8;
@@ -1029,35 +993,35 @@ ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name)
break;
}
- snd_pcm_uframes_t bufferSizeInFrames{maxu(device->UpdateSize*device->NumUpdates,
- 100*device->Frequency/1000)};
- snd_pcm_uframes_t periodSizeInFrames{minu(bufferSizeInFrames, 25*device->Frequency/1000)};
+ snd_pcm_uframes_t bufferSizeInFrames{maxu(mDevice->UpdateSize*mDevice->NumUpdates,
+ 100*mDevice->Frequency/1000)};
+ snd_pcm_uframes_t periodSizeInFrames{minu(bufferSizeInFrames, 25*mDevice->Frequency/1000)};
bool needring{false};
const char *funcerr{};
snd_pcm_hw_params_t *hp{};
snd_pcm_hw_params_malloc(&hp);
#define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error
- CHECK(snd_pcm_hw_params_any(self->mPcmHandle, hp));
+ CHECK(snd_pcm_hw_params_any(mPcmHandle, hp));
/* set interleaved access */
- CHECK(snd_pcm_hw_params_set_access(self->mPcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED));
+ CHECK(snd_pcm_hw_params_set_access(mPcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED));
/* set format (implicitly sets sample bits) */
- CHECK(snd_pcm_hw_params_set_format(self->mPcmHandle, hp, format));
+ CHECK(snd_pcm_hw_params_set_format(mPcmHandle, hp, format));
/* set channels (implicitly sets frame bits) */
- CHECK(snd_pcm_hw_params_set_channels(self->mPcmHandle, hp, device->channelsFromFmt()));
+ CHECK(snd_pcm_hw_params_set_channels(mPcmHandle, hp, mDevice->channelsFromFmt()));
/* set rate (implicitly constrains period/buffer parameters) */
- CHECK(snd_pcm_hw_params_set_rate(self->mPcmHandle, hp, device->Frequency, 0));
+ CHECK(snd_pcm_hw_params_set_rate(mPcmHandle, hp, mDevice->Frequency, 0));
/* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
- if(snd_pcm_hw_params_set_buffer_size_min(self->mPcmHandle, hp, &bufferSizeInFrames) < 0)
+ if(snd_pcm_hw_params_set_buffer_size_min(mPcmHandle, hp, &bufferSizeInFrames) < 0)
{
TRACE("Buffer too large, using intermediate ring buffer\n");
needring = true;
- CHECK(snd_pcm_hw_params_set_buffer_size_near(self->mPcmHandle, hp, &bufferSizeInFrames));
+ CHECK(snd_pcm_hw_params_set_buffer_size_near(mPcmHandle, hp, &bufferSizeInFrames));
}
/* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
- CHECK(snd_pcm_hw_params_set_period_size_near(self->mPcmHandle, hp, &periodSizeInFrames, nullptr));
+ CHECK(snd_pcm_hw_params_set_period_size_near(mPcmHandle, hp, &periodSizeInFrames, nullptr));
/* install and prepare hardware configuration */
- CHECK(snd_pcm_hw_params(self->mPcmHandle, hp));
+ CHECK(snd_pcm_hw_params(mPcmHandle, hp));
/* retrieve configuration info */
CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, nullptr));
#undef CHECK
@@ -1066,16 +1030,16 @@ ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name)
if(needring)
{
- self->mRing = CreateRingBuffer(device->UpdateSize*device->NumUpdates,
- device->frameSizeFromFmt(), false);
- if(!self->mRing)
+ mRing = CreateRingBuffer(mDevice->UpdateSize*mDevice->NumUpdates,
+ mDevice->frameSizeFromFmt(), false);
+ if(!mRing)
{
ERR("ring buffer create failed\n");
goto error2;
}
}
- device->DeviceName = name;
+ mDevice->DeviceName = name;
return ALC_NO_ERROR;
@@ -1084,99 +1048,99 @@ error:
if(hp) snd_pcm_hw_params_free(hp);
error2:
- self->mRing = nullptr;
- snd_pcm_close(self->mPcmHandle);
- self->mPcmHandle = nullptr;
+ mRing = nullptr;
+ snd_pcm_close(mPcmHandle);
+ mPcmHandle = nullptr;
return ALC_INVALID_VALUE;
}
-ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self)
+
+ALCboolean AlsaCapture::start()
{
- int err{snd_pcm_prepare(self->mPcmHandle)};
+ int err{snd_pcm_prepare(mPcmHandle)};
if(err < 0)
ERR("prepare failed: %s\n", snd_strerror(err));
else
{
- err = snd_pcm_start(self->mPcmHandle);
+ err = snd_pcm_start(mPcmHandle);
if(err < 0)
ERR("start failed: %s\n", snd_strerror(err));
}
if(err < 0)
{
- aluHandleDisconnect(self->mDevice, "Capture state failure: %s", snd_strerror(err));
+ aluHandleDisconnect(mDevice, "Capture state failure: %s", snd_strerror(err));
return ALC_FALSE;
}
- self->mDoCapture = true;
+ mDoCapture = true;
return ALC_TRUE;
}
-void ALCcaptureAlsa_stop(ALCcaptureAlsa *self)
+void AlsaCapture::stop()
{
/* OpenAL requires access to unread audio after stopping, but ALSA's
* snd_pcm_drain is unreliable and snd_pcm_drop drops it. Capture what's
- * available now so it'll be available later after the drop. */
- ALCuint avail{ALCcaptureAlsa_availableSamples(self)};
- if(!self->mRing && avail > 0)
+ * available now so it'll be available later after the drop.
+ */
+ ALCuint avail{availableSamples()};
+ if(!mRing && avail > 0)
{
/* The ring buffer implicitly captures when checking availability.
* Direct access needs to explicitly capture it into temp storage. */
- al::vector<char> temp(snd_pcm_frames_to_bytes(self->mPcmHandle, avail));
- ALCcaptureAlsa_captureSamples(self, temp.data(), avail);
- self->mBuffer = std::move(temp);
+ al::vector<char> temp(snd_pcm_frames_to_bytes(mPcmHandle, avail));
+ captureSamples(temp.data(), avail);
+ mBuffer = std::move(temp);
}
- int err{snd_pcm_drop(self->mPcmHandle)};
+ int err{snd_pcm_drop(mPcmHandle)};
if(err < 0)
ERR("drop failed: %s\n", snd_strerror(err));
- self->mDoCapture = false;
+ mDoCapture = false;
}
-ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buffer, ALCuint samples)
+ALCenum AlsaCapture::captureSamples(ALCvoid *buffer, ALCuint samples)
{
- ALCdevice *device{self->mDevice};
-
- if(RingBuffer *ring{self->mRing.get()})
+ if(mRing)
{
- ring->read(buffer, samples);
+ mRing->read(buffer, samples);
return ALC_NO_ERROR;
}
- self->mLastAvail -= samples;
- while(device->Connected.load(std::memory_order_acquire) && samples > 0)
+ mLastAvail -= samples;
+ while(mDevice->Connected.load(std::memory_order_acquire) && samples > 0)
{
snd_pcm_sframes_t amt{0};
- if(!self->mBuffer.empty())
+ if(!mBuffer.empty())
{
/* First get any data stored from the last stop */
- amt = snd_pcm_bytes_to_frames(self->mPcmHandle, self->mBuffer.size());
+ amt = snd_pcm_bytes_to_frames(mPcmHandle, mBuffer.size());
if((snd_pcm_uframes_t)amt > samples) amt = samples;
- amt = snd_pcm_frames_to_bytes(self->mPcmHandle, amt);
- memcpy(buffer, self->mBuffer.data(), amt);
+ amt = snd_pcm_frames_to_bytes(mPcmHandle, amt);
+ memcpy(buffer, mBuffer.data(), amt);
- self->mBuffer.erase(self->mBuffer.begin(), self->mBuffer.begin()+amt);
- amt = snd_pcm_bytes_to_frames(self->mPcmHandle, amt);
+ mBuffer.erase(mBuffer.begin(), mBuffer.begin()+amt);
+ amt = snd_pcm_bytes_to_frames(mPcmHandle, amt);
}
- else if(self->mDoCapture)
- amt = snd_pcm_readi(self->mPcmHandle, buffer, samples);
+ else if(mDoCapture)
+ amt = snd_pcm_readi(mPcmHandle, buffer, samples);
if(amt < 0)
{
ERR("read error: %s\n", snd_strerror(amt));
if(amt == -EAGAIN)
continue;
- if((amt=snd_pcm_recover(self->mPcmHandle, amt, 1)) >= 0)
+ if((amt=snd_pcm_recover(mPcmHandle, amt, 1)) >= 0)
{
- amt = snd_pcm_start(self->mPcmHandle);
+ amt = snd_pcm_start(mPcmHandle);
if(amt >= 0)
- amt = snd_pcm_avail_update(self->mPcmHandle);
+ amt = snd_pcm_avail_update(mPcmHandle);
}
if(amt < 0)
{
ERR("restore error: %s\n", snd_strerror(amt));
- aluHandleDisconnect(device, "Capture recovery failure: %s", snd_strerror(amt));
+ aluHandleDisconnect(mDevice, "Capture recovery failure: %s", snd_strerror(amt));
break;
}
/* If the amount available is less than what's asked, we lost it
@@ -1190,100 +1154,96 @@ ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buffer, ALC
samples -= amt;
}
if(samples > 0)
- memset(buffer, ((device->FmtType == DevFmtUByte) ? 0x80 : 0),
- snd_pcm_frames_to_bytes(self->mPcmHandle, samples));
+ memset(buffer, ((mDevice->FmtType == DevFmtUByte) ? 0x80 : 0),
+ snd_pcm_frames_to_bytes(mPcmHandle, samples));
return ALC_NO_ERROR;
}
-ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self)
+ALCuint AlsaCapture::availableSamples()
{
- ALCdevice *device{self->mDevice};
-
snd_pcm_sframes_t avail{0};
- if(device->Connected.load(std::memory_order_acquire) && self->mDoCapture)
- avail = snd_pcm_avail_update(self->mPcmHandle);
+ if(mDevice->Connected.load(std::memory_order_acquire) && mDoCapture)
+ avail = snd_pcm_avail_update(mPcmHandle);
if(avail < 0)
{
ERR("avail update failed: %s\n", snd_strerror(avail));
- if((avail=snd_pcm_recover(self->mPcmHandle, avail, 1)) >= 0)
+ if((avail=snd_pcm_recover(mPcmHandle, avail, 1)) >= 0)
{
- if(self->mDoCapture)
- avail = snd_pcm_start(self->mPcmHandle);
+ if(mDoCapture)
+ avail = snd_pcm_start(mPcmHandle);
if(avail >= 0)
- avail = snd_pcm_avail_update(self->mPcmHandle);
+ avail = snd_pcm_avail_update(mPcmHandle);
}
if(avail < 0)
{
ERR("restore error: %s\n", snd_strerror(avail));
- aluHandleDisconnect(device, "Capture recovery failure: %s", snd_strerror(avail));
+ aluHandleDisconnect(mDevice, "Capture recovery failure: %s", snd_strerror(avail));
}
}
- RingBuffer *ring{self->mRing.get()};
- if(!ring)
+ if(!mRing)
{
if(avail < 0) avail = 0;
- avail += snd_pcm_bytes_to_frames(self->mPcmHandle, self->mBuffer.size());
- if(avail > self->mLastAvail) self->mLastAvail = avail;
- return self->mLastAvail;
+ avail += snd_pcm_bytes_to_frames(mPcmHandle, mBuffer.size());
+ if(avail > mLastAvail) mLastAvail = avail;
+ return mLastAvail;
}
while(avail > 0)
{
- auto vec = ring->getWriteVector();
+ auto vec = mRing->getWriteVector();
if(vec.first.len == 0) break;
snd_pcm_sframes_t amt{std::min<snd_pcm_sframes_t>(vec.first.len, avail)};
- amt = snd_pcm_readi(self->mPcmHandle, vec.first.buf, amt);
+ amt = snd_pcm_readi(mPcmHandle, vec.first.buf, amt);
if(amt < 0)
{
ERR("read error: %s\n", snd_strerror(amt));
if(amt == -EAGAIN)
continue;
- if((amt=snd_pcm_recover(self->mPcmHandle, amt, 1)) >= 0)
+ if((amt=snd_pcm_recover(mPcmHandle, amt, 1)) >= 0)
{
- if(self->mDoCapture)
- amt = snd_pcm_start(self->mPcmHandle);
+ if(mDoCapture)
+ amt = snd_pcm_start(mPcmHandle);
if(amt >= 0)
- amt = snd_pcm_avail_update(self->mPcmHandle);
+ amt = snd_pcm_avail_update(mPcmHandle);
}
if(amt < 0)
{
ERR("restore error: %s\n", snd_strerror(amt));
- aluHandleDisconnect(device, "Capture recovery failure: %s", snd_strerror(amt));
+ aluHandleDisconnect(mDevice, "Capture recovery failure: %s", snd_strerror(amt));
break;
}
avail = amt;
continue;
}
- ring->writeAdvance(amt);
+ mRing->writeAdvance(amt);
avail -= amt;
}
- return ring->readSpace();
+ return mRing->readSpace();
}
-ClockLatency ALCcaptureAlsa_getClockLatency(ALCcaptureAlsa *self)
+ClockLatency AlsaCapture::getClockLatency()
{
- ALCdevice *device{self->mDevice};
ClockLatency ret;
- ALCcaptureAlsa_lock(self);
- ret.ClockTime = GetDeviceClockTime(device);
+ lock();
+ ret.ClockTime = GetDeviceClockTime(mDevice);
snd_pcm_sframes_t delay{};
- int err{snd_pcm_delay(self->mPcmHandle, &delay)};
+ int err{snd_pcm_delay(mPcmHandle, &delay)};
if(err < 0)
{
ERR("Failed to get pcm delay: %s\n", snd_strerror(err));
delay = 0;
}
ret.Latency = std::chrono::seconds{std::max<snd_pcm_sframes_t>(0, delay)};
- ret.Latency /= device->Frequency;
- ALCcaptureAlsa_unlock(self);
+ ret.Latency /= mDevice->Frequency;
+ unlock();
return ret;
}
@@ -1332,21 +1292,12 @@ void AlsaBackendFactory::probe(DevProbe type, std::string *outnames)
}
}
-ALCbackend *AlsaBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type)
+BackendBase *AlsaBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type)
{
if(type == ALCbackend_Playback)
- {
- ALCplaybackAlsa *backend;
- NEW_OBJ(backend, ALCplaybackAlsa)(device);
- return backend;
- }
+ return new AlsaPlayback{device};
if(type == ALCbackend_Capture)
- {
- ALCcaptureAlsa *backend;
- NEW_OBJ(backend, ALCcaptureAlsa)(device);
- return backend;
- }
-
+ return new AlsaCapture{device};
return nullptr;
}