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.

585 lines
15KB

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