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.

1362 lines
47KB

  1. /*
  2. * Carla JACK API for external applications
  3. * Copyright (C) 2016-2019 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. #include "libjack.hpp"
  18. #include "CarlaThread.hpp"
  19. #include <signal.h>
  20. #include <sys/prctl.h>
  21. #include <sys/time.h>
  22. // ---------------------------------------------------------------------------------------------------------------------
  23. CARLA_EXPORT
  24. int jack_carla_interposed_action(uint, uint, void*)
  25. {
  26. static bool printWarning = true;
  27. if (printWarning)
  28. {
  29. printWarning = false;
  30. carla_stderr2("Non-exported jack_carla_interposed_action called, this should not happen!!");
  31. carla_stderr("Printing some info:");
  32. carla_stderr("\tLD_LIBRARY_PATH: '%s'", std::getenv("LD_LIBRARY_PATH"));
  33. carla_stderr("\tLD_PRELOAD: '%s'", std::getenv("LD_PRELOAD"));
  34. std::fflush(stderr);
  35. }
  36. // ::kill(::getpid(), SIGKILL);
  37. return 1337;
  38. }
  39. // ---------------------------------------------------------------------------------------------------------------------
  40. CARLA_BACKEND_START_NAMESPACE
  41. // ---------------------------------------------------------------------------------------------------------------------
  42. static int64_t getCurrentTimeMilliseconds() noexcept
  43. {
  44. struct timeval tv;
  45. gettimeofday (&tv, nullptr);
  46. return ((int64_t) tv.tv_sec) * 1000 + tv.tv_usec / 1000;
  47. }
  48. static int carla_interposed_callback(int, void*);
  49. // ---------------------------------------------------------------------------------------------------------------------
  50. class CarlaJackRealtimeThread : public CarlaThread
  51. {
  52. public:
  53. struct Callback {
  54. Callback() {}
  55. virtual ~Callback() {};
  56. virtual void runRealtimeThread() = 0;
  57. };
  58. CarlaJackRealtimeThread(Callback* const callback)
  59. : CarlaThread("CarlaJackRealtimeThread"),
  60. fCallback(callback) {}
  61. protected:
  62. void run() override
  63. {
  64. fCallback->runRealtimeThread();
  65. }
  66. private:
  67. Callback* const fCallback;
  68. CARLA_DECLARE_NON_COPY_CLASS(CarlaJackRealtimeThread)
  69. };
  70. // --------------------------------------------------------------------------------------------------------------------
  71. class CarlaJackNonRealtimeThread : public CarlaThread
  72. {
  73. public:
  74. struct Callback {
  75. Callback() {}
  76. virtual ~Callback() {};
  77. virtual void runNonRealtimeThread() = 0;
  78. };
  79. CarlaJackNonRealtimeThread(Callback* const callback)
  80. : CarlaThread("CarlaJackNonRealtimeThread"),
  81. fCallback(callback) {}
  82. protected:
  83. void run() override
  84. {
  85. fCallback->runNonRealtimeThread();
  86. }
  87. private:
  88. Callback* const fCallback;
  89. CARLA_DECLARE_NON_COPY_CLASS(CarlaJackNonRealtimeThread)
  90. };
  91. // ---------------------------------------------------------------------------------------------------------------------
  92. class CarlaJackAppClient : public CarlaJackRealtimeThread::Callback,
  93. public CarlaJackNonRealtimeThread::Callback
  94. {
  95. public:
  96. JackServerState fServer;
  97. LinkedList<JackClientState*> fClients;
  98. LinkedList<JackClientState*> fNewClients;
  99. CarlaJackAppClient()
  100. : fServer(this),
  101. fClients(),
  102. fNewClients(),
  103. fShmAudioPool(),
  104. fShmRtClientControl(),
  105. fShmNonRtClientControl(),
  106. fShmNonRtServerControl(),
  107. fAudioPoolCopy(nullptr),
  108. fAudioTmpBuf(nullptr),
  109. fDummyMidiInBuffer(true),
  110. fDummyMidiOutBuffer(false),
  111. fMidiInBuffers(nullptr),
  112. fMidiOutBuffers(nullptr),
  113. fIsOffline(false),
  114. fIsReady(false),
  115. fLastPingTime(-1),
  116. fSessionManager(0),
  117. fSetupHints(0),
  118. fRealtimeThread(this),
  119. fNonRealtimeThread(this),
  120. fRealtimeThreadMutex()
  121. #ifdef DEBUG
  122. ,leakDetector_CarlaJackAppClient()
  123. #endif
  124. {
  125. carla_debug("CarlaJackAppClient::CarlaJackAppClient()");
  126. const char* const shmIds(std::getenv("CARLA_SHM_IDS"));
  127. CARLA_SAFE_ASSERT_INT2_RETURN(shmIds != nullptr && std::strlen(shmIds) == 6*4, std::strlen(shmIds), 6*4,);
  128. const char* const libjackSetup(std::getenv("CARLA_LIBJACK_SETUP"));
  129. CARLA_SAFE_ASSERT_RETURN(libjackSetup != nullptr && std::strlen(libjackSetup) >= 6,);
  130. // make sure we don't get loaded again
  131. carla_unsetenv("CARLA_SHM_IDS");
  132. // kill ourselves if main carla dies
  133. carla_terminateProcessOnParentExit(true);
  134. for (int i=4; --i >= 0;) {
  135. CARLA_SAFE_ASSERT_RETURN(libjackSetup[i] >= '0' && libjackSetup[i] <= '0'+64,);
  136. }
  137. CARLA_SAFE_ASSERT_RETURN(libjackSetup[4] >= '0' && libjackSetup[4] <= '0' + LIBJACK_SESSION_MANAGER_NSM,);
  138. CARLA_SAFE_ASSERT_RETURN(libjackSetup[5] >= '0' && libjackSetup[5] < '0'+0x4f,);
  139. std::memcpy(fBaseNameAudioPool, shmIds+6*0, 6);
  140. std::memcpy(fBaseNameRtClientControl, shmIds+6*1, 6);
  141. std::memcpy(fBaseNameNonRtClientControl, shmIds+6*2, 6);
  142. std::memcpy(fBaseNameNonRtServerControl, shmIds+6*3, 6);
  143. fBaseNameAudioPool[6] = '\0';
  144. fBaseNameRtClientControl[6] = '\0';
  145. fBaseNameNonRtClientControl[6] = '\0';
  146. fBaseNameNonRtServerControl[6] = '\0';
  147. fServer.numAudioIns = static_cast<uint8_t>(libjackSetup[0] - '0');
  148. fServer.numAudioOuts = static_cast<uint8_t>(libjackSetup[1] - '0');
  149. fServer.numMidiIns = static_cast<uint8_t>(libjackSetup[2] - '0');
  150. fServer.numMidiOuts = static_cast<uint8_t>(libjackSetup[3] - '0');
  151. fSessionManager = static_cast<uint>(libjackSetup[4] - '0');
  152. fSetupHints = static_cast<uint>(libjackSetup[5] - '0');
  153. jack_carla_interposed_action(LIBJACK_INTERPOSER_ACTION_SET_HINTS_AND_CALLBACK,
  154. fSetupHints,
  155. (void*)carla_interposed_callback);
  156. jack_carla_interposed_action(LIBJACK_INTERPOSER_ACTION_SET_SESSION_MANAGER,
  157. fSessionManager,
  158. nullptr);
  159. fNonRealtimeThread.startThread(false);
  160. }
  161. ~CarlaJackAppClient() noexcept override
  162. {
  163. carla_debug("CarlaJackAppClient::~CarlaJackAppClient()");
  164. fLastPingTime = -1;
  165. fNonRealtimeThread.stopThread(5000);
  166. const CarlaMutexLocker cms(fRealtimeThreadMutex);
  167. for (LinkedList<JackClientState*>::Itenerator it = fClients.begin2(); it.valid(); it.next())
  168. {
  169. JackClientState* const jclient(it.getValue(nullptr));
  170. CARLA_SAFE_ASSERT_CONTINUE(jclient != nullptr);
  171. delete jclient;
  172. }
  173. fClients.clear();
  174. }
  175. JackClientState* createClient(const char* const name)
  176. {
  177. while (fNonRealtimeThread.isThreadRunning() && ! fIsReady)
  178. carla_sleep(1);
  179. return new JackClientState(fServer, name);
  180. }
  181. void destroyClient(JackClientState* const jclient)
  182. {
  183. {
  184. const CarlaMutexLocker cms(fRealtimeThreadMutex);
  185. fClients.removeOne(jclient);
  186. }
  187. delete jclient;
  188. }
  189. bool activateClient(JackClientState* const jclient)
  190. {
  191. const CarlaMutexLocker cms(fRealtimeThreadMutex);
  192. if (! fClients.append(jclient))
  193. return false;
  194. if (! fNewClients.append(jclient))
  195. {
  196. fClients.removeOne(jclient);
  197. return false;
  198. }
  199. jclient->activated = true;
  200. jclient->deactivated = false;
  201. return true;
  202. }
  203. bool deactivateClient(JackClientState* const jclient)
  204. {
  205. const CarlaMutexLocker cms(fRealtimeThreadMutex);
  206. if (! fClients.removeOne(jclient))
  207. return false;
  208. jclient->activated = false;
  209. jclient->deactivated = true;
  210. return true;
  211. }
  212. pthread_t getRealtimeThreadId() const noexcept
  213. {
  214. return (pthread_t)fRealtimeThread.getThreadId();
  215. }
  216. int handleInterposerCallback(const int cb_action, void* const ptr)
  217. {
  218. carla_debug("handleInterposerCallback(%o, %p)", cb_action, ptr);
  219. switch (cb_action)
  220. {
  221. case LIBJACK_INTERPOSER_CALLBACK_UI_HIDE: {
  222. const CarlaMutexLocker cml(fShmNonRtServerControl.mutex);
  223. fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerUiClosed);
  224. fShmNonRtServerControl.commitWrite();
  225. break;
  226. }
  227. }
  228. return 0;
  229. // maybe unused
  230. (void)ptr;
  231. }
  232. // -------------------------------------------------------------------
  233. protected:
  234. void runRealtimeThread() override;
  235. void runNonRealtimeThread() override;
  236. private:
  237. bool initSharedMemmory();
  238. void clearSharedMemory() noexcept;
  239. bool handleRtData();
  240. bool handleNonRtData();
  241. BridgeAudioPool fShmAudioPool;
  242. BridgeRtClientControl fShmRtClientControl;
  243. BridgeNonRtClientControl fShmNonRtClientControl;
  244. BridgeNonRtServerControl fShmNonRtServerControl;
  245. float* fAudioPoolCopy;
  246. float* fAudioTmpBuf;
  247. JackMidiPortBufferDummy fDummyMidiInBuffer;
  248. JackMidiPortBufferDummy fDummyMidiOutBuffer;
  249. JackMidiPortBufferOnStack* fMidiInBuffers;
  250. JackMidiPortBufferOnStack* fMidiOutBuffers;
  251. char fBaseNameAudioPool[6+1];
  252. char fBaseNameRtClientControl[6+1];
  253. char fBaseNameNonRtClientControl[6+1];
  254. char fBaseNameNonRtServerControl[6+1];
  255. bool fIsOffline;
  256. volatile bool fIsReady;
  257. int64_t fLastPingTime;
  258. uint fSessionManager;
  259. uint fSetupHints;
  260. CarlaJackRealtimeThread fRealtimeThread;
  261. CarlaJackNonRealtimeThread fNonRealtimeThread;
  262. CarlaMutex fRealtimeThreadMutex;
  263. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaJackAppClient)
  264. };
  265. // ---------------------------------------------------------------------------------------------------------------------
  266. bool CarlaJackAppClient::initSharedMemmory()
  267. {
  268. if (! fShmAudioPool.attachClient(fBaseNameAudioPool))
  269. {
  270. carla_stderr("Failed to attach to audio pool shared memory");
  271. return false;
  272. }
  273. if (! fShmRtClientControl.attachClient(fBaseNameRtClientControl))
  274. {
  275. clearSharedMemory();
  276. carla_stderr("Failed to attach to rt client control shared memory");
  277. return false;
  278. }
  279. if (! fShmRtClientControl.mapData())
  280. {
  281. clearSharedMemory();
  282. carla_stderr("Failed to map rt client control shared memory");
  283. return false;
  284. }
  285. if (! fShmNonRtClientControl.attachClient(fBaseNameNonRtClientControl))
  286. {
  287. clearSharedMemory();
  288. carla_stderr("Failed to attach to non-rt client control shared memory");
  289. return false;
  290. }
  291. if (! fShmNonRtClientControl.mapData())
  292. {
  293. clearSharedMemory();
  294. carla_stderr("Failed to map non-rt control client shared memory");
  295. return false;
  296. }
  297. if (! fShmNonRtServerControl.attachClient(fBaseNameNonRtServerControl))
  298. {
  299. clearSharedMemory();
  300. carla_stderr("Failed to attach to non-rt server control shared memory");
  301. return false;
  302. }
  303. if (! fShmNonRtServerControl.mapData())
  304. {
  305. clearSharedMemory();
  306. carla_stderr("Failed to map non-rt control server shared memory");
  307. return false;
  308. }
  309. PluginBridgeNonRtClientOpcode opcode;
  310. opcode = fShmNonRtClientControl.readOpcode();
  311. CARLA_SAFE_ASSERT_RETURN(opcode == kPluginBridgeNonRtClientVersion, false);
  312. const uint32_t apiVersion = fShmNonRtClientControl.readUInt();
  313. CARLA_SAFE_ASSERT_RETURN(apiVersion == CARLA_PLUGIN_BRIDGE_API_VERSION, false);
  314. const uint32_t shmRtClientDataSize = fShmNonRtClientControl.readUInt();
  315. CARLA_SAFE_ASSERT_INT2(shmRtClientDataSize == sizeof(BridgeRtClientData), shmRtClientDataSize, sizeof(BridgeRtClientData));
  316. const uint32_t shmNonRtClientDataSize = fShmNonRtClientControl.readUInt();
  317. CARLA_SAFE_ASSERT_INT2(shmNonRtClientDataSize == sizeof(BridgeNonRtClientData), shmNonRtClientDataSize, sizeof(BridgeNonRtClientData));
  318. const uint32_t shmNonRtServerDataSize = fShmNonRtClientControl.readUInt();
  319. CARLA_SAFE_ASSERT_INT2(shmNonRtServerDataSize == sizeof(BridgeNonRtServerData), shmNonRtServerDataSize, sizeof(BridgeNonRtServerData));
  320. if (shmRtClientDataSize != sizeof(BridgeRtClientData) ||
  321. shmNonRtClientDataSize != sizeof(BridgeNonRtClientData) ||
  322. shmNonRtServerDataSize != sizeof(BridgeNonRtServerData))
  323. {
  324. carla_stderr2("CarlaJackAppClient: data size mismatch");
  325. return false;
  326. }
  327. opcode = fShmNonRtClientControl.readOpcode();
  328. CARLA_SAFE_ASSERT_RETURN(opcode == kPluginBridgeNonRtClientInitialSetup, false);
  329. fServer.bufferSize = fShmNonRtClientControl.readUInt();
  330. fServer.sampleRate = fShmNonRtClientControl.readDouble();
  331. if (fServer.bufferSize == 0 || carla_isZero(fServer.sampleRate))
  332. {
  333. carla_stderr2("CarlaJackAppClient: invalid empty state");
  334. return false;
  335. }
  336. fAudioTmpBuf = new float[fServer.bufferSize];
  337. carla_zeroFloats(fAudioTmpBuf, fServer.bufferSize);
  338. fLastPingTime = getCurrentTimeMilliseconds();
  339. CARLA_SAFE_ASSERT(fLastPingTime > 0);
  340. {
  341. // tell backend we're live
  342. const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
  343. // ready!
  344. fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerReady);
  345. fShmNonRtServerControl.commitWrite();
  346. fShmNonRtServerControl.waitIfDataIsReachingLimit();
  347. }
  348. fIsReady = true;
  349. return true;
  350. }
  351. void CarlaJackAppClient::clearSharedMemory() noexcept
  352. {
  353. const CarlaMutexLocker cml(fRealtimeThreadMutex);
  354. if (fAudioPoolCopy != nullptr)
  355. {
  356. delete[] fAudioPoolCopy;
  357. fAudioPoolCopy = nullptr;
  358. }
  359. if (fAudioTmpBuf != nullptr)
  360. {
  361. delete[] fAudioTmpBuf;
  362. fAudioTmpBuf = nullptr;
  363. }
  364. if (fMidiInBuffers != nullptr)
  365. {
  366. delete[] fMidiInBuffers;
  367. fMidiInBuffers = nullptr;
  368. }
  369. if (fMidiOutBuffers != nullptr)
  370. {
  371. delete[] fMidiOutBuffers;
  372. fMidiOutBuffers = nullptr;
  373. }
  374. fShmAudioPool.clear();
  375. fShmRtClientControl.clear();
  376. fShmNonRtClientControl.clear();
  377. fShmNonRtServerControl.clear();
  378. }
  379. bool CarlaJackAppClient::handleRtData()
  380. {
  381. if (fNewClients.count() != 0)
  382. {
  383. for (LinkedList<JackClientState*>::Itenerator it = fNewClients.begin2(); it.valid(); it.next())
  384. {
  385. JackClientState* const jclient(it.getValue(nullptr));
  386. CARLA_SAFE_ASSERT_CONTINUE(jclient != nullptr);
  387. if (jclient->threadInitCb != nullptr)
  388. jclient->threadInitCb(jclient->threadInitCbPtr);
  389. }
  390. fNewClients.clear();
  391. }
  392. const BridgeRtClientControl::WaitHelper helper(fShmRtClientControl);
  393. if (! helper.ok)
  394. return false;
  395. bool ret = false;
  396. for (; fShmRtClientControl.isDataAvailableForReading();)
  397. {
  398. const PluginBridgeRtClientOpcode opcode(fShmRtClientControl.readOpcode());
  399. #ifdef DEBUG
  400. if (opcode != kPluginBridgeRtClientProcess && opcode != kPluginBridgeRtClientMidiEvent) {
  401. carla_debug("CarlaJackAppClientRtThread::run() - got opcode: %s", PluginBridgeRtClientOpcode2str(opcode));
  402. }
  403. #endif
  404. switch (opcode)
  405. {
  406. case kPluginBridgeRtClientNull:
  407. break;
  408. case kPluginBridgeRtClientSetAudioPool: {
  409. const CarlaMutexLocker cml(fRealtimeThreadMutex);
  410. if (fShmAudioPool.data != nullptr)
  411. {
  412. jackbridge_shm_unmap(fShmAudioPool.shm, fShmAudioPool.data);
  413. fShmAudioPool.data = nullptr;
  414. }
  415. if (fAudioPoolCopy != nullptr)
  416. {
  417. delete[] fAudioPoolCopy;
  418. fAudioPoolCopy = nullptr;
  419. }
  420. const uint64_t poolSize(fShmRtClientControl.readULong());
  421. CARLA_SAFE_ASSERT_BREAK(poolSize > 0);
  422. fShmAudioPool.data = (float*)jackbridge_shm_map(fShmAudioPool.shm, static_cast<size_t>(poolSize));
  423. fAudioPoolCopy = new float[poolSize];
  424. break;
  425. }
  426. case kPluginBridgeRtClientSetBufferSize:
  427. if (const uint32_t newBufferSize = fShmRtClientControl.readUInt())
  428. {
  429. if (fServer.bufferSize != newBufferSize)
  430. {
  431. const CarlaMutexLocker cml(fRealtimeThreadMutex);
  432. fServer.bufferSize = newBufferSize;
  433. for (LinkedList<JackClientState*>::Itenerator it = fClients.begin2(); it.valid(); it.next())
  434. {
  435. JackClientState* const jclient(it.getValue(nullptr));
  436. CARLA_SAFE_ASSERT_CONTINUE(jclient != nullptr);
  437. if (jclient->bufferSizeCb != nullptr)
  438. jclient->bufferSizeCb(fServer.bufferSize, jclient->bufferSizeCbPtr);
  439. }
  440. delete[] fAudioTmpBuf;
  441. fAudioTmpBuf = new float[fServer.bufferSize];
  442. carla_zeroFloats(fAudioTmpBuf, fServer.bufferSize);
  443. }
  444. }
  445. break;
  446. case kPluginBridgeRtClientSetSampleRate: {
  447. const double newSampleRate = fShmRtClientControl.readDouble();
  448. if (carla_isNotZero(newSampleRate) && carla_isNotEqual(fServer.sampleRate, newSampleRate))
  449. {
  450. const CarlaMutexLocker cml(fRealtimeThreadMutex);
  451. fServer.sampleRate = newSampleRate;
  452. for (LinkedList<JackClientState*>::Itenerator it = fClients.begin2(); it.valid(); it.next())
  453. {
  454. JackClientState* const jclient(it.getValue(nullptr));
  455. CARLA_SAFE_ASSERT_CONTINUE(jclient != nullptr);
  456. if (jclient->sampleRateCb != nullptr)
  457. jclient->sampleRateCb(static_cast<uint32_t>(fServer.sampleRate), jclient->sampleRateCbPtr);
  458. }
  459. }
  460. } break;
  461. case kPluginBridgeRtClientSetOnline: {
  462. const bool offline = fShmRtClientControl.readBool();
  463. if (fIsOffline != offline)
  464. {
  465. const CarlaMutexLocker cml(fRealtimeThreadMutex);
  466. fIsOffline = offline;
  467. for (LinkedList<JackClientState*>::Itenerator it = fClients.begin2(); it.valid(); it.next())
  468. {
  469. JackClientState* const jclient(it.getValue(nullptr));
  470. CARLA_SAFE_ASSERT_CONTINUE(jclient != nullptr);
  471. if (jclient->freewheelCb != nullptr)
  472. jclient->freewheelCb(offline ? 1 : 0, jclient->freewheelCbPtr);
  473. }
  474. }
  475. } break;
  476. case kPluginBridgeRtClientControlEventParameter:
  477. case kPluginBridgeRtClientControlEventMidiBank:
  478. case kPluginBridgeRtClientControlEventMidiProgram:
  479. case kPluginBridgeRtClientControlEventAllSoundOff:
  480. case kPluginBridgeRtClientControlEventAllNotesOff:
  481. break;
  482. case kPluginBridgeRtClientMidiEvent: {
  483. const uint32_t time(fShmRtClientControl.readUInt());
  484. const uint8_t port(fShmRtClientControl.readByte());
  485. const uint8_t size(fShmRtClientControl.readByte());
  486. CARLA_SAFE_ASSERT_BREAK(size > 0);
  487. if (port >= fServer.numMidiIns || size > JackMidiPortBufferBase::kMaxEventSize || ! fRealtimeThreadMutex.tryLock())
  488. {
  489. for (uint8_t i=0; i<size; ++i)
  490. fShmRtClientControl.readByte();
  491. break;
  492. }
  493. JackMidiPortBufferOnStack& midiPortBuf(fMidiInBuffers[port]);
  494. if (midiPortBuf.count < JackMidiPortBufferBase::kMaxEventCount &&
  495. midiPortBuf.bufferPoolPos + size < JackMidiPortBufferBase::kBufferPoolSize)
  496. {
  497. jack_midi_event_t& ev(midiPortBuf.events[midiPortBuf.count++]);
  498. ev.time = time;
  499. ev.size = size;
  500. ev.buffer = midiPortBuf.bufferPool + midiPortBuf.bufferPoolPos;
  501. midiPortBuf.bufferPoolPos += size;
  502. for (uint8_t i=0; i<size; ++i)
  503. ev.buffer[i] = fShmRtClientControl.readByte();
  504. }
  505. fRealtimeThreadMutex.unlock(true);
  506. break;
  507. }
  508. case kPluginBridgeRtClientProcess: {
  509. const uint32_t frames(fShmRtClientControl.readUInt());
  510. CARLA_SAFE_ASSERT_UINT2_BREAK(frames == fServer.bufferSize, frames, fServer.bufferSize);
  511. // TODO tell client of xrun in case buffersize does not match
  512. const CarlaMutexTryLocker cmtl(fRealtimeThreadMutex, fIsOffline);
  513. if (cmtl.wasLocked())
  514. {
  515. CARLA_SAFE_ASSERT_BREAK(fShmAudioPool.data != nullptr);
  516. // mixdown is default, do buffer addition (for multiple clients) if requested
  517. const bool doBufferAddition = fSetupHints & 0x10;
  518. // location to start of audio outputs (shm buffer)
  519. float* const fdataRealOuts = fShmAudioPool.data+(fServer.bufferSize*fServer.numAudioIns);
  520. if (doBufferAddition && fServer.numAudioOuts > 0)
  521. carla_zeroFloats(fdataRealOuts, fServer.bufferSize*fServer.numAudioOuts);
  522. if (! fClients.isEmpty())
  523. {
  524. // save transport for all clients
  525. const BridgeTimeInfo& bridgeTimeInfo(fShmRtClientControl.data->timeInfo);
  526. fServer.playing = bridgeTimeInfo.playing;
  527. fServer.position.frame = static_cast<jack_nframes_t>(bridgeTimeInfo.frame);
  528. fServer.position.usecs = bridgeTimeInfo.usecs;
  529. fServer.position.frame_rate = static_cast<jack_nframes_t>(fServer.sampleRate);
  530. if (bridgeTimeInfo.validFlags & kPluginBridgeTimeInfoValidBBT)
  531. {
  532. fServer.position.valid = JackPositionBBT;
  533. fServer.position.bar = bridgeTimeInfo.bar;
  534. fServer.position.beat = bridgeTimeInfo.beat;
  535. fServer.position.tick = static_cast<int32_t>(bridgeTimeInfo.tick + 0.5);
  536. fServer.position.beats_per_bar = bridgeTimeInfo.beatsPerBar;
  537. fServer.position.beat_type = bridgeTimeInfo.beatType;
  538. fServer.position.ticks_per_beat = bridgeTimeInfo.ticksPerBeat;
  539. fServer.position.beats_per_minute = bridgeTimeInfo.beatsPerMinute;
  540. fServer.position.bar_start_tick = bridgeTimeInfo.barStartTick;
  541. }
  542. else
  543. {
  544. fServer.position.valid = static_cast<jack_position_bits_t>(0x0);
  545. }
  546. int numClientOutputsProcessed = 0;
  547. // now go through each client
  548. for (LinkedList<JackClientState*>::Itenerator it = fClients.begin2(); it.valid(); it.next())
  549. {
  550. JackClientState* const jclient(it.getValue(nullptr));
  551. CARLA_SAFE_ASSERT_CONTINUE(jclient != nullptr);
  552. // FIXME - lock if offline
  553. const CarlaMutexTryLocker cmtl2(jclient->mutex);
  554. // check if we can process
  555. if (cmtl2.wasNotLocked() || jclient->processCb == nullptr || ! jclient->activated)
  556. {
  557. if (fServer.numAudioOuts > 0)
  558. carla_zeroFloats(fdataRealOuts, fServer.bufferSize*fServer.numAudioOuts);
  559. if (jclient->deactivated)
  560. fShmRtClientControl.data->procFlags = 1;
  561. }
  562. else
  563. {
  564. uint8_t i;
  565. // direct access to shm buffer, used only for inputs
  566. float* fdataReal = fShmAudioPool.data;
  567. // safe temp location for output, mixed down to shm buffer later on
  568. float* fdataCopy = fAudioPoolCopy;
  569. // wherever we're using fAudioTmpBuf
  570. bool needsTmpBufClear = false;
  571. // set audio inputs
  572. i = 0;
  573. for (LinkedList<JackPortState*>::Itenerator it2 = jclient->audioIns.begin2(); it2.valid(); it2.next())
  574. {
  575. JackPortState* const jport = it2.getValue(nullptr);
  576. CARLA_SAFE_ASSERT_CONTINUE(jport != nullptr);
  577. if (i++ < fServer.numAudioIns)
  578. {
  579. if (numClientOutputsProcessed == 0 || ! doBufferAddition)
  580. jport->buffer = fdataReal;
  581. else
  582. jport->buffer = fdataRealOuts + (i*fServer.bufferSize);
  583. fdataReal += fServer.bufferSize;
  584. fdataCopy += fServer.bufferSize;
  585. }
  586. else
  587. {
  588. jport->buffer = fAudioTmpBuf;
  589. needsTmpBufClear = true;
  590. }
  591. }
  592. if (i < fServer.numAudioIns)
  593. {
  594. const std::size_t remainingBufferSize = fServer.bufferSize * static_cast<uint8_t>(fServer.numAudioIns - i);
  595. //fdataReal += remainingBufferSize;
  596. fdataCopy += remainingBufferSize;
  597. }
  598. // location to start of audio outputs
  599. float* const fdataCopyOuts = fdataCopy;
  600. // set audio outputs
  601. i = 0;
  602. for (LinkedList<JackPortState*>::Itenerator it2 = jclient->audioOuts.begin2(); it2.valid(); it2.next())
  603. {
  604. JackPortState* const jport = it2.getValue(nullptr);
  605. CARLA_SAFE_ASSERT_CONTINUE(jport != nullptr);
  606. if (i++ < fServer.numAudioOuts)
  607. {
  608. jport->buffer = fdataCopy;
  609. fdataCopy += fServer.bufferSize;
  610. }
  611. else
  612. {
  613. jport->buffer = fAudioTmpBuf;
  614. needsTmpBufClear = true;
  615. }
  616. }
  617. if (i < fServer.numAudioOuts)
  618. {
  619. const std::size_t remainingBufferSize = fServer.bufferSize * static_cast<uint8_t>(fServer.numAudioOuts - i);
  620. carla_zeroFloats(fdataCopy, remainingBufferSize);
  621. //fdataCopy += remainingBufferSize;
  622. }
  623. // set midi inputs
  624. i = 0;
  625. for (LinkedList<JackPortState*>::Itenerator it2 = jclient->midiIns.begin2(); it2.valid(); it2.next())
  626. {
  627. JackPortState* const jport = it2.getValue(nullptr);
  628. CARLA_SAFE_ASSERT_CONTINUE(jport != nullptr);
  629. if (i++ < fServer.numMidiIns)
  630. jport->buffer = &fMidiInBuffers[i-1];
  631. else
  632. jport->buffer = &fDummyMidiInBuffer;
  633. }
  634. // set midi outputs
  635. i = 0;
  636. for (LinkedList<JackPortState*>::Itenerator it2 = jclient->midiOuts.begin2(); it2.valid(); it2.next())
  637. {
  638. JackPortState* const jport = it2.getValue(nullptr);
  639. CARLA_SAFE_ASSERT_CONTINUE(jport != nullptr);
  640. if (i++ < fServer.numMidiOuts)
  641. jport->buffer = &fMidiOutBuffers[i-1];
  642. else
  643. jport->buffer = &fDummyMidiOutBuffer;
  644. }
  645. if (needsTmpBufClear)
  646. carla_zeroFloats(fAudioTmpBuf, fServer.bufferSize);
  647. jclient->processCb(fServer.bufferSize, jclient->processCbPtr);
  648. if (fServer.numAudioOuts > 0)
  649. {
  650. if (++numClientOutputsProcessed == 1)
  651. {
  652. // first client, we can copy stuff over
  653. carla_copyFloats(fdataRealOuts, fdataCopyOuts,
  654. fServer.bufferSize*fServer.numAudioOuts);
  655. }
  656. else
  657. {
  658. // subsequent clients, add data (then divide by number of clients later on)
  659. carla_add(fdataRealOuts, fdataCopyOuts,
  660. fServer.bufferSize*fServer.numAudioOuts);
  661. if (doBufferAddition)
  662. {
  663. // for more than 1 client addition, we need to divide buffers now
  664. carla_multiply(fdataRealOuts,
  665. 1.0f/static_cast<float>(numClientOutputsProcessed),
  666. fServer.bufferSize*fServer.numAudioOuts);
  667. }
  668. }
  669. if (jclient->audioOuts.count() == 1 && fServer.numAudioOuts > 1)
  670. {
  671. for (uint8_t j=1; j<fServer.numAudioOuts; ++j)
  672. {
  673. carla_copyFloats(fdataRealOuts+(fServer.bufferSize*j),
  674. fdataCopyOuts,
  675. fServer.bufferSize);
  676. }
  677. }
  678. }
  679. }
  680. }
  681. if (numClientOutputsProcessed > 1 && ! doBufferAddition)
  682. {
  683. // more than 1 client active, need to divide buffers
  684. carla_multiply(fdataRealOuts,
  685. 1.0f/static_cast<float>(numClientOutputsProcessed),
  686. fServer.bufferSize*fServer.numAudioOuts);
  687. }
  688. }
  689. // fClients.isEmpty()
  690. else if (fServer.numAudioOuts > 0)
  691. {
  692. carla_zeroFloats(fdataRealOuts, fServer.bufferSize*fServer.numAudioOuts);
  693. }
  694. for (uint8_t i=0; i<fServer.numMidiIns; ++i)
  695. {
  696. fMidiInBuffers[i].count = 0;
  697. fMidiInBuffers[i].bufferPoolPos = 0;
  698. }
  699. if (fServer.numMidiOuts > 0)
  700. {
  701. uint8_t* midiData(fShmRtClientControl.data->midiOut);
  702. carla_zeroBytes(midiData, kBridgeBaseMidiOutHeaderSize);
  703. std::size_t curMidiDataPos = 0;
  704. for (uint8_t i=0; i<fServer.numMidiOuts; ++i)
  705. {
  706. JackMidiPortBufferOnStack& midiPortBuf(fMidiOutBuffers[i]);
  707. for (uint16_t j=0; j<midiPortBuf.count; ++j)
  708. {
  709. jack_midi_event_t& jmevent(midiPortBuf.events[j]);
  710. if (curMidiDataPos + kBridgeBaseMidiOutHeaderSize + jmevent.size >= kBridgeRtClientDataMidiOutSize)
  711. break;
  712. // set time
  713. *(uint32_t*)midiData = jmevent.time;
  714. midiData += 4;
  715. // set port
  716. *midiData++ = i;
  717. // set size
  718. *midiData++ = static_cast<uint8_t>(jmevent.size);
  719. // set data
  720. std::memcpy(midiData, jmevent.buffer, jmevent.size);
  721. midiData += jmevent.size;
  722. curMidiDataPos += kBridgeBaseMidiOutHeaderSize + jmevent.size;
  723. }
  724. }
  725. if (curMidiDataPos != 0 &&
  726. curMidiDataPos + kBridgeBaseMidiOutHeaderSize < kBridgeRtClientDataMidiOutSize)
  727. carla_zeroBytes(midiData, kBridgeBaseMidiOutHeaderSize);
  728. }
  729. }
  730. else
  731. {
  732. carla_stderr2("CarlaJackAppClient: fRealtimeThreadMutex tryLock failed");
  733. }
  734. break;
  735. }
  736. case kPluginBridgeRtClientQuit:
  737. ret = true;
  738. break;
  739. }
  740. #ifdef DEBUG
  741. if (opcode != kPluginBridgeRtClientProcess && opcode != kPluginBridgeRtClientMidiEvent) {
  742. carla_debug("CarlaJackAppClientRtThread::run() - opcode %s done", PluginBridgeRtClientOpcode2str(opcode));
  743. }
  744. #endif
  745. }
  746. return ret;
  747. }
  748. bool CarlaJackAppClient::handleNonRtData()
  749. {
  750. bool ret = false;
  751. for (; fShmNonRtClientControl.isDataAvailableForReading();)
  752. {
  753. const PluginBridgeNonRtClientOpcode opcode(fShmNonRtClientControl.readOpcode());
  754. #ifdef DEBUG
  755. if (opcode != kPluginBridgeNonRtClientPing) {
  756. carla_debug("CarlaJackAppClient::handleNonRtData() - got opcode: %s", PluginBridgeNonRtClientOpcode2str(opcode));
  757. }
  758. #endif
  759. if (opcode != kPluginBridgeNonRtClientNull && opcode != kPluginBridgeNonRtClientPingOnOff && fLastPingTime > 0)
  760. fLastPingTime = getCurrentTimeMilliseconds();
  761. switch (opcode)
  762. {
  763. case kPluginBridgeNonRtClientNull:
  764. break;
  765. case kPluginBridgeNonRtClientVersion: {
  766. const uint apiVersion = fShmNonRtServerControl.readUInt();
  767. CARLA_SAFE_ASSERT_UINT2(apiVersion == CARLA_PLUGIN_BRIDGE_API_VERSION, apiVersion, CARLA_PLUGIN_BRIDGE_API_VERSION);
  768. } break;
  769. case kPluginBridgeNonRtClientPing: {
  770. const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
  771. fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerPong);
  772. fShmNonRtServerControl.commitWrite();
  773. } break;
  774. case kPluginBridgeNonRtClientPingOnOff: {
  775. const uint32_t onOff(fShmNonRtClientControl.readBool());
  776. fLastPingTime = onOff ? getCurrentTimeMilliseconds() : -1;
  777. } break;
  778. case kPluginBridgeNonRtClientActivate:
  779. case kPluginBridgeNonRtClientDeactivate:
  780. break;
  781. case kPluginBridgeNonRtClientInitialSetup:
  782. // should never happen!!
  783. fShmNonRtServerControl.readUInt();
  784. fShmNonRtServerControl.readDouble();
  785. break;
  786. case kPluginBridgeNonRtClientSetParameterValue:
  787. case kPluginBridgeNonRtClientSetParameterMidiChannel:
  788. case kPluginBridgeNonRtClientSetParameterMidiCC:
  789. case kPluginBridgeNonRtClientSetProgram:
  790. case kPluginBridgeNonRtClientSetMidiProgram:
  791. case kPluginBridgeNonRtClientSetCustomData:
  792. case kPluginBridgeNonRtClientSetChunkDataFile:
  793. break;
  794. case kPluginBridgeNonRtClientSetOption:
  795. fShmNonRtClientControl.readUInt();
  796. fShmNonRtClientControl.readBool();
  797. break;
  798. case kPluginBridgeNonRtClientSetCtrlChannel:
  799. fShmNonRtClientControl.readShort();
  800. break;
  801. case kPluginBridgeNonRtClientGetParameterText:
  802. fShmNonRtClientControl.readUInt();
  803. break;
  804. case kPluginBridgeNonRtClientPrepareForSave:
  805. {
  806. if (fSessionManager == LIBJACK_SESSION_MANAGER_AUTO && std::getenv("NSM_URL") == nullptr)
  807. {
  808. struct sigaction sig;
  809. carla_zeroStruct(sig);
  810. sigaction(SIGUSR1, nullptr, &sig);
  811. if (sig.sa_handler != nullptr)
  812. fSessionManager = LIBJACK_SESSION_MANAGER_LADISH;
  813. }
  814. if (fSessionManager == LIBJACK_SESSION_MANAGER_LADISH)
  815. ::kill(::getpid(), SIGUSR1);
  816. const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
  817. fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerSaved);
  818. fShmNonRtServerControl.commitWrite();
  819. }
  820. break;
  821. case kPluginBridgeNonRtClientRestoreLV2State:
  822. break;
  823. case kPluginBridgeNonRtClientShowUI:
  824. if (jack_carla_interposed_action(LIBJACK_INTERPOSER_ACTION_SHOW_HIDE_GUI, 1, nullptr) == 1337)
  825. {
  826. // failed, LD_PRELOAD did not work?
  827. const char* const message("Cannot show UI, LD_PRELOAD not working?");
  828. const std::size_t messageSize(std::strlen(message));
  829. const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
  830. fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerUiClosed);
  831. fShmNonRtServerControl.commitWrite();
  832. fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerError);
  833. fShmNonRtServerControl.writeUInt(messageSize);
  834. fShmNonRtServerControl.writeCustomData(message, messageSize);
  835. fShmNonRtServerControl.commitWrite();
  836. }
  837. break;
  838. case kPluginBridgeNonRtClientHideUI:
  839. jack_carla_interposed_action(LIBJACK_INTERPOSER_ACTION_SHOW_HIDE_GUI, 0, nullptr);
  840. break;
  841. case kPluginBridgeNonRtClientUiParameterChange:
  842. case kPluginBridgeNonRtClientUiProgramChange:
  843. case kPluginBridgeNonRtClientUiMidiProgramChange:
  844. case kPluginBridgeNonRtClientUiNoteOn:
  845. case kPluginBridgeNonRtClientUiNoteOff:
  846. break;
  847. case kPluginBridgeNonRtClientQuit:
  848. ret = true;
  849. break;
  850. }
  851. #ifdef DEBUG
  852. if (opcode != kPluginBridgeNonRtClientPing) {
  853. carla_debug("CarlaJackAppClient::handleNonRtData() - opcode %s handled", PluginBridgeNonRtClientOpcode2str(opcode));
  854. }
  855. #endif
  856. }
  857. return ret;
  858. }
  859. void CarlaJackAppClient::runRealtimeThread()
  860. {
  861. carla_debug("CarlaJackAppClient runRealtimeThread START");
  862. #ifdef __SSE2_MATH__
  863. // Set FTZ and DAZ flags
  864. _mm_setcsr(_mm_getcsr() | 0x8040);
  865. #endif
  866. bool quitReceived = false;
  867. for (; ! fRealtimeThread.shouldThreadExit();)
  868. {
  869. if (handleRtData())
  870. {
  871. quitReceived = true;
  872. break;
  873. }
  874. }
  875. fNonRealtimeThread.signalThreadShouldExit();
  876. carla_debug("CarlaJackAppClient runRealtimeThread FINISHED");
  877. // TODO
  878. return; (void)quitReceived;
  879. }
  880. void CarlaJackAppClient::runNonRealtimeThread()
  881. {
  882. carla_debug("CarlaJackAppClient runNonRealtimeThread START");
  883. CARLA_SAFE_ASSERT_RETURN(initSharedMemmory(),);
  884. if (fServer.numMidiIns > 0)
  885. {
  886. fMidiInBuffers = new JackMidiPortBufferOnStack[fServer.numMidiIns];
  887. for (uint8_t i=0; i<fServer.numMidiIns; ++i)
  888. fMidiInBuffers[i].isInput = true;
  889. }
  890. if (fServer.numMidiOuts > 0)
  891. {
  892. fMidiOutBuffers = new JackMidiPortBufferOnStack[fServer.numMidiOuts];
  893. for (uint8_t i=0; i<fServer.numMidiOuts; ++i)
  894. fMidiOutBuffers[i].isInput = false;
  895. }
  896. fRealtimeThread.startThread(true);
  897. fLastPingTime = getCurrentTimeMilliseconds();
  898. carla_stdout("Carla Jack Client Ready!");
  899. bool quitReceived = false,
  900. timedOut = false;
  901. for (; ! fNonRealtimeThread.shouldThreadExit();)
  902. {
  903. carla_msleep(50);
  904. try {
  905. quitReceived = handleNonRtData();
  906. } CARLA_SAFE_EXCEPTION("handleNonRtData");
  907. if (quitReceived)
  908. break;
  909. /*
  910. if (fLastPingTime > 0 && getCurrentTimeMilliseconds() > fLastPingTime + 30000)
  911. {
  912. carla_stderr("Did not receive ping message from server for 30 secs, closing...");
  913. timedOut = true;
  914. fRealtimeThread.signalThreadShouldExit();
  915. break;
  916. }
  917. */
  918. }
  919. //callback(true, true, ENGINE_CALLBACK_ENGINE_STOPPED, 0, 0, 0, 0.0f, nullptr);
  920. if (quitReceived)
  921. {
  922. ::kill(::getpid(), SIGTERM);
  923. }
  924. else if (timedOut)
  925. {
  926. // TODO send shutdown?
  927. carla_stderr("CarlaJackAppClient error: runNonRealtimeThread ended with time out");
  928. ::kill(::getpid(), SIGTERM);
  929. }
  930. else
  931. {
  932. bool activated;
  933. {
  934. const CarlaMutexLocker cms(fRealtimeThreadMutex);
  935. if (fClients.isEmpty())
  936. {
  937. activated = false;
  938. }
  939. else if (JackClientState* const jclient = fClients.getLast(nullptr))
  940. {
  941. const CarlaMutexLocker cms2(jclient->mutex);
  942. activated = jclient->activated;
  943. }
  944. else
  945. {
  946. activated = true;
  947. }
  948. }
  949. if (activated)
  950. {
  951. carla_stderr("CarlaJackAppClient error: runNonRealtimeThread ended while client is activated");
  952. const char* const message("Plugin bridge error, process thread has stopped");
  953. const std::size_t messageSize(std::strlen(message));
  954. const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
  955. fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerError);
  956. fShmNonRtServerControl.writeUInt(messageSize);
  957. fShmNonRtServerControl.writeCustomData(message, messageSize);
  958. fShmNonRtServerControl.commitWrite();
  959. }
  960. }
  961. if (fRealtimeThread.isThreadRunning())
  962. {
  963. fRealtimeThread.signalThreadShouldExit();
  964. const CarlaMutexLocker cml(fRealtimeThreadMutex);
  965. if (fShmRtClientControl.data != nullptr)
  966. fShmRtClientControl.data->procFlags = 1;
  967. }
  968. clearSharedMemory();
  969. fRealtimeThread.stopThread(5000);
  970. carla_debug("CarlaJackAppClient runNonRealtimeThread FINISHED");
  971. }
  972. CARLA_BACKEND_END_NAMESPACE
  973. // ---------------------------------------------------------------------------------------------------------------------
  974. using CarlaBackend::CarlaJackAppClient;
  975. using CarlaBackend::JackClientState;
  976. static CarlaJackAppClient gClient;
  977. CARLA_BACKEND_START_NAMESPACE
  978. static int carla_interposed_callback(int cb_action, void* ptr)
  979. {
  980. return gClient.handleInterposerCallback(cb_action, ptr);
  981. }
  982. CARLA_BACKEND_END_NAMESPACE
  983. // ---------------------------------------------------------------------------------------------------------------------
  984. CARLA_EXPORT
  985. jack_client_t* jack_client_open(const char* client_name, jack_options_t options, jack_status_t* status, ...)
  986. {
  987. carla_debug("%s(%s, 0x%x, %p)", __FUNCTION__, client_name, options, status);
  988. if (JackClientState* const client = gClient.createClient(client_name))
  989. {
  990. if (status != nullptr)
  991. *status = static_cast<JackStatus>(0x0);
  992. return (jack_client_t*)client;
  993. }
  994. if (status != nullptr)
  995. *status = JackServerError;
  996. return nullptr;
  997. // unused
  998. (void)options;
  999. }
  1000. CARLA_EXPORT
  1001. jack_client_t* jack_client_new(const char* client_name)
  1002. {
  1003. return jack_client_open(client_name, JackNullOption, nullptr);
  1004. }
  1005. CARLA_EXPORT
  1006. int jack_client_close(jack_client_t* client)
  1007. {
  1008. carla_debug("%s(%p)", __FUNCTION__, client);
  1009. JackClientState* const jclient = (JackClientState*)client;
  1010. CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, 1);
  1011. gClient.destroyClient(jclient);
  1012. return 0;
  1013. }
  1014. CARLA_EXPORT
  1015. int jack_activate(jack_client_t* client)
  1016. {
  1017. carla_debug("%s(%p)", __FUNCTION__, client);
  1018. JackClientState* const jclient = (JackClientState*)client;
  1019. CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, 1);
  1020. return gClient.activateClient(jclient) ? 0 : 1;
  1021. }
  1022. CARLA_EXPORT
  1023. int jack_deactivate(jack_client_t* client)
  1024. {
  1025. carla_debug("%s(%p)", __FUNCTION__, client);
  1026. JackClientState* const jclient = (JackClientState*)client;
  1027. CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, 1);
  1028. return gClient.deactivateClient(jclient) ? 0 : 1;
  1029. }
  1030. // ---------------------------------------------------------------------------------------------------------------------
  1031. CARLA_EXPORT
  1032. pthread_t jack_client_thread_id(jack_client_t* client)
  1033. {
  1034. carla_debug("%s(%p)", __FUNCTION__, client);
  1035. JackClientState* const jclient = (JackClientState*)client;
  1036. CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, 0);
  1037. CarlaJackAppClient* const jackAppPtr = jclient->server.jackAppPtr;
  1038. CARLA_SAFE_ASSERT_RETURN(jackAppPtr != nullptr && jackAppPtr == &gClient, 0);
  1039. return jackAppPtr->getRealtimeThreadId();
  1040. }
  1041. // ---------------------------------------------------------------------------------------------------------------------
  1042. #include "jackbridge/JackBridge2.cpp"
  1043. #include "CarlaBridgeUtils.cpp"
  1044. // ---------------------------------------------------------------------------------------------------------------------
  1045. // TODO
  1046. CARLA_BACKEND_USE_NAMESPACE
  1047. CARLA_EXPORT
  1048. int jack_client_real_time_priority(jack_client_t* client)
  1049. {
  1050. carla_debug("%s(%p)", __FUNCTION__, client);
  1051. // code as used by water
  1052. const int minPriority = sched_get_priority_min(SCHED_RR);
  1053. const int maxPriority = sched_get_priority_max(SCHED_RR);
  1054. return ((maxPriority - minPriority) * 9) / 10 + minPriority;
  1055. // unused
  1056. (void)client;
  1057. }
  1058. int jack_client_create_thread(jack_client_t* client, pthread_t* thread, int priority,
  1059. int realtime, void *(*start_routine)(void*), void* arg)
  1060. {
  1061. carla_stderr2("%s(%p, %p, %i, %i, %p, %p)", __FUNCTION__, client, thread, priority, realtime, start_routine, arg);
  1062. return ENOSYS;
  1063. }
  1064. typedef void (*JackSessionCallback)(jack_session_event_t*, void*);
  1065. CARLA_EXPORT
  1066. int jack_set_session_callback(jack_client_t* client, JackSessionCallback callback, void* arg)
  1067. {
  1068. carla_stderr2("%s(%p, %p, %p)", __FUNCTION__, client, callback, arg);
  1069. return 0;
  1070. }
  1071. // ---------------------------------------------------------------------------------------------------------------------