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.

760 lines
26KB

  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. #include "libjack.hpp"
  18. #include <sys/prctl.h>
  19. using juce::FloatVectorOperations;
  20. using juce::Time;
  21. CARLA_BACKEND_START_NAMESPACE
  22. // --------------------------------------------------------------------------------------------------------------------
  23. class CarlaJackAppClient : public juce::Thread
  24. {
  25. public:
  26. JackServerState fServer;
  27. LinkedList<JackClientState*> fClients;
  28. CarlaJackAppClient()
  29. : Thread("CarlaJackAppClient"),
  30. fServer(this),
  31. fAudioPoolCopy(nullptr),
  32. fIsValid(false),
  33. fIsOffline(false),
  34. fLastPingTime(-1)
  35. {
  36. carla_debug("CarlaJackAppClient::CarlaJackAppClient()");
  37. const char* const shmIds(std::getenv("CARLA_SHM_IDS"));
  38. CARLA_SAFE_ASSERT_RETURN(shmIds != nullptr && std::strlen(shmIds) == 6*4,);
  39. const char* const libjackSetup(std::getenv("CARLA_LIBJACK_SETUP"));
  40. CARLA_SAFE_ASSERT_RETURN(libjackSetup != nullptr && std::strlen(libjackSetup) == 5,);
  41. // make sure we don't get loaded again
  42. carla_unsetenv("CARLA_SHM_IDS");
  43. // kill ourselves if main carla dies
  44. ::prctl(PR_SET_PDEATHSIG, SIGKILL);
  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. if (opcode != kPluginBridgeNonRtClientPing)
  231. {
  232. static int shownNull = 0;
  233. if (opcode == kPluginBridgeNonRtClientNull)
  234. {
  235. if (shownNull > 5)
  236. continue;
  237. ++shownNull;
  238. }
  239. carla_stdout("CarlaJackAppClient::handleNonRtData() - opcode %s handled", PluginBridgeNonRtClientOpcode2str(opcode));
  240. }
  241. }
  242. }
  243. void CarlaJackAppClient::run()
  244. {
  245. carla_stderr("CarlaJackAppClient run START");
  246. if (! fShmAudioPool.attachClient(fBaseNameAudioPool))
  247. {
  248. carla_stderr("Failed to attach to audio pool shared memory");
  249. return;
  250. }
  251. if (! fShmRtClientControl.attachClient(fBaseNameRtClientControl))
  252. {
  253. clear();
  254. carla_stderr("Failed to attach to rt client control shared memory");
  255. return;
  256. }
  257. if (! fShmRtClientControl.mapData())
  258. {
  259. clear();
  260. carla_stderr("Failed to map rt client control shared memory");
  261. return;
  262. }
  263. if (! fShmNonRtClientControl.attachClient(fBaseNameNonRtClientControl))
  264. {
  265. clear();
  266. carla_stderr("Failed to attach to non-rt client control shared memory");
  267. return;
  268. }
  269. if (! fShmNonRtClientControl.mapData())
  270. {
  271. clear();
  272. carla_stderr("Failed to map non-rt control client shared memory");
  273. return;
  274. }
  275. if (! fShmNonRtServerControl.attachClient(fBaseNameNonRtServerControl))
  276. {
  277. clear();
  278. carla_stderr("Failed to attach to non-rt server control shared memory");
  279. return;
  280. }
  281. if (! fShmNonRtServerControl.mapData())
  282. {
  283. clear();
  284. carla_stderr("Failed to map non-rt control server shared memory");
  285. return;
  286. }
  287. PluginBridgeNonRtClientOpcode opcode;
  288. opcode = fShmNonRtClientControl.readOpcode();
  289. CARLA_SAFE_ASSERT_INT(opcode == kPluginBridgeNonRtClientNull, opcode);
  290. const uint32_t shmRtClientDataSize = fShmNonRtClientControl.readUInt();
  291. CARLA_SAFE_ASSERT_INT2(shmRtClientDataSize == sizeof(BridgeRtClientData), shmRtClientDataSize, sizeof(BridgeRtClientData));
  292. const uint32_t shmNonRtClientDataSize = fShmNonRtClientControl.readUInt();
  293. CARLA_SAFE_ASSERT_INT2(shmNonRtClientDataSize == sizeof(BridgeNonRtClientData), shmNonRtClientDataSize, sizeof(BridgeNonRtClientData));
  294. const uint32_t shmNonRtServerDataSize = fShmNonRtClientControl.readUInt();
  295. CARLA_SAFE_ASSERT_INT2(shmNonRtServerDataSize == sizeof(BridgeNonRtServerData), shmNonRtServerDataSize, sizeof(BridgeNonRtServerData));
  296. if (shmRtClientDataSize != sizeof(BridgeRtClientData) || shmNonRtClientDataSize != sizeof(BridgeNonRtClientData) || shmNonRtServerDataSize != sizeof(BridgeNonRtServerData))
  297. {
  298. carla_stderr2("CarlaJackAppClient: data size mismatch");
  299. return;
  300. }
  301. opcode = fShmNonRtClientControl.readOpcode();
  302. CARLA_SAFE_ASSERT_INT(opcode == kPluginBridgeNonRtClientSetBufferSize, opcode);
  303. fServer.bufferSize = fShmNonRtClientControl.readUInt();
  304. opcode = fShmNonRtClientControl.readOpcode();
  305. CARLA_SAFE_ASSERT_INT(opcode == kPluginBridgeNonRtClientSetSampleRate, opcode);
  306. fServer.sampleRate = fShmNonRtClientControl.readDouble();
  307. if (fServer.bufferSize == 0 || carla_isZero(fServer.sampleRate))
  308. {
  309. carla_stderr2("CarlaJackAppClient: invalid empty state");
  310. return;
  311. }
  312. // tell backend we're live
  313. {
  314. const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
  315. fLastPingTime = Time::currentTimeMillis();
  316. CARLA_SAFE_ASSERT(fLastPingTime > 0);
  317. // ready!
  318. fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerReady);
  319. fShmNonRtServerControl.commitWrite();
  320. fShmNonRtServerControl.waitIfDataIsReachingLimit();
  321. }
  322. fIsValid = true;
  323. fLastPingTime = Time::currentTimeMillis();
  324. carla_stdout("Carla Jack Client Ready!");
  325. #ifdef __SSE2_MATH__
  326. // Set FTZ and DAZ flags
  327. _mm_setcsr(_mm_getcsr() | 0x8040);
  328. #endif
  329. bool quitReceived = false;
  330. for (; ! quitReceived && ! threadShouldExit();)
  331. {
  332. handleNonRtData();
  333. const BridgeRtClientControl::WaitHelper helper(fShmRtClientControl);
  334. if (! helper.ok)
  335. continue;
  336. for (; fShmRtClientControl.isDataAvailableForReading();)
  337. {
  338. const PluginBridgeRtClientOpcode opcode(fShmRtClientControl.readOpcode());
  339. //#ifdef DEBUG
  340. if (opcode != kPluginBridgeRtClientProcess && opcode != kPluginBridgeRtClientMidiEvent)
  341. {
  342. carla_stdout("CarlaJackAppClientRtThread::run() - got opcode: %s", PluginBridgeRtClientOpcode2str(opcode));
  343. }
  344. //#endif
  345. switch (opcode)
  346. {
  347. case kPluginBridgeRtClientNull:
  348. break;
  349. case kPluginBridgeRtClientSetAudioPool: {
  350. if (fShmAudioPool.data != nullptr)
  351. {
  352. jackbridge_shm_unmap(fShmAudioPool.shm, fShmAudioPool.data);
  353. fShmAudioPool.data = nullptr;
  354. }
  355. if (fAudioPoolCopy != nullptr)
  356. {
  357. delete[] fAudioPoolCopy;
  358. fAudioPoolCopy = nullptr;
  359. }
  360. const uint64_t poolSize(fShmRtClientControl.readULong());
  361. CARLA_SAFE_ASSERT_BREAK(poolSize > 0);
  362. fShmAudioPool.data = (float*)jackbridge_shm_map(fShmAudioPool.shm, static_cast<size_t>(poolSize));
  363. fAudioPoolCopy = new float[poolSize];
  364. break;
  365. }
  366. case kPluginBridgeRtClientControlEventParameter:
  367. case kPluginBridgeRtClientControlEventMidiBank:
  368. case kPluginBridgeRtClientControlEventMidiProgram:
  369. case kPluginBridgeRtClientControlEventAllSoundOff:
  370. case kPluginBridgeRtClientControlEventAllNotesOff:
  371. case kPluginBridgeRtClientMidiEvent:
  372. break;
  373. case kPluginBridgeRtClientProcess: {
  374. CARLA_SAFE_ASSERT_BREAK(fShmAudioPool.data != nullptr);
  375. const CarlaMutexTryLocker cmtl(fRealtimeThreadMutex);
  376. if (cmtl.wasLocked())
  377. {
  378. // location to start of audio outputs (shm buffer)
  379. float* const fdataRealOuts = fShmAudioPool.data+(fServer.bufferSize*fNumPorts.audioIns);
  380. // silence outputs first
  381. if (fNumPorts.audioOuts > 0)
  382. FloatVectorOperations::clear(fdataRealOuts, fServer.bufferSize*fNumPorts.audioOuts);
  383. // see if there's any clients
  384. if (! fClients.isEmpty())
  385. {
  386. // save tranport for all clients
  387. const BridgeTimeInfo& bridgeTimeInfo(fShmRtClientControl.data->timeInfo);
  388. fServer.playing = bridgeTimeInfo.playing;
  389. fServer.position.frame = bridgeTimeInfo.frame;
  390. fServer.position.usecs = bridgeTimeInfo.usecs;
  391. if (bridgeTimeInfo.valid & 0x1 /* kValidBBT */)
  392. {
  393. fServer.position.valid = JackPositionBBT;
  394. fServer.position.bar = bridgeTimeInfo.bar;
  395. fServer.position.beat = bridgeTimeInfo.beat;
  396. fServer.position.tick = bridgeTimeInfo.tick;
  397. fServer.position.beats_per_bar = bridgeTimeInfo.beatsPerBar;
  398. fServer.position.beat_type = bridgeTimeInfo.beatType;
  399. fServer.position.ticks_per_beat = bridgeTimeInfo.ticksPerBeat;
  400. fServer.position.beats_per_minute = bridgeTimeInfo.beatsPerMinute;
  401. fServer.position.bar_start_tick = bridgeTimeInfo.barStartTick;
  402. }
  403. else
  404. {
  405. fServer.position.valid = static_cast<jack_position_bits_t>(0);
  406. }
  407. // now go through each client
  408. for (LinkedList<JackClientState*>::Itenerator it = fClients.begin2(); it.valid(); it.next())
  409. {
  410. JackClientState* const jclient(it.getValue(nullptr));
  411. CARLA_SAFE_ASSERT_CONTINUE(jclient != nullptr);
  412. int numClientOutputsProcessed = 0;
  413. const CarlaMutexTryLocker cmtl2(jclient->mutex);
  414. // check if we can process
  415. if (cmtl2.wasNotLocked() || jclient->processCb == nullptr || ! jclient->activated)
  416. {
  417. if (jclient->deactivated)
  418. {
  419. fShmRtClientControl.data->procFlags = 1;
  420. }
  421. }
  422. else
  423. {
  424. uint32_t i;
  425. // direct access to shm buffer, used only for inputs
  426. float* fdataReal = fShmAudioPool.data;
  427. // safe temp location for output, mixed down to shm buffer later on
  428. float* fdataCopy = fAudioPoolCopy;
  429. // set inputs
  430. i = 0;
  431. for (LinkedList<JackPortState*>::Itenerator it = jclient->audioIns.begin2(); it.valid(); it.next())
  432. {
  433. CARLA_SAFE_ASSERT_BREAK(i++ < fNumPorts.audioIns);
  434. if (JackPortState* const jport = it.getValue(nullptr))
  435. jport->buffer = fdataReal;
  436. fdataReal += fServer.bufferSize;
  437. fdataCopy += fServer.bufferSize;
  438. }
  439. // FIXME one single "if"
  440. for (; i++ < fNumPorts.audioIns;)
  441. {
  442. fdataReal += fServer.bufferSize;
  443. fdataCopy += fServer.bufferSize;
  444. }
  445. // location to start of audio outputs
  446. float* const fdataCopyOuts = fdataCopy;
  447. // set ouputs
  448. i = 0;
  449. for (LinkedList<JackPortState*>::Itenerator it = jclient->audioOuts.begin2(); it.valid(); it.next())
  450. {
  451. CARLA_SAFE_ASSERT_BREAK(i++ < fNumPorts.audioOuts);
  452. if (JackPortState* const jport = it.getValue(nullptr))
  453. jport->buffer = fdataCopy;
  454. fdataCopy += fServer.bufferSize;
  455. }
  456. // FIXME one single "if"
  457. for (; i++ < fNumPorts.audioOuts;)
  458. {
  459. FloatVectorOperations::clear(fdataCopy, fServer.bufferSize);
  460. fdataCopy += fServer.bufferSize;
  461. }
  462. jclient->processCb(fServer.bufferSize, jclient->processCbPtr);
  463. if (fNumPorts.audioOuts > 0)
  464. {
  465. ++numClientOutputsProcessed;
  466. FloatVectorOperations::add(fdataRealOuts, fdataCopyOuts,
  467. fServer.bufferSize*fNumPorts.audioOuts);
  468. }
  469. }
  470. if (numClientOutputsProcessed > 1)
  471. {
  472. FloatVectorOperations::multiply(fdataRealOuts,
  473. 1.0f/static_cast<float>(numClientOutputsProcessed),
  474. fServer.bufferSize*fNumPorts.audioOuts);
  475. }
  476. }
  477. }
  478. }
  479. else
  480. {
  481. carla_stderr2("CarlaJackAppClient: fRealtimeThreadMutex tryLock failed");
  482. }
  483. carla_zeroBytes(fShmRtClientControl.data->midiOut, kBridgeRtClientDataMidiOutSize);
  484. break;
  485. }
  486. case kPluginBridgeRtClientQuit:
  487. quitReceived = true;
  488. signalThreadShouldExit();
  489. break;
  490. }
  491. //#ifdef DEBUG
  492. if (opcode != kPluginBridgeRtClientProcess && opcode != kPluginBridgeRtClientMidiEvent)
  493. {
  494. carla_stdout("CarlaJackAppClientRtThread::run() - opcode %s done", PluginBridgeRtClientOpcode2str(opcode));
  495. }
  496. //#endif
  497. }
  498. }
  499. //callback(ENGINE_CALLBACK_ENGINE_STOPPED, 0, 0, 0, 0.0f, nullptr);
  500. if (quitReceived)
  501. {
  502. carla_stderr("CarlaJackAppClient run END - quit by carla");
  503. ::kill(::getpid(), SIGTERM);
  504. }
  505. else
  506. {
  507. const char* const message("Plugin bridge error, process thread has stopped");
  508. const std::size_t messageSize(std::strlen(message));
  509. bool activated;
  510. {
  511. const CarlaMutexLocker cms(fRealtimeThreadMutex);
  512. if (fClients.isEmpty())
  513. {
  514. activated = false;
  515. }
  516. else if (JackClientState* const jclient = fClients.getLast(nullptr))
  517. {
  518. const CarlaMutexLocker cms(jclient->mutex);
  519. activated = jclient->activated;
  520. }
  521. else
  522. {
  523. activated = true;
  524. }
  525. }
  526. if (activated)
  527. {
  528. carla_stderr("CarlaJackAppClient run END - quit error");
  529. const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
  530. fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerError);
  531. fShmNonRtServerControl.writeUInt(messageSize);
  532. fShmNonRtServerControl.writeCustomData(message, messageSize);
  533. fShmNonRtServerControl.commitWrite();
  534. }
  535. else
  536. {
  537. carla_stderr("CarlaJackAppClient run END - quit itself");
  538. const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
  539. fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerUiClosed);
  540. fShmNonRtServerControl.commitWrite();
  541. }
  542. /*
  543. if (activated)
  544. {
  545. // TODO infoShutdown
  546. if (fClient.shutdownCb != nullptr)
  547. fClient.shutdownCb(fClient.shutdownCbPtr);
  548. }
  549. */
  550. }
  551. }
  552. // --------------------------------------------------------------------------------------------------------------------
  553. static CarlaJackAppClient gClient;
  554. CARLA_EXPORT
  555. jack_client_t* jack_client_open(const char* client_name, jack_options_t options, jack_status_t* status, ...)
  556. {
  557. carla_stdout("%s(%s, 0x%x, %p)", __FUNCTION__, client_name, options, status);
  558. if (JackClientState* const client = gClient.addClient(client_name))
  559. return (jack_client_t*)client;
  560. if (status != nullptr)
  561. *status = JackServerError;
  562. return nullptr;
  563. }
  564. CARLA_EXPORT
  565. jack_client_t* jack_client_new(const char* client_name)
  566. {
  567. return jack_client_open(client_name, JackNullOption, nullptr);
  568. }
  569. CARLA_EXPORT
  570. int jack_client_close(jack_client_t* client)
  571. {
  572. carla_stdout("%s(%p)", __FUNCTION__, client);
  573. JackClientState* const jclient = (JackClientState*)client;
  574. CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, 1);
  575. gClient.removeClient(jclient);
  576. return 0;
  577. }
  578. CARLA_EXPORT
  579. pthread_t jack_client_thread_id(jack_client_t* client)
  580. {
  581. carla_stdout("%s(%p)", __FUNCTION__, client);
  582. JackClientState* const jclient = (JackClientState*)client;
  583. CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, 0);
  584. CarlaJackAppClient* const jackAppPtr = jclient->server.jackAppPtr;
  585. CARLA_SAFE_ASSERT_RETURN(jackAppPtr != nullptr && jackAppPtr == &gClient, 0);
  586. return (pthread_t)jackAppPtr->getThreadId();
  587. }
  588. CARLA_BACKEND_END_NAMESPACE
  589. // --------------------------------------------------------------------------------------------------------------------
  590. #include "jackbridge/JackBridge2.cpp"
  591. #include "CarlaBridgeUtils.cpp"
  592. // --------------------------------------------------------------------------------------------------------------------
  593. // TODO
  594. CARLA_BACKEND_USE_NAMESPACE
  595. CARLA_EXPORT
  596. int jack_client_real_time_priority(jack_client_t* client)
  597. {
  598. carla_stdout("%s(%p)", __FUNCTION__, client);
  599. return -1;
  600. }
  601. typedef void (*JackSessionCallback)(jack_session_event_t*, void*);
  602. CARLA_EXPORT
  603. int jack_set_session_callback(jack_client_t* client, JackSessionCallback callback, void* arg)
  604. {
  605. carla_stdout("%s(%p, %p, %p)", __FUNCTION__, client, callback, arg);
  606. return 0;
  607. }
  608. // --------------------------------------------------------------------------------------------------------------------