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.

598 lines
15KB

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