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.

588 lines
15KB

  1. /*
  2. * Carla Bridge utils
  3. * Copyright (C) 2013-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 "CarlaBridgeUtils.hpp"
  18. #include "CarlaShmUtils.hpp"
  19. // must be last
  20. #include "jackbridge/JackBridge.hpp"
  21. #if defined(CARLA_OS_WIN) && defined(BUILDING_CARLA_FOR_WINDOWS)
  22. # define PLUGIN_BRIDGE_NAMEPREFIX_AUDIO_POOL "Global\\carla-bridge_shm_ap_"
  23. # define PLUGIN_BRIDGE_NAMEPREFIX_RT_CLIENT "Global\\carla-bridge_shm_rtC_"
  24. # define PLUGIN_BRIDGE_NAMEPREFIX_NON_RT_CLIENT "Global\\carla-bridge_shm_nonrtC_"
  25. # define PLUGIN_BRIDGE_NAMEPREFIX_NON_RT_SERVER "Global\\carla-bridge_shm_nonrtS_"
  26. #else
  27. # define PLUGIN_BRIDGE_NAMEPREFIX_AUDIO_POOL "/crlbrdg_shm_ap_"
  28. # define PLUGIN_BRIDGE_NAMEPREFIX_RT_CLIENT "/crlbrdg_shm_rtC_"
  29. # define PLUGIN_BRIDGE_NAMEPREFIX_NON_RT_CLIENT "/crlbrdg_shm_nonrtC_"
  30. # define PLUGIN_BRIDGE_NAMEPREFIX_NON_RT_SERVER "/crlbrdg_shm_nonrtS_"
  31. #endif
  32. // -------------------------------------------------------------------------------------------------------------------
  33. template<typename T>
  34. bool jackbridge_shm_map2(void* shm, T*& value) noexcept
  35. {
  36. value = (T*)jackbridge_shm_map(shm, sizeof(T));
  37. return (value != nullptr);
  38. }
  39. // -------------------------------------------------------------------------------------------------------------------
  40. BridgeAudioPool::BridgeAudioPool() noexcept
  41. : data(nullptr),
  42. dataSize(0),
  43. filename(),
  44. isServer(false)
  45. {
  46. carla_zeroChars(shm, 64);
  47. jackbridge_shm_init(shm);
  48. }
  49. BridgeAudioPool::~BridgeAudioPool() noexcept
  50. {
  51. // should be cleared by now
  52. CARLA_SAFE_ASSERT(data == nullptr);
  53. clear();
  54. }
  55. bool BridgeAudioPool::initializeServer() noexcept
  56. {
  57. char tmpFileBase[64];
  58. std::sprintf(tmpFileBase, PLUGIN_BRIDGE_NAMEPREFIX_AUDIO_POOL "XXXXXX");
  59. const carla_shm_t shm2 = carla_shm_create_temp(tmpFileBase);
  60. CARLA_SAFE_ASSERT_RETURN(carla_is_shm_valid(shm2), false);
  61. void* const shmptr = shm;
  62. carla_shm_t& shm1 = *(carla_shm_t*)shmptr;
  63. carla_copyStruct(shm1, shm2);
  64. filename = tmpFileBase;
  65. isServer = true;
  66. return true;
  67. }
  68. bool BridgeAudioPool::attachClient(const char* const basename) noexcept
  69. {
  70. CARLA_SAFE_ASSERT_RETURN(basename != nullptr && basename[0] != '\0', false);
  71. // must be invalid right now
  72. CARLA_SAFE_ASSERT_RETURN(! jackbridge_shm_is_valid(shm), false);
  73. filename = PLUGIN_BRIDGE_NAMEPREFIX_AUDIO_POOL;
  74. filename += basename;
  75. jackbridge_shm_attach(shm, filename);
  76. return jackbridge_shm_is_valid(shm);
  77. }
  78. void BridgeAudioPool::clear() noexcept
  79. {
  80. filename.clear();
  81. if (! jackbridge_shm_is_valid(shm))
  82. {
  83. CARLA_SAFE_ASSERT(data == nullptr);
  84. return;
  85. }
  86. if (data != nullptr)
  87. {
  88. if (isServer)
  89. jackbridge_shm_unmap(shm, data);
  90. data = nullptr;
  91. }
  92. dataSize = 0;
  93. jackbridge_shm_close(shm);
  94. jackbridge_shm_init(shm);
  95. }
  96. void BridgeAudioPool::resize(const uint32_t bufferSize, const uint32_t audioPortCount, const uint32_t cvPortCount) noexcept
  97. {
  98. CARLA_SAFE_ASSERT_RETURN(jackbridge_shm_is_valid(shm),);
  99. CARLA_SAFE_ASSERT_RETURN(isServer,);
  100. if (data != nullptr)
  101. jackbridge_shm_unmap(shm, data);
  102. dataSize = (audioPortCount+cvPortCount)*bufferSize*sizeof(float);
  103. if (dataSize == 0)
  104. dataSize = sizeof(float);
  105. data = (float*)jackbridge_shm_map(shm, dataSize);
  106. CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
  107. std::memset(data, 0, dataSize);
  108. }
  109. // -------------------------------------------------------------------------------------------------------------------
  110. BridgeRtClientControl::BridgeRtClientControl() noexcept
  111. : data(nullptr),
  112. filename(),
  113. needsSemDestroy(false),
  114. isServer(false)
  115. {
  116. carla_zeroChars(shm, 64);
  117. jackbridge_shm_init(shm);
  118. }
  119. BridgeRtClientControl::~BridgeRtClientControl() noexcept
  120. {
  121. // should be cleared by now
  122. CARLA_SAFE_ASSERT(data == nullptr);
  123. clear();
  124. }
  125. bool BridgeRtClientControl::initializeServer() noexcept
  126. {
  127. char tmpFileBase[64];
  128. std::sprintf(tmpFileBase, PLUGIN_BRIDGE_NAMEPREFIX_RT_CLIENT "XXXXXX");
  129. const carla_shm_t shm2 = carla_shm_create_temp(tmpFileBase);
  130. CARLA_SAFE_ASSERT_RETURN(carla_is_shm_valid(shm2), false);
  131. void* const shmptr = shm;
  132. carla_shm_t& shm1 = *(carla_shm_t*)shmptr;
  133. carla_copyStruct(shm1, shm2);
  134. filename = tmpFileBase;
  135. isServer = true;
  136. needsSemDestroy = true;
  137. if (! mapData())
  138. {
  139. jackbridge_shm_close(shm);
  140. jackbridge_shm_init(shm);
  141. return false;
  142. }
  143. CARLA_SAFE_ASSERT(data != nullptr);
  144. if (! jackbridge_sem_init(&data->sem.server))
  145. {
  146. unmapData();
  147. jackbridge_shm_close(shm);
  148. jackbridge_shm_init(shm);
  149. return false;
  150. }
  151. if (! jackbridge_sem_init(&data->sem.client))
  152. {
  153. jackbridge_sem_destroy(&data->sem.server);
  154. unmapData();
  155. jackbridge_shm_close(shm);
  156. jackbridge_shm_init(shm);
  157. return false;
  158. }
  159. return true;
  160. }
  161. bool BridgeRtClientControl::attachClient(const char* const basename) noexcept
  162. {
  163. CARLA_SAFE_ASSERT_RETURN(basename != nullptr && basename[0] != '\0', false);
  164. // must be invalid right now
  165. CARLA_SAFE_ASSERT_RETURN(! jackbridge_shm_is_valid(shm), false);
  166. filename = PLUGIN_BRIDGE_NAMEPREFIX_RT_CLIENT;
  167. filename += basename;
  168. jackbridge_shm_attach(shm, filename);
  169. return jackbridge_shm_is_valid(shm);
  170. }
  171. void BridgeRtClientControl::clear() noexcept
  172. {
  173. filename.clear();
  174. if (needsSemDestroy)
  175. {
  176. jackbridge_sem_destroy(&data->sem.client);
  177. jackbridge_sem_destroy(&data->sem.server);
  178. needsSemDestroy = false;
  179. }
  180. if (data != nullptr)
  181. unmapData();
  182. if (! jackbridge_shm_is_valid(shm))
  183. return;
  184. jackbridge_shm_close(shm);
  185. jackbridge_shm_init(shm);
  186. }
  187. bool BridgeRtClientControl::mapData() noexcept
  188. {
  189. CARLA_SAFE_ASSERT(data == nullptr);
  190. if (! jackbridge_shm_map2<BridgeRtClientData>(shm, data))
  191. return false;
  192. if (isServer)
  193. {
  194. std::memset(data, 0, sizeof(BridgeRtClientData));
  195. setRingBuffer(&data->ringBuffer, true);
  196. }
  197. else
  198. {
  199. CARLA_SAFE_ASSERT(data->midiOut[0] == 0);
  200. setRingBuffer(&data->ringBuffer, false);
  201. CARLA_SAFE_ASSERT_RETURN(jackbridge_sem_connect(&data->sem.server), false);
  202. CARLA_SAFE_ASSERT_RETURN(jackbridge_sem_connect(&data->sem.client), false);
  203. }
  204. return true;
  205. }
  206. void BridgeRtClientControl::unmapData() noexcept
  207. {
  208. if (isServer)
  209. {
  210. CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
  211. jackbridge_shm_unmap(shm, data);
  212. }
  213. data = nullptr;
  214. setRingBuffer(nullptr, false);
  215. }
  216. bool BridgeRtClientControl::waitForClient(const uint msecs) noexcept
  217. {
  218. CARLA_SAFE_ASSERT_RETURN(msecs > 0, false);
  219. CARLA_SAFE_ASSERT_RETURN(data != nullptr, false);
  220. CARLA_SAFE_ASSERT_RETURN(isServer, false);
  221. jackbridge_sem_post(&data->sem.server, true);
  222. return jackbridge_sem_timedwait(&data->sem.client, msecs, true);
  223. return false;
  224. }
  225. void BridgeRtClientControl::writeOpcode(const PluginBridgeRtClientOpcode opcode) noexcept
  226. {
  227. writeUInt(static_cast<uint32_t>(opcode));
  228. }
  229. PluginBridgeRtClientOpcode BridgeRtClientControl::readOpcode() noexcept
  230. {
  231. CARLA_SAFE_ASSERT_RETURN(! isServer, kPluginBridgeRtClientNull);
  232. return static_cast<PluginBridgeRtClientOpcode>(readUInt());
  233. }
  234. BridgeRtClientControl::WaitHelper::WaitHelper(BridgeRtClientControl& c) noexcept
  235. : data(c.data),
  236. ok(jackbridge_sem_timedwait(&data->sem.server, 5000, false)) {}
  237. BridgeRtClientControl::WaitHelper::~WaitHelper() noexcept
  238. {
  239. if (ok)
  240. jackbridge_sem_post(&data->sem.client, false);
  241. }
  242. // -------------------------------------------------------------------------------------------------------------------
  243. BridgeNonRtClientControl::BridgeNonRtClientControl() noexcept
  244. : data(nullptr),
  245. filename(),
  246. mutex(),
  247. isServer(false)
  248. {
  249. carla_zeroChars(shm, 64);
  250. jackbridge_shm_init(shm);
  251. }
  252. BridgeNonRtClientControl::~BridgeNonRtClientControl() noexcept
  253. {
  254. // should be cleared by now
  255. CARLA_SAFE_ASSERT(data == nullptr);
  256. clear();
  257. }
  258. bool BridgeNonRtClientControl::initializeServer() noexcept
  259. {
  260. char tmpFileBase[64];
  261. std::sprintf(tmpFileBase, PLUGIN_BRIDGE_NAMEPREFIX_NON_RT_CLIENT "XXXXXX");
  262. const carla_shm_t shm2 = carla_shm_create_temp(tmpFileBase);
  263. CARLA_SAFE_ASSERT_RETURN(carla_is_shm_valid(shm2), false);
  264. void* const shmptr = shm;
  265. carla_shm_t& shm1 = *(carla_shm_t*)shmptr;
  266. carla_copyStruct(shm1, shm2);
  267. filename = tmpFileBase;
  268. isServer = true;
  269. if (! mapData())
  270. {
  271. jackbridge_shm_close(shm);
  272. jackbridge_shm_init(shm);
  273. return false;
  274. }
  275. CARLA_SAFE_ASSERT(data != nullptr);
  276. return true;
  277. }
  278. bool BridgeNonRtClientControl::attachClient(const char* const basename) noexcept
  279. {
  280. CARLA_SAFE_ASSERT_RETURN(basename != nullptr && basename[0] != '\0', false);
  281. // must be invalid right now
  282. CARLA_SAFE_ASSERT_RETURN(! jackbridge_shm_is_valid(shm), false);
  283. filename = PLUGIN_BRIDGE_NAMEPREFIX_NON_RT_CLIENT;
  284. filename += basename;
  285. jackbridge_shm_attach(shm, filename);
  286. return jackbridge_shm_is_valid(shm);
  287. }
  288. void BridgeNonRtClientControl::clear() noexcept
  289. {
  290. filename.clear();
  291. if (data != nullptr)
  292. unmapData();
  293. if (! jackbridge_shm_is_valid(shm))
  294. {
  295. if (! isServer) {
  296. CARLA_SAFE_ASSERT(data == nullptr);
  297. }
  298. return;
  299. }
  300. jackbridge_shm_close(shm);
  301. jackbridge_shm_init(shm);
  302. }
  303. bool BridgeNonRtClientControl::mapData() noexcept
  304. {
  305. CARLA_SAFE_ASSERT(data == nullptr);
  306. if (jackbridge_shm_map2<BridgeNonRtClientData>(shm, data))
  307. {
  308. setRingBuffer(&data->ringBuffer, isServer);
  309. return true;
  310. }
  311. return false;
  312. }
  313. void BridgeNonRtClientControl::unmapData() noexcept
  314. {
  315. if (isServer)
  316. {
  317. CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
  318. jackbridge_shm_unmap(shm, data);
  319. }
  320. data = nullptr;
  321. setRingBuffer(nullptr, false);
  322. }
  323. void BridgeNonRtClientControl::waitIfDataIsReachingLimit() noexcept
  324. {
  325. CARLA_SAFE_ASSERT_RETURN(isServer,);
  326. if (getAvailableDataSize() < BigStackBuffer::size/4)
  327. return;
  328. for (int i=50; --i >= 0;)
  329. {
  330. if (getAvailableDataSize() >= BigStackBuffer::size*3/4)
  331. {
  332. writeOpcode(kPluginBridgeNonRtClientPing);
  333. commitWrite();
  334. return;
  335. }
  336. carla_msleep(20);
  337. }
  338. carla_stderr("Server waitIfDataIsReachingLimit() reached and failed");
  339. }
  340. void BridgeNonRtClientControl::writeOpcode(const PluginBridgeNonRtClientOpcode opcode) noexcept
  341. {
  342. CARLA_SAFE_ASSERT_RETURN(isServer,);
  343. writeUInt(static_cast<uint32_t>(opcode));
  344. }
  345. PluginBridgeNonRtClientOpcode BridgeNonRtClientControl::readOpcode() noexcept
  346. {
  347. CARLA_SAFE_ASSERT_RETURN(! isServer, kPluginBridgeNonRtClientNull);
  348. return static_cast<PluginBridgeNonRtClientOpcode>(readUInt());
  349. }
  350. // -------------------------------------------------------------------------------------------------------------------
  351. BridgeNonRtServerControl::BridgeNonRtServerControl() noexcept
  352. : data(nullptr),
  353. filename(),
  354. mutex(),
  355. isServer(false)
  356. {
  357. carla_zeroChars(shm, 64);
  358. jackbridge_shm_init(shm);
  359. }
  360. BridgeNonRtServerControl::~BridgeNonRtServerControl() noexcept
  361. {
  362. // should be cleared by now
  363. CARLA_SAFE_ASSERT(data == nullptr);
  364. clear();
  365. }
  366. bool BridgeNonRtServerControl::initializeServer() noexcept
  367. {
  368. char tmpFileBase[64];
  369. std::sprintf(tmpFileBase, PLUGIN_BRIDGE_NAMEPREFIX_NON_RT_SERVER "XXXXXX");
  370. const carla_shm_t shm2 = carla_shm_create_temp(tmpFileBase);
  371. CARLA_SAFE_ASSERT_RETURN(carla_is_shm_valid(shm2), false);
  372. void* const shmptr = shm;
  373. carla_shm_t& shm1 = *(carla_shm_t*)shmptr;
  374. carla_copyStruct(shm1, shm2);
  375. filename = tmpFileBase;
  376. isServer = true;
  377. if (! mapData())
  378. {
  379. jackbridge_shm_close(shm);
  380. jackbridge_shm_init(shm);
  381. return false;
  382. }
  383. CARLA_SAFE_ASSERT(data != nullptr);
  384. return true;
  385. }
  386. bool BridgeNonRtServerControl::attachClient(const char* const basename) noexcept
  387. {
  388. CARLA_SAFE_ASSERT_RETURN(basename != nullptr && basename[0] != '\0', false);
  389. // must be invalid right now
  390. CARLA_SAFE_ASSERT_RETURN(! jackbridge_shm_is_valid(shm), false);
  391. filename = PLUGIN_BRIDGE_NAMEPREFIX_NON_RT_SERVER;
  392. filename += basename;
  393. jackbridge_shm_attach(shm, filename);
  394. return jackbridge_shm_is_valid(shm);
  395. }
  396. void BridgeNonRtServerControl::clear() noexcept
  397. {
  398. filename.clear();
  399. if (data != nullptr)
  400. unmapData();
  401. if (! jackbridge_shm_is_valid(shm))
  402. {
  403. CARLA_SAFE_ASSERT(data == nullptr);
  404. return;
  405. }
  406. jackbridge_shm_close(shm);
  407. jackbridge_shm_init(shm);
  408. }
  409. bool BridgeNonRtServerControl::mapData() noexcept
  410. {
  411. CARLA_SAFE_ASSERT(data == nullptr);
  412. if (jackbridge_shm_map2<BridgeNonRtServerData>(shm, data))
  413. {
  414. setRingBuffer(&data->ringBuffer, isServer);
  415. return true;
  416. }
  417. return false;
  418. }
  419. void BridgeNonRtServerControl::unmapData() noexcept
  420. {
  421. if (isServer)
  422. {
  423. CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
  424. jackbridge_shm_unmap(shm, data);
  425. }
  426. data = nullptr;
  427. setRingBuffer(nullptr, false);
  428. }
  429. PluginBridgeNonRtServerOpcode BridgeNonRtServerControl::readOpcode() noexcept
  430. {
  431. CARLA_SAFE_ASSERT_RETURN(isServer, kPluginBridgeNonRtServerNull);
  432. return static_cast<PluginBridgeNonRtServerOpcode>(readUInt());
  433. }
  434. void BridgeNonRtServerControl::waitIfDataIsReachingLimit() noexcept
  435. {
  436. CARLA_SAFE_ASSERT_RETURN(! isServer,);
  437. if (getAvailableDataSize() < HugeStackBuffer::size/4)
  438. return;
  439. for (int i=50; --i >= 0;)
  440. {
  441. if (getAvailableDataSize() >= HugeStackBuffer::size*3/4)
  442. {
  443. writeOpcode(kPluginBridgeNonRtServerPong);
  444. commitWrite();
  445. return;
  446. }
  447. carla_msleep(20);
  448. }
  449. carla_stderr("Client waitIfDataIsReachingLimit() reached and failed");
  450. }
  451. void BridgeNonRtServerControl::writeOpcode(const PluginBridgeNonRtServerOpcode opcode) noexcept
  452. {
  453. CARLA_SAFE_ASSERT_RETURN(! isServer,);
  454. writeUInt(static_cast<uint32_t>(opcode));
  455. }
  456. // -------------------------------------------------------------------------------------------------------------------