LMMS
Loading...
Searching...
No Matches
CarlaBridgeUtils.cpp
Go to the documentation of this file.
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
18#include "CarlaBridgeUtils.hpp"
19#include "CarlaShmUtils.hpp"
20#include "CarlaTimeUtils.hpp"
21
22// must be last
23#include "jackbridge/JackBridge.hpp"
24
25#if defined(CARLA_OS_WIN) && !defined(BUILDING_CARLA_FOR_WINE)
26# define PLUGIN_BRIDGE_NAMEPREFIX_AUDIO_POOL "Local\\carla-bridge_shm_ap_"
27# define PLUGIN_BRIDGE_NAMEPREFIX_RT_CLIENT "Local\\carla-bridge_shm_rtC_"
28# define PLUGIN_BRIDGE_NAMEPREFIX_NON_RT_CLIENT "Local\\carla-bridge_shm_nonrtC_"
29# define PLUGIN_BRIDGE_NAMEPREFIX_NON_RT_SERVER "Local\\carla-bridge_shm_nonrtS_"
30#else
31# define PLUGIN_BRIDGE_NAMEPREFIX_AUDIO_POOL "/crlbrdg_shm_ap_"
32# define PLUGIN_BRIDGE_NAMEPREFIX_RT_CLIENT "/crlbrdg_shm_rtC_"
33# define PLUGIN_BRIDGE_NAMEPREFIX_NON_RT_CLIENT "/crlbrdg_shm_nonrtC_"
34# define PLUGIN_BRIDGE_NAMEPREFIX_NON_RT_SERVER "/crlbrdg_shm_nonrtS_"
35#endif
36
37// -------------------------------------------------------------------------------------------------------------------
38
39template<typename T>
40bool jackbridge_shm_map2(void* shm, T*& value) noexcept
41{
42 value = (T*)jackbridge_shm_map(shm, sizeof(T));
43 return (value != nullptr);
44}
45
46// -------------------------------------------------------------------------------------------------------------------
47
48BridgeAudioPool::BridgeAudioPool() noexcept
49 : data(nullptr),
50 dataSize(0),
51 filename(),
52 isServer(false)
53{
54 carla_zeroChars(shm, 64);
56}
57
58BridgeAudioPool::~BridgeAudioPool() noexcept
59{
60 // should be cleared by now
61 CARLA_SAFE_ASSERT(data == nullptr);
62
63 clear();
64}
65
66bool BridgeAudioPool::initializeServer() noexcept
67{
68 char tmpFileBase[64] = {};
69 std::snprintf(tmpFileBase, sizeof(tmpFileBase)-1, PLUGIN_BRIDGE_NAMEPREFIX_AUDIO_POOL "XXXXXX");
70
71 const carla_shm_t shm2 = carla_shm_create_temp(tmpFileBase);
72 CARLA_SAFE_ASSERT_RETURN(carla_is_shm_valid(shm2), false);
73
74 void* const shmptr = shm;
75 carla_shm_t& shm1 = *(carla_shm_t*)shmptr;
76 carla_copyStruct(shm1, shm2);
77
78 filename = tmpFileBase;
79 isServer = true;
80 return true;
81}
82
83bool BridgeAudioPool::attachClient(const char* const basename) noexcept
84{
85 CARLA_SAFE_ASSERT_RETURN(basename != nullptr && basename[0] != '\0', false);
86
87 // must be invalid right now
89
91 filename += basename;
92
94
95 return jackbridge_shm_is_valid(shm);
96}
97
98void BridgeAudioPool::clear() noexcept
99{
100 filename.clear();
101
102 if (! jackbridge_shm_is_valid(shm))
103 {
104 CARLA_SAFE_ASSERT(data == nullptr);
105 return;
106 }
107
108 if (data != nullptr)
109 {
110 if (isServer)
112 data = nullptr;
113 }
114
115 dataSize = 0;
118}
119
120void BridgeAudioPool::resize(const uint32_t bufferSize, const uint32_t audioPortCount, const uint32_t cvPortCount) noexcept
121{
123 CARLA_SAFE_ASSERT_RETURN(isServer,);
124
125 if (data != nullptr)
127
128 dataSize = (audioPortCount+cvPortCount)*bufferSize*sizeof(float);
129
130 if (dataSize == 0)
131 dataSize = sizeof(float);
132
133 data = (float*)jackbridge_shm_map(shm, dataSize);
134 CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
135
136 std::memset(data, 0, dataSize);
137}
138
139const char* BridgeAudioPool::getFilenameSuffix() const noexcept
140{
141 CARLA_SAFE_ASSERT_RETURN(filename.isNotEmpty(), nullptr);
142
143 const std::size_t prefixLength(std::strlen(PLUGIN_BRIDGE_NAMEPREFIX_AUDIO_POOL));
144 CARLA_SAFE_ASSERT_RETURN(filename.length() > prefixLength, nullptr);
145
146 return filename.buffer() + prefixLength;
147}
148
149// -------------------------------------------------------------------------------------------------------------------
150
151BridgeRtClientControl::BridgeRtClientControl() noexcept
152 : data(nullptr),
153 filename(),
154 needsSemDestroy(false),
155 isServer(false)
156{
157 carla_zeroChars(shm, 64);
159}
160
161BridgeRtClientControl::~BridgeRtClientControl() noexcept
162{
163 // should be cleared by now
164 CARLA_SAFE_ASSERT(data == nullptr);
165
166 clear();
167}
168
169bool BridgeRtClientControl::initializeServer() noexcept
170{
171 char tmpFileBase[64] = {};
172 std::snprintf(tmpFileBase, sizeof(tmpFileBase)-1, PLUGIN_BRIDGE_NAMEPREFIX_RT_CLIENT "XXXXXX");
173
174 const carla_shm_t shm2 = carla_shm_create_temp(tmpFileBase);
175 CARLA_SAFE_ASSERT_RETURN(carla_is_shm_valid(shm2), false);
176
177 void* const shmptr = shm;
178 carla_shm_t& shm1 = *(carla_shm_t*)shmptr;
179 carla_copyStruct(shm1, shm2);
180
181 filename = tmpFileBase;
182 isServer = true;
183
184 if (! mapData())
185 {
188 return false;
189 }
190
191 CARLA_SAFE_ASSERT(data != nullptr);
192
193 if (! jackbridge_sem_init(&data->sem.server))
194 {
195 unmapData();
198 return false;
199 }
200
201 if (! jackbridge_sem_init(&data->sem.client))
202 {
203 jackbridge_sem_destroy(&data->sem.server);
204 unmapData();
207 return false;
208 }
209
210 needsSemDestroy = true;
211 return true;
212}
213
214bool BridgeRtClientControl::attachClient(const char* const basename) noexcept
215{
216 CARLA_SAFE_ASSERT_RETURN(basename != nullptr && basename[0] != '\0', false);
217
218 // must be invalid right now
220
222 filename += basename;
223
225
226 return jackbridge_shm_is_valid(shm);
227}
228
229void BridgeRtClientControl::clear() noexcept
230{
231 filename.clear();
232
233 if (needsSemDestroy)
234 {
235 jackbridge_sem_destroy(&data->sem.client);
236 jackbridge_sem_destroy(&data->sem.server);
237 needsSemDestroy = false;
238 }
239
240 if (data != nullptr)
241 unmapData();
242
243 if (! jackbridge_shm_is_valid(shm))
244 return;
245
248}
249
250bool BridgeRtClientControl::mapData() noexcept
251{
252 CARLA_SAFE_ASSERT(data == nullptr);
253
255 return false;
256
257 if (isServer)
258 {
259 std::memset(data, 0, sizeof(BridgeRtClientData));
260 setRingBuffer(&data->ringBuffer, true);
261 }
262 else
263 {
264 CARLA_SAFE_ASSERT(data->midiOut[0] == 0);
265 setRingBuffer(&data->ringBuffer, false);
266
269 }
270
271 return true;
272}
273
274void BridgeRtClientControl::unmapData() noexcept
275{
276 if (isServer)
277 {
278 CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
280 }
281
282 data = nullptr;
283 setRingBuffer(nullptr, false);
284}
285
286bool BridgeRtClientControl::waitForClient(const uint msecs) noexcept
287{
288 CARLA_SAFE_ASSERT_RETURN(msecs > 0, false);
289 CARLA_SAFE_ASSERT_RETURN(data != nullptr, false);
290 CARLA_SAFE_ASSERT_RETURN(isServer, false);
291
292 jackbridge_sem_post(&data->sem.server, true);
293
294 return jackbridge_sem_timedwait(&data->sem.client, msecs, true);
295}
296
297bool BridgeRtClientControl::writeOpcode(const PluginBridgeRtClientOpcode opcode) noexcept
298{
299 return writeUInt(static_cast<uint32_t>(opcode));
300}
301
302PluginBridgeRtClientOpcode BridgeRtClientControl::readOpcode() noexcept
303{
304 CARLA_SAFE_ASSERT_RETURN(! isServer, kPluginBridgeRtClientNull);
305
306 return static_cast<PluginBridgeRtClientOpcode>(readUInt());
307}
308
309BridgeRtClientControl::WaitHelper::WaitHelper(BridgeRtClientControl& c) noexcept
310 : data(c.data),
311 ok(jackbridge_sem_timedwait(&data->sem.server, 5000, false)) {}
312
313BridgeRtClientControl::WaitHelper::~WaitHelper() noexcept
314{
315 if (ok)
316 jackbridge_sem_post(&data->sem.client, false);
317}
318
319// -------------------------------------------------------------------------------------------------------------------
320
321BridgeNonRtClientControl::BridgeNonRtClientControl() noexcept
322 : data(nullptr),
323 filename(),
324 mutex(),
325 isServer(false)
326{
327 carla_zeroChars(shm, 64);
329}
330
331BridgeNonRtClientControl::~BridgeNonRtClientControl() noexcept
332{
333 // should be cleared by now
334 CARLA_SAFE_ASSERT(data == nullptr);
335
336 clear();
337}
338
339bool BridgeNonRtClientControl::initializeServer() noexcept
340{
341 char tmpFileBase[64] = {};
342 std::snprintf(tmpFileBase, sizeof(tmpFileBase)-1, PLUGIN_BRIDGE_NAMEPREFIX_NON_RT_CLIENT "XXXXXX");
343
344 const carla_shm_t shm2 = carla_shm_create_temp(tmpFileBase);
345 CARLA_SAFE_ASSERT_RETURN(carla_is_shm_valid(shm2), false);
346
347 void* const shmptr = shm;
348 carla_shm_t& shm1 = *(carla_shm_t*)shmptr;
349 carla_copyStruct(shm1, shm2);
350
351 filename = tmpFileBase;
352 isServer = true;
353
354 if (! mapData())
355 {
358 return false;
359 }
360
361 CARLA_SAFE_ASSERT(data != nullptr);
362 return true;
363}
364
365bool BridgeNonRtClientControl::attachClient(const char* const basename) noexcept
366{
367 CARLA_SAFE_ASSERT_RETURN(basename != nullptr && basename[0] != '\0', false);
368
369 // must be invalid right now
371
373 filename += basename;
374
376
377 return jackbridge_shm_is_valid(shm);
378}
379
380void BridgeNonRtClientControl::clear() noexcept
381{
382 filename.clear();
383
384 if (data != nullptr)
385 unmapData();
386
387 if (! jackbridge_shm_is_valid(shm))
388 {
389 if (! isServer) {
390 CARLA_SAFE_ASSERT(data == nullptr);
391 }
392 return;
393 }
394
397}
398
399bool BridgeNonRtClientControl::mapData() noexcept
400{
401 CARLA_SAFE_ASSERT(data == nullptr);
402
404 {
405 setRingBuffer(&data->ringBuffer, isServer);
406 return true;
407 }
408
409 return false;
410}
411
412void BridgeNonRtClientControl::unmapData() noexcept
413{
414 if (isServer)
415 {
416 CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
418 }
419
420 data = nullptr;
421 setRingBuffer(nullptr, false);
422}
423
424void BridgeNonRtClientControl::waitIfDataIsReachingLimit() noexcept
425{
426 CARLA_SAFE_ASSERT_RETURN(isServer,);
427
428 if (getWritableDataSize() < BigStackBuffer::size/4)
429 return;
430
431 for (int i=50; --i >= 0;)
432 {
433 if (getWritableDataSize() >= BigStackBuffer::size*3/4)
434 {
435 writeOpcode(kPluginBridgeNonRtClientPing);
436 commitWrite();
437 return;
438 }
439 carla_msleep(20);
440 }
441
442 carla_stderr("Server waitIfDataIsReachingLimit() reached and failed");
443}
444
445bool BridgeNonRtClientControl::writeOpcode(const PluginBridgeNonRtClientOpcode opcode) noexcept
446{
447 CARLA_SAFE_ASSERT_RETURN(isServer, false);
448
449 return writeUInt(static_cast<uint32_t>(opcode));
450}
451
452PluginBridgeNonRtClientOpcode BridgeNonRtClientControl::readOpcode() noexcept
453{
454 CARLA_SAFE_ASSERT_RETURN(! isServer, kPluginBridgeNonRtClientNull);
455
456 return static_cast<PluginBridgeNonRtClientOpcode>(readUInt());
457}
458
459// -------------------------------------------------------------------------------------------------------------------
460
461BridgeNonRtServerControl::BridgeNonRtServerControl() noexcept
462 : data(nullptr),
463 filename(),
464 mutex(),
465 isServer(false)
466{
467 carla_zeroChars(shm, 64);
469}
470
471BridgeNonRtServerControl::~BridgeNonRtServerControl() noexcept
472{
473 // should be cleared by now
474 CARLA_SAFE_ASSERT(data == nullptr);
475
476 clear();
477}
478
479bool BridgeNonRtServerControl::initializeServer() noexcept
480{
481 char tmpFileBase[64] = {};
482 std::snprintf(tmpFileBase, sizeof(tmpFileBase)-1, PLUGIN_BRIDGE_NAMEPREFIX_NON_RT_SERVER "XXXXXX");
483
484 const carla_shm_t shm2 = carla_shm_create_temp(tmpFileBase);
485 CARLA_SAFE_ASSERT_RETURN(carla_is_shm_valid(shm2), false);
486
487 void* const shmptr = shm;
488 carla_shm_t& shm1 = *(carla_shm_t*)shmptr;
489 carla_copyStruct(shm1, shm2);
490
491 filename = tmpFileBase;
492 isServer = true;
493
494 if (! mapData())
495 {
498 return false;
499 }
500
501 CARLA_SAFE_ASSERT(data != nullptr);
502 return true;
503}
504
505bool BridgeNonRtServerControl::attachClient(const char* const basename) noexcept
506{
507 CARLA_SAFE_ASSERT_RETURN(basename != nullptr && basename[0] != '\0', false);
508
509 // must be invalid right now
511
513 filename += basename;
514
516
517 return jackbridge_shm_is_valid(shm);
518}
519
520void BridgeNonRtServerControl::clear() noexcept
521{
522 filename.clear();
523
524 if (data != nullptr)
525 unmapData();
526
527 if (! jackbridge_shm_is_valid(shm))
528 {
529 CARLA_SAFE_ASSERT(data == nullptr);
530 return;
531 }
532
535}
536
537bool BridgeNonRtServerControl::mapData() noexcept
538{
539 CARLA_SAFE_ASSERT(data == nullptr);
540
542 {
543 setRingBuffer(&data->ringBuffer, isServer);
544 return true;
545 }
546
547 return false;
548}
549
550void BridgeNonRtServerControl::unmapData() noexcept
551{
552 if (isServer)
553 {
554 CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
556 }
557
558 data = nullptr;
559 setRingBuffer(nullptr, false);
560}
561
562PluginBridgeNonRtServerOpcode BridgeNonRtServerControl::readOpcode() noexcept
563{
564 CARLA_SAFE_ASSERT_RETURN(isServer, kPluginBridgeNonRtServerNull);
565
566 return static_cast<PluginBridgeNonRtServerOpcode>(readUInt());
567}
568
569void BridgeNonRtServerControl::waitIfDataIsReachingLimit() noexcept
570{
571 CARLA_SAFE_ASSERT_RETURN(! isServer,);
572
573 if (getWritableDataSize() < HugeStackBuffer::size/4)
574 return;
575
576 for (int i=50; --i >= 0;)
577 {
578 if (getWritableDataSize() >= HugeStackBuffer::size*3/4)
579 {
580 writeOpcode(kPluginBridgeNonRtServerPong);
581 commitWrite();
582 return;
583 }
584 carla_msleep(20);
585 }
586
587 carla_stderr("Client waitIfDataIsReachingLimit() reached and failed");
588}
589
590bool BridgeNonRtServerControl::writeOpcode(const PluginBridgeNonRtServerOpcode opcode) noexcept
591{
592 CARLA_SAFE_ASSERT_RETURN(! isServer, false);
593
594 return writeUInt(static_cast<uint32_t>(opcode));
595}
596
597// -------------------------------------------------------------------------------------------------------------------
#define PLUGIN_BRIDGE_NAMEPREFIX_NON_RT_SERVER
Definition CarlaBridgeUtils.cpp:34
#define PLUGIN_BRIDGE_NAMEPREFIX_RT_CLIENT
Definition CarlaBridgeUtils.cpp:32
#define PLUGIN_BRIDGE_NAMEPREFIX_NON_RT_CLIENT
Definition CarlaBridgeUtils.cpp:33
#define PLUGIN_BRIDGE_NAMEPREFIX_AUDIO_POOL
Definition CarlaBridgeUtils.cpp:31
bool jackbridge_shm_map2(void *shm, T *&value) noexcept
Definition CarlaBridgeUtils.cpp:40
#define CARLA_SAFE_ASSERT_RETURN(cond, ret)
Definition CarlaDefines.h:190
unsigned int uint
Definition CarlaDefines.h:327
#define CARLA_SAFE_ASSERT(cond)
Definition CarlaDefines.h:182
pthread_mutex_t mutex
Definition Controller.C:6
#define noexcept
Definition DistrhoDefines.h:72
bool jackbridge_sem_connect(void *sem) noexcept
Definition JackBridge2.cpp:51
bool jackbridge_shm_is_valid(const void *shm) noexcept
Definition JackBridge2.cpp:86
void jackbridge_sem_destroy(void *sem) noexcept
Definition JackBridge2.cpp:42
void jackbridge_shm_close(void *shm) noexcept
Definition JackBridge2.cpp:115
void jackbridge_shm_attach(void *shm, const char *name) noexcept
Definition JackBridge2.cpp:106
void jackbridge_shm_init(void *shm) noexcept
Definition JackBridge2.cpp:97
bool jackbridge_sem_timedwait(void *sem, uint msecs, bool server) noexcept
Definition JackBridge2.cpp:72
void jackbridge_sem_post(void *sem, bool server) noexcept
Definition JackBridge2.cpp:62
void jackbridge_shm_unmap(void *shm, void *ptr) noexcept
Definition JackBridge2.cpp:135
bool jackbridge_sem_init(void *sem) noexcept
Definition JackBridge2.cpp:33
void * jackbridge_shm_map(void *shm, uint64_t size) noexcept
Definition JackBridge2.cpp:124
opcode
Definition Spc_Cpu.h:173
register unsigned i
Definition inflate.c:1575
static char filename[]
Definition features.c:5
static PuglViewHint int value
Definition pugl.h:1708
JSAMPIMAGE data
Definition jpeglib.h:945
unsigned int uint32_t
Definition mid.cpp:100
void clear(void *s)
Definition juce_FixedSizeFunction.h:71
#define false
Definition ordinals.h:83
return c
Definition crypt.c:175
#define const
Definition zconf.h:137