Don't explicitly try to spawn servers by default
[openal-soft.git] / alc / backends / jack.cpp
blob419eb7e7f98087be3cdf72f1a1cad98740316914
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include "jack.h"
25 #include <cstdlib>
26 #include <cstdio>
27 #include <cstring>
28 #include <memory.h>
30 #include <array>
31 #include <thread>
32 #include <functional>
34 #include "alc/alconfig.h"
35 #include "alnumeric.h"
36 #include "core/device.h"
37 #include "core/helpers.h"
38 #include "core/logging.h"
39 #include "dynload.h"
40 #include "ringbuffer.h"
41 #include "threads.h"
43 #include <jack/jack.h>
44 #include <jack/ringbuffer.h>
47 namespace {
49 #ifdef HAVE_DYNLOAD
50 #define JACK_FUNCS(MAGIC) \
51 MAGIC(jack_client_open); \
52 MAGIC(jack_client_close); \
53 MAGIC(jack_client_name_size); \
54 MAGIC(jack_get_client_name); \
55 MAGIC(jack_connect); \
56 MAGIC(jack_activate); \
57 MAGIC(jack_deactivate); \
58 MAGIC(jack_port_register); \
59 MAGIC(jack_port_unregister); \
60 MAGIC(jack_port_get_buffer); \
61 MAGIC(jack_port_name); \
62 MAGIC(jack_get_ports); \
63 MAGIC(jack_free); \
64 MAGIC(jack_get_sample_rate); \
65 MAGIC(jack_set_error_function); \
66 MAGIC(jack_set_process_callback); \
67 MAGIC(jack_set_buffer_size_callback); \
68 MAGIC(jack_set_buffer_size); \
69 MAGIC(jack_get_buffer_size);
71 void *jack_handle;
72 #define MAKE_FUNC(f) decltype(f) * p##f
73 JACK_FUNCS(MAKE_FUNC)
74 decltype(jack_error_callback) * pjack_error_callback;
75 #undef MAKE_FUNC
77 #ifndef IN_IDE_PARSER
78 #define jack_client_open pjack_client_open
79 #define jack_client_close pjack_client_close
80 #define jack_client_name_size pjack_client_name_size
81 #define jack_get_client_name pjack_get_client_name
82 #define jack_connect pjack_connect
83 #define jack_activate pjack_activate
84 #define jack_deactivate pjack_deactivate
85 #define jack_port_register pjack_port_register
86 #define jack_port_unregister pjack_port_unregister
87 #define jack_port_get_buffer pjack_port_get_buffer
88 #define jack_port_name pjack_port_name
89 #define jack_get_ports pjack_get_ports
90 #define jack_free pjack_free
91 #define jack_get_sample_rate pjack_get_sample_rate
92 #define jack_set_error_function pjack_set_error_function
93 #define jack_set_process_callback pjack_set_process_callback
94 #define jack_set_buffer_size_callback pjack_set_buffer_size_callback
95 #define jack_set_buffer_size pjack_set_buffer_size
96 #define jack_get_buffer_size pjack_get_buffer_size
97 #define jack_error_callback (*pjack_error_callback)
98 #endif
99 #endif
102 constexpr char JackDefaultAudioType[] = JACK_DEFAULT_AUDIO_TYPE;
104 jack_options_t ClientOptions = JackNullOption;
106 bool jack_load()
108 bool error{false};
110 #ifdef HAVE_DYNLOAD
111 if(!jack_handle)
113 std::string missing_funcs;
115 #ifdef _WIN32
116 #define JACKLIB "libjack.dll"
117 #else
118 #define JACKLIB "libjack.so.0"
119 #endif
120 jack_handle = LoadLib(JACKLIB);
121 if(!jack_handle)
123 WARN("Failed to load %s\n", JACKLIB);
124 return false;
127 error = false;
128 #define LOAD_FUNC(f) do { \
129 p##f = reinterpret_cast<decltype(p##f)>(GetSymbol(jack_handle, #f)); \
130 if(p##f == nullptr) { \
131 error = true; \
132 missing_funcs += "\n" #f; \
134 } while(0)
135 JACK_FUNCS(LOAD_FUNC);
136 #undef LOAD_FUNC
137 /* Optional symbols. These don't exist in all versions of JACK. */
138 #define LOAD_SYM(f) p##f = reinterpret_cast<decltype(p##f)>(GetSymbol(jack_handle, #f))
139 LOAD_SYM(jack_error_callback);
140 #undef LOAD_SYM
142 if(error)
144 WARN("Missing expected functions:%s\n", missing_funcs.c_str());
145 CloseLib(jack_handle);
146 jack_handle = nullptr;
149 #endif
151 return !error;
155 struct JackDeleter {
156 void operator()(void *ptr) { jack_free(ptr); }
158 using JackPortsPtr = std::unique_ptr<const char*[],JackDeleter>;
160 struct DeviceEntry {
161 std::string mName;
162 std::string mPattern;
164 template<typename T, typename U>
165 DeviceEntry(T&& name, U&& pattern)
166 : mName{std::forward<T>(name)}, mPattern{std::forward<U>(pattern)}
170 al::vector<DeviceEntry> PlaybackList;
173 void EnumerateDevices(jack_client_t *client, al::vector<DeviceEntry> &list)
175 std::remove_reference_t<decltype(list)>{}.swap(list);
177 if(JackPortsPtr ports{jack_get_ports(client, nullptr, JackDefaultAudioType, JackPortIsInput)})
179 for(size_t i{0};ports[i];++i)
181 const char *sep{std::strchr(ports[i], ':')};
182 if(!sep || ports[i] == sep) continue;
184 const al::span<const char> portdev{ports[i], sep};
185 auto check_name = [portdev](const DeviceEntry &entry) -> bool
187 const size_t len{portdev.size()};
188 return entry.mName.length() == len
189 && entry.mName.compare(0, len, portdev.data(), len) == 0;
191 if(std::find_if(list.cbegin(), list.cend(), check_name) != list.cend())
192 continue;
194 std::string name{portdev.data(), portdev.size()};
195 list.emplace_back(name, name+":");
196 const auto &entry = list.back();
197 TRACE("Got device: %s = %s\n", entry.mName.c_str(), entry.mPattern.c_str());
199 /* There are ports but couldn't get device names from them. Add a
200 * generic entry.
202 if(ports[0] && list.empty())
204 WARN("No device names found in available ports, adding a generic name.\n");
205 list.emplace_back("JACK", "");
209 if(auto listopt = ConfigValueStr(nullptr, "jack", "custom-devices"))
211 for(size_t strpos{0};strpos < listopt->size();)
213 size_t nextpos{listopt->find(';', strpos)};
214 size_t seppos{listopt->find('=', strpos)};
215 if(seppos >= nextpos || seppos == strpos)
217 const std::string entry{listopt->substr(strpos, nextpos-strpos)};
218 ERR("Invalid device entry: \"%s\"\n", entry.c_str());
219 if(nextpos != std::string::npos) ++nextpos;
220 strpos = nextpos;
221 continue;
224 const al::span<const char> name{listopt->data()+strpos, seppos-strpos};
225 const al::span<const char> pattern{listopt->data()+(seppos+1),
226 std::min(nextpos, listopt->size())-(seppos+1)};
228 /* Check if this custom pattern already exists in the list. */
229 auto check_pattern = [pattern](const DeviceEntry &entry) -> bool
231 const size_t len{pattern.size()};
232 return entry.mPattern.length() == len
233 && entry.mPattern.compare(0, len, pattern.data(), len) == 0;
235 auto itemmatch = std::find_if(list.begin(), list.end(), check_pattern);
236 if(itemmatch != list.end())
238 /* If so, replace the name with this custom one. */
239 itemmatch->mName.assign(name.data(), name.size());
240 TRACE("Customized device name: %s = %s\n", itemmatch->mName.c_str(),
241 itemmatch->mPattern.c_str());
243 else
245 /* Otherwise, add a new device entry. */
246 list.emplace_back(std::string{name.data(), name.size()},
247 std::string{pattern.data(), pattern.size()});
248 const auto &entry = list.back();
249 TRACE("Got custom device: %s = %s\n", entry.mName.c_str(), entry.mPattern.c_str());
252 if(nextpos != std::string::npos) ++nextpos;
253 strpos = nextpos;
257 if(list.size() > 1)
259 /* Rename entries that have matching names, by appending '#2', '#3',
260 * etc, as needed.
262 for(auto curitem = list.begin()+1;curitem != list.end();++curitem)
264 auto check_match = [curitem](const DeviceEntry &entry) -> bool
265 { return entry.mName == curitem->mName; };
266 if(std::find_if(list.begin(), curitem, check_match) != curitem)
268 std::string name{curitem->mName};
269 size_t count{1};
270 auto check_name = [&name](const DeviceEntry &entry) -> bool
271 { return entry.mName == name; };
272 do {
273 name = curitem->mName;
274 name += " #";
275 name += std::to_string(++count);
276 } while(std::find_if(list.begin(), curitem, check_name) != curitem);
277 curitem->mName = std::move(name);
284 struct JackPlayback final : public BackendBase {
285 JackPlayback(DeviceBase *device) noexcept : BackendBase{device} { }
286 ~JackPlayback() override;
288 int processRt(jack_nframes_t numframes) noexcept;
289 static int processRtC(jack_nframes_t numframes, void *arg) noexcept
290 { return static_cast<JackPlayback*>(arg)->processRt(numframes); }
292 int process(jack_nframes_t numframes) noexcept;
293 static int processC(jack_nframes_t numframes, void *arg) noexcept
294 { return static_cast<JackPlayback*>(arg)->process(numframes); }
296 int mixerProc();
298 void open(const char *name) override;
299 bool reset() override;
300 void start() override;
301 void stop() override;
302 ClockLatency getClockLatency() override;
304 std::string mPortPattern;
306 jack_client_t *mClient{nullptr};
307 std::array<jack_port_t*,MAX_OUTPUT_CHANNELS> mPort{};
309 std::mutex mMutex;
311 std::atomic<bool> mPlaying{false};
312 bool mRTMixing{false};
313 RingBufferPtr mRing;
314 al::semaphore mSem;
316 std::atomic<bool> mKillNow{true};
317 std::thread mThread;
319 DEF_NEWDEL(JackPlayback)
322 JackPlayback::~JackPlayback()
324 if(!mClient)
325 return;
327 auto unregister_port = [this](jack_port_t *port) -> void
328 { if(port) jack_port_unregister(mClient, port); };
329 std::for_each(mPort.begin(), mPort.end(), unregister_port);
330 mPort.fill(nullptr);
332 jack_client_close(mClient);
333 mClient = nullptr;
337 int JackPlayback::processRt(jack_nframes_t numframes) noexcept
339 std::array<jack_default_audio_sample_t*,MAX_OUTPUT_CHANNELS> out;
340 size_t numchans{0};
341 for(auto port : mPort)
343 if(!port || numchans == mDevice->RealOut.Buffer.size())
344 break;
345 out[numchans++] = static_cast<float*>(jack_port_get_buffer(port, numframes));
348 if(mPlaying.load(std::memory_order_acquire)) [[likely]]
349 mDevice->renderSamples({out.data(), numchans}, static_cast<uint>(numframes));
350 else
352 auto clear_buf = [numframes](float *outbuf) -> void
353 { std::fill_n(outbuf, numframes, 0.0f); };
354 std::for_each(out.begin(), out.begin()+numchans, clear_buf);
357 return 0;
361 int JackPlayback::process(jack_nframes_t numframes) noexcept
363 std::array<jack_default_audio_sample_t*,MAX_OUTPUT_CHANNELS> out;
364 size_t numchans{0};
365 for(auto port : mPort)
367 if(!port) break;
368 out[numchans++] = static_cast<float*>(jack_port_get_buffer(port, numframes));
371 jack_nframes_t total{0};
372 if(mPlaying.load(std::memory_order_acquire)) [[likely]]
374 auto data = mRing->getReadVector();
375 jack_nframes_t todo{minu(numframes, static_cast<uint>(data.first.len))};
376 auto write_first = [&data,numchans,todo](float *outbuf) -> float*
378 const float *RESTRICT in = reinterpret_cast<float*>(data.first.buf);
379 auto deinterlace_input = [&in,numchans]() noexcept -> float
381 float ret{*in};
382 in += numchans;
383 return ret;
385 std::generate_n(outbuf, todo, deinterlace_input);
386 data.first.buf += sizeof(float);
387 return outbuf + todo;
389 std::transform(out.begin(), out.begin()+numchans, out.begin(), write_first);
390 total += todo;
392 todo = minu(numframes-total, static_cast<uint>(data.second.len));
393 if(todo > 0)
395 auto write_second = [&data,numchans,todo](float *outbuf) -> float*
397 const float *RESTRICT in = reinterpret_cast<float*>(data.second.buf);
398 auto deinterlace_input = [&in,numchans]() noexcept -> float
400 float ret{*in};
401 in += numchans;
402 return ret;
404 std::generate_n(outbuf, todo, deinterlace_input);
405 data.second.buf += sizeof(float);
406 return outbuf + todo;
408 std::transform(out.begin(), out.begin()+numchans, out.begin(), write_second);
409 total += todo;
412 mRing->readAdvance(total);
413 mSem.post();
416 if(numframes > total)
418 const jack_nframes_t todo{numframes - total};
419 auto clear_buf = [todo](float *outbuf) -> void { std::fill_n(outbuf, todo, 0.0f); };
420 std::for_each(out.begin(), out.begin()+numchans, clear_buf);
423 return 0;
426 int JackPlayback::mixerProc()
428 SetRTPriority();
429 althrd_setname(MIXER_THREAD_NAME);
431 const size_t frame_step{mDevice->channelsFromFmt()};
433 while(!mKillNow.load(std::memory_order_acquire)
434 && mDevice->Connected.load(std::memory_order_acquire))
436 if(mRing->writeSpace() < mDevice->UpdateSize)
438 mSem.wait();
439 continue;
442 auto data = mRing->getWriteVector();
443 size_t todo{data.first.len + data.second.len};
444 todo -= todo%mDevice->UpdateSize;
446 const auto len1 = static_cast<uint>(minz(data.first.len, todo));
447 const auto len2 = static_cast<uint>(minz(data.second.len, todo-len1));
449 std::lock_guard<std::mutex> _{mMutex};
450 mDevice->renderSamples(data.first.buf, len1, frame_step);
451 if(len2 > 0)
452 mDevice->renderSamples(data.second.buf, len2, frame_step);
453 mRing->writeAdvance(todo);
456 return 0;
460 void JackPlayback::open(const char *name)
462 if(!mClient)
464 const PathNamePair &binname = GetProcBinary();
465 const char *client_name{binname.fname.empty() ? "alsoft" : binname.fname.c_str()};
467 jack_status_t status;
468 mClient = jack_client_open(client_name, ClientOptions, &status, nullptr);
469 if(mClient == nullptr)
470 throw al::backend_exception{al::backend_error::DeviceError,
471 "Failed to open client connection: 0x%02x", status};
472 if((status&JackServerStarted))
473 TRACE("JACK server started\n");
474 if((status&JackNameNotUnique))
476 client_name = jack_get_client_name(mClient);
477 TRACE("Client name not unique, got '%s' instead\n", client_name);
481 if(PlaybackList.empty())
482 EnumerateDevices(mClient, PlaybackList);
484 if(!name && !PlaybackList.empty())
486 name = PlaybackList[0].mName.c_str();
487 mPortPattern = PlaybackList[0].mPattern;
489 else
491 auto check_name = [name](const DeviceEntry &entry) -> bool
492 { return entry.mName == name; };
493 auto iter = std::find_if(PlaybackList.cbegin(), PlaybackList.cend(), check_name);
494 if(iter == PlaybackList.cend())
495 throw al::backend_exception{al::backend_error::NoDevice,
496 "Device name \"%s\" not found", name?name:""};
497 mPortPattern = iter->mPattern;
500 mRTMixing = GetConfigValueBool(name, "jack", "rt-mix", 1);
501 jack_set_process_callback(mClient,
502 mRTMixing ? &JackPlayback::processRtC : &JackPlayback::processC, this);
504 mDevice->DeviceName = name;
507 bool JackPlayback::reset()
509 auto unregister_port = [this](jack_port_t *port) -> void
510 { if(port) jack_port_unregister(mClient, port); };
511 std::for_each(mPort.begin(), mPort.end(), unregister_port);
512 mPort.fill(nullptr);
514 /* Ignore the requested buffer metrics and just keep one JACK-sized buffer
515 * ready for when requested.
517 mDevice->Frequency = jack_get_sample_rate(mClient);
518 mDevice->UpdateSize = jack_get_buffer_size(mClient);
519 if(mRTMixing)
521 /* Assume only two periods when directly mixing. Should try to query
522 * the total port latency when connected.
524 mDevice->BufferSize = mDevice->UpdateSize * 2;
526 else
528 const char *devname{mDevice->DeviceName.c_str()};
529 uint bufsize{ConfigValueUInt(devname, "jack", "buffer-size").value_or(mDevice->UpdateSize)};
530 bufsize = maxu(NextPowerOf2(bufsize), mDevice->UpdateSize);
531 mDevice->BufferSize = bufsize + mDevice->UpdateSize;
534 /* Force 32-bit float output. */
535 mDevice->FmtType = DevFmtFloat;
537 int port_num{0};
538 auto ports_end = mPort.begin() + mDevice->channelsFromFmt();
539 auto bad_port = mPort.begin();
540 while(bad_port != ports_end)
542 std::string name{"channel_" + std::to_string(++port_num)};
543 *bad_port = jack_port_register(mClient, name.c_str(), JackDefaultAudioType,
544 JackPortIsOutput | JackPortIsTerminal, 0);
545 if(!*bad_port) break;
546 ++bad_port;
548 if(bad_port != ports_end)
550 ERR("Failed to register enough JACK ports for %s output\n",
551 DevFmtChannelsString(mDevice->FmtChans));
552 if(bad_port == mPort.begin()) return false;
554 if(bad_port == mPort.begin()+1)
555 mDevice->FmtChans = DevFmtMono;
556 else
558 ports_end = mPort.begin()+2;
559 while(bad_port != ports_end)
561 jack_port_unregister(mClient, *(--bad_port));
562 *bad_port = nullptr;
564 mDevice->FmtChans = DevFmtStereo;
568 setDefaultChannelOrder();
570 return true;
573 void JackPlayback::start()
575 if(jack_activate(mClient))
576 throw al::backend_exception{al::backend_error::DeviceError, "Failed to activate client"};
578 const char *devname{mDevice->DeviceName.c_str()};
579 if(ConfigValueBool(devname, "jack", "connect-ports").value_or(true))
581 JackPortsPtr pnames{jack_get_ports(mClient, mPortPattern.c_str(), JackDefaultAudioType,
582 JackPortIsInput)};
583 if(!pnames)
585 jack_deactivate(mClient);
586 throw al::backend_exception{al::backend_error::DeviceError, "No playback ports found"};
589 for(size_t i{0};i < al::size(mPort) && mPort[i];++i)
591 if(!pnames[i])
593 ERR("No physical playback port for \"%s\"\n", jack_port_name(mPort[i]));
594 break;
596 if(jack_connect(mClient, jack_port_name(mPort[i]), pnames[i]))
597 ERR("Failed to connect output port \"%s\" to \"%s\"\n", jack_port_name(mPort[i]),
598 pnames[i]);
602 /* Reconfigure buffer metrics in case the server changed it since the reset
603 * (it won't change again after jack_activate), then allocate the ring
604 * buffer with the appropriate size.
606 mDevice->Frequency = jack_get_sample_rate(mClient);
607 mDevice->UpdateSize = jack_get_buffer_size(mClient);
608 mDevice->BufferSize = mDevice->UpdateSize * 2;
610 mRing = nullptr;
611 if(mRTMixing)
612 mPlaying.store(true, std::memory_order_release);
613 else
615 uint bufsize{ConfigValueUInt(devname, "jack", "buffer-size").value_or(mDevice->UpdateSize)};
616 bufsize = maxu(NextPowerOf2(bufsize), mDevice->UpdateSize);
617 mDevice->BufferSize = bufsize + mDevice->UpdateSize;
619 mRing = RingBuffer::Create(bufsize, mDevice->frameSizeFromFmt(), true);
621 try {
622 mPlaying.store(true, std::memory_order_release);
623 mKillNow.store(false, std::memory_order_release);
624 mThread = std::thread{std::mem_fn(&JackPlayback::mixerProc), this};
626 catch(std::exception& e) {
627 jack_deactivate(mClient);
628 mPlaying.store(false, std::memory_order_release);
629 throw al::backend_exception{al::backend_error::DeviceError,
630 "Failed to start mixing thread: %s", e.what()};
635 void JackPlayback::stop()
637 if(mPlaying.load(std::memory_order_acquire))
639 mKillNow.store(true, std::memory_order_release);
640 if(mThread.joinable())
642 mSem.post();
643 mThread.join();
646 jack_deactivate(mClient);
647 mPlaying.store(false, std::memory_order_release);
652 ClockLatency JackPlayback::getClockLatency()
654 ClockLatency ret;
656 std::lock_guard<std::mutex> _{mMutex};
657 ret.ClockTime = GetDeviceClockTime(mDevice);
658 ret.Latency = std::chrono::seconds{mRing ? mRing->readSpace() : mDevice->UpdateSize};
659 ret.Latency /= mDevice->Frequency;
661 return ret;
665 void jack_msg_handler(const char *message)
667 WARN("%s\n", message);
670 } // namespace
672 bool JackBackendFactory::init()
674 if(!jack_load())
675 return false;
677 if(!GetConfigValueBool(nullptr, "jack", "spawn-server", false))
678 ClientOptions = static_cast<jack_options_t>(ClientOptions | JackNoStartServer);
680 const PathNamePair &binname = GetProcBinary();
681 const char *client_name{binname.fname.empty() ? "alsoft" : binname.fname.c_str()};
683 void (*old_error_cb)(const char*){&jack_error_callback ? jack_error_callback : nullptr};
684 jack_set_error_function(jack_msg_handler);
685 jack_status_t status;
686 jack_client_t *client{jack_client_open(client_name, ClientOptions, &status, nullptr)};
687 jack_set_error_function(old_error_cb);
688 if(!client)
690 WARN("jack_client_open() failed, 0x%02x\n", status);
691 if((status&JackServerFailed) && !(ClientOptions&JackNoStartServer))
692 ERR("Unable to connect to JACK server\n");
693 return false;
696 jack_client_close(client);
697 return true;
700 bool JackBackendFactory::querySupport(BackendType type)
701 { return (type == BackendType::Playback); }
703 std::string JackBackendFactory::probe(BackendType type)
705 std::string outnames;
706 auto append_name = [&outnames](const DeviceEntry &entry) -> void
708 /* Includes null char. */
709 outnames.append(entry.mName.c_str(), entry.mName.length()+1);
712 const PathNamePair &binname = GetProcBinary();
713 const char *client_name{binname.fname.empty() ? "alsoft" : binname.fname.c_str()};
714 jack_status_t status;
715 switch(type)
717 case BackendType::Playback:
718 if(jack_client_t *client{jack_client_open(client_name, ClientOptions, &status, nullptr)})
720 EnumerateDevices(client, PlaybackList);
721 jack_client_close(client);
723 else
724 WARN("jack_client_open() failed, 0x%02x\n", status);
725 std::for_each(PlaybackList.cbegin(), PlaybackList.cend(), append_name);
726 break;
727 case BackendType::Capture:
728 break;
730 return outnames;
733 BackendPtr JackBackendFactory::createBackend(DeviceBase *device, BackendType type)
735 if(type == BackendType::Playback)
736 return BackendPtr{new JackPlayback{device}};
737 return nullptr;
740 BackendFactory &JackBackendFactory::getFactory()
742 static JackBackendFactory factory{};
743 return factory;