JUCE-7.0.12-0-g4f43011b96 JUCE-7.0.12-0-g4f43011b96
JUCE — C++ application framework with suport for VST, VST3, LV2 audio plug-ins

« « « Anklang Documentation
Loading...
Searching...
No Matches
juce_OSCSender.cpp
Go to the documentation of this file.
1 /*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11 Agreement and JUCE Privacy Policy.
12
13 End User License Agreement: www.juce.com/juce-7-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
15
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
18
19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21 DISCLAIMED.
22
23 ==============================================================================
24*/
25
26namespace juce
27{
28
29namespace
30{
31 //==============================================================================
40 struct OSCOutputStream
41 {
42 OSCOutputStream() noexcept {}
43
45 const void* getData() const noexcept { return output.getData(); }
46
48 size_t getDataSize() const noexcept { return output.getDataSize(); }
49
50 //==============================================================================
51 bool writeInt32 (int32 value)
52 {
53 return output.writeIntBigEndian (value);
54 }
55
56 bool writeUint64 (uint64 value)
57 {
58 return output.writeInt64BigEndian (int64 (value));
59 }
60
61 bool writeFloat32 (float value)
62 {
63 return output.writeFloatBigEndian (value);
64 }
65
66 bool writeString (const String& value)
67 {
68 if (! output.writeString (value))
69 return false;
70
71 const size_t numPaddingZeros = ~value.getNumBytesAsUTF8() & 3;
72
73 return output.writeRepeatedByte ('\0', numPaddingZeros);
74 }
75
76 bool writeBlob (const MemoryBlock& blob)
77 {
78 if (! (output.writeIntBigEndian ((int) blob.getSize())
79 && output.write (blob.getData(), blob.getSize())))
80 return false;
81
82 const size_t numPaddingZeros = ~(blob.getSize() - 1) & 3;
83
84 return output.writeRepeatedByte (0, numPaddingZeros);
85 }
86
87 bool writeColour (OSCColour colour)
88 {
89 return output.writeIntBigEndian ((int32) colour.toInt32());
90 }
91
92 bool writeTimeTag (OSCTimeTag timeTag)
93 {
94 return output.writeInt64BigEndian (int64 (timeTag.getRawTimeTag()));
95 }
96
97 bool writeAddress (const OSCAddress& address)
98 {
99 return writeString (address.toString());
100 }
101
102 bool writeAddressPattern (const OSCAddressPattern& ap)
103 {
104 return writeString (ap.toString());
105 }
106
108 {
109 output.writeByte (',');
110
111 if (typeList.size() > 0)
112 output.write (typeList.begin(), (size_t) typeList.size());
113
114 output.writeByte ('\0');
115
116 size_t bytesWritten = (size_t) typeList.size() + 1;
117 size_t numPaddingZeros = ~bytesWritten & 0x03;
118
119 return output.writeRepeatedByte ('\0', numPaddingZeros);
120 }
121
122 bool writeArgument (const OSCArgument& arg)
123 {
124 switch (arg.getType())
125 {
126 case OSCTypes::int32: return writeInt32 (arg.getInt32());
127 case OSCTypes::float32: return writeFloat32 (arg.getFloat32());
128 case OSCTypes::string: return writeString (arg.getString());
129 case OSCTypes::blob: return writeBlob (arg.getBlob());
130 case OSCTypes::colour: return writeColour (arg.getColour());
131
132 default:
133 // In this very unlikely case you supplied an invalid OSCType!
135 return false;
136 }
137 }
138
139 //==============================================================================
140 bool writeMessage (const OSCMessage& msg)
141 {
142 if (! writeAddressPattern (msg.getAddressPattern()))
143 return false;
144
146
147 for (auto& arg : msg)
148 typeList.add (arg.getType());
149
151 return false;
152
153 for (auto& arg : msg)
154 if (! writeArgument (arg))
156
157 return true;
158 }
159
160 bool writeBundle (const OSCBundle& bundle)
161 {
162 if (! writeString ("#bundle"))
163 return false;
164
165 if (! writeTimeTag (bundle.getTimeTag()))
166 return false;
167
168 for (auto& element : bundle)
169 if (! writeBundleElement (element))
171
172 return true;
173 }
174
175 //==============================================================================
176 bool writeBundleElement (const OSCBundle::Element& element)
177 {
178 const int64 startPos = output.getPosition();
179
180 if (! writeInt32 (0)) // writing dummy value for element size
181 return false;
182
183 if (element.isBundle())
184 {
185 if (! writeBundle (element.getBundle()))
186 return false;
187 }
188 else
189 {
190 if (! writeMessage (element.getMessage()))
191 return false;
192 }
193
194 const int64 endPos = output.getPosition();
195 const int64 elementSize = endPos - (startPos + 4);
196
197 return output.setPosition (startPos)
198 && writeInt32 ((int32) elementSize)
199 && output.setPosition (endPos);
200 }
201
202 private:
203 MemoryOutputStream output;
204
206 };
207
208} // namespace
209
210
211//==============================================================================
213{
214 Pimpl() noexcept {}
215 ~Pimpl() noexcept { disconnect(); }
216
217 //==============================================================================
218 bool connect (const String& newTargetHost, int newTargetPort)
219 {
220 if (! disconnect())
221 return false;
222
223 socket.setOwned (new DatagramSocket (true));
224 targetHostName = newTargetHost;
225 targetPortNumber = newTargetPort;
226
227 if (socket->bindToPort (0)) // 0 = use any local port assigned by the OS.
228 return true;
229
230 socket.reset();
231 return false;
232 }
233
234 bool connectToSocket (DatagramSocket& newSocket, const String& newTargetHost, int newTargetPort)
235 {
236 if (! disconnect())
237 return false;
238
239 socket.setNonOwned (&newSocket);
240 targetHostName = newTargetHost;
241 targetPortNumber = newTargetPort;
242 return true;
243 }
244
245 bool disconnect()
246 {
247 socket.reset();
248 return true;
249 }
250
251 //==============================================================================
252 bool send (const OSCMessage& message, const String& hostName, int portNumber)
253 {
254 OSCOutputStream outStream;
255
256 return outStream.writeMessage (message)
257 && sendOutputStream (outStream, hostName, portNumber);
258 }
259
260 bool send (const OSCBundle& bundle, const String& hostName, int portNumber)
261 {
262 OSCOutputStream outStream;
263
264 return outStream.writeBundle (bundle)
265 && sendOutputStream (outStream, hostName, portNumber);
266 }
267
268 bool send (const OSCMessage& message) { return send (message, targetHostName, targetPortNumber); }
269 bool send (const OSCBundle& bundle) { return send (bundle, targetHostName, targetPortNumber); }
270
271private:
272 //==============================================================================
273 bool sendOutputStream (OSCOutputStream& outStream, const String& hostName, int portNumber)
274 {
275 if (socket != nullptr)
276 {
277 const int streamSize = (int) outStream.getDataSize();
278
279 const int bytesWritten = socket->write (hostName, portNumber,
280 outStream.getData(), streamSize);
281 return bytesWritten == streamSize;
282 }
283
284 // if you hit this, you tried to send some OSC data without being
285 // connected to a port! You should call OSCSender::connect() first.
287
288 return false;
289 }
290
291 //==============================================================================
293 String targetHostName;
294 int targetPortNumber = 0;
295
297};
298
299
300//==============================================================================
302{
303}
304
306{
307 pimpl->disconnect();
308 pimpl.reset();
309}
310
311//==============================================================================
312bool OSCSender::connect (const String& targetHostName, int targetPortNumber)
313{
314 return pimpl->connect (targetHostName, targetPortNumber);
315}
316
317bool OSCSender::connectToSocket (DatagramSocket& socket, const String& targetHostName, int targetPortNumber)
318{
319 return pimpl->connectToSocket (socket, targetHostName, targetPortNumber);
320}
321
323{
324 return pimpl->disconnect();
325}
326
327//==============================================================================
328bool OSCSender::send (const OSCMessage& message) { return pimpl->send (message); }
329bool OSCSender::send (const OSCBundle& bundle) { return pimpl->send (bundle); }
330
331bool OSCSender::sendToIPAddress (const String& host, int port, const OSCMessage& message) { return pimpl->send (message, host, port); }
332bool OSCSender::sendToIPAddress (const String& host, int port, const OSCBundle& bundle) { return pimpl->send (bundle, host, port); }
333
334
335//==============================================================================
336//==============================================================================
337#if JUCE_UNIT_TESTS
338
340{
341public:
343 : UnitTest ("OSCBinaryWriter class", UnitTestCategories::osc)
344 {}
345
346 void runTest() override
347 {
348 beginTest ("writing OSC addresses");
349 {
350 OSCOutputStream outStream;
351 const char check[16] = { '/', 't', 'e', 's', 't', '/', 'f', 'a', 'd', 'e', 'r', '7', '\0', '\0', '\0', '\0' };
352
353 OSCAddress address ("/test/fader7");
354 expect (outStream.writeAddress (address));
355
356 expect (outStream.getDataSize() == sizeof (check));
357 expect (std::memcmp (outStream.getData(), check, sizeof (check)) == 0);
358 }
359
360 beginTest ("writing OSC address patterns");
361 {
362 OSCOutputStream outStream;
363 const char check[20] = { '/', '*', '/', '*', 'p', 'u', 't', '/', 'f', 'a', 'd', 'e', 'r', '[', '0', '-', '9', ']', '\0', '\0' };
364
365 OSCAddressPattern ap ("/*/*put/fader[0-9]");
366 expect (outStream.writeAddressPattern (ap));
367
368 expect (outStream.getDataSize() == sizeof (check));
369 expect (std::memcmp (outStream.getData(), check, sizeof (check)) == 0);
370 }
371
372 beginTest ("writing OSC time tags");
373 {
374 OSCOutputStream outStream;
375 const char check[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };
376 OSCTimeTag tag;
377
378 expect (outStream.writeTimeTag (tag));
379 expect (outStream.getDataSize() == 8);
380 expect (std::memcmp (outStream.getData(), check, sizeof (check)) == 0);
381 }
382
383 beginTest ("writing OSC type tag strings");
384 {
385 {
386 OSCOutputStream outStream;
387
388 OSCTypeList list;
389
390 const char check[4] = { ',', '\0', '\0', '\0' };
391 expect (outStream.writeTypeTagString (list));
392 expect (outStream.getDataSize() == 4);
393 expect (std::memcmp (outStream.getData(), check, sizeof (check)) == 0);
394 }
395
396 {
397 OSCOutputStream outStream;
398
399 OSCTypeList list;
400 list.add (OSCTypes::int32);
401 list.add (OSCTypes::float32);
402
403 const char check[4] = { ',', 'i', 'f', '\0' };
404 expect (outStream.writeTypeTagString (list));
405 expect (outStream.getDataSize() == sizeof (check));
406 expect (std::memcmp (outStream.getData(), check, sizeof (check)) == 0);
407 }
408
409 {
410 OSCOutputStream outStream;
411
412 OSCTypeList list;
413 list.add (OSCTypes::blob);
414 list.add (OSCTypes::blob);
415 list.add (OSCTypes::string);
416
417 const char check[8] = { ',', 'b', 'b', 's', '\0', '\0', '\0', '\0' };
418 expect (outStream.writeTypeTagString (list));
419 expect (outStream.getDataSize() == sizeof (check));
420 expect (std::memcmp (outStream.getData(), check, sizeof (check)) == 0);
421 }
422 }
423
424 beginTest ("writing OSC arguments");
425 {
426 // test data:
427 int testInt = -2015;
428 const uint8 testIntRepresentation[] = { 0xFF, 0xFF, 0xF8, 0x21 }; // big endian two's complement
429
430 float testFloat = 345.6125f;
431 const uint8 testFloatRepresentation[] = { 0x43, 0xAC, 0xCE, 0x66 }; // big endian IEEE 754
432
433 String testString = "Hello, World!";
434 const char testStringRepresentation[] = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', '\0', '\0', '\0' }; // padded to size % 4 == 0
435
436 const uint8 testBlobData[] = { 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
437 const MemoryBlock testBlob (testBlobData, sizeof (testBlobData));
438 const uint8 testBlobRepresentation[] = { 0x00, 0x00, 0x00, 0x05, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x00, 0x00 }; // padded to size % 4 == 0
439
440 // write:
441
442 {
443 // int32:
444 OSCArgument arg (testInt);
445 OSCOutputStream outStream;
446
447 expect (outStream.writeArgument (arg));
448 expect (outStream.getDataSize() == 4);
450 }
451 {
452 // float32:
453 OSCArgument arg (testFloat);
454 OSCOutputStream outStream;
455
456 expect (outStream.writeArgument (arg));
457 expect (outStream.getDataSize() == 4);
459
460 }
461 {
462 // string:
463 expect (testString.length() % 4 != 0); // check whether we actually cover padding
464 static_assert (sizeof (testStringRepresentation) % 4 == 0, "Size must be a multiple of 4");
465
466 OSCArgument arg (testString);
467 OSCOutputStream outStream;
468
469 expect (outStream.writeArgument (arg));
470 expect (outStream.getDataSize() == sizeof (testStringRepresentation));
472
473 }
474 {
475 // blob:
476 expect (testBlob.getSize() % 4 != 0); // check whether we actually cover padding
477 static_assert (sizeof (testBlobRepresentation) % 4 == 0, "Size must be a multiple of 4");
478
479 OSCArgument arg (testBlob);
480 OSCOutputStream outStream;
481
482 expect (outStream.writeArgument (arg));
483 expect (outStream.getDataSize() == sizeof (testBlobRepresentation));
485
486 }
487 }
488
489 beginTest ("Writing strings with correct padding");
490 {
491 // the only OSC-specific thing to check is the correct number of padding zeros
492
493 {
494 OSCArgument with15Chars ("123456789012345");
495 OSCOutputStream outStream;
496 expect (outStream.writeArgument (with15Chars));
497 expect (outStream.getDataSize() == 16);
498 }
499 {
500 OSCArgument with16Chars ("1234567890123456");
501 OSCOutputStream outStream;
502 expect (outStream.writeArgument (with16Chars));
503 expect (outStream.getDataSize() == 20);
504 }
505 {
506 OSCArgument with17Chars ("12345678901234567");
507 OSCOutputStream outStream;
508 expect (outStream.writeArgument (with17Chars));
509 expect (outStream.getDataSize() == 20);
510 }
511 {
512
513 OSCArgument with18Chars ("123456789012345678");
514 OSCOutputStream outStream;
515 expect (outStream.writeArgument (with18Chars));
516 expect (outStream.getDataSize() == 20);
517 }
518 {
519
520 OSCArgument with19Chars ("1234567890123456789");
521 OSCOutputStream outStream;
522 expect (outStream.writeArgument (with19Chars));
523 expect (outStream.getDataSize() == 20);
524 }
525 {
526
527 OSCArgument with20Chars ("12345678901234567890");
528 OSCOutputStream outStream;
529 expect (outStream.writeArgument (with20Chars));
530 expect (outStream.getDataSize() == 24);
531 }
532 }
533 beginTest ("Writing blobs with correct padding");
534 {
535 const char buffer[20] = {};
536 {
537 OSCArgument with15Bytes (MemoryBlock (buffer, 15));
538 OSCOutputStream outStream;
539 expect (outStream.writeArgument (with15Bytes));
540 expect (outStream.getDataSize() == 20);
541 }
542 {
543 OSCArgument with16Bytes (MemoryBlock (buffer, 16));
544 OSCOutputStream outStream;
545 expect (outStream.writeArgument (with16Bytes));
546 expect (outStream.getDataSize() == 20);
547 }
548 {
549 OSCArgument with17Bytes (MemoryBlock (buffer, 17));
550 OSCOutputStream outStream;
551 expect (outStream.writeArgument (with17Bytes));
552 expect (outStream.getDataSize() == 24);
553 }
554 {
555 OSCArgument with18Bytes (MemoryBlock (buffer, 18));
556 OSCOutputStream outStream;
557 expect (outStream.writeArgument (with18Bytes));
558 expect (outStream.getDataSize() == 24);
559 }
560 {
561 OSCArgument with19Bytes (MemoryBlock (buffer, 19));
562 OSCOutputStream outStream;
563 expect (outStream.writeArgument (with19Bytes));
564 expect (outStream.getDataSize() == 24);
565 }
566 {
567 OSCArgument with20Bytes (MemoryBlock (buffer, 20));
568 OSCOutputStream outStream;
569 expect (outStream.writeArgument (with20Bytes));
570 expect (outStream.getDataSize() == 24);
571 }
572 }
573
574 beginTest ("Writing OSC messages.");
575 {
576 {
577 int32 testInt = -2015;
578 float testFloat = 345.6125f;
579 String testString = "Hello, World!";
580
581 const uint8 testBlobData[] = { 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
582 const MemoryBlock testBlob (testBlobData, sizeof (testBlobData));
583
584 uint8 check[52] = { '/', 't', 'e', 's', 't', '\0', '\0', '\0',
585 ',', 'i', 'f', 's', 'b', '\0', '\0', '\0',
586 0xFF, 0xFF, 0xF8, 0x21,
587 0x43, 0xAC, 0xCE, 0x66,
588 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', '\0', '\0', '\0',
589 0x00, 0x00, 0x00, 0x05, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x00, 0x00
590 };
591
592 OSCOutputStream outStream;
593
594 OSCMessage msg ("/test");
595
596 msg.addInt32 (testInt);
597 msg.addFloat32 (testFloat);
598 msg.addString (testString);
599 msg.addBlob (testBlob);
600
601 expect (outStream.writeMessage (msg));
602 expect (outStream.getDataSize() == sizeof (check));
603 expect (std::memcmp (outStream.getData(), check, sizeof (check)) == 0);
604 }
605 }
606
607 beginTest ("Writing OSC bundle.");
608 {
609 {
610 int32 testInt = -2015;
611 float testFloat = 345.6125f;
612 String testString = "Hello, World!";
613 const uint8 testBlobData[] = { 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
614 const MemoryBlock testBlob (testBlobData, sizeof (testBlobData));
615
616 uint8 check[] = {
617 '#', 'b', 'u', 'n', 'd', 'l', 'e', '\0',
618 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
619
620 0x00, 0x00, 0x00, 0x34,
621
622 '/', 't', 'e', 's', 't', '/', '1', '\0',
623 ',', 'i', 'f', 's', 'b', '\0', '\0', '\0',
624 0xFF, 0xFF, 0xF8, 0x21,
625 0x43, 0xAC, 0xCE, 0x66,
626 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', '\0', '\0', '\0',
627 0x00, 0x00, 0x00, 0x05, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x00, 0x00,
628
629 0x00, 0x00, 0x00, 0x0C,
630
631 '/', 't', 'e', 's', 't', '/', '2', '\0',
632 ',', '\0', '\0', '\0',
633
634 0x00, 0x00, 0x00, 0x10,
635
636 '#', 'b', 'u', 'n', 'd', 'l', 'e', '\0',
637 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
638 };
639
640 OSCOutputStream outStream;
641
642 OSCBundle bundle;
643
644 OSCMessage msg1 ("/test/1");
645 msg1.addInt32 (testInt);
646 msg1.addFloat32 (testFloat);
647 msg1.addString (testString);
648 msg1.addBlob (testBlob);
649 bundle.addElement (msg1);
650
651 OSCMessage msg2 ("/test/2");
652 bundle.addElement (msg2);
653
654 OSCBundle subBundle;
655 bundle.addElement (subBundle);
656
657 expect (outStream.writeBundle (bundle));
658 expect (outStream.getDataSize() == sizeof (check));
659 expect (std::memcmp (outStream.getData(), check, sizeof (check)) == 0);
660 }
661 }
662 }
663};
664
666
667//==============================================================================
668class OSCRoundTripTests final : public UnitTest
669{
670public:
672 : UnitTest ("OSCRoundTripTests class", UnitTestCategories::osc)
673 {}
674
675 void runTest() override
676 {
677 beginTest ("Empty OSC message");
678 {
679 OSCMessage outMessage ("/test/empty");
680
681 OSCOutputStream output;
682 output.writeMessage (outMessage);
683
684 OSCInputStream input (output.getData(), output.getDataSize());
685 OSCMessage inMessage = input.readMessage();
686
687 expectEquals (inMessage.size(), 0);
688 }
689
690 beginTest ("OSC message with single argument");
691 {
692 OSCMessage outMessage ("/test/one_arg", 42);
693
694 OSCOutputStream output;
695 output.writeMessage (outMessage);
696
697 OSCInputStream input (output.getData(), output.getDataSize());
698 OSCMessage inMessage = input.readMessage();
699
700 expectEquals (inMessage.size(), 1);
701 expectEquals (inMessage[0].getInt32(), 42);
702 }
703
704 beginTest ("OSC message with multiple arguments");
705 {
706 OSCMessage outMessage ("/test/four_args", 42, 0.5f, String ("foo"), String ("bar"));
707
708 OSCOutputStream output;
709 output.writeMessage (outMessage);
710
711 OSCInputStream input (output.getData(), output.getDataSize());
712 OSCMessage inMessage = input.readMessage();
713
714 expectEquals (inMessage.size(), 4);
715 expectEquals (inMessage[0].getInt32(), 42);
716 expectEquals (inMessage[1].getFloat32(), 0.5f);
717 expectEquals (inMessage[2].getString(), String ("foo"));
718 expectEquals (inMessage[3].getString(), String ("bar"));
719 }
720
721 beginTest ("Empty OSC bundle");
722 {
723 OSCBundle outBundle;
724
725 OSCOutputStream output;
726 output.writeBundle (outBundle);
727
728 OSCInputStream input (output.getData(), output.getDataSize());
729 OSCBundle inBundle = input.readBundle();
730
731 expectEquals (inBundle.size(), 0);
732 }
733
734 beginTest ("OSC bundle with single message");
735 {
736 OSCMessage outMessage ("/test/one_arg", 42);
737 OSCBundle outBundle;
738 outBundle.addElement (outMessage);
739
740 OSCOutputStream output;
741 output.writeBundle (outBundle);
742
743 OSCInputStream input (output.getData(), output.getDataSize());
744 OSCBundle inBundle = input.readBundle();
745
746 expectEquals (inBundle.size(), 1);
747
748 OSCMessage inMessage = inBundle[0].getMessage();
749
750 expectEquals (inMessage.getAddressPattern().toString(), String ("/test/one_arg"));
751 expectEquals (inMessage.size(), 1);
752 expectEquals (inMessage[0].getInt32(), 42);
753 }
754
755 beginTest ("OSC bundle with multiple messages");
756 {
757 OSCMessage outMessage1 ("/test/empty");
758 OSCMessage outMessage2 ("/test/one_arg", 42);
759 OSCMessage outMessage3 ("/test/four_args", 42, 0.5f, String ("foo"), String ("bar"));
760
761 OSCBundle outBundle;
762 outBundle.addElement (outMessage1);
763 outBundle.addElement (outMessage2);
764 outBundle.addElement (outMessage3);
765
766 OSCOutputStream output;
767 output.writeBundle (outBundle);
768
769 OSCInputStream input (output.getData(), output.getDataSize());
770 OSCBundle inBundle = input.readBundle();
771
772 expectEquals (inBundle.size(), 3);
773
774 {
775 OSCMessage inMessage = inBundle[0].getMessage();
776
777 expectEquals (inMessage.getAddressPattern().toString(), String ("/test/empty"));
778 expectEquals (inMessage.size(), 0);
779 }
780 {
781 OSCMessage inMessage = inBundle[1].getMessage();
782
783 expectEquals (inMessage.getAddressPattern().toString(), String ("/test/one_arg"));
784 expectEquals (inMessage.size(), 1);
785 expectEquals (inMessage[0].getInt32(), 42);
786 }
787 {
788 OSCMessage inMessage = inBundle[2].getMessage();
789
790 expectEquals (inMessage.getAddressPattern().toString(), String ("/test/four_args"));
791 expectEquals (inMessage.size(), 4);
792 expectEquals (inMessage[0].getInt32(), 42);
793 expectEquals (inMessage[1].getFloat32(), 0.5f);
794 expectEquals (inMessage[2].getString(), String ("foo"));
795 expectEquals (inMessage[3].getString(), String ("bar"));
796 }
797 }
798
799 beginTest ("OSC bundle containing another bundle");
800 {
801 OSCBundle outBundleNested;
802 outBundleNested.addElement (OSCMessage ("/test/one_arg", 42));
803
804 OSCBundle outBundle;
805 outBundle.addElement (outBundleNested);
806
807 OSCOutputStream output;
808 output.writeBundle (outBundle);
809
810 OSCInputStream input (output.getData(), output.getDataSize());
811 OSCBundle inBundle = input.readBundle();
812
813 expectEquals (inBundle.size(), 1);
814 expect (inBundle[0].isBundle());
815 OSCBundle inBundleNested = inBundle[0].getBundle();
816 expectEquals (inBundleNested.size(), 1);
817 expect (inBundleNested[0].isMessage());
818
819 OSCMessage msg = inBundleNested[0].getMessage();
820
821 expectEquals (msg.getAddressPattern().toString(), String ("/test/one_arg"));
822 expectEquals (msg.size(), 1);
823 expectEquals (msg[0].getInt32(), 42);
824 }
825
826 beginTest ("OSC bundle containing multiple other bundles");
827 {
828 OSCBundle outBundleNested1;
829 outBundleNested1.addElement (OSCMessage ("/test/empty"));
830 OSCBundle outBundleNested2;
831 outBundleNested2.addElement (OSCMessage ("/test/one_arg", 42));
832
833 OSCBundle outBundle;
834 outBundle.addElement (outBundleNested1);
835 outBundle.addElement (outBundleNested2);
836
837 OSCOutputStream output;
838 output.writeBundle (outBundle);
839
840 OSCInputStream input (output.getData(), output.getDataSize());
841 OSCBundle inBundle = input.readBundle();
842
843 expectEquals (inBundle.size(), 2);
844
845 {
846 expect (inBundle[0].isBundle());
847 OSCBundle inBundleNested = inBundle[0].getBundle();
848 expectEquals (inBundleNested.size(), 1);
849 expect (inBundleNested[0].isMessage());
850
851 OSCMessage msg = inBundleNested[0].getMessage();
852
853 expectEquals (msg.getAddressPattern().toString(), String ("/test/empty"));
854 expectEquals (msg.size(), 0);
855 }
856 {
857 expect (inBundle[1].isBundle());
858 OSCBundle inBundleNested = inBundle[1].getBundle();
859 expectEquals (inBundleNested.size(), 1);
860 expect (inBundleNested[0].isMessage());
861
862 OSCMessage msg = inBundleNested[0].getMessage();
863
864 expectEquals (msg.getAddressPattern().toString(), String ("/test/one_arg"));
865 expectEquals (msg.size(), 1);
866 expectEquals (msg[0].getInt32(), 42);
867 }
868 }
869 }
870};
871
873
874#endif
875
876} // namespace juce
A wrapper for a datagram (UDP) socket.
An OSC bundle.
An OSC Message.
bool connectToSocket(DatagramSocket &socket, const String &targetHostName, int targetPortNumber)
Uses an existing datagram socket for sending OSC packets to the specified target.
bool disconnect()
Disconnects from the currently used UDP port.
~OSCSender()
Destructor.
OSCSender()
Constructs a new OSCSender.
bool connect(const String &targetHostName, int targetPortNumber)
Connects to a datagram socket and prepares the socket for sending OSC packets to the specified target...
bool sendToIPAddress(const String &targetIPAddress, int targetPortNumber, const OSCMessage &message)
Sends an OSC message to a specific IP address and port.
bool send(const OSCMessage &message)
Sends an OSC message to the target.
Holds a pointer to an object which can optionally be deleted when this pointer goes out of scope.
The JUCE String class!
Definition juce_String.h:53
This is a base class for classes that perform a unit test.
#define JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className)
This is a shorthand way of writing both a JUCE_DECLARE_NON_COPYABLE and JUCE_LEAK_DETECTOR macro for ...
#define jassertfalse
This will always cause an assertion failure.
typedef int
T memcmp(T... args)
JUCE Namespace.
signed int int32
A platform-independent 32-bit signed integer type.
Array< OSCType > OSCTypeList
The type used for OSC type tag strings.
unsigned long long uint64
A platform-independent 64-bit unsigned integer type.
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
Definition juce_Memory.h:88
unsigned char uint8
A platform-independent 8-bit unsigned integer type.
long long int64
A platform-independent 64-bit integer type.
T reset(T... args)
socket
typedef size_t