Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

693 lines
23KB

  1. /*
  2. * Carla JACK API for external applications
  3. * Copyright (C) 2016-2017 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the doc/GPL.txt file.
  16. */
  17. // need to include this first
  18. #include "libjack.hpp"
  19. using juce::File;
  20. using juce::MemoryBlock;
  21. using juce::String;
  22. using juce::Time;
  23. using juce::Thread;
  24. CARLA_BACKEND_START_NAMESPACE
  25. // --------------------------------------------------------------------------------------------------------------------
  26. class CarlaJackAppClient : public juce::Thread
  27. {
  28. public:
  29. JackServerState fServer;
  30. LinkedList<JackClientState*> fClients;
  31. CarlaJackAppClient()
  32. : Thread("CarlaJackAppClient"),
  33. fServer(),
  34. fIsValid(false),
  35. fIsOffline(false),
  36. fLastPingTime(-1)
  37. {
  38. carla_debug("CarlaJackAppClient::CarlaJackAppClient()");
  39. const char* const shmIds(std::getenv("CARLA_SHM_IDS"));
  40. CARLA_SAFE_ASSERT_RETURN(shmIds != nullptr && std::strlen(shmIds) == 6*4,);
  41. const char* const numPortsStr(std::getenv("CARLA_NUM_PORTS"));
  42. CARLA_SAFE_ASSERT_RETURN(numPortsStr != nullptr && std::strlen(numPortsStr) == 3*2,);
  43. for (int i=6; --i >= 0;) {
  44. CARLA_SAFE_ASSERT_RETURN(numPortsStr[i] >= '0' && numPortsStr[i] < '0'+64,);
  45. }
  46. std::memcpy(fBaseNameAudioPool, shmIds+6*0, 6);
  47. std::memcpy(fBaseNameRtClientControl, shmIds+6*1, 6);
  48. std::memcpy(fBaseNameNonRtClientControl, shmIds+6*2, 6);
  49. std::memcpy(fBaseNameNonRtServerControl, shmIds+6*3, 6);
  50. fBaseNameAudioPool[6] = '\0';
  51. fBaseNameRtClientControl[6] = '\0';
  52. fBaseNameNonRtClientControl[6] = '\0';
  53. fBaseNameNonRtServerControl[6] = '\0';
  54. fNumPorts.audioIns = numPortsStr[0] - '0';
  55. fNumPorts.audioOuts = numPortsStr[1] - '0';
  56. fNumPorts.cvIns = numPortsStr[2] - '0';
  57. fNumPorts.cvOuts = numPortsStr[3] - '0';
  58. fNumPorts.midiIns = numPortsStr[4] - '0';
  59. fNumPorts.midiOuts = numPortsStr[5] - '0';
  60. startThread(10);
  61. }
  62. ~CarlaJackAppClient() noexcept override
  63. {
  64. carla_debug("CarlaJackAppClient::~CarlaJackAppClient()");
  65. fLastPingTime = -1;
  66. stopThread(5000);
  67. clear();
  68. const CarlaMutexLocker cms(fRealtimeThreadMutex);
  69. for (LinkedList<JackClientState*>::Itenerator it = fClients.begin2(); it.valid(); it.next())
  70. {
  71. JackClientState* const jclient(it.getValue(nullptr));
  72. CARLA_SAFE_ASSERT_CONTINUE(jclient != nullptr);
  73. delete jclient;
  74. }
  75. fClients.clear();
  76. }
  77. JackClientState* addClient(const char* const name)
  78. {
  79. JackClientState* const jclient(new JackClientState(fServer, name));
  80. const CarlaMutexLocker cms(fRealtimeThreadMutex);
  81. fClients.append(jclient);
  82. return jclient;
  83. }
  84. bool removeClient(JackClientState* const jclient)
  85. {
  86. {
  87. const CarlaMutexLocker cms(fRealtimeThreadMutex);
  88. CARLA_SAFE_ASSERT_RETURN(fClients.removeOne(jclient), false);
  89. }
  90. delete jclient;
  91. return true;
  92. }
  93. void clear() noexcept;
  94. bool isValid() const noexcept;
  95. void handleNonRtData();
  96. // -------------------------------------------------------------------
  97. protected:
  98. void run() override;
  99. private:
  100. BridgeAudioPool fShmAudioPool;
  101. BridgeRtClientControl fShmRtClientControl;
  102. BridgeNonRtClientControl fShmNonRtClientControl;
  103. BridgeNonRtServerControl fShmNonRtServerControl;
  104. char fBaseNameAudioPool[6+1];
  105. char fBaseNameRtClientControl[6+1];
  106. char fBaseNameNonRtClientControl[6+1];
  107. char fBaseNameNonRtServerControl[6+1];
  108. bool fIsValid;
  109. bool fIsOffline;
  110. int64_t fLastPingTime;
  111. struct NumPorts {
  112. uint32_t audioIns;
  113. uint32_t audioOuts;
  114. uint32_t cvIns;
  115. uint32_t cvOuts;
  116. uint32_t midiIns;
  117. uint32_t midiOuts;
  118. NumPorts()
  119. : audioIns(0),
  120. audioOuts(0),
  121. cvIns(0),
  122. cvOuts(0),
  123. midiIns(0),
  124. midiOuts(0) {}
  125. } fNumPorts;
  126. CarlaMutex fRealtimeThreadMutex;
  127. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaJackAppClient)
  128. };
  129. // --------------------------------------------------------------------------------------------------------------------
  130. void CarlaJackAppClient::clear() noexcept
  131. {
  132. fShmAudioPool.clear();
  133. fShmRtClientControl.clear();
  134. fShmNonRtClientControl.clear();
  135. fShmNonRtServerControl.clear();
  136. }
  137. bool CarlaJackAppClient::isValid() const noexcept
  138. {
  139. return fIsValid;
  140. }
  141. void CarlaJackAppClient::handleNonRtData()
  142. {
  143. for (; fShmNonRtClientControl.isDataAvailableForReading();)
  144. {
  145. const PluginBridgeNonRtClientOpcode opcode(fShmNonRtClientControl.readOpcode());
  146. // #ifdef DEBUG
  147. if (opcode != kPluginBridgeNonRtClientPing)
  148. {
  149. static int shownNull = 0;
  150. if (opcode == kPluginBridgeNonRtClientNull)
  151. {
  152. if (shownNull > 5)
  153. continue;
  154. ++shownNull;
  155. }
  156. carla_stdout("CarlaJackAppClient::handleNonRtData() - got opcode: %s", PluginBridgeNonRtClientOpcode2str(opcode));
  157. }
  158. // #endif
  159. if (opcode != kPluginBridgeNonRtClientNull && opcode != kPluginBridgeNonRtClientPingOnOff && fLastPingTime > 0)
  160. fLastPingTime = Time::currentTimeMillis();
  161. switch (opcode)
  162. {
  163. case kPluginBridgeNonRtClientNull:
  164. break;
  165. case kPluginBridgeNonRtClientPing: {
  166. const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
  167. fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerPong);
  168. fShmNonRtServerControl.commitWrite();
  169. } break;
  170. case kPluginBridgeNonRtClientPingOnOff: {
  171. const uint32_t onOff(fShmNonRtClientControl.readBool());
  172. fLastPingTime = onOff ? Time::currentTimeMillis() : -1;
  173. } break;
  174. case kPluginBridgeNonRtClientActivate:
  175. case kPluginBridgeNonRtClientDeactivate:
  176. break;
  177. case kPluginBridgeNonRtClientSetBufferSize:
  178. fShmNonRtClientControl.readUInt();
  179. //bufferSizeChanged();
  180. break;
  181. case kPluginBridgeNonRtClientSetSampleRate:
  182. fShmNonRtClientControl.readDouble();
  183. //sampleRateChanged();
  184. break;
  185. case kPluginBridgeNonRtClientSetOffline:
  186. fIsOffline = true;
  187. //offlineModeChanged(true);
  188. break;
  189. case kPluginBridgeNonRtClientSetOnline:
  190. fIsOffline = false;
  191. //offlineModeChanged(false);
  192. break;
  193. case kPluginBridgeNonRtClientSetParameterValue:
  194. case kPluginBridgeNonRtClientSetParameterMidiChannel:
  195. case kPluginBridgeNonRtClientSetParameterMidiCC:
  196. case kPluginBridgeNonRtClientSetProgram:
  197. case kPluginBridgeNonRtClientSetMidiProgram:
  198. case kPluginBridgeNonRtClientSetCustomData:
  199. case kPluginBridgeNonRtClientSetChunkDataFile:
  200. break;
  201. case kPluginBridgeNonRtClientSetOption:
  202. fShmNonRtClientControl.readUInt();
  203. fShmNonRtClientControl.readBool();
  204. break;
  205. case kPluginBridgeNonRtClientSetCtrlChannel:
  206. fShmNonRtClientControl.readShort();
  207. break;
  208. case kPluginBridgeNonRtClientPrepareForSave:
  209. {
  210. const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
  211. fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerSaved);
  212. fShmNonRtServerControl.commitWrite();
  213. }
  214. break;
  215. case kPluginBridgeNonRtClientShowUI:
  216. case kPluginBridgeNonRtClientHideUI:
  217. case kPluginBridgeNonRtClientUiParameterChange:
  218. case kPluginBridgeNonRtClientUiProgramChange:
  219. case kPluginBridgeNonRtClientUiMidiProgramChange:
  220. case kPluginBridgeNonRtClientUiNoteOn:
  221. case kPluginBridgeNonRtClientUiNoteOff:
  222. break;
  223. case kPluginBridgeNonRtClientQuit:
  224. signalThreadShouldExit();
  225. break;
  226. }
  227. }
  228. }
  229. void CarlaJackAppClient::run()
  230. {
  231. carla_stderr("CarlaJackAppClient run START");
  232. if (! fShmAudioPool.attachClient(fBaseNameAudioPool))
  233. {
  234. carla_stderr("Failed to attach to audio pool shared memory");
  235. return;
  236. }
  237. if (! fShmRtClientControl.attachClient(fBaseNameRtClientControl))
  238. {
  239. clear();
  240. carla_stderr("Failed to attach to rt client control shared memory");
  241. return;
  242. }
  243. if (! fShmRtClientControl.mapData())
  244. {
  245. clear();
  246. carla_stderr("Failed to map rt client control shared memory");
  247. return;
  248. }
  249. if (! fShmNonRtClientControl.attachClient(fBaseNameNonRtClientControl))
  250. {
  251. clear();
  252. carla_stderr("Failed to attach to non-rt client control shared memory");
  253. return;
  254. }
  255. if (! fShmNonRtClientControl.mapData())
  256. {
  257. clear();
  258. carla_stderr("Failed to map non-rt control client shared memory");
  259. return;
  260. }
  261. if (! fShmNonRtServerControl.attachClient(fBaseNameNonRtServerControl))
  262. {
  263. clear();
  264. carla_stderr("Failed to attach to non-rt server control shared memory");
  265. return;
  266. }
  267. if (! fShmNonRtServerControl.mapData())
  268. {
  269. clear();
  270. carla_stderr("Failed to map non-rt control server shared memory");
  271. return;
  272. }
  273. PluginBridgeNonRtClientOpcode opcode;
  274. opcode = fShmNonRtClientControl.readOpcode();
  275. CARLA_SAFE_ASSERT_INT(opcode == kPluginBridgeNonRtClientNull, opcode);
  276. const uint32_t shmRtClientDataSize = fShmNonRtClientControl.readUInt();
  277. CARLA_SAFE_ASSERT_INT2(shmRtClientDataSize == sizeof(BridgeRtClientData), shmRtClientDataSize, sizeof(BridgeRtClientData));
  278. const uint32_t shmNonRtClientDataSize = fShmNonRtClientControl.readUInt();
  279. CARLA_SAFE_ASSERT_INT2(shmNonRtClientDataSize == sizeof(BridgeNonRtClientData), shmNonRtClientDataSize, sizeof(BridgeNonRtClientData));
  280. const uint32_t shmNonRtServerDataSize = fShmNonRtClientControl.readUInt();
  281. CARLA_SAFE_ASSERT_INT2(shmNonRtServerDataSize == sizeof(BridgeNonRtServerData), shmNonRtServerDataSize, sizeof(BridgeNonRtServerData));
  282. if (shmRtClientDataSize != sizeof(BridgeRtClientData) || shmNonRtClientDataSize != sizeof(BridgeNonRtClientData) || shmNonRtServerDataSize != sizeof(BridgeNonRtServerData))
  283. {
  284. carla_stderr2("CarlaJackAppClient: data size mismatch");
  285. return;
  286. }
  287. opcode = fShmNonRtClientControl.readOpcode();
  288. CARLA_SAFE_ASSERT_INT(opcode == kPluginBridgeNonRtClientSetBufferSize, opcode);
  289. fServer.bufferSize = fShmNonRtClientControl.readUInt();
  290. opcode = fShmNonRtClientControl.readOpcode();
  291. CARLA_SAFE_ASSERT_INT(opcode == kPluginBridgeNonRtClientSetSampleRate, opcode);
  292. fServer.sampleRate = fShmNonRtClientControl.readDouble();
  293. if (fServer.bufferSize == 0 || carla_isZero(fServer.sampleRate))
  294. {
  295. carla_stderr2("CarlaJackAppClient: invalid empty state");
  296. return;
  297. }
  298. // tell backend we're live
  299. {
  300. const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
  301. fLastPingTime = Time::currentTimeMillis();
  302. CARLA_SAFE_ASSERT(fLastPingTime > 0);
  303. // ready!
  304. fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerReady);
  305. fShmNonRtServerControl.commitWrite();
  306. fShmNonRtServerControl.waitIfDataIsReachingLimit();
  307. }
  308. fIsValid = true;
  309. fLastPingTime = Time::currentTimeMillis();
  310. carla_stdout("Carla Jack Client Ready!");
  311. #ifdef __SSE2_MATH__
  312. // Set FTZ and DAZ flags
  313. _mm_setcsr(_mm_getcsr() | 0x8040);
  314. #endif
  315. bool quitReceived = false;
  316. for (; ! quitReceived && ! threadShouldExit();)
  317. {
  318. handleNonRtData();
  319. const BridgeRtClientControl::WaitHelper helper(fShmRtClientControl);
  320. if (! helper.ok)
  321. continue;
  322. for (; fShmRtClientControl.isDataAvailableForReading();)
  323. {
  324. const PluginBridgeRtClientOpcode opcode(fShmRtClientControl.readOpcode());
  325. //#ifdef DEBUG
  326. if (opcode != kPluginBridgeRtClientProcess && opcode != kPluginBridgeRtClientMidiEvent)
  327. {
  328. carla_stdout("CarlaJackAppClientRtThread::run() - got opcode: %s", PluginBridgeRtClientOpcode2str(opcode));
  329. }
  330. //#endif
  331. switch (opcode)
  332. {
  333. case kPluginBridgeRtClientNull:
  334. break;
  335. case kPluginBridgeRtClientSetAudioPool: {
  336. if (fShmAudioPool.data != nullptr)
  337. {
  338. jackbridge_shm_unmap(fShmAudioPool.shm, fShmAudioPool.data);
  339. fShmAudioPool.data = nullptr;
  340. }
  341. const uint64_t poolSize(fShmRtClientControl.readULong());
  342. CARLA_SAFE_ASSERT_BREAK(poolSize > 0);
  343. fShmAudioPool.data = (float*)jackbridge_shm_map(fShmAudioPool.shm, static_cast<size_t>(poolSize));
  344. break;
  345. }
  346. case kPluginBridgeRtClientControlEventParameter:
  347. case kPluginBridgeRtClientControlEventMidiBank:
  348. case kPluginBridgeRtClientControlEventMidiProgram:
  349. case kPluginBridgeRtClientControlEventAllSoundOff:
  350. case kPluginBridgeRtClientControlEventAllNotesOff:
  351. case kPluginBridgeRtClientMidiEvent:
  352. break;
  353. case kPluginBridgeRtClientProcess: {
  354. CARLA_SAFE_ASSERT_BREAK(fShmAudioPool.data != nullptr);
  355. const CarlaMutexTryLocker cmtl(fRealtimeThreadMutex);
  356. if (cmtl.wasLocked())
  357. {
  358. float* fdata = fShmAudioPool.data;
  359. if (! fClients.isEmpty())
  360. {
  361. // tranport for all clients
  362. const BridgeTimeInfo& bridgeTimeInfo(fShmRtClientControl.data->timeInfo);
  363. fServer.playing = bridgeTimeInfo.playing;
  364. fServer.position.frame = bridgeTimeInfo.frame;
  365. fServer.position.usecs = bridgeTimeInfo.usecs;
  366. if (bridgeTimeInfo.valid & 0x1 /* kValidBBT */)
  367. {
  368. fServer.position.valid = JackPositionBBT;
  369. fServer.position.bar = bridgeTimeInfo.bar;
  370. fServer.position.beat = bridgeTimeInfo.beat;
  371. fServer.position.tick = bridgeTimeInfo.tick;
  372. fServer.position.beats_per_bar = bridgeTimeInfo.beatsPerBar;
  373. fServer.position.beat_type = bridgeTimeInfo.beatType;
  374. fServer.position.ticks_per_beat = bridgeTimeInfo.ticksPerBeat;
  375. fServer.position.beats_per_minute = bridgeTimeInfo.beatsPerMinute;
  376. fServer.position.bar_start_tick = bridgeTimeInfo.barStartTick;
  377. }
  378. else
  379. {
  380. fServer.position.valid = static_cast<jack_position_bits_t>(0);
  381. }
  382. for (LinkedList<JackClientState*>::Itenerator it = fClients.begin2(); it.valid(); it.next())
  383. {
  384. JackClientState* const jclient(it.getValue(nullptr));
  385. CARLA_SAFE_ASSERT_CONTINUE(jclient != nullptr);
  386. const CarlaMutexTryLocker cmtl2(jclient->mutex);
  387. if (cmtl2.wasNotLocked() || jclient->processCb == nullptr || ! jclient->activated)
  388. {
  389. if (fNumPorts.audioIns > 0)
  390. fdata += fServer.bufferSize*fNumPorts.audioIns;
  391. if (fNumPorts.audioOuts > 0)
  392. carla_zeroFloats(fdata, fServer.bufferSize*fNumPorts.audioOuts);
  393. if (jclient->deactivated)
  394. {
  395. fShmRtClientControl.data->procFlags = 1;
  396. }
  397. }
  398. else
  399. {
  400. uint32_t i;
  401. i = 0;
  402. for (LinkedList<JackPortState*>::Itenerator it = jclient->audioIns.begin2(); it.valid(); it.next())
  403. {
  404. CARLA_SAFE_ASSERT_BREAK(i++ < fNumPorts.audioIns);
  405. if (JackPortState* const jport = it.getValue(nullptr))
  406. jport->buffer = fdata;
  407. fdata += fServer.bufferSize;
  408. }
  409. for (; i++ < fNumPorts.audioIns;)
  410. fdata += fServer.bufferSize;
  411. i = 0;
  412. for (LinkedList<JackPortState*>::Itenerator it = jclient->audioOuts.begin2(); it.valid(); it.next())
  413. {
  414. CARLA_SAFE_ASSERT_BREAK(i++ < fNumPorts.audioOuts);
  415. if (JackPortState* const jport = it.getValue(nullptr))
  416. jport->buffer = fdata;
  417. fdata += fServer.bufferSize;
  418. }
  419. for (; i++ < fNumPorts.audioOuts;)
  420. {
  421. carla_zeroFloats(fdata, fServer.bufferSize);
  422. fdata += fServer.bufferSize;
  423. }
  424. jclient->processCb(fServer.bufferSize, jclient->processCbPtr);
  425. }
  426. }
  427. }
  428. else
  429. {
  430. if (fNumPorts.audioIns > 0)
  431. fdata += fServer.bufferSize*fNumPorts.audioIns;
  432. if (fNumPorts.audioOuts > 0)
  433. carla_zeroFloats(fdata, fServer.bufferSize*fNumPorts.audioOuts);
  434. }
  435. }
  436. else
  437. {
  438. carla_stderr2("CarlaJackAppClient: fRealtimeThreadMutex tryLock failed");
  439. }
  440. carla_zeroBytes(fShmRtClientControl.data->midiOut, kBridgeRtClientDataMidiOutSize);
  441. break;
  442. }
  443. case kPluginBridgeRtClientQuit:
  444. quitReceived = true;
  445. signalThreadShouldExit();
  446. break;
  447. }
  448. }
  449. }
  450. //callback(ENGINE_CALLBACK_ENGINE_STOPPED, 0, 0, 0, 0.0f, nullptr);
  451. if (quitReceived)
  452. {
  453. carla_stderr("CarlaJackAppClient run END - quit by carla");
  454. ::kill(::getpid(), SIGTERM);
  455. }
  456. else
  457. {
  458. const char* const message("Plugin bridge error, process thread has stopped");
  459. const std::size_t messageSize(std::strlen(message));
  460. bool activated;
  461. {
  462. const CarlaMutexLocker cms(fRealtimeThreadMutex);
  463. if (fClients.isEmpty())
  464. {
  465. activated = false;
  466. }
  467. else if (JackClientState* const jclient = fClients.getLast(nullptr))
  468. {
  469. const CarlaMutexLocker cms(jclient->mutex);
  470. activated = jclient->activated;
  471. }
  472. else
  473. {
  474. activated = true;
  475. }
  476. }
  477. if (activated)
  478. {
  479. carla_stderr("CarlaJackAppClient run END - quit error");
  480. const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
  481. fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerError);
  482. fShmNonRtServerControl.writeUInt(messageSize);
  483. fShmNonRtServerControl.writeCustomData(message, messageSize);
  484. fShmNonRtServerControl.commitWrite();
  485. }
  486. else
  487. {
  488. carla_stderr("CarlaJackAppClient run END - quit itself");
  489. const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
  490. fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerUiClosed);
  491. fShmNonRtServerControl.commitWrite();
  492. }
  493. /*
  494. if (activated)
  495. {
  496. // TODO infoShutdown
  497. if (fClient.shutdownCb != nullptr)
  498. fClient.shutdownCb(fClient.shutdownCbPtr);
  499. }
  500. */
  501. }
  502. }
  503. // --------------------------------------------------------------------------------------------------------------------
  504. static CarlaJackAppClient gClient;
  505. CARLA_EXPORT
  506. jack_client_t* jack_client_open(const char* client_name, jack_options_t options, jack_status_t* status, ...)
  507. {
  508. if (status != nullptr)
  509. *status = JackNameNotUnique;
  510. if (options & JackUseExactName)
  511. return nullptr;
  512. if (JackClientState* const client = gClient.addClient(client_name))
  513. return (jack_client_t*)client;
  514. if (status != nullptr)
  515. *status = JackServerError;
  516. return nullptr;
  517. }
  518. CARLA_EXPORT
  519. jack_client_t* jack_client_new(const char* client_name)
  520. {
  521. return jack_client_open(client_name, JackNullOption, nullptr);
  522. }
  523. CARLA_EXPORT
  524. int jack_client_close(jack_client_t* client)
  525. {
  526. JackClientState* const jclient = (JackClientState*)client;
  527. CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, 1);
  528. gClient.removeClient(jclient);
  529. return 0;
  530. }
  531. CARLA_EXPORT
  532. pthread_t jack_client_thread_id(jack_client_t* client)
  533. {
  534. JackClientState* const jclient = (JackClientState*)client;
  535. CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, 0);
  536. CarlaJackAppClient* const jackAppPtr = jclient->server.jackAppPtr;
  537. CARLA_SAFE_ASSERT_RETURN(jackAppPtr != nullptr, 0);
  538. return (pthread_t)jackAppPtr->getThreadId();
  539. }
  540. CARLA_BACKEND_END_NAMESPACE
  541. // --------------------------------------------------------------------------------------------------------------------
  542. #include "jackbridge/JackBridge2.cpp"
  543. #include "CarlaBridgeUtils.cpp"
  544. // --------------------------------------------------------------------------------------------------------------------
  545. // TODO
  546. CARLA_BACKEND_USE_NAMESPACE
  547. CARLA_EXPORT
  548. int jack_client_real_time_priority(jack_client_t*)
  549. {
  550. carla_stdout("CarlaJackAppClient :: %s", __FUNCTION__);
  551. return -1;
  552. }
  553. // --------------------------------------------------------------------------------------------------------------------