iPlug2 - C++ Audio Plug-in Framework
Loading...
Searching...
No Matches
IPlugOSC.cpp
1#include "IPlugOSC.h"
2
3using namespace iplug;
4
5std::unique_ptr<Timer> OSCInterface::mTimer;
6int OSCInterface::sInstances = 0;
7WDL_PtrList<OSCDevice> gDevices;
8
9#ifdef OS_WIN
10#define XSleep Sleep
11#else
12void XSleep(int ms) { usleep(ms?ms*1000:100); }
13#endif
14
15OSCDevice::OSCDevice(const char* dest, int maxpacket, int sendsleep, sockaddr_in* listen_addr)
16{
17 mHasOutput = dest != nullptr;
18 mHasInput = listen_addr != nullptr;
19
20 memset(&mSendAddress, 0, sizeof(mSendAddress));
21 mMaxMacketSize = maxpacket > 0 ? maxpacket : 1024;
22 mSendSleep = sendsleep >= 0 ? sendsleep : 10;
23 mSendSocket = socket(AF_INET, SOCK_DGRAM, 0);
24
25 if (mSendSocket == INVALID_SOCKET)
26 {
27 //TODO:
28 }
29 else if (listen_addr)
30 {
31 mReceiveAddress = *listen_addr;
32 int on = 1;
33 setsockopt(mSendSocket, SOL_SOCKET, SO_BROADCAST, (char*)&on, sizeof(on));
34 if (!bind(mSendSocket, (struct sockaddr*) & mReceiveAddress, sizeof(struct sockaddr)))
35 {
36 SET_SOCK_BLOCK(mSendSocket, false);
37 }
38 else
39 {
40 closesocket(mSendSocket);
41 mSendSocket = INVALID_SOCKET;
42 }
43 }
44 else
45 {
46 mDestination.Set(dest);
47
48 WDL_String tmp(dest);
49 int sendport = 0;
50 char* p = strstr(tmp.Get(), ":");
51 if (p)
52 {
53 *p++ = 0;
54 sendport = atoi(p);
55 }
56 if (!sendport) sendport = 8000;
57
58 mSendAddress.sin_family = AF_INET;
59 mSendAddress.sin_addr.s_addr = inet_addr(tmp.Get());
60 mSendAddress.sin_port = htons(sendport);
61
62 int on = 1;
63 setsockopt(mSendSocket, SOL_SOCKET, SO_BROADCAST, (char*)&on, sizeof(on));
64 SET_SOCK_BLOCK(mSendSocket, false);
65 }
66}
67
68OSCDevice::~OSCDevice()
69{
70 if (mSendSocket != INVALID_SOCKET)
71 {
72 shutdown(mSendSocket, SHUT_RDWR);
73 closesocket(mSendSocket);
74 mSendSocket = INVALID_SOCKET;
75 }
76}
77
79{
80 if (mSendSocket == INVALID_SOCKET)
81 return;
82
83 struct sockaddr* p = mDestination.GetLength() ? nullptr : (struct sockaddr*) & mSendAddress;
84
85 for (;;)
86 {
87 char buf[16384];
88 buf[0] = 0;
89 socklen_t plen = (socklen_t)sizeof(mSendAddress);
90 const int len = (int)recvfrom(mSendSocket, buf, sizeof(buf), 0, p, p ? &plen : nullptr);
91
92 if (len < 1)
93 break;
94
95 OnMessage(1, (const unsigned char*)buf, len);
96 }
97}
98
100{
101 static char hdr[16] = { '#', 'b', 'u', 'n', 'd', 'l', 'e', 0, 0, 0, 0, 0, 1, 0, 0, 0 };
102
103 // send mSendQueue as UDP blocks
104 if (mSendQueue.Available() <= 16)
105 {
106 if (mSendQueue.Available() > 0) mSendQueue.Clear();
107 return;
108 }
109 // mSendQueue should begin with a 16 byte pad, then messages in OSC
110
111 char* packetstart = (char*)mSendQueue.Get();
112 int packetlen = 16;
113 bool hasbundle = false;
114 mSendQueue.Advance(16); // skip bundle for now, but keep it around
115
116 SET_SOCK_BLOCK(mSendSocket, true);
117
118 while (mSendQueue.Available() >= sizeof(int))
119 {
120 int len = *(int*)mSendQueue.Get(); // not advancing
121 OSC_MAKEINTMEM4BE((char*)&len);
122
123 if (len < 1 || len > MAX_OSC_MSG_LEN || len > mSendQueue.Available()) break;
124
125 if (packetlen > 16 && packetlen + sizeof(int) + len > mMaxMacketSize)
126 {
127 // packet is full
128 if (!hasbundle)
129 {
130 packetstart += 20;
131 packetlen -= 20;
132 }
133 else
134 {
135 memcpy(packetstart, hdr, 16);
136 }
137
138 sendto(mSendSocket, packetstart, packetlen, 0, (struct sockaddr*) & mSendAddress, sizeof(mSendAddress));
139 if (mSendSleep > 0)
140 XSleep(mSendSleep);
141
142 packetstart = (char*)mSendQueue.Get() - 16; // safe since we padded the queue start
143 packetlen = 16;
144 hasbundle = false;
145 }
146
147 if (packetlen > 16) hasbundle = true;
148 mSendQueue.Advance(sizeof(int) + len);
149 packetlen += sizeof(int) + len;
150 }
151
152 if (packetlen > 16)
153 {
154 if (!hasbundle)
155 {
156 packetstart += 20;
157 packetlen -= 20;
158 }
159 else
160 {
161 memcpy(packetstart, hdr, 16);
162 }
163 sendto(mSendSocket, packetstart, packetlen, 0, (struct sockaddr*) & mSendAddress, sizeof(mSendAddress));
164 if (mSendSleep > 0)
165 XSleep(mSendSleep);
166 }
167 SET_SOCK_BLOCK(mSendSocket, false);
168
169 mSendQueue.Clear();
170}
171
172void OSCDevice::AddInstance(void(*callback)(void* d1, int dev_idx, int msglen, void* msg), void* d1, int dev_idx)
173{
174 const rec r = { callback, d1, dev_idx };
175 mInstances.Add(r);
176}
177
178void OSCDevice::OnMessage(char type, const unsigned char* msg, int len)
179{
180 const int n = mInstances.GetSize();
181 const rec* r = mInstances.Get();
182 for (int x = 0; x < n; x++)
183 if (r[x].callback) r[x].callback(r[x].data1, r[x].dev_idx, len, (void*)msg);
184}
185
186void OSCDevice::SendOSC(const char* src, int len)
187{
188 if (!mSendQueue.GetSize())
189 mSendQueue.Add(nullptr, 16);
190
191 int tlen = len;
192 OSC_MAKEINTMEM4BE(&tlen);
193 mSendQueue.Add(&tlen, sizeof(tlen));
194 mSendQueue.Add(src, len);
195}
196
197//static
198void OSCInterface::MessageCallback(void* d1, int dev_idx, int len, void* msg)
199{
200 OSCInterface* _this = (OSCInterface*)d1;
201
202 if (_this && msg)
203 {
204 if (_this->mIncomingEvents.GetSize() < 65536 * 8)
205 {
206 const int this_sz = ((sizeof(incomingEvent) + (len - 3)) + 7) & ~7;
207
208 _this->mIncomingEvents_mutex.Enter();
209 const int oldsz = _this->mIncomingEvents.GetSize();
210 _this->mIncomingEvents.Resize(oldsz + this_sz, false);
211
212 if (_this->mIncomingEvents.GetSize() == oldsz + this_sz)
213 {
214 incomingEvent* item = (incomingEvent*)((char*)_this->mIncomingEvents.Get() + oldsz);
215 item->dev_ptr = _this->mDevices.Get(dev_idx);
216 item->sz = len;
217 memcpy(item->msg, msg, len);
218 }
219 _this->mIncomingEvents_mutex.Leave();
220 }
221 }
222}
223
224void OSCInterface::OnTimer(Timer& timer)
225{
226 const int nDevices = gDevices.GetSize();
227
228 for (auto i = 0; i < nDevices; i++)
229 {
230 auto* pDev = gDevices.Get(i);
231 if (pDev->mHasInput)
232 pDev->RunInput();
233 }
234
235 if (mIncomingEvents.GetSize())
236 {
237 static WDL_HeapBuf tmp;
238
239 mIncomingEvents_mutex.Enter();
240 tmp.CopyFrom(&mIncomingEvents, false);
241 mIncomingEvents.Resize(0, false);
242 mIncomingEvents_mutex.Leave();
243
244 int pos = 0;
245 const int endpos = tmp.GetSize();
246 while (pos < endpos + 1 - sizeof(incomingEvent))
247 {
248 incomingEvent* evt = (incomingEvent*)((char*)tmp.Get() + pos);
249
250 const int this_sz = ((sizeof(incomingEvent) + (evt->sz - 3)) + 7) & ~7;
251
252 if (pos + this_sz > endpos) break;
253 pos += this_sz;
254
255 int rd_pos = 0;
256 int rd_sz = evt->sz;
257 if (evt->sz > 20 && !strcmp((char*)evt->msg, "#bundle"))
258 {
259 rd_sz = *(int*)(evt->msg + 16);
260 OSC_MAKEINTMEM4BE(&rd_sz);
261 rd_pos += 20;
262 }
263 // if (m_var_msgs[3]) m_var_msgs[3][0] = evt->dev_ptr ? *evt->dev_ptr : -1.0;
264
265 while (rd_pos + rd_sz <= evt->sz && rd_sz >= 0)
266 {
267 OscMessageRead rmsg((char*)evt->msg + rd_pos, rd_sz);
268
269 const char* mstr = rmsg.GetMessage();
270 if (mstr && *mstr)
271 OnOSCMessage(rmsg);
272
273 rd_pos += rd_sz + 4;
274 if (rd_pos >= evt->sz) break;
275
276 rd_sz = *(int*)(evt->msg + rd_pos - 4);
277 OSC_MAKEINTMEM4BE(&rd_sz);
278 }
279 }
280 }
281
282 for (auto i = 0; i < nDevices; i++)
283 {
284 auto* pDev = gDevices.Get(i);
285 if (pDev->mHasOutput)
286 pDev->RunOutput(); // send queued messages
287 }
288}
289
290OSCInterface::OSCInterface(OSCLogFunc logFunc)
291: mLogFunc(logFunc)
292{
293 JNL::open_socketlib();
294
295 if (!mTimer)
296 mTimer = std::unique_ptr<Timer>(Timer::Create(std::bind(&OSCInterface::OnTimer, this, std::placeholders::_1), OSC_TIMER_RATE));
297
298 sInstances++;
299}
300
301OSCInterface::~OSCInterface()
302{
303 if (--sInstances == 0) {
304 mTimer = nullptr;
305 gDevices.Empty(true);
306 }
307}
308
309OSCDevice* OSCInterface::CreateReceiver(WDL_String& log, int port)
310{
311 const char buf[] = "127.0.0.1";
312
313 struct sockaddr_in addr;
314 addr.sin_addr.s_addr = INADDR_ANY;
315 addr.sin_family = AF_INET;
316 if (buf[0] && buf[0] != '*') addr.sin_addr.s_addr = inet_addr(buf);
317 if (addr.sin_addr.s_addr == INADDR_NONE) addr.sin_addr.s_addr = INADDR_ANY;
318 addr.sin_port = htons(port);
319
320 int x;
321 bool isReuse = false;
322 OSCDevice* r = nullptr;
323 for (x = 0; x < gDevices.GetSize(); x++)
324 {
325 OSCDevice* dev = gDevices.Get(x);
326 if (dev && dev->mHasInput)
327 {
328 if (dev->mReceiveAddress.sin_port == addr.sin_port && dev->mReceiveAddress.sin_addr.s_addr == addr.sin_addr.s_addr)
329 {
330 r = dev;
331 isReuse = true;
332
333 log.AppendFormatted(1024, "Attached to already-opened listener '%s:%i'\r\n", buf, port);
334
335 break;
336 }
337 }
338 }
339
340 if (!r)
341 {
342 std::unique_ptr<OSCDevice> device(new OSCDevice(nullptr, 0, -1, &addr));
343
344 if (device->mSendSocket == INVALID_SOCKET)
345 {
346 log.AppendFormatted(1024, "Error listening for '%s:%i'\r\n", buf, port);
347 }
348 else
349 {
350 r = device.release();
351 log.AppendFormatted(1024, "Listening for OSC on '%s:%i'\r\n", buf, port);
352 }
353 }
354
355 if (r)
356 {
357 r->AddInstance(MessageCallback, this, mDevices.GetSize());
358 mDevices.Add(r);
359
360 if (!isReuse)
361 gDevices.Add(r);
362 }
363
364 return r;
365}
366
367OSCDevice* OSCInterface::CreateSender(WDL_String& log, const char* ip, int port)
368{
369 WDL_String destStr;
370 destStr.SetFormatted(256, "%s:%i", ip, port);
371 OSCDevice* r = nullptr;
372 bool isReuse = false;
373 for (auto x = 0; x < gDevices.GetSize(); x++)
374 {
375 OSCDevice* d = gDevices.Get(x);
376 if (d && d->mHasOutput)
377 {
378 if (!strcmp(d->mDestination.Get(), destStr.Get()))
379 {
380 isReuse = true;
381 r = d; // reuse!
382 break;
383 }
384 }
385 }
386
387 if (!r)
388 {
389 isReuse = false;
390 std::unique_ptr<OSCDevice> device(new OSCDevice(destStr.Get(), 0, -1, nullptr));
391 if (device->mSendSocket == INVALID_SOCKET)
392 {
393 log.AppendFormatted(1024, "Warning: failed creating destination for output '%s'\n", destStr.Get());
394 }
395 else
396 {
397 r = device.release();
398 }
399 }
400
401 if (r)
402 {
403 log.AppendFormatted(1024, "Set destination: '%s'\n", destStr.Get());
404
405 r->AddInstance(MessageCallback, this, mDevices.GetSize());
406 mDevices.Add(r);
407
408 if (!isReuse)
409 gDevices.Add(r);
410 }
411
412 return r;
413}
414
415OSCSender::OSCSender(const char* destIP, int port, OSCLogFunc logFunc)
416: OSCInterface(logFunc)
417, mDestIP("")
418{
419 SetDestination(destIP, port);
420}
421
422void OSCSender::SetDestination(const char* ip, int port)
423{
424 if (strcmp(ip, mDestIP.Get()) || port != mPort)
425 {
426 mDestIP.Set(ip);
427 mPort = port;
428
429 if (mDevice != nullptr)
430 {
431 gDevices.DeletePtr(mDevice, true);
432 }
433
434 WDL_String log;
435 mDevice = CreateSender(log, ip, port);
436
437 if(mLogFunc)
438 mLogFunc(log);
439 }
440}
441
443{
444 int len;
445 const char* msgStr = msg.GetBuffer(&len);
446 mDevice->SendOSC(msgStr, len);
447}
448
449OSCReceiver::OSCReceiver(int port, OSCLogFunc logFunc)
450: OSCInterface(logFunc)
451{
452 SetReceivePort(port);
453}
454
456{
457 if (port != mPort)
458 {
459 if (mDevice != nullptr)
460 {
461 gDevices.DeletePtr(mDevice, true);
462 }
463
464 WDL_String log;
465 mDevice = CreateReceiver(log, port);
466 mPort = port;
467
468 if(mLogFunc)
469 mLogFunc(log);
470 }
471}
void OnMessage(char type, const unsigned char *msg, int len)
Definition: IPlugOSC.cpp:178
void RunOutput()
Definition: IPlugOSC.cpp:99
void SendOSC(const char *src, int len)
Definition: IPlugOSC.cpp:186
OSCDevice(const char *dest, int maxpacket, int sendsleep, struct sockaddr_in *listen_addr)
Construct a new OSCDevice object.
Definition: IPlugOSC.cpp:15
void AddInstance(void(*callback)(void *d1, int dev_idx, int msglen, void *msg), void *d1, int dev_idx)
Definition: IPlugOSC.cpp:172
void RunInput()
Definition: IPlugOSC.cpp:78
OSCDevice * CreateReceiver(WDL_String &log, int port=8000)
Create a Receiver object.
Definition: IPlugOSC.cpp:309
OSCDevice * CreateSender(WDL_String &log, const char *ip="127.0.0.1", int port=8000)
Create a Sender object.
Definition: IPlugOSC.cpp:367
virtual void OnOSCMessage(OscMessageRead &msg)
Definition: IPlugOSC.h:131
OSCInterface(OSCLogFunc logFunc=nullptr)
Construct a new OSCInterface object.
Definition: IPlugOSC.cpp:290
OSCReceiver(int port=8000, OSCLogFunc logFunc=nullptr)
Construct a new OSCReceiver object.
Definition: IPlugOSC.cpp:449
void SetReceivePort(int port)
Set the Receive Port object.
Definition: IPlugOSC.cpp:455
void SetDestination(const char *ip, int port)
Set the Destination object.
Definition: IPlugOSC.cpp:422
OSCSender(const char *destIP="127.0.0.1", int port=8000, OSCLogFunc logFunc=nullptr)
Construct a new OSCSender object.
Definition: IPlugOSC.cpp:415
void SendOSCMessage(OscMessageWrite &msg)
Definition: IPlugOSC.cpp:442
Base class for timer.
Definition: IPlugTimer.h:40