jack.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753
  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.
  8. *
  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.
  13. *
  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
  19. */
  20. #include "config.h"
  21. #include "jack.h"
  22. #include <array>
  23. #include <cstdlib>
  24. #include <cstdio>
  25. #include <cstring>
  26. #include <memory.h>
  27. #include <mutex>
  28. #include <thread>
  29. #include <vector>
  30. #include "alc/alconfig.h"
  31. #include "alnumeric.h"
  32. #include "alsem.h"
  33. #include "althrd_setname.h"
  34. #include "core/device.h"
  35. #include "core/helpers.h"
  36. #include "core/logging.h"
  37. #include "dynload.h"
  38. #include "fmt/format.h"
  39. #include "ringbuffer.h"
  40. #include <jack/jack.h>
  41. #include <jack/ringbuffer.h>
  42. namespace {
  43. using namespace std::string_view_literals;
  44. #if HAVE_DYNLOAD
  45. #define JACK_FUNCS(MAGIC) \
  46. MAGIC(jack_client_open); \
  47. MAGIC(jack_client_close); \
  48. MAGIC(jack_client_name_size); \
  49. MAGIC(jack_get_client_name); \
  50. MAGIC(jack_connect); \
  51. MAGIC(jack_activate); \
  52. MAGIC(jack_deactivate); \
  53. MAGIC(jack_port_register); \
  54. MAGIC(jack_port_unregister); \
  55. MAGIC(jack_port_get_buffer); \
  56. MAGIC(jack_port_name); \
  57. MAGIC(jack_get_ports); \
  58. MAGIC(jack_free); \
  59. MAGIC(jack_get_sample_rate); \
  60. MAGIC(jack_set_error_function); \
  61. MAGIC(jack_set_process_callback); \
  62. MAGIC(jack_set_buffer_size_callback); \
  63. MAGIC(jack_set_buffer_size); \
  64. MAGIC(jack_get_buffer_size);
  65. void *jack_handle;
  66. #define MAKE_FUNC(f) decltype(f) * p##f
  67. JACK_FUNCS(MAKE_FUNC)
  68. decltype(jack_error_callback) * pjack_error_callback;
  69. #undef MAKE_FUNC
  70. #ifndef IN_IDE_PARSER
  71. #define jack_client_open pjack_client_open
  72. #define jack_client_close pjack_client_close
  73. #define jack_client_name_size pjack_client_name_size
  74. #define jack_get_client_name pjack_get_client_name
  75. #define jack_connect pjack_connect
  76. #define jack_activate pjack_activate
  77. #define jack_deactivate pjack_deactivate
  78. #define jack_port_register pjack_port_register
  79. #define jack_port_unregister pjack_port_unregister
  80. #define jack_port_get_buffer pjack_port_get_buffer
  81. #define jack_port_name pjack_port_name
  82. #define jack_get_ports pjack_get_ports
  83. #define jack_free pjack_free
  84. #define jack_get_sample_rate pjack_get_sample_rate
  85. #define jack_set_error_function pjack_set_error_function
  86. #define jack_set_process_callback pjack_set_process_callback
  87. #define jack_set_buffer_size_callback pjack_set_buffer_size_callback
  88. #define jack_set_buffer_size pjack_set_buffer_size
  89. #define jack_get_buffer_size pjack_get_buffer_size
  90. #define jack_error_callback (*pjack_error_callback)
  91. #endif
  92. #endif
  93. jack_options_t ClientOptions = JackNullOption;
  94. bool jack_load()
  95. {
  96. #if HAVE_DYNLOAD
  97. if(!jack_handle)
  98. {
  99. #if defined(_WIN64)
  100. #define JACKLIB "libjack64.dll"
  101. #elif defined(_WIN32)
  102. #define JACKLIB "libjack.dll"
  103. #else
  104. #define JACKLIB "libjack.so.0"
  105. #endif
  106. jack_handle = LoadLib(JACKLIB);
  107. if(!jack_handle)
  108. {
  109. WARN("Failed to load {}", JACKLIB);
  110. return false;
  111. }
  112. std::string missing_funcs;
  113. #define LOAD_FUNC(f) do { \
  114. p##f = reinterpret_cast<decltype(p##f)>(GetSymbol(jack_handle, #f)); \
  115. if(p##f == nullptr) missing_funcs += "\n" #f; \
  116. } while(0)
  117. JACK_FUNCS(LOAD_FUNC);
  118. #undef LOAD_FUNC
  119. /* Optional symbols. These don't exist in all versions of JACK. */
  120. #define LOAD_SYM(f) p##f = reinterpret_cast<decltype(p##f)>(GetSymbol(jack_handle, #f))
  121. LOAD_SYM(jack_error_callback);
  122. #undef LOAD_SYM
  123. if(!missing_funcs.empty())
  124. {
  125. WARN("Missing expected functions:{}", missing_funcs);
  126. CloseLib(jack_handle);
  127. jack_handle = nullptr;
  128. return false;
  129. }
  130. }
  131. #endif
  132. return true;
  133. }
  134. struct JackDeleter {
  135. void operator()(void *ptr) { jack_free(ptr); }
  136. };
  137. using JackPortsPtr = std::unique_ptr<const char*[],JackDeleter>; /* NOLINT(*-avoid-c-arrays) */
  138. struct DeviceEntry {
  139. std::string mName;
  140. std::string mPattern;
  141. DeviceEntry() = default;
  142. DeviceEntry(const DeviceEntry&) = default;
  143. DeviceEntry(DeviceEntry&&) = default;
  144. template<typename T, typename U>
  145. DeviceEntry(T&& name, U&& pattern)
  146. : mName{std::forward<T>(name)}, mPattern{std::forward<U>(pattern)}
  147. { }
  148. ~DeviceEntry();
  149. DeviceEntry& operator=(const DeviceEntry&) = default;
  150. DeviceEntry& operator=(DeviceEntry&&) = default;
  151. };
  152. DeviceEntry::~DeviceEntry() = default;
  153. std::vector<DeviceEntry> PlaybackList;
  154. void EnumerateDevices(jack_client_t *client, std::vector<DeviceEntry> &list)
  155. {
  156. std::remove_reference_t<decltype(list)>{}.swap(list);
  157. if(JackPortsPtr ports{jack_get_ports(client, nullptr, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput)})
  158. {
  159. for(size_t i{0};ports[i];++i)
  160. {
  161. const std::string_view portname{ports[i]};
  162. const size_t seppos{portname.find(':')};
  163. if(seppos == 0 || seppos >= portname.size())
  164. continue;
  165. const auto portdev = portname.substr(0, seppos);
  166. auto check_name = [portdev](const DeviceEntry &entry) -> bool
  167. { return entry.mName == portdev; };
  168. if(std::find_if(list.cbegin(), list.cend(), check_name) != list.cend())
  169. continue;
  170. const auto &entry = list.emplace_back(portdev, fmt::format("{}:", portdev));
  171. TRACE("Got device: {} = {}", entry.mName, entry.mPattern);
  172. }
  173. /* There are ports but couldn't get device names from them. Add a
  174. * generic entry.
  175. */
  176. if(ports[0] && list.empty())
  177. {
  178. WARN("No device names found in available ports, adding a generic name.");
  179. list.emplace_back("JACK"sv, ""sv);
  180. }
  181. }
  182. if(auto listopt = ConfigValueStr({}, "jack", "custom-devices"))
  183. {
  184. for(size_t strpos{0};strpos < listopt->size();)
  185. {
  186. size_t nextpos{listopt->find(';', strpos)};
  187. size_t seppos{listopt->find('=', strpos)};
  188. if(seppos >= nextpos || seppos == strpos)
  189. {
  190. const auto entry = std::string_view{*listopt}.substr(strpos, nextpos-strpos);
  191. ERR("Invalid device entry: \"{}\"", entry);
  192. if(nextpos != std::string::npos) ++nextpos;
  193. strpos = nextpos;
  194. continue;
  195. }
  196. const auto name = std::string_view{*listopt}.substr(strpos, seppos-strpos);
  197. const auto pattern = std::string_view{*listopt}.substr(seppos+1,
  198. std::min(nextpos, listopt->size())-(seppos+1));
  199. /* Check if this custom pattern already exists in the list. */
  200. auto check_pattern = [pattern](const DeviceEntry &entry) -> bool
  201. { return entry.mPattern == pattern; };
  202. auto itemmatch = std::find_if(list.begin(), list.end(), check_pattern);
  203. if(itemmatch != list.end())
  204. {
  205. /* If so, replace the name with this custom one. */
  206. itemmatch->mName = name;
  207. TRACE("Customized device name: {} = {}", itemmatch->mName, itemmatch->mPattern);
  208. }
  209. else
  210. {
  211. /* Otherwise, add a new device entry. */
  212. const auto &entry = list.emplace_back(name, pattern);
  213. TRACE("Got custom device: {} = {}", entry.mName, entry.mPattern);
  214. }
  215. if(nextpos != std::string::npos) ++nextpos;
  216. strpos = nextpos;
  217. }
  218. }
  219. if(list.size() > 1)
  220. {
  221. /* Rename entries that have matching names, by appending '#2', '#3',
  222. * etc, as needed.
  223. */
  224. for(auto curitem = list.begin()+1;curitem != list.end();++curitem)
  225. {
  226. auto check_match = [curitem](const DeviceEntry &entry) -> bool
  227. { return entry.mName == curitem->mName; };
  228. if(std::find_if(list.begin(), curitem, check_match) != curitem)
  229. {
  230. std::string name{curitem->mName};
  231. size_t count{1};
  232. auto check_name = [&name](const DeviceEntry &entry) -> bool
  233. { return entry.mName == name; };
  234. do {
  235. name = curitem->mName;
  236. name += " #";
  237. name += std::to_string(++count);
  238. } while(std::find_if(list.begin(), curitem, check_name) != curitem);
  239. curitem->mName = std::move(name);
  240. }
  241. }
  242. }
  243. }
  244. struct JackPlayback final : public BackendBase {
  245. explicit JackPlayback(DeviceBase *device) noexcept : BackendBase{device} { }
  246. ~JackPlayback() override;
  247. int processRt(jack_nframes_t numframes) noexcept;
  248. static int processRtC(jack_nframes_t numframes, void *arg) noexcept
  249. { return static_cast<JackPlayback*>(arg)->processRt(numframes); }
  250. int process(jack_nframes_t numframes) noexcept;
  251. static int processC(jack_nframes_t numframes, void *arg) noexcept
  252. { return static_cast<JackPlayback*>(arg)->process(numframes); }
  253. int mixerProc();
  254. void open(std::string_view name) override;
  255. bool reset() override;
  256. void start() override;
  257. void stop() override;
  258. ClockLatency getClockLatency() override;
  259. std::string mPortPattern;
  260. jack_client_t *mClient{nullptr};
  261. std::array<jack_port_t*,MaxOutputChannels> mPort{};
  262. std::mutex mMutex;
  263. std::atomic<bool> mPlaying{false};
  264. bool mRTMixing{false};
  265. RingBufferPtr mRing;
  266. al::semaphore mSem;
  267. std::atomic<bool> mKillNow{true};
  268. std::thread mThread;
  269. };
  270. JackPlayback::~JackPlayback()
  271. {
  272. if(!mClient)
  273. return;
  274. auto unregister_port = [this](jack_port_t *port) -> void
  275. { if(port) jack_port_unregister(mClient, port); };
  276. std::for_each(mPort.begin(), mPort.end(), unregister_port);
  277. mPort.fill(nullptr);
  278. jack_client_close(mClient);
  279. mClient = nullptr;
  280. }
  281. int JackPlayback::processRt(jack_nframes_t numframes) noexcept
  282. {
  283. auto outptrs = std::array<void*,MaxOutputChannels>{};
  284. auto numchans = size_t{0};
  285. for(auto port : mPort)
  286. {
  287. if(!port || numchans == mDevice->RealOut.Buffer.size())
  288. break;
  289. outptrs[numchans++] = jack_port_get_buffer(port, numframes);
  290. }
  291. const auto dst = al::span{outptrs}.first(numchans);
  292. if(mPlaying.load(std::memory_order_acquire)) LIKELY
  293. mDevice->renderSamples(dst, static_cast<uint>(numframes));
  294. else
  295. {
  296. std::for_each(dst.begin(), dst.end(), [numframes](void *outbuf) -> void
  297. { std::fill_n(static_cast<float*>(outbuf), numframes, 0.0f); });
  298. }
  299. return 0;
  300. }
  301. int JackPlayback::process(jack_nframes_t numframes) noexcept
  302. {
  303. std::array<al::span<float>,MaxOutputChannels> out;
  304. size_t numchans{0};
  305. for(auto port : mPort)
  306. {
  307. if(!port) break;
  308. out[numchans++] = {static_cast<float*>(jack_port_get_buffer(port, numframes)), numframes};
  309. }
  310. size_t total{0};
  311. if(mPlaying.load(std::memory_order_acquire)) LIKELY
  312. {
  313. auto data = mRing->getReadVector();
  314. const auto update_size = size_t{mDevice->mUpdateSize};
  315. const auto outlen = size_t{numframes / update_size};
  316. const auto len1 = size_t{std::min(data[0].len/update_size, outlen)};
  317. const auto len2 = size_t{std::min(data[1].len/update_size, outlen-len1)};
  318. auto src = al::span{reinterpret_cast<float*>(data[0].buf), update_size*len1*numchans};
  319. for(size_t i{0};i < len1;++i)
  320. {
  321. for(size_t c{0};c < numchans;++c)
  322. {
  323. const auto iter = std::copy_n(src.begin(), update_size, out[c].begin());
  324. out[c] = {iter, out[c].end()};
  325. src = src.subspan(update_size);
  326. }
  327. total += update_size;
  328. }
  329. src = al::span{reinterpret_cast<float*>(data[1].buf), update_size*len2*numchans};
  330. for(size_t i{0};i < len2;++i)
  331. {
  332. for(size_t c{0};c < numchans;++c)
  333. {
  334. const auto iter = std::copy_n(src.begin(), update_size, out[c].begin());
  335. out[c] = {iter, out[c].end()};
  336. src = src.subspan(update_size);
  337. }
  338. total += update_size;
  339. }
  340. mRing->readAdvance(total);
  341. mSem.post();
  342. }
  343. if(numframes > total)
  344. {
  345. auto clear_buf = [](const al::span<float> outbuf) -> void
  346. { std::fill(outbuf.begin(), outbuf.end(), 0.0f); };
  347. std::for_each(out.begin(), out.begin()+numchans, clear_buf);
  348. }
  349. return 0;
  350. }
  351. int JackPlayback::mixerProc()
  352. {
  353. SetRTPriority();
  354. althrd_setname(GetMixerThreadName());
  355. const auto update_size = uint{mDevice->mUpdateSize};
  356. const auto num_channels = size_t{mDevice->channelsFromFmt()};
  357. auto outptrs = std::vector<void*>(num_channels);
  358. while(!mKillNow.load(std::memory_order_acquire)
  359. && mDevice->Connected.load(std::memory_order_acquire))
  360. {
  361. if(mRing->writeSpace() < update_size)
  362. {
  363. mSem.wait();
  364. continue;
  365. }
  366. auto data = mRing->getWriteVector();
  367. const auto len1 = size_t{data[0].len / update_size};
  368. const auto len2 = size_t{data[1].len / update_size};
  369. std::lock_guard<std::mutex> dlock{mMutex};
  370. auto buffer = al::span{reinterpret_cast<float*>(data[0].buf), data[0].len*num_channels};
  371. auto bufiter = buffer.begin();
  372. for(size_t i{0};i < len1;++i)
  373. {
  374. std::generate_n(outptrs.begin(), outptrs.size(), [&bufiter,update_size]
  375. {
  376. auto ret = al::to_address(bufiter);
  377. bufiter += ptrdiff_t(update_size);
  378. return ret;
  379. });
  380. mDevice->renderSamples(outptrs, update_size);
  381. }
  382. if(len2 > 0)
  383. {
  384. buffer = al::span{reinterpret_cast<float*>(data[1].buf), data[1].len*num_channels};
  385. bufiter = buffer.begin();
  386. for(size_t i{0};i < len2;++i)
  387. {
  388. std::generate_n(outptrs.begin(), outptrs.size(), [&bufiter,update_size]
  389. {
  390. auto ret = al::to_address(bufiter);
  391. bufiter += ptrdiff_t(update_size);
  392. return ret;
  393. });
  394. mDevice->renderSamples(outptrs, update_size);
  395. }
  396. }
  397. mRing->writeAdvance((len1+len2) * update_size);
  398. }
  399. return 0;
  400. }
  401. void JackPlayback::open(std::string_view name)
  402. {
  403. if(!mClient)
  404. {
  405. const PathNamePair &binname = GetProcBinary();
  406. const char *client_name{binname.fname.empty() ? "alsoft" : binname.fname.c_str()};
  407. jack_status_t status{};
  408. mClient = jack_client_open(client_name, ClientOptions, &status, nullptr);
  409. if(mClient == nullptr)
  410. throw al::backend_exception{al::backend_error::DeviceError,
  411. "Failed to open client connection: {:#02x}",
  412. as_unsigned(al::to_underlying(status))};
  413. if((status&JackServerStarted))
  414. TRACE("JACK server started");
  415. if((status&JackNameNotUnique))
  416. {
  417. client_name = jack_get_client_name(mClient);
  418. TRACE("Client name not unique, got '{}' instead", client_name);
  419. }
  420. }
  421. if(PlaybackList.empty())
  422. EnumerateDevices(mClient, PlaybackList);
  423. if(name.empty() && !PlaybackList.empty())
  424. {
  425. name = PlaybackList[0].mName;
  426. mPortPattern = PlaybackList[0].mPattern;
  427. }
  428. else
  429. {
  430. auto check_name = [name](const DeviceEntry &entry) -> bool
  431. { return entry.mName == name; };
  432. auto iter = std::find_if(PlaybackList.cbegin(), PlaybackList.cend(), check_name);
  433. if(iter == PlaybackList.cend())
  434. throw al::backend_exception{al::backend_error::NoDevice,
  435. "Device name \"{}\" not found", name};
  436. mPortPattern = iter->mPattern;
  437. }
  438. mDeviceName = name;
  439. }
  440. bool JackPlayback::reset()
  441. {
  442. auto unregister_port = [this](jack_port_t *port) -> void
  443. { if(port) jack_port_unregister(mClient, port); };
  444. std::for_each(mPort.begin(), mPort.end(), unregister_port);
  445. mPort.fill(nullptr);
  446. mRTMixing = GetConfigValueBool(mDevice->mDeviceName, "jack", "rt-mix", true);
  447. jack_set_process_callback(mClient,
  448. mRTMixing ? &JackPlayback::processRtC : &JackPlayback::processC, this);
  449. /* Ignore the requested buffer metrics and just keep one JACK-sized buffer
  450. * ready for when requested.
  451. */
  452. mDevice->mSampleRate = jack_get_sample_rate(mClient);
  453. mDevice->mUpdateSize = jack_get_buffer_size(mClient);
  454. if(mRTMixing)
  455. {
  456. /* Assume only two periods when directly mixing. Should try to query
  457. * the total port latency when connected.
  458. */
  459. mDevice->mBufferSize = mDevice->mUpdateSize * 2;
  460. }
  461. else
  462. {
  463. const auto devname = std::string_view{mDevice->mDeviceName};
  464. auto bufsize = ConfigValueUInt(devname, "jack", "buffer-size")
  465. .value_or(mDevice->mUpdateSize);
  466. bufsize = std::max(NextPowerOf2(bufsize), mDevice->mUpdateSize);
  467. mDevice->mBufferSize = bufsize + mDevice->mUpdateSize;
  468. }
  469. /* Force 32-bit float output. */
  470. mDevice->FmtType = DevFmtFloat;
  471. int port_num{0};
  472. auto ports = al::span{mPort}.first(mDevice->channelsFromFmt());
  473. auto bad_port = ports.begin();
  474. while(bad_port != ports.end())
  475. {
  476. std::string name{"channel_" + std::to_string(++port_num)};
  477. *bad_port = jack_port_register(mClient, name.c_str(), JACK_DEFAULT_AUDIO_TYPE,
  478. JackPortIsOutput | JackPortIsTerminal, 0);
  479. if(!*bad_port) break;
  480. ++bad_port;
  481. }
  482. if(bad_port != ports.end())
  483. {
  484. ERR("Failed to register enough JACK ports for {} output",
  485. DevFmtChannelsString(mDevice->FmtChans));
  486. if(bad_port == ports.begin()) return false;
  487. if(bad_port == ports.begin()+1)
  488. mDevice->FmtChans = DevFmtMono;
  489. else
  490. {
  491. const auto ports_end = ports.begin()+2;
  492. while(bad_port != ports_end)
  493. {
  494. jack_port_unregister(mClient, *(--bad_port));
  495. *bad_port = nullptr;
  496. }
  497. mDevice->FmtChans = DevFmtStereo;
  498. }
  499. }
  500. setDefaultChannelOrder();
  501. return true;
  502. }
  503. void JackPlayback::start()
  504. {
  505. if(jack_activate(mClient))
  506. throw al::backend_exception{al::backend_error::DeviceError, "Failed to activate client"};
  507. const auto devname = std::string_view{mDevice->mDeviceName};
  508. if(ConfigValueBool(devname, "jack", "connect-ports").value_or(true))
  509. {
  510. JackPortsPtr pnames{jack_get_ports(mClient, mPortPattern.c_str(), JACK_DEFAULT_AUDIO_TYPE,
  511. JackPortIsInput)};
  512. if(!pnames)
  513. {
  514. jack_deactivate(mClient);
  515. throw al::backend_exception{al::backend_error::DeviceError, "No playback ports found"};
  516. }
  517. for(size_t i{0};i < std::size(mPort) && mPort[i];++i)
  518. {
  519. if(!pnames[i])
  520. {
  521. ERR("No physical playback port for \"{}\"", jack_port_name(mPort[i]));
  522. break;
  523. }
  524. if(jack_connect(mClient, jack_port_name(mPort[i]), pnames[i]))
  525. ERR("Failed to connect output port \"{}\" to \"{}\"", jack_port_name(mPort[i]),
  526. pnames[i]);
  527. }
  528. }
  529. /* Reconfigure buffer metrics in case the server changed it since the reset
  530. * (it won't change again after jack_activate), then allocate the ring
  531. * buffer with the appropriate size.
  532. */
  533. mDevice->mSampleRate = jack_get_sample_rate(mClient);
  534. mDevice->mUpdateSize = jack_get_buffer_size(mClient);
  535. mDevice->mBufferSize = mDevice->mUpdateSize * 2;
  536. mRing = nullptr;
  537. if(mRTMixing)
  538. mPlaying.store(true, std::memory_order_release);
  539. else
  540. {
  541. uint bufsize{ConfigValueUInt(devname, "jack", "buffer-size")
  542. .value_or(mDevice->mUpdateSize)};
  543. bufsize = std::max(NextPowerOf2(bufsize), mDevice->mUpdateSize);
  544. mDevice->mBufferSize = bufsize + mDevice->mUpdateSize;
  545. mRing = RingBuffer::Create(bufsize, mDevice->frameSizeFromFmt(), true);
  546. try {
  547. mPlaying.store(true, std::memory_order_release);
  548. mKillNow.store(false, std::memory_order_release);
  549. mThread = std::thread{&JackPlayback::mixerProc, this};
  550. }
  551. catch(std::exception& e) {
  552. jack_deactivate(mClient);
  553. mPlaying.store(false, std::memory_order_release);
  554. throw al::backend_exception{al::backend_error::DeviceError,
  555. "Failed to start mixing thread: {}", e.what()};
  556. }
  557. }
  558. }
  559. void JackPlayback::stop()
  560. {
  561. if(mPlaying.load(std::memory_order_acquire))
  562. {
  563. mKillNow.store(true, std::memory_order_release);
  564. if(mThread.joinable())
  565. {
  566. mSem.post();
  567. mThread.join();
  568. }
  569. jack_deactivate(mClient);
  570. mPlaying.store(false, std::memory_order_release);
  571. }
  572. }
  573. ClockLatency JackPlayback::getClockLatency()
  574. {
  575. std::lock_guard<std::mutex> dlock{mMutex};
  576. ClockLatency ret{};
  577. ret.ClockTime = mDevice->getClockTime();
  578. ret.Latency = std::chrono::seconds{mRing ? mRing->readSpace() : mDevice->mUpdateSize};
  579. ret.Latency /= mDevice->mSampleRate;
  580. return ret;
  581. }
  582. void jack_msg_handler(const char *message)
  583. {
  584. WARN("{}", message);
  585. }
  586. } // namespace
  587. bool JackBackendFactory::init()
  588. {
  589. if(!jack_load())
  590. return false;
  591. if(!GetConfigValueBool({}, "jack", "spawn-server", false))
  592. ClientOptions = static_cast<jack_options_t>(ClientOptions | JackNoStartServer);
  593. const PathNamePair &binname = GetProcBinary();
  594. const char *client_name{binname.fname.empty() ? "alsoft" : binname.fname.c_str()};
  595. void (*old_error_cb)(const char*){&jack_error_callback ? jack_error_callback : nullptr};
  596. jack_set_error_function(jack_msg_handler);
  597. jack_status_t status{};
  598. jack_client_t *client{jack_client_open(client_name, ClientOptions, &status, nullptr)};
  599. jack_set_error_function(old_error_cb);
  600. if(!client)
  601. {
  602. WARN("jack_client_open() failed, {:#02x}", as_unsigned(al::to_underlying(status)));
  603. if((status&JackServerFailed) && !(ClientOptions&JackNoStartServer))
  604. ERR("Unable to connect to JACK server");
  605. return false;
  606. }
  607. jack_client_close(client);
  608. return true;
  609. }
  610. bool JackBackendFactory::querySupport(BackendType type)
  611. { return (type == BackendType::Playback); }
  612. auto JackBackendFactory::enumerate(BackendType type) -> std::vector<std::string>
  613. {
  614. std::vector<std::string> outnames;
  615. auto append_name = [&outnames](const DeviceEntry &entry) -> void
  616. { outnames.emplace_back(entry.mName); };
  617. const PathNamePair &binname = GetProcBinary();
  618. const char *client_name{binname.fname.empty() ? "alsoft" : binname.fname.c_str()};
  619. jack_status_t status{};
  620. switch(type)
  621. {
  622. case BackendType::Playback:
  623. if(jack_client_t *client{jack_client_open(client_name, ClientOptions, &status, nullptr)})
  624. {
  625. EnumerateDevices(client, PlaybackList);
  626. jack_client_close(client);
  627. }
  628. else
  629. WARN("jack_client_open() failed, {:#02x}", as_unsigned(al::to_underlying(status)));
  630. outnames.reserve(PlaybackList.size());
  631. std::for_each(PlaybackList.cbegin(), PlaybackList.cend(), append_name);
  632. break;
  633. case BackendType::Capture:
  634. break;
  635. }
  636. return outnames;
  637. }
  638. BackendPtr JackBackendFactory::createBackend(DeviceBase *device, BackendType type)
  639. {
  640. if(type == BackendType::Playback)
  641. return BackendPtr{new JackPlayback{device}};
  642. return nullptr;
  643. }
  644. BackendFactory &JackBackendFactory::getFactory()
  645. {
  646. static JackBackendFactory factory{};
  647. return factory;
  648. }