diff options
Diffstat (limited to 'alc')
-rw-r--r-- | alc/backends/alsa.cpp | 260 |
1 files changed, 128 insertions, 132 deletions
diff --git a/alc/backends/alsa.cpp b/alc/backends/alsa.cpp index 91415c32..1b8c6298 100644 --- a/alc/backends/alsa.cpp +++ b/alc/backends/alsa.cpp @@ -216,6 +216,29 @@ ALSA_FUNCS(MAKE_FUNC); #endif +struct HwParamsDeleter { + void operator()(snd_pcm_hw_params_t *ptr) { snd_pcm_hw_params_free(ptr); } +}; +using HwParamsPtr = std::unique_ptr<snd_pcm_hw_params_t,HwParamsDeleter>; +HwParamsPtr CreateHwParams() +{ + snd_pcm_hw_params_t *hp{}; + snd_pcm_hw_params_malloc(&hp); + return HwParamsPtr{hp}; +} + +struct SwParamsDeleter { + void operator()(snd_pcm_sw_params_t *ptr) { snd_pcm_sw_params_free(ptr); } +}; +using SwParamsPtr = std::unique_ptr<snd_pcm_sw_params_t,SwParamsDeleter>; +SwParamsPtr CreateSwParams() +{ + snd_pcm_sw_params_t *sp{}; + snd_pcm_sw_params_malloc(&sp); + return SwParamsPtr{sp}; +} + + struct DevMap { std::string name; std::string device_name; @@ -630,27 +653,27 @@ bool AlsaPlayback::reset() snd_pcm_format_t format{SND_PCM_FORMAT_UNKNOWN}; switch(mDevice->FmtType) { - case DevFmtByte: - format = SND_PCM_FORMAT_S8; - break; - case DevFmtUByte: - format = SND_PCM_FORMAT_U8; - break; - case DevFmtShort: - format = SND_PCM_FORMAT_S16; - break; - case DevFmtUShort: - format = SND_PCM_FORMAT_U16; - break; - case DevFmtInt: - format = SND_PCM_FORMAT_S32; - break; - case DevFmtUInt: - format = SND_PCM_FORMAT_U32; - break; - case DevFmtFloat: - format = SND_PCM_FORMAT_FLOAT; - break; + case DevFmtByte: + format = SND_PCM_FORMAT_S8; + break; + case DevFmtUByte: + format = SND_PCM_FORMAT_U8; + break; + case DevFmtShort: + format = SND_PCM_FORMAT_S16; + break; + case DevFmtUShort: + format = SND_PCM_FORMAT_U16; + break; + case DevFmtInt: + format = SND_PCM_FORMAT_S32; + break; + case DevFmtUInt: + format = SND_PCM_FORMAT_U32; + break; + case DevFmtFloat: + format = SND_PCM_FORMAT_FLOAT; + break; } bool allowmmap{!!GetConfigValueBool(mDevice->DeviceName.c_str(), "alsa", "mmap", 1)}; @@ -658,25 +681,22 @@ bool AlsaPlayback::reset() ALuint bufferLen{static_cast<ALuint>(mDevice->BufferSize * 1000000_u64 / mDevice->Frequency)}; ALuint rate{mDevice->Frequency}; - snd_pcm_uframes_t periodSizeInFrames{}; - snd_pcm_uframes_t bufferSizeInFrames{}; - snd_pcm_sw_params_t *sp{}; - snd_pcm_hw_params_t *hp{}; - snd_pcm_access_t access{}; - const char *funcerr{}; int err{}; - - snd_pcm_hw_params_malloc(&hp); -#define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error - CHECK(snd_pcm_hw_params_any(mPcmHandle, hp)); + HwParamsPtr hp{CreateHwParams()}; +#define CHECK(x) do { \ + if((err=(x)) < 0) \ + throw al::backend_exception{ALC_INVALID_VALUE, #x " failed: %s", snd_strerror(err)}; \ +} while(0) + CHECK(snd_pcm_hw_params_any(mPcmHandle, hp.get())); /* set interleaved access */ - if(!allowmmap || snd_pcm_hw_params_set_access(mPcmHandle, hp, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) + if(!allowmmap + || snd_pcm_hw_params_set_access(mPcmHandle, hp.get(), SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) { /* No mmap */ - CHECK(snd_pcm_hw_params_set_access(mPcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED)); + CHECK(snd_pcm_hw_params_set_access(mPcmHandle, hp.get(), SND_PCM_ACCESS_RW_INTERLEAVED)); } /* test and set format (implicitly sets sample bits) */ - if(snd_pcm_hw_params_test_format(mPcmHandle, hp, format) < 0) + if(snd_pcm_hw_params_test_format(mPcmHandle, hp.get(), format) < 0) { static const struct { snd_pcm_format_t format; @@ -694,16 +714,16 @@ bool AlsaPlayback::reset() for(const auto &fmt : formatlist) { format = fmt.format; - if(snd_pcm_hw_params_test_format(mPcmHandle, hp, format) >= 0) + if(snd_pcm_hw_params_test_format(mPcmHandle, hp.get(), format) >= 0) { mDevice->FmtType = fmt.fmttype; break; } } } - CHECK(snd_pcm_hw_params_set_format(mPcmHandle, hp, format)); + CHECK(snd_pcm_hw_params_set_format(mPcmHandle, hp.get(), format)); /* test and set channels (implicitly sets frame bits) */ - if(snd_pcm_hw_params_test_channels(mPcmHandle, hp, mDevice->channelsFromFmt()) < 0) + if(snd_pcm_hw_params_test_channels(mPcmHandle, hp.get(), mDevice->channelsFromFmt()) < 0) { static const DevFmtChannels channellist[] = { DevFmtStereo, @@ -715,7 +735,7 @@ bool AlsaPlayback::reset() for(const auto &chan : channellist) { - if(snd_pcm_hw_params_test_channels(mPcmHandle, hp, ChannelsFromDevFmt(chan, 0)) >= 0) + if(snd_pcm_hw_params_test_channels(mPcmHandle, hp.get(), ChannelsFromDevFmt(chan, 0)) >= 0) { mDevice->FmtChans = chan; mDevice->mAmbiOrder = 0; @@ -723,40 +743,42 @@ bool AlsaPlayback::reset() } } } - CHECK(snd_pcm_hw_params_set_channels(mPcmHandle, hp, mDevice->channelsFromFmt())); + CHECK(snd_pcm_hw_params_set_channels(mPcmHandle, hp.get(), mDevice->channelsFromFmt())); /* set rate (implicitly constrains period/buffer parameters) */ if(!GetConfigValueBool(mDevice->DeviceName.c_str(), "alsa", "allow-resampler", 0) || !mDevice->Flags.get<FrequencyRequest>()) { - if(snd_pcm_hw_params_set_rate_resample(mPcmHandle, hp, 0) < 0) + if(snd_pcm_hw_params_set_rate_resample(mPcmHandle, hp.get(), 0) < 0) ERR("Failed to disable ALSA resampler\n"); } - else if(snd_pcm_hw_params_set_rate_resample(mPcmHandle, hp, 1) < 0) + else if(snd_pcm_hw_params_set_rate_resample(mPcmHandle, hp.get(), 1) < 0) ERR("Failed to enable ALSA resampler\n"); - CHECK(snd_pcm_hw_params_set_rate_near(mPcmHandle, hp, &rate, nullptr)); + CHECK(snd_pcm_hw_params_set_rate_near(mPcmHandle, hp.get(), &rate, nullptr)); /* set period time (implicitly constrains period/buffer parameters) */ - if((err=snd_pcm_hw_params_set_period_time_near(mPcmHandle, hp, &periodLen, nullptr)) < 0) + if((err=snd_pcm_hw_params_set_period_time_near(mPcmHandle, hp.get(), &periodLen, nullptr)) < 0) ERR("snd_pcm_hw_params_set_period_time_near failed: %s\n", snd_strerror(err)); /* set buffer time (implicitly sets buffer size/bytes/time and period size/bytes) */ - if((err=snd_pcm_hw_params_set_buffer_time_near(mPcmHandle, hp, &bufferLen, nullptr)) < 0) + if((err=snd_pcm_hw_params_set_buffer_time_near(mPcmHandle, hp.get(), &bufferLen, nullptr)) < 0) ERR("snd_pcm_hw_params_set_buffer_time_near failed: %s\n", snd_strerror(err)); /* install and prepare hardware configuration */ - CHECK(snd_pcm_hw_params(mPcmHandle, hp)); + CHECK(snd_pcm_hw_params(mPcmHandle, hp.get())); /* retrieve configuration info */ - CHECK(snd_pcm_hw_params_get_access(hp, &access)); - CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, nullptr)); - CHECK(snd_pcm_hw_params_get_buffer_size(hp, &bufferSizeInFrames)); - snd_pcm_hw_params_free(hp); + snd_pcm_uframes_t periodSizeInFrames{}; + snd_pcm_uframes_t bufferSizeInFrames{}; + snd_pcm_access_t access{}; + + CHECK(snd_pcm_hw_params_get_access(hp.get(), &access)); + CHECK(snd_pcm_hw_params_get_period_size(hp.get(), &periodSizeInFrames, nullptr)); + CHECK(snd_pcm_hw_params_get_buffer_size(hp.get(), &bufferSizeInFrames)); hp = nullptr; - snd_pcm_sw_params_malloc(&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, bufferSizeInFrames)); - CHECK(snd_pcm_sw_params(mPcmHandle, sp)); + SwParamsPtr sp{CreateSwParams()}; + CHECK(snd_pcm_sw_params_current(mPcmHandle, sp.get())); + CHECK(snd_pcm_sw_params_set_avail_min(mPcmHandle, sp.get(), periodSizeInFrames)); + CHECK(snd_pcm_sw_params_set_stop_threshold(mPcmHandle, sp.get(), bufferSizeInFrames)); + CHECK(snd_pcm_sw_params(mPcmHandle, sp.get())); #undef CHECK - snd_pcm_sw_params_free(sp); sp = nullptr; mDevice->BufferSize = static_cast<ALuint>(bufferSizeInFrames); @@ -766,35 +788,21 @@ bool AlsaPlayback::reset() SetDefaultChannelOrder(mDevice); return true; - -error: - ERR("%s failed: %s\n", funcerr, snd_strerror(err)); - if(hp) snd_pcm_hw_params_free(hp); - if(sp) snd_pcm_sw_params_free(sp); - return false; } bool AlsaPlayback::start() { - snd_pcm_hw_params_t *hp{}; - snd_pcm_access_t access; - const char *funcerr; - int err; - - snd_pcm_hw_params_malloc(&hp); -#define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error - CHECK(snd_pcm_hw_params_current(mPcmHandle, hp)); + int err{}; + snd_pcm_access_t access{}; + HwParamsPtr hp{CreateHwParams()}; +#define CHECK(x) do { \ + if((err=(x)) < 0) \ + throw al::backend_exception{ALC_INVALID_VALUE, #x " failed: %s", snd_strerror(err)}; \ +} while(0) + CHECK(snd_pcm_hw_params_current(mPcmHandle, hp.get())); /* retrieve configuration info */ - CHECK(snd_pcm_hw_params_get_access(hp, &access)); + CHECK(snd_pcm_hw_params_get_access(hp.get(), &access)); #undef CHECK - if(0) - { - error: - ERR("%s failed: %s\n", funcerr, snd_strerror(err)); - if(hp) snd_pcm_hw_params_free(hp); - return false; - } - snd_pcm_hw_params_free(hp); hp = nullptr; int (AlsaPlayback::*thread_func)(){}; @@ -823,8 +831,6 @@ bool AlsaPlayback::start() catch(std::exception& e) { ERR("Could not create playback thread: %s\n", e.what()); } - catch(...) { - } mBuffer.clear(); return false; } @@ -923,72 +929,67 @@ void AlsaCapture::open(const ALCchar *name) snd_pcm_format_t format{SND_PCM_FORMAT_UNKNOWN}; switch(mDevice->FmtType) { - case DevFmtByte: - format = SND_PCM_FORMAT_S8; - break; - case DevFmtUByte: - format = SND_PCM_FORMAT_U8; - break; - case DevFmtShort: - format = SND_PCM_FORMAT_S16; - break; - case DevFmtUShort: - format = SND_PCM_FORMAT_U16; - break; - case DevFmtInt: - format = SND_PCM_FORMAT_S32; - break; - case DevFmtUInt: - format = SND_PCM_FORMAT_U32; - break; - case DevFmtFloat: - format = SND_PCM_FORMAT_FLOAT; - break; + case DevFmtByte: + format = SND_PCM_FORMAT_S8; + break; + case DevFmtUByte: + format = SND_PCM_FORMAT_U8; + break; + case DevFmtShort: + format = SND_PCM_FORMAT_S16; + break; + case DevFmtUShort: + format = SND_PCM_FORMAT_U16; + break; + case DevFmtInt: + format = SND_PCM_FORMAT_S32; + break; + case DevFmtUInt: + format = SND_PCM_FORMAT_U32; + break; + case DevFmtFloat: + format = SND_PCM_FORMAT_FLOAT; + break; } snd_pcm_uframes_t bufferSizeInFrames{maxu(mDevice->BufferSize, 100*mDevice->Frequency/1000)}; snd_pcm_uframes_t periodSizeInFrames{minu(mDevice->BufferSize, 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(mPcmHandle, hp)); + HwParamsPtr hp{CreateHwParams()}; +#define CHECK(x) do { \ + if((err=(x)) < 0) \ + throw al::backend_exception{ALC_INVALID_VALUE, #x " failed: %s", snd_strerror(err)}; \ +} while(0) + CHECK(snd_pcm_hw_params_any(mPcmHandle, hp.get())); /* set interleaved access */ - CHECK(snd_pcm_hw_params_set_access(mPcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED)); + CHECK(snd_pcm_hw_params_set_access(mPcmHandle, hp.get(), SND_PCM_ACCESS_RW_INTERLEAVED)); /* set format (implicitly sets sample bits) */ - CHECK(snd_pcm_hw_params_set_format(mPcmHandle, hp, format)); + CHECK(snd_pcm_hw_params_set_format(mPcmHandle, hp.get(), format)); /* set channels (implicitly sets frame bits) */ - CHECK(snd_pcm_hw_params_set_channels(mPcmHandle, hp, mDevice->channelsFromFmt())); + CHECK(snd_pcm_hw_params_set_channels(mPcmHandle, hp.get(), mDevice->channelsFromFmt())); /* set rate (implicitly constrains period/buffer parameters) */ - CHECK(snd_pcm_hw_params_set_rate(mPcmHandle, hp, mDevice->Frequency, 0)); + CHECK(snd_pcm_hw_params_set_rate(mPcmHandle, hp.get(), 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(mPcmHandle, hp, &bufferSizeInFrames) < 0) + if(snd_pcm_hw_params_set_buffer_size_min(mPcmHandle, hp.get(), &bufferSizeInFrames) < 0) { TRACE("Buffer too large, using intermediate ring buffer\n"); needring = true; - CHECK(snd_pcm_hw_params_set_buffer_size_near(mPcmHandle, hp, &bufferSizeInFrames)); + CHECK(snd_pcm_hw_params_set_buffer_size_near(mPcmHandle, hp.get(), &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(mPcmHandle, hp, &periodSizeInFrames, nullptr)); + CHECK(snd_pcm_hw_params_set_period_size_near(mPcmHandle, hp.get(), &periodSizeInFrames, nullptr)); /* install and prepare hardware configuration */ - CHECK(snd_pcm_hw_params(mPcmHandle, hp)); + CHECK(snd_pcm_hw_params(mPcmHandle, hp.get())); /* retrieve configuration info */ - CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, nullptr)); + CHECK(snd_pcm_hw_params_get_period_size(hp.get(), &periodSizeInFrames, nullptr)); #undef CHECK - snd_pcm_hw_params_free(hp); hp = nullptr; if(needring) mRing = CreateRingBuffer(mDevice->BufferSize, mDevice->frameSizeFromFmt(), false); mDevice->DeviceName = name; - return; - -error: - if(hp) snd_pcm_hw_params_free(hp); - throw al::backend_exception{ALC_INVALID_VALUE, "%s failed: %s", funcerr, snd_strerror(err)}; } @@ -996,18 +997,13 @@ bool AlsaCapture::start() { int err{snd_pcm_prepare(mPcmHandle)}; if(err < 0) - ERR("prepare failed: %s\n", snd_strerror(err)); - else - { - err = snd_pcm_start(mPcmHandle); - if(err < 0) - ERR("start failed: %s\n", snd_strerror(err)); - } + throw al::backend_exception{ALC_INVALID_VALUE, "snd_pcm_prepare failed: %s", + snd_strerror(err)}; + + err = snd_pcm_start(mPcmHandle); if(err < 0) - { - aluHandleDisconnect(mDevice, "Capture state failure: %s", snd_strerror(err)); - return false; - } + throw al::backend_exception{ALC_INVALID_VALUE, "snd_pcm_start failed: %s", + snd_strerror(err)}; mDoCapture = true; return true; |