|
- /*
- ==============================================================================
-
- This file is part of the JUCE library.
- Copyright (c) 2020 - Raw Material Software Limited
-
- JUCE is an open source library subject to commercial or open-source
- licensing.
-
- By using JUCE, you agree to the terms of both the JUCE 6 End-User License
- Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
-
- End User License Agreement: www.juce.com/juce-6-licence
- Privacy Policy: www.juce.com/juce-privacy-policy
-
- Or: You may also use this code under the terms of the GPL v3 (see
- www.gnu.org/licenses).
-
- JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
- EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
- DISCLAIMED.
-
- ==============================================================================
- */
-
- namespace juce
- {
-
- namespace
- {
- //==============================================================================
- /** Writes OSC data to an internal memory buffer, which grows as required.
-
- The data that was written into the stream can then be accessed later as
- a contiguous block of memory.
-
- This class implements the Open Sound Control 1.0 Specification for
- the format in which the OSC data will be written into the buffer.
- */
- struct OSCOutputStream
- {
- OSCOutputStream() noexcept {}
-
- /** Returns a pointer to the data that has been written to the stream. */
- const void* getData() const noexcept { return output.getData(); }
-
- /** Returns the number of bytes of data that have been written to the stream. */
- size_t getDataSize() const noexcept { return output.getDataSize(); }
-
- //==============================================================================
- bool writeInt32 (int32 value)
- {
- return output.writeIntBigEndian (value);
- }
-
- bool writeUint64 (uint64 value)
- {
- return output.writeInt64BigEndian (int64 (value));
- }
-
- bool writeFloat32 (float value)
- {
- return output.writeFloatBigEndian (value);
- }
-
- bool writeString (const String& value)
- {
- if (! output.writeString (value))
- return false;
-
- const size_t numPaddingZeros = ~value.getNumBytesAsUTF8() & 3;
-
- return output.writeRepeatedByte ('\0', numPaddingZeros);
- }
-
- bool writeBlob (const MemoryBlock& blob)
- {
- if (! (output.writeIntBigEndian ((int) blob.getSize())
- && output.write (blob.getData(), blob.getSize())))
- return false;
-
- const size_t numPaddingZeros = ~(blob.getSize() - 1) & 3;
-
- return output.writeRepeatedByte (0, numPaddingZeros);
- }
-
- bool writeColour (OSCColour colour)
- {
- return output.writeIntBigEndian ((int32) colour.toInt32());
- }
-
- bool writeTimeTag (OSCTimeTag timeTag)
- {
- return output.writeInt64BigEndian (int64 (timeTag.getRawTimeTag()));
- }
-
- bool writeAddress (const OSCAddress& address)
- {
- return writeString (address.toString());
- }
-
- bool writeAddressPattern (const OSCAddressPattern& ap)
- {
- return writeString (ap.toString());
- }
-
- bool writeTypeTagString (const OSCTypeList& typeList)
- {
- output.writeByte (',');
-
- if (typeList.size() > 0)
- output.write (typeList.begin(), (size_t) typeList.size());
-
- output.writeByte ('\0');
-
- size_t bytesWritten = (size_t) typeList.size() + 1;
- size_t numPaddingZeros = ~bytesWritten & 0x03;
-
- return output.writeRepeatedByte ('\0', numPaddingZeros);
- }
-
- bool writeArgument (const OSCArgument& arg)
- {
- switch (arg.getType())
- {
- case OSCTypes::int32: return writeInt32 (arg.getInt32());
- case OSCTypes::float32: return writeFloat32 (arg.getFloat32());
- case OSCTypes::string: return writeString (arg.getString());
- case OSCTypes::blob: return writeBlob (arg.getBlob());
- case OSCTypes::colour: return writeColour (arg.getColour());
-
- default:
- // In this very unlikely case you supplied an invalid OSCType!
- jassertfalse;
- return false;
- }
- }
-
- //==============================================================================
- bool writeMessage (const OSCMessage& msg)
- {
- if (! writeAddressPattern (msg.getAddressPattern()))
- return false;
-
- OSCTypeList typeList;
-
- for (auto& arg : msg)
- typeList.add (arg.getType());
-
- if (! writeTypeTagString (typeList))
- return false;
-
- for (auto& arg : msg)
- if (! writeArgument (arg))
- return false;
-
- return true;
- }
-
- bool writeBundle (const OSCBundle& bundle)
- {
- if (! writeString ("#bundle"))
- return false;
-
- if (! writeTimeTag (bundle.getTimeTag()))
- return false;
-
- for (auto& element : bundle)
- if (! writeBundleElement (element))
- return false;
-
- return true;
- }
-
- //==============================================================================
- bool writeBundleElement (const OSCBundle::Element& element)
- {
- const int64 startPos = output.getPosition();
-
- if (! writeInt32 (0)) // writing dummy value for element size
- return false;
-
- if (element.isBundle())
- {
- if (! writeBundle (element.getBundle()))
- return false;
- }
- else
- {
- if (! writeMessage (element.getMessage()))
- return false;
- }
-
- const int64 endPos = output.getPosition();
- const int64 elementSize = endPos - (startPos + 4);
-
- return output.setPosition (startPos)
- && writeInt32 ((int32) elementSize)
- && output.setPosition (endPos);
- }
-
- private:
- MemoryOutputStream output;
-
- JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OSCOutputStream)
- };
-
- } // namespace
-
-
- //==============================================================================
- struct OSCSender::Pimpl
- {
- Pimpl() noexcept {}
- ~Pimpl() noexcept { disconnect(); }
-
- //==============================================================================
- bool connect (const String& newTargetHost, int newTargetPort)
- {
- if (! disconnect())
- return false;
-
- socket.setOwned (new DatagramSocket (true));
- targetHostName = newTargetHost;
- targetPortNumber = newTargetPort;
-
- if (socket->bindToPort (0)) // 0 = use any local port assigned by the OS.
- return true;
-
- socket.reset();
- return false;
- }
-
- bool connectToSocket (DatagramSocket& newSocket, const String& newTargetHost, int newTargetPort)
- {
- if (! disconnect())
- return false;
-
- socket.setNonOwned (&newSocket);
- targetHostName = newTargetHost;
- targetPortNumber = newTargetPort;
- return true;
- }
-
- bool disconnect()
- {
- socket.reset();
- return true;
- }
-
- //==============================================================================
- bool send (const OSCMessage& message, const String& hostName, int portNumber)
- {
- OSCOutputStream outStream;
-
- return outStream.writeMessage (message)
- && sendOutputStream (outStream, hostName, portNumber);
- }
-
- bool send (const OSCBundle& bundle, const String& hostName, int portNumber)
- {
- OSCOutputStream outStream;
-
- return outStream.writeBundle (bundle)
- && sendOutputStream (outStream, hostName, portNumber);
- }
-
- bool send (const OSCMessage& message) { return send (message, targetHostName, targetPortNumber); }
- bool send (const OSCBundle& bundle) { return send (bundle, targetHostName, targetPortNumber); }
-
- private:
- //==============================================================================
- bool sendOutputStream (OSCOutputStream& outStream, const String& hostName, int portNumber)
- {
- if (socket != nullptr)
- {
- const int streamSize = (int) outStream.getDataSize();
-
- const int bytesWritten = socket->write (hostName, portNumber,
- outStream.getData(), streamSize);
- return bytesWritten == streamSize;
- }
-
- // if you hit this, you tried to send some OSC data without being
- // connected to a port! You should call OSCSender::connect() first.
- jassertfalse;
-
- return false;
- }
-
- //==============================================================================
- OptionalScopedPointer<DatagramSocket> socket;
- String targetHostName;
- int targetPortNumber = 0;
-
- JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
- };
-
-
- //==============================================================================
- OSCSender::OSCSender() : pimpl (new Pimpl())
- {
- }
-
- OSCSender::~OSCSender()
- {
- pimpl->disconnect();
- pimpl.reset();
- }
-
- //==============================================================================
- bool OSCSender::connect (const String& targetHostName, int targetPortNumber)
- {
- return pimpl->connect (targetHostName, targetPortNumber);
- }
-
- bool OSCSender::connectToSocket (DatagramSocket& socket, const String& targetHostName, int targetPortNumber)
- {
- return pimpl->connectToSocket (socket, targetHostName, targetPortNumber);
- }
-
- bool OSCSender::disconnect()
- {
- return pimpl->disconnect();
- }
-
- //==============================================================================
- bool OSCSender::send (const OSCMessage& message) { return pimpl->send (message); }
- bool OSCSender::send (const OSCBundle& bundle) { return pimpl->send (bundle); }
-
- bool OSCSender::sendToIPAddress (const String& host, int port, const OSCMessage& message) { return pimpl->send (message, host, port); }
- bool OSCSender::sendToIPAddress (const String& host, int port, const OSCBundle& bundle) { return pimpl->send (bundle, host, port); }
-
-
- //==============================================================================
- //==============================================================================
- #if JUCE_UNIT_TESTS
-
- class OSCBinaryWriterTests : public UnitTest
- {
- public:
- OSCBinaryWriterTests()
- : UnitTest ("OSCBinaryWriter class", UnitTestCategories::osc)
- {}
-
- void runTest()
- {
- beginTest ("writing OSC addresses");
- {
- OSCOutputStream outStream;
- const char check[16] = { '/', 't', 'e', 's', 't', '/', 'f', 'a', 'd', 'e', 'r', '7', '\0', '\0', '\0', '\0' };
-
- OSCAddress address ("/test/fader7");
- expect (outStream.writeAddress (address));
-
- expect (outStream.getDataSize() == sizeof (check));
- expect (std::memcmp (outStream.getData(), check, sizeof (check)) == 0);
- }
-
- beginTest ("writing OSC address patterns");
- {
- OSCOutputStream outStream;
- const char check[20] = { '/', '*', '/', '*', 'p', 'u', 't', '/', 'f', 'a', 'd', 'e', 'r', '[', '0', '-', '9', ']', '\0', '\0' };
-
- OSCAddressPattern ap ("/*/*put/fader[0-9]");
- expect (outStream.writeAddressPattern (ap));
-
- expect (outStream.getDataSize() == sizeof (check));
- expect (std::memcmp (outStream.getData(), check, sizeof (check)) == 0);
- }
-
- beginTest ("writing OSC time tags");
- {
- OSCOutputStream outStream;
- const char check[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };
- OSCTimeTag tag;
-
- expect (outStream.writeTimeTag (tag));
- expect (outStream.getDataSize() == 8);
- expect (std::memcmp (outStream.getData(), check, sizeof (check)) == 0);
- }
-
- beginTest ("writing OSC type tag strings");
- {
- {
- OSCOutputStream outStream;
-
- OSCTypeList list;
-
- const char check[4] = { ',', '\0', '\0', '\0' };
- expect (outStream.writeTypeTagString (list));
- expect (outStream.getDataSize() == 4);
- expect (std::memcmp (outStream.getData(), check, sizeof (check)) == 0);
- }
-
- {
- OSCOutputStream outStream;
-
- OSCTypeList list;
- list.add (OSCTypes::int32);
- list.add (OSCTypes::float32);
-
- const char check[4] = { ',', 'i', 'f', '\0' };
- expect (outStream.writeTypeTagString (list));
- expect (outStream.getDataSize() == sizeof (check));
- expect (std::memcmp (outStream.getData(), check, sizeof (check)) == 0);
- }
-
- {
- OSCOutputStream outStream;
-
- OSCTypeList list;
- list.add (OSCTypes::blob);
- list.add (OSCTypes::blob);
- list.add (OSCTypes::string);
-
- const char check[8] = { ',', 'b', 'b', 's', '\0', '\0', '\0', '\0' };
- expect (outStream.writeTypeTagString (list));
- expect (outStream.getDataSize() == sizeof (check));
- expect (std::memcmp (outStream.getData(), check, sizeof (check)) == 0);
- }
- }
-
- beginTest ("writing OSC arguments");
- {
- // test data:
- int testInt = -2015;
- const uint8 testIntRepresentation[] = { 0xFF, 0xFF, 0xF8, 0x21 }; // big endian two's complement
-
- float testFloat = 345.6125f;
- const uint8 testFloatRepresentation[] = { 0x43, 0xAC, 0xCE, 0x66 }; // big endian IEEE 754
-
- String testString = "Hello, World!";
- const char testStringRepresentation[] = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', '\0', '\0', '\0' }; // padded to size % 4 == 0
-
- const uint8 testBlobData[] = { 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
- const MemoryBlock testBlob (testBlobData, sizeof (testBlobData));
- const uint8 testBlobRepresentation[] = { 0x00, 0x00, 0x00, 0x05, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x00, 0x00 }; // padded to size % 4 == 0
-
- // write:
-
- {
- // int32:
- OSCArgument arg (testInt);
- OSCOutputStream outStream;
-
- expect (outStream.writeArgument (arg));
- expect (outStream.getDataSize() == 4);
- expect (std::memcmp (outStream.getData(), testIntRepresentation, sizeof (testIntRepresentation)) == 0);
- }
- {
- // float32:
- OSCArgument arg (testFloat);
- OSCOutputStream outStream;
-
- expect (outStream.writeArgument (arg));
- expect (outStream.getDataSize() == 4);
- expect (std::memcmp (outStream.getData(), testFloatRepresentation, sizeof (testFloatRepresentation)) == 0);
-
- }
- {
- // string:
- expect (testString.length() % 4 != 0); // check whether we actually cover padding
- static_assert (sizeof (testStringRepresentation) % 4 == 0, "Size must be a multiple of 4");
-
- OSCArgument arg (testString);
- OSCOutputStream outStream;
-
- expect (outStream.writeArgument (arg));
- expect (outStream.getDataSize() == sizeof (testStringRepresentation));
- expect (std::memcmp (outStream.getData(), testStringRepresentation, sizeof (testStringRepresentation)) == 0);
-
- }
- {
- // blob:
- expect (testBlob.getSize() % 4 != 0); // check whether we actually cover padding
- static_assert (sizeof (testBlobRepresentation) % 4 == 0, "Size must be a multiple of 4");
-
- OSCArgument arg (testBlob);
- OSCOutputStream outStream;
-
- expect (outStream.writeArgument (arg));
- expect (outStream.getDataSize() == sizeof (testBlobRepresentation));
- expect (std::memcmp (outStream.getData(), testBlobRepresentation, sizeof (testBlobRepresentation)) == 0);
-
- }
- }
-
- beginTest ("Writing strings with correct padding");
- {
- // the only OSC-specific thing to check is the correct number of padding zeros
-
- {
- OSCArgument with15Chars ("123456789012345");
- OSCOutputStream outStream;
- expect (outStream.writeArgument (with15Chars));
- expect (outStream.getDataSize() == 16);
- }
- {
- OSCArgument with16Chars ("1234567890123456");
- OSCOutputStream outStream;
- expect (outStream.writeArgument (with16Chars));
- expect (outStream.getDataSize() == 20);
- }
- {
- OSCArgument with17Chars ("12345678901234567");
- OSCOutputStream outStream;
- expect (outStream.writeArgument (with17Chars));
- expect (outStream.getDataSize() == 20);
- }
- {
-
- OSCArgument with18Chars ("123456789012345678");
- OSCOutputStream outStream;
- expect (outStream.writeArgument (with18Chars));
- expect (outStream.getDataSize() == 20);
- }
- {
-
- OSCArgument with19Chars ("1234567890123456789");
- OSCOutputStream outStream;
- expect (outStream.writeArgument (with19Chars));
- expect (outStream.getDataSize() == 20);
- }
- {
-
- OSCArgument with20Chars ("12345678901234567890");
- OSCOutputStream outStream;
- expect (outStream.writeArgument (with20Chars));
- expect (outStream.getDataSize() == 24);
- }
- }
- beginTest ("Writing blobs with correct padding");
- {
- const char buffer[20] = {};
- {
- OSCArgument with15Bytes (MemoryBlock (buffer, 15));
- OSCOutputStream outStream;
- expect (outStream.writeArgument (with15Bytes));
- expect (outStream.getDataSize() == 20);
- }
- {
- OSCArgument with16Bytes (MemoryBlock (buffer, 16));
- OSCOutputStream outStream;
- expect (outStream.writeArgument (with16Bytes));
- expect (outStream.getDataSize() == 20);
- }
- {
- OSCArgument with17Bytes (MemoryBlock (buffer, 17));
- OSCOutputStream outStream;
- expect (outStream.writeArgument (with17Bytes));
- expect (outStream.getDataSize() == 24);
- }
- {
- OSCArgument with18Bytes (MemoryBlock (buffer, 18));
- OSCOutputStream outStream;
- expect (outStream.writeArgument (with18Bytes));
- expect (outStream.getDataSize() == 24);
- }
- {
- OSCArgument with19Bytes (MemoryBlock (buffer, 19));
- OSCOutputStream outStream;
- expect (outStream.writeArgument (with19Bytes));
- expect (outStream.getDataSize() == 24);
- }
- {
- OSCArgument with20Bytes (MemoryBlock (buffer, 20));
- OSCOutputStream outStream;
- expect (outStream.writeArgument (with20Bytes));
- expect (outStream.getDataSize() == 24);
- }
- }
-
- beginTest ("Writing OSC messages.");
- {
- {
- int32 testInt = -2015;
- float testFloat = 345.6125f;
- String testString = "Hello, World!";
-
- const uint8 testBlobData[] = { 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
- const MemoryBlock testBlob (testBlobData, sizeof (testBlobData));
-
- uint8 check[52] = { '/', 't', 'e', 's', 't', '\0', '\0', '\0',
- ',', 'i', 'f', 's', 'b', '\0', '\0', '\0',
- 0xFF, 0xFF, 0xF8, 0x21,
- 0x43, 0xAC, 0xCE, 0x66,
- 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', '\0', '\0', '\0',
- 0x00, 0x00, 0x00, 0x05, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x00, 0x00
- };
-
- OSCOutputStream outStream;
-
- OSCMessage msg ("/test");
-
- msg.addInt32 (testInt);
- msg.addFloat32 (testFloat);
- msg.addString (testString);
- msg.addBlob (testBlob);
-
- expect (outStream.writeMessage (msg));
- expect (outStream.getDataSize() == sizeof (check));
- expect (std::memcmp (outStream.getData(), check, sizeof (check)) == 0);
- }
- }
-
- beginTest ("Writing OSC bundle.");
- {
- {
- int32 testInt = -2015;
- float testFloat = 345.6125f;
- String testString = "Hello, World!";
- const uint8 testBlobData[] = { 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
- const MemoryBlock testBlob (testBlobData, sizeof (testBlobData));
-
- uint8 check[] = {
- '#', 'b', 'u', 'n', 'd', 'l', 'e', '\0',
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-
- 0x00, 0x00, 0x00, 0x34,
-
- '/', 't', 'e', 's', 't', '/', '1', '\0',
- ',', 'i', 'f', 's', 'b', '\0', '\0', '\0',
- 0xFF, 0xFF, 0xF8, 0x21,
- 0x43, 0xAC, 0xCE, 0x66,
- 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', '\0', '\0', '\0',
- 0x00, 0x00, 0x00, 0x05, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x00, 0x00,
-
- 0x00, 0x00, 0x00, 0x0C,
-
- '/', 't', 'e', 's', 't', '/', '2', '\0',
- ',', '\0', '\0', '\0',
-
- 0x00, 0x00, 0x00, 0x10,
-
- '#', 'b', 'u', 'n', 'd', 'l', 'e', '\0',
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
- };
-
- OSCOutputStream outStream;
-
- OSCBundle bundle;
-
- OSCMessage msg1 ("/test/1");
- msg1.addInt32 (testInt);
- msg1.addFloat32 (testFloat);
- msg1.addString (testString);
- msg1.addBlob (testBlob);
- bundle.addElement (msg1);
-
- OSCMessage msg2 ("/test/2");
- bundle.addElement (msg2);
-
- OSCBundle subBundle;
- bundle.addElement (subBundle);
-
- expect (outStream.writeBundle (bundle));
- expect (outStream.getDataSize() == sizeof (check));
- expect (std::memcmp (outStream.getData(), check, sizeof (check)) == 0);
- }
- }
- }
- };
-
- static OSCBinaryWriterTests OSCBinaryWriterUnitTests;
-
- //==============================================================================
- class OSCRoundTripTests : public UnitTest
- {
- public:
- OSCRoundTripTests()
- : UnitTest ("OSCRoundTripTests class", UnitTestCategories::osc)
- {}
-
- void runTest()
- {
- beginTest ("Empty OSC message");
- {
- OSCMessage outMessage ("/test/empty");
-
- OSCOutputStream output;
- output.writeMessage (outMessage);
-
- OSCInputStream input (output.getData(), output.getDataSize());
- OSCMessage inMessage = input.readMessage();
-
- expectEquals (inMessage.size(), 0);
- }
-
- beginTest ("OSC message with single argument");
- {
- OSCMessage outMessage ("/test/one_arg", 42);
-
- OSCOutputStream output;
- output.writeMessage (outMessage);
-
- OSCInputStream input (output.getData(), output.getDataSize());
- OSCMessage inMessage = input.readMessage();
-
- expectEquals (inMessage.size(), 1);
- expectEquals (inMessage[0].getInt32(), 42);
- }
-
- beginTest ("OSC message with multiple arguments");
- {
- OSCMessage outMessage ("/test/four_args", 42, 0.5f, String ("foo"), String ("bar"));
-
- OSCOutputStream output;
- output.writeMessage (outMessage);
-
- OSCInputStream input (output.getData(), output.getDataSize());
- OSCMessage inMessage = input.readMessage();
-
- expectEquals (inMessage.size(), 4);
- expectEquals (inMessage[0].getInt32(), 42);
- expectEquals (inMessage[1].getFloat32(), 0.5f);
- expectEquals (inMessage[2].getString(), String ("foo"));
- expectEquals (inMessage[3].getString(), String ("bar"));
- }
-
- beginTest ("Empty OSC bundle");
- {
- OSCBundle outBundle;
-
- OSCOutputStream output;
- output.writeBundle (outBundle);
-
- OSCInputStream input (output.getData(), output.getDataSize());
- OSCBundle inBundle = input.readBundle();
-
- expectEquals (inBundle.size(), 0);
- }
-
- beginTest ("OSC bundle with single message");
- {
- OSCMessage outMessage ("/test/one_arg", 42);
- OSCBundle outBundle;
- outBundle.addElement (outMessage);
-
- OSCOutputStream output;
- output.writeBundle (outBundle);
-
- OSCInputStream input (output.getData(), output.getDataSize());
- OSCBundle inBundle = input.readBundle();
-
- expectEquals (inBundle.size(), 1);
-
- OSCMessage inMessage = inBundle[0].getMessage();
-
- expectEquals (inMessage.getAddressPattern().toString(), String ("/test/one_arg"));
- expectEquals (inMessage.size(), 1);
- expectEquals (inMessage[0].getInt32(), 42);
- }
-
- beginTest ("OSC bundle with multiple messages");
- {
- OSCMessage outMessage1 ("/test/empty");
- OSCMessage outMessage2 ("/test/one_arg", 42);
- OSCMessage outMessage3 ("/test/four_args", 42, 0.5f, String ("foo"), String ("bar"));
-
- OSCBundle outBundle;
- outBundle.addElement (outMessage1);
- outBundle.addElement (outMessage2);
- outBundle.addElement (outMessage3);
-
- OSCOutputStream output;
- output.writeBundle (outBundle);
-
- OSCInputStream input (output.getData(), output.getDataSize());
- OSCBundle inBundle = input.readBundle();
-
- expectEquals (inBundle.size(), 3);
-
- {
- OSCMessage inMessage = inBundle[0].getMessage();
-
- expectEquals (inMessage.getAddressPattern().toString(), String ("/test/empty"));
- expectEquals (inMessage.size(), 0);
- }
- {
- OSCMessage inMessage = inBundle[1].getMessage();
-
- expectEquals (inMessage.getAddressPattern().toString(), String ("/test/one_arg"));
- expectEquals (inMessage.size(), 1);
- expectEquals (inMessage[0].getInt32(), 42);
- }
- {
- OSCMessage inMessage = inBundle[2].getMessage();
-
- expectEquals (inMessage.getAddressPattern().toString(), String ("/test/four_args"));
- expectEquals (inMessage.size(), 4);
- expectEquals (inMessage[0].getInt32(), 42);
- expectEquals (inMessage[1].getFloat32(), 0.5f);
- expectEquals (inMessage[2].getString(), String ("foo"));
- expectEquals (inMessage[3].getString(), String ("bar"));
- }
- }
-
- beginTest ("OSC bundle containing another bundle");
- {
- OSCBundle outBundleNested;
- outBundleNested.addElement (OSCMessage ("/test/one_arg", 42));
-
- OSCBundle outBundle;
- outBundle.addElement (outBundleNested);
-
- OSCOutputStream output;
- output.writeBundle (outBundle);
-
- OSCInputStream input (output.getData(), output.getDataSize());
- OSCBundle inBundle = input.readBundle();
-
- expectEquals (inBundle.size(), 1);
- expect (inBundle[0].isBundle());
- OSCBundle inBundleNested = inBundle[0].getBundle();
- expectEquals (inBundleNested.size(), 1);
- expect (inBundleNested[0].isMessage());
-
- OSCMessage msg = inBundleNested[0].getMessage();
-
- expectEquals (msg.getAddressPattern().toString(), String ("/test/one_arg"));
- expectEquals (msg.size(), 1);
- expectEquals (msg[0].getInt32(), 42);
- }
-
- beginTest ("OSC bundle containing multiple other bundles");
- {
- OSCBundle outBundleNested1;
- outBundleNested1.addElement (OSCMessage ("/test/empty"));
- OSCBundle outBundleNested2;
- outBundleNested2.addElement (OSCMessage ("/test/one_arg", 42));
-
- OSCBundle outBundle;
- outBundle.addElement (outBundleNested1);
- outBundle.addElement (outBundleNested2);
-
- OSCOutputStream output;
- output.writeBundle (outBundle);
-
- OSCInputStream input (output.getData(), output.getDataSize());
- OSCBundle inBundle = input.readBundle();
-
- expectEquals (inBundle.size(), 2);
-
- {
- expect (inBundle[0].isBundle());
- OSCBundle inBundleNested = inBundle[0].getBundle();
- expectEquals (inBundleNested.size(), 1);
- expect (inBundleNested[0].isMessage());
-
- OSCMessage msg = inBundleNested[0].getMessage();
-
- expectEquals (msg.getAddressPattern().toString(), String ("/test/empty"));
- expectEquals (msg.size(), 0);
- }
- {
- expect (inBundle[1].isBundle());
- OSCBundle inBundleNested = inBundle[1].getBundle();
- expectEquals (inBundleNested.size(), 1);
- expect (inBundleNested[0].isMessage());
-
- OSCMessage msg = inBundleNested[0].getMessage();
-
- expectEquals (msg.getAddressPattern().toString(), String ("/test/one_arg"));
- expectEquals (msg.size(), 1);
- expectEquals (msg[0].getInt32(), 42);
- }
- }
- }
- };
-
- static OSCRoundTripTests OSCRoundTripUnitTests;
-
- #endif
-
- } // namespace juce
|