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.

729 lines
25KB

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