aboutsummaryrefslogtreecommitdiffstats
path: root/alc/backends
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2021-06-08 10:52:37 -0700
committerChris Robinson <[email protected]>2021-06-08 10:52:37 -0700
commitdebb932573010fb7b260f56d618644dbadd2e6b1 (patch)
tree1664315e916e7899ed1a2b4c5c68173755f85884 /alc/backends
parent58a9549a5886fe91aba698abb4e6e4c0c94f129e (diff)
Add an option to mix directly in the JACK callback
Diffstat (limited to 'alc/backends')
-rw-r--r--alc/backends/jack.cpp111
1 files changed, 80 insertions, 31 deletions
diff --git a/alc/backends/jack.cpp b/alc/backends/jack.cpp
index 54bd19e6..51be503d 100644
--- a/alc/backends/jack.cpp
+++ b/alc/backends/jack.cpp
@@ -239,6 +239,10 @@ struct JackPlayback final : public BackendBase {
JackPlayback(DeviceBase *device) noexcept : BackendBase{device} { }
~JackPlayback() override;
+ int processRt(jack_nframes_t numframes) noexcept;
+ static int processRtC(jack_nframes_t numframes, void *arg) noexcept
+ { return static_cast<JackPlayback*>(arg)->processRt(numframes); }
+
int process(jack_nframes_t numframes) noexcept;
static int processC(jack_nframes_t numframes, void *arg) noexcept
{ return static_cast<JackPlayback*>(arg)->process(numframes); }
@@ -259,6 +263,7 @@ struct JackPlayback final : public BackendBase {
std::mutex mMutex;
std::atomic<bool> mPlaying{false};
+ bool mRTMixing{false};
RingBufferPtr mRing;
al::semaphore mSem;
@@ -283,6 +288,30 @@ JackPlayback::~JackPlayback()
}
+int JackPlayback::processRt(jack_nframes_t numframes) noexcept
+{
+ std::array<jack_default_audio_sample_t*,MAX_OUTPUT_CHANNELS> out;
+ size_t numchans{0};
+ for(auto port : mPort)
+ {
+ if(!port || numchans == mDevice->RealOut.Buffer.size())
+ break;
+ out[numchans++] = static_cast<float*>(jack_port_get_buffer(port, numframes));
+ }
+
+ if LIKELY(mPlaying.load(std::memory_order_acquire))
+ mDevice->renderSamples({out.data(), numchans}, static_cast<uint>(numframes));
+ else
+ {
+ auto clear_buf = [numframes](float *outbuf) -> void
+ { std::fill_n(outbuf, numframes, 0.0f); };
+ std::for_each(out.begin(), out.begin()+numchans, clear_buf);
+ }
+
+ return 0;
+}
+
+
int JackPlayback::process(jack_nframes_t numframes) noexcept
{
std::array<jack_default_audio_sample_t*,MAX_OUTPUT_CHANNELS> out;
@@ -422,7 +451,9 @@ void JackPlayback::open(const char *name)
mPortPattern = iter->mPattern;
}
- jack_set_process_callback(mClient, &JackPlayback::processC, this);
+ mRTMixing = GetConfigValueBool(name, "jack", "rt-mix", 1);
+ jack_set_process_callback(mClient,
+ mRTMixing ? &JackPlayback::processRtC : &JackPlayback::processC, this);
mDevice->DeviceName = name;
}
@@ -439,12 +470,20 @@ bool JackPlayback::reset()
*/
mDevice->Frequency = jack_get_sample_rate(mClient);
mDevice->UpdateSize = jack_get_buffer_size(mClient);
- mDevice->BufferSize = mDevice->UpdateSize * 2;
-
- const char *devname{mDevice->DeviceName.c_str()};
- uint bufsize{ConfigValueUInt(devname, "jack", "buffer-size").value_or(mDevice->UpdateSize)};
- bufsize = maxu(NextPowerOf2(bufsize), mDevice->UpdateSize);
- mDevice->BufferSize = bufsize + mDevice->UpdateSize;
+ if(mRTMixing)
+ {
+ /* Assume only two periods when directly mixing. Should try to query
+ * the total port latency when connected.
+ */
+ mDevice->BufferSize = mDevice->UpdateSize * 2;
+ }
+ else
+ {
+ const char *devname{mDevice->DeviceName.c_str()};
+ uint bufsize{ConfigValueUInt(devname, "jack", "buffer-size").value_or(mDevice->UpdateSize)};
+ bufsize = maxu(NextPowerOf2(bufsize), mDevice->UpdateSize);
+ mDevice->BufferSize = bufsize + mDevice->UpdateSize;
+ }
/* Force 32-bit float output. */
mDevice->FmtType = DevFmtFloat;
@@ -460,7 +499,8 @@ bool JackPlayback::reset()
});
if(bad_port != ports_end)
{
- ERR("Not enough JACK ports available for %s output\n", DevFmtChannelsString(mDevice->FmtChans));
+ ERR("Not enough JACK ports available for %s output\n",
+ DevFmtChannelsString(mDevice->FmtChans));
if(bad_port == mPort.begin()) return false;
if(bad_port == mPort.begin()+1)
@@ -523,36 +563,45 @@ void JackPlayback::start()
mDevice->UpdateSize = jack_get_buffer_size(mClient);
mDevice->BufferSize = mDevice->UpdateSize * 2;
- uint bufsize{ConfigValueUInt(devname, "jack", "buffer-size").value_or(mDevice->UpdateSize)};
- bufsize = maxu(NextPowerOf2(bufsize), mDevice->UpdateSize);
- mDevice->BufferSize = bufsize + mDevice->UpdateSize;
-
mRing = nullptr;
- mRing = RingBuffer::Create(bufsize, mDevice->frameSizeFromFmt(), true);
-
- try {
+ if(mRTMixing)
mPlaying.store(true, std::memory_order_release);
- mKillNow.store(false, std::memory_order_release);
- mThread = std::thread{std::mem_fn(&JackPlayback::mixerProc), this};
- }
- catch(std::exception& e) {
- jack_deactivate(mClient);
- mPlaying.store(false, std::memory_order_release);
- throw al::backend_exception{al::backend_error::DeviceError,
- "Failed to start mixing thread: %s", e.what()};
+ else
+ {
+ uint bufsize{ConfigValueUInt(devname, "jack", "buffer-size").value_or(mDevice->UpdateSize)};
+ bufsize = maxu(NextPowerOf2(bufsize), mDevice->UpdateSize);
+ mDevice->BufferSize = bufsize + mDevice->UpdateSize;
+
+ mRing = RingBuffer::Create(bufsize, mDevice->frameSizeFromFmt(), true);
+
+ try {
+ mPlaying.store(true, std::memory_order_release);
+ mKillNow.store(false, std::memory_order_release);
+ mThread = std::thread{std::mem_fn(&JackPlayback::mixerProc), this};
+ }
+ catch(std::exception& e) {
+ jack_deactivate(mClient);
+ mPlaying.store(false, std::memory_order_release);
+ throw al::backend_exception{al::backend_error::DeviceError,
+ "Failed to start mixing thread: %s", e.what()};
+ }
}
}
void JackPlayback::stop()
{
- if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable())
- return;
-
- mSem.post();
- mThread.join();
+ if(mPlaying.load(std::memory_order_acquire))
+ {
+ mKillNow.store(true, std::memory_order_release);
+ if(mThread.joinable())
+ {
+ mSem.post();
+ mThread.join();
+ }
- jack_deactivate(mClient);
- mPlaying.store(false, std::memory_order_release);
+ jack_deactivate(mClient);
+ mPlaying.store(false, std::memory_order_release);
+ }
}
@@ -562,7 +611,7 @@ ClockLatency JackPlayback::getClockLatency()
std::lock_guard<std::mutex> _{mMutex};
ret.ClockTime = GetDeviceClockTime(mDevice);
- ret.Latency = std::chrono::seconds{mRing->readSpace()};
+ ret.Latency = std::chrono::seconds{mRing ? mRing->readSpace() : mDevice->UpdateSize};
ret.Latency /= mDevice->Frequency;
return ret;