diff options
Diffstat (limited to 'Alc/backends')
36 files changed, 1870 insertions, 2733 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; } diff --git a/Alc/backends/alsa.h b/Alc/backends/alsa.h index 8ee78f56..e9169c48 100644 --- a/Alc/backends/alsa.h +++ b/Alc/backends/alsa.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/base.cpp b/Alc/backends/base.cpp index 021a0f17..1fef0439 100644 --- a/Alc/backends/base.cpp +++ b/Alc/backends/base.cpp @@ -12,80 +12,60 @@ void ALCdevice_Lock(ALCdevice *device) -{ V0(device->Backend,lock)(); } +{ device->Backend->lock(); } void ALCdevice_Unlock(ALCdevice *device) -{ V0(device->Backend,unlock)(); } +{ device->Backend->unlock(); } ClockLatency GetClockLatency(ALCdevice *device) { - ClockLatency ret = V0(device->Backend,getClockLatency)(); + BackendBase *backend{device->Backend}; + ClockLatency ret{backend->getClockLatency()}; ret.Latency += device->FixedLatency; return ret; } -/* Base ALCbackend method implementations. */ -ALCbackend::ALCbackend(ALCdevice *device) noexcept : mDevice{device} +/* BackendBase method implementations. */ +BackendBase::BackendBase(ALCdevice *device) noexcept : mDevice{device} { } -ALCbackend::~ALCbackend() +BackendBase::~BackendBase() { } -ALCboolean ALCbackend_reset(ALCbackend* UNUSED(self)) -{ - return ALC_FALSE; -} +ALCboolean BackendBase::reset() +{ return ALC_FALSE; } -ALCenum ALCbackend_captureSamples(ALCbackend* UNUSED(self), void* UNUSED(buffer), ALCuint UNUSED(samples)) -{ - return ALC_INVALID_DEVICE; -} +ALCenum BackendBase::captureSamples(void* UNUSED(buffer), ALCuint UNUSED(samples)) +{ return ALC_INVALID_DEVICE; } -ALCuint ALCbackend_availableSamples(ALCbackend* UNUSED(self)) -{ - return 0; -} +ALCuint BackendBase::availableSamples() +{ return 0; } -ClockLatency ALCbackend_getClockLatency(ALCbackend *self) +ClockLatency BackendBase::getClockLatency() { - ALCdevice *device = self->mDevice; - ALuint refcount; ClockLatency ret; + ALuint refcount; do { - while(((refcount=device->MixCount.load(std::memory_order_acquire))&1)) + while(((refcount=mDevice->MixCount.load(std::memory_order_acquire))&1)) std::this_thread::yield(); - ret.ClockTime = GetDeviceClockTime(device); + ret.ClockTime = GetDeviceClockTime(mDevice); std::atomic_thread_fence(std::memory_order_acquire); - } while(refcount != device->MixCount.load(std::memory_order_relaxed)); + } while(refcount != mDevice->MixCount.load(std::memory_order_relaxed)); /* NOTE: The device will generally have about all but one periods filled at * any given time during playback. Without a more accurate measurement from * the output, this is an okay approximation. */ - ret.Latency = std::chrono::seconds{device->UpdateSize*maxi(device->NumUpdates-1, 0)}; - ret.Latency /= device->Frequency; + ret.Latency = std::chrono::seconds{mDevice->UpdateSize*maxi(mDevice->NumUpdates-1, 0)}; + ret.Latency /= mDevice->Frequency; return ret; } -void ALCbackend_lock(ALCbackend *self) -{ - try { - self->mMutex.lock(); - } - catch(...) { - std::terminate(); - } -} +void BackendBase::lock() noexcept +{ mMutex.lock(); } -void ALCbackend_unlock(ALCbackend *self) -{ - try { - self->mMutex.unlock(); - } - catch(...) { - std::terminate(); - } -} +void BackendBase::unlock() noexcept +{ mMutex.unlock(); } diff --git a/Alc/backends/base.h b/Alc/backends/base.h index 4380540f..b9ea3b61 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -6,7 +6,6 @@ #include <mutex> #include "alMain.h" -#include "polymorphism.h" struct ClockLatency { @@ -32,77 +31,29 @@ void ALCdevice_Unlock(ALCdevice *device); ClockLatency GetClockLatency(ALCdevice *device); +struct BackendBase { + virtual ALCenum open(const ALCchar *name) = 0; -struct ALCbackendVtable; + virtual ALCboolean reset(); + virtual ALCboolean start() = 0; + virtual void stop() = 0; -struct ALCbackend { - const ALCbackendVtable *vtbl; + virtual ALCenum captureSamples(void *buffer, ALCuint samples); + virtual ALCuint availableSamples(); - ALCdevice *mDevice; - - std::recursive_mutex mMutex; - - ALCbackend(ALCdevice *device) noexcept; - virtual ~ALCbackend(); -}; - -ALCboolean ALCbackend_reset(ALCbackend *self); -ALCenum ALCbackend_captureSamples(ALCbackend *self, void *buffer, ALCuint samples); -ALCuint ALCbackend_availableSamples(ALCbackend *self); -ClockLatency ALCbackend_getClockLatency(ALCbackend *self); -void ALCbackend_lock(ALCbackend *self); -void ALCbackend_unlock(ALCbackend *self); - -struct ALCbackendVtable { - void (*const Destruct)(ALCbackend*); + virtual ClockLatency getClockLatency(); - ALCenum (*const open)(ALCbackend*, const ALCchar*); + virtual void lock() noexcept; + virtual void unlock() noexcept; - ALCboolean (*const reset)(ALCbackend*); - ALCboolean (*const start)(ALCbackend*); - void (*const stop)(ALCbackend*); - - ALCenum (*const captureSamples)(ALCbackend*, void*, ALCuint); - ALCuint (*const availableSamples)(ALCbackend*); - - ClockLatency (*const getClockLatency)(ALCbackend*); + ALCdevice *mDevice; - void (*const lock)(ALCbackend*); - void (*const unlock)(ALCbackend*); + std::recursive_mutex mMutex; - void (*const Delete)(void*); + BackendBase(ALCdevice *device) noexcept; + virtual ~BackendBase(); }; -#define DEFINE_ALCBACKEND_VTABLE(T) \ -DECLARE_THUNK(T, ALCbackend, void, Destruct) \ -DECLARE_THUNK1(T, ALCbackend, ALCenum, open, const ALCchar*) \ -DECLARE_THUNK(T, ALCbackend, ALCboolean, reset) \ -DECLARE_THUNK(T, ALCbackend, ALCboolean, start) \ -DECLARE_THUNK(T, ALCbackend, void, stop) \ -DECLARE_THUNK2(T, ALCbackend, ALCenum, captureSamples, void*, ALCuint) \ -DECLARE_THUNK(T, ALCbackend, ALCuint, availableSamples) \ -DECLARE_THUNK(T, ALCbackend, ClockLatency, getClockLatency) \ -DECLARE_THUNK(T, ALCbackend, void, lock) \ -DECLARE_THUNK(T, ALCbackend, void, unlock) \ -static void T##_ALCbackend_Delete(void *ptr) \ -{ T##_Delete(static_cast<T*>(static_cast<ALCbackend*>(ptr))); } \ - \ -static const ALCbackendVtable T##_ALCbackend_vtable = { \ - T##_ALCbackend_Destruct, \ - \ - T##_ALCbackend_open, \ - T##_ALCbackend_reset, \ - T##_ALCbackend_start, \ - T##_ALCbackend_stop, \ - T##_ALCbackend_captureSamples, \ - T##_ALCbackend_availableSamples, \ - T##_ALCbackend_getClockLatency, \ - T##_ALCbackend_lock, \ - T##_ALCbackend_unlock, \ - \ - T##_ALCbackend_Delete, \ -} - enum ALCbackend_Type { ALCbackend_Playback, @@ -119,7 +70,7 @@ struct BackendFactory { virtual void probe(DevProbe type, std::string *outnames) = 0; - virtual ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) = 0; + virtual BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) = 0; }; #endif /* ALC_BACKENDS_BASE_H */ diff --git a/Alc/backends/coreaudio.cpp b/Alc/backends/coreaudio.cpp index 82312d67..3f1f48d8 100644 --- a/Alc/backends/coreaudio.cpp +++ b/Alc/backends/coreaudio.cpp @@ -30,6 +30,7 @@ #include "alu.h" #include "ringbuffer.h" #include "converter.h" +#include "backends/base.h" #include <unistd.h> #include <AudioUnit/AudioUnit.h> @@ -41,9 +42,9 @@ namespace { static const ALCchar ca_device[] = "CoreAudio Default"; -struct ALCcoreAudioPlayback final : public ALCbackend { - ALCcoreAudioPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } - ~ALCcoreAudioPlayback() override; +struct CoreAudioPlayback final : public BackendBase { + CoreAudioPlayback(ALCdevice *device) noexcept : BackendBase{device} { } + ~CoreAudioPlayback() override; static OSStatus MixerProcC(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, @@ -52,64 +53,47 @@ struct ALCcoreAudioPlayback final : public ALCbackend { const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData); + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + AudioUnit mAudioUnit; ALuint mFrameSize{0u}; AudioStreamBasicDescription mFormat{}; // This is the OpenAL format as a CoreAudio ASBD -}; - -static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice *device); -static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback *self); -static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCchar *name); -static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self); -static ALCboolean ALCcoreAudioPlayback_start(ALCcoreAudioPlayback *self); -static void ALCcoreAudioPlayback_stop(ALCcoreAudioPlayback *self); -static DECLARE_FORWARD2(ALCcoreAudioPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, ALCuint, availableSamples) -static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCcoreAudioPlayback) - -DEFINE_ALCBACKEND_VTABLE(ALCcoreAudioPlayback); - - -static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice *device) -{ - new (self) ALCcoreAudioPlayback{device}; - SET_VTABLE2(ALCcoreAudioPlayback, ALCbackend, self); -} -static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback *self) -{ self->~ALCcoreAudioPlayback(); } + static constexpr inline const char *CurrentPrefix() noexcept { return "CoreAudioPlayback::"; } + DEF_NEWDEL(CoreAudioPlayback) +}; -ALCcoreAudioPlayback::~ALCcoreAudioPlayback() +CoreAudioPlayback::~CoreAudioPlayback() { AudioUnitUninitialize(mAudioUnit); AudioComponentInstanceDispose(mAudioUnit); } -OSStatus ALCcoreAudioPlayback::MixerProcC(void *inRefCon, +OSStatus CoreAudioPlayback::MixerProcC(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) { - return static_cast<ALCcoreAudioPlayback*>(inRefCon)->MixerProc(ioActionFlags, inTimeStamp, + return static_cast<CoreAudioPlayback*>(inRefCon)->MixerProc(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData); } -OSStatus ALCcoreAudioPlayback::MixerProc(AudioUnitRenderActionFlags* UNUSED(ioActionFlags), +OSStatus CoreAudioPlayback::MixerProc(AudioUnitRenderActionFlags* UNUSED(ioActionFlags), const AudioTimeStamp* UNUSED(inTimeStamp), UInt32 UNUSED(inBusNumber), UInt32 UNUSED(inNumberFrames), AudioBufferList *ioData) { - ALCcoreAudioPlayback_lock(this); + lock(); aluMixData(mDevice, ioData->mBuffers[0].mData, ioData->mBuffers[0].mDataByteSize/mFrameSize); - ALCcoreAudioPlayback_unlock(this); + unlock(); return noErr; } -static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCchar *name) +ALCenum CoreAudioPlayback::open(const ALCchar *name) { if(!name) name = ca_device; @@ -135,7 +119,7 @@ static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCch return ALC_INVALID_VALUE; } - OSStatus err{AudioComponentInstanceNew(comp, &self->mAudioUnit)}; + OSStatus err{AudioComponentInstanceNew(comp, &mAudioUnit)}; if(err != noErr) { ERR("AudioComponentInstanceNew failed\n"); @@ -143,32 +127,29 @@ static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCch } /* init and start the default audio unit... */ - err = AudioUnitInitialize(self->mAudioUnit); + err = AudioUnitInitialize(mAudioUnit); if(err != noErr) { ERR("AudioUnitInitialize failed\n"); - AudioComponentInstanceDispose(self->mAudioUnit); + AudioComponentInstanceDispose(mAudioUnit); return ALC_INVALID_VALUE; } - ALCdevice *device{self->mDevice}; - device->DeviceName = name; + mDevice->DeviceName = name; return ALC_NO_ERROR; } -static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) +ALCboolean CoreAudioPlayback::reset() { - ALCdevice *device{self->mDevice}; - - OSStatus err{AudioUnitUninitialize(self->mAudioUnit)}; + OSStatus err{AudioUnitUninitialize(mAudioUnit)}; if(err != noErr) ERR("-- AudioUnitUninitialize failed.\n"); /* retrieve default output unit's properties (output side) */ AudioStreamBasicDescription streamFormat{}; auto size = static_cast<UInt32>(sizeof(AudioStreamBasicDescription)); - err = AudioUnitGetProperty(self->mAudioUnit, kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Output, 0, &streamFormat, &size); + err = AudioUnitGetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, + 0, &streamFormat, &size); if(err != noErr || size != sizeof(AudioStreamBasicDescription)) { ERR("AudioUnitGetProperty failed\n"); @@ -186,19 +167,19 @@ static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) #endif /* set default output unit's input side to match output side */ - err = AudioUnitSetProperty(self->mAudioUnit, kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Input, 0, &streamFormat, size); + err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, + 0, &streamFormat, size); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); return ALC_FALSE; } - if(device->Frequency != streamFormat.mSampleRate) + if(mDevice->Frequency != streamFormat.mSampleRate) { - device->NumUpdates = static_cast<ALuint>( - (ALuint64)device->NumUpdates*streamFormat.mSampleRate/device->Frequency); - device->Frequency = streamFormat.mSampleRate; + mDevice->NumUpdates = static_cast<ALuint>( + (ALuint64)mDevice->NumUpdates*streamFormat.mSampleRate/mDevice->Frequency); + mDevice->Frequency = streamFormat.mSampleRate; } /* FIXME: How to tell what channels are what in the output device, and how @@ -206,53 +187,53 @@ static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) switch(streamFormat.mChannelsPerFrame) { case 1: - device->FmtChans = DevFmtMono; + mDevice->FmtChans = DevFmtMono; break; case 2: - device->FmtChans = DevFmtStereo; + mDevice->FmtChans = DevFmtStereo; break; case 4: - device->FmtChans = DevFmtQuad; + mDevice->FmtChans = DevFmtQuad; break; case 6: - device->FmtChans = DevFmtX51; + mDevice->FmtChans = DevFmtX51; break; case 7: - device->FmtChans = DevFmtX61; + mDevice->FmtChans = DevFmtX61; break; case 8: - device->FmtChans = DevFmtX71; + mDevice->FmtChans = DevFmtX71; break; default: ERR("Unhandled channel count (%d), using Stereo\n", streamFormat.mChannelsPerFrame); - device->FmtChans = DevFmtStereo; + mDevice->FmtChans = DevFmtStereo; streamFormat.mChannelsPerFrame = 2; break; } - SetDefaultWFXChannelOrder(device); + SetDefaultWFXChannelOrder(mDevice); /* use channel count and sample rate from the default output unit's current * parameters, but reset everything else */ streamFormat.mFramesPerPacket = 1; streamFormat.mFormatFlags = 0; - switch(device->FmtType) + switch(mDevice->FmtType) { case DevFmtUByte: - device->FmtType = DevFmtByte; + mDevice->FmtType = DevFmtByte; /* fall-through */ case DevFmtByte: streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; streamFormat.mBitsPerChannel = 8; break; case DevFmtUShort: - device->FmtType = DevFmtShort; + mDevice->FmtType = DevFmtShort; /* fall-through */ case DevFmtShort: streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; streamFormat.mBitsPerChannel = 16; break; case DevFmtUInt: - device->FmtType = DevFmtInt; + mDevice->FmtType = DevFmtInt; /* fall-through */ case DevFmtInt: streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; @@ -270,8 +251,8 @@ static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) streamFormat.mFormatFlags |= kAudioFormatFlagsNativeEndian | kLinearPCMFormatFlagIsPacked; - err = AudioUnitSetProperty(self->mAudioUnit, kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Input, 0, &streamFormat, sizeof(AudioStreamBasicDescription)); + err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, + 0, &streamFormat, sizeof(AudioStreamBasicDescription)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); @@ -279,12 +260,12 @@ static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) } /* setup callback */ - self->mFrameSize = device->frameSizeFromFmt(); + mFrameSize = mDevice->frameSizeFromFmt(); AURenderCallbackStruct input{}; - input.inputProc = ALCcoreAudioPlayback::MixerProcC; - input.inputProcRefCon = self; + input.inputProc = CoreAudioPlayback::MixerProcC; + input.inputProcRefCon = this; - err = AudioUnitSetProperty(self->mAudioUnit, kAudioUnitProperty_SetRenderCallback, + err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &input, sizeof(AURenderCallbackStruct)); if(err != noErr) { @@ -293,7 +274,7 @@ static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) } /* init the default audio unit... */ - err = AudioUnitInitialize(self->mAudioUnit); + err = AudioUnitInitialize(mAudioUnit); if(err != noErr) { ERR("AudioUnitInitialize failed\n"); @@ -303,9 +284,9 @@ static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) return ALC_TRUE; } -static ALCboolean ALCcoreAudioPlayback_start(ALCcoreAudioPlayback *self) +ALCboolean CoreAudioPlayback::start() { - OSStatus err{AudioOutputUnitStart(self->mAudioUnit)}; + OSStatus err{AudioOutputUnitStart(mAudioUnit)}; if(err != noErr) { ERR("AudioOutputUnitStart failed\n"); @@ -314,17 +295,17 @@ static ALCboolean ALCcoreAudioPlayback_start(ALCcoreAudioPlayback *self) return ALC_TRUE; } -static void ALCcoreAudioPlayback_stop(ALCcoreAudioPlayback *self) +void CoreAudioPlayback::stop() { - OSStatus err{AudioOutputUnitStop(self->mAudioUnit)}; + OSStatus err{AudioOutputUnitStop(mAudioUnit)}; if(err != noErr) ERR("AudioOutputUnitStop failed\n"); } -struct ALCcoreAudioCapture final : public ALCbackend { - ALCcoreAudioCapture(ALCdevice *device) noexcept : ALCbackend{device} { } - ~ALCcoreAudioCapture() override; +struct CoreAudioCapture final : public BackendBase { + CoreAudioCapture(ALCdevice *device) noexcept : BackendBase{device} { } + ~CoreAudioCapture() override; static OSStatus RecordProcC(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, @@ -333,6 +314,12 @@ struct ALCcoreAudioCapture final : public ALCbackend { const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData); + ALCenum open(const ALCchar *name) override; + ALCboolean start() override; + void stop() override; + ALCenum captureSamples(void *buffer, ALCuint samples) override; + ALCuint availableSamples() override; + AudioUnit mAudioUnit{0}; ALuint mFrameSize{0u}; @@ -341,34 +328,12 @@ struct ALCcoreAudioCapture final : public ALCbackend { SampleConverterPtr mConverter; RingBufferPtr mRing{nullptr}; -}; - -static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice *device); -static void ALCcoreAudioCapture_Destruct(ALCcoreAudioCapture *self); -static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar *name); -static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, ALCboolean, reset) -static ALCboolean ALCcoreAudioCapture_start(ALCcoreAudioCapture *self); -static void ALCcoreAudioCapture_stop(ALCcoreAudioCapture *self); -static ALCenum ALCcoreAudioCapture_captureSamples(ALCcoreAudioCapture *self, ALCvoid *buffer, ALCuint samples); -static ALCuint ALCcoreAudioCapture_availableSamples(ALCcoreAudioCapture *self); -static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCcoreAudioCapture) -DEFINE_ALCBACKEND_VTABLE(ALCcoreAudioCapture); - - -static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice *device) -{ - new (self) ALCcoreAudioCapture{device}; - SET_VTABLE2(ALCcoreAudioCapture, ALCbackend, self); -} - -static void ALCcoreAudioCapture_Destruct(ALCcoreAudioCapture *self) -{ self->~ALCcoreAudioCapture(); } + static constexpr inline const char *CurrentPrefix() noexcept { return "CoreAudioCapture::"; } + DEF_NEWDEL(CoreAudioCapture) +}; -ALCcoreAudioCapture::~ALCcoreAudioCapture() +CoreAudioCapture::~CoreAudioCapture() { if(mAudioUnit) AudioComponentInstanceDispose(mAudioUnit); @@ -376,17 +341,17 @@ ALCcoreAudioCapture::~ALCcoreAudioCapture() } -OSStatus ALCcoreAudioCapture::RecordProcC(void *inRefCon, +OSStatus CoreAudioCapture::RecordProcC(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) { - return static_cast<ALCcoreAudioCapture*>(inRefCon)->RecordProc(ioActionFlags, inTimeStamp, + return static_cast<CoreAudioCapture*>(inRefCon)->RecordProc(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData); } -OSStatus ALCcoreAudioCapture::RecordProc(AudioUnitRenderActionFlags *ioActionFlags, - const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, - AudioBufferList *ioData) +OSStatus CoreAudioCapture::RecordProc(AudioUnitRenderActionFlags* UNUSED(ioActionFlags), + const AudioTimeStamp *inTimeStamp, UInt32 UNUSED(inBusNumber), UInt32 inNumberFrames, + AudioBufferList* UNUSED(ioData)) { AudioUnitRenderActionFlags flags = 0; union { @@ -430,9 +395,8 @@ OSStatus ALCcoreAudioCapture::RecordProc(AudioUnitRenderActionFlags *ioActionFla } -static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar *name) +ALCenum CoreAudioCapture::open(const ALCchar *name) { - ALCdevice *device{self->mDevice}; AudioStreamBasicDescription requestedFormat; // The application requested format AudioStreamBasicDescription hardwareFormat; // The hardware format AudioStreamBasicDescription outputFormat; // The AudioUnit output format @@ -469,7 +433,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar } // Open the component - err = AudioComponentInstanceNew(comp, &self->mAudioUnit); + err = AudioComponentInstanceNew(comp, &mAudioUnit); if(err != noErr) { ERR("AudioComponentInstanceNew failed\n"); @@ -478,7 +442,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar // Turn off AudioUnit output enableIO = 0; - err = AudioUnitSetProperty(self->mAudioUnit, kAudioOutputUnitProperty_EnableIO, + err = AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(ALuint)); if(err != noErr) { @@ -488,7 +452,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar // Turn on AudioUnit input enableIO = 1; - err = AudioUnitSetProperty(self->mAudioUnit, kAudioOutputUnitProperty_EnableIO, + err = AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(ALuint)); if(err != noErr) { @@ -519,7 +483,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar } // Track the input device - err = AudioUnitSetProperty(self->mAudioUnit, kAudioOutputUnitProperty_CurrentDevice, + err = AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &inputDevice, sizeof(AudioDeviceID)); if(err != noErr) { @@ -530,10 +494,10 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar #endif // set capture callback - input.inputProc = ALCcoreAudioCapture::RecordProcC; - input.inputProcRefCon = self; + input.inputProc = CoreAudioCapture::RecordProcC; + input.inputProcRefCon = this; - err = AudioUnitSetProperty(self->mAudioUnit, kAudioOutputUnitProperty_SetInputCallback, + err = AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &input, sizeof(AURenderCallbackStruct)); if(err != noErr) { @@ -542,7 +506,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar } // Initialize the device - err = AudioUnitInitialize(self->mAudioUnit); + err = AudioUnitInitialize(mAudioUnit); if(err != noErr) { ERR("AudioUnitInitialize failed\n"); @@ -551,8 +515,8 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar // Get the hardware format propertySize = sizeof(AudioStreamBasicDescription); - err = AudioUnitGetProperty(self->mAudioUnit, kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Input, 1, &hardwareFormat, &propertySize); + err = AudioUnitGetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, + 1, &hardwareFormat, &propertySize); if(err != noErr || propertySize != sizeof(AudioStreamBasicDescription)) { ERR("AudioUnitGetProperty failed\n"); @@ -560,7 +524,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar } // Set up the requested format description - switch(device->FmtType) + switch(mDevice->FmtType) { case DevFmtUByte: requestedFormat.mBitsPerChannel = 8; @@ -581,11 +545,11 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar case DevFmtByte: case DevFmtUShort: case DevFmtUInt: - ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType)); + ERR("%s samples not supported\n", DevFmtTypeString(mDevice->FmtType)); return ALC_INVALID_VALUE; } - switch(device->FmtChans) + switch(mDevice->FmtChans) { case DevFmtMono: requestedFormat.mChannelsPerFrame = 1; @@ -600,20 +564,20 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar case DevFmtX61: case DevFmtX71: case DevFmtAmbi3D: - ERR("%s not supported\n", DevFmtChannelsString(device->FmtChans)); + ERR("%s not supported\n", DevFmtChannelsString(mDevice->FmtChans)); return ALC_INVALID_VALUE; } requestedFormat.mBytesPerFrame = requestedFormat.mChannelsPerFrame * requestedFormat.mBitsPerChannel / 8; requestedFormat.mBytesPerPacket = requestedFormat.mBytesPerFrame; - requestedFormat.mSampleRate = device->Frequency; + requestedFormat.mSampleRate = mDevice->Frequency; requestedFormat.mFormatID = kAudioFormatLinearPCM; requestedFormat.mReserved = 0; requestedFormat.mFramesPerPacket = 1; // save requested format description for later use - self->mFormat = requestedFormat; - self->mFrameSize = device->frameSizeFromFmt(); + mFormat = requestedFormat; + mFrameSize = mDevice->frameSizeFromFmt(); // Use intermediate format for sample rate conversion (outputFormat) // Set sample rate to the same as hardware for resampling later @@ -622,8 +586,8 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar // The output format should be the requested format, but using the hardware sample rate // This is because the AudioUnit will automatically scale other properties, except for sample rate - err = AudioUnitSetProperty(self->mAudioUnit, kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Output, 1, (void *)&outputFormat, sizeof(outputFormat)); + err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, + 1, (void*)&outputFormat, sizeof(outputFormat)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); @@ -631,9 +595,9 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar } // Set the AudioUnit output format frame count - ALuint64 FrameCount64{device->UpdateSize}; - FrameCount64 = (FrameCount64*outputFormat.mSampleRate + device->Frequency-1) / - device->Frequency; + ALuint64 FrameCount64{mDevice->UpdateSize}; + FrameCount64 = (FrameCount64*outputFormat.mSampleRate + mDevice->Frequency-1) / + mDevice->Frequency; FrameCount64 += MAX_RESAMPLE_PADDING*2; if(FrameCount64 > std::numeric_limits<uint32_t>::max()/2) { @@ -642,7 +606,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar } outputFrameCount = static_cast<uint32_t>(FrameCount64); - err = AudioUnitSetProperty(self->mAudioUnit, kAudioUnitProperty_MaximumFramesPerSlice, + err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Output, 0, &outputFrameCount, sizeof(outputFrameCount)); if(err != noErr) { @@ -651,22 +615,22 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar } // Set up sample converter if needed - if(outputFormat.mSampleRate != device->Frequency) - self->mConverter = CreateSampleConverter(device->FmtType, device->FmtType, - self->mFormat.mChannelsPerFrame, hardwareFormat.mSampleRate, device->Frequency, + if(outputFormat.mSampleRate != mDevice->Frequency) + mConverter = CreateSampleConverter(mDevice->FmtType, mDevice->FmtType, + mFormat.mChannelsPerFrame, hardwareFormat.mSampleRate, mDevice->Frequency, BSinc24Resampler); - self->mRing = CreateRingBuffer(outputFrameCount, self->mFrameSize, false); - if(!self->mRing) return ALC_INVALID_VALUE; + mRing = CreateRingBuffer(outputFrameCount, mFrameSize, false); + if(!mRing) return ALC_INVALID_VALUE; - device->DeviceName = name; + mDevice->DeviceName = name; return ALC_NO_ERROR; } -static ALCboolean ALCcoreAudioCapture_start(ALCcoreAudioCapture *self) +ALCboolean CoreAudioCapture::start() { - OSStatus err{AudioOutputUnitStart(self->mAudioUnit)}; + OSStatus err{AudioOutputUnitStart(mAudioUnit)}; if(err != noErr) { ERR("AudioOutputUnitStart failed\n"); @@ -675,48 +639,44 @@ static ALCboolean ALCcoreAudioCapture_start(ALCcoreAudioCapture *self) return ALC_TRUE; } -static void ALCcoreAudioCapture_stop(ALCcoreAudioCapture *self) +void CoreAudioCapture::stop() { - OSStatus err{AudioOutputUnitStop(self->mAudioUnit)}; + OSStatus err{AudioOutputUnitStop(mAudioUnit)}; if(err != noErr) ERR("AudioOutputUnitStop failed\n"); } -static ALCenum ALCcoreAudioCapture_captureSamples(ALCcoreAudioCapture *self, ALCvoid *buffer, ALCuint samples) +ALCenum CoreAudioCapture::captureSamples(void *buffer, ALCuint samples) { - RingBuffer *ring{self->mRing.get()}; - - if(!self->mConverter) + if(!mConverter) { - ring->read(buffer, samples); + mRing->read(buffer, samples); return ALC_NO_ERROR; } - auto rec_vec = ring->getReadVector(); + auto rec_vec = mRing->getReadVector(); const void *src0{rec_vec.first.buf}; auto src0len = static_cast<ALsizei>(rec_vec.first.len); - auto got = static_cast<ALuint>(SampleConverterInput(self->mConverter.get(), &src0, &src0len, + auto got = static_cast<ALuint>(SampleConverterInput(mConverter.get(), &src0, &src0len, buffer, samples)); size_t total_read{rec_vec.first.len - src0len}; if(got < samples && !src0len && rec_vec.second.len > 0) { const void *src1{rec_vec.second.buf}; auto src1len = static_cast<ALsizei>(rec_vec.second.len); - got += static_cast<ALuint>(SampleConverterInput(self->mConverter.get(), &src1, &src1len, + got += static_cast<ALuint>(SampleConverterInput(mConverter.get(), &src1, &src1len, static_cast<char*>(buffer)+got, samples-got)); total_read += rec_vec.second.len - src1len; } - ring->readAdvance(total_read); + mRing->readAdvance(total_read); return ALC_NO_ERROR; } -static ALCuint ALCcoreAudioCapture_availableSamples(ALCcoreAudioCapture *self) +ALCuint CoreAudioCapture::availableSamples() { - RingBuffer *ring{self->mRing.get()}; - - if(!self->mConverter) return ring->readSpace(); - return SampleConverterAvailableOut(self->mConverter.get(), ring->readSpace()); + if(!mConverter) return mRing->readSpace(); + return SampleConverterAvailableOut(mConverter.get(), mRing->readSpace()); } } // namespace @@ -744,20 +704,11 @@ void CoreAudioBackendFactory::probe(DevProbe type, std::string *outnames) } } -ALCbackend *CoreAudioBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *CoreAudioBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) - { - ALCcoreAudioPlayback *backend; - NEW_OBJ(backend, ALCcoreAudioPlayback)(device); - return backend; - } + return new CoreAudioPlayback{device}; if(type == ALCbackend_Capture) - { - ALCcoreAudioCapture *backend; - NEW_OBJ(backend, ALCcoreAudioCapture)(device); - return backend; - } - + return new CoreAudioCapture{device}; return nullptr; } diff --git a/Alc/backends/coreaudio.h b/Alc/backends/coreaudio.h index bc9c492c..db151b8a 100644 --- a/Alc/backends/coreaudio.h +++ b/Alc/backends/coreaudio.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index 832068ad..44e6fde4 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -184,12 +184,17 @@ BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHAR* UNUS } -struct ALCdsoundPlayback final : public ALCbackend { - ALCdsoundPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } - ~ALCdsoundPlayback() override; +struct DSoundPlayback final : public BackendBase { + DSoundPlayback(ALCdevice *device) noexcept : BackendBase{device} { } + ~DSoundPlayback() override; int mixerProc(); + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + IDirectSound *mDS{nullptr}; IDirectSoundBuffer *mPrimaryBuffer{nullptr}; IDirectSoundBuffer *mBuffer{nullptr}; @@ -198,34 +203,12 @@ struct ALCdsoundPlayback final : public ALCbackend { std::atomic<ALenum> mKillNow{AL_TRUE}; std::thread mThread; -}; - -void ALCdsoundPlayback_Construct(ALCdsoundPlayback *self, ALCdevice *device); -void ALCdsoundPlayback_Destruct(ALCdsoundPlayback *self); -ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *name); -ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self); -ALCboolean ALCdsoundPlayback_start(ALCdsoundPlayback *self); -void ALCdsoundPlayback_stop(ALCdsoundPlayback *self); -DECLARE_FORWARD2(ALCdsoundPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, ALCuint, availableSamples) -DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, void, lock) -DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCdsoundPlayback) - -DEFINE_ALCBACKEND_VTABLE(ALCdsoundPlayback); - -void ALCdsoundPlayback_Construct(ALCdsoundPlayback *self, ALCdevice *device) -{ - new (self) ALCdsoundPlayback{device}; - SET_VTABLE2(ALCdsoundPlayback, ALCbackend, self); -} - -void ALCdsoundPlayback_Destruct(ALCdsoundPlayback *self) -{ self->~ALCdsoundPlayback(); } + static constexpr inline const char *CurrentPrefix() noexcept { return "DSoundPlayback::"; } + DEF_NEWDEL(DSoundPlayback) +}; -ALCdsoundPlayback::~ALCdsoundPlayback() +DSoundPlayback::~DSoundPlayback() { if(mNotifies) mNotifies->Release(); @@ -246,7 +229,7 @@ ALCdsoundPlayback::~ALCdsoundPlayback() } -FORCE_ALIGN int ALCdsoundPlayback::mixerProc() +FORCE_ALIGN int DSoundPlayback::mixerProc() { SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); @@ -257,9 +240,9 @@ FORCE_ALIGN int ALCdsoundPlayback::mixerProc() if(FAILED(err)) { ERR("Failed to get buffer caps: 0x%lx\n", err); - ALCdsoundPlayback_lock(this); + lock(); aluHandleDisconnect(mDevice, "Failure retrieving playback buffer info: 0x%lx", err); - ALCdsoundPlayback_unlock(this); + unlock(); return 1; } @@ -285,9 +268,9 @@ FORCE_ALIGN int ALCdsoundPlayback::mixerProc() if(FAILED(err)) { ERR("Failed to play buffer: 0x%lx\n", err); - ALCdsoundPlayback_lock(this); + lock(); aluHandleDisconnect(mDevice, "Failure starting playback: 0x%lx", err); - ALCdsoundPlayback_unlock(this); + unlock(); return 1; } Playing = true; @@ -319,25 +302,22 @@ FORCE_ALIGN int ALCdsoundPlayback::mixerProc() } } - // Successfully locked the output buffer if(SUCCEEDED(err)) { - // If we have an active context, mix data directly into output buffer otherwise fill with silence - ALCdsoundPlayback_lock(this); + lock(); aluMixData(mDevice, WritePtr1, WriteCnt1/FrameSize); if(WriteCnt2 > 0) aluMixData(mDevice, WritePtr2, WriteCnt2/FrameSize); - ALCdsoundPlayback_unlock(this); + unlock(); - // Unlock output buffer only when successfully locked mBuffer->Unlock(WritePtr1, WriteCnt1, WritePtr2, WriteCnt2); } else { ERR("Buffer lock error: %#lx\n", err); - ALCdsoundPlayback_lock(this); + lock(); aluHandleDisconnect(mDevice, "Failed to lock output buffer: 0x%lx", err); - ALCdsoundPlayback_unlock(this); + unlock(); return 1; } @@ -349,10 +329,8 @@ FORCE_ALIGN int ALCdsoundPlayback::mixerProc() return 0; } -ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *deviceName) +ALCenum DSoundPlayback::open(const ALCchar *name) { - ALCdevice *device{self->mDevice}; - HRESULT hr; if(PlaybackDevices.empty()) { @@ -366,16 +344,16 @@ ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *deviceNam } const GUID *guid{nullptr}; - if(!deviceName && !PlaybackDevices.empty()) + if(!name && !PlaybackDevices.empty()) { - deviceName = PlaybackDevices[0].name.c_str(); + name = PlaybackDevices[0].name.c_str(); guid = &PlaybackDevices[0].guid; } else { auto iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), - [deviceName](const DevMap &entry) -> bool - { return entry.name == deviceName; } + [name](const DevMap &entry) -> bool + { return entry.name == name; } ); if(iter == PlaybackDevices.cend()) return ALC_INVALID_VALUE; @@ -383,52 +361,50 @@ ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *deviceNam } hr = DS_OK; - self->mNotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); - if(!self->mNotifyEvent) hr = E_FAIL; + mNotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); + if(!mNotifyEvent) hr = E_FAIL; //DirectSound Init code if(SUCCEEDED(hr)) - hr = DirectSoundCreate(guid, &self->mDS, nullptr); + hr = DirectSoundCreate(guid, &mDS, nullptr); if(SUCCEEDED(hr)) - hr = self->mDS->SetCooperativeLevel(GetForegroundWindow(), DSSCL_PRIORITY); + hr = mDS->SetCooperativeLevel(GetForegroundWindow(), DSSCL_PRIORITY); if(FAILED(hr)) { ERR("Device init failed: 0x%08lx\n", hr); return ALC_INVALID_VALUE; } - device->DeviceName = deviceName; + mDevice->DeviceName = name; return ALC_NO_ERROR; } -ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self) +ALCboolean DSoundPlayback::reset() { - ALCdevice *device{self->mDevice}; - - if(self->mNotifies) - self->mNotifies->Release(); - self->mNotifies = nullptr; - if(self->mBuffer) - self->mBuffer->Release(); - self->mBuffer = nullptr; - if(self->mPrimaryBuffer) - self->mPrimaryBuffer->Release(); - self->mPrimaryBuffer = nullptr; + if(mNotifies) + mNotifies->Release(); + mNotifies = nullptr; + if(mBuffer) + mBuffer->Release(); + mBuffer = nullptr; + if(mPrimaryBuffer) + mPrimaryBuffer->Release(); + mPrimaryBuffer = nullptr; - switch(device->FmtType) + switch(mDevice->FmtType) { case DevFmtByte: - device->FmtType = DevFmtUByte; + mDevice->FmtType = DevFmtUByte; break; case DevFmtFloat: - if((device->Flags&DEVICE_SAMPLE_TYPE_REQUEST)) + if((mDevice->Flags&DEVICE_SAMPLE_TYPE_REQUEST)) break; /* fall-through */ case DevFmtUShort: - device->FmtType = DevFmtShort; + mDevice->FmtType = DevFmtShort; break; case DevFmtUInt: - device->FmtType = DevFmtInt; + mDevice->FmtType = DevFmtInt; break; case DevFmtUByte: case DevFmtShort: @@ -438,37 +414,37 @@ ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self) WAVEFORMATEXTENSIBLE OutputType{}; DWORD speakers; - HRESULT hr{self->mDS->GetSpeakerConfig(&speakers)}; + HRESULT hr{mDS->GetSpeakerConfig(&speakers)}; if(SUCCEEDED(hr)) { speakers = DSSPEAKER_CONFIG(speakers); - if(!(device->Flags&DEVICE_CHANNELS_REQUEST)) + if(!(mDevice->Flags&DEVICE_CHANNELS_REQUEST)) { if(speakers == DSSPEAKER_MONO) - device->FmtChans = DevFmtMono; + mDevice->FmtChans = DevFmtMono; else if(speakers == DSSPEAKER_STEREO || speakers == DSSPEAKER_HEADPHONE) - device->FmtChans = DevFmtStereo; + mDevice->FmtChans = DevFmtStereo; else if(speakers == DSSPEAKER_QUAD) - device->FmtChans = DevFmtQuad; + mDevice->FmtChans = DevFmtQuad; else if(speakers == DSSPEAKER_5POINT1_SURROUND) - device->FmtChans = DevFmtX51; + mDevice->FmtChans = DevFmtX51; else if(speakers == DSSPEAKER_5POINT1_BACK) - device->FmtChans = DevFmtX51Rear; + mDevice->FmtChans = DevFmtX51Rear; else if(speakers == DSSPEAKER_7POINT1 || speakers == DSSPEAKER_7POINT1_SURROUND) - device->FmtChans = DevFmtX71; + mDevice->FmtChans = DevFmtX71; else ERR("Unknown system speaker config: 0x%lx\n", speakers); } - device->IsHeadphones = (device->FmtChans == DevFmtStereo && - speakers == DSSPEAKER_HEADPHONE); + mDevice->IsHeadphones = (mDevice->FmtChans == DevFmtStereo && + speakers == DSSPEAKER_HEADPHONE); - switch(device->FmtChans) + switch(mDevice->FmtChans) { case DevFmtMono: OutputType.dwChannelMask = SPEAKER_FRONT_CENTER; break; case DevFmtAmbi3D: - device->FmtChans = DevFmtStereo; + mDevice->FmtChans = DevFmtStereo; /*fall-through*/ case DevFmtStereo: OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | @@ -520,62 +496,62 @@ ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self) retry_open: hr = S_OK; OutputType.Format.wFormatTag = WAVE_FORMAT_PCM; - OutputType.Format.nChannels = device->channelsFromFmt(); - OutputType.Format.wBitsPerSample = device->bytesFromFmt() * 8; + OutputType.Format.nChannels = mDevice->channelsFromFmt(); + OutputType.Format.wBitsPerSample = mDevice->bytesFromFmt() * 8; OutputType.Format.nBlockAlign = OutputType.Format.nChannels*OutputType.Format.wBitsPerSample/8; - OutputType.Format.nSamplesPerSec = device->Frequency; + OutputType.Format.nSamplesPerSec = mDevice->Frequency; OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec*OutputType.Format.nBlockAlign; OutputType.Format.cbSize = 0; } - if(OutputType.Format.nChannels > 2 || device->FmtType == DevFmtFloat) + if(OutputType.Format.nChannels > 2 || mDevice->FmtType == DevFmtFloat) { OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; OutputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); - if(device->FmtType == DevFmtFloat) + if(mDevice->FmtType == DevFmtFloat) OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; else OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - if(self->mPrimaryBuffer) - self->mPrimaryBuffer->Release(); - self->mPrimaryBuffer = nullptr; + if(mPrimaryBuffer) + mPrimaryBuffer->Release(); + mPrimaryBuffer = nullptr; } else { - if(SUCCEEDED(hr) && !self->mPrimaryBuffer) + if(SUCCEEDED(hr) && !mPrimaryBuffer) { DSBUFFERDESC DSBDescription{}; DSBDescription.dwSize = sizeof(DSBDescription); DSBDescription.dwFlags = DSBCAPS_PRIMARYBUFFER; - hr = self->mDS->CreateSoundBuffer(&DSBDescription, &self->mPrimaryBuffer, nullptr); + hr = mDS->CreateSoundBuffer(&DSBDescription, &mPrimaryBuffer, nullptr); } if(SUCCEEDED(hr)) - hr = self->mPrimaryBuffer->SetFormat(&OutputType.Format); + hr = mPrimaryBuffer->SetFormat(&OutputType.Format); } if(SUCCEEDED(hr)) { - if(device->NumUpdates > MAX_UPDATES) + if(mDevice->NumUpdates > MAX_UPDATES) { - device->UpdateSize = (device->UpdateSize*device->NumUpdates + - MAX_UPDATES-1) / MAX_UPDATES; - device->NumUpdates = MAX_UPDATES; + mDevice->UpdateSize = (mDevice->UpdateSize*mDevice->NumUpdates + MAX_UPDATES-1) / + MAX_UPDATES; + mDevice->NumUpdates = MAX_UPDATES; } DSBUFFERDESC DSBDescription{}; DSBDescription.dwSize = sizeof(DSBDescription); DSBDescription.dwFlags = DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS; - DSBDescription.dwBufferBytes = device->UpdateSize * device->NumUpdates * + DSBDescription.dwBufferBytes = mDevice->UpdateSize * mDevice->NumUpdates * OutputType.Format.nBlockAlign; DSBDescription.lpwfxFormat = &OutputType.Format; - hr = self->mDS->CreateSoundBuffer(&DSBDescription, &self->mBuffer, nullptr); - if(FAILED(hr) && device->FmtType == DevFmtFloat) + hr = mDS->CreateSoundBuffer(&DSBDescription, &mBuffer, nullptr); + if(FAILED(hr) && mDevice->FmtType == DevFmtFloat) { - device->FmtType = DevFmtShort; + mDevice->FmtType = DevFmtShort; goto retry_open; } } @@ -583,50 +559,50 @@ retry_open: if(SUCCEEDED(hr)) { void *ptr; - hr = self->mBuffer->QueryInterface(IID_IDirectSoundNotify, &ptr); + hr = mBuffer->QueryInterface(IID_IDirectSoundNotify, &ptr); if(SUCCEEDED(hr)) { auto Notifies = static_cast<IDirectSoundNotify*>(ptr); - self->mNotifies = Notifies; + mNotifies = Notifies; - device->NumUpdates = minu(device->NumUpdates, MAX_UPDATES); + mDevice->NumUpdates = minu(mDevice->NumUpdates, MAX_UPDATES); std::array<DSBPOSITIONNOTIFY,MAX_UPDATES> nots; - for(ALuint i{0};i < device->NumUpdates;++i) + for(ALuint i{0};i < mDevice->NumUpdates;++i) { - nots[i].dwOffset = i * device->UpdateSize * OutputType.Format.nBlockAlign; - nots[i].hEventNotify = self->mNotifyEvent; + nots[i].dwOffset = i * mDevice->UpdateSize * OutputType.Format.nBlockAlign; + nots[i].hEventNotify = mNotifyEvent; } - if(Notifies->SetNotificationPositions(device->NumUpdates, nots.data()) != DS_OK) + if(Notifies->SetNotificationPositions(mDevice->NumUpdates, nots.data()) != DS_OK) hr = E_FAIL; } } if(FAILED(hr)) { - if(self->mNotifies) - self->mNotifies->Release(); - self->mNotifies = nullptr; - if(self->mBuffer) - self->mBuffer->Release(); - self->mBuffer = nullptr; - if(self->mPrimaryBuffer) - self->mPrimaryBuffer->Release(); - self->mPrimaryBuffer = nullptr; + if(mNotifies) + mNotifies->Release(); + mNotifies = nullptr; + if(mBuffer) + mBuffer->Release(); + mBuffer = nullptr; + if(mPrimaryBuffer) + mPrimaryBuffer->Release(); + mPrimaryBuffer = nullptr; return ALC_FALSE; } - ResetEvent(self->mNotifyEvent); - SetDefaultWFXChannelOrder(device); + ResetEvent(mNotifyEvent); + SetDefaultWFXChannelOrder(mDevice); return ALC_TRUE; } -ALCboolean ALCdsoundPlayback_start(ALCdsoundPlayback *self) +ALCboolean DSoundPlayback::start() { try { - self->mKillNow.store(AL_FALSE, std::memory_order_release); - self->mThread = std::thread(std::mem_fn(&ALCdsoundPlayback::mixerProc), self); + mKillNow.store(AL_FALSE, std::memory_order_release); + mThread = std::thread{std::mem_fn(&DSoundPlayback::mixerProc), this}; return ALC_TRUE; } catch(std::exception& e) { @@ -637,20 +613,25 @@ ALCboolean ALCdsoundPlayback_start(ALCdsoundPlayback *self) return ALC_FALSE; } -void ALCdsoundPlayback_stop(ALCdsoundPlayback *self) +void DSoundPlayback::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->Stop(); + mBuffer->Stop(); } -struct ALCdsoundCapture final : public ALCbackend { - ALCdsoundCapture(ALCdevice *device) noexcept : ALCbackend{device} { } - ~ALCdsoundCapture() override; +struct DSoundCapture final : public BackendBase { + DSoundCapture(ALCdevice *device) noexcept : BackendBase{device} { } + ~DSoundCapture() override; + + ALCenum open(const ALCchar *name) override; + ALCboolean start() override; + void stop() override; + ALCenum captureSamples(void *buffer, ALCuint samples) override; + ALCuint availableSamples() override; IDirectSoundCapture *mDSC{nullptr}; IDirectSoundCaptureBuffer *mDSCbuffer{nullptr}; @@ -658,32 +639,12 @@ struct ALCdsoundCapture final : public ALCbackend { DWORD mCursor{0u}; RingBufferPtr mRing; -}; - -void ALCdsoundCapture_Construct(ALCdsoundCapture *self, ALCdevice *device); -void ALCdsoundCapture_Destruct(ALCdsoundCapture *self); -ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *name); -DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, ALCboolean, reset) -ALCboolean ALCdsoundCapture_start(ALCdsoundCapture *self); -void ALCdsoundCapture_stop(ALCdsoundCapture *self); -ALCenum ALCdsoundCapture_captureSamples(ALCdsoundCapture *self, ALCvoid *buffer, ALCuint samples); -ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self); -DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, void, lock) -DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCdsoundCapture) -DEFINE_ALCBACKEND_VTABLE(ALCdsoundCapture); - -void ALCdsoundCapture_Construct(ALCdsoundCapture *self, ALCdevice *device) -{ - new (self) ALCdsoundCapture{device}; - SET_VTABLE2(ALCdsoundCapture, ALCbackend, self); -} -void ALCdsoundCapture_Destruct(ALCdsoundCapture *self) -{ self->~ALCdsoundCapture(); } + static constexpr inline const char *CurrentPrefix() noexcept { return "DSoundCapture::"; } + DEF_NEWDEL(DSoundCapture) +}; -ALCdsoundCapture::~ALCdsoundCapture() +DSoundCapture::~DSoundCapture() { if(mDSCbuffer) { @@ -698,10 +659,8 @@ ALCdsoundCapture::~ALCdsoundCapture() } -ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *deviceName) +ALCenum DSoundCapture::open(const ALCchar *name) { - ALCdevice *device{self->mDevice}; - HRESULT hr; if(CaptureDevices.empty()) { @@ -715,28 +674,28 @@ ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *deviceName) } const GUID *guid{nullptr}; - if(!deviceName && !CaptureDevices.empty()) + if(!name && !CaptureDevices.empty()) { - deviceName = CaptureDevices[0].name.c_str(); + name = CaptureDevices[0].name.c_str(); guid = &CaptureDevices[0].guid; } else { auto iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), - [deviceName](const DevMap &entry) -> bool - { return entry.name == deviceName; } + [name](const DevMap &entry) -> bool + { return entry.name == name; } ); if(iter == CaptureDevices.cend()) return ALC_INVALID_VALUE; guid = &iter->guid; } - switch(device->FmtType) + switch(mDevice->FmtType) { case DevFmtByte: case DevFmtUShort: case DevFmtUInt: - WARN("%s capture samples not supported\n", DevFmtTypeString(device->FmtType)); + WARN("%s capture samples not supported\n", DevFmtTypeString(mDevice->FmtType)); return ALC_INVALID_ENUM; case DevFmtUByte: @@ -747,7 +706,7 @@ ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *deviceName) } WAVEFORMATEXTENSIBLE InputType{}; - switch(device->FmtChans) + switch(mDevice->FmtChans) { case DevFmtMono: InputType.dwChannelMask = SPEAKER_FRONT_CENTER; @@ -798,31 +757,31 @@ ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *deviceName) SPEAKER_SIDE_RIGHT; break; case DevFmtAmbi3D: - WARN("%s capture not supported\n", DevFmtChannelsString(device->FmtChans)); + WARN("%s capture not supported\n", DevFmtChannelsString(mDevice->FmtChans)); return ALC_INVALID_ENUM; } InputType.Format.wFormatTag = WAVE_FORMAT_PCM; - InputType.Format.nChannels = device->channelsFromFmt(); - InputType.Format.wBitsPerSample = device->bytesFromFmt() * 8; + InputType.Format.nChannels = mDevice->channelsFromFmt(); + InputType.Format.wBitsPerSample = mDevice->bytesFromFmt() * 8; InputType.Format.nBlockAlign = InputType.Format.nChannels*InputType.Format.wBitsPerSample/8; - InputType.Format.nSamplesPerSec = device->Frequency; + InputType.Format.nSamplesPerSec = mDevice->Frequency; InputType.Format.nAvgBytesPerSec = InputType.Format.nSamplesPerSec*InputType.Format.nBlockAlign; InputType.Format.cbSize = 0; InputType.Samples.wValidBitsPerSample = InputType.Format.wBitsPerSample; - if(device->FmtType == DevFmtFloat) + if(mDevice->FmtType == DevFmtFloat) InputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; else InputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - if(InputType.Format.nChannels > 2 || device->FmtType == DevFmtFloat) + if(InputType.Format.nChannels > 2 || mDevice->FmtType == DevFmtFloat) { InputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; InputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); } - ALuint samples{device->UpdateSize * device->NumUpdates}; - samples = maxu(samples, 100 * device->Frequency / 1000); + ALuint samples{mDevice->UpdateSize * mDevice->NumUpdates}; + samples = maxu(samples, 100 * mDevice->Frequency / 1000); DSCBUFFERDESC DSCBDescription{}; DSCBDescription.dwSize = sizeof(DSCBDescription); @@ -831,107 +790,101 @@ ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *deviceName) DSCBDescription.lpwfxFormat = &InputType.Format; //DirectSoundCapture Init code - hr = DirectSoundCaptureCreate(guid, &self->mDSC, nullptr); + hr = DirectSoundCaptureCreate(guid, &mDSC, nullptr); if(SUCCEEDED(hr)) - self->mDSC->CreateCaptureBuffer(&DSCBDescription, &self->mDSCbuffer, nullptr); + mDSC->CreateCaptureBuffer(&DSCBDescription, &mDSCbuffer, nullptr); if(SUCCEEDED(hr)) { - self->mRing = CreateRingBuffer(device->UpdateSize*device->NumUpdates, + mRing = CreateRingBuffer(mDevice->UpdateSize*mDevice->NumUpdates, InputType.Format.nBlockAlign, false); - if(!self->mRing) hr = DSERR_OUTOFMEMORY; + if(!mRing) hr = DSERR_OUTOFMEMORY; } if(FAILED(hr)) { ERR("Device init failed: 0x%08lx\n", hr); - self->mRing = nullptr; - if(self->mDSCbuffer) - self->mDSCbuffer->Release(); - self->mDSCbuffer = nullptr; - if(self->mDSC) - self->mDSC->Release(); - self->mDSC = nullptr; + mRing = nullptr; + if(mDSCbuffer) + mDSCbuffer->Release(); + mDSCbuffer = nullptr; + if(mDSC) + mDSC->Release(); + mDSC = nullptr; return ALC_INVALID_VALUE; } - self->mBufferBytes = DSCBDescription.dwBufferBytes; - SetDefaultWFXChannelOrder(device); + mBufferBytes = DSCBDescription.dwBufferBytes; + SetDefaultWFXChannelOrder(mDevice); - device->DeviceName = deviceName; + mDevice->DeviceName = name; return ALC_NO_ERROR; } -ALCboolean ALCdsoundCapture_start(ALCdsoundCapture *self) +ALCboolean DSoundCapture::start() { - HRESULT hr{self->mDSCbuffer->Start(DSCBSTART_LOOPING)}; + HRESULT hr{mDSCbuffer->Start(DSCBSTART_LOOPING)}; if(FAILED(hr)) { ERR("start failed: 0x%08lx\n", hr); - aluHandleDisconnect(self->mDevice, "Failure starting capture: 0x%lx", hr); + aluHandleDisconnect(mDevice, "Failure starting capture: 0x%lx", hr); return ALC_FALSE; } - return ALC_TRUE; } -void ALCdsoundCapture_stop(ALCdsoundCapture *self) +void DSoundCapture::stop() { - HRESULT hr{self->mDSCbuffer->Stop()}; + HRESULT hr{mDSCbuffer->Stop()}; if(FAILED(hr)) { ERR("stop failed: 0x%08lx\n", hr); - aluHandleDisconnect(self->mDevice, "Failure stopping capture: 0x%lx", hr); + aluHandleDisconnect(mDevice, "Failure stopping capture: 0x%lx", hr); } } -ALCenum ALCdsoundCapture_captureSamples(ALCdsoundCapture *self, ALCvoid *buffer, ALCuint samples) +ALCenum DSoundCapture::captureSamples(void *buffer, ALCuint samples) { - RingBuffer *ring{self->mRing.get()}; - ring->read(buffer, samples); + mRing->read(buffer, samples); return ALC_NO_ERROR; } -ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self) +ALCuint DSoundCapture::availableSamples() { - ALCdevice *device{self->mDevice}; - RingBuffer *ring{self->mRing.get()}; - - if(!device->Connected.load(std::memory_order_acquire)) - return static_cast<ALCuint>(ring->readSpace()); + if(!mDevice->Connected.load(std::memory_order_acquire)) + return static_cast<ALCuint>(mRing->readSpace()); - ALsizei FrameSize{device->frameSizeFromFmt()}; - DWORD BufferBytes{self->mBufferBytes}; - DWORD LastCursor{self->mCursor}; + ALsizei FrameSize{mDevice->frameSizeFromFmt()}; + DWORD BufferBytes{mBufferBytes}; + DWORD LastCursor{mCursor}; DWORD ReadCursor; void *ReadPtr1, *ReadPtr2; DWORD ReadCnt1, ReadCnt2; - HRESULT hr{self->mDSCbuffer->GetCurrentPosition(nullptr, &ReadCursor)}; + HRESULT hr{mDSCbuffer->GetCurrentPosition(nullptr, &ReadCursor)}; if(SUCCEEDED(hr)) { DWORD NumBytes{(ReadCursor-LastCursor + BufferBytes) % BufferBytes}; - if(!NumBytes) return static_cast<ALCubyte>(ring->readSpace()); - hr = self->mDSCbuffer->Lock(LastCursor, NumBytes, &ReadPtr1, &ReadCnt1, - &ReadPtr2, &ReadCnt2, 0); + if(!NumBytes) return static_cast<ALCubyte>(mRing->readSpace()); + hr = mDSCbuffer->Lock(LastCursor, NumBytes, &ReadPtr1, &ReadCnt1, &ReadPtr2, &ReadCnt2, 0); } if(SUCCEEDED(hr)) { - ring->write(ReadPtr1, ReadCnt1/FrameSize); + mRing->write(ReadPtr1, ReadCnt1/FrameSize); if(ReadPtr2 != nullptr && ReadCnt2 > 0) - ring->write(ReadPtr2, ReadCnt2/FrameSize); - hr = self->mDSCbuffer->Unlock(ReadPtr1, ReadCnt1, ReadPtr2, ReadCnt2); - self->mCursor = (LastCursor+ReadCnt1+ReadCnt2) % BufferBytes; + mRing->write(ReadPtr2, ReadCnt2/FrameSize); + hr = mDSCbuffer->Unlock(ReadPtr1, ReadCnt1, ReadPtr2, ReadCnt2); + mCursor = (LastCursor+ReadCnt1+ReadCnt2) % BufferBytes; } if(FAILED(hr)) { ERR("update failed: 0x%08lx\n", hr); - aluHandleDisconnect(device, "Failure retrieving capture data: 0x%lx", hr); + aluHandleDisconnect(mDevice, "Failure retrieving capture data: 0x%lx", hr); } - return static_cast<ALCuint>(ring->readSpace()); + return static_cast<ALCuint>(mRing->readSpace()); } } // namespace @@ -996,21 +949,11 @@ void DSoundBackendFactory::probe(DevProbe type, std::string *outnames) CoUninitialize(); } -ALCbackend *DSoundBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *DSoundBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) - { - ALCdsoundPlayback *backend; - NEW_OBJ(backend, ALCdsoundPlayback)(device); - return backend; - } - + return new DSoundPlayback{device}; if(type == ALCbackend_Capture) - { - ALCdsoundCapture *backend; - NEW_OBJ(backend, ALCdsoundCapture)(device); - return backend; - } - + return new DSoundCapture{device}; return nullptr; } diff --git a/Alc/backends/dsound.h b/Alc/backends/dsound.h index 3911686e..93b76c7c 100644 --- a/Alc/backends/dsound.h +++ b/Alc/backends/dsound.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp index 26086bf9..77bbf487 100644 --- a/Alc/backends/jack.cpp +++ b/Alc/backends/jack.cpp @@ -148,9 +148,9 @@ ALCboolean jack_load(void) } -struct ALCjackPlayback final : public ALCbackend { - ALCjackPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } - ~ALCjackPlayback() override; +struct JackPlayback final : public BackendBase { + JackPlayback(ALCdevice *device) noexcept : BackendBase{device} { } + ~JackPlayback() override; static int bufferSizeNotifyC(jack_nframes_t numframes, void *arg); int bufferSizeNotify(jack_nframes_t numframes); @@ -160,6 +160,12 @@ struct ALCjackPlayback final : public ALCbackend { int mixerProc(); + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + ClockLatency getClockLatency() override; + jack_client_t *mClient{nullptr}; jack_port_t *mPort[MAX_OUTPUT_CHANNELS]{}; @@ -168,34 +174,12 @@ struct ALCjackPlayback final : public ALCbackend { std::atomic<bool> mKillNow{true}; std::thread mThread; -}; - -void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device); -void ALCjackPlayback_Destruct(ALCjackPlayback *self); -ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name); -ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self); -ALCboolean ALCjackPlayback_start(ALCjackPlayback *self); -void ALCjackPlayback_stop(ALCjackPlayback *self); -DECLARE_FORWARD2(ALCjackPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -DECLARE_FORWARD(ALCjackPlayback, ALCbackend, ALCuint, availableSamples) -ClockLatency ALCjackPlayback_getClockLatency(ALCjackPlayback *self); -DECLARE_FORWARD(ALCjackPlayback, ALCbackend, void, lock) -DECLARE_FORWARD(ALCjackPlayback, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCjackPlayback) - -DEFINE_ALCBACKEND_VTABLE(ALCjackPlayback); + static constexpr inline const char *CurrentPrefix() noexcept { return "JackPlayback::"; } + DEF_NEWDEL(JackPlayback) +}; -void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device) -{ - new (self) ALCjackPlayback{device}; - SET_VTABLE2(ALCjackPlayback, ALCbackend, self); -} - -void ALCjackPlayback_Destruct(ALCjackPlayback *self) -{ self->~ALCjackPlayback(); } - -ALCjackPlayback::~ALCjackPlayback() +JackPlayback::~JackPlayback() { if(!mClient) return; @@ -210,12 +194,12 @@ ALCjackPlayback::~ALCjackPlayback() } -int ALCjackPlayback::bufferSizeNotifyC(jack_nframes_t numframes, void *arg) -{ return static_cast<ALCjackPlayback*>(arg)->bufferSizeNotify(numframes); } +int JackPlayback::bufferSizeNotifyC(jack_nframes_t numframes, void *arg) +{ return static_cast<JackPlayback*>(arg)->bufferSizeNotify(numframes); } -int ALCjackPlayback::bufferSizeNotify(jack_nframes_t numframes) +int JackPlayback::bufferSizeNotify(jack_nframes_t numframes) { - ALCjackPlayback_lock(this); + lock(); mDevice->UpdateSize = numframes; mDevice->NumUpdates = 2; @@ -233,15 +217,15 @@ int ALCjackPlayback::bufferSizeNotify(jack_nframes_t numframes) ERR("Failed to reallocate ringbuffer\n"); aluHandleDisconnect(mDevice, "Failed to reallocate %u-sample buffer", bufsize); } - ALCjackPlayback_unlock(this); + unlock(); return 0; } -int ALCjackPlayback::processC(jack_nframes_t numframes, void *arg) -{ return static_cast<ALCjackPlayback*>(arg)->process(numframes); } +int JackPlayback::processC(jack_nframes_t numframes, void *arg) +{ return static_cast<JackPlayback*>(arg)->process(numframes); } -int ALCjackPlayback::process(jack_nframes_t numframes) +int JackPlayback::process(jack_nframes_t numframes) { jack_default_audio_sample_t *out[MAX_OUTPUT_CHANNELS]; ALsizei numchans{0}; @@ -311,20 +295,20 @@ int ALCjackPlayback::process(jack_nframes_t numframes) return 0; } -int ALCjackPlayback::mixerProc() +int JackPlayback::mixerProc() { SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); - ALCjackPlayback_lock(this); + lock(); while(!mKillNow.load(std::memory_order_acquire) && mDevice->Connected.load(std::memory_order_acquire)) { if(mRing->writeSpace() < mDevice->UpdateSize) { - ALCjackPlayback_unlock(this); + unlock(); mSem.wait(); - ALCjackPlayback_lock(this); + lock(); continue; } @@ -340,13 +324,13 @@ int ALCjackPlayback::mixerProc() aluMixData(mDevice, data.second.buf, len2); mRing->writeAdvance(todo); } - ALCjackPlayback_unlock(this); + unlock(); return 0; } -ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name) +ALCenum JackPlayback::open(const ALCchar *name) { if(!name) name = jackDevice; @@ -355,8 +339,8 @@ ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name) const char *client_name{"alsoft"}; jack_status_t status; - self->mClient = jack_client_open(client_name, ClientOptions, &status, nullptr); - if(self->mClient == nullptr) + mClient = jack_client_open(client_name, ClientOptions, &status, nullptr); + if(mClient == nullptr) { ERR("jack_client_open() failed, status = 0x%02x\n", status); return ALC_INVALID_VALUE; @@ -365,104 +349,102 @@ ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name) TRACE("JACK server started\n"); if((status&JackNameNotUnique)) { - client_name = jack_get_client_name(self->mClient); + client_name = jack_get_client_name(mClient); TRACE("Client name not unique, got `%s' instead\n", client_name); } - jack_set_process_callback(self->mClient, &ALCjackPlayback::processC, self); - jack_set_buffer_size_callback(self->mClient, &ALCjackPlayback::bufferSizeNotifyC, self); + jack_set_process_callback(mClient, &JackPlayback::processC, this); + jack_set_buffer_size_callback(mClient, &JackPlayback::bufferSizeNotifyC, this); - ALCdevice *device{self->mDevice}; - device->DeviceName = name; + mDevice->DeviceName = name; return ALC_NO_ERROR; } -ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self) +ALCboolean JackPlayback::reset() { - std::for_each(std::begin(self->mPort), std::end(self->mPort), - [self](jack_port_t *port) -> void - { if(port) jack_port_unregister(self->mClient, port); } + std::for_each(std::begin(mPort), std::end(mPort), + [this](jack_port_t *port) -> void + { if(port) jack_port_unregister(mClient, port); } ); - std::fill(std::begin(self->mPort), std::end(self->mPort), nullptr); + std::fill(std::begin(mPort), std::end(mPort), nullptr); /* Ignore the requested buffer metrics and just keep one JACK-sized buffer * ready for when requested. */ - ALCdevice *device{self->mDevice}; - device->Frequency = jack_get_sample_rate(self->mClient); - device->UpdateSize = jack_get_buffer_size(self->mClient); - device->NumUpdates = 2; + mDevice->Frequency = jack_get_sample_rate(mClient); + mDevice->UpdateSize = jack_get_buffer_size(mClient); + mDevice->NumUpdates = 2; - ALuint bufsize{device->UpdateSize}; - if(ConfigValueUInt(device->DeviceName.c_str(), "jack", "buffer-size", &bufsize)) - bufsize = maxu(NextPowerOf2(bufsize), device->UpdateSize); - device->NumUpdates = (bufsize+device->UpdateSize) / device->UpdateSize; + ALuint bufsize{mDevice->UpdateSize}; + if(ConfigValueUInt(mDevice->DeviceName.c_str(), "jack", "buffer-size", &bufsize)) + bufsize = maxu(NextPowerOf2(bufsize), mDevice->UpdateSize); + mDevice->NumUpdates = (bufsize+mDevice->UpdateSize) / mDevice->UpdateSize; /* Force 32-bit float output. */ - device->FmtType = DevFmtFloat; + mDevice->FmtType = DevFmtFloat; - ALsizei numchans{device->channelsFromFmt()}; - auto ports_end = std::begin(self->mPort) + numchans; - auto bad_port = std::find_if_not(std::begin(self->mPort), ports_end, - [self](jack_port_t *&port) -> bool + ALsizei numchans{mDevice->channelsFromFmt()}; + auto ports_end = std::begin(mPort) + numchans; + auto bad_port = std::find_if_not(std::begin(mPort), ports_end, + [this](jack_port_t *&port) -> bool { - std::string name{"channel_" + std::to_string(&port - self->mPort + 1)}; - port = jack_port_register(self->mClient, name.c_str(), JACK_DEFAULT_AUDIO_TYPE, + std::string name{"channel_" + std::to_string(&port - mPort + 1)}; + port = jack_port_register(mClient, name.c_str(), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); return port != nullptr; } ); if(bad_port != ports_end) { - ERR("Not enough JACK ports available for %s output\n", DevFmtChannelsString(device->FmtChans)); - if(bad_port == std::begin(self->mPort)) return ALC_FALSE; + ERR("Not enough JACK ports available for %s output\n", DevFmtChannelsString(mDevice->FmtChans)); + if(bad_port == std::begin(mPort)) return ALC_FALSE; - if(bad_port == std::begin(self->mPort)+1) - device->FmtChans = DevFmtMono; + if(bad_port == std::begin(mPort)+1) + mDevice->FmtChans = DevFmtMono; else { - ports_end = self->mPort+2; + ports_end = mPort+2; while(bad_port != ports_end) { - jack_port_unregister(self->mClient, *(--bad_port)); + jack_port_unregister(mClient, *(--bad_port)); *bad_port = nullptr; } - device->FmtChans = DevFmtStereo; + mDevice->FmtChans = DevFmtStereo; } - numchans = std::distance(std::begin(self->mPort), bad_port); + numchans = std::distance(std::begin(mPort), bad_port); } - self->mRing = nullptr; - self->mRing = CreateRingBuffer(bufsize, device->frameSizeFromFmt(), true); - if(!self->mRing) + mRing = nullptr; + mRing = CreateRingBuffer(bufsize, mDevice->frameSizeFromFmt(), true); + if(!mRing) { ERR("Failed to allocate ringbuffer\n"); return ALC_FALSE; } - SetDefaultChannelOrder(device); + SetDefaultChannelOrder(mDevice); return ALC_TRUE; } -ALCboolean ALCjackPlayback_start(ALCjackPlayback *self) +ALCboolean JackPlayback::start() { - if(jack_activate(self->mClient)) + if(jack_activate(mClient)) { ERR("Failed to activate client\n"); return ALC_FALSE; } - const char **ports{jack_get_ports(self->mClient, nullptr, nullptr, + const char **ports{jack_get_ports(mClient, nullptr, nullptr, JackPortIsPhysical|JackPortIsInput)}; if(ports == nullptr) { ERR("No physical playback ports found\n"); - jack_deactivate(self->mClient); + jack_deactivate(mClient); return ALC_FALSE; } - std::mismatch(std::begin(self->mPort), std::end(self->mPort), ports, - [self](const jack_port_t *port, const char *pname) -> bool + std::mismatch(std::begin(mPort), std::end(mPort), ports, + [this](const jack_port_t *port, const char *pname) -> bool { if(!port) return false; if(!pname) @@ -470,7 +452,7 @@ ALCboolean ALCjackPlayback_start(ALCjackPlayback *self) ERR("No physical playback port for \"%s\"\n", jack_port_name(port)); return false; } - if(jack_connect(self->mClient, jack_port_name(port), pname)) + if(jack_connect(mClient, jack_port_name(port), pname)) ERR("Failed to connect output port \"%s\" to \"%s\"\n", jack_port_name(port), pname); return true; @@ -479,8 +461,8 @@ ALCboolean ALCjackPlayback_start(ALCjackPlayback *self) jack_free(ports); try { - self->mKillNow.store(false, std::memory_order_release); - self->mThread = std::thread(std::mem_fn(&ALCjackPlayback::mixerProc), self); + mKillNow.store(false, std::memory_order_release); + mThread = std::thread{std::mem_fn(&JackPlayback::mixerProc), this}; return ALC_TRUE; } catch(std::exception& e) { @@ -488,33 +470,31 @@ ALCboolean ALCjackPlayback_start(ALCjackPlayback *self) } catch(...) { } - jack_deactivate(self->mClient); + jack_deactivate(mClient); return ALC_FALSE; } -void ALCjackPlayback_stop(ALCjackPlayback *self) +void JackPlayback::stop() { - if(self->mKillNow.exchange(true, std::memory_order_acq_rel) || !self->mThread.joinable()) + if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) return; - self->mSem.post(); - self->mThread.join(); + mSem.post(); + mThread.join(); - jack_deactivate(self->mClient); + jack_deactivate(mClient); } -ClockLatency ALCjackPlayback_getClockLatency(ALCjackPlayback *self) +ClockLatency JackPlayback::getClockLatency() { ClockLatency ret; - ALCjackPlayback_lock(self); - ALCdevice *device{self->mDevice}; - RingBuffer *ring{self->mRing.get()}; - ret.ClockTime = GetDeviceClockTime(device); - ret.Latency = std::chrono::seconds{ring->readSpace()}; - ret.Latency /= device->Frequency; - ALCjackPlayback_unlock(self); + lock(); + ret.ClockTime = GetDeviceClockTime(mDevice); + ret.Latency = std::chrono::seconds{mRing->readSpace()}; + ret.Latency /= mDevice->Frequency; + unlock(); return ret; } @@ -578,15 +558,10 @@ void JackBackendFactory::probe(DevProbe type, std::string *outnames) } } -ALCbackend *JackBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *JackBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) - { - ALCjackPlayback *backend; - NEW_OBJ(backend, ALCjackPlayback)(device); - return backend; - } - + return new JackPlayback{device}; return nullptr; } diff --git a/Alc/backends/jack.h b/Alc/backends/jack.h index bdf73701..b9bb13b2 100644 --- a/Alc/backends/jack.h +++ b/Alc/backends/jack.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/loopback.cpp b/Alc/backends/loopback.cpp index eadacdfb..373b11c9 100644 --- a/Alc/backends/loopback.cpp +++ b/Alc/backends/loopback.cpp @@ -28,59 +28,35 @@ namespace { -struct ALCloopback final : public ALCbackend { - ALCloopback(ALCdevice *device) noexcept : ALCbackend{device} { } -}; +struct LoopbackBackend final : public BackendBase { + LoopbackBackend(ALCdevice *device) noexcept : BackendBase{device} { } -void ALCloopback_Construct(ALCloopback *self, ALCdevice *device); -void ALCloopback_Destruct(ALCloopback *self); -ALCenum ALCloopback_open(ALCloopback *self, const ALCchar *name); -ALCboolean ALCloopback_reset(ALCloopback *self); -ALCboolean ALCloopback_start(ALCloopback *self); -void ALCloopback_stop(ALCloopback *self); -DECLARE_FORWARD2(ALCloopback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -DECLARE_FORWARD(ALCloopback, ALCbackend, ALCuint, availableSamples) -DECLARE_FORWARD(ALCloopback, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(ALCloopback, ALCbackend, void, lock) -DECLARE_FORWARD(ALCloopback, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCloopback) -DEFINE_ALCBACKEND_VTABLE(ALCloopback); - - -void ALCloopback_Construct(ALCloopback *self, ALCdevice *device) -{ - new (self) ALCloopback{device}; - SET_VTABLE2(ALCloopback, ALCbackend, self); -} + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; -void ALCloopback_Destruct(ALCloopback *self) -{ - self->~ALCloopback(); -} + DEF_NEWDEL(LoopbackBackend) +}; -ALCenum ALCloopback_open(ALCloopback *self, const ALCchar *name) +ALCenum LoopbackBackend::open(const ALCchar *name) { - ALCdevice *device{self->mDevice}; - - device->DeviceName = name; + mDevice->DeviceName = name; return ALC_NO_ERROR; } -ALCboolean ALCloopback_reset(ALCloopback *self) +ALCboolean LoopbackBackend::reset() { - SetDefaultWFXChannelOrder(self->mDevice); + SetDefaultWFXChannelOrder(mDevice); return ALC_TRUE; } -ALCboolean ALCloopback_start(ALCloopback* UNUSED(self)) -{ - return ALC_TRUE; -} +ALCboolean LoopbackBackend::start() +{ return ALC_TRUE; } -void ALCloopback_stop(ALCloopback* UNUSED(self)) -{ -} +void LoopbackBackend::stop() +{ } } // namespace @@ -94,15 +70,10 @@ bool LoopbackBackendFactory::querySupport(ALCbackend_Type type) void LoopbackBackendFactory::probe(DevProbe, std::string*) { } -ALCbackend *LoopbackBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *LoopbackBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Loopback) - { - ALCloopback *backend; - NEW_OBJ(backend, ALCloopback)(device); - return backend; - } - + new LoopbackBackend{device}; return nullptr; } diff --git a/Alc/backends/loopback.h b/Alc/backends/loopback.h index 4607d6ed..ab37c2d7 100644 --- a/Alc/backends/loopback.h +++ b/Alc/backends/loopback.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/null.cpp b/Alc/backends/null.cpp index 5367c46f..33340a5d 100644 --- a/Alc/backends/null.cpp +++ b/Alc/backends/null.cpp @@ -44,42 +44,24 @@ using std::chrono::nanoseconds; constexpr ALCchar nullDevice[] = "No Output"; -struct ALCnullBackend final : public ALCbackend { - ALCnullBackend(ALCdevice *device) noexcept : ALCbackend{device} { } +struct NullBackend final : public BackendBase { + NullBackend(ALCdevice *device) noexcept : BackendBase{device} { } int mixerProc(); + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + std::atomic<ALenum> mKillNow{AL_TRUE}; std::thread mThread; -}; - -void ALCnullBackend_Construct(ALCnullBackend *self, ALCdevice *device); -void ALCnullBackend_Destruct(ALCnullBackend *self); -ALCenum ALCnullBackend_open(ALCnullBackend *self, const ALCchar *name); -ALCboolean ALCnullBackend_reset(ALCnullBackend *self); -ALCboolean ALCnullBackend_start(ALCnullBackend *self); -void ALCnullBackend_stop(ALCnullBackend *self); -DECLARE_FORWARD2(ALCnullBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -DECLARE_FORWARD(ALCnullBackend, ALCbackend, ALCuint, availableSamples) -DECLARE_FORWARD(ALCnullBackend, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(ALCnullBackend, ALCbackend, void, lock) -DECLARE_FORWARD(ALCnullBackend, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCnullBackend) - -DEFINE_ALCBACKEND_VTABLE(ALCnullBackend); - - -void ALCnullBackend_Construct(ALCnullBackend *self, ALCdevice *device) -{ - new (self) ALCnullBackend{device}; - SET_VTABLE2(ALCnullBackend, ALCbackend, self); -} - -void ALCnullBackend_Destruct(ALCnullBackend *self) -{ self->~ALCnullBackend(); } + static constexpr inline const char *CurrentPrefix() noexcept { return "NullBackend::"; } + DEF_NEWDEL(NullBackend) +}; -int ALCnullBackend::mixerProc() +int NullBackend::mixerProc() { const milliseconds restTime{mDevice->UpdateSize*1000/mDevice->Frequency / 2}; @@ -102,9 +84,9 @@ int ALCnullBackend::mixerProc() } while(avail-done >= mDevice->UpdateSize) { - ALCnullBackend_lock(this); + lock(); aluMixData(mDevice, nullptr, mDevice->UpdateSize); - ALCnullBackend_unlock(this); + unlock(); done += mDevice->UpdateSize; } @@ -125,30 +107,29 @@ int ALCnullBackend::mixerProc() } -ALCenum ALCnullBackend_open(ALCnullBackend *self, const ALCchar *name) +ALCenum NullBackend::open(const ALCchar *name) { if(!name) name = nullDevice; else if(strcmp(name, nullDevice) != 0) return ALC_INVALID_VALUE; - ALCdevice *device{self->mDevice}; - device->DeviceName = name; + mDevice->DeviceName = name; return ALC_NO_ERROR; } -ALCboolean ALCnullBackend_reset(ALCnullBackend *self) +ALCboolean NullBackend::reset() { - SetDefaultWFXChannelOrder(self->mDevice); + SetDefaultWFXChannelOrder(mDevice); return ALC_TRUE; } -ALCboolean ALCnullBackend_start(ALCnullBackend *self) +ALCboolean NullBackend::start() { try { - self->mKillNow.store(AL_FALSE, std::memory_order_release); - self->mThread = std::thread(std::mem_fn(&ALCnullBackend::mixerProc), self); + mKillNow.store(AL_FALSE, std::memory_order_release); + mThread = std::thread{std::mem_fn(&NullBackend::mixerProc), this}; return ALC_TRUE; } catch(std::exception& e) { @@ -159,11 +140,11 @@ ALCboolean ALCnullBackend_start(ALCnullBackend *self) return ALC_FALSE; } -void ALCnullBackend_stop(ALCnullBackend *self) +void NullBackend::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; - self->mThread.join(); + mThread.join(); } } // namespace @@ -188,16 +169,11 @@ void NullBackendFactory::probe(DevProbe type, std::string *outnames) } } -ALCbackend *NullBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *NullBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) - { - ALCnullBackend *backend; - NEW_OBJ(backend, ALCnullBackend)(device); - return backend; - } - - return NULL; + return new NullBackend{device}; + return nullptr; } BackendFactory &NullBackendFactory::getFactory() diff --git a/Alc/backends/null.h b/Alc/backends/null.h index 37457d94..d4164198 100644 --- a/Alc/backends/null.h +++ b/Alc/backends/null.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index b0e51441..4f2e07be 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -42,14 +42,15 @@ namespace { /* Helper macros */ +#define EXTRACT_VCALL_ARGS(...) __VA_ARGS__)) #define VCALL(obj, func) ((*(obj))->func((obj), EXTRACT_VCALL_ARGS #define VCALL0(obj, func) ((*(obj))->func((obj) EXTRACT_VCALL_ARGS -static const ALCchar opensl_device[] = "OpenSL"; +constexpr ALCchar opensl_device[] = "OpenSL"; -static SLuint32 GetChannelMask(DevFmtChannels chans) +SLuint32 GetChannelMask(DevFmtChannels chans) { switch(chans) { @@ -78,7 +79,7 @@ static SLuint32 GetChannelMask(DevFmtChannels chans) } #ifdef SL_DATAFORMAT_PCM_EX -static SLuint32 GetTypeRepresentation(DevFmtType type) +SLuint32 GetTypeRepresentation(DevFmtType type) { switch(type) { @@ -97,7 +98,7 @@ static SLuint32 GetTypeRepresentation(DevFmtType type) } #endif -static const char *res_str(SLresult result) +const char *res_str(SLresult result) { switch(result) { @@ -132,20 +133,26 @@ static const char *res_str(SLresult result) } #define PRINTERR(x, s) do { \ - if((x) != SL_RESULT_SUCCESS) \ + if(UNLIKELY((x) != SL_RESULT_SUCCESS)) \ ERR("%s: %s\n", (s), res_str((x))); \ } while(0) -struct ALCopenslPlayback final : public ALCbackend { - ALCopenslPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } - ~ALCopenslPlayback() override; +struct OpenSLPlayback final : public BackendBase { + OpenSLPlayback(ALCdevice *device) noexcept : BackendBase{device} { } + ~OpenSLPlayback() override; static void processC(SLAndroidSimpleBufferQueueItf bq, void *context); void process(SLAndroidSimpleBufferQueueItf bq); int mixerProc(); + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + ClockLatency getClockLatency() override; + /* engine interfaces */ SLObjectItf mEngineObj{nullptr}; SLEngineItf mEngine{nullptr}; @@ -163,34 +170,12 @@ struct ALCopenslPlayback final : public ALCbackend { std::atomic<ALenum> mKillNow{AL_TRUE}; std::thread mThread; -}; - -static void ALCopenslPlayback_Construct(ALCopenslPlayback *self, ALCdevice *device); -static void ALCopenslPlayback_Destruct(ALCopenslPlayback *self); -static ALCenum ALCopenslPlayback_open(ALCopenslPlayback *self, const ALCchar *name); -static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self); -static ALCboolean ALCopenslPlayback_start(ALCopenslPlayback *self); -static void ALCopenslPlayback_stop(ALCopenslPlayback *self); -static DECLARE_FORWARD2(ALCopenslPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -static DECLARE_FORWARD(ALCopenslPlayback, ALCbackend, ALCuint, availableSamples) -static ClockLatency ALCopenslPlayback_getClockLatency(ALCopenslPlayback *self); -static DECLARE_FORWARD(ALCopenslPlayback, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCopenslPlayback, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCopenslPlayback) -DEFINE_ALCBACKEND_VTABLE(ALCopenslPlayback); - - -static void ALCopenslPlayback_Construct(ALCopenslPlayback *self, ALCdevice *device) -{ - new (self) ALCopenslPlayback{device}; - SET_VTABLE2(ALCopenslPlayback, ALCbackend, self); -} - -static void ALCopenslPlayback_Destruct(ALCopenslPlayback* self) -{ self->~ALCopenslPlayback(); } + static constexpr inline const char *CurrentPrefix() noexcept { return "OpenSLPlayback::"; } + DEF_NEWDEL(OpenSLPlayback) +}; -ALCopenslPlayback::~ALCopenslPlayback() +OpenSLPlayback::~OpenSLPlayback() { if(mBufferQueueObj) VCALL0(mBufferQueueObj,Destroy)(); @@ -208,10 +193,10 @@ ALCopenslPlayback::~ALCopenslPlayback() /* this callback handler is called every time a buffer finishes playing */ -void ALCopenslPlayback::processC(SLAndroidSimpleBufferQueueItf bq, void *context) -{ static_cast<ALCopenslPlayback*>(context)->process(bq); } +void OpenSLPlayback::processC(SLAndroidSimpleBufferQueueItf bq, void *context) +{ static_cast<OpenSLPlayback*>(context)->process(bq); } -void ALCopenslPlayback::process(SLAndroidSimpleBufferQueueItf UNUSED(bq)) +void OpenSLPlayback::process(SLAndroidSimpleBufferQueueItf UNUSED(bq)) { /* A note on the ringbuffer usage: The buffer queue seems to hold on to the * pointer passed to the Enqueue method, rather than copying the audio. @@ -226,7 +211,7 @@ void ALCopenslPlayback::process(SLAndroidSimpleBufferQueueItf UNUSED(bq)) mSem.post(); } -int ALCopenslPlayback::mixerProc() +int OpenSLPlayback::mixerProc() { SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); @@ -242,7 +227,7 @@ int ALCopenslPlayback::mixerProc() PRINTERR(result, "bufferQueue->GetInterface SL_IID_PLAY"); } - ALCopenslPlayback_lock(this); + lock(); if(SL_RESULT_SUCCESS != result) aluHandleDisconnect(mDevice, "Failed to get playback buffer: 0x%08x", result); @@ -251,7 +236,7 @@ int ALCopenslPlayback::mixerProc() { if(mRing->writeSpace() == 0) { - SLuint32 state = 0; + SLuint32 state{0}; result = VCALL(player,GetPlayState)(&state); PRINTERR(result, "player->GetPlayState"); @@ -268,9 +253,9 @@ int ALCopenslPlayback::mixerProc() if(mRing->writeSpace() == 0) { - ALCopenslPlayback_unlock(this); + unlock(); mSem.wait(); - ALCopenslPlayback_lock(this); + lock(); continue; } } @@ -304,67 +289,63 @@ int ALCopenslPlayback::mixerProc() data.first.buf += mDevice->UpdateSize*mFrameSize; } } - ALCopenslPlayback_unlock(this); + unlock(); return 0; } -static ALCenum ALCopenslPlayback_open(ALCopenslPlayback *self, const ALCchar *name) +ALCenum OpenSLPlayback::open(const ALCchar *name) { - ALCdevice *device{self->mDevice}; - SLresult result; - if(!name) name = opensl_device; else if(strcmp(name, opensl_device) != 0) return ALC_INVALID_VALUE; // create engine - result = slCreateEngine(&self->mEngineObj, 0, NULL, 0, NULL, NULL); + SLresult result{slCreateEngine(&mEngineObj, 0, NULL, 0, NULL, NULL)}; PRINTERR(result, "slCreateEngine"); if(SL_RESULT_SUCCESS == result) { - result = VCALL(self->mEngineObj,Realize)(SL_BOOLEAN_FALSE); + result = VCALL(mEngineObj,Realize)(SL_BOOLEAN_FALSE); PRINTERR(result, "engine->Realize"); } if(SL_RESULT_SUCCESS == result) { - result = VCALL(self->mEngineObj,GetInterface)(SL_IID_ENGINE, &self->mEngine); + result = VCALL(mEngineObj,GetInterface)(SL_IID_ENGINE, &mEngine); PRINTERR(result, "engine->GetInterface"); } if(SL_RESULT_SUCCESS == result) { - result = VCALL(self->mEngine,CreateOutputMix)(&self->mOutputMix, 0, NULL, NULL); + result = VCALL(mEngine,CreateOutputMix)(&mOutputMix, 0, NULL, NULL); PRINTERR(result, "engine->CreateOutputMix"); } if(SL_RESULT_SUCCESS == result) { - result = VCALL(self->mOutputMix,Realize)(SL_BOOLEAN_FALSE); + result = VCALL(mOutputMix,Realize)(SL_BOOLEAN_FALSE); PRINTERR(result, "outputMix->Realize"); } if(SL_RESULT_SUCCESS != result) { - if(self->mOutputMix != NULL) - VCALL0(self->mOutputMix,Destroy)(); - self->mOutputMix = NULL; + if(mOutputMix) + VCALL0(mOutputMix,Destroy)(); + mOutputMix = NULL; - if(self->mEngineObj != NULL) - VCALL0(self->mEngineObj,Destroy)(); - self->mEngineObj = NULL; - self->mEngine = NULL; + if(mEngineObj) + VCALL0(mEngineObj,Destroy)(); + mEngineObj = NULL; + mEngine = NULL; return ALC_INVALID_VALUE; } - device->DeviceName = name; + mDevice->DeviceName = name; return ALC_NO_ERROR; } -static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) +ALCboolean OpenSLPlayback::reset() { - ALCdevice *device{self->mDevice}; SLDataLocator_AndroidSimpleBufferQueue loc_bufq; SLDataLocator_OutputMix loc_outmix; SLDataSource audioSrc; @@ -374,15 +355,15 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) SLboolean reqs[2]; SLresult result; - if(self->mBufferQueueObj != NULL) - VCALL0(self->mBufferQueueObj,Destroy)(); - self->mBufferQueueObj = NULL; + if(mBufferQueueObj) + VCALL0(mBufferQueueObj,Destroy)(); + mBufferQueueObj = NULL; - self->mRing = nullptr; + mRing = nullptr; - sampleRate = device->Frequency; + sampleRate = mDevice->Frequency; #if 0 - if(!(device->Flags&DEVICE_FREQUENCY_REQUEST)) + if(!(mDevice->Flags&DEVICE_FREQUENCY_REQUEST)) { /* FIXME: Disabled until I figure out how to get the Context needed for * the getSystemService call. @@ -449,43 +430,43 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) } #endif - if(sampleRate != device->Frequency) + if(sampleRate != mDevice->Frequency) { - device->NumUpdates = (device->NumUpdates*sampleRate + (device->Frequency>>1)) / - device->Frequency; - device->NumUpdates = maxu(device->NumUpdates, 2); - device->Frequency = sampleRate; + mDevice->NumUpdates = (mDevice->NumUpdates*sampleRate + (mDevice->Frequency>>1)) / + mDevice->Frequency; + mDevice->NumUpdates = maxu(mDevice->NumUpdates, 2); + mDevice->Frequency = sampleRate; } - device->FmtChans = DevFmtStereo; - device->FmtType = DevFmtShort; + mDevice->FmtChans = DevFmtStereo; + mDevice->FmtType = DevFmtShort; - SetDefaultWFXChannelOrder(device); - self->mFrameSize = device->frameSizeFromFmt(); + SetDefaultWFXChannelOrder(mDevice); + mFrameSize = mDevice->frameSizeFromFmt(); loc_bufq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; - loc_bufq.numBuffers = device->NumUpdates; + loc_bufq.numBuffers = mDevice->NumUpdates; #ifdef SL_DATAFORMAT_PCM_EX SLDataFormat_PCM_EX format_pcm; format_pcm.formatType = SL_DATAFORMAT_PCM_EX; - format_pcm.numChannels = device->channelsFromFmt(); - format_pcm.sampleRate = device->Frequency * 1000; - format_pcm.bitsPerSample = device->bytesFromFmt() * 8; + format_pcm.numChannels = mDevice->channelsFromFmt(); + format_pcm.sampleRate = mDevice->Frequency * 1000; + format_pcm.bitsPerSample = mDevice->bytesFromFmt() * 8; format_pcm.containerSize = format_pcm.bitsPerSample; - format_pcm.channelMask = GetChannelMask(device->FmtChans); + format_pcm.channelMask = GetChannelMask(mDevice->FmtChans); format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN; - format_pcm.representation = GetTypeRepresentation(device->FmtType); + format_pcm.representation = GetTypeRepresentation(mDevice->FmtType); #else SLDataFormat_PCM format_pcm; format_pcm.formatType = SL_DATAFORMAT_PCM; - format_pcm.numChannels = device->channelsFromFmt(); - format_pcm.samplesPerSec = device->Frequency * 1000; - format_pcm.bitsPerSample = device->bytesFromFmt() * 8; + format_pcm.numChannels = mDevice->channelsFromFmt(); + format_pcm.samplesPerSec = mDevice->Frequency * 1000; + format_pcm.bitsPerSample = mDevice->bytesFromFmt() * 8; format_pcm.containerSize = format_pcm.bitsPerSample; - format_pcm.channelMask = GetChannelMask(device->FmtChans); + format_pcm.channelMask = GetChannelMask(mDevice->FmtChans); format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN; #endif @@ -494,7 +475,7 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) audioSrc.pFormat = &format_pcm; loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX; - loc_outmix.outputMix = self->mOutputMix; + loc_outmix.outputMix = mOutputMix; audioSnk.pLocator = &loc_outmix; audioSnk.pFormat = NULL; @@ -504,22 +485,20 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) ids[1] = SL_IID_ANDROIDCONFIGURATION; reqs[1] = SL_BOOLEAN_FALSE; - result = VCALL(self->mEngine,CreateAudioPlayer)(&self->mBufferQueueObj, - &audioSrc, &audioSnk, COUNTOF(ids), ids, reqs - ); + result = VCALL(mEngine,CreateAudioPlayer)(&mBufferQueueObj, &audioSrc, &audioSnk, COUNTOF(ids), + ids, reqs); PRINTERR(result, "engine->CreateAudioPlayer"); if(SL_RESULT_SUCCESS == result) { /* Set the stream type to "media" (games, music, etc), if possible. */ SLAndroidConfigurationItf config; - result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDCONFIGURATION, &config); + result = VCALL(mBufferQueueObj,GetInterface)(SL_IID_ANDROIDCONFIGURATION, &config); PRINTERR(result, "bufferQueue->GetInterface SL_IID_ANDROIDCONFIGURATION"); if(SL_RESULT_SUCCESS == result) { SLint32 streamType = SL_ANDROID_STREAM_MEDIA; - result = VCALL(config,SetConfiguration)(SL_ANDROID_KEY_STREAM_TYPE, - &streamType, sizeof(streamType) - ); + result = VCALL(config,SetConfiguration)(SL_ANDROID_KEY_STREAM_TYPE, &streamType, + sizeof(streamType)); PRINTERR(result, "config->SetConfiguration"); } @@ -528,26 +507,25 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) } if(SL_RESULT_SUCCESS == result) { - result = VCALL(self->mBufferQueueObj,Realize)(SL_BOOLEAN_FALSE); + result = VCALL(mBufferQueueObj,Realize)(SL_BOOLEAN_FALSE); PRINTERR(result, "bufferQueue->Realize"); } if(SL_RESULT_SUCCESS == result) { - self->mRing = CreateRingBuffer(device->NumUpdates, - self->mFrameSize*device->UpdateSize, true); - if(!self->mRing) + mRing = CreateRingBuffer(mDevice->NumUpdates, mFrameSize*mDevice->UpdateSize, true); + if(!mRing) { - ERR("Out of memory allocating ring buffer %ux%u %u\n", device->UpdateSize, - device->NumUpdates, self->mFrameSize); + ERR("Out of memory allocating ring buffer %ux%u %u\n", mDevice->UpdateSize, + mDevice->NumUpdates, mFrameSize); result = SL_RESULT_MEMORY_FAILURE; } } if(SL_RESULT_SUCCESS != result) { - if(self->mBufferQueueObj != NULL) - VCALL0(self->mBufferQueueObj,Destroy)(); - self->mBufferQueueObj = NULL; + if(mBufferQueueObj) + VCALL0(mBufferQueueObj,Destroy)(); + mBufferQueueObj = NULL; return ALC_FALSE; } @@ -555,26 +533,24 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) return ALC_TRUE; } -static ALCboolean ALCopenslPlayback_start(ALCopenslPlayback *self) +ALCboolean OpenSLPlayback::start() { - RingBuffer *ring{self->mRing.get()}; - - ring->reset(); + mRing->reset(); SLAndroidSimpleBufferQueueItf bufferQueue; - SLresult result{VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, + SLresult result{VCALL(mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue)}; PRINTERR(result, "bufferQueue->GetInterface"); if(SL_RESULT_SUCCESS != result) return ALC_FALSE; - result = VCALL(bufferQueue,RegisterCallback)(&ALCopenslPlayback::processC, self); + result = VCALL(bufferQueue,RegisterCallback)(&OpenSLPlayback::processC, this); PRINTERR(result, "bufferQueue->RegisterCallback"); if(SL_RESULT_SUCCESS != result) return ALC_FALSE; try { - self->mKillNow.store(AL_FALSE); - self->mThread = std::thread(std::mem_fn(&ALCopenslPlayback::mixerProc), self); + mKillNow.store(AL_FALSE); + mThread = std::thread(std::mem_fn(&OpenSLPlayback::mixerProc), this); return ALC_TRUE; } catch(std::exception& e) { @@ -585,20 +561,16 @@ static ALCboolean ALCopenslPlayback_start(ALCopenslPlayback *self) return ALC_FALSE; } - -static void ALCopenslPlayback_stop(ALCopenslPlayback *self) +void OpenSLPlayback::stop() { - SLAndroidSimpleBufferQueueItf bufferQueue; - SLPlayItf player; - SLresult result; - - if(self->mKillNow.exchange(AL_TRUE) || !self->mThread.joinable()) + if(mKillNow.exchange(AL_TRUE) || !mThread.joinable()) return; - self->mSem.post(); - self->mThread.join(); + mSem.post(); + mThread.join(); - result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player); + SLPlayItf player; + SLresult result{VCALL(mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player)}; PRINTERR(result, "bufferQueue->GetInterface"); if(SL_RESULT_SUCCESS == result) { @@ -606,8 +578,8 @@ static void ALCopenslPlayback_stop(ALCopenslPlayback *self) PRINTERR(result, "player->SetPlayState"); } - result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - &bufferQueue); + SLAndroidSimpleBufferQueueItf bufferQueue; + result = VCALL(mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue); PRINTERR(result, "bufferQueue->GetInterface"); if(SL_RESULT_SUCCESS == result) { @@ -630,29 +602,33 @@ static void ALCopenslPlayback_stop(ALCopenslPlayback *self) } } -static ClockLatency ALCopenslPlayback_getClockLatency(ALCopenslPlayback *self) +ClockLatency OpenSLPlayback::getClockLatency() { - ALCdevice *device{self->mDevice}; - RingBuffer *ring{self->mRing.get()}; ClockLatency ret; - ALCopenslPlayback_lock(self); - ret.ClockTime = GetDeviceClockTime(device); - ret.Latency = std::chrono::seconds{ring->readSpace() * device->UpdateSize}; - ret.Latency /= device->Frequency; - ALCopenslPlayback_unlock(self); + lock(); + ret.ClockTime = GetDeviceClockTime(mDevice); + ret.Latency = std::chrono::seconds{mRing->readSpace() * mDevice->UpdateSize}; + ret.Latency /= mDevice->Frequency; + unlock(); return ret; } -struct ALCopenslCapture final : public ALCbackend { - ALCopenslCapture(ALCdevice *device) noexcept : ALCbackend{device} { } - ~ALCopenslCapture() override; +struct OpenSLCapture final : public BackendBase { + OpenSLCapture(ALCdevice *device) noexcept : BackendBase{device} { } + ~OpenSLCapture() override; static void processC(SLAndroidSimpleBufferQueueItf bq, void *context); void process(SLAndroidSimpleBufferQueueItf bq); + ALCenum open(const ALCchar *name) override; + ALCboolean start() override; + void stop() override; + ALCenum captureSamples(void *buffer, ALCuint samples) override; + ALCuint availableSamples() override; + /* engine interfaces */ SLObjectItf mEngineObj{nullptr}; SLEngineItf mEngine; @@ -664,33 +640,12 @@ struct ALCopenslCapture final : public ALCbackend { ALCuint mSplOffset{0u}; ALsizei mFrameSize{0}; -}; -static void ALCopenslCapture_Construct(ALCopenslCapture *self, ALCdevice *device); -static void ALCopenslCapture_Destruct(ALCopenslCapture *self); -static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name); -static DECLARE_FORWARD(ALCopenslCapture, ALCbackend, ALCboolean, reset) -static ALCboolean ALCopenslCapture_start(ALCopenslCapture *self); -static void ALCopenslCapture_stop(ALCopenslCapture *self); -static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid *buffer, ALCuint samples); -static ALCuint ALCopenslCapture_availableSamples(ALCopenslCapture *self); -static DECLARE_FORWARD(ALCopenslCapture, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCopenslCapture, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCopenslCapture, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCopenslCapture) -DEFINE_ALCBACKEND_VTABLE(ALCopenslCapture); - - -static void ALCopenslCapture_Construct(ALCopenslCapture *self, ALCdevice *device) -{ - new (self) ALCopenslCapture{device}; - SET_VTABLE2(ALCopenslCapture, ALCbackend, self); -} - -static void ALCopenslCapture_Destruct(ALCopenslCapture *self) -{ self->~ALCopenslCapture(); } + static constexpr inline const char *CurrentPrefix() noexcept { return "OpenSLCapture::"; } + DEF_NEWDEL(OpenSLCapture) +}; -ALCopenslCapture::~ALCopenslCapture() +OpenSLCapture::~OpenSLCapture() { if(mRecordObj) VCALL0(mRecordObj,Destroy)(); @@ -703,19 +658,18 @@ ALCopenslCapture::~ALCopenslCapture() } -void ALCopenslCapture::processC(SLAndroidSimpleBufferQueueItf bq, void *context) -{ static_cast<ALCopenslCapture*>(context)->process(bq); } +void OpenSLCapture::processC(SLAndroidSimpleBufferQueueItf bq, void *context) +{ static_cast<OpenSLCapture*>(context)->process(bq); } -void ALCopenslCapture::process(SLAndroidSimpleBufferQueueItf UNUSED(bq)) +void OpenSLCapture::process(SLAndroidSimpleBufferQueueItf UNUSED(bq)) { /* A new chunk has been written into the ring buffer, advance it. */ mRing->writeAdvance(1); } -static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name) +ALCenum OpenSLCapture::open(const ALCchar* name) { - ALCdevice *device{self->mDevice}; SLDataLocator_AndroidSimpleBufferQueue loc_bq; SLAndroidSimpleBufferQueueItf bufferQueue; SLDataLocator_IODevice loc_dev; @@ -728,32 +682,30 @@ static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name else if(strcmp(name, opensl_device) != 0) return ALC_INVALID_VALUE; - result = slCreateEngine(&self->mEngineObj, 0, NULL, 0, NULL, NULL); + result = slCreateEngine(&mEngineObj, 0, NULL, 0, NULL, NULL); PRINTERR(result, "slCreateEngine"); if(SL_RESULT_SUCCESS == result) { - result = VCALL(self->mEngineObj,Realize)(SL_BOOLEAN_FALSE); + result = VCALL(mEngineObj,Realize)(SL_BOOLEAN_FALSE); PRINTERR(result, "engine->Realize"); } if(SL_RESULT_SUCCESS == result) { - result = VCALL(self->mEngineObj,GetInterface)(SL_IID_ENGINE, &self->mEngine); + result = VCALL(mEngineObj,GetInterface)(SL_IID_ENGINE, &mEngine); PRINTERR(result, "engine->GetInterface"); } if(SL_RESULT_SUCCESS == result) { /* Ensure the total length is at least 100ms */ - ALsizei length = maxi(device->NumUpdates * device->UpdateSize, - device->Frequency / 10); + ALsizei length{maxi(mDevice->NumUpdates*mDevice->UpdateSize, mDevice->Frequency/10)}; /* Ensure the per-chunk length is at least 10ms, and no more than 50ms. */ - ALsizei update_len = clampi(device->NumUpdates*device->UpdateSize / 3, - device->Frequency / 100, - device->Frequency / 100 * 5); + ALsizei update_len{clampi(mDevice->NumUpdates*mDevice->UpdateSize / 3, + mDevice->Frequency/100, mDevice->Frequency/100*5)}; - device->UpdateSize = update_len; - device->NumUpdates = (length+update_len-1) / update_len; + mDevice->UpdateSize = update_len; + mDevice->NumUpdates = (length+update_len-1) / update_len; - self->mFrameSize = device->frameSizeFromFmt(); + mFrameSize = mDevice->frameSizeFromFmt(); } loc_dev.locatorType = SL_DATALOCATOR_IODEVICE; loc_dev.deviceType = SL_IODEVICE_AUDIOINPUT; @@ -764,27 +716,27 @@ static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name audioSrc.pFormat = NULL; loc_bq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; - loc_bq.numBuffers = device->NumUpdates; + loc_bq.numBuffers = mDevice->NumUpdates; #ifdef SL_DATAFORMAT_PCM_EX SLDataFormat_PCM_EX format_pcm; format_pcm.formatType = SL_DATAFORMAT_PCM_EX; - format_pcm.numChannels = device->channelsFromFmt(); - format_pcm.sampleRate = device->Frequency * 1000; - format_pcm.bitsPerSample = device->bytesFromFmt() * 8; + format_pcm.numChannels = mDevice->channelsFromFmt(); + format_pcm.sampleRate = mDevice->Frequency * 1000; + format_pcm.bitsPerSample = mDevice->bytesFromFmt() * 8; format_pcm.containerSize = format_pcm.bitsPerSample; - format_pcm.channelMask = GetChannelMask(device->FmtChans); + format_pcm.channelMask = GetChannelMask(mDevice->FmtChans); format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN; - format_pcm.representation = GetTypeRepresentation(device->FmtType); + format_pcm.representation = GetTypeRepresentation(mDevice->FmtType); #else SLDataFormat_PCM format_pcm; format_pcm.formatType = SL_DATAFORMAT_PCM; - format_pcm.numChannels = device->channelsFromFmt(); - format_pcm.samplesPerSec = device->Frequency * 1000; - format_pcm.bitsPerSample = device->bytesFromFmt() * 8; + format_pcm.numChannels = mDevice->channelsFromFmt(); + format_pcm.samplesPerSec = mDevice->Frequency * 1000; + format_pcm.bitsPerSample = mDevice->bytesFromFmt() * 8; format_pcm.containerSize = format_pcm.bitsPerSample; - format_pcm.channelMask = GetChannelMask(device->FmtChans); + format_pcm.channelMask = GetChannelMask(mDevice->FmtChans); format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN; #endif @@ -797,23 +749,21 @@ static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name const SLInterfaceID ids[2] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION }; const SLboolean reqs[2] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE }; - result = VCALL(self->mEngine,CreateAudioRecorder)(&self->mRecordObj, - &audioSrc, &audioSnk, COUNTOF(ids), ids, reqs - ); + result = VCALL(mEngine,CreateAudioRecorder)(&mRecordObj, &audioSrc, &audioSnk, + COUNTOF(ids), ids, reqs); PRINTERR(result, "engine->CreateAudioRecorder"); } if(SL_RESULT_SUCCESS == result) { /* Set the record preset to "generic", if possible. */ SLAndroidConfigurationItf config; - result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDCONFIGURATION, &config); + result = VCALL(mRecordObj,GetInterface)(SL_IID_ANDROIDCONFIGURATION, &config); PRINTERR(result, "recordObj->GetInterface SL_IID_ANDROIDCONFIGURATION"); if(SL_RESULT_SUCCESS == result) { SLuint32 preset = SL_ANDROID_RECORDING_PRESET_GENERIC; - result = VCALL(config,SetConfiguration)(SL_ANDROID_KEY_RECORDING_PRESET, - &preset, sizeof(preset) - ); + result = VCALL(config,SetConfiguration)(SL_ANDROID_KEY_RECORDING_PRESET, &preset, + sizeof(preset)); PRINTERR(result, "config->SetConfiguration"); } @@ -822,31 +772,28 @@ static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name } if(SL_RESULT_SUCCESS == result) { - result = VCALL(self->mRecordObj,Realize)(SL_BOOLEAN_FALSE); + result = VCALL(mRecordObj,Realize)(SL_BOOLEAN_FALSE); PRINTERR(result, "recordObj->Realize"); } if(SL_RESULT_SUCCESS == result) { - self->mRing = CreateRingBuffer(device->NumUpdates, - device->UpdateSize*self->mFrameSize, false); + mRing = CreateRingBuffer(mDevice->NumUpdates, mDevice->UpdateSize*mFrameSize, false); - result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - &bufferQueue); + result = VCALL(mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue); PRINTERR(result, "recordObj->GetInterface"); } if(SL_RESULT_SUCCESS == result) { - result = VCALL(bufferQueue,RegisterCallback)(&ALCopenslCapture::processC, self); + result = VCALL(bufferQueue,RegisterCallback)(&OpenSLCapture::processC, this); PRINTERR(result, "bufferQueue->RegisterCallback"); } if(SL_RESULT_SUCCESS == result) { - RingBuffer *ring{self->mRing.get()}; - ALsizei chunk_size = device->UpdateSize * self->mFrameSize; + ALsizei chunk_size = mDevice->UpdateSize * mFrameSize; size_t i; - auto data = ring->getWriteVector(); + auto data = mRing->getWriteVector(); for(i = 0;i < data.first.len && SL_RESULT_SUCCESS == result;i++) { result = VCALL(bufferQueue,Enqueue)(data.first.buf + chunk_size*i, chunk_size); @@ -861,28 +808,26 @@ static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name if(SL_RESULT_SUCCESS != result) { - if(self->mRecordObj != NULL) - VCALL0(self->mRecordObj,Destroy)(); - self->mRecordObj = NULL; + if(mRecordObj) + VCALL0(mRecordObj,Destroy)(); + mRecordObj = nullptr; - if(self->mEngineObj != NULL) - VCALL0(self->mEngineObj,Destroy)(); - self->mEngineObj = NULL; - self->mEngine = NULL; + if(mEngineObj) + VCALL0(mEngineObj,Destroy)(); + mEngineObj = nullptr; + mEngine = nullptr; return ALC_INVALID_VALUE; } - device->DeviceName = name; + mDevice->DeviceName = name; return ALC_NO_ERROR; } -static ALCboolean ALCopenslCapture_start(ALCopenslCapture *self) +ALCboolean OpenSLCapture::start() { SLRecordItf record; - SLresult result; - - result = VCALL(self->mRecordObj,GetInterface)(SL_IID_RECORD, &record); + SLresult result{VCALL(mRecordObj,GetInterface)(SL_IID_RECORD, &record)}; PRINTERR(result, "recordObj->GetInterface"); if(SL_RESULT_SUCCESS == result) @@ -893,21 +838,19 @@ static ALCboolean ALCopenslCapture_start(ALCopenslCapture *self) if(SL_RESULT_SUCCESS != result) { - ALCopenslCapture_lock(self); - aluHandleDisconnect(self->mDevice, "Failed to start capture: 0x%08x", result); - ALCopenslCapture_unlock(self); + lock(); + aluHandleDisconnect(mDevice, "Failed to start capture: 0x%08x", result); + unlock(); return ALC_FALSE; } return ALC_TRUE; } -static void ALCopenslCapture_stop(ALCopenslCapture *self) +void OpenSLCapture::stop() { SLRecordItf record; - SLresult result; - - result = VCALL(self->mRecordObj,GetInterface)(SL_IID_RECORD, &record); + SLresult result{VCALL(mRecordObj,GetInterface)(SL_IID_RECORD, &record)}; PRINTERR(result, "recordObj->GetInterface"); if(SL_RESULT_SUCCESS == result) @@ -917,37 +860,33 @@ static void ALCopenslCapture_stop(ALCopenslCapture *self) } } -static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid *buffer, ALCuint samples) +ALCenum OpenSLCapture::captureSamples(void* buffer, ALCuint samples) { - ALCdevice *device{self->mDevice}; - RingBuffer *ring{self->mRing.get()}; - ALsizei chunk_size = device->UpdateSize * self->mFrameSize; + ALsizei chunk_size = mDevice->UpdateSize * mFrameSize; SLAndroidSimpleBufferQueueItf bufferQueue; SLresult result; ALCuint i; - result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - &bufferQueue); + result = VCALL(mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue); PRINTERR(result, "recordObj->GetInterface"); /* Read the desired samples from the ring buffer then advance its read * pointer. */ - auto data = ring->getReadVector(); + auto data = mRing->getReadVector(); for(i = 0;i < samples;) { - ALCuint rem = minu(samples - i, device->UpdateSize - self->mSplOffset); - memcpy((ALCbyte*)buffer + i*self->mFrameSize, - data.first.buf + self->mSplOffset*self->mFrameSize, - rem * self->mFrameSize); + ALCuint rem{minu(samples - i, mDevice->UpdateSize - mSplOffset)}; + memcpy((ALCbyte*)buffer + i*mFrameSize, data.first.buf + mSplOffset*mFrameSize, + rem * mFrameSize); - self->mSplOffset += rem; - if(self->mSplOffset == device->UpdateSize) + mSplOffset += rem; + if(mSplOffset == mDevice->UpdateSize) { /* Finished a chunk, reset the offset and advance the read pointer. */ - self->mSplOffset = 0; + mSplOffset = 0; - ring->readAdvance(1); + mRing->readAdvance(1); result = VCALL(bufferQueue,Enqueue)(data.first.buf, chunk_size); PRINTERR(result, "bufferQueue->Enqueue"); if(SL_RESULT_SUCCESS != result) break; @@ -964,21 +903,17 @@ static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid * if(SL_RESULT_SUCCESS != result) { - ALCopenslCapture_lock(self); - aluHandleDisconnect(device, "Failed to update capture buffer: 0x%08x", result); - ALCopenslCapture_unlock(self); + lock(); + aluHandleDisconnect(mDevice, "Failed to update capture buffer: 0x%08x", result); + unlock(); return ALC_INVALID_DEVICE; } return ALC_NO_ERROR; } -static ALCuint ALCopenslCapture_availableSamples(ALCopenslCapture *self) -{ - ALCdevice *device{self->mDevice}; - RingBuffer *ring{self->mRing.get()}; - return ring->readSpace() * device->UpdateSize; -} +ALCuint OpenSLCapture::availableSamples() +{ return mRing->readSpace()*mDevice->UpdateSize - mSplOffset; } } // namespace @@ -999,21 +934,12 @@ void OSLBackendFactory::probe(DevProbe type, std::string *outnames) } } -ALCbackend *OSLBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *OSLBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) - { - ALCopenslPlayback *backend; - NEW_OBJ(backend, ALCopenslPlayback)(device); - return backend; - } + return new OpenSLPlayback{device}; if(type == ALCbackend_Capture) - { - ALCopenslCapture *backend; - NEW_OBJ(backend, ALCopenslCapture)(device); - return backend; - } - + return new OpenSLCapture{device}; return nullptr; } diff --git a/Alc/backends/opensl.h b/Alc/backends/opensl.h index 31d0caae..bab15115 100644 --- a/Alc/backends/opensl.h +++ b/Alc/backends/opensl.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index 54d7e0af..c2139d4d 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -241,45 +241,29 @@ int log2i(ALCuint x) } -struct ALCplaybackOSS final : public ALCbackend { - ALCplaybackOSS(ALCdevice *device) noexcept : ALCbackend{device} { } - ~ALCplaybackOSS() override; +struct OSSPlayback final : public BackendBase { + OSSPlayback(ALCdevice *device) noexcept : BackendBase{device} { } + ~OSSPlayback() override; int mixerProc(); + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + int mFd{-1}; al::vector<ALubyte> mMixData; std::atomic<ALenum> mKillNow{AL_TRUE}; std::thread mThread; -}; - -void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device); -void ALCplaybackOSS_Destruct(ALCplaybackOSS *self); -ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name); -ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self); -ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self); -void ALCplaybackOSS_stop(ALCplaybackOSS *self); -DECLARE_FORWARD2(ALCplaybackOSS, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) -DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, ALCuint, availableSamples) -DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, lock) -DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCplaybackOSS) -DEFINE_ALCBACKEND_VTABLE(ALCplaybackOSS); - - -void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device) -{ - new (self) ALCplaybackOSS{device}; - SET_VTABLE2(ALCplaybackOSS, ALCbackend, self); -} -void ALCplaybackOSS_Destruct(ALCplaybackOSS *self) -{ self->~ALCplaybackOSS(); } + static constexpr inline const char *CurrentPrefix() noexcept { return "OSSPlayback::"; } + DEF_NEWDEL(OSSPlayback) +}; -ALCplaybackOSS::~ALCplaybackOSS() +OSSPlayback::~OSSPlayback() { if(mFd != -1) close(mFd); @@ -287,14 +271,14 @@ ALCplaybackOSS::~ALCplaybackOSS() } -int ALCplaybackOSS::mixerProc() +int OSSPlayback::mixerProc() { SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); const int frame_size{mDevice->frameSizeFromFmt()}; - ALCplaybackOSS_lock(this); + lock(); while(!mKillNow.load(std::memory_order_acquire) && mDevice->Connected.load(std::memory_order_acquire)) { @@ -302,9 +286,9 @@ int ALCplaybackOSS::mixerProc() pollitem.fd = mFd; pollitem.events = POLLOUT; - ALCplaybackOSS_unlock(this); + unlock(); int pret{poll(&pollitem, 1, 1000)}; - ALCplaybackOSS_lock(this); + lock(); if(pret < 0) { if(errno == EINTR || errno == EAGAIN) @@ -339,16 +323,14 @@ int ALCplaybackOSS::mixerProc() write_ptr += wrote; } } - ALCplaybackOSS_unlock(this); + unlock(); return 0; } -ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name) +ALCenum OSSPlayback::open(const ALCchar *name) { - ALCdevice *device{self->mDevice}; - const char *devname{DefaultPlayback}; if(!name) name = DefaultName; @@ -366,20 +348,19 @@ ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name) devname = iter->device_name.c_str(); } - self->mFd = open(devname, O_WRONLY); - if(self->mFd == -1) + mFd = ::open(devname, O_WRONLY); + if(mFd == -1) { ERR("Could not open %s: %s\n", devname, strerror(errno)); return ALC_INVALID_VALUE; } - device->DeviceName = name; + mDevice->DeviceName = name; return ALC_NO_ERROR; } -ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self) +ALCboolean OSSPlayback::reset() { - ALCdevice *device{self->mDevice}; int numFragmentsLogSize; int log2FragmentSize; unsigned int periods; @@ -390,7 +371,7 @@ ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self) int ossSpeed; const char *err; - switch(device->FmtType) + switch(mDevice->FmtType) { case DevFmtByte: ossFormat = AFMT_S8; @@ -402,19 +383,19 @@ ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self) case DevFmtInt: case DevFmtUInt: case DevFmtFloat: - device->FmtType = DevFmtShort; + mDevice->FmtType = DevFmtShort; /* fall-through */ case DevFmtShort: ossFormat = AFMT_S16_NE; break; } - periods = device->NumUpdates; - numChannels = device->channelsFromFmt(); - ossSpeed = device->Frequency; - frameSize = numChannels * device->bytesFromFmt(); + periods = mDevice->NumUpdates; + numChannels = mDevice->channelsFromFmt(); + ossSpeed = mDevice->Frequency; + frameSize = numChannels * mDevice->bytesFromFmt(); /* According to the OSS spec, 16 bytes (log2(16)) is the minimum. */ - log2FragmentSize = maxi(log2i(device->UpdateSize*frameSize), 4); + log2FragmentSize = maxi(log2i(mDevice->UpdateSize*frameSize), 4); numFragmentsLogSize = (periods << 16) | log2FragmentSize; #define CHECKERR(func) if((func) < 0) { \ @@ -423,11 +404,11 @@ ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self) } /* Don't fail if SETFRAGMENT fails. We can handle just about anything * that's reported back via GETOSPACE */ - ioctl(self->mFd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize); - CHECKERR(ioctl(self->mFd, SNDCTL_DSP_SETFMT, &ossFormat)); - CHECKERR(ioctl(self->mFd, SNDCTL_DSP_CHANNELS, &numChannels)); - CHECKERR(ioctl(self->mFd, SNDCTL_DSP_SPEED, &ossSpeed)); - CHECKERR(ioctl(self->mFd, SNDCTL_DSP_GETOSPACE, &info)); + ioctl(mFd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize); + CHECKERR(ioctl(mFd, SNDCTL_DSP_SETFMT, &ossFormat)); + CHECKERR(ioctl(mFd, SNDCTL_DSP_CHANNELS, &numChannels)); + CHECKERR(ioctl(mFd, SNDCTL_DSP_SPEED, &ossSpeed)); + CHECKERR(ioctl(mFd, SNDCTL_DSP_GETOSPACE, &info)); if(0) { err: @@ -436,38 +417,38 @@ ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self) } #undef CHECKERR - if(device->channelsFromFmt() != numChannels) + if(mDevice->channelsFromFmt() != numChannels) { - ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels); + ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(mDevice->FmtChans), + numChannels); return ALC_FALSE; } - if(!((ossFormat == AFMT_S8 && device->FmtType == DevFmtByte) || - (ossFormat == AFMT_U8 && device->FmtType == DevFmtUByte) || - (ossFormat == AFMT_S16_NE && device->FmtType == DevFmtShort))) + if(!((ossFormat == AFMT_S8 && mDevice->FmtType == DevFmtByte) || + (ossFormat == AFMT_U8 && mDevice->FmtType == DevFmtUByte) || + (ossFormat == AFMT_S16_NE && mDevice->FmtType == DevFmtShort))) { - ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(device->FmtType), ossFormat); + ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(mDevice->FmtType), + ossFormat); return ALC_FALSE; } - device->Frequency = ossSpeed; - device->UpdateSize = info.fragsize / frameSize; - device->NumUpdates = info.fragments; + mDevice->Frequency = ossSpeed; + mDevice->UpdateSize = info.fragsize / frameSize; + mDevice->NumUpdates = info.fragments; + + SetDefaultChannelOrder(mDevice); - SetDefaultChannelOrder(device); + mMixData.resize(mDevice->UpdateSize * mDevice->frameSizeFromFmt()); return ALC_TRUE; } -ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self) +ALCboolean OSSPlayback::start() { - ALCdevice *device{self->mDevice}; - try { - self->mMixData.resize(device->UpdateSize * device->frameSizeFromFmt()); - - self->mKillNow.store(AL_FALSE); - self->mThread = std::thread{std::mem_fn(&ALCplaybackOSS::mixerProc), self}; + mKillNow.store(AL_FALSE); + mThread = std::thread{std::mem_fn(&OSSPlayback::mixerProc), this}; return ALC_TRUE; } catch(std::exception& e) { @@ -478,58 +459,41 @@ ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self) return ALC_FALSE; } -void ALCplaybackOSS_stop(ALCplaybackOSS *self) +void OSSPlayback::stop() { - if(self->mKillNow.exchange(AL_TRUE) || !self->mThread.joinable()) + if(mKillNow.exchange(AL_TRUE) || !mThread.joinable()) return; - self->mThread.join(); + mThread.join(); - if(ioctl(self->mFd, SNDCTL_DSP_RESET) != 0) + if(ioctl(mFd, SNDCTL_DSP_RESET) != 0) ERR("Error resetting device: %s\n", strerror(errno)); - - self->mMixData.clear(); } -struct ALCcaptureOSS final : public ALCbackend { - ALCcaptureOSS(ALCdevice *device) noexcept : ALCbackend{device} { } - ~ALCcaptureOSS() override; +struct OSScapture final : public BackendBase { + OSScapture(ALCdevice *device) noexcept : BackendBase{device} { } + ~OSScapture() override; int recordProc(); + ALCenum open(const ALCchar *name) override; + ALCboolean start() override; + void stop() override; + ALCenum captureSamples(ALCvoid *buffer, ALCuint samples) override; + ALCuint availableSamples() override; + int mFd{-1}; RingBufferPtr mRing{nullptr}; std::atomic<ALenum> mKillNow{AL_TRUE}; std::thread mThread; -}; - -void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device); -void ALCcaptureOSS_Destruct(ALCcaptureOSS *self); -ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name); -DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, ALCboolean, reset) -ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self); -void ALCcaptureOSS_stop(ALCcaptureOSS *self); -ALCenum ALCcaptureOSS_captureSamples(ALCcaptureOSS *self, ALCvoid *buffer, ALCuint samples); -ALCuint ALCcaptureOSS_availableSamples(ALCcaptureOSS *self); -DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, lock) -DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCcaptureOSS) -DEFINE_ALCBACKEND_VTABLE(ALCcaptureOSS); - - -void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device) -{ - new (self) ALCcaptureOSS{device}; - SET_VTABLE2(ALCcaptureOSS, ALCbackend, self); -} -void ALCcaptureOSS_Destruct(ALCcaptureOSS *self) -{ self->~ALCcaptureOSS(); } + static constexpr inline const char *CurrentPrefix() noexcept { return "OSScapture::"; } + DEF_NEWDEL(OSScapture) +}; -ALCcaptureOSS::~ALCcaptureOSS() +OSScapture::~OSScapture() { if(mFd != -1) close(mFd); @@ -537,7 +501,7 @@ ALCcaptureOSS::~ALCcaptureOSS() } -int ALCcaptureOSS::recordProc() +int OSScapture::recordProc() { SetRTPriority(); althrd_setname(RECORD_THREAD_NAME); @@ -555,7 +519,9 @@ int ALCcaptureOSS::recordProc() if(errno == EINTR || errno == EAGAIN) continue; ERR("poll failed: %s\n", strerror(errno)); + lock(); aluHandleDisconnect(mDevice, "Failed to check capture samples: %s", strerror(errno)); + unlock(); break; } else if(sret == 0) @@ -571,10 +537,10 @@ int ALCcaptureOSS::recordProc() if(amt < 0) { ERR("read failed: %s\n", strerror(errno)); - ALCcaptureOSS_lock(this); + lock(); aluHandleDisconnect(mDevice, "Failed reading capture samples: %s", strerror(errno)); - ALCcaptureOSS_unlock(this); + unlock(); break; } mRing->writeAdvance(amt/frame_size); @@ -585,10 +551,8 @@ int ALCcaptureOSS::recordProc() } -ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) +ALCenum OSScapture::open(const ALCchar *name) { - ALCdevice *device{self->mDevice}; - const char *devname{DefaultCapture}; if(!name) name = DefaultName; @@ -606,15 +570,15 @@ ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) devname = iter->device_name.c_str(); } - self->mFd = open(devname, O_RDONLY); - if(self->mFd == -1) + mFd = ::open(devname, O_RDONLY); + if(mFd == -1) { ERR("Could not open %s: %s\n", devname, strerror(errno)); return ALC_INVALID_VALUE; } int ossFormat{}; - switch(device->FmtType) + switch(mDevice->FmtType) { case DevFmtByte: ossFormat = AFMT_S8; @@ -629,15 +593,15 @@ ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) case DevFmtInt: case DevFmtUInt: case DevFmtFloat: - ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType)); + ERR("%s capture samples not supported\n", DevFmtTypeString(mDevice->FmtType)); return ALC_INVALID_VALUE; } int periods{4}; - int numChannels{device->channelsFromFmt()}; - int frameSize{numChannels * device->bytesFromFmt()}; - int ossSpeed{static_cast<int>(device->Frequency)}; - int log2FragmentSize{log2i(device->UpdateSize * device->NumUpdates * + int numChannels{mDevice->channelsFromFmt()}; + int frameSize{numChannels * mDevice->bytesFromFmt()}; + int ossSpeed{static_cast<int>(mDevice->Frequency)}; + int log2FragmentSize{log2i(mDevice->UpdateSize * mDevice->NumUpdates * frameSize / periods)}; /* according to the OSS spec, 16 bytes are the minimum */ @@ -650,57 +614,58 @@ ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) err = #func; \ goto err; \ } - CHECKERR(ioctl(self->mFd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize)); - CHECKERR(ioctl(self->mFd, SNDCTL_DSP_SETFMT, &ossFormat)); - CHECKERR(ioctl(self->mFd, SNDCTL_DSP_CHANNELS, &numChannels)); - CHECKERR(ioctl(self->mFd, SNDCTL_DSP_SPEED, &ossSpeed)); - CHECKERR(ioctl(self->mFd, SNDCTL_DSP_GETISPACE, &info)); + CHECKERR(ioctl(mFd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize)); + CHECKERR(ioctl(mFd, SNDCTL_DSP_SETFMT, &ossFormat)); + CHECKERR(ioctl(mFd, SNDCTL_DSP_CHANNELS, &numChannels)); + CHECKERR(ioctl(mFd, SNDCTL_DSP_SPEED, &ossSpeed)); + CHECKERR(ioctl(mFd, SNDCTL_DSP_GETISPACE, &info)); if(0) { err: ERR("%s failed: %s\n", err, strerror(errno)); - close(self->mFd); - self->mFd = -1; + close(mFd); + mFd = -1; return ALC_INVALID_VALUE; } #undef CHECKERR - if(device->channelsFromFmt() != numChannels) + if(mDevice->channelsFromFmt() != numChannels) { - ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels); - close(self->mFd); - self->mFd = -1; + ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(mDevice->FmtChans), + numChannels); + close(mFd); + mFd = -1; return ALC_INVALID_VALUE; } - if(!((ossFormat == AFMT_S8 && device->FmtType == DevFmtByte) || - (ossFormat == AFMT_U8 && device->FmtType == DevFmtUByte) || - (ossFormat == AFMT_S16_NE && device->FmtType == DevFmtShort))) + if(!((ossFormat == AFMT_S8 && mDevice->FmtType == DevFmtByte) || + (ossFormat == AFMT_U8 && mDevice->FmtType == DevFmtUByte) || + (ossFormat == AFMT_S16_NE && mDevice->FmtType == DevFmtShort))) { - ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(device->FmtType), ossFormat); - close(self->mFd); - self->mFd = -1; + ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(mDevice->FmtType), ossFormat); + close(mFd); + mFd = -1; return ALC_INVALID_VALUE; } - self->mRing = CreateRingBuffer(device->UpdateSize*device->NumUpdates, frameSize, false); - if(!self->mRing) + mRing = CreateRingBuffer(mDevice->UpdateSize*mDevice->NumUpdates, frameSize, false); + if(!mRing) { ERR("Ring buffer create failed\n"); - close(self->mFd); - self->mFd = -1; + close(mFd); + mFd = -1; return ALC_OUT_OF_MEMORY; } - device->DeviceName = name; + mDevice->DeviceName = name; return ALC_NO_ERROR; } -ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self) +ALCboolean OSScapture::start() { try { - self->mKillNow.store(AL_FALSE); - self->mThread = std::thread{std::mem_fn(&ALCcaptureOSS::recordProc), self}; + mKillNow.store(AL_FALSE); + mThread = std::thread{std::mem_fn(&OSScapture::recordProc), this}; return ALC_TRUE; } catch(std::exception& e) { @@ -711,29 +676,24 @@ ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self) return ALC_FALSE; } -void ALCcaptureOSS_stop(ALCcaptureOSS *self) +void OSScapture::stop() { - if(self->mKillNow.exchange(AL_TRUE) || !self->mThread.joinable()) + if(mKillNow.exchange(AL_TRUE) || !mThread.joinable()) return; + mThread.join(); - self->mThread.join(); - - if(ioctl(self->mFd, SNDCTL_DSP_RESET) != 0) + if(ioctl(mFd, SNDCTL_DSP_RESET) != 0) ERR("Error resetting device: %s\n", strerror(errno)); } -ALCenum ALCcaptureOSS_captureSamples(ALCcaptureOSS *self, ALCvoid *buffer, ALCuint samples) +ALCenum OSScapture::captureSamples(ALCvoid *buffer, ALCuint samples) { - RingBuffer *ring{self->mRing.get()}; - ring->read(buffer, samples); + mRing->read(buffer, samples); return ALC_NO_ERROR; } -ALCuint ALCcaptureOSS_availableSamples(ALCcaptureOSS *self) -{ - RingBuffer *ring{self->mRing.get()}; - return ring->readSpace(); -} +ALCuint OSScapture::availableSamples() +{ return mRing->readSpace(); } } // namespace @@ -791,20 +751,11 @@ void OSSBackendFactory::probe(DevProbe type, std::string *outnames) } } -ALCbackend *OSSBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *OSSBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) - { - ALCplaybackOSS *backend; - NEW_OBJ(backend, ALCplaybackOSS)(device); - return backend; - } + return new OSSPlayback{device}; if(type == ALCbackend_Capture) - { - ALCcaptureOSS *backend; - NEW_OBJ(backend, ALCcaptureOSS)(device); - return backend; - } - + return new OSScapture{device}; return nullptr; } diff --git a/Alc/backends/oss.h b/Alc/backends/oss.h index 4652a779..8f65f1cc 100644 --- a/Alc/backends/oss.h +++ b/Alc/backends/oss.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/portaudio.cpp b/Alc/backends/portaudio.cpp index 44ffd9bd..34688db9 100644 --- a/Alc/backends/portaudio.cpp +++ b/Alc/backends/portaudio.cpp @@ -130,9 +130,9 @@ bool pa_load(void) } -struct ALCportPlayback final : public ALCbackend { - ALCportPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } - ~ALCportPlayback() override; +struct PortPlayback final : public BackendBase { + PortPlayback(ALCdevice *device) noexcept : BackendBase{device} { } + ~PortPlayback() override; static int writeCallbackC(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, @@ -140,37 +140,20 @@ struct ALCportPlayback final : public ALCbackend { int writeCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags); + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + PaStream *mStream{nullptr}; PaStreamParameters mParams{}; ALuint mUpdateSize{0u}; -}; - -void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device); -void ALCportPlayback_Destruct(ALCportPlayback *self); -ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name); -ALCboolean ALCportPlayback_reset(ALCportPlayback *self); -ALCboolean ALCportPlayback_start(ALCportPlayback *self); -void ALCportPlayback_stop(ALCportPlayback *self); -DECLARE_FORWARD2(ALCportPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) -DECLARE_FORWARD(ALCportPlayback, ALCbackend, ALCuint, availableSamples) -DECLARE_FORWARD(ALCportPlayback, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(ALCportPlayback, ALCbackend, void, lock) -DECLARE_FORWARD(ALCportPlayback, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCportPlayback) - -DEFINE_ALCBACKEND_VTABLE(ALCportPlayback); - - -void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device) -{ - new (self) ALCportPlayback{device}; - SET_VTABLE2(ALCportPlayback, ALCbackend, self); -} -void ALCportPlayback_Destruct(ALCportPlayback *self) -{ self->~ALCportPlayback(); } + static constexpr inline const char *CurrentPrefix() noexcept { return "PortPlayback::"; } + DEF_NEWDEL(PortPlayback) +}; -ALCportPlayback::~ALCportPlayback() +PortPlayback::~PortPlayback() { PaError err{mStream ? Pa_CloseStream(mStream) : paNoError}; if(err != paNoError) @@ -179,132 +162,124 @@ ALCportPlayback::~ALCportPlayback() } -int ALCportPlayback::writeCallbackC(const void *inputBuffer, void *outputBuffer, +int PortPlayback::writeCallbackC(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags, void *userData) { - return static_cast<ALCportPlayback*>(userData)->writeCallback(inputBuffer, outputBuffer, + return static_cast<PortPlayback*>(userData)->writeCallback(inputBuffer, outputBuffer, framesPerBuffer, timeInfo, statusFlags); } -int ALCportPlayback::writeCallback(const void* UNUSED(inputBuffer), void *outputBuffer, +int PortPlayback::writeCallback(const void* UNUSED(inputBuffer), void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* UNUSED(timeInfo), const PaStreamCallbackFlags UNUSED(statusFlags)) { - ALCportPlayback_lock(this); + lock(); aluMixData(mDevice, outputBuffer, framesPerBuffer); - ALCportPlayback_unlock(this); + unlock(); return 0; } -ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name) +ALCenum PortPlayback::open(const ALCchar *name) { - ALCdevice *device{self->mDevice}; - PaError err; - if(!name) name = pa_device; else if(strcmp(name, pa_device) != 0) return ALC_INVALID_VALUE; - self->mUpdateSize = device->UpdateSize; + mUpdateSize = mDevice->UpdateSize; - self->mParams.device = -1; - if(!ConfigValueInt(nullptr, "port", "device", &self->mParams.device) || - self->mParams.device < 0) - self->mParams.device = Pa_GetDefaultOutputDevice(); - self->mParams.suggestedLatency = (device->UpdateSize*device->NumUpdates) / - (float)device->Frequency; - self->mParams.hostApiSpecificStreamInfo = nullptr; + mParams.device = -1; + if(!ConfigValueInt(nullptr, "port", "device", &mParams.device) || mParams.device < 0) + mParams.device = Pa_GetDefaultOutputDevice(); + mParams.suggestedLatency = (mDevice->UpdateSize*mDevice->NumUpdates) / + (float)mDevice->Frequency; + mParams.hostApiSpecificStreamInfo = nullptr; - self->mParams.channelCount = ((device->FmtChans == DevFmtMono) ? 1 : 2); + mParams.channelCount = ((mDevice->FmtChans == DevFmtMono) ? 1 : 2); - switch(device->FmtType) + switch(mDevice->FmtType) { case DevFmtByte: - self->mParams.sampleFormat = paInt8; + mParams.sampleFormat = paInt8; break; case DevFmtUByte: - self->mParams.sampleFormat = paUInt8; + mParams.sampleFormat = paUInt8; break; case DevFmtUShort: /* fall-through */ case DevFmtShort: - self->mParams.sampleFormat = paInt16; + mParams.sampleFormat = paInt16; break; case DevFmtUInt: /* fall-through */ case DevFmtInt: - self->mParams.sampleFormat = paInt32; + mParams.sampleFormat = paInt32; break; case DevFmtFloat: - self->mParams.sampleFormat = paFloat32; + mParams.sampleFormat = paFloat32; break; } retry_open: - err = Pa_OpenStream(&self->mStream, nullptr, &self->mParams, - device->Frequency, device->UpdateSize, paNoFlag, - &ALCportPlayback::writeCallbackC, self - ); + PaError err{Pa_OpenStream(&mStream, nullptr, &mParams, mDevice->Frequency, mDevice->UpdateSize, + paNoFlag, &PortPlayback::writeCallbackC, this)}; if(err != paNoError) { - if(self->mParams.sampleFormat == paFloat32) + if(mParams.sampleFormat == paFloat32) { - self->mParams.sampleFormat = paInt16; + mParams.sampleFormat = paInt16; goto retry_open; } ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err)); return ALC_INVALID_VALUE; } - device->DeviceName = name; + mDevice->DeviceName = name; return ALC_NO_ERROR; } -ALCboolean ALCportPlayback_reset(ALCportPlayback *self) +ALCboolean PortPlayback::reset() { - ALCdevice *device{self->mDevice}; - - const PaStreamInfo *streamInfo{Pa_GetStreamInfo(self->mStream)}; - device->Frequency = streamInfo->sampleRate; - device->UpdateSize = self->mUpdateSize; - - if(self->mParams.sampleFormat == paInt8) - device->FmtType = DevFmtByte; - else if(self->mParams.sampleFormat == paUInt8) - device->FmtType = DevFmtUByte; - else if(self->mParams.sampleFormat == paInt16) - device->FmtType = DevFmtShort; - else if(self->mParams.sampleFormat == paInt32) - device->FmtType = DevFmtInt; - else if(self->mParams.sampleFormat == paFloat32) - device->FmtType = DevFmtFloat; + const PaStreamInfo *streamInfo{Pa_GetStreamInfo(mStream)}; + mDevice->Frequency = streamInfo->sampleRate; + mDevice->UpdateSize = mUpdateSize; + + if(mParams.sampleFormat == paInt8) + mDevice->FmtType = DevFmtByte; + else if(mParams.sampleFormat == paUInt8) + mDevice->FmtType = DevFmtUByte; + else if(mParams.sampleFormat == paInt16) + mDevice->FmtType = DevFmtShort; + else if(mParams.sampleFormat == paInt32) + mDevice->FmtType = DevFmtInt; + else if(mParams.sampleFormat == paFloat32) + mDevice->FmtType = DevFmtFloat; else { - ERR("Unexpected sample format: 0x%lx\n", self->mParams.sampleFormat); + ERR("Unexpected sample format: 0x%lx\n", mParams.sampleFormat); return ALC_FALSE; } - if(self->mParams.channelCount == 2) - device->FmtChans = DevFmtStereo; - else if(self->mParams.channelCount == 1) - device->FmtChans = DevFmtMono; + if(mParams.channelCount == 2) + mDevice->FmtChans = DevFmtStereo; + else if(mParams.channelCount == 1) + mDevice->FmtChans = DevFmtMono; else { - ERR("Unexpected channel count: %u\n", self->mParams.channelCount); + ERR("Unexpected channel count: %u\n", mParams.channelCount); return ALC_FALSE; } - SetDefaultChannelOrder(device); + SetDefaultChannelOrder(mDevice); return ALC_TRUE; } -ALCboolean ALCportPlayback_start(ALCportPlayback *self) +ALCboolean PortPlayback::start() { - PaError err{Pa_StartStream(self->mStream)}; + PaError err{Pa_StartStream(mStream)}; if(err != paNoError) { ERR("Pa_StartStream() returned an error: %s\n", Pa_GetErrorText(err)); @@ -313,17 +288,17 @@ ALCboolean ALCportPlayback_start(ALCportPlayback *self) return ALC_TRUE; } -void ALCportPlayback_stop(ALCportPlayback *self) +void PortPlayback::stop() { - PaError err{Pa_StopStream(self->mStream)}; + PaError err{Pa_StopStream(mStream)}; if(err != paNoError) ERR("Error stopping stream: %s\n", Pa_GetErrorText(err)); } -struct ALCportCapture final : public ALCbackend { - ALCportCapture(ALCdevice *device) noexcept : ALCbackend{device} { } - ~ALCportCapture() override; +struct PortCapture final : public BackendBase { + PortCapture(ALCdevice *device) noexcept : BackendBase{device} { } + ~PortCapture() override; static int readCallbackC(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, @@ -331,38 +306,22 @@ struct ALCportCapture final : public ALCbackend { int readCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags); + ALCenum open(const ALCchar *name) override; + ALCboolean start() override; + void stop() override; + ALCenum captureSamples(ALCvoid *buffer, ALCuint samples) override; + ALCuint availableSamples() override; + PaStream *mStream{nullptr}; PaStreamParameters mParams; RingBufferPtr mRing{nullptr}; -}; - -void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device); -void ALCportCapture_Destruct(ALCportCapture *self); -ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name); -DECLARE_FORWARD(ALCportCapture, ALCbackend, ALCboolean, reset) -ALCboolean ALCportCapture_start(ALCportCapture *self); -void ALCportCapture_stop(ALCportCapture *self); -ALCenum ALCportCapture_captureSamples(ALCportCapture *self, ALCvoid *buffer, ALCuint samples); -ALCuint ALCportCapture_availableSamples(ALCportCapture *self); -DECLARE_FORWARD(ALCportCapture, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(ALCportCapture, ALCbackend, void, lock) -DECLARE_FORWARD(ALCportCapture, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCportCapture) - -DEFINE_ALCBACKEND_VTABLE(ALCportCapture); + static constexpr inline const char *CurrentPrefix() noexcept { return "PortCapture::"; } + DEF_NEWDEL(PortCapture) +}; -void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device) -{ - new (self) ALCportCapture{device}; - SET_VTABLE2(ALCportCapture, ALCbackend, self); -} - -void ALCportCapture_Destruct(ALCportCapture *self) -{ self->~ALCportCapture(); } - -ALCportCapture::~ALCportCapture() +PortCapture::~PortCapture() { PaError err{mStream ? Pa_CloseStream(mStream) : paNoError}; if(err != paNoError) @@ -371,15 +330,15 @@ ALCportCapture::~ALCportCapture() } -int ALCportCapture::readCallbackC(const void *inputBuffer, void *outputBuffer, +int PortCapture::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, + return static_cast<PortCapture*>(userData)->readCallback(inputBuffer, outputBuffer, framesPerBuffer, timeInfo, statusFlags); } -int ALCportCapture::readCallback(const void *inputBuffer, void *UNUSED(outputBuffer), +int PortCapture::readCallback(const void *inputBuffer, void *UNUSED(outputBuffer), unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo), const PaStreamCallbackFlags UNUSED(statusFlags)) { @@ -388,73 +347,66 @@ int ALCportCapture::readCallback(const void *inputBuffer, void *UNUSED(outputBuf } -ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name) +ALCenum PortCapture::open(const ALCchar *name) { - ALCdevice *device{self->mDevice}; - ALuint samples, frame_size; - PaError err; - if(!name) name = pa_device; else if(strcmp(name, pa_device) != 0) return ALC_INVALID_VALUE; - samples = device->UpdateSize * device->NumUpdates; - samples = maxu(samples, 100 * device->Frequency / 1000); - frame_size = device->frameSizeFromFmt(); + ALuint samples{mDevice->UpdateSize * mDevice->NumUpdates}; + samples = maxu(samples, 100 * mDevice->Frequency / 1000); + ALsizei frame_size{mDevice->frameSizeFromFmt()}; - self->mRing = CreateRingBuffer(samples, frame_size, false); - if(!self->mRing) return ALC_INVALID_VALUE; + mRing = CreateRingBuffer(samples, frame_size, false); + if(!mRing) return ALC_INVALID_VALUE; - self->mParams.device = -1; - if(!ConfigValueInt(nullptr, "port", "capture", &self->mParams.device) || - self->mParams.device < 0) - self->mParams.device = Pa_GetDefaultInputDevice(); - self->mParams.suggestedLatency = 0.0f; - self->mParams.hostApiSpecificStreamInfo = nullptr; + mParams.device = -1; + if(!ConfigValueInt(nullptr, "port", "capture", &mParams.device) || mParams.device < 0) + mParams.device = Pa_GetDefaultInputDevice(); + mParams.suggestedLatency = 0.0f; + mParams.hostApiSpecificStreamInfo = nullptr; - switch(device->FmtType) + switch(mDevice->FmtType) { case DevFmtByte: - self->mParams.sampleFormat = paInt8; + mParams.sampleFormat = paInt8; break; case DevFmtUByte: - self->mParams.sampleFormat = paUInt8; + mParams.sampleFormat = paUInt8; break; case DevFmtShort: - self->mParams.sampleFormat = paInt16; + mParams.sampleFormat = paInt16; break; case DevFmtInt: - self->mParams.sampleFormat = paInt32; + mParams.sampleFormat = paInt32; break; case DevFmtFloat: - self->mParams.sampleFormat = paFloat32; + mParams.sampleFormat = paFloat32; break; case DevFmtUInt: case DevFmtUShort: - ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType)); + ERR("%s samples not supported\n", DevFmtTypeString(mDevice->FmtType)); return ALC_INVALID_VALUE; } - self->mParams.channelCount = device->channelsFromFmt(); + mParams.channelCount = mDevice->channelsFromFmt(); - err = Pa_OpenStream(&self->mStream, &self->mParams, nullptr, - device->Frequency, paFramesPerBufferUnspecified, paNoFlag, - &ALCportCapture::readCallbackC, self - ); + PaError err{Pa_OpenStream(&mStream, &mParams, nullptr, mDevice->Frequency, + paFramesPerBufferUnspecified, paNoFlag, &PortCapture::readCallbackC, this)}; if(err != paNoError) { ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err)); return ALC_INVALID_VALUE; } - device->DeviceName = name; + mDevice->DeviceName = name; return ALC_NO_ERROR; } -ALCboolean ALCportCapture_start(ALCportCapture *self) +ALCboolean PortCapture::start() { - PaError err = Pa_StartStream(self->mStream); + PaError err{Pa_StartStream(mStream)}; if(err != paNoError) { ERR("Error starting stream: %s\n", Pa_GetErrorText(err)); @@ -463,24 +415,20 @@ ALCboolean ALCportCapture_start(ALCportCapture *self) return ALC_TRUE; } -void ALCportCapture_stop(ALCportCapture *self) +void PortCapture::stop() { - PaError err = Pa_StopStream(self->mStream); + PaError err{Pa_StopStream(mStream)}; if(err != paNoError) ERR("Error stopping stream: %s\n", Pa_GetErrorText(err)); } -ALCuint ALCportCapture_availableSamples(ALCportCapture *self) -{ - RingBuffer *ring{self->mRing.get()}; - return ring->readSpace(); -} +ALCuint PortCapture::availableSamples() +{ return mRing->readSpace(); } -ALCenum ALCportCapture_captureSamples(ALCportCapture *self, ALCvoid *buffer, ALCuint samples) +ALCenum PortCapture::captureSamples(ALCvoid *buffer, ALCuint samples) { - RingBuffer *ring{self->mRing.get()}; - ring->read(buffer, samples); + mRing->read(buffer, samples); return ALC_NO_ERROR; } @@ -519,21 +467,12 @@ void PortBackendFactory::probe(DevProbe type, std::string *outnames) } } -ALCbackend *PortBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *PortBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) - { - ALCportPlayback *backend; - NEW_OBJ(backend, ALCportPlayback)(device); - return backend; - } + return new PortPlayback{device}; if(type == ALCbackend_Capture) - { - ALCportCapture *backend; - NEW_OBJ(backend, ALCportCapture)(device); - return backend; - } - + return new PortCapture{device}; return nullptr; } diff --git a/Alc/backends/portaudio.h b/Alc/backends/portaudio.h index 581d4901..7687c6b3 100644 --- a/Alc/backends/portaudio.h +++ b/Alc/backends/portaudio.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index a99503e1..c911e365 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -729,8 +729,8 @@ void probeCaptureDevices(void) } -struct PulsePlayback final : public ALCbackend { - PulsePlayback(ALCdevice *device) noexcept : ALCbackend{device} { } +struct PulsePlayback final : public BackendBase { + PulsePlayback(ALCdevice *device) noexcept : BackendBase{device} { } ~PulsePlayback() override; static void bufferAttrCallbackC(pa_stream *stream, void *pdata); @@ -754,6 +754,14 @@ struct PulsePlayback final : public ALCbackend { static void streamMovedCallbackC(pa_stream *stream, void *pdata); void streamMovedCallback(pa_stream *stream); + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + ClockLatency getClockLatency() override; + void lock() noexcept override; + void unlock() noexcept override; + std::string mDeviceName; pa_buffer_attr mAttr; @@ -768,33 +776,9 @@ struct PulsePlayback final : public ALCbackend { ALuint mFrameSize{0u}; static constexpr inline const char *CurrentPrefix() noexcept { return "PulsePlayback::"; } + DEF_NEWDEL(PulsePlayback) }; -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) @@ -960,7 +944,7 @@ void PulsePlayback::streamMovedCallback(pa_stream *stream) } -ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name) +ALCenum PulsePlayback::open(const ALCchar *name) { const char *pulse_name{nullptr}; const char *dev_name{nullptr}; @@ -980,10 +964,10 @@ ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name) dev_name = iter->name.c_str(); } - std::tie(self->mLoop, self->mContext) = pulse_open(&PulsePlayback::contextStateCallbackC, self); - if(!self->mLoop) return ALC_INVALID_VALUE; + std::tie(mLoop, mContext) = pulse_open(&PulsePlayback::contextStateCallbackC, this); + if(!mLoop) return ALC_INVALID_VALUE; - unique_palock palock{self->mLoop}; + unique_palock palock{mLoop}; pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | PA_STREAM_FIX_CHANNELS}; @@ -1001,93 +985,89 @@ ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *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) + mStream = pulse_connect_stream(pulse_name, mLoop, mContext, flags, nullptr, &spec, nullptr, + ALCbackend_Playback); + if(!mStream) { palock = unique_palock{}; - pulse_close(self->mLoop, self->mContext, self->mStream); - self->mLoop = nullptr; - self->mContext = nullptr; + pulse_close(mLoop, mContext, mStream); + mLoop = nullptr; + mContext = nullptr; return ALC_INVALID_VALUE; } - pa_stream_set_moved_callback(self->mStream, &PulsePlayback::streamMovedCallbackC, self); - self->mFrameSize = pa_frame_size(pa_stream_get_sample_spec(self->mStream)); + pa_stream_set_moved_callback(mStream, &PulsePlayback::streamMovedCallbackC, this); + mFrameSize = pa_frame_size(pa_stream_get_sample_spec(mStream)); - self->mDeviceName = pa_stream_get_device_name(self->mStream); + mDeviceName = pa_stream_get_device_name(mStream); if(!dev_name) { - pa_operation *op{pa_context_get_sink_info_by_name(self->mContext, - self->mDeviceName.c_str(), &PulsePlayback::sinkNameCallbackC, self)}; - wait_for_operation(op, self->mLoop); + pa_operation *op{pa_context_get_sink_info_by_name(mContext, mDeviceName.c_str(), + &PulsePlayback::sinkNameCallbackC, this)}; + wait_for_operation(op, mLoop); } else - { - ALCdevice *device{self->mDevice}; - device->DeviceName = dev_name; - } + mDevice->DeviceName = dev_name; return ALC_NO_ERROR; } -ALCboolean PulsePlayback_reset(PulsePlayback *self) +ALCboolean PulsePlayback::reset() { - unique_palock palock{self->mLoop}; + unique_palock palock{mLoop}; - if(self->mStream) + if(mStream) { - pa_stream_set_state_callback(self->mStream, nullptr, nullptr); - pa_stream_set_moved_callback(self->mStream, nullptr, nullptr); - pa_stream_set_write_callback(self->mStream, nullptr, nullptr); - pa_stream_set_buffer_attr_callback(self->mStream, nullptr, nullptr); - pa_stream_disconnect(self->mStream); - pa_stream_unref(self->mStream); - self->mStream = nullptr; + pa_stream_set_state_callback(mStream, nullptr, nullptr); + pa_stream_set_moved_callback(mStream, nullptr, nullptr); + pa_stream_set_write_callback(mStream, nullptr, nullptr); + pa_stream_set_buffer_attr_callback(mStream, nullptr, nullptr); + pa_stream_disconnect(mStream); + pa_stream_unref(mStream); + mStream = nullptr; } - pa_operation *op{pa_context_get_sink_info_by_name(self->mContext, - self->mDeviceName.c_str(), &PulsePlayback::sinkInfoCallbackC, self)}; - wait_for_operation(op, self->mLoop); + pa_operation *op{pa_context_get_sink_info_by_name(mContext, mDeviceName.c_str(), + &PulsePlayback::sinkInfoCallbackC, this)}; + wait_for_operation(op, mLoop); - ALCdevice *device{self->mDevice}; pa_stream_flags_t flags{PA_STREAM_START_CORKED | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE}; if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", 0)) flags |= PA_STREAM_DONT_MOVE; - if(GetConfigValueBool(device->DeviceName.c_str(), "pulse", "adjust-latency", 0)) + if(GetConfigValueBool(mDevice->DeviceName.c_str(), "pulse", "adjust-latency", 0)) flags |= PA_STREAM_ADJUST_LATENCY; - if(GetConfigValueBool(device->DeviceName.c_str(), "pulse", "fix-rate", 0) || - !(device->Flags&DEVICE_FREQUENCY_REQUEST)) + if(GetConfigValueBool(mDevice->DeviceName.c_str(), "pulse", "fix-rate", 0) || + !(mDevice->Flags&DEVICE_FREQUENCY_REQUEST)) flags |= PA_STREAM_FIX_RATE; - switch(device->FmtType) + switch(mDevice->FmtType) { case DevFmtByte: - device->FmtType = DevFmtUByte; + mDevice->FmtType = DevFmtUByte; /* fall-through */ case DevFmtUByte: - self->mSpec.format = PA_SAMPLE_U8; + mSpec.format = PA_SAMPLE_U8; break; case DevFmtUShort: - device->FmtType = DevFmtShort; + mDevice->FmtType = DevFmtShort; /* fall-through */ case DevFmtShort: - self->mSpec.format = PA_SAMPLE_S16NE; + mSpec.format = PA_SAMPLE_S16NE; break; case DevFmtUInt: - device->FmtType = DevFmtInt; + mDevice->FmtType = DevFmtInt; /* fall-through */ case DevFmtInt: - self->mSpec.format = PA_SAMPLE_S32NE; + mSpec.format = PA_SAMPLE_S32NE; break; case DevFmtFloat: - self->mSpec.format = PA_SAMPLE_FLOAT32NE; + mSpec.format = PA_SAMPLE_FLOAT32NE; break; } - self->mSpec.rate = device->Frequency; - self->mSpec.channels = device->channelsFromFmt(); + mSpec.rate = mDevice->Frequency; + mSpec.channels = mDevice->channelsFromFmt(); - if(pa_sample_spec_valid(&self->mSpec) == 0) + if(pa_sample_spec_valid(&mSpec) == 0) { ERR("Invalid sample format\n"); return ALC_FALSE; @@ -1095,13 +1075,13 @@ ALCboolean PulsePlayback_reset(PulsePlayback *self) const char *mapname{nullptr}; pa_channel_map chanmap; - switch(device->FmtChans) + switch(mDevice->FmtChans) { case DevFmtMono: mapname = "mono"; break; case DevFmtAmbi3D: - device->FmtChans = DevFmtStereo; + mDevice->FmtChans = DevFmtStereo; /*fall-through*/ case DevFmtStereo: mapname = "front-left,front-right"; @@ -1124,54 +1104,52 @@ ALCboolean PulsePlayback_reset(PulsePlayback *self) } if(!pa_channel_map_parse(&chanmap, mapname)) { - ERR("Failed to build channel map for %s\n", DevFmtChannelsString(device->FmtChans)); + ERR("Failed to build channel map for %s\n", DevFmtChannelsString(mDevice->FmtChans)); return ALC_FALSE; } - SetDefaultWFXChannelOrder(device); + SetDefaultWFXChannelOrder(mDevice); - size_t period_size{device->UpdateSize * pa_frame_size(&self->mSpec)}; - self->mAttr.maxlength = -1; - self->mAttr.tlength = period_size * maxu(device->NumUpdates, 2); - self->mAttr.prebuf = 0; - self->mAttr.minreq = period_size; - self->mAttr.fragsize = -1; + size_t period_size{mDevice->UpdateSize * pa_frame_size(&mSpec)}; + mAttr.maxlength = -1; + mAttr.tlength = period_size * maxu(mDevice->NumUpdates, 2); + mAttr.prebuf = 0; + mAttr.minreq = period_size; + mAttr.fragsize = -1; - 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; + mStream = pulse_connect_stream(mDeviceName.c_str(), mLoop, mContext, flags, &mAttr, &mSpec, + &chanmap, ALCbackend_Playback); + if(!mStream) return ALC_FALSE; - pa_stream_set_state_callback(self->mStream, &PulsePlayback::streamStateCallbackC, self); - pa_stream_set_moved_callback(self->mStream, &PulsePlayback::streamMovedCallbackC, self); + pa_stream_set_state_callback(mStream, &PulsePlayback::streamStateCallbackC, this); + pa_stream_set_moved_callback(mStream, &PulsePlayback::streamMovedCallbackC, this); - self->mSpec = *(pa_stream_get_sample_spec(self->mStream)); - self->mFrameSize = pa_frame_size(&self->mSpec); + mSpec = *(pa_stream_get_sample_spec(mStream)); + mFrameSize = pa_frame_size(&mSpec); - if(device->Frequency != self->mSpec.rate) + if(mDevice->Frequency != mSpec.rate) { /* Server updated our playback rate, so modify the buffer attribs * accordingly. */ - device->NumUpdates = static_cast<ALuint>(clampd( - (ALdouble)self->mSpec.rate/device->Frequency*device->NumUpdates + 0.5, 2.0, 16.0)); + mDevice->NumUpdates = static_cast<ALuint>(clampd( + (ALdouble)mSpec.rate/mDevice->Frequency*mDevice->NumUpdates + 0.5, 2.0, 16.0)); - period_size = device->UpdateSize * self->mFrameSize; - self->mAttr.maxlength = -1; - self->mAttr.tlength = period_size * maxu(device->NumUpdates, 2); - self->mAttr.prebuf = 0; - self->mAttr.minreq = period_size; + period_size = mDevice->UpdateSize * mFrameSize; + mAttr.maxlength = -1; + mAttr.tlength = period_size * maxu(mDevice->NumUpdates, 2); + mAttr.prebuf = 0; + mAttr.minreq = period_size; - op = pa_stream_set_buffer_attr(self->mStream, &self->mAttr, stream_success_callback, - self->mLoop); - wait_for_operation(op, self->mLoop); + op = pa_stream_set_buffer_attr(mStream, &mAttr, stream_success_callback, mLoop); + wait_for_operation(op, mLoop); - device->Frequency = self->mSpec.rate; + mDevice->Frequency = mSpec.rate; } - pa_stream_set_buffer_attr_callback(self->mStream, &PulsePlayback::bufferAttrCallbackC, self); - self->bufferAttrCallback(self->mStream); + pa_stream_set_buffer_attr_callback(mStream, &PulsePlayback::bufferAttrCallbackC, this); + bufferAttrCallback(mStream); - device->NumUpdates = clampu( - (self->mAttr.tlength + self->mAttr.minreq/2u) / self->mAttr.minreq, 2u, 16u); - device->UpdateSize = self->mAttr.minreq / self->mFrameSize; + mDevice->NumUpdates = clampu((mAttr.tlength + mAttr.minreq/2u) / mAttr.minreq, 2u, 16u); + mDevice->UpdateSize = mAttr.minreq / mFrameSize; /* HACK: prebuf should be 0 as that's what we set it to. However on some * systems it comes back as non-0, so we have to make sure the device will @@ -1179,53 +1157,53 @@ ALCboolean PulsePlayback_reset(PulsePlayback *self) * may have unintended consequences, but it's better than not starting at * all. */ - if(self->mAttr.prebuf != 0) + if(mAttr.prebuf != 0) { - ALuint len{self->mAttr.prebuf / self->mFrameSize}; - if(len <= device->UpdateSize*device->NumUpdates) + ALuint len{mAttr.prebuf / mFrameSize}; + if(len <= mDevice->UpdateSize*mDevice->NumUpdates) ERR("Non-0 prebuf, %u samples (%u bytes), device has %u samples\n", - len, self->mAttr.prebuf, device->UpdateSize*device->NumUpdates); + len, mAttr.prebuf, mDevice->UpdateSize*mDevice->NumUpdates); else { ERR("Large prebuf, %u samples (%u bytes), increasing device from %u samples", - len, self->mAttr.prebuf, device->UpdateSize*device->NumUpdates); - device->NumUpdates = (len+device->UpdateSize-1) / device->UpdateSize; + len, mAttr.prebuf, mDevice->UpdateSize*mDevice->NumUpdates); + mDevice->NumUpdates = (len+mDevice->UpdateSize-1) / mDevice->UpdateSize; } } return ALC_TRUE; } -ALCboolean PulsePlayback_start(PulsePlayback *self) +ALCboolean PulsePlayback::start() { - unique_palock palock{self->mLoop}; + unique_palock palock{mLoop}; - pa_stream_set_write_callback(self->mStream, &PulsePlayback::streamWriteCallbackC, self); - pa_operation *op{pa_stream_cork(self->mStream, 0, stream_success_callback, self->mLoop)}; - wait_for_operation(op, self->mLoop); + pa_stream_set_write_callback(mStream, &PulsePlayback::streamWriteCallbackC, this); + pa_operation *op{pa_stream_cork(mStream, 0, stream_success_callback, mLoop)}; + wait_for_operation(op, mLoop); return ALC_TRUE; } -void PulsePlayback_stop(PulsePlayback *self) +void PulsePlayback::stop() { - unique_palock palock{self->mLoop}; + unique_palock palock{mLoop}; - pa_stream_set_write_callback(self->mStream, nullptr, nullptr); - pa_operation *op{pa_stream_cork(self->mStream, 1, stream_success_callback, self->mLoop)}; - wait_for_operation(op, self->mLoop); + pa_stream_set_write_callback(mStream, nullptr, nullptr); + pa_operation *op{pa_stream_cork(mStream, 1, stream_success_callback, mLoop)}; + wait_for_operation(op, mLoop); } -ClockLatency PulsePlayback_getClockLatency(PulsePlayback *self) +ClockLatency PulsePlayback::getClockLatency() { ClockLatency ret; pa_usec_t latency; int neg, err; - { palock_guard _{self->mLoop}; - ret.ClockTime = GetDeviceClockTime(self->mDevice); - err = pa_stream_get_latency(self->mStream, &latency, &neg); + { palock_guard _{mLoop}; + ret.ClockTime = GetDeviceClockTime(mDevice); + err = pa_stream_get_latency(mStream, &latency, &neg); } if(UNLIKELY(err != 0)) @@ -1247,19 +1225,15 @@ ClockLatency PulsePlayback_getClockLatency(PulsePlayback *self) } -void PulsePlayback_lock(PulsePlayback *self) -{ - pa_threaded_mainloop_lock(self->mLoop); -} +void PulsePlayback::lock() noexcept +{ pa_threaded_mainloop_lock(mLoop); } -void PulsePlayback_unlock(PulsePlayback *self) -{ - pa_threaded_mainloop_unlock(self->mLoop); -} +void PulsePlayback::unlock() noexcept +{ pa_threaded_mainloop_unlock(mLoop); } -struct PulseCapture final : public ALCbackend { - PulseCapture(ALCdevice *device) noexcept : ALCbackend{device} { } +struct PulseCapture final : public BackendBase { + PulseCapture(ALCdevice *device) noexcept : BackendBase{device} { } ~PulseCapture() override; static void contextStateCallbackC(pa_context *context, void *pdata); @@ -1274,6 +1248,15 @@ struct PulseCapture final : public ALCbackend { static void streamMovedCallbackC(pa_stream *stream, void *pdata); void streamMovedCallback(pa_stream *stream); + 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; + void lock() noexcept override; + void unlock() noexcept override; + std::string mDeviceName; const void *mCapStore{nullptr}; @@ -1291,33 +1274,9 @@ struct PulseCapture final : public ALCbackend { pa_context *mContext{nullptr}; static constexpr inline const char *CurrentPrefix() noexcept { return "PulseCapture::"; } + DEF_NEWDEL(PulseCapture) }; -void PulseCapture_Construct(PulseCapture *self, ALCdevice *device); -void PulseCapture_Destruct(PulseCapture *self); -ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name); -DECLARE_FORWARD(PulseCapture, ALCbackend, ALCboolean, reset) -ALCboolean PulseCapture_start(PulseCapture *self); -void PulseCapture_stop(PulseCapture *self); -ALCenum PulseCapture_captureSamples(PulseCapture *self, ALCvoid *buffer, ALCuint samples); -ALCuint PulseCapture_availableSamples(PulseCapture *self); -ClockLatency PulseCapture_getClockLatency(PulseCapture *self); -void PulseCapture_lock(PulseCapture *self); -void PulseCapture_unlock(PulseCapture *self); -DECLARE_DEFAULT_ALLOCATORS(PulseCapture) - -DEFINE_ALCBACKEND_VTABLE(PulseCapture); - - -void PulseCapture_Construct(PulseCapture *self, ALCdevice *device) -{ - new (self) PulseCapture{device}; - SET_VTABLE2(PulseCapture, ALCbackend, self); -} - -void PulseCapture_Destruct(PulseCapture *self) -{ self->~PulseCapture(); } - PulseCapture::~PulseCapture() { if(!mLoop) @@ -1377,11 +1336,9 @@ void PulseCapture::streamMovedCallback(pa_stream *stream) } -ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name) +ALCenum PulseCapture::open(const ALCchar *name) { - ALCdevice *device{self->mDevice}; const char *pulse_name{nullptr}; - if(name) { if(CaptureDevices.empty()) @@ -1394,38 +1351,38 @@ ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name) if(iter == CaptureDevices.cend()) return ALC_INVALID_VALUE; pulse_name = iter->device_name.c_str(); - device->DeviceName = iter->name; + mDevice->DeviceName = iter->name; } - std::tie(self->mLoop, self->mContext) = pulse_open(&PulseCapture::contextStateCallbackC, self); - if(!self->mLoop) return ALC_INVALID_VALUE; + std::tie(mLoop, mContext) = pulse_open(&PulseCapture::contextStateCallbackC, this); + if(!mLoop) return ALC_INVALID_VALUE; - unique_palock palock{self->mLoop}; + unique_palock palock{mLoop}; - switch(device->FmtType) + switch(mDevice->FmtType) { case DevFmtUByte: - self->mSpec.format = PA_SAMPLE_U8; + mSpec.format = PA_SAMPLE_U8; break; case DevFmtShort: - self->mSpec.format = PA_SAMPLE_S16NE; + mSpec.format = PA_SAMPLE_S16NE; break; case DevFmtInt: - self->mSpec.format = PA_SAMPLE_S32NE; + mSpec.format = PA_SAMPLE_S32NE; break; case DevFmtFloat: - self->mSpec.format = PA_SAMPLE_FLOAT32NE; + mSpec.format = PA_SAMPLE_FLOAT32NE; break; case DevFmtByte: case DevFmtUShort: case DevFmtUInt: - ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType)); + ERR("%s capture samples not supported\n", DevFmtTypeString(mDevice->FmtType)); return ALC_INVALID_VALUE; } const char *mapname{nullptr}; pa_channel_map chanmap; - switch(device->FmtChans) + switch(mDevice->FmtChans) { case DevFmtMono: mapname = "mono"; @@ -1449,166 +1406,161 @@ ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name) mapname = "front-left,front-right,front-center,lfe,rear-left,rear-right,side-left,side-right"; break; case DevFmtAmbi3D: - ERR("%s capture samples not supported\n", DevFmtChannelsString(device->FmtChans)); + ERR("%s capture samples not supported\n", DevFmtChannelsString(mDevice->FmtChans)); return ALC_INVALID_VALUE; } if(!pa_channel_map_parse(&chanmap, mapname)) { - ERR("Failed to build channel map for %s\n", DevFmtChannelsString(device->FmtChans)); + ERR("Failed to build channel map for %s\n", DevFmtChannelsString(mDevice->FmtChans)); return ALC_INVALID_VALUE; } - self->mSpec.rate = device->Frequency; - self->mSpec.channels = device->channelsFromFmt(); + mSpec.rate = mDevice->Frequency; + mSpec.channels = mDevice->channelsFromFmt(); - if(pa_sample_spec_valid(&self->mSpec) == 0) + if(pa_sample_spec_valid(&mSpec) == 0) { ERR("Invalid sample format\n"); return ALC_INVALID_VALUE; } - if(!pa_channel_map_init_auto(&chanmap, self->mSpec.channels, PA_CHANNEL_MAP_WAVEEX)) + if(!pa_channel_map_init_auto(&chanmap, mSpec.channels, PA_CHANNEL_MAP_WAVEEX)) { - ERR("Couldn't build map for channel count (%d)!\n", self->mSpec.channels); + ERR("Couldn't build map for channel count (%d)!\n", mSpec.channels); return ALC_INVALID_VALUE; } - ALuint samples{device->UpdateSize * device->NumUpdates}; - samples = maxu(samples, 100 * device->Frequency / 1000); + ALuint samples{mDevice->UpdateSize * mDevice->NumUpdates}; + samples = maxu(samples, 100 * mDevice->Frequency / 1000); - self->mAttr.minreq = -1; - self->mAttr.prebuf = -1; - self->mAttr.maxlength = samples * pa_frame_size(&self->mSpec); - self->mAttr.tlength = -1; - self->mAttr.fragsize = minu(samples, 50*device->Frequency/1000) * - pa_frame_size(&self->mSpec); + mAttr.minreq = -1; + mAttr.prebuf = -1; + mAttr.maxlength = samples * pa_frame_size(&mSpec); + mAttr.tlength = -1; + mAttr.fragsize = minu(samples, 50*mDevice->Frequency/1000) * pa_frame_size(&mSpec); pa_stream_flags_t flags{PA_STREAM_START_CORKED|PA_STREAM_ADJUST_LATENCY}; if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", 0)) flags |= PA_STREAM_DONT_MOVE; TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)"); - 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; + mStream = pulse_connect_stream(pulse_name, mLoop, mContext, flags, &mAttr, &mSpec, &chanmap, + ALCbackend_Capture); + if(!mStream) return ALC_INVALID_VALUE; - pa_stream_set_moved_callback(self->mStream, &PulseCapture::streamMovedCallbackC, self); - pa_stream_set_state_callback(self->mStream, &PulseCapture::streamStateCallbackC, self); + pa_stream_set_moved_callback(mStream, &PulseCapture::streamMovedCallbackC, this); + pa_stream_set_state_callback(mStream, &PulseCapture::streamStateCallbackC, this); - self->mDeviceName = pa_stream_get_device_name(self->mStream); - if(device->DeviceName.empty()) + mDeviceName = pa_stream_get_device_name(mStream); + if(mDevice->DeviceName.empty()) { - pa_operation *op{pa_context_get_source_info_by_name(self->mContext, - self->mDeviceName.c_str(), &PulseCapture::sourceNameCallbackC, self - )}; - wait_for_operation(op, self->mLoop); + pa_operation *op{pa_context_get_source_info_by_name(mContext, mDeviceName.c_str(), + &PulseCapture::sourceNameCallbackC, this)}; + wait_for_operation(op, mLoop); } return ALC_NO_ERROR; } -ALCboolean PulseCapture_start(PulseCapture *self) +ALCboolean PulseCapture::start() { - palock_guard _{self->mLoop}; - pa_operation *op{pa_stream_cork(self->mStream, 0, stream_success_callback, self->mLoop)}; - wait_for_operation(op, self->mLoop); + palock_guard _{mLoop}; + pa_operation *op{pa_stream_cork(mStream, 0, stream_success_callback, mLoop)}; + wait_for_operation(op, mLoop); return ALC_TRUE; } -void PulseCapture_stop(PulseCapture *self) +void PulseCapture::stop() { - palock_guard _{self->mLoop}; - pa_operation *op{pa_stream_cork(self->mStream, 1, stream_success_callback, self->mLoop)}; - wait_for_operation(op, self->mLoop); + palock_guard _{mLoop}; + pa_operation *op{pa_stream_cork(mStream, 1, stream_success_callback, mLoop)}; + wait_for_operation(op, mLoop); } -ALCenum PulseCapture_captureSamples(PulseCapture *self, ALCvoid *buffer, ALCuint samples) +ALCenum PulseCapture::captureSamples(ALCvoid *buffer, ALCuint samples) { - ALCdevice *device{self->mDevice}; - ALCuint todo{samples * static_cast<ALCuint>(pa_frame_size(&self->mSpec))}; + ALCuint todo{samples * static_cast<ALCuint>(pa_frame_size(&mSpec))}; /* Capture is done in fragment-sized chunks, so we loop until we get all * that's available */ - self->mLastReadable -= todo; - unique_palock palock{self->mLoop}; + mLastReadable -= todo; + unique_palock palock{mLoop}; while(todo > 0) { size_t rem{todo}; - if(self->mCapLen == 0) + if(mCapLen == 0) { - pa_stream_state_t state{pa_stream_get_state(self->mStream)}; + pa_stream_state_t state{pa_stream_get_state(mStream)}; if(!PA_STREAM_IS_GOOD(state)) { - aluHandleDisconnect(device, "Bad capture state: %u", state); + aluHandleDisconnect(mDevice, "Bad capture state: %u", state); return ALC_INVALID_DEVICE; } - if(pa_stream_peek(self->mStream, &self->mCapStore, &self->mCapLen) < 0) + if(pa_stream_peek(mStream, &mCapStore, &mCapLen) < 0) { ERR("pa_stream_peek() failed: %s\n", - pa_strerror(pa_context_errno(self->mContext))); - aluHandleDisconnect(device, "Failed retrieving capture samples: %s", - pa_strerror(pa_context_errno(self->mContext))); + pa_strerror(pa_context_errno(mContext))); + aluHandleDisconnect(mDevice, "Failed retrieving capture samples: %s", + pa_strerror(pa_context_errno(mContext))); return ALC_INVALID_DEVICE; } - self->mCapRemain = self->mCapLen; + mCapRemain = mCapLen; } - if(rem > self->mCapRemain) - rem = self->mCapRemain; + rem = minz(rem, mCapRemain); - memcpy(buffer, self->mCapStore, rem); + memcpy(buffer, mCapStore, rem); buffer = (ALbyte*)buffer + rem; todo -= rem; - self->mCapStore = (ALbyte*)self->mCapStore + rem; - self->mCapRemain -= rem; - if(self->mCapRemain == 0) + mCapStore = (ALbyte*)mCapStore + rem; + mCapRemain -= rem; + if(mCapRemain == 0) { - pa_stream_drop(self->mStream); - self->mCapLen = 0; + pa_stream_drop(mStream); + mCapLen = 0; } } palock.unlock(); if(todo > 0) - memset(buffer, ((device->FmtType==DevFmtUByte) ? 0x80 : 0), todo); + memset(buffer, ((mDevice->FmtType==DevFmtUByte) ? 0x80 : 0), todo); return ALC_NO_ERROR; } -ALCuint PulseCapture_availableSamples(PulseCapture *self) +ALCuint PulseCapture::availableSamples() { - ALCdevice *device{self->mDevice}; - size_t readable{self->mCapRemain}; + size_t readable{mCapRemain}; - if(device->Connected.load(std::memory_order_acquire)) + if(mDevice->Connected.load(std::memory_order_acquire)) { - palock_guard _{self->mLoop}; - size_t got{pa_stream_readable_size(self->mStream)}; + palock_guard _{mLoop}; + size_t got{pa_stream_readable_size(mStream)}; if(static_cast<ssize_t>(got) < 0) { ERR("pa_stream_readable_size() failed: %s\n", pa_strerror(got)); - aluHandleDisconnect(device, "Failed getting readable size: %s", pa_strerror(got)); + aluHandleDisconnect(mDevice, "Failed getting readable size: %s", pa_strerror(got)); } - else if(got > self->mCapLen) - readable += got - self->mCapLen; + else if(got > mCapLen) + readable += got - mCapLen; } - if(self->mLastReadable < readable) - self->mLastReadable = readable; - return self->mLastReadable / pa_frame_size(&self->mSpec); + if(mLastReadable < readable) + mLastReadable = readable; + return mLastReadable / pa_frame_size(&mSpec); } -ClockLatency PulseCapture_getClockLatency(PulseCapture *self) +ClockLatency PulseCapture::getClockLatency() { ClockLatency ret; pa_usec_t latency; int neg, err; - { palock_guard _{self->mLoop}; - ret.ClockTime = GetDeviceClockTime(self->mDevice); - err = pa_stream_get_latency(self->mStream, &latency, &neg); + { palock_guard _{mLoop}; + ret.ClockTime = GetDeviceClockTime(mDevice); + err = pa_stream_get_latency(mStream, &latency, &neg); } if(UNLIKELY(err != 0)) @@ -1625,15 +1577,11 @@ ClockLatency PulseCapture_getClockLatency(PulseCapture *self) } -void PulseCapture_lock(PulseCapture *self) -{ - pa_threaded_mainloop_lock(self->mLoop); -} +void PulseCapture::lock() noexcept +{ pa_threaded_mainloop_lock(mLoop); } -void PulseCapture_unlock(PulseCapture *self) -{ - pa_threaded_mainloop_unlock(self->mLoop); -} +void PulseCapture::unlock() noexcept +{ pa_threaded_mainloop_unlock(mLoop); } } // namespace @@ -1720,21 +1668,12 @@ void PulseBackendFactory::probe(DevProbe type, std::string *outnames) } } -ALCbackend *PulseBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *PulseBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) - { - PulsePlayback *backend; - NEW_OBJ(backend, PulsePlayback)(device); - return backend; - } + return new PulsePlayback{device}; if(type == ALCbackend_Capture) - { - PulseCapture *backend; - NEW_OBJ(backend, PulseCapture)(device); - return backend; - } - + return new PulseCapture{device}; return nullptr; } diff --git a/Alc/backends/pulseaudio.h b/Alc/backends/pulseaudio.h index eb7045dc..07d74b64 100644 --- a/Alc/backends/pulseaudio.h +++ b/Alc/backends/pulseaudio.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/qsa.cpp b/Alc/backends/qsa.cpp index c7c8e90b..7641ad57 100644 --- a/Alc/backends/qsa.cpp +++ b/Alc/backends/qsa.cpp @@ -170,26 +170,20 @@ void deviceList(int type, al::vector<DevMap> *devmap) /* Wrappers to use an old-style backend with the new interface. */ -struct PlaybackWrapper final : public ALCbackend { - PlaybackWrapper(ALCdevice *device) noexcept : ALCbackend{device} { } +struct PlaybackWrapper final : public BackendBase { + PlaybackWrapper(ALCdevice *device) noexcept : BackendBase{device} { } ~PlaybackWrapper() override; + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + std::unique_ptr<qsa_data> mExtraData; -}; -static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device); -static void PlaybackWrapper_Destruct(PlaybackWrapper *self); -static ALCenum PlaybackWrapper_open(PlaybackWrapper *self, const ALCchar *name); -static ALCboolean PlaybackWrapper_reset(PlaybackWrapper *self); -static ALCboolean PlaybackWrapper_start(PlaybackWrapper *self); -static void PlaybackWrapper_stop(PlaybackWrapper *self); -static DECLARE_FORWARD2(PlaybackWrapper, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, ALCuint, availableSamples) -static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, lock) -static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(PlaybackWrapper) -DEFINE_ALCBACKEND_VTABLE(PlaybackWrapper); + static constexpr inline const char *CurrentPrefix() noexcept { return "PlaybackWrapper::"; } + DEF_NEWDEL(PlaybackWrapper) +}; FORCE_ALIGN static int qsa_proc_playback(void *ptr) @@ -213,7 +207,7 @@ FORCE_ALIGN static int qsa_proc_playback(void *ptr) const ALint frame_size = device->frameSizeFromFmt(); - PlaybackWrapper_lock(self); + self->lock(); while(!data->mKillNow.load(std::memory_order_acquire)) { pollfd pollitem{}; @@ -221,9 +215,9 @@ FORCE_ALIGN static int qsa_proc_playback(void *ptr) pollitem.events = POLLOUT; /* Select also works like time slice to OS */ - PlaybackWrapper_unlock(self); + self->unlock(); sret = poll(&pollitem, 1, 2000); - PlaybackWrapper_lock(self); + self->lock(); if(sret == -1) { if(errno == EINTR || errno == EAGAIN) @@ -272,7 +266,7 @@ FORCE_ALIGN static int qsa_proc_playback(void *ptr) } } } - PlaybackWrapper_unlock(self); + self->unlock(); return 0; } @@ -614,68 +608,44 @@ static void qsa_stop_playback(PlaybackWrapper *self) } -static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device) -{ - new (self) PlaybackWrapper{device}; - SET_VTABLE2(PlaybackWrapper, ALCbackend, self); -} - -static void PlaybackWrapper_Destruct(PlaybackWrapper *self) -{ self->~PlaybackWrapper(); } - PlaybackWrapper::~PlaybackWrapper() { if(mExtraData) qsa_close_playback(this); } -static ALCenum PlaybackWrapper_open(PlaybackWrapper *self, const ALCchar *name) -{ - return qsa_open_playback(self, name); -} - -static ALCboolean PlaybackWrapper_reset(PlaybackWrapper *self) -{ - return qsa_reset_playback(self); -} +ALCenum PlaybackWrapper::open(const ALCchar *name) +{ return qsa_open_playback(this, name); } -static ALCboolean PlaybackWrapper_start(PlaybackWrapper *self) -{ - return qsa_start_playback(self); -} +ALCboolean PlaybackWrapper::reset() +{ return qsa_reset_playback(this); } -static void PlaybackWrapper_stop(PlaybackWrapper *self) -{ - qsa_stop_playback(self); -} +ALCboolean PlaybackWrapper::start() +{ return qsa_start_playback(this); } +void PlaybackWrapper::stop() +{ qsa_stop_playback(this); } /***********/ /* Capture */ /***********/ -struct CaptureWrapper final : public ALCbackend { - CaptureWrapper(ALCdevice *device) noexcept : ALCbackend{device} { } +struct CaptureWrapper final : public BackendBase { + CaptureWrapper(ALCdevice *device) noexcept : BackendBase{device} { } ~CaptureWrapper() override; - std::unique_ptr<qsa_data> mExtraData; -}; + ALCenum open(const ALCchar *name) override; + ALCboolean start() override; + void stop() override; + ALCenum captureSamples(void *buffer, ALCuint samples) override; + ALCuint availableSamples() override; -static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device); -static void CaptureWrapper_Destruct(CaptureWrapper *self); -static ALCenum CaptureWrapper_open(CaptureWrapper *self, const ALCchar *name); -static DECLARE_FORWARD(CaptureWrapper, ALCbackend, ALCboolean, reset) -static ALCboolean CaptureWrapper_start(CaptureWrapper *self); -static void CaptureWrapper_stop(CaptureWrapper *self); -static ALCenum CaptureWrapper_captureSamples(CaptureWrapper *self, void *buffer, ALCuint samples); -static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self); -static DECLARE_FORWARD(CaptureWrapper, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, lock) -static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(CaptureWrapper) -DEFINE_ALCBACKEND_VTABLE(CaptureWrapper); + std::unique_ptr<qsa_data> mExtraData; + static constexpr inline const char *CurrentPrefix() noexcept { return "CaptureWrapper::"; } + DEF_NEWDEL(CaptureWrapper) +}; static ALCenum qsa_open_capture(CaptureWrapper *self, const ALCchar *deviceName) { @@ -917,46 +887,26 @@ static ALCenum qsa_capture_samples(CaptureWrapper *self, ALCvoid *buffer, ALCuin } -static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device) -{ - new (self) CaptureWrapper{device}; - SET_VTABLE2(CaptureWrapper, ALCbackend, self); -} - -static void CaptureWrapper_Destruct(CaptureWrapper *self) -{ self->~CaptureWrapper(); } - CaptureWrapper::~CaptureWrapper() { if(mExtraData) qsa_close_capture(this); } -static ALCenum CaptureWrapper_open(CaptureWrapper *self, const ALCchar *name) -{ - return qsa_open_capture(self, name); -} +ALCenum CaptureWrapper::open(const ALCchar *name) +{ return qsa_open_capture(this, name); } -static ALCboolean CaptureWrapper_start(CaptureWrapper *self) -{ - qsa_start_capture(self); - return ALC_TRUE; -} +ALCboolean CaptureWrapper::start() +{ qsa_start_capture(this); return ALC_TRUE; } -static void CaptureWrapper_stop(CaptureWrapper *self) -{ - qsa_stop_capture(self); -} +void CaptureWrapper::stop() +{ qsa_stop_capture(this); } -static ALCenum CaptureWrapper_captureSamples(CaptureWrapper *self, void *buffer, ALCuint samples) -{ - return qsa_capture_samples(self, buffer, samples); -} +ALCenum CaptureWrapper::captureSamples(void *buffer, ALCuint samples) +{ return qsa_capture_samples(this, buffer, samples); } -static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self) -{ - return qsa_available_samples(self); -} +ALCuint CaptureWrapper::availableSamples() +{ return qsa_available_samples(this); } } // namespace @@ -1002,22 +952,13 @@ void QSABackendFactory::probe(DevProbe type, std::string *outnames) } } -ALCbackend *QSABackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *QSABackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) - { - PlaybackWrapper *backend; - NEW_OBJ(backend, PlaybackWrapper)(device); - return backend; - } + return new PlaybackWrapper{device}; if(type == ALCbackend_Capture) - { - CaptureWrapper *backend; - NEW_OBJ(backend, CaptureWrapper)(device); - return backend; - } - - return NULL; + return new CaptureWrapper{device}; + return nullptr; } BackendFactory &QSABackendFactory::getFactory() diff --git a/Alc/backends/qsa.h b/Alc/backends/qsa.h index 99d80106..46cc7dd1 100644 --- a/Alc/backends/qsa.h +++ b/Alc/backends/qsa.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/sdl2.cpp b/Alc/backends/sdl2.cpp index 985afa2e..91d1cece 100644 --- a/Alc/backends/sdl2.cpp +++ b/Alc/backends/sdl2.cpp @@ -43,13 +43,20 @@ namespace { constexpr ALCchar defaultDeviceName[] = DEVNAME_PREFIX "Default Device"; -struct ALCsdl2Backend final : public ALCbackend { - ALCsdl2Backend(ALCdevice *device) noexcept : ALCbackend{device} { } - ~ALCsdl2Backend() override; +struct Sdl2Backend final : public BackendBase { + Sdl2Backend(ALCdevice *device) noexcept : BackendBase{device} { } + ~Sdl2Backend() override; static void audioCallbackC(void *ptr, Uint8 *stream, int len); void audioCallback(Uint8 *stream, int len); + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + void lock() noexcept override; + void unlock() noexcept override; + SDL_AudioDeviceID mDeviceID{0u}; ALsizei mFrameSize{0}; @@ -57,55 +64,32 @@ struct ALCsdl2Backend final : public ALCbackend { DevFmtChannels mFmtChans{}; DevFmtType mFmtType{}; ALuint mUpdateSize{0u}; -}; - -void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device); -void ALCsdl2Backend_Destruct(ALCsdl2Backend *self); -ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name); -ALCboolean ALCsdl2Backend_reset(ALCsdl2Backend *self); -ALCboolean ALCsdl2Backend_start(ALCsdl2Backend *self); -void ALCsdl2Backend_stop(ALCsdl2Backend *self); -DECLARE_FORWARD2(ALCsdl2Backend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -DECLARE_FORWARD(ALCsdl2Backend, ALCbackend, ALCuint, availableSamples) -DECLARE_FORWARD(ALCsdl2Backend, ALCbackend, ClockLatency, getClockLatency) -void ALCsdl2Backend_lock(ALCsdl2Backend *self); -void ALCsdl2Backend_unlock(ALCsdl2Backend *self); -DECLARE_DEFAULT_ALLOCATORS(ALCsdl2Backend) - -DEFINE_ALCBACKEND_VTABLE(ALCsdl2Backend); - -void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device) -{ - new (self) ALCsdl2Backend{device}; - SET_VTABLE2(ALCsdl2Backend, ALCbackend, self); -} -void ALCsdl2Backend_Destruct(ALCsdl2Backend *self) -{ self->~ALCsdl2Backend(); } + static constexpr inline const char *CurrentPrefix() noexcept { return "ALCsdl2Playback::"; } + DEF_NEWDEL(Sdl2Backend) +}; -ALCsdl2Backend::~ALCsdl2Backend() +Sdl2Backend::~Sdl2Backend() { if(mDeviceID) SDL_CloseAudioDevice(mDeviceID); mDeviceID = 0; } -void ALCsdl2Backend::audioCallbackC(void *ptr, Uint8 *stream, int len) -{ static_cast<ALCsdl2Backend*>(ptr)->audioCallback(stream, len); } +void Sdl2Backend::audioCallbackC(void *ptr, Uint8 *stream, int len) +{ static_cast<Sdl2Backend*>(ptr)->audioCallback(stream, len); } -void ALCsdl2Backend::audioCallback(Uint8 *stream, int len) +void Sdl2Backend::audioCallback(Uint8 *stream, int len) { assert((len % mFrameSize) == 0); aluMixData(mDevice, stream, len / mFrameSize); } -ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) +ALCenum Sdl2Backend::open(const ALCchar *name) { - ALCdevice *device{self->mDevice}; SDL_AudioSpec want{}, have{}; - - want.freq = device->Frequency; - switch(device->FmtType) + want.freq = mDevice->Frequency; + switch(mDevice->FmtType) { case DevFmtUByte: want.format = AUDIO_U8; break; case DevFmtByte: want.format = AUDIO_S8; break; @@ -115,35 +99,35 @@ ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) case DevFmtInt: want.format = AUDIO_S32SYS; break; case DevFmtFloat: want.format = AUDIO_F32; break; } - want.channels = (device->FmtChans == DevFmtMono) ? 1 : 2; - want.samples = device->UpdateSize; - want.callback = &ALCsdl2Backend::audioCallbackC; - want.userdata = self; + want.channels = (mDevice->FmtChans == DevFmtMono) ? 1 : 2; + want.samples = mDevice->UpdateSize; + want.callback = &Sdl2Backend::audioCallbackC; + want.userdata = this; /* Passing nullptr to SDL_OpenAudioDevice opens a default, which isn't * necessarily the first in the list. */ if(!name || strcmp(name, defaultDeviceName) == 0) - self->mDeviceID = SDL_OpenAudioDevice(nullptr, SDL_FALSE, &want, &have, - SDL_AUDIO_ALLOW_ANY_CHANGE); + mDeviceID = SDL_OpenAudioDevice(nullptr, SDL_FALSE, &want, &have, + SDL_AUDIO_ALLOW_ANY_CHANGE); else { const size_t prefix_len = strlen(DEVNAME_PREFIX); if(strncmp(name, DEVNAME_PREFIX, prefix_len) == 0) - self->mDeviceID = SDL_OpenAudioDevice(name+prefix_len, SDL_FALSE, &want, &have, - SDL_AUDIO_ALLOW_ANY_CHANGE); + mDeviceID = SDL_OpenAudioDevice(name+prefix_len, SDL_FALSE, &want, &have, + SDL_AUDIO_ALLOW_ANY_CHANGE); else - self->mDeviceID = SDL_OpenAudioDevice(name, SDL_FALSE, &want, &have, - SDL_AUDIO_ALLOW_ANY_CHANGE); + mDeviceID = SDL_OpenAudioDevice(name, SDL_FALSE, &want, &have, + SDL_AUDIO_ALLOW_ANY_CHANGE); } - if(self->mDeviceID == 0) + if(mDeviceID == 0) return ALC_INVALID_VALUE; - device->Frequency = have.freq; + mDevice->Frequency = have.freq; if(have.channels == 1) - device->FmtChans = DevFmtMono; + mDevice->FmtChans = DevFmtMono; else if(have.channels == 2) - device->FmtChans = DevFmtStereo; + mDevice->FmtChans = DevFmtStereo; else { ERR("Got unhandled SDL channel count: %d\n", (int)have.channels); @@ -151,61 +135,54 @@ ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) } switch(have.format) { - case AUDIO_U8: device->FmtType = DevFmtUByte; break; - case AUDIO_S8: device->FmtType = DevFmtByte; break; - case AUDIO_U16SYS: device->FmtType = DevFmtUShort; break; - case AUDIO_S16SYS: device->FmtType = DevFmtShort; break; - case AUDIO_S32SYS: device->FmtType = DevFmtInt; break; - case AUDIO_F32SYS: device->FmtType = DevFmtFloat; break; + case AUDIO_U8: mDevice->FmtType = DevFmtUByte; break; + case AUDIO_S8: mDevice->FmtType = DevFmtByte; break; + case AUDIO_U16SYS: mDevice->FmtType = DevFmtUShort; break; + case AUDIO_S16SYS: mDevice->FmtType = DevFmtShort; break; + case AUDIO_S32SYS: mDevice->FmtType = DevFmtInt; break; + case AUDIO_F32SYS: mDevice->FmtType = DevFmtFloat; break; default: ERR("Got unsupported SDL format: 0x%04x\n", have.format); return ALC_INVALID_VALUE; } - device->UpdateSize = have.samples; - device->NumUpdates = 2; /* SDL always (tries to) use two periods. */ + mDevice->UpdateSize = have.samples; + mDevice->NumUpdates = 2; /* SDL always (tries to) use two periods. */ - self->mFrameSize = device->frameSizeFromFmt(); - self->mFrequency = device->Frequency; - self->mFmtChans = device->FmtChans; - self->mFmtType = device->FmtType; - self->mUpdateSize = device->UpdateSize; + mFrameSize = mDevice->frameSizeFromFmt(); + mFrequency = mDevice->Frequency; + mFmtChans = mDevice->FmtChans; + mFmtType = mDevice->FmtType; + mUpdateSize = mDevice->UpdateSize; - device->DeviceName = name ? name : defaultDeviceName; + mDevice->DeviceName = name ? name : defaultDeviceName; return ALC_NO_ERROR; } -ALCboolean ALCsdl2Backend_reset(ALCsdl2Backend *self) +ALCboolean Sdl2Backend::reset() { - ALCdevice *device{self->mDevice}; - device->Frequency = self->mFrequency; - device->FmtChans = self->mFmtChans; - device->FmtType = self->mFmtType; - device->UpdateSize = self->mUpdateSize; - device->NumUpdates = 2; - SetDefaultWFXChannelOrder(device); + mDevice->Frequency = mFrequency; + mDevice->FmtChans = mFmtChans; + mDevice->FmtType = mFmtType; + mDevice->UpdateSize = mUpdateSize; + mDevice->NumUpdates = 2; + SetDefaultWFXChannelOrder(mDevice); return ALC_TRUE; } -ALCboolean ALCsdl2Backend_start(ALCsdl2Backend *self) +ALCboolean Sdl2Backend::start() { - SDL_PauseAudioDevice(self->mDeviceID, 0); + SDL_PauseAudioDevice(mDeviceID, 0); return ALC_TRUE; } -void ALCsdl2Backend_stop(ALCsdl2Backend *self) -{ - SDL_PauseAudioDevice(self->mDeviceID, 1); -} +void Sdl2Backend::stop() +{ SDL_PauseAudioDevice(mDeviceID, 1); } -void ALCsdl2Backend_lock(ALCsdl2Backend *self) -{ - SDL_LockAudioDevice(self->mDeviceID); -} +void Sdl2Backend::lock() noexcept +{ SDL_LockAudioDevice(mDeviceID); } -void ALCsdl2Backend_unlock(ALCsdl2Backend *self) -{ - SDL_UnlockAudioDevice(self->mDeviceID); -} +void Sdl2Backend::unlock() noexcept +{ SDL_UnlockAudioDevice(mDeviceID); } } // namespace @@ -248,14 +225,9 @@ void SDL2BackendFactory::probe(DevProbe type, std::string *outnames) } } -ALCbackend *SDL2BackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *SDL2BackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) - { - ALCsdl2Backend *backend; - NEW_OBJ(backend, ALCsdl2Backend)(device); - return backend; - } - + return new Sdl2Backend{device}; return nullptr; } diff --git a/Alc/backends/sdl2.h b/Alc/backends/sdl2.h index 7bf4d0e4..7a4ae9eb 100644 --- a/Alc/backends/sdl2.h +++ b/Alc/backends/sdl2.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp index d185adab..2c2397e6 100644 --- a/Alc/backends/sndio.cpp +++ b/Alc/backends/sndio.cpp @@ -42,12 +42,17 @@ namespace { static const ALCchar sndio_device[] = "SndIO Default"; -struct SndioPlayback final : public ALCbackend { - SndioPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } +struct SndioPlayback final : public BackendBase { + SndioPlayback(ALCdevice *device) noexcept : BackendBase{device} { } ~SndioPlayback() override; int mixerProc(); + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + sio_hdl *mSndHandle{nullptr}; al::vector<ALubyte> mBuffer; @@ -56,32 +61,9 @@ struct SndioPlayback final : public ALCbackend { std::thread mThread; static constexpr inline const char *CurrentPrefix() noexcept { return "SndioPlayback::"; } + DEF_NEWDEL(SndioPlayback) }; -void SndioPlayback_Construct(SndioPlayback *self, ALCdevice *device); -void SndioPlayback_Destruct(SndioPlayback *self); -ALCenum SndioPlayback_open(SndioPlayback *self, const ALCchar *name); -ALCboolean SndioPlayback_reset(SndioPlayback *self); -ALCboolean SndioPlayback_start(SndioPlayback *self); -void SndioPlayback_stop(SndioPlayback *self); -DECLARE_FORWARD2(SndioPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -DECLARE_FORWARD(SndioPlayback, ALCbackend, ALCuint, availableSamples) -DECLARE_FORWARD(SndioPlayback, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(SndioPlayback, ALCbackend, void, lock) -DECLARE_FORWARD(SndioPlayback, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(SndioPlayback) - -DEFINE_ALCBACKEND_VTABLE(SndioPlayback); - -void SndioPlayback_Construct(SndioPlayback *self, ALCdevice *device) -{ - new (self) SndioPlayback{device}; - SET_VTABLE2(SndioPlayback, ALCbackend, self); -} - -void SndioPlayback_Destruct(SndioPlayback *self) -{ self->~SndioPlayback(); } - SndioPlayback::~SndioPlayback() { if(mSndHandle) @@ -102,18 +84,18 @@ int SndioPlayback::mixerProc() auto WritePtr = static_cast<ALubyte*>(mBuffer.data()); size_t len{mBuffer.size()}; - SndioPlayback_lock(this); + lock(); aluMixData(mDevice, WritePtr, len/frameSize); - SndioPlayback_unlock(this); + unlock(); while(len > 0 && !mKillNow.load(std::memory_order_acquire)) { size_t wrote{sio_write(mSndHandle, WritePtr, len)}; if(wrote == 0) { ERR("sio_write failed\n"); - SndioPlayback_lock(this); + lock(); aluHandleDisconnect(mDevice, "Failed to write playback samples"); - SndioPlayback_unlock(this); + unlock(); break; } @@ -126,37 +108,33 @@ int SndioPlayback::mixerProc() } -ALCenum SndioPlayback_open(SndioPlayback *self, const ALCchar *name) +ALCenum SndioPlayback::open(const ALCchar *name) { - ALCdevice *device{self->mDevice}; - if(!name) name = sndio_device; else if(strcmp(name, sndio_device) != 0) return ALC_INVALID_VALUE; - self->mSndHandle = sio_open(nullptr, SIO_PLAY, 0); - if(self->mSndHandle == nullptr) + mSndHandle = sio_open(nullptr, SIO_PLAY, 0); + if(mSndHandle == nullptr) { ERR("Could not open device\n"); return ALC_INVALID_VALUE; } - device->DeviceName = name; + mDevice->DeviceName = name; return ALC_NO_ERROR; } -ALCboolean SndioPlayback_reset(SndioPlayback *self) +ALCboolean SndioPlayback::reset() { - ALCdevice *device{self->mDevice}; sio_par par; - sio_initpar(&par); - par.rate = device->Frequency; - par.pchan = ((device->FmtChans != DevFmtMono) ? 2 : 1); + par.rate = mDevice->Frequency; + par.pchan = ((mDevice->FmtChans != DevFmtMono) ? 2 : 1); - switch(device->FmtType) + switch(mDevice->FmtType) { case DevFmtByte: par.bits = 8; @@ -186,11 +164,11 @@ ALCboolean SndioPlayback_reset(SndioPlayback *self) } par.le = SIO_LE_NATIVE; - par.round = device->UpdateSize; - par.appbufsz = device->UpdateSize * (device->NumUpdates-1); - if(!par.appbufsz) par.appbufsz = device->UpdateSize; + par.round = mDevice->UpdateSize; + par.appbufsz = mDevice->UpdateSize * (mDevice->NumUpdates-1); + if(!par.appbufsz) par.appbufsz = mDevice->UpdateSize; - if(!sio_setpar(self->mSndHandle, &par) || !sio_getpar(self->mSndHandle, &par)) + if(!sio_setpar(mSndHandle, &par) || !sio_getpar(mSndHandle, &par)) { ERR("Failed to set device parameters\n"); return ALC_FALSE; @@ -202,49 +180,49 @@ ALCboolean SndioPlayback_reset(SndioPlayback *self) return ALC_FALSE; } - device->Frequency = par.rate; - device->FmtChans = ((par.pchan==1) ? DevFmtMono : DevFmtStereo); + mDevice->Frequency = par.rate; + mDevice->FmtChans = ((par.pchan==1) ? DevFmtMono : DevFmtStereo); if(par.bits == 8 && par.sig == 1) - device->FmtType = DevFmtByte; + mDevice->FmtType = DevFmtByte; else if(par.bits == 8 && par.sig == 0) - device->FmtType = DevFmtUByte; + mDevice->FmtType = DevFmtUByte; else if(par.bits == 16 && par.sig == 1) - device->FmtType = DevFmtShort; + mDevice->FmtType = DevFmtShort; else if(par.bits == 16 && par.sig == 0) - device->FmtType = DevFmtUShort; + mDevice->FmtType = DevFmtUShort; else if(par.bits == 32 && par.sig == 1) - device->FmtType = DevFmtInt; + mDevice->FmtType = DevFmtInt; else if(par.bits == 32 && par.sig == 0) - device->FmtType = DevFmtUInt; + mDevice->FmtType = DevFmtUInt; else { ERR("Unhandled sample format: %s %u-bit\n", (par.sig?"signed":"unsigned"), par.bits); return ALC_FALSE; } - SetDefaultChannelOrder(device); + SetDefaultChannelOrder(mDevice); - device->UpdateSize = par.round; - device->NumUpdates = (par.bufsz/par.round) + 1; + mDevice->UpdateSize = par.round; + mDevice->NumUpdates = (par.bufsz/par.round) + 1; - self->mBuffer.resize(device->UpdateSize * device->frameSizeFromFmt()); - std::fill(self->mBuffer.begin(), self->mBuffer.end(), 0); + mBuffer.resize(mDevice->UpdateSize * mDevice->frameSizeFromFmt()); + std::fill(mBuffer.begin(), mBuffer.end(), 0); return ALC_TRUE; } -ALCboolean SndioPlayback_start(SndioPlayback *self) +ALCboolean SndioPlayback::start() { - if(!sio_start(self->mSndHandle)) + if(!sio_start(mSndHandle)) { ERR("Error starting playback\n"); return ALC_FALSE; } try { - self->mKillNow.store(false, std::memory_order_release); - self->mThread = std::thread{std::mem_fn(&SndioPlayback::mixerProc), self}; + mKillNow.store(false, std::memory_order_release); + mThread = std::thread{std::mem_fn(&SndioPlayback::mixerProc), this}; return ALC_TRUE; } catch(std::exception& e) { @@ -252,27 +230,33 @@ ALCboolean SndioPlayback_start(SndioPlayback *self) } catch(...) { } - sio_stop(self->mSndHandle); + sio_stop(mSndHandle); return ALC_FALSE; } -void SndioPlayback_stop(SndioPlayback *self) +void SndioPlayback::stop() { - if(self->mKillNow.exchange(true, std::memory_order_acq_rel) || !self->mThread.joinable()) + if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) return; - self->mThread.join(); + mThread.join(); - if(!sio_stop(self->mSndHandle)) + if(!sio_stop(mSndHandle)) ERR("Error stopping device\n"); } -struct SndioCapture final : public ALCbackend { - SndioCapture(ALCdevice *device) noexcept : ALCbackend{device} { } +struct SndioCapture final : public BackendBase { + SndioCapture(ALCdevice *device) noexcept : BackendBase{device} { } ~SndioCapture() override; int recordProc(); + ALCenum open(const ALCchar *name) override; + ALCboolean start() override; + void stop() override; + ALCenum captureSamples(void *buffer, ALCuint samples) override; + ALCuint availableSamples() override; + sio_hdl *mSndHandle{nullptr}; RingBufferPtr mRing; @@ -281,32 +265,9 @@ struct SndioCapture final : public ALCbackend { std::thread mThread; static constexpr inline const char *CurrentPrefix() noexcept { return "SndioCapture::"; } + DEF_NEWDEL(SndioCapture) }; -void SndioCapture_Construct(SndioCapture *self, ALCdevice *device); -void SndioCapture_Destruct(SndioCapture *self); -ALCenum SndioCapture_open(SndioCapture *self, const ALCchar *name); -DECLARE_FORWARD(SndioCapture, ALCbackend, ALCboolean, reset) -ALCboolean SndioCapture_start(SndioCapture *self); -void SndioCapture_stop(SndioCapture *self); -ALCenum SndioCapture_captureSamples(SndioCapture *self, void *buffer, ALCuint samples); -ALCuint SndioCapture_availableSamples(SndioCapture *self); -DECLARE_FORWARD(SndioCapture, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(SndioCapture, ALCbackend, void, lock) -DECLARE_FORWARD(SndioCapture, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(SndioCapture) - -DEFINE_ALCBACKEND_VTABLE(SndioCapture); - -void SndioCapture_Construct(SndioCapture *self, ALCdevice *device) -{ - new (self) SndioCapture{device}; - SET_VTABLE2(SndioCapture, ALCbackend, self); -} - -void SndioCapture_Destruct(SndioCapture *self) -{ self->~SndioCapture(); } - SndioCapture::~SndioCapture() { if(mSndHandle) @@ -346,9 +307,9 @@ int SndioCapture::recordProc() size_t got{sio_read(mSndHandle, data.first.buf, minz(todo-total, data.first.len))}; if(!got) { - SndioCapture_lock(this); + lock(); aluHandleDisconnect(mDevice, "Failed to read capture samples"); - SndioCapture_unlock(this); + unlock(); break; } @@ -363,26 +324,24 @@ int SndioCapture::recordProc() } -ALCenum SndioCapture_open(SndioCapture *self, const ALCchar *name) +ALCenum SndioCapture::open(const ALCchar *name) { - ALCdevice *device{self->mDevice}; - sio_par par; - if(!name) name = sndio_device; else if(strcmp(name, sndio_device) != 0) return ALC_INVALID_VALUE; - self->mSndHandle = sio_open(nullptr, SIO_REC, 0); - if(self->mSndHandle == nullptr) + mSndHandle = sio_open(nullptr, SIO_REC, 0); + if(mSndHandle == nullptr) { ERR("Could not open device\n"); return ALC_INVALID_VALUE; } + sio_par par; sio_initpar(&par); - switch(device->FmtType) + switch(mDevice->FmtType) { case DevFmtByte: par.bps = 1; @@ -409,23 +368,23 @@ ALCenum SndioCapture_open(SndioCapture *self, const ALCchar *name) par.sig = 0; break; case DevFmtFloat: - ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType)); + ERR("%s capture samples not supported\n", DevFmtTypeString(mDevice->FmtType)); return ALC_INVALID_VALUE; } par.bits = par.bps * 8; par.le = SIO_LE_NATIVE; par.msb = SIO_LE_NATIVE ? 0 : 1; - par.rchan = device->channelsFromFmt(); - par.rate = device->Frequency; + par.rchan = mDevice->channelsFromFmt(); + par.rate = mDevice->Frequency; - par.appbufsz = maxu(device->UpdateSize*device->NumUpdates, (device->Frequency+9)/10); - par.round = clampu(par.appbufsz/device->NumUpdates, (device->Frequency+99)/100, - (device->Frequency+19)/20); + par.appbufsz = maxu(mDevice->UpdateSize*mDevice->NumUpdates, (mDevice->Frequency+9)/10); + par.round = clampu(par.appbufsz/mDevice->NumUpdates, (mDevice->Frequency+99)/100, + (mDevice->Frequency+19)/20); - device->UpdateSize = par.round; - device->NumUpdates = maxu(par.appbufsz/par.round, 1); + mDevice->UpdateSize = par.round; + mDevice->NumUpdates = maxu(par.appbufsz/par.round, 1); - if(!sio_setpar(self->mSndHandle, &par) || !sio_getpar(self->mSndHandle, &par)) + if(!sio_setpar(mSndHandle, &par) || !sio_getpar(mSndHandle, &par)) { ERR("Failed to set device parameters\n"); return ALC_INVALID_VALUE; @@ -437,46 +396,46 @@ ALCenum SndioCapture_open(SndioCapture *self, const ALCchar *name) return ALC_INVALID_VALUE; } - if(!((device->FmtType == DevFmtByte && par.bits == 8 && par.sig != 0) || - (device->FmtType == DevFmtUByte && par.bits == 8 && par.sig == 0) || - (device->FmtType == DevFmtShort && par.bits == 16 && par.sig != 0) || - (device->FmtType == DevFmtUShort && par.bits == 16 && par.sig == 0) || - (device->FmtType == DevFmtInt && par.bits == 32 && par.sig != 0) || - (device->FmtType == DevFmtUInt && par.bits == 32 && par.sig == 0)) || - device->channelsFromFmt() != (ALsizei)par.rchan || - device->Frequency != par.rate) + if(!((mDevice->FmtType == DevFmtByte && par.bits == 8 && par.sig != 0) || + (mDevice->FmtType == DevFmtUByte && par.bits == 8 && par.sig == 0) || + (mDevice->FmtType == DevFmtShort && par.bits == 16 && par.sig != 0) || + (mDevice->FmtType == DevFmtUShort && par.bits == 16 && par.sig == 0) || + (mDevice->FmtType == DevFmtInt && par.bits == 32 && par.sig != 0) || + (mDevice->FmtType == DevFmtUInt && par.bits == 32 && par.sig == 0)) || + mDevice->channelsFromFmt() != (ALsizei)par.rchan || + mDevice->Frequency != par.rate) { ERR("Failed to set format %s %s %uhz, got %c%u %u-channel %uhz instead\n", - DevFmtTypeString(device->FmtType), DevFmtChannelsString(device->FmtChans), - device->Frequency, par.sig?'s':'u', par.bits, par.rchan, par.rate); + DevFmtTypeString(mDevice->FmtType), DevFmtChannelsString(mDevice->FmtChans), + mDevice->Frequency, par.sig?'s':'u', par.bits, par.rchan, par.rate); return ALC_INVALID_VALUE; } - self->mRing = CreateRingBuffer(device->UpdateSize*device->NumUpdates, par.bps*par.rchan, false); - if(!self->mRing) + mRing = CreateRingBuffer(mDevice->UpdateSize*mDevice->NumUpdates, par.bps*par.rchan, false); + if(!mRing) { ERR("Failed to allocate %u-byte ringbuffer\n", - device->UpdateSize*device->NumUpdates*par.bps*par.rchan); + mDevice->UpdateSize*mDevice->NumUpdates*par.bps*par.rchan); return ALC_OUT_OF_MEMORY; } - SetDefaultChannelOrder(device); + SetDefaultChannelOrder(mDevice); - device->DeviceName = name; + mDevice->DeviceName = name; return ALC_NO_ERROR; } -ALCboolean SndioCapture_start(SndioCapture *self) +ALCboolean SndioCapture::start() { - if(!sio_start(self->mSndHandle)) + if(!sio_start(mSndHandle)) { ERR("Error starting playback\n"); return ALC_FALSE; } try { - self->mKillNow.store(false, std::memory_order_release); - self->mThread = std::thread{std::mem_fn(&SndioCapture::recordProc), self}; + mKillNow.store(false, std::memory_order_release); + mThread = std::thread{std::mem_fn(&SndioCapture::recordProc), this}; return ALC_TRUE; } catch(std::exception& e) { @@ -484,32 +443,28 @@ ALCboolean SndioCapture_start(SndioCapture *self) } catch(...) { } - sio_stop(self->mSndHandle); + sio_stop(mSndHandle); return ALC_FALSE; } -void SndioCapture_stop(SndioCapture *self) +void SndioCapture::stop() { - if(self->mKillNow.exchange(true, std::memory_order_acq_rel) || !self->mThread.joinable()) + if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) return; - self->mThread.join(); + mThread.join(); - if(!sio_stop(self->mSndHandle)) + if(!sio_stop(mSndHandle)) ERR("Error stopping device\n"); } -ALCenum SndioCapture_captureSamples(SndioCapture *self, void *buffer, ALCuint samples) +ALCenum SndioCapture::captureSamples(void *buffer, ALCuint samples) { - RingBuffer *ring{self->mRing.get()}; - ring->read(buffer, samples); + mRing->read(buffer, samples); return ALC_NO_ERROR; } -ALCuint SndioCapture_availableSamples(SndioCapture *self) -{ - RingBuffer *ring{self->mRing.get()}; - return ring->readSpace(); -} +ALCuint SndioCapture::availableSamples() +{ return mRing->readSpace(); } } // namespace @@ -537,20 +492,11 @@ void SndIOBackendFactory::probe(DevProbe type, std::string *outnames) } } -ALCbackend *SndIOBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *SndIOBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) - { - SndioPlayback *backend; - NEW_OBJ(backend, SndioPlayback)(device); - return backend; - } + return new SndioPlayback{device}; if(type == ALCbackend_Capture) - { - SndioCapture *backend; - NEW_OBJ(backend, SndioCapture)(device); - return backend; - } - + return new SndioCapture{device}; return nullptr; } diff --git a/Alc/backends/sndio.h b/Alc/backends/sndio.h index 20e99afb..bf8d833d 100644 --- a/Alc/backends/sndio.h +++ b/Alc/backends/sndio.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/solaris.cpp b/Alc/backends/solaris.cpp index 7d7e3883..6463c225 100644 --- a/Alc/backends/solaris.cpp +++ b/Alc/backends/solaris.cpp @@ -54,12 +54,17 @@ constexpr ALCchar solaris_device[] = "Solaris Default"; const char *solaris_driver = "/dev/audio"; -struct SolarisBackend final : public ALCbackend { - SolarisBackend(ALCdevice *device) noexcept : ALCbackend{device} { } +struct SolarisBackend final : public BackendBase { + SolarisBackend(ALCdevice *device) noexcept : BackendBase{device} { } ~SolarisBackend() override; int mixerProc(); + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + int mFd{-1}; al::vector<ALubyte> mBuffer; @@ -68,32 +73,9 @@ struct SolarisBackend final : public ALCbackend { std::thread mThread; static constexpr inline const char *CurrentPrefix() noexcept { return "SolarisBackend::"; } + DEF_NEWDEL(SolarisBackend) }; -void SolarisBackend_Construct(SolarisBackend *self, ALCdevice *device); -void SolarisBackend_Destruct(SolarisBackend *self); -ALCenum SolarisBackend_open(SolarisBackend *self, const ALCchar *name); -ALCboolean SolarisBackend_reset(SolarisBackend *self); -ALCboolean SolarisBackend_start(SolarisBackend *self); -void SolarisBackend_stop(SolarisBackend *self); -DECLARE_FORWARD2(SolarisBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -DECLARE_FORWARD(SolarisBackend, ALCbackend, ALCuint, availableSamples) -DECLARE_FORWARD(SolarisBackend, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(SolarisBackend, ALCbackend, void, lock) -DECLARE_FORWARD(SolarisBackend, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(SolarisBackend) - -DEFINE_ALCBACKEND_VTABLE(SolarisBackend); - -void SolarisBackend_Construct(SolarisBackend *self, ALCdevice *device) -{ - new (self) SolarisBackend{device}; - SET_VTABLE2(SolarisBackend, ALCbackend, self); -} - -void SolarisBackend_Destruct(SolarisBackend *self) -{ self->~SolarisBackend(); } - SolarisBackend::~SolarisBackend() { if(mFd != -1) @@ -108,7 +90,7 @@ int SolarisBackend::mixerProc() const int frame_size{mDevice->frameSizeFromFmt()}; - SolarisBackend_lock(this); + lock(); while(!mKillNow.load(std::memory_order_acquire) && mDevice->Connected.load(std::memory_order_acquire)) { @@ -116,9 +98,9 @@ int SolarisBackend::mixerProc() pollitem.fd = mFd; pollitem.events = POLLOUT; - SolarisBackend_unlock(this); + unlock(); int pret{poll(&pollitem, 1, 1000)}; - SolarisBackend_lock(this); + lock(); if(pret < 0) { if(errno == EINTR || errno == EAGAIN) @@ -154,49 +136,43 @@ int SolarisBackend::mixerProc() write_ptr += wrote; } } - SolarisBackend_unlock(this); + unlock(); return 0; } -ALCenum SolarisBackend_open(SolarisBackend *self, const ALCchar *name) +ALCenum SolarisBackend::open(const ALCchar *name) { if(!name) name = solaris_device; else if(strcmp(name, solaris_device) != 0) return ALC_INVALID_VALUE; - self->mFd = open(solaris_driver, O_WRONLY); - if(self->mFd == -1) + mFd = ::open(solaris_driver, O_WRONLY); + if(mFd == -1) { ERR("Could not open %s: %s\n", solaris_driver, strerror(errno)); return ALC_INVALID_VALUE; } - ALCdevice *device{self->mDevice}; - device->DeviceName = name; - + mDevice->DeviceName = name; return ALC_NO_ERROR; } -ALCboolean SolarisBackend_reset(SolarisBackend *self) +ALCboolean SolarisBackend::reset() { - ALCdevice *device{self->mDevice}; audio_info_t info; - ALsizei frameSize; - ALsizei numChannels; - AUDIO_INITINFO(&info); - info.play.sample_rate = device->Frequency; + info.play.sample_rate = mDevice->Frequency; - if(device->FmtChans != DevFmtMono) - device->FmtChans = DevFmtStereo; - numChannels = device->channelsFromFmt(); + if(mDevice->FmtChans != DevFmtMono) + mDevice->FmtChans = DevFmtStereo; + ALsizei numChannels{mDevice->channelsFromFmt()}; info.play.channels = numChannels; - switch(device->FmtType) + switch(mDevice->FmtType) { case DevFmtByte: info.play.precision = 8; @@ -210,7 +186,7 @@ ALCboolean SolarisBackend_reset(SolarisBackend *self) case DevFmtInt: case DevFmtUInt: case DevFmtFloat: - device->FmtType = DevFmtShort; + mDevice->FmtType = DevFmtShort; /* fall-through */ case DevFmtShort: info.play.precision = 16; @@ -218,48 +194,48 @@ ALCboolean SolarisBackend_reset(SolarisBackend *self) break; } - frameSize = numChannels * device->bytesFromFmt(); - info.play.buffer_size = device->UpdateSize*device->NumUpdates * frameSize; + ALsizei frameSize{numChannels * mDevice->bytesFromFmt()}; + info.play.buffer_size = mDevice->UpdateSize*mDevice->NumUpdates * frameSize; - if(ioctl(self->mFd, AUDIO_SETINFO, &info) < 0) + if(ioctl(mFd, AUDIO_SETINFO, &info) < 0) { ERR("ioctl failed: %s\n", strerror(errno)); return ALC_FALSE; } - if(device->channelsFromFmt() != (ALsizei)info.play.channels) + if(mDevice->channelsFromFmt() != (ALsizei)info.play.channels) { - ERR("Failed to set %s, got %u channels instead\n", DevFmtChannelsString(device->FmtChans), + ERR("Failed to set %s, got %u channels instead\n", DevFmtChannelsString(mDevice->FmtChans), info.play.channels); return ALC_FALSE; } - if(!((info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR8 && device->FmtType == DevFmtUByte) || - (info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR && device->FmtType == DevFmtByte) || - (info.play.precision == 16 && info.play.encoding == AUDIO_ENCODING_LINEAR && device->FmtType == DevFmtShort) || - (info.play.precision == 32 && info.play.encoding == AUDIO_ENCODING_LINEAR && device->FmtType == DevFmtInt))) + if(!((info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR8 && mDevice->FmtType == DevFmtUByte) || + (info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR && mDevice->FmtType == DevFmtByte) || + (info.play.precision == 16 && info.play.encoding == AUDIO_ENCODING_LINEAR && mDevice->FmtType == DevFmtShort) || + (info.play.precision == 32 && info.play.encoding == AUDIO_ENCODING_LINEAR && mDevice->FmtType == DevFmtInt))) { - ERR("Could not set %s samples, got %d (0x%x)\n", DevFmtTypeString(device->FmtType), + ERR("Could not set %s samples, got %d (0x%x)\n", DevFmtTypeString(mDevice->FmtType), info.play.precision, info.play.encoding); return ALC_FALSE; } - device->Frequency = info.play.sample_rate; - device->UpdateSize = (info.play.buffer_size/device->NumUpdates) + 1; + mDevice->Frequency = info.play.sample_rate; + mDevice->UpdateSize = (info.play.buffer_size/mDevice->NumUpdates) + 1; - SetDefaultChannelOrder(device); + SetDefaultChannelOrder(mDevice); - self->mBuffer.resize(device->UpdateSize * device->frameSizeFromFmt()); - std::fill(self->mBuffer.begin(), self->mBuffer.end(), 0); + mBuffer.resize(mDevice->UpdateSize * mDevice->frameSizeFromFmt()); + std::fill(mBuffer.begin(), mBuffer.end(), 0); return ALC_TRUE; } -ALCboolean SolarisBackend_start(SolarisBackend *self) +ALCboolean SolarisBackend::start() { try { - self->mKillNow.store(false, std::memory_order_release); - self->mThread = std::thread{std::mem_fn(&SolarisBackend::mixerProc), self}; + mKillNow.store(false, std::memory_order_release); + mThread = std::thread{std::mem_fn(&SolarisBackend::mixerProc), this}; return ALC_TRUE; } catch(std::exception& e) { @@ -270,14 +246,13 @@ ALCboolean SolarisBackend_start(SolarisBackend *self) return ALC_FALSE; } -void SolarisBackend_stop(SolarisBackend *self) +void SolarisBackend::stop() { - if(self->mKillNow.exchange(true, std::memory_order_acq_rel) || !self->mThread.joinable()) + if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) return; + mThread.join(); - self->mThread.join(); - - if(ioctl(self->mFd, AUDIO_DRAIN) < 0) + if(ioctl(mFd, AUDIO_DRAIN) < 0) ERR("Error draining device: %s\n", strerror(errno)); } @@ -317,14 +292,9 @@ void SolarisBackendFactory::probe(DevProbe type, std::string *outnames) } } -ALCbackend *SolarisBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *SolarisBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) - { - SolarisBackend *backend; - NEW_OBJ(backend, SolarisBackend)(device); - return backend; - } - + return new SolarisBackend{device}; return nullptr; } diff --git a/Alc/backends/solaris.h b/Alc/backends/solaris.h index 73f4a467..f675d6d7 100644 --- a/Alc/backends/solaris.h +++ b/Alc/backends/solaris.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index 5c97324e..0d3d067e 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -494,19 +494,25 @@ DWORD WasapiProxy::messageHandler(void *ptr) } -struct WasapiPlayback final : public ALCbackend, WasapiProxy { - WasapiPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } +struct WasapiPlayback final : public BackendBase, WasapiProxy { + WasapiPlayback(ALCdevice *device) noexcept : BackendBase{device} { } ~WasapiPlayback() override; int mixerProc(); + ALCenum open(const ALCchar *name) override; HRESULT openProxy() override; void closeProxy() override; + ALCboolean reset() override; HRESULT resetProxy() override; + ALCboolean start() override; HRESULT startProxy() override; + void stop() override; void stopProxy() override; + ClockLatency getClockLatency() override; + std::wstring mDevId; IMMDevice *mMMDev{nullptr}; @@ -522,32 +528,9 @@ struct WasapiPlayback final : public ALCbackend, WasapiProxy { std::thread mThread; static constexpr inline const char *CurrentPrefix() noexcept { return "WasapiPlayback::"; } + DEF_NEWDEL(WasapiPlayback) }; -void WasapiPlayback_Construct(WasapiPlayback *self, ALCdevice *device); -void WasapiPlayback_Destruct(WasapiPlayback *self); -ALCenum WasapiPlayback_open(WasapiPlayback *self, const ALCchar *name); -ALCboolean WasapiPlayback_reset(WasapiPlayback *self); -ALCboolean WasapiPlayback_start(WasapiPlayback *self); -void WasapiPlayback_stop(WasapiPlayback *self); -DECLARE_FORWARD2(WasapiPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) -DECLARE_FORWARD(WasapiPlayback, ALCbackend, ALCuint, availableSamples) -ClockLatency WasapiPlayback_getClockLatency(WasapiPlayback *self); -DECLARE_FORWARD(WasapiPlayback, ALCbackend, void, lock) -DECLARE_FORWARD(WasapiPlayback, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(WasapiPlayback) - -DEFINE_ALCBACKEND_VTABLE(WasapiPlayback); - -void WasapiPlayback_Construct(WasapiPlayback *self, ALCdevice *device) -{ - new (self) WasapiPlayback{device}; - SET_VTABLE2(WasapiPlayback, ALCbackend, self); -} - -void WasapiPlayback_Destruct(WasapiPlayback *self) -{ self->~WasapiPlayback(); } - WasapiPlayback::~WasapiPlayback() { if(mMsgEvent) @@ -576,9 +559,9 @@ FORCE_ALIGN int WasapiPlayback::mixerProc() if(FAILED(hr)) { ERR("CoInitializeEx(nullptr, COINIT_MULTITHREADED) failed: 0x%08lx\n", hr); - WasapiPlayback_lock(this); + lock(); aluHandleDisconnect(mDevice, "COM init failed: 0x%08lx", hr); - WasapiPlayback_unlock(this); + unlock(); return 1; } @@ -594,9 +577,9 @@ FORCE_ALIGN int WasapiPlayback::mixerProc() if(FAILED(hr)) { ERR("Failed to get padding: 0x%08lx\n", hr); - WasapiPlayback_lock(this); + lock(); aluHandleDisconnect(mDevice, "Failed to retrieve buffer padding: 0x%08lx", hr); - WasapiPlayback_unlock(this); + unlock(); break; } mPadding.store(written, std::memory_order_relaxed); @@ -615,18 +598,18 @@ FORCE_ALIGN int WasapiPlayback::mixerProc() hr = mRender->GetBuffer(len, &buffer); if(SUCCEEDED(hr)) { - WasapiPlayback_lock(this); + lock(); aluMixData(mDevice, buffer, len); mPadding.store(written + len, std::memory_order_relaxed); - WasapiPlayback_unlock(this); + unlock(); hr = mRender->ReleaseBuffer(len, 0); } if(FAILED(hr)) { ERR("Failed to buffer data: 0x%08lx\n", hr); - WasapiPlayback_lock(this); + lock(); aluHandleDisconnect(mDevice, "Failed to send playback samples: 0x%08lx", hr); - WasapiPlayback_unlock(this); + unlock(); break; } } @@ -676,13 +659,13 @@ ALCboolean MakeExtensible(WAVEFORMATEXTENSIBLE *out, const WAVEFORMATEX *in) return ALC_TRUE; } -ALCenum WasapiPlayback_open(WasapiPlayback *self, const ALCchar *deviceName) +ALCenum WasapiPlayback::open(const ALCchar *name) { - HRESULT hr = S_OK; + HRESULT hr{S_OK}; - self->mNotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); - self->mMsgEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); - if(self->mNotifyEvent == nullptr || self->mMsgEvent == nullptr) + mNotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); + mMsgEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); + if(mNotifyEvent == nullptr || mMsgEvent == nullptr) { ERR("Failed to create message events: %lu\n", GetLastError()); hr = E_FAIL; @@ -690,35 +673,34 @@ ALCenum WasapiPlayback_open(WasapiPlayback *self, const ALCchar *deviceName) if(SUCCEEDED(hr)) { - if(deviceName) + if(name) { if(PlaybackDevices.empty()) { - ThreadRequest req = { self->mMsgEvent, 0 }; + ThreadRequest req = { mMsgEvent, 0 }; if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, ALL_DEVICE_PROBE)) (void)WaitForResponse(&req); } hr = E_FAIL; auto iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), - [deviceName](const DevMap &entry) -> bool - { return entry.name == deviceName || entry.endpoint_guid == deviceName; } + [name](const DevMap &entry) -> bool + { return entry.name == name || entry.endpoint_guid == name; } ); if(iter == PlaybackDevices.cend()) { - std::wstring wname{utf8_to_wstr(deviceName)}; + std::wstring wname{utf8_to_wstr(name)}; iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), [&wname](const DevMap &entry) -> bool { return entry.devid == wname; } ); } if(iter == PlaybackDevices.cend()) - WARN("Failed to find device name matching \"%s\"\n", deviceName); + WARN("Failed to find device name matching \"%s\"\n", name); else { - ALCdevice *device{self->mDevice}; - self->mDevId = iter->devid; - device->DeviceName = iter->name; + mDevId = iter->devid; + mDevice->DeviceName = iter->name; hr = S_OK; } } @@ -726,8 +708,8 @@ ALCenum WasapiPlayback_open(WasapiPlayback *self, const ALCchar *deviceName) if(SUCCEEDED(hr)) { - ThreadRequest req{ self->mMsgEvent, 0 }; - auto proxy = static_cast<WasapiProxy*>(self); + ThreadRequest req{ mMsgEvent, 0 }; + auto proxy = static_cast<WasapiProxy*>(this); hr = E_FAIL; if(PostThreadMessage(ThreadID, WM_USER_OpenDevice, (WPARAM)&req, (LPARAM)proxy)) @@ -738,14 +720,14 @@ ALCenum WasapiPlayback_open(WasapiPlayback *self, const ALCchar *deviceName) if(FAILED(hr)) { - if(self->mNotifyEvent != nullptr) - CloseHandle(self->mNotifyEvent); - self->mNotifyEvent = nullptr; - if(self->mMsgEvent != nullptr) - CloseHandle(self->mMsgEvent); - self->mMsgEvent = nullptr; + if(mNotifyEvent != nullptr) + CloseHandle(mNotifyEvent); + mNotifyEvent = nullptr; + if(mMsgEvent != nullptr) + CloseHandle(mMsgEvent); + mMsgEvent = nullptr; - self->mDevId.clear(); + mDevId.clear(); ERR("Device init failed: 0x%08lx\n", hr); return ALC_INVALID_VALUE; @@ -798,12 +780,11 @@ void WasapiPlayback::closeProxy() } -ALCboolean WasapiPlayback_reset(WasapiPlayback *self) +ALCboolean WasapiPlayback::reset() { - ThreadRequest req{ self->mMsgEvent, 0 }; + ThreadRequest req{ mMsgEvent, 0 }; + auto proxy = static_cast<WasapiProxy*>(this); HRESULT hr{E_FAIL}; - - auto proxy = static_cast<WasapiProxy*>(self); if(PostThreadMessage(ThreadID, WM_USER_ResetDevice, (WPARAM)&req, (LPARAM)proxy)) hr = WaitForResponse(&req); @@ -1066,12 +1047,11 @@ HRESULT WasapiPlayback::resetProxy() } -ALCboolean WasapiPlayback_start(WasapiPlayback *self) +ALCboolean WasapiPlayback::start() { - ThreadRequest req{ self->mMsgEvent, 0 }; + ThreadRequest req{ mMsgEvent, 0 }; + auto proxy = static_cast<WasapiProxy*>(this); HRESULT hr{E_FAIL}; - - auto proxy = static_cast<WasapiProxy*>(self); if(PostThreadMessage(ThreadID, WM_USER_StartDevice, (WPARAM)&req, (LPARAM)proxy)) hr = WaitForResponse(&req); @@ -1113,10 +1093,10 @@ HRESULT WasapiPlayback::startProxy() } -void WasapiPlayback_stop(WasapiPlayback *self) +void WasapiPlayback::stop() { - ThreadRequest req{ self->mMsgEvent, 0 }; - auto proxy = static_cast<WasapiProxy*>(self); + ThreadRequest req{ mMsgEvent, 0 }; + auto proxy = static_cast<WasapiProxy*>(this); if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)proxy)) (void)WaitForResponse(&req); } @@ -1135,34 +1115,39 @@ void WasapiPlayback::stopProxy() } -ClockLatency WasapiPlayback_getClockLatency(WasapiPlayback *self) +ClockLatency WasapiPlayback::getClockLatency() { ClockLatency ret; - WasapiPlayback_lock(self); - ALCdevice *device{self->mDevice}; - ret.ClockTime = GetDeviceClockTime(device); - ret.Latency = std::chrono::seconds{self->mPadding.load(std::memory_order_relaxed)}; - ret.Latency /= device->Frequency; - WasapiPlayback_unlock(self); + lock(); + ret.ClockTime = GetDeviceClockTime(mDevice); + ret.Latency = std::chrono::seconds{mPadding.load(std::memory_order_relaxed)}; + ret.Latency /= mDevice->Frequency; + unlock(); return ret; } -struct WasapiCapture final : public ALCbackend, WasapiProxy { - WasapiCapture(ALCdevice *device) noexcept : ALCbackend{device} { } +struct WasapiCapture final : public BackendBase, WasapiProxy { + WasapiCapture(ALCdevice *device) noexcept : BackendBase{device} { } ~WasapiCapture() override; int recordProc(); + ALCenum open(const ALCchar *name) override; HRESULT openProxy() override; void closeProxy() override; HRESULT resetProxy() override; + ALCboolean start() override; HRESULT startProxy() override; + void stop() override; void stopProxy() override; + ALCenum captureSamples(void *buffer, ALCuint samples) override; + ALCuint availableSamples() override; + std::wstring mDevId; IMMDevice *mMMDev{nullptr}; @@ -1180,33 +1165,9 @@ struct WasapiCapture final : public ALCbackend, WasapiProxy { std::thread mThread; static constexpr inline const char *CurrentPrefix() noexcept { return "WasapiCapture::"; } + DEF_NEWDEL(WasapiCapture) }; -void WasapiCapture_Construct(WasapiCapture *self, ALCdevice *device); -void WasapiCapture_Destruct(WasapiCapture *self); -ALCenum WasapiCapture_open(WasapiCapture *self, const ALCchar *name); -DECLARE_FORWARD(WasapiCapture, ALCbackend, ALCboolean, reset) -ALCboolean WasapiCapture_start(WasapiCapture *self); -void WasapiCapture_stop(WasapiCapture *self); -ALCenum WasapiCapture_captureSamples(WasapiCapture *self, ALCvoid *buffer, ALCuint samples); -ALuint WasapiCapture_availableSamples(WasapiCapture *self); -DECLARE_FORWARD(WasapiCapture, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(WasapiCapture, ALCbackend, void, lock) -DECLARE_FORWARD(WasapiCapture, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(WasapiCapture) - -DEFINE_ALCBACKEND_VTABLE(WasapiCapture); - - -void WasapiCapture_Construct(WasapiCapture *self, ALCdevice *device) -{ - new (self) WasapiCapture{device}; - SET_VTABLE2(WasapiCapture, ALCbackend, self); -} - -void WasapiCapture_Destruct(WasapiCapture *self) -{ self->~WasapiCapture(); } - WasapiCapture::~WasapiCapture() { if(mMsgEvent) @@ -1232,9 +1193,9 @@ FORCE_ALIGN int WasapiCapture::recordProc() if(FAILED(hr)) { ERR("CoInitializeEx(nullptr, COINIT_MULTITHREADED) failed: 0x%08lx\n", hr); - WasapiCapture_lock(this); + lock(); aluHandleDisconnect(mDevice, "COM init failed: 0x%08lx", hr); - WasapiCapture_unlock(this); + unlock(); return 1; } @@ -1306,9 +1267,9 @@ FORCE_ALIGN int WasapiCapture::recordProc() if(FAILED(hr)) { - WasapiCapture_lock(this); + lock(); aluHandleDisconnect(mDevice, "Failed to capture samples: 0x%08lx", hr); - WasapiCapture_unlock(this); + unlock(); break; } @@ -1322,13 +1283,13 @@ FORCE_ALIGN int WasapiCapture::recordProc() } -ALCenum WasapiCapture_open(WasapiCapture *self, const ALCchar *deviceName) +ALCenum WasapiCapture::open(const ALCchar *name) { HRESULT hr{S_OK}; - self->mNotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); - self->mMsgEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); - if(self->mNotifyEvent == nullptr || self->mMsgEvent == nullptr) + mNotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); + mMsgEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); + if(mNotifyEvent == nullptr || mMsgEvent == nullptr) { ERR("Failed to create message events: %lu\n", GetLastError()); hr = E_FAIL; @@ -1336,35 +1297,34 @@ ALCenum WasapiCapture_open(WasapiCapture *self, const ALCchar *deviceName) if(SUCCEEDED(hr)) { - if(deviceName) + if(name) { if(CaptureDevices.empty()) { - ThreadRequest req{ self->mMsgEvent, 0 }; + ThreadRequest req{ mMsgEvent, 0 }; if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, CAPTURE_DEVICE_PROBE)) (void)WaitForResponse(&req); } hr = E_FAIL; auto iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), - [deviceName](const DevMap &entry) -> bool - { return entry.name == deviceName || entry.endpoint_guid == deviceName; } + [name](const DevMap &entry) -> bool + { return entry.name == name || entry.endpoint_guid == name; } ); if(iter == CaptureDevices.cend()) { - std::wstring wname{utf8_to_wstr(deviceName)}; + std::wstring wname{utf8_to_wstr(name)}; iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), [&wname](const DevMap &entry) -> bool { return entry.devid == wname; } ); } if(iter == CaptureDevices.cend()) - WARN("Failed to find device name matching \"%s\"\n", deviceName); + WARN("Failed to find device name matching \"%s\"\n", name); else { - ALCdevice *device{self->mDevice}; - self->mDevId = iter->devid; - device->DeviceName = iter->name; + mDevId = iter->devid; + mDevice->DeviceName = iter->name; hr = S_OK; } } @@ -1372,10 +1332,9 @@ ALCenum WasapiCapture_open(WasapiCapture *self, const ALCchar *deviceName) if(SUCCEEDED(hr)) { - ThreadRequest req{ self->mMsgEvent, 0 }; - + ThreadRequest req{ mMsgEvent, 0 }; + auto proxy = static_cast<WasapiProxy*>(this); hr = E_FAIL; - auto proxy = static_cast<WasapiProxy*>(self); if(PostThreadMessage(ThreadID, WM_USER_OpenDevice, (WPARAM)&req, (LPARAM)proxy)) hr = WaitForResponse(&req); else @@ -1384,24 +1343,23 @@ ALCenum WasapiCapture_open(WasapiCapture *self, const ALCchar *deviceName) if(FAILED(hr)) { - if(self->mNotifyEvent != nullptr) - CloseHandle(self->mNotifyEvent); - self->mNotifyEvent = nullptr; - if(self->mMsgEvent != nullptr) - CloseHandle(self->mMsgEvent); - self->mMsgEvent = nullptr; + if(mNotifyEvent != nullptr) + CloseHandle(mNotifyEvent); + mNotifyEvent = nullptr; + if(mMsgEvent != nullptr) + CloseHandle(mMsgEvent); + mMsgEvent = nullptr; - self->mDevId.clear(); + mDevId.clear(); ERR("Device init failed: 0x%08lx\n", hr); return ALC_INVALID_VALUE; } else { - ThreadRequest req{ self->mMsgEvent, 0 }; - + ThreadRequest req{ mMsgEvent, 0 }; + auto proxy = static_cast<WasapiProxy*>(this); hr = E_FAIL; - auto proxy = static_cast<WasapiProxy*>(self); if(PostThreadMessage(ThreadID, WM_USER_ResetDevice, (WPARAM)&req, (LPARAM)proxy)) hr = WaitForResponse(&req); else @@ -1694,12 +1652,11 @@ HRESULT WasapiCapture::resetProxy() } -ALCboolean WasapiCapture_start(WasapiCapture *self) +ALCboolean WasapiCapture::start() { - ThreadRequest req{ self->mMsgEvent, 0 }; + ThreadRequest req{ mMsgEvent, 0 }; + auto proxy = static_cast<WasapiProxy*>(this); HRESULT hr{E_FAIL}; - - auto proxy = static_cast<WasapiProxy*>(self); if(PostThreadMessage(ThreadID, WM_USER_StartDevice, (WPARAM)&req, (LPARAM)proxy)) hr = WaitForResponse(&req); @@ -1744,10 +1701,10 @@ HRESULT WasapiCapture::startProxy() } -void WasapiCapture_stop(WasapiCapture *self) +void WasapiCapture::stop() { - ThreadRequest req{ self->mMsgEvent, 0 }; - auto proxy = static_cast<WasapiProxy*>(self); + ThreadRequest req{ mMsgEvent, 0 }; + auto proxy = static_cast<WasapiProxy*>(this); if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)proxy)) (void)WaitForResponse(&req); } @@ -1767,16 +1724,12 @@ void WasapiCapture::stopProxy() } -ALuint WasapiCapture_availableSamples(WasapiCapture *self) -{ - RingBuffer *ring{self->mRing.get()}; - return (ALuint)ring->readSpace(); -} +ALCuint WasapiCapture::availableSamples() +{ return (ALCuint)mRing->readSpace(); } -ALCenum WasapiCapture_captureSamples(WasapiCapture *self, ALCvoid *buffer, ALCuint samples) +ALCenum WasapiCapture::captureSamples(void *buffer, ALCuint samples) { - RingBuffer *ring{self->mRing.get()}; - ring->read(buffer, samples); + mRing->read(buffer, samples); return ALC_NO_ERROR; } @@ -1857,21 +1810,12 @@ void WasapiBackendFactory::probe(DevProbe type, std::string *outnames) } } -ALCbackend *WasapiBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *WasapiBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) - { - WasapiPlayback *backend; - NEW_OBJ(backend, WasapiPlayback)(device); - return backend; - } + return new WasapiPlayback{device}; if(type == ALCbackend_Capture) - { - WasapiCapture *backend; - NEW_OBJ(backend, WasapiCapture)(device); - return backend; - } - + return new WasapiCapture{device}; return nullptr; } diff --git a/Alc/backends/wasapi.h b/Alc/backends/wasapi.h index a94f85df..47bd0e0c 100644 --- a/Alc/backends/wasapi.h +++ b/Alc/backends/wasapi.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index a1951c7b..01948b20 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -78,12 +78,17 @@ void fwrite32le(ALuint val, FILE *f) } -struct WaveBackend final : public ALCbackend { - WaveBackend(ALCdevice *device) noexcept : ALCbackend{device} { } +struct WaveBackend final : public BackendBase { + WaveBackend(ALCdevice *device) noexcept : BackendBase{device} { } ~WaveBackend() override; int mixerProc(); + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + FILE *mFile{nullptr}; long mDataStart{-1}; @@ -93,32 +98,9 @@ struct WaveBackend final : public ALCbackend { std::thread mThread; static constexpr inline const char *CurrentPrefix() noexcept { return "WaveBackend::"; } + DEF_NEWDEL(WaveBackend) }; -void WaveBackend_Construct(WaveBackend *self, ALCdevice *device); -void WaveBackend_Destruct(WaveBackend *self); -ALCenum WaveBackend_open(WaveBackend *self, const ALCchar *name); -ALCboolean WaveBackend_reset(WaveBackend *self); -ALCboolean WaveBackend_start(WaveBackend *self); -void WaveBackend_stop(WaveBackend *self); -DECLARE_FORWARD2(WaveBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -DECLARE_FORWARD(WaveBackend, ALCbackend, ALCuint, availableSamples) -DECLARE_FORWARD(WaveBackend, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(WaveBackend, ALCbackend, void, lock) -DECLARE_FORWARD(WaveBackend, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(WaveBackend) - -DEFINE_ALCBACKEND_VTABLE(WaveBackend); - -void WaveBackend_Construct(WaveBackend *self, ALCdevice *device) -{ - new (self) WaveBackend{device}; - SET_VTABLE2(WaveBackend, ALCbackend, self); -} - -void WaveBackend_Destruct(WaveBackend *self) -{ self->~WaveBackend(); } - WaveBackend::~WaveBackend() { if(mFile) @@ -151,9 +133,9 @@ int WaveBackend::mixerProc() } while(avail-done >= mDevice->UpdateSize) { - WaveBackend_lock(this); + lock(); aluMixData(mDevice, mBuffer.data(), mDevice->UpdateSize); - WaveBackend_unlock(this); + unlock(); done += mDevice->UpdateSize; if(!IS_LITTLE_ENDIAN) @@ -189,9 +171,9 @@ int WaveBackend::mixerProc() if(ferror(mFile)) { ERR("Error writing to file\n"); - WaveBackend_lock(this); + lock(); aluHandleDisconnect(mDevice, "Failed to write playback samples"); - WaveBackend_unlock(this); + unlock(); break; } } @@ -212,8 +194,7 @@ int WaveBackend::mixerProc() return 0; } - -ALCenum WaveBackend_open(WaveBackend *self, const ALCchar *name) +ALCenum WaveBackend::open(const ALCchar *name) { const char *fname{GetConfigValue(nullptr, "wave", "file", "")}; if(!fname[0]) return ALC_INVALID_VALUE; @@ -226,49 +207,47 @@ ALCenum WaveBackend_open(WaveBackend *self, const ALCchar *name) #ifdef _WIN32 { std::wstring wname = utf8_to_wstr(fname); - self->mFile = _wfopen(wname.c_str(), L"wb"); + mFile = _wfopen(wname.c_str(), L"wb"); } #else - self->mFile = fopen(fname, "wb"); + mFile = fopen(fname, "wb"); #endif - if(!self->mFile) + if(!mFile) { ERR("Could not open file '%s': %s\n", fname, strerror(errno)); return ALC_INVALID_VALUE; } - ALCdevice *device{self->mDevice}; - device->DeviceName = name; + mDevice->DeviceName = name; return ALC_NO_ERROR; } -ALCboolean WaveBackend_reset(WaveBackend *self) +ALCboolean WaveBackend::reset() { - ALCdevice *device{self->mDevice}; ALuint channels=0, bits=0, chanmask=0; int isbformat = 0; size_t val; - fseek(self->mFile, 0, SEEK_SET); - clearerr(self->mFile); + fseek(mFile, 0, SEEK_SET); + clearerr(mFile); if(GetConfigValueBool(nullptr, "wave", "bformat", 0)) { - device->FmtChans = DevFmtAmbi3D; - device->mAmbiOrder = 1; + mDevice->FmtChans = DevFmtAmbi3D; + mDevice->mAmbiOrder = 1; } - switch(device->FmtType) + switch(mDevice->FmtType) { case DevFmtByte: - device->FmtType = DevFmtUByte; + mDevice->FmtType = DevFmtUByte; break; case DevFmtUShort: - device->FmtType = DevFmtShort; + mDevice->FmtType = DevFmtShort; break; case DevFmtUInt: - device->FmtType = DevFmtInt; + mDevice->FmtType = DevFmtInt; break; case DevFmtUByte: case DevFmtShort: @@ -276,7 +255,7 @@ ALCboolean WaveBackend_reset(WaveBackend *self) case DevFmtFloat: break; } - switch(device->FmtChans) + switch(mDevice->FmtChans) { case DevFmtMono: chanmask = 0x04; break; case DevFmtStereo: chanmask = 0x01 | 0x02; break; @@ -287,71 +266,71 @@ ALCboolean WaveBackend_reset(WaveBackend *self) case DevFmtX71: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020 | 0x200 | 0x400; break; case DevFmtAmbi3D: /* .amb output requires FuMa */ - device->mAmbiOrder = mini(device->mAmbiOrder, 3); - device->mAmbiLayout = AmbiLayout::FuMa; - device->mAmbiScale = AmbiNorm::FuMa; + mDevice->mAmbiOrder = mini(mDevice->mAmbiOrder, 3); + mDevice->mAmbiLayout = AmbiLayout::FuMa; + mDevice->mAmbiScale = AmbiNorm::FuMa; isbformat = 1; chanmask = 0; break; } - bits = device->bytesFromFmt() * 8; - channels = device->channelsFromFmt(); + bits = mDevice->bytesFromFmt() * 8; + channels = mDevice->channelsFromFmt(); - fputs("RIFF", self->mFile); - fwrite32le(0xFFFFFFFF, self->mFile); // 'RIFF' header len; filled in at close + fputs("RIFF", mFile); + fwrite32le(0xFFFFFFFF, mFile); // 'RIFF' header len; filled in at close - fputs("WAVE", self->mFile); + fputs("WAVE", mFile); - fputs("fmt ", self->mFile); - fwrite32le(40, self->mFile); // 'fmt ' header len; 40 bytes for EXTENSIBLE + fputs("fmt ", mFile); + fwrite32le(40, mFile); // 'fmt ' header len; 40 bytes for EXTENSIBLE // 16-bit val, format type id (extensible: 0xFFFE) - fwrite16le(0xFFFE, self->mFile); + fwrite16le(0xFFFE, mFile); // 16-bit val, channel count - fwrite16le(channels, self->mFile); + fwrite16le(channels, mFile); // 32-bit val, frequency - fwrite32le(device->Frequency, self->mFile); + fwrite32le(mDevice->Frequency, mFile); // 32-bit val, bytes per second - fwrite32le(device->Frequency * channels * bits / 8, self->mFile); + fwrite32le(mDevice->Frequency * channels * bits / 8, mFile); // 16-bit val, frame size - fwrite16le(channels * bits / 8, self->mFile); + fwrite16le(channels * bits / 8, mFile); // 16-bit val, bits per sample - fwrite16le(bits, self->mFile); + fwrite16le(bits, mFile); // 16-bit val, extra byte count - fwrite16le(22, self->mFile); + fwrite16le(22, mFile); // 16-bit val, valid bits per sample - fwrite16le(bits, self->mFile); + fwrite16le(bits, mFile); // 32-bit val, channel mask - fwrite32le(chanmask, self->mFile); + fwrite32le(chanmask, mFile); // 16 byte GUID, sub-type format - val = fwrite((device->FmtType == DevFmtFloat) ? + val = fwrite((mDevice->FmtType == DevFmtFloat) ? (isbformat ? SUBTYPE_BFORMAT_FLOAT : SUBTYPE_FLOAT) : - (isbformat ? SUBTYPE_BFORMAT_PCM : SUBTYPE_PCM), 1, 16, self->mFile); + (isbformat ? SUBTYPE_BFORMAT_PCM : SUBTYPE_PCM), 1, 16, mFile); (void)val; - fputs("data", self->mFile); - fwrite32le(0xFFFFFFFF, self->mFile); // 'data' header len; filled in at close + fputs("data", mFile); + fwrite32le(0xFFFFFFFF, mFile); // 'data' header len; filled in at close - if(ferror(self->mFile)) + if(ferror(mFile)) { ERR("Error writing header: %s\n", strerror(errno)); return ALC_FALSE; } - self->mDataStart = ftell(self->mFile); + mDataStart = ftell(mFile); - SetDefaultWFXChannelOrder(device); + SetDefaultWFXChannelOrder(mDevice); - const ALuint bufsize{device->frameSizeFromFmt() * device->UpdateSize}; - self->mBuffer.resize(bufsize); + const ALuint bufsize{mDevice->frameSizeFromFmt() * mDevice->UpdateSize}; + mBuffer.resize(bufsize); return ALC_TRUE; } -ALCboolean WaveBackend_start(WaveBackend *self) +ALCboolean WaveBackend::start() { try { - self->mKillNow.store(AL_FALSE, std::memory_order_release); - self->mThread = std::thread{std::mem_fn(&WaveBackend::mixerProc), self}; + mKillNow.store(AL_FALSE, std::memory_order_release); + mThread = std::thread{std::mem_fn(&WaveBackend::mixerProc), this}; return ALC_TRUE; } catch(std::exception& e) { @@ -362,20 +341,20 @@ ALCboolean WaveBackend_start(WaveBackend *self) return ALC_FALSE; } -void WaveBackend_stop(WaveBackend *self) +void WaveBackend::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; - self->mThread.join(); + mThread.join(); - long size{ftell(self->mFile)}; + long size{ftell(mFile)}; if(size > 0) { - long dataLen{size - self->mDataStart}; - if(fseek(self->mFile, self->mDataStart-4, SEEK_SET) == 0) - fwrite32le(dataLen, self->mFile); // 'data' header len - if(fseek(self->mFile, 4, SEEK_SET) == 0) - fwrite32le(size-8, self->mFile); // 'WAVE' header len + long dataLen{size - mDataStart}; + if(fseek(mFile, mDataStart-4, SEEK_SET) == 0) + fwrite32le(dataLen, mFile); // 'data' header len + if(fseek(mFile, 4, SEEK_SET) == 0) + fwrite32le(size-8, mFile); // 'WAVE' header len } } @@ -401,15 +380,10 @@ void WaveBackendFactory::probe(DevProbe type, std::string *outnames) } } -ALCbackend *WaveBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *WaveBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) - { - WaveBackend *backend; - NEW_OBJ(backend, WaveBackend)(device); - return backend; - } - + return new WaveBackend{device}; return nullptr; } diff --git a/Alc/backends/wave.h b/Alc/backends/wave.h index bb51cc71..08d3f0c2 100644 --- a/Alc/backends/wave.h +++ b/Alc/backends/wave.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp index 09b7a2e2..5051aa00 100644 --- a/Alc/backends/winmm.cpp +++ b/Alc/backends/winmm.cpp @@ -120,8 +120,8 @@ void ProbeCaptureDevices(void) } -struct WinMMPlayback final : public ALCbackend { - WinMMPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } +struct WinMMPlayback final : public BackendBase { + WinMMPlayback(ALCdevice *device) noexcept : BackendBase{device} { } ~WinMMPlayback() override; static void CALLBACK waveOutProcC(HWAVEOUT device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2); @@ -129,6 +129,11 @@ struct WinMMPlayback final : public ALCbackend { int mixerProc(); + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + std::atomic<ALuint> mWritable{0u}; al::semaphore mSem; int mIdx{0}; @@ -142,32 +147,9 @@ struct WinMMPlayback final : public ALCbackend { std::thread mThread; static constexpr inline const char *CurrentPrefix() noexcept { return "WinMMPlayback::"; } + DEF_NEWDEL(WinMMPlayback) }; -void WinMMPlayback_Construct(WinMMPlayback *self, ALCdevice *device); -void WinMMPlayback_Destruct(WinMMPlayback *self); -ALCenum WinMMPlayback_open(WinMMPlayback *self, const ALCchar *name); -ALCboolean WinMMPlayback_reset(WinMMPlayback *self); -ALCboolean WinMMPlayback_start(WinMMPlayback *self); -void WinMMPlayback_stop(WinMMPlayback *self); -DECLARE_FORWARD2(WinMMPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) -DECLARE_FORWARD(WinMMPlayback, ALCbackend, ALCuint, availableSamples) -DECLARE_FORWARD(WinMMPlayback, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(WinMMPlayback, ALCbackend, void, lock) -DECLARE_FORWARD(WinMMPlayback, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(WinMMPlayback) - -DEFINE_ALCBACKEND_VTABLE(WinMMPlayback); - -void WinMMPlayback_Construct(WinMMPlayback *self, ALCdevice *device) -{ - new (self) WinMMPlayback{device}; - SET_VTABLE2(WinMMPlayback, ALCbackend, self); -} - -void WinMMPlayback_Destruct(WinMMPlayback *self) -{ self->~WinMMPlayback(); } - WinMMPlayback::~WinMMPlayback() { if(mOutHdl) @@ -200,16 +182,16 @@ FORCE_ALIGN int WinMMPlayback::mixerProc() SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); - WinMMPlayback_lock(this); + lock(); while(!mKillNow.load(std::memory_order_acquire) && mDevice->Connected.load(std::memory_order_acquire)) { ALsizei todo = mWritable.load(std::memory_order_acquire); if(todo < 1) { - WinMMPlayback_unlock(this); + unlock(); mSem.wait(); - WinMMPlayback_lock(this); + lock(); continue; } @@ -224,146 +206,137 @@ FORCE_ALIGN int WinMMPlayback::mixerProc() } while(--todo); mIdx = widx; } - WinMMPlayback_unlock(this); + unlock(); return 0; } -ALCenum WinMMPlayback_open(WinMMPlayback *self, const ALCchar *deviceName) +ALCenum WinMMPlayback::open(const ALCchar *name) { - ALCdevice *device{self->mDevice}; - if(PlaybackDevices.empty()) ProbePlaybackDevices(); // Find the Device ID matching the deviceName if valid - auto iter = deviceName ? - std::find(PlaybackDevices.cbegin(), PlaybackDevices.cend(), deviceName) : + auto iter = name ? + std::find(PlaybackDevices.cbegin(), PlaybackDevices.cend(), name) : PlaybackDevices.cbegin(); if(iter == PlaybackDevices.cend()) return ALC_INVALID_VALUE; auto DeviceID = static_cast<UINT>(std::distance(PlaybackDevices.cbegin(), iter)); retry_open: - self->mFormat = WAVEFORMATEX{}; - if(device->FmtType == DevFmtFloat) + mFormat = WAVEFORMATEX{}; + if(mDevice->FmtType == DevFmtFloat) { - self->mFormat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; - self->mFormat.wBitsPerSample = 32; + mFormat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; + mFormat.wBitsPerSample = 32; } else { - self->mFormat.wFormatTag = WAVE_FORMAT_PCM; - if(device->FmtType == DevFmtUByte || device->FmtType == DevFmtByte) - self->mFormat.wBitsPerSample = 8; + mFormat.wFormatTag = WAVE_FORMAT_PCM; + if(mDevice->FmtType == DevFmtUByte || mDevice->FmtType == DevFmtByte) + mFormat.wBitsPerSample = 8; else - self->mFormat.wBitsPerSample = 16; + mFormat.wBitsPerSample = 16; } - self->mFormat.nChannels = ((device->FmtChans == DevFmtMono) ? 1 : 2); - self->mFormat.nBlockAlign = self->mFormat.wBitsPerSample * - self->mFormat.nChannels / 8; - self->mFormat.nSamplesPerSec = device->Frequency; - self->mFormat.nAvgBytesPerSec = self->mFormat.nSamplesPerSec * - self->mFormat.nBlockAlign; - self->mFormat.cbSize = 0; - - MMRESULT res{waveOutOpen(&self->mOutHdl, DeviceID, &self->mFormat, - (DWORD_PTR)&WinMMPlayback::waveOutProcC, (DWORD_PTR)self, CALLBACK_FUNCTION)}; + mFormat.nChannels = ((mDevice->FmtChans == DevFmtMono) ? 1 : 2); + mFormat.nBlockAlign = mFormat.wBitsPerSample * mFormat.nChannels / 8; + mFormat.nSamplesPerSec = mDevice->Frequency; + mFormat.nAvgBytesPerSec = mFormat.nSamplesPerSec * mFormat.nBlockAlign; + mFormat.cbSize = 0; + + MMRESULT res{waveOutOpen(&mOutHdl, DeviceID, &mFormat, (DWORD_PTR)&WinMMPlayback::waveOutProcC, + reinterpret_cast<DWORD_PTR>(this), CALLBACK_FUNCTION)}; if(res != MMSYSERR_NOERROR) { - if(device->FmtType == DevFmtFloat) + if(mDevice->FmtType == DevFmtFloat) { - device->FmtType = DevFmtShort; + mDevice->FmtType = DevFmtShort; goto retry_open; } ERR("waveOutOpen failed: %u\n", res); return ALC_INVALID_VALUE; } - device->DeviceName = PlaybackDevices[DeviceID]; + mDevice->DeviceName = PlaybackDevices[DeviceID]; return ALC_NO_ERROR; } -ALCboolean WinMMPlayback_reset(WinMMPlayback *self) +ALCboolean WinMMPlayback::reset() { - ALCdevice *device{self->mDevice}; + mDevice->UpdateSize = static_cast<ALuint>( + (ALuint64)mDevice->UpdateSize * mFormat.nSamplesPerSec / mDevice->Frequency); + mDevice->UpdateSize = (mDevice->UpdateSize*mDevice->NumUpdates + 3) / 4; + mDevice->NumUpdates = 4; + mDevice->Frequency = mFormat.nSamplesPerSec; - device->UpdateSize = static_cast<ALuint>( - (ALuint64)device->UpdateSize * self->mFormat.nSamplesPerSec / device->Frequency); - device->UpdateSize = (device->UpdateSize*device->NumUpdates + 3) / 4; - device->NumUpdates = 4; - device->Frequency = self->mFormat.nSamplesPerSec; - - if(self->mFormat.wFormatTag == WAVE_FORMAT_IEEE_FLOAT) + if(mFormat.wFormatTag == WAVE_FORMAT_IEEE_FLOAT) { - if(self->mFormat.wBitsPerSample == 32) - device->FmtType = DevFmtFloat; + if(mFormat.wBitsPerSample == 32) + mDevice->FmtType = DevFmtFloat; else { - ERR("Unhandled IEEE float sample depth: %d\n", self->mFormat.wBitsPerSample); + ERR("Unhandled IEEE float sample depth: %d\n", mFormat.wBitsPerSample); return ALC_FALSE; } } - else if(self->mFormat.wFormatTag == WAVE_FORMAT_PCM) + else if(mFormat.wFormatTag == WAVE_FORMAT_PCM) { - if(self->mFormat.wBitsPerSample == 16) - device->FmtType = DevFmtShort; - else if(self->mFormat.wBitsPerSample == 8) - device->FmtType = DevFmtUByte; + if(mFormat.wBitsPerSample == 16) + mDevice->FmtType = DevFmtShort; + else if(mFormat.wBitsPerSample == 8) + mDevice->FmtType = DevFmtUByte; else { - ERR("Unhandled PCM sample depth: %d\n", self->mFormat.wBitsPerSample); + ERR("Unhandled PCM sample depth: %d\n", mFormat.wBitsPerSample); return ALC_FALSE; } } else { - ERR("Unhandled format tag: 0x%04x\n", self->mFormat.wFormatTag); + ERR("Unhandled format tag: 0x%04x\n", mFormat.wFormatTag); return ALC_FALSE; } - if(self->mFormat.nChannels == 2) - device->FmtChans = DevFmtStereo; - else if(self->mFormat.nChannels == 1) - device->FmtChans = DevFmtMono; + if(mFormat.nChannels == 2) + mDevice->FmtChans = DevFmtStereo; + else if(mFormat.nChannels == 1) + mDevice->FmtChans = DevFmtMono; else { - ERR("Unhandled channel count: %d\n", self->mFormat.nChannels); + ERR("Unhandled channel count: %d\n", mFormat.nChannels); return ALC_FALSE; } - SetDefaultWFXChannelOrder(device); + SetDefaultWFXChannelOrder(mDevice); - ALuint BufferSize{device->UpdateSize * device->frameSizeFromFmt()}; + ALuint BufferSize{mDevice->UpdateSize * mDevice->frameSizeFromFmt()}; - al_free(self->mWaveBuffer[0].lpData); - self->mWaveBuffer[0] = WAVEHDR{}; - self->mWaveBuffer[0].lpData = static_cast<char*>(al_calloc(16, - BufferSize * self->mWaveBuffer.size())); - self->mWaveBuffer[0].dwBufferLength = BufferSize; - for(size_t i{1};i < self->mWaveBuffer.size();i++) + al_free(mWaveBuffer[0].lpData); + mWaveBuffer[0] = WAVEHDR{}; + mWaveBuffer[0].lpData = static_cast<char*>(al_calloc(16, BufferSize * mWaveBuffer.size())); + mWaveBuffer[0].dwBufferLength = BufferSize; + for(size_t i{1};i < mWaveBuffer.size();i++) { - self->mWaveBuffer[i] = WAVEHDR{}; - self->mWaveBuffer[i].lpData = self->mWaveBuffer[i-1].lpData + - self->mWaveBuffer[i-1].dwBufferLength; - self->mWaveBuffer[i].dwBufferLength = BufferSize; + mWaveBuffer[i] = WAVEHDR{}; + mWaveBuffer[i].lpData = mWaveBuffer[i-1].lpData + mWaveBuffer[i-1].dwBufferLength; + mWaveBuffer[i].dwBufferLength = BufferSize; } - self->mIdx = 0; + mIdx = 0; return ALC_TRUE; } -ALCboolean WinMMPlayback_start(WinMMPlayback *self) +ALCboolean WinMMPlayback::start() { try { - std::for_each(self->mWaveBuffer.begin(), self->mWaveBuffer.end(), - [self](WAVEHDR &waveHdr) -> void - { waveOutPrepareHeader(self->mOutHdl, &waveHdr, static_cast<UINT>(sizeof(WAVEHDR))); } + std::for_each(mWaveBuffer.begin(), mWaveBuffer.end(), + [this](WAVEHDR &waveHdr) -> void + { waveOutPrepareHeader(mOutHdl, &waveHdr, static_cast<UINT>(sizeof(WAVEHDR))); } ); - self->mWritable.store(static_cast<ALuint>(self->mWaveBuffer.size()), - std::memory_order_release); + mWritable.store(static_cast<ALuint>(mWaveBuffer.size()), std::memory_order_release); - self->mKillNow.store(AL_FALSE, std::memory_order_release); - self->mThread = std::thread{std::mem_fn(&WinMMPlayback::mixerProc), self}; + mKillNow.store(AL_FALSE, std::memory_order_release); + mThread = std::thread{std::mem_fn(&WinMMPlayback::mixerProc), this}; return ALC_TRUE; } catch(std::exception& e) { @@ -374,24 +347,24 @@ ALCboolean WinMMPlayback_start(WinMMPlayback *self) return ALC_FALSE; } -void WinMMPlayback_stop(WinMMPlayback *self) +void WinMMPlayback::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; - self->mThread.join(); + mThread.join(); - while(self->mWritable.load(std::memory_order_acquire) < self->mWaveBuffer.size()) - self->mSem.wait(); - std::for_each(self->mWaveBuffer.begin(), self->mWaveBuffer.end(), - [self](WAVEHDR &waveHdr) -> void - { waveOutUnprepareHeader(self->mOutHdl, &waveHdr, sizeof(WAVEHDR)); } + while(mWritable.load(std::memory_order_acquire) < mWaveBuffer.size()) + mSem.wait(); + std::for_each(mWaveBuffer.begin(), mWaveBuffer.end(), + [this](WAVEHDR &waveHdr) -> void + { waveOutUnprepareHeader(mOutHdl, &waveHdr, sizeof(WAVEHDR)); } ); - self->mWritable.store(0, std::memory_order_release); + mWritable.store(0, std::memory_order_release); } -struct WinMMCapture final : public ALCbackend { - WinMMCapture(ALCdevice *device) noexcept : ALCbackend{device} { } +struct WinMMCapture final : public BackendBase { + WinMMCapture(ALCdevice *device) noexcept : BackendBase{device} { } ~WinMMCapture() override; static void CALLBACK waveInProcC(HWAVEIN device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2); @@ -399,6 +372,12 @@ struct WinMMCapture final : public ALCbackend { int captureProc(); + ALCenum open(const ALCchar *name) override; + ALCboolean start() override; + void stop() override; + ALCenum captureSamples(void *buffer, ALCuint samples) override; + ALCuint availableSamples() override; + std::atomic<ALuint> mReadable{0u}; al::semaphore mSem; int mIdx{0}; @@ -414,32 +393,9 @@ struct WinMMCapture final : public ALCbackend { std::thread mThread; static constexpr inline const char *CurrentPrefix() noexcept { return "WinMMCapture::"; } + DEF_NEWDEL(WinMMCapture) }; -void WinMMCapture_Construct(WinMMCapture *self, ALCdevice *device); -void WinMMCapture_Destruct(WinMMCapture *self); -ALCenum WinMMCapture_open(WinMMCapture *self, const ALCchar *deviceName); -DECLARE_FORWARD(WinMMCapture, ALCbackend, ALCboolean, reset) -ALCboolean WinMMCapture_start(WinMMCapture *self); -void WinMMCapture_stop(WinMMCapture *self); -ALCenum WinMMCapture_captureSamples(WinMMCapture *self, ALCvoid *buffer, ALCuint samples); -ALCuint WinMMCapture_availableSamples(WinMMCapture *self); -DECLARE_FORWARD(WinMMCapture, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(WinMMCapture, ALCbackend, void, lock) -DECLARE_FORWARD(WinMMCapture, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(WinMMCapture) - -DEFINE_ALCBACKEND_VTABLE(WinMMCapture); - -void WinMMCapture_Construct(WinMMCapture *self, ALCdevice *device) -{ - new (self) WinMMCapture{device}; - SET_VTABLE2(WinMMCapture, ALCbackend, self); -} - -void WinMMCapture_Destruct(WinMMCapture *self) -{ self->~WinMMCapture(); } - WinMMCapture::~WinMMCapture() { // Close the Wave device @@ -471,16 +427,16 @@ int WinMMCapture::captureProc() { althrd_setname(RECORD_THREAD_NAME); - WinMMCapture_lock(this); + lock(); while(!mKillNow.load(std::memory_order_acquire) && mDevice->Connected.load(std::memory_order_acquire)) { ALuint todo{mReadable.load(std::memory_order_acquire)}; if(todo < 1) { - WinMMCapture_unlock(this); + unlock(); mSem.wait(); - WinMMCapture_lock(this); + lock(); continue; } @@ -495,27 +451,25 @@ int WinMMCapture::captureProc() } while(--todo); mIdx = widx; } - WinMMCapture_unlock(this); + unlock(); return 0; } -ALCenum WinMMCapture_open(WinMMCapture *self, const ALCchar *deviceName) +ALCenum WinMMCapture::open(const ALCchar *name) { - ALCdevice *device{self->mDevice}; - if(CaptureDevices.empty()) ProbeCaptureDevices(); // Find the Device ID matching the deviceName if valid - auto iter = deviceName ? - std::find(CaptureDevices.cbegin(), CaptureDevices.cend(), deviceName) : + auto iter = name ? + std::find(CaptureDevices.cbegin(), CaptureDevices.cend(), name) : CaptureDevices.cbegin(); if(iter == CaptureDevices.cend()) return ALC_INVALID_VALUE; auto DeviceID = static_cast<UINT>(std::distance(CaptureDevices.cbegin(), iter)); - switch(device->FmtChans) + switch(mDevice->FmtChans) { case DevFmtMono: case DevFmtStereo: @@ -530,7 +484,7 @@ ALCenum WinMMCapture_open(WinMMCapture *self, const ALCchar *deviceName) return ALC_INVALID_ENUM; } - switch(device->FmtType) + switch(mDevice->FmtType) { case DevFmtUByte: case DevFmtShort: @@ -544,21 +498,18 @@ ALCenum WinMMCapture_open(WinMMCapture *self, const ALCchar *deviceName) return ALC_INVALID_ENUM; } - self->mFormat = WAVEFORMATEX{}; - self->mFormat.wFormatTag = (device->FmtType == DevFmtFloat) ? - WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM; - self->mFormat.nChannels = device->channelsFromFmt(); - self->mFormat.wBitsPerSample = device->bytesFromFmt() * 8; - self->mFormat.nBlockAlign = self->mFormat.wBitsPerSample * - self->mFormat.nChannels / 8; - self->mFormat.nSamplesPerSec = device->Frequency; - self->mFormat.nAvgBytesPerSec = self->mFormat.nSamplesPerSec * - self->mFormat.nBlockAlign; - self->mFormat.cbSize = 0; - - MMRESULT res{waveInOpen(&self->mInHdl, DeviceID, &self->mFormat, - (DWORD_PTR)&WinMMCapture::waveInProcC, (DWORD_PTR)self, CALLBACK_FUNCTION - )}; + mFormat = WAVEFORMATEX{}; + mFormat.wFormatTag = (mDevice->FmtType == DevFmtFloat) ? + WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM; + mFormat.nChannels = mDevice->channelsFromFmt(); + mFormat.wBitsPerSample = mDevice->bytesFromFmt() * 8; + mFormat.nBlockAlign = mFormat.wBitsPerSample * mFormat.nChannels / 8; + mFormat.nSamplesPerSec = mDevice->Frequency; + mFormat.nAvgBytesPerSec = mFormat.nSamplesPerSec * mFormat.nBlockAlign; + mFormat.cbSize = 0; + + MMRESULT res{waveInOpen(&mInHdl, DeviceID, &mFormat, (DWORD_PTR)&WinMMCapture::waveInProcC, + reinterpret_cast<DWORD_PTR>(this), CALLBACK_FUNCTION)}; if(res != MMSYSERR_NOERROR) { ERR("waveInOpen failed: %u\n", res); @@ -566,47 +517,46 @@ ALCenum WinMMCapture_open(WinMMCapture *self, const ALCchar *deviceName) } // Ensure each buffer is 50ms each - DWORD BufferSize{self->mFormat.nAvgBytesPerSec / 20u}; - BufferSize -= (BufferSize % self->mFormat.nBlockAlign); + DWORD BufferSize{mFormat.nAvgBytesPerSec / 20u}; + BufferSize -= (BufferSize % mFormat.nBlockAlign); // Allocate circular memory buffer for the captured audio // Make sure circular buffer is at least 100ms in size - ALuint CapturedDataSize{device->UpdateSize*device->NumUpdates}; + ALuint CapturedDataSize{mDevice->UpdateSize*mDevice->NumUpdates}; CapturedDataSize = static_cast<ALuint>( - std::max<size_t>(CapturedDataSize, BufferSize*self->mWaveBuffer.size())); + std::max<size_t>(CapturedDataSize, BufferSize*mWaveBuffer.size())); - self->mRing = CreateRingBuffer(CapturedDataSize, self->mFormat.nBlockAlign, false); - if(!self->mRing) return ALC_INVALID_VALUE; + mRing = CreateRingBuffer(CapturedDataSize, mFormat.nBlockAlign, false); + if(!mRing) return ALC_INVALID_VALUE; - al_free(self->mWaveBuffer[0].lpData); - self->mWaveBuffer[0] = WAVEHDR{}; - self->mWaveBuffer[0].lpData = static_cast<char*>(al_calloc(16, BufferSize*4)); - self->mWaveBuffer[0].dwBufferLength = BufferSize; - for(size_t i{1};i < self->mWaveBuffer.size();++i) + al_free(mWaveBuffer[0].lpData); + mWaveBuffer[0] = WAVEHDR{}; + mWaveBuffer[0].lpData = static_cast<char*>(al_calloc(16, BufferSize*4)); + mWaveBuffer[0].dwBufferLength = BufferSize; + for(size_t i{1};i < mWaveBuffer.size();++i) { - self->mWaveBuffer[i] = WAVEHDR{}; - self->mWaveBuffer[i].lpData = self->mWaveBuffer[i-1].lpData + - self->mWaveBuffer[i-1].dwBufferLength; - self->mWaveBuffer[i].dwBufferLength = self->mWaveBuffer[i-1].dwBufferLength; + mWaveBuffer[i] = WAVEHDR{}; + mWaveBuffer[i].lpData = mWaveBuffer[i-1].lpData + mWaveBuffer[i-1].dwBufferLength; + mWaveBuffer[i].dwBufferLength = mWaveBuffer[i-1].dwBufferLength; } - device->DeviceName = CaptureDevices[DeviceID]; + mDevice->DeviceName = CaptureDevices[DeviceID]; return ALC_NO_ERROR; } -ALCboolean WinMMCapture_start(WinMMCapture *self) +ALCboolean WinMMCapture::start() { try { - for(size_t i{0};i < self->mWaveBuffer.size();++i) + for(size_t i{0};i < mWaveBuffer.size();++i) { - waveInPrepareHeader(self->mInHdl, &self->mWaveBuffer[i], sizeof(WAVEHDR)); - waveInAddBuffer(self->mInHdl, &self->mWaveBuffer[i], sizeof(WAVEHDR)); + waveInPrepareHeader(mInHdl, &mWaveBuffer[i], sizeof(WAVEHDR)); + waveInAddBuffer(mInHdl, &mWaveBuffer[i], sizeof(WAVEHDR)); } - self->mKillNow.store(AL_FALSE, std::memory_order_release); - self->mThread = std::thread{std::mem_fn(&WinMMCapture::captureProc), self}; + mKillNow.store(AL_FALSE, std::memory_order_release); + mThread = std::thread{std::mem_fn(&WinMMCapture::captureProc), this}; - waveInStart(self->mInHdl); + waveInStart(mInHdl); return ALC_TRUE; } catch(std::exception& e) { @@ -617,37 +567,33 @@ ALCboolean WinMMCapture_start(WinMMCapture *self) return ALC_FALSE; } -void WinMMCapture_stop(WinMMCapture *self) +void WinMMCapture::stop() { - waveInStop(self->mInHdl); + waveInStop(mInHdl); - self->mKillNow.store(AL_TRUE, std::memory_order_release); - if(self->mThread.joinable()) + mKillNow.store(AL_TRUE, std::memory_order_release); + if(mThread.joinable()) { - self->mSem.post(); - self->mThread.join(); + mSem.post(); + mThread.join(); } - waveInReset(self->mInHdl); - for(size_t i{0};i < self->mWaveBuffer.size();++i) - waveInUnprepareHeader(self->mInHdl, &self->mWaveBuffer[i], sizeof(WAVEHDR)); + waveInReset(mInHdl); + for(size_t i{0};i < mWaveBuffer.size();++i) + waveInUnprepareHeader(mInHdl, &mWaveBuffer[i], sizeof(WAVEHDR)); - self->mReadable.store(0, std::memory_order_release); - self->mIdx = 0; + mReadable.store(0, std::memory_order_release); + mIdx = 0; } -ALCenum WinMMCapture_captureSamples(WinMMCapture *self, ALCvoid *buffer, ALCuint samples) +ALCenum WinMMCapture::captureSamples(void *buffer, ALCuint samples) { - RingBuffer *ring{self->mRing.get()}; - ring->read(buffer, samples); + mRing->read(buffer, samples); return ALC_NO_ERROR; } -ALCuint WinMMCapture_availableSamples(WinMMCapture *self) -{ - RingBuffer *ring{self->mRing.get()}; - return (ALCuint)ring->readSpace(); -} +ALCuint WinMMCapture::availableSamples() +{ return (ALCuint)mRing->readSpace(); } } // namespace @@ -688,21 +634,12 @@ void WinMMBackendFactory::probe(DevProbe type, std::string *outnames) } } -ALCbackend *WinMMBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *WinMMBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) - { - WinMMPlayback *backend; - NEW_OBJ(backend, WinMMPlayback)(device); - return backend; - } + return new WinMMPlayback{device}; if(type == ALCbackend_Capture) - { - WinMMCapture *backend; - NEW_OBJ(backend, WinMMCapture)(device); - return backend; - } - + return new WinMMCapture{device}; return nullptr; } diff --git a/Alc/backends/winmm.h b/Alc/backends/winmm.h index e5801c01..63be6598 100644 --- a/Alc/backends/winmm.h +++ b/Alc/backends/winmm.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; |