From af08f68448b37a9c1a22f6d9721b5c2c0708c960 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 12 Jan 2020 07:48:11 -0800 Subject: Fix JACK process callback handling The callback apparently can't be set after activation, but we can't allocate the ring buffer until after activation when the callback is already getting called. An ugly flag it is, then, I guess. --- alc/backends/jack.cpp | 98 +++++++++++++++++++++++++-------------------------- 1 file changed, 48 insertions(+), 50 deletions(-) (limited to 'alc/backends') diff --git a/alc/backends/jack.cpp b/alc/backends/jack.cpp index 9ec66cfe..485225e4 100644 --- a/alc/backends/jack.cpp +++ b/alc/backends/jack.cpp @@ -169,6 +169,7 @@ struct JackPlayback final : public BackendBase { jack_client_t *mClient{nullptr}; jack_port_t *mPort[MAX_OUTPUT_CHANNELS]{}; + std::atomic mPlaying{false}; RingBufferPtr mRing; al::semaphore mSem; @@ -196,68 +197,63 @@ JackPlayback::~JackPlayback() int JackPlayback::process(jack_nframes_t numframes) noexcept { jack_default_audio_sample_t *out[MAX_OUTPUT_CHANNELS]; - ALsizei numchans{0}; + size_t numchans{0}; for(auto port : mPort) { if(!port) break; out[numchans++] = static_cast(jack_port_get_buffer(port, numframes)); } - auto data = mRing->getReadVector(); - jack_nframes_t todo{minu(numframes, static_cast(data.first.len))}; - std::transform(out, out+numchans, out, - [&data,numchans,todo](ALfloat *outbuf) -> ALfloat* + jack_nframes_t total{0}; + if LIKELY(mPlaying.load(std::memory_order_acquire)) + { + auto data = mRing->getReadVector(); + jack_nframes_t todo{minu(numframes, static_cast(data.first.len))}; + auto write_first = [&data,numchans,todo](float *outbuf) -> float* + { + const float *RESTRICT in = reinterpret_cast(data.first.buf); + auto deinterlace_input = [&in,numchans]() noexcept -> float + { + float ret{*in}; + in += numchans; + return ret; + }; + std::generate_n(outbuf, todo, deinterlace_input); + data.first.buf += sizeof(float); + return outbuf + todo; + }; + std::transform(out, out+numchans, out, write_first); + total += todo; + + todo = minu(numframes-total, static_cast(data.second.len)); + if(todo > 0) { - const ALfloat *RESTRICT in = reinterpret_cast(data.first.buf); - std::generate_n(outbuf, todo, - [&in,numchans]() noexcept -> ALfloat + auto write_second = [&data,numchans,todo](float *outbuf) -> float* + { + const float *RESTRICT in = reinterpret_cast(data.second.buf); + auto deinterlace_input = [&in,numchans]() noexcept -> float { - ALfloat ret{*in}; + float ret{*in}; in += numchans; return ret; - } - ); - data.first.buf += sizeof(ALfloat); - return outbuf + todo; + }; + std::generate_n(outbuf, todo, deinterlace_input); + data.second.buf += sizeof(float); + return outbuf + todo; + }; + std::transform(out, out+numchans, out, write_second); + total += todo; } - ); - jack_nframes_t total{todo}; - todo = minu(numframes-total, static_cast(data.second.len)); - if(todo > 0) - { - std::transform(out, out+numchans, out, - [&data,numchans,todo](ALfloat *outbuf) -> ALfloat* - { - const ALfloat *RESTRICT in = reinterpret_cast(data.second.buf); - std::generate_n(outbuf, todo, - [&in,numchans]() noexcept -> ALfloat - { - ALfloat ret{*in}; - in += numchans; - return ret; - } - ); - data.second.buf += sizeof(ALfloat); - return outbuf + todo; - } - ); - total += todo; + mRing->readAdvance(total); + mSem.post(); } - mRing->readAdvance(total); - mSem.post(); - if(numframes > total) { - todo = numframes-total; - std::transform(out, out+numchans, out, - [todo](ALfloat *outbuf) -> ALfloat* - { - std::fill_n(outbuf, todo, 0.0f); - return outbuf + todo; - } - ); + jack_nframes_t todo{numframes - total}; + auto clear_buf = [todo](ALfloat *outbuf) -> void { std::fill_n(outbuf, todo, 0.0f); }; + std::for_each(out, out+numchans, clear_buf); } return 0; @@ -318,9 +314,11 @@ void JackPlayback::open(const ALCchar *name) if((status&JackNameNotUnique)) { client_name = jack_get_client_name(mClient); - TRACE("Client name not unique, got `%s' instead\n", client_name); + TRACE("Client name not unique, got '%s' instead\n", client_name); } + jack_set_process_callback(mClient, &JackPlayback::processC, this); + mDevice->DeviceName = name; } @@ -429,8 +427,8 @@ bool JackPlayback::start() mRing = nullptr; mRing = RingBuffer::Create(bufsize, mDevice->frameSizeFromFmt(), true); - jack_set_process_callback(mClient, &JackPlayback::processC, this); try { + mPlaying.store(true, std::memory_order_release); mKillNow.store(false, std::memory_order_release); mThread = std::thread{std::mem_fn(&JackPlayback::mixerProc), this}; return true; @@ -440,8 +438,8 @@ bool JackPlayback::start() } catch(...) { } - jack_set_process_callback(mClient, nullptr, nullptr); jack_deactivate(mClient); + mPlaying.store(false, std::memory_order_release); return false; } @@ -454,7 +452,7 @@ void JackPlayback::stop() mThread.join(); jack_deactivate(mClient); - jack_set_process_callback(mClient, nullptr, nullptr); + mPlaying.store(false, std::memory_order_release); } -- cgit v1.2.3