Compare commits

...

2 Commits

Author SHA1 Message Date
Paolo Marrone
622b2ba169 vst3 messaging: more thread safeness and error handling 2025-06-11 16:54:34 +02:00
Paolo Marrone
010a8e314b vst3 messaging: minor fixes 2025-06-11 15:35:55 +02:00
2 changed files with 73 additions and 41 deletions

View File

@ -318,11 +318,13 @@ typedef struct pluginInstance {
#ifdef DATA_MESSAGING #ifdef DATA_MESSAGING
Steinberg_Vst_IConnectionPointVtbl *vtblIConnectionPoint; Steinberg_Vst_IConnectionPointVtbl *vtblIConnectionPoint;
Steinberg_Vst_IConnectionPoint *connectedPoint; Steinberg_Vst_IConnectionPoint *connectedPoint;
uint8_t message_data[DATA_MESSAGING_MAX]; uint8_t message_data_in[DATA_MESSAGING_MAX];
size_t message_data_size; size_t message_data_in_size;
char message_data_tosend; // This is to tell message_thread to send data uint8_t message_data_out[DATA_MESSAGING_MAX];
size_t message_data_out_size;
char message_data_out_tosend; // This is to tell message_thread to send data
thrd_t message_thread; thrd_t message_thread;
int message_flag; int message_cmd;
mtx_t message_mutex; mtx_t message_mutex;
cnd_t message_cond; cnd_t message_cond;
@ -436,7 +438,10 @@ static Steinberg_tresult pluginIConnectionPointConnect(void* thisInterface, stru
if (!other) return Steinberg_kInvalidArgument; if (!other) return Steinberg_kInvalidArgument;
if (p->connectedPoint) return Steinberg_kResultFalse; if (p->connectedPoint) return Steinberg_kResultFalse;
mtx_lock(&p->message_mutex);
p->connectedPoint = other; p->connectedPoint = other;
mtx_unlock(&p->message_mutex);
return Steinberg_kResultOk; return Steinberg_kResultOk;
} }
@ -444,7 +449,9 @@ static Steinberg_tresult pluginIConnectionPointConnect(void* thisInterface, stru
static Steinberg_tresult pluginIConnectionPointDisconnect(void* thisInterface, struct Steinberg_Vst_IConnectionPoint* other) { static Steinberg_tresult pluginIConnectionPointDisconnect(void* thisInterface, struct Steinberg_Vst_IConnectionPoint* other) {
pluginInstance *p = (pluginInstance *)((char *)thisInterface - offsetof(pluginInstance, vtblIConnectionPoint)); pluginInstance *p = (pluginInstance *)((char *)thisInterface - offsetof(pluginInstance, vtblIConnectionPoint));
if (p->connectedPoint && other == p->connectedPoint) { if (p->connectedPoint && other == p->connectedPoint) {
mtx_lock(&p->message_mutex);
p->connectedPoint = NULL; p->connectedPoint = NULL;
mtx_unlock(&p->message_mutex);
return Steinberg_kResultOk; return Steinberg_kResultOk;
} }
return Steinberg_kResultFalse; return Steinberg_kResultFalse;
@ -463,12 +470,16 @@ static Steinberg_tresult pluginIConnectionPointNotify(void* thisInterface, struc
const void *data = NULL; const void *data = NULL;
unsigned int size = 0; unsigned int size = 0;
alist->lpVtbl->getBinary(alist, "yoyoyo", &data, &size); alist->lpVtbl->getBinary(alist, "message_data", &data, &size);
if (!data || size <= 0) if (!data || size == 0)
return Steinberg_kResultFalse; return Steinberg_kResultFalse;
plugin_receive_from_ui(&(p->p), data, size); mtx_lock(&p->message_mutex);
memcpy(&p->message_data_in, data, size);
p->message_data_in_size = size;
mtx_unlock(&p->message_mutex);
return Steinberg_kResultOk; return Steinberg_kResultOk;
} }
@ -487,12 +498,12 @@ static Steinberg_Vst_IConnectionPointVtbl pluginVtblIConnectionPoint = {
// Assuming this gets called by audio thread only // Assuming this gets called by audio thread only
static char send_to_ui (void *handle, const void *data, size_t bytes) { static char send_to_ui (void *handle, const void *data, size_t bytes) {
pluginInstance *p = (pluginInstance *)handle; pluginInstance *p = (pluginInstance *)handle;
if (!data || bytes <= 0 || bytes > DATA_MESSAGING_MAX) { if (!data || bytes == 0 || bytes > DATA_MESSAGING_MAX) {
return 1; return 1;
} }
memcpy(p->message_data, data, bytes); memcpy(p->message_data_out, data, bytes);
p->message_data_size = bytes; p->message_data_out_size = bytes;
p->message_data_tosend = 1; p->message_data_out_tosend = 1;
return 0; return 0;
} }
# endif # endif
@ -519,13 +530,14 @@ int message_thread_f(void *arg) {
while (1) { while (1) {
mtx_lock(&p->message_mutex); mtx_lock(&p->message_mutex);
while (p->message_flag == 0) { // Wait if (p->message_cmd == 0) { // Wait
cnd_wait(&p->message_cond, &p->message_mutex); cnd_wait(&p->message_cond, &p->message_mutex);
} }
if (p->message_flag == 1) { // do work if (p->message_cmd == 1) { // do work
if (!p->connectedPoint || ! p->context) { if (!p->connectedPoint || ! p->context) {
// TODO: What to do there? mtx_unlock(&p->message_mutex);
thrd_sleep(&(struct timespec){.tv_nsec=1e+8}, NULL); // sleep 100 msec
continue; continue;
} }
@ -535,25 +547,33 @@ int message_thread_f(void *arg) {
app->lpVtbl->createInstance(app, (char*) Steinberg_Vst_IMessage_iid, (char*) Steinberg_Vst_IMessage_iid, (void**)&msg); app->lpVtbl->createInstance(app, (char*) Steinberg_Vst_IMessage_iid, (char*) Steinberg_Vst_IMessage_iid, (void**)&msg);
if (!msg) { if (!msg) {
// TODO: what to do here? mtx_unlock(&p->message_mutex);
thrd_sleep(&(struct timespec){.tv_nsec=1e+8}, NULL); // sleep 100 msec
continue; continue;
} }
msg->lpVtbl->setMessageID(msg, "HelloMessage");
Steinberg_Vst_IAttributeList *alist = msg->lpVtbl->getAttributes(msg); Steinberg_Vst_IAttributeList *alist = msg->lpVtbl->getAttributes(msg);
if (!alist) { if (!alist) {
// TODO: what to do here? msg->lpVtbl->release(msg);
mtx_unlock(&p->message_mutex);
thrd_sleep(&(struct timespec){.tv_nsec=1e+8}, NULL); // sleep 100 msec
continue; continue;
} }
alist->lpVtbl->setBinary(alist, "yoyoyo", p->message_data, p->message_data_size); alist->lpVtbl->setBinary(alist, "message_data", p->message_data_out, p->message_data_out_size);
ov->notify(p->connectedPoint, msg); Steinberg_tresult r = ov->notify(p->connectedPoint, msg);
if (r == Steinberg_kResultFalse) {
msg->lpVtbl->release(msg);
mtx_unlock(&p->message_mutex);
thrd_sleep(&(struct timespec){.tv_nsec=1e+8}, NULL); // sleep 100 msec
continue;
}
msg->lpVtbl->release(msg); msg->lpVtbl->release(msg);
p->message_flag = 0; p->message_cmd = 0;
} else if (p->message_flag == 2) { // exit } else if (p->message_cmd == 2) { // exit
mtx_unlock(&p->message_mutex); mtx_unlock(&p->message_mutex);
break; break;
} }
@ -626,7 +646,6 @@ static Steinberg_tresult pluginInitialize(void *thisInterface, struct Steinberg_
mtx_init(&p->message_mutex, mtx_plain); mtx_init(&p->message_mutex, mtx_plain);
cnd_init(&p->message_cond); cnd_init(&p->message_cond);
if (thrd_create(&p->message_thread, message_thread_f, p) != thrd_success) { if (thrd_create(&p->message_thread, message_thread_f, p) != thrd_success) {
fprintf(stderr, "Failed to create message_thread\n");
return Steinberg_kResultFalse; return Steinberg_kResultFalse;
} }
#endif #endif
@ -644,7 +663,7 @@ static Steinberg_tresult pluginTerminate(void *thisInterface) {
#ifdef DATA_MESSAGING #ifdef DATA_MESSAGING
mtx_lock(&p->message_mutex); mtx_lock(&p->message_mutex);
p->message_flag = 2; p->message_cmd = 2;
cnd_signal(&p->message_cond); cnd_signal(&p->message_cond);
mtx_unlock(&p->message_mutex); mtx_unlock(&p->message_mutex);
thrd_join(p->message_thread, NULL); thrd_join(p->message_thread, NULL);
@ -1269,12 +1288,19 @@ static Steinberg_tresult pluginProcess(void* thisInterface, struct Steinberg_Vst
#endif #endif
#ifdef DATA_MESSAGING #ifdef DATA_MESSAGING
if (p->message_data_tosend) { // message_data_tosend is manipulated by audio thread only if (p->message_data_in_size > 0 || p->message_data_out_tosend) {
if (mtx_trylock(&p->message_mutex) == thrd_success) { if (mtx_trylock(&p->message_mutex) == thrd_success) {
p->message_flag = 1; if (p->message_data_in_size > 0) {
plugin_receive_from_ui(&(p->p), p->message_data_in, p->message_data_in_size);
p->message_data_in_size = 0;
}
if (p->message_data_out_tosend) { // message_data_out_tosend is manipulated by audio thread only
p->message_cmd = 1;
cnd_signal(&p->message_cond); cnd_signal(&p->message_cond);
p->message_data_out_tosend = 0;
}
mtx_unlock(&p->message_mutex); mtx_unlock(&p->message_mutex);
p->message_data_tosend = 0;
} }
} }
#endif #endif
@ -1656,12 +1682,13 @@ static void plugViewSetParameterEndCb(void *handle, size_t index, float value) {
static char send_to_dsp (void *handle, const void *data, size_t bytes) { static char send_to_dsp (void *handle, const void *data, size_t bytes) {
plugView *v = (plugView *)handle; plugView *v = (plugView *)handle;
if (!data || bytes <= 0 || bytes > DATA_MESSAGING_MAX) { if (!data || bytes == 0 || bytes > DATA_MESSAGING_MAX) {
return 1; return 1;
} }
if (!v->ctrl->connectedPoint || !v->ctrl->context) if (!v->ctrl->connectedPoint || !v->ctrl->context) {
return 2; return 1;
}
Steinberg_Vst_IConnectionPointVtbl *ov = (Steinberg_Vst_IConnectionPointVtbl*) v->ctrl->connectedPoint->lpVtbl; Steinberg_Vst_IConnectionPointVtbl *ov = (Steinberg_Vst_IConnectionPointVtbl*) v->ctrl->connectedPoint->lpVtbl;
Steinberg_Vst_IHostApplication *app = (Steinberg_Vst_IHostApplication*) v->ctrl->context; Steinberg_Vst_IHostApplication *app = (Steinberg_Vst_IHostApplication*) v->ctrl->context;
@ -1669,19 +1696,23 @@ static char send_to_dsp (void *handle, const void *data, size_t bytes) {
app->lpVtbl->createInstance(app, (char*) Steinberg_Vst_IMessage_iid, (char*) Steinberg_Vst_IMessage_iid, (void**)&(msg)); app->lpVtbl->createInstance(app, (char*) Steinberg_Vst_IMessage_iid, (char*) Steinberg_Vst_IMessage_iid, (void**)&(msg));
if (!msg) if (!msg)
return 3; return 1;
msg->lpVtbl->setMessageID(msg, "HelloMessage");
Steinberg_Vst_IAttributeList *alist = msg->lpVtbl->getAttributes(msg); Steinberg_Vst_IAttributeList *alist = msg->lpVtbl->getAttributes(msg);
if (!alist) if (!alist) {
return 4; msg->lpVtbl->release(msg);
return 1;
}
alist->lpVtbl->setBinary(alist, "yoyoyo", data, bytes); alist->lpVtbl->setBinary(alist, "message_data", data, bytes);
ov->notify(v->ctrl->connectedPoint, msg); Steinberg_tresult r = ov->notify(v->ctrl->connectedPoint, msg);
if (r == Steinberg_kResultFalse) {
msg->lpVtbl->release(msg);
return 1;
}
msg->lpVtbl->release(msg); msg->lpVtbl->release(msg);
return 0; return 0;
} }
# endif # endif
@ -2572,9 +2603,9 @@ static Steinberg_tresult controllerIConnectionPointNotify(void* thisInterface, s
const void *data = NULL; const void *data = NULL;
unsigned int size = 0; unsigned int size = 0;
alist->lpVtbl->getBinary(alist, "yoyoyo", &data, &size); alist->lpVtbl->getBinary(alist, "message_data", &data, &size);
if (!data || size <= 0) if (!data || size == 0)
return Steinberg_kResultFalse; return Steinberg_kResultFalse;
for (size_t i = 0; i < c->viewsCount; i++) { for (size_t i = 0; i < c->viewsCount; i++) {
@ -2695,7 +2726,8 @@ static Steinberg_tresult factoryCreateInstance(void *thisInterface, Steinberg_FI
#ifdef DATA_MESSAGING #ifdef DATA_MESSAGING
p->vtblIConnectionPoint = &pluginVtblIConnectionPoint; p->vtblIConnectionPoint = &pluginVtblIConnectionPoint;
p->connectedPoint = NULL; p->connectedPoint = NULL;
p->message_data_tosend = 0; p->message_data_out_tosend = 0;
p->message_data_in_size = 0;
#endif #endif
*obj = p; *obj = p;
TRACE(" instance: %p\n", (void *)p); TRACE(" instance: %p\n", (void *)p);

View File

@ -38,7 +38,7 @@ typedef struct {
plugin_ui_callbacks cbs; plugin_ui_callbacks cbs;
} plugin_ui; } plugin_ui;
#if TEMPLATE_SUPPORTS_MESSAGING #ifdef TEMPLATE_SUPPORTS_MESSAGING
static void plugin_ui_receive_from_dsp (plugin_ui *instance, const void *data, size_t bytes) { static void plugin_ui_receive_from_dsp (plugin_ui *instance, const void *data, size_t bytes) {
(void) instance; (void) instance;
printf("plugin_ui_receive_from_dsp %ld bytes at %p: \n", bytes, data); printf("plugin_ui_receive_from_dsp %ld bytes at %p: \n", bytes, data);