50 OSCInputStream (
const void* sourceData,
size_t sourceDataSize)
51 : input (sourceData, sourceDataSize, false)
56 const void* getData() const noexcept {
return input.getData(); }
59 size_t getDataSize() const noexcept {
return input.getDataSize(); }
62 uint64 getPosition() {
return (
uint64) input.getPosition(); }
65 bool setPosition (
int64 pos) {
return input.setPosition (pos); }
68 int64 getTotalLength() {
return input.getTotalLength(); }
71 bool isExhausted() {
return input.isExhausted(); }
76 checkBytesAvailable (4,
"OSC input stream exhausted while reading int32");
77 return input.readIntBigEndian();
82 checkBytesAvailable (8,
"OSC input stream exhausted while reading uint64");
83 return (
uint64) input.readInt64BigEndian();
88 checkBytesAvailable (4,
"OSC input stream exhausted while reading float");
89 return input.readFloatBigEndian();
94 checkBytesAvailable (4,
"OSC input stream exhausted while reading string");
96 auto posBegin = (
size_t) getPosition();
97 auto s = input.readString();
98 auto posEnd = (
size_t) getPosition();
100 if (
static_cast<const char*
> (getData()) [posEnd - 1] !=
'\0')
101 throw OSCFormatError (
"OSC input stream exhausted before finding null terminator of string");
103 size_t bytesRead = posEnd - posBegin;
104 readPaddingZeros (bytesRead);
109 MemoryBlock readBlob()
111 checkBytesAvailable (4,
"OSC input stream exhausted while reading blob");
113 auto blobDataSize = input.readIntBigEndian();
114 checkBytesAvailable ((blobDataSize + 3) % 4,
"OSC input stream exhausted before reaching end of blob");
117 auto bytesRead = input.readIntoMemoryBlock (blob, (ssize_t) blobDataSize);
118 readPaddingZeros (bytesRead);
123 OSCColour readColour()
125 checkBytesAvailable (4,
"OSC input stream exhausted while reading colour");
126 return OSCColour::fromInt32 ((
uint32) input.readIntBigEndian());
129 OSCTimeTag readTimeTag()
131 checkBytesAvailable (8,
"OSC input stream exhausted while reading time tag");
132 return OSCTimeTag (
uint64 (input.readInt64BigEndian()));
135 OSCAddress readAddress()
137 return OSCAddress (readString());
140 OSCAddressPattern readAddressPattern()
142 return OSCAddressPattern (readString());
150 checkBytesAvailable (4,
"OSC input stream exhausted while reading type tag string");
152 if (input.readByte() !=
',')
153 throw OSCFormatError (
"OSC input stream format error: expected type tag string");
158 throw OSCFormatError (
"OSC input stream exhausted while reading type tag string");
160 const OSCType type = input.readByte();
165 if (! OSCTypes::isSupportedType (type))
166 throw OSCFormatError (
"OSC input stream format error: encountered unsupported type tag");
171 auto bytesRead = (
size_t) typeList.size() + 2;
172 readPaddingZeros (bytesRead);
178 OSCArgument readArgument (
OSCType type)
182 case OSCTypes::int32:
return OSCArgument (readInt32());
183 case OSCTypes::float32:
return OSCArgument (readFloat32());
184 case OSCTypes::string:
return OSCArgument (readString());
185 case OSCTypes::blob:
return OSCArgument (readBlob());
186 case OSCTypes::colour:
return OSCArgument (readColour());
191 throw OSCInternalError (
"OSC input stream: internal error while reading message argument");
196 OSCMessage readMessage()
198 auto ap = readAddressPattern();
199 auto types = readTypeTagString();
203 for (
auto& type : types)
204 msg.addArgument (readArgument (type));
216 checkBytesAvailable (16,
"OSC input stream exhausted while reading bundle");
218 if (readString() !=
"#bundle")
219 throw OSCFormatError (
"OSC input stream format error: bundle does not start with string '#bundle'");
221 OSCBundle bundle (readTimeTag());
223 size_t bytesRead = 16;
224 auto pos = getPosition();
226 while (! isExhausted() && bytesRead < maxBytesToRead)
228 bundle.addElement (readElement());
230 auto newPos = getPosition();
231 bytesRead += (
size_t) (newPos - pos);
239 OSCBundle::Element readElement()
241 checkBytesAvailable (4,
"OSC input stream exhausted while reading bundle element size");
243 auto elementSize = (
size_t) readInt32();
246 throw OSCFormatError (
"OSC input stream format error: invalid bundle element size");
248 return readElementWithKnownSize (elementSize);
252 OSCBundle::Element readElementWithKnownSize (
size_t elementSize)
254 checkBytesAvailable ((
int64) elementSize,
"OSC input stream exhausted while reading bundle element content");
256 auto firstContentChar =
static_cast<const char*
> (getData()) [getPosition()];
258 if (firstContentChar ==
'/')
return OSCBundle::Element (readMessageWithCheckedSize (elementSize));
259 if (firstContentChar ==
'#')
return OSCBundle::Element (readBundleWithCheckedSize (elementSize));
261 throw OSCFormatError (
"OSC input stream: invalid bundle element content");
265 MemoryInputStream input;
268 void readPaddingZeros (
size_t bytesRead)
270 size_t numZeros = ~(bytesRead - 1) & 0x03;
274 if (isExhausted() || input.readByte() != 0)
275 throw OSCFormatError (
"OSC input stream format error: missing padding zeros");
281 OSCBundle readBundleWithCheckedSize (
size_t size)
284 auto maxBytesToRead =
size - 4;
286 OSCBundle bundle (readBundle (maxBytesToRead));
288 if (getPosition() -
begin != size)
289 throw OSCFormatError (
"OSC input stream format error: wrong element content size encountered while reading");
294 OSCMessage readMessageWithCheckedSize (
size_t size)
297 auto message = readMessage();
299 if (getPosition() -
begin != size)
300 throw OSCFormatError (
"OSC input stream format error: wrong element content size encountered while reading");
305 void checkBytesAvailable (
int64 requiredBytes,
const char* message)
307 if (input.getNumBytesRemaining() < requiredBytes)
308 throw OSCFormatError (message);
329 bool connectToPort (
int portNumber)
336 if (! socket->bindToPort (portNumber))
348 socket.setNonOwned (&newSocket);
355 if (socket !=
nullptr)
359 if (socket.willDeleteObject())
372 listeners.add (listenerToAdd);
377 realtimeListeners.add (listenerToAdd);
383 addListenerWithAddress (listenerToAdd, addressToMatch, listenersWithAddress);
388 addListenerWithAddress (listenerToAdd, addressToMatch, realtimeListenersWithAddress);
393 listeners.remove (listenerToRemove);
398 realtimeListeners.remove (listenerToRemove);
403 removeListenerWithAddress (listenerToRemove, listenersWithAddress);
408 removeListenerWithAddress (listenerToRemove, realtimeListenersWithAddress);
421 void handleBuffer (
const char* data,
size_t dataSize)
423 OSCInputStream inStream (data, dataSize);
427 auto content = inStream.readElementWithKnownSize (dataSize);
431 callRealtimeListeners (content);
433 if (content.isMessage())
434 callRealtimeListenersWithAddress (content.getMessage());
438 if (listeners.size() > 0 || listenersWithAddress.size() > 0)
443 NullCheckedInvocation::invoke (formatErrorHandler, data, (
int) dataSize);
450 formatErrorHandler = handler;
457 int bufferSize = 65535;
458 HeapBlock<char> oscBuffer (bufferSize);
463 auto ready = socket->waitUntilReady (
true, 100);
471 auto bytesRead = (
size_t) socket->read (oscBuffer.getData(), bufferSize,
false);
474 handleBuffer (oscBuffer.getData(), bytesRead);
479 template <
typename ListenerType>
480 void addListenerWithAddress (ListenerType* listenerToAdd,
484 for (
auto& i : array)
485 if (address == i.first && listenerToAdd == i.second)
492 template <
typename ListenerType>
493 void removeListenerWithAddress (ListenerType* listenerToRemove,
496 for (
int i = 0; i < array.size(); ++i)
498 if (listenerToRemove == array.getReference (i).second)
503 array.swap (i, array.size() - 1);
511 void handleMessage (
const Message& msg)
override
513 if (
auto* callbackMessage =
dynamic_cast<const CallbackMessage*
> (&msg))
515 auto& content = callbackMessage->content;
517 callListeners (content);
519 if (content.isMessage())
520 callListenersWithAddress (content.getMessage());
525 void callListeners (
const OSCBundle::Element& content)
527 using OSCListener = OSCReceiver::Listener<OSCReceiver::MessageLoopCallback>;
529 if (content.isMessage())
531 auto&& message = content.getMessage();
532 listeners.call ([&] (OSCListener& l) { l.oscMessageReceived (message); });
534 else if (content.isBundle())
536 auto&& bundle = content.getBundle();
537 listeners.call ([&] (OSCListener& l) { l.oscBundleReceived (bundle); });
541 void callRealtimeListeners (
const OSCBundle::Element& content)
543 using OSCListener = OSCReceiver::Listener<OSCReceiver::RealtimeCallback>;
545 if (content.isMessage())
547 auto&& message = content.getMessage();
548 realtimeListeners.call ([&] (OSCListener& l) { l.oscMessageReceived (message); });
550 else if (content.isBundle())
552 auto&& bundle = content.getBundle();
553 realtimeListeners.call ([&] (OSCListener& l) { l.oscBundleReceived (bundle); });
558 void callListenersWithAddress (
const OSCMessage& message)
560 for (
auto& entry : listenersWithAddress)
561 if (auto* listener = entry.second)
562 if (message.getAddressPattern().matches (entry.first))
563 listener->oscMessageReceived (message);
566 void callRealtimeListenersWithAddress (
const OSCMessage& message)
568 for (
auto& entry : realtimeListenersWithAddress)
569 if (auto* listener = entry.second)
570 if (message.getAddressPattern().matches (entry.first))
571 listener->oscMessageReceived (message);
575 ListenerList<OSCReceiver::Listener<OSCReceiver::MessageLoopCallback>> listeners;
576 ListenerList<OSCReceiver::Listener<OSCReceiver::RealtimeCallback>> realtimeListeners;
578 Array<std::pair<OSCAddress, OSCReceiver::ListenerWithOSCAddress<OSCReceiver::MessageLoopCallback>*>> listenersWithAddress;
579 Array<std::pair<OSCAddress, OSCReceiver::ListenerWithOSCAddress<OSCReceiver::RealtimeCallback>*>> realtimeListenersWithAddress;
581 OptionalScopedPointer<DatagramSocket> socket;
603 return pimpl->connectToPort (portNumber);
608 return pimpl->connectToSocket (
socket);
613 return pimpl->disconnect();
618 pimpl->addListener (listenerToAdd);
623 pimpl->addListener (listenerToAdd);
628 pimpl->addListener (listenerToAdd, addressToMatch);
633 pimpl->addListener (listenerToAdd, addressToMatch);
638 pimpl->removeListener (listenerToRemove);
643 pimpl->removeListener (listenerToRemove);
648 pimpl->removeListener (listenerToRemove);
653 pimpl->removeListener (listenerToRemove);
658 pimpl->registerFormatErrorHandler (handler);
666class OSCInputStreamTests final :
public UnitTest
669 OSCInputStreamTests()
670 :
UnitTest (
"OSCInputStream class", UnitTestCategories::osc)
673 void runTest()
override
675 beginTest (
"reading OSC addresses");
677 const char buffer[16] = {
678 '/',
't',
'e',
's',
't',
'/',
'f',
'a',
679 'd',
'e',
'r',
'7',
'\0',
'\0',
'\0',
'\0' };
683 OSCInputStream inStream (buffer,
sizeof (buffer));
684 OSCAddress address = inStream.readAddress();
686 expect (inStream.getPosition() == sizeof (buffer));
687 expectEquals (address.toString(), String (
"/test/fader7"));
693 OSCInputStream inStream (buffer, 15);
698 OSCInputStream inStream (buffer, 12);
703 OSCInputStream inStream (buffer + 4, 12);
708 beginTest (
"reading OSC address patterns");
710 const char buffer[20] = {
711 '/',
'*',
'/',
'*',
'p',
'u',
't',
'/',
712 'f',
'a',
'd',
'e',
'r',
'[',
'0',
'-',
713 '9',
']',
'\0',
'\0' };
717 OSCInputStream inStream (buffer,
sizeof (buffer));
721 OSCInputStream inStream (buffer,
sizeof (buffer));
722 OSCAddressPattern ap = inStream.readAddressPattern();
724 expect (inStream.getPosition() == sizeof (buffer));
725 expectEquals (ap.toString(), String (
"/*/*put/fader[0-9]"));
726 expect (ap.containsWildcards());
732 OSCInputStream inStream (buffer, 19);
737 OSCInputStream inStream (buffer, 16);
742 OSCInputStream inStream (buffer + 4, 16);
747 beginTest (
"reading OSC time tags");
750 char buffer[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };
751 OSCInputStream inStream (buffer,
sizeof (buffer));
753 OSCTimeTag tag = inStream.readTimeTag();
754 expect (tag.isImmediately());
757 char buffer[8] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
758 OSCInputStream inStream (buffer,
sizeof (buffer));
760 OSCTimeTag tag = inStream.readTimeTag();
761 expect (! tag.isImmediately());
764 beginTest (
"reading OSC arguments");
769 const uint8 testIntRepresentation[] = { 0xFF, 0xFF, 0xF8, 0x21 };
771 float testFloat = 345.6125f;
772 const uint8 testFloatRepresentation[] = { 0x43, 0xAC, 0xCE, 0x66 };
774 String testString =
"Hello, World!";
775 const char testStringRepresentation[] = {
776 'H',
'e',
'l',
'l',
'o',
',',
' ',
'W',
777 'o',
'r',
'l',
'd',
'!',
'\0',
'\0',
'\0' };
779 const uint8 testBlobData[] = { 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
780 const MemoryBlock testBlob (testBlobData,
sizeof (testBlobData));
781 const uint8 testBlobRepresentation[] = {
782 0x00, 0x00, 0x00, 0x05,
783 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x00, 0x00 };
789 OSCInputStream inStream (testIntRepresentation,
sizeof (testIntRepresentation));
790 OSCArgument arg = inStream.readArgument (OSCTypes::int32);
792 expect (inStream.getPosition() == 4);
793 expect (arg.isInt32());
794 expectEquals (arg.getInt32(), testInt);
798 OSCInputStream inStream (testFloatRepresentation,
sizeof (testFloatRepresentation));
799 OSCArgument arg = inStream.readArgument (OSCTypes::float32);
801 expect (inStream.getPosition() == 4);
802 expect (arg.isFloat32());
803 expectEquals (arg.getFloat32(), testFloat);
807 OSCInputStream inStream (testStringRepresentation,
sizeof (testStringRepresentation));
808 OSCArgument arg = inStream.readArgument (OSCTypes::string);
810 expect (inStream.getPosition() == sizeof (testStringRepresentation));
811 expect (arg.isString());
812 expectEquals (arg.getString(), testString);
816 OSCInputStream inStream (testBlobRepresentation,
sizeof (testBlobRepresentation));
817 OSCArgument arg = inStream.readArgument (OSCTypes::blob);
819 expect (inStream.getPosition() == sizeof (testBlobRepresentation));
820 expect (arg.isBlob());
821 expect (arg.getBlob() == testBlob);
830 const uint8 rawData[] = { 0xF8, 0x21 };
832 OSCInputStream inStream (rawData,
sizeof (rawData));
835 expectThrowsType (inStream.readArgument (OSCTypes::float32), OSCFormatError);
840 const char rawData[] = {
841 'H',
'e',
'l',
'l',
'o',
',',
' ',
'W',
842 'o',
'r',
'l',
'd',
'!',
'\0' };
844 OSCInputStream inStream (rawData,
sizeof (rawData));
846 expectThrowsType (inStream.readArgument (OSCTypes::string), OSCFormatError);
849 const char rawData[] = {
850 'H',
'e',
'l',
'l',
'o',
',',
' ',
'W',
851 'o',
'r',
'l',
'd',
'!',
'\0',
'x',
'x' };
853 OSCInputStream inStream (rawData,
sizeof (rawData));
855 expectThrowsType (inStream.readArgument (OSCTypes::string), OSCFormatError);
860 const uint8 rawData[] = { 0x00, 0x00, 0x00, 0x05, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
862 OSCInputStream inStream (rawData,
sizeof (rawData));
869 const uint8 rawData[] = { 0x00, 0x00, 0x00, 0x12, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
871 OSCInputStream inStream (rawData,
sizeof (rawData));
878 beginTest (
"reading OSC messages (type tag string)");
882 const char data[] = {
883 '/',
't',
'e',
's',
't',
'\0',
'\0',
'\0',
884 ',',
'\0',
'\0',
'\0' };
886 OSCInputStream inStream (data,
sizeof (data));
888 auto msg = inStream.readMessage();
889 expect (msg.getAddressPattern().toString() ==
"/test");
890 expect (msg.size() == 0);
895 const char data[] = {
896 '/',
't',
'e',
's',
't',
'\0',
'\0',
'\0',
897 'H',
'e',
'l',
'l',
'o',
',',
' ',
'W',
898 'o',
'r',
'l',
'd',
'!',
'\0',
'\0',
'\0' };
900 OSCInputStream inStream (data,
sizeof (data));
907 const char data[] = {
'/',
't',
'e',
's',
't',
'\0',
'\0',
'\0' };
909 OSCInputStream inStream (data,
sizeof (data));
916 const char data[] = {
'/',
't',
'e',
's',
't',
'\0',
'\0',
'\0',
',',
'\0',
'\0',
'\0' };
917 OSCInputStream inStream (data,
sizeof (data) - 1);
924 const char data[] = {
'/',
't',
'e',
's',
't',
'\0',
'\0',
'\0',
',',
'i',
'\0',
'\0' };
925 OSCInputStream inStream (data,
sizeof (data));
932 const char data[] = {
'/',
't',
'e',
's',
't',
'\0',
'\0',
'\0',
',',
'i',
'f',
'\0' };
933 OSCInputStream inStream (data,
sizeof (data));
939 beginTest (
"reading OSC messages (contents)");
944 int32 testInt = -2015;
945 float testFloat = 345.6125f;
946 String testString =
"Hello, World!";
948 const uint8 testBlobData[] = { 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
949 const MemoryBlock testBlob (testBlobData,
sizeof (testBlobData));
952 '/',
't',
'e',
's',
't',
'\0',
'\0',
'\0',
953 ',',
'i',
'f',
's',
'b',
'\0',
'\0',
'\0',
954 0xFF, 0xFF, 0xF8, 0x21,
955 0x43, 0xAC, 0xCE, 0x66,
956 'H',
'e',
'l',
'l',
'o',
',',
' ',
'W',
'o',
'r',
'l',
'd',
'!',
'\0',
'\0',
'\0',
957 0x00, 0x00, 0x00, 0x05, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x00, 0x00
960 OSCInputStream inStream (data,
sizeof (data));
962 auto msg = inStream.readMessage();
964 expectEquals (msg.getAddressPattern().toString(), String (
"/test"));
965 expectEquals (msg.size(), 4);
967 expectEquals (msg[0].getType(), OSCTypes::int32);
968 expectEquals (msg[1].getType(), OSCTypes::float32);
969 expectEquals (msg[2].getType(), OSCTypes::string);
970 expectEquals (msg[3].getType(), OSCTypes::blob);
972 expectEquals (msg[0].getInt32(), testInt);
973 expectEquals (msg[1].getFloat32(), testFloat);
974 expectEquals (msg[2].getString(), testString);
975 expect (msg[3].getBlob() == testBlob);
978 beginTest (
"reading OSC messages (handling of corrupted messages)");
983 OSCInputStream inStream (
nullptr, 0);
988 const uint8
data[] = { 0x00 };
989 OSCInputStream inStream (data, 0);
995 '/',
't',
'e',
's',
't',
'\0',
'\0',
'\0',
996 ',',
'i',
'f',
's',
'b',
997 0xFF, 0xFF, 0xF8, 0x21,
998 0x43, 0xAC, 0xCE, 0x66,
999 'H',
'e',
'l',
'l',
'o',
',',
' ',
'W',
'o',
'r',
'l',
'd',
'!',
'\0',
'\0',
'\0',
1000 0x00, 0x00, 0x00, 0x05, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x00, 0x00
1003 OSCInputStream inStream (data,
sizeof (data));
1009 '/',
't',
'e',
's',
't',
'\0',
'\0',
'\0',
1010 ',',
'i',
'f',
's',
'b',
'\0',
'\0',
'\0',
1011 0xFF, 0xFF, 0xF8, 0x21,
1012 0x43, 0xAC, 0xCE, 0x66,
1013 'H',
'e',
'l',
'l',
'o',
',',
' ',
'W',
'o',
'r',
'l',
'd',
'!',
'\0',
'\0',
'\0'
1016 OSCInputStream inStream (data,
sizeof (data));
1021 beginTest (
"reading OSC messages (handling messages without type tag strings)");
1025 uint8
data[] = {
'/',
't',
'e',
's',
't',
'\0',
'\0',
'\0' };
1027 OSCInputStream inStream (data,
sizeof (data));
1033 '/',
't',
'e',
's',
't',
'\0',
'\0',
'\0',
1034 0xFF, 0xFF, 0xF8, 0x21,
1035 0x43, 0xAC, 0xCE, 0x66,
1036 'H',
'e',
'l',
'l',
'o',
',',
' ',
'W',
'o',
'r',
'l',
'd',
'!',
'\0',
'\0',
'\0',
1037 0x00, 0x00, 0x00, 0x05, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x00, 0x00
1040 OSCInputStream inStream (data,
sizeof (data));
1045 beginTest (
"reading OSC bundles");
1050 '#',
'b',
'u',
'n',
'd',
'l',
'e',
'\0',
1051 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
1054 OSCInputStream inStream (data,
sizeof (data));
1055 OSCBundle bundle = inStream.readBundle();
1057 expect (bundle.getTimeTag().isImmediately());
1058 expect (bundle.size() == 0);
1064 int32 testInt = -2015;
1065 float testFloat = 345.6125f;
1066 String testString =
"Hello, World!";
1067 const uint8 testBlobData[] = { 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
1068 const MemoryBlock testBlob (testBlobData,
sizeof (testBlobData));
1071 '#',
'b',
'u',
'n',
'd',
'l',
'e',
'\0',
1072 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
1074 0x00, 0x00, 0x00, 0x34,
1076 '/',
't',
'e',
's',
't',
'/',
'1',
'\0',
1077 ',',
'i',
'f',
's',
'b',
'\0',
'\0',
'\0',
1078 0xFF, 0xFF, 0xF8, 0x21,
1079 0x43, 0xAC, 0xCE, 0x66,
1080 'H',
'e',
'l',
'l',
'o',
',',
' ',
'W',
'o',
'r',
'l',
'd',
'!',
'\0',
'\0',
'\0',
1081 0x00, 0x00, 0x00, 0x05, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x00, 0x00,
1083 0x00, 0x00, 0x00, 0x0C,
1085 '/',
't',
'e',
's',
't',
'/',
'2',
'\0',
1086 ',',
'\0',
'\0',
'\0',
1088 0x00, 0x00, 0x00, 0x10,
1090 '#',
'b',
'u',
'n',
'd',
'l',
'e',
'\0',
1091 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
1094 OSCInputStream inStream (data,
sizeof (data));
1095 OSCBundle bundle = inStream.readBundle();
1097 expect (bundle.getTimeTag().isImmediately());
1098 expect (bundle.size() == 3);
1100 OSCBundle::Element* elements = bundle.begin();
1102 expect (elements[0].isMessage());
1103 expect (elements[0].getMessage().getAddressPattern().
toString() ==
"/test/1");
1104 expect (elements[0].getMessage().
size() == 4);
1105 expect (elements[0].getMessage()[0].isInt32());
1106 expect (elements[0].getMessage()[1].isFloat32());
1107 expect (elements[0].getMessage()[2].isString());
1108 expect (elements[0].getMessage()[3].isBlob());
1109 expectEquals (elements[0].getMessage()[0].getInt32(), testInt);
1110 expectEquals (elements[0].getMessage()[1].getFloat32(), testFloat);
1111 expectEquals (elements[0].getMessage()[2].getString(), testString);
1112 expect (elements[0].getMessage()[3].getBlob() == testBlob);
1114 expect (elements[1].isMessage());
1115 expect (elements[1].getMessage().getAddressPattern().
toString() ==
"/test/2");
1116 expect (elements[1].getMessage().
size() == 0);
1118 expect (elements[2].isBundle());
1119 expect (! elements[2].getBundle().getTimeTag().isImmediately());
1126 '#',
'b',
'u',
'n',
'd',
'l',
'e',
'\0',
1127 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
1129 0x00, 0x00, 0x00, 0x34,
1131 '/',
't',
'e',
's',
't',
'/',
'1',
'\0',
1132 ',',
's',
'\0',
'\0',
1133 'H',
'e',
'l',
'l',
'o',
',',
' ',
'W',
'o',
'r',
'l',
'd',
'!',
'\0',
'\0',
'\0'
1136 OSCInputStream inStream (data,
sizeof (data));
1142 '#',
'b',
'u',
'n',
'd',
'l',
'e',
'\0',
1143 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
1145 0x00, 0x00, 0x00, 0x08,
1147 '/',
't',
'e',
's',
't',
'/',
'1',
'\0',
1148 ',',
's',
'\0',
'\0',
1149 'H',
'e',
'l',
'l',
'o',
',',
' ',
'W',
'o',
'r',
'l',
'd',
'!',
'\0',
'\0',
'\0'
1152 OSCInputStream inStream (data,
sizeof (data));
1158 '#',
'b',
'u',
'n',
'd',
'l',
'e',
'\0',
1159 0x00, 0x00, 0x00, 0x00
1162 OSCInputStream inStream (data,
sizeof (data));
1168 '#',
'b',
'u',
'n',
'x',
'l',
'e',
'\0',
1169 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1172 OSCInputStream inStream (data,
sizeof (data));
1178 '#',
'b',
'u',
'n',
'd',
'l',
'e',
1179 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1182 OSCInputStream inStream (data,
sizeof (data));
1189static OSCInputStreamTests OSCInputStreamUnitTests;
A wrapper for a datagram (UDP) socket.
MessageListener subclasses can post and receive Message objects.
void postMessage(Message *message) const
Sends a message to the message queue, for asynchronous delivery to this listener later on.
The base class for objects that can be sent to a MessageListener.
A class for receiving only those OSC messages from an OSCReceiver that match a given OSC address.
A class for receiving OSC data from an OSCReceiver.
A class for receiving OSC data.
bool connect(int portNumber)
Connects to the specified UDP port using a datagram socket, and starts listening to OSC packets arriv...
~OSCReceiver()
Destructor.
bool connectToSocket(DatagramSocket &socketToUse)
Connects to a UDP datagram socket that is already set up, and starts listening to OSC packets arrivin...
OSCReceiver()
Creates an OSCReceiver.
bool disconnect()
Disconnects from the currently used UDP port.
std::function< void(const char *data, int dataSize)> FormatErrorHandler
An error handler function for OSC format errors that can be called by the OSCReceiver.
void registerFormatErrorHandler(FormatErrorHandler handler)
Installs a custom error handler which is called in case the receiver encounters a stream it cannot pa...
void addListener(Listener< MessageLoopCallback > *listenerToAdd)
Adds a listener that listens to OSC messages and bundles.
void removeListener(Listener< MessageLoopCallback > *listenerToRemove)
Removes a previously-registered listener.
bool waitForThreadToExit(int timeOutMilliseconds) const
Waits for the thread to stop.
bool startThread()
Attempts to start a new thread with default ('Priority::normal') priority.
bool threadShouldExit() const
Checks whether the thread has been told to stop running.
void signalThreadShouldExit()
Sets a flag to tell the thread it should stop.
This is a base class for classes that perform a unit test.
#define expectDoesNotThrow(expr)
Checks that the result of an expression does not throw an exception.
#define expectThrowsType(expr, type)
Checks that the result of an expression throws an exception of a certain type.
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.
char OSCType
The type used for OSC type tags.
unsigned int uint32
A platform-independent 32-bit unsigned integer type.
RangedDirectoryIterator begin(const RangedDirectoryIterator &it)
Returns the iterator that was passed in.
long long int64
A platform-independent 64-bit integer type.
std::u16string toString(NumberT value)
convert an number to an UTF-16 string