From 88a093b486e74a4674158aca06ad9c83e3235a21 Mon Sep 17 00:00:00 2001 From: monsieurgustav Date: Wed, 2 Mar 2016 00:30:59 +0100 Subject: [PATCH] add SendOscBundle blueprint function --- .../OSC/Private/Common/OscFunctionLibrary.cpp | 174 +++++++++++++----- .../OSC/Private/Common/OscFunctionLibrary.h | 9 + .../oscpack/osc/OscOutboundPacketStream.cpp | 21 ++- 3 files changed, 156 insertions(+), 48 deletions(-) diff --git a/OSC/Source/OSC/Private/Common/OscFunctionLibrary.cpp b/OSC/Source/OSC/Private/Common/OscFunctionLibrary.cpp index 3d070c0..2778e48 100644 --- a/OSC/Source/OSC/Private/Common/OscFunctionLibrary.cpp +++ b/OSC/Source/OSC/Private/Common/OscFunctionLibrary.cpp @@ -135,68 +135,148 @@ FOscDataElemStruct UOscFunctionLibrary::FromString(FName input) } -void UOscFunctionLibrary::SendOsc(FName Address, const TArray & Data, int32 TargetIndex) +namespace { - if(!Address.IsValid()) + bool isValidAddress(const FName & Address) { - UE_LOG(LogOSC, Error, TEXT("Empty OSC address")); - return; + if(!Address.IsValid()) + { + UE_LOG(LogOSC, Error, TEXT("Empty OSC address")); + return false; + } + + if(Address.GetDisplayNameEntry()->IsWide()) + { + const auto tmp = Address.GetPlainNameString(); + UE_LOG(LogOSC, Error, TEXT("Invalid OSC address \"%s\": ASCII only"), *tmp); + return false; + } + + if(Address.GetPlainANSIString()[0] != '/') + { + const auto tmp = Address.GetPlainNameString(); + UE_LOG(LogOSC, Error, TEXT("Invalid OSC address \"%s\": must start with '/'"), *tmp); + return false; + } + + return true; } - if(Address.GetDisplayNameEntry()->IsWide()) + void appendMessage(osc::OutboundPacketStream & output, FName Address, const TArray & Data) { - const auto tmp = Address.GetPlainNameString(); - UE_LOG(LogOSC, Error, TEXT("Invalid OSC address \"%s\": ASCII only"), *tmp); - return; - } - - if(Address.GetPlainANSIString()[0] != '/') - { - const auto tmp = Address.GetPlainNameString(); - UE_LOG(LogOSC, Error, TEXT("Invalid OSC address \"%s\": must start with '/'"), *tmp); - return; - } - - static_assert(sizeof(uint8) == sizeof(char), "Cannot cast uint8 to char"); - uint8 buffer[1024]; - - osc::OutboundPacketStream output((char *)buffer, sizeof(buffer)); - output << osc::BeginMessage(Address.GetPlainANSIString()); - for(const auto & elem : Data) - { - if(elem.IsFloat()) - { - output << (float)elem.AsFloatValue(); - } - else if(elem.IsInt()) - { - output << (int32)elem.AsIntValue(); - } - else if(elem.IsBool()) - { - output << elem.AsBoolValue(); - } - else if(elem.IsString()) - { - output << elem.AsStringValue().GetPlainANSIString(); - } - + output << osc::BeginMessage(Address.GetPlainANSIString()); if(output.State() != osc::SUCCESS) { - UE_LOG(LogOSC, Error, TEXT("OSC Send Message Error: %s"), osc::errorString(output.State())); + return; + } + + for(const auto & elem : Data) + { + if(elem.IsFloat()) + { + output << (float)elem.AsFloatValue(); + } + else if(elem.IsInt()) + { + output << (int32)elem.AsIntValue(); + } + else if(elem.IsBool()) + { + output << elem.AsBoolValue(); + } + else if(elem.IsString()) + { + output << elem.AsStringValue().GetPlainANSIString(); + } + + if(output.State() != osc::SUCCESS) + { + return; + } + } + output << osc::EndMessage; + } + + TArray GlobalBuffer(TArray(), 1024); +} + +void UOscFunctionLibrary::SendOsc(FName Address, const TArray & Data, int32 TargetIndex) +{ + if(!isValidAddress(Address)) + { + return; + } + + static_assert(sizeof(uint8) == sizeof(char), "Cannot cast uint8 to char"); + + osc::OutboundPacketStream output((char *)GlobalBuffer.GetData(), GlobalBuffer.Max()); + check(reinterpret_cast(GlobalBuffer.GetData()) == reinterpret_cast(output.Data())); + + appendMessage(output, Address, Data); + + if(output.State() == osc::OUT_OF_BUFFER_MEMORY_ERROR) + { + GlobalBuffer.Reserve(GlobalBuffer.Max() * 2); // not enough memory: double the size + SendOsc(Address, Data, TargetIndex); // try again + return; + } + + if(output.State() == osc::SUCCESS) + { + GetMutableDefault()->Send(GlobalBuffer.GetData(), output.Size(), TargetIndex); + } + else + { + UE_LOG(LogOSC, Error, TEXT("OSC Send Message Error: %s"), osc::errorString(output.State())); + } +} + +void UOscFunctionLibrary::SendOscBundle(const TArray & Messages, int32 TargetIndex) +{ + static_assert(sizeof(uint8) == sizeof(char), "Cannot cast uint8 to char"); + + osc::OutboundPacketStream output((char *)GlobalBuffer.GetData(), GlobalBuffer.Max()); + check(reinterpret_cast(GlobalBuffer.GetData()) == reinterpret_cast(output.Data())); + + output << osc::BeginBundle(); + for(const auto & message : Messages) + { + if(!isValidAddress(message.Address)) + { + return; + } + + appendMessage(output, message.Address, message.Data); + + if(output.State() == osc::OUT_OF_BUFFER_MEMORY_ERROR) + { + GlobalBuffer.Reserve(GlobalBuffer.Max() * 2); // not enough memory: double the size + SendOscBundle(Messages, TargetIndex); // try again + return; + } + if(output.State() != osc::SUCCESS) + { + UE_LOG(LogOSC, Error, TEXT("OSC Send Bundle Error: %s"), osc::errorString(output.State())); return; } } - output << osc::EndMessage; + output << osc::EndBundle; - if(output.State() != osc::SUCCESS) + if(output.State() == osc::OUT_OF_BUFFER_MEMORY_ERROR) { - UE_LOG(LogOSC, Error, TEXT("OSC Send Message Error: %s"), osc::errorString(output.State())); + GlobalBuffer.Reserve(GlobalBuffer.Max() * 2); // not enough memory: double the size + SendOscBundle(Messages, TargetIndex); // try again return; } - check(reinterpret_cast(buffer) == reinterpret_cast(output.Data())); - GetMutableDefault()->Send(buffer, output.Size(), TargetIndex); + if(output.State() == osc::SUCCESS) + { + GetMutableDefault()->Send(GlobalBuffer.GetData(), output.Size(), TargetIndex); + } + else + { + UE_LOG(LogOSC, Error, TEXT("OSC Send Bundle Error: %s"), osc::errorString(output.State())); + } } int32 UOscFunctionLibrary::AddSendOscTarget(FString IpPort) diff --git a/OSC/Source/OSC/Private/Common/OscFunctionLibrary.h b/OSC/Source/OSC/Private/Common/OscFunctionLibrary.h index 56d5538..6530b0d 100644 --- a/OSC/Source/OSC/Private/Common/OscFunctionLibrary.h +++ b/OSC/Source/OSC/Private/Common/OscFunctionLibrary.h @@ -1,6 +1,7 @@ #pragma once #include "OscDataElemStruct.h" +#include "OscMessageStruct.h" #include "OscFunctionLibrary.generated.h" @@ -88,6 +89,14 @@ public: UFUNCTION(BlueprintCallable, Category=OSC, meta=(AutoCreateRefTerm = "Data")) static void SendOsc(FName Address, const TArray & Data, int32 TargetIndex); + /** + * @brief Send several OSC messages in an OSC bundle. + * @param Messages of the bundle. + * @param Index index of the destination, -1 for all destinations. (SendTarget list of the plugin settings) + */ + UFUNCTION(BlueprintCallable, Category=OSC) + static void SendOscBundle(const TArray & Messages, int32 TargetIndex); + /** * @brief Add Ip:Port to the available OSC send targets. * @param IpPort "ip:port". e.g. "192.168.0.1:7777" diff --git a/OSC/Source/OSC/Private/Common/oscpack/osc/OscOutboundPacketStream.cpp b/OSC/Source/OSC/Private/Common/oscpack/osc/OscOutboundPacketStream.cpp index 7c35ed2..2a908d4 100644 --- a/OSC/Source/OSC/Private/Common/oscpack/osc/OscOutboundPacketStream.cpp +++ b/OSC/Source/OSC/Private/Common/oscpack/osc/OscOutboundPacketStream.cpp @@ -321,7 +321,7 @@ bool OutboundPacketStream::IsBundleInProgress() const OutboundPacketStream& OutboundPacketStream::operator<<( const BundleInitiator& rhs ) { check( !IsMessageInProgress() ) - + check( state_ == SUCCESS ) state_ = CheckForAvailableBundleSpace(); if(state_ == SUCCESS) { @@ -344,6 +344,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const BundleTerminator& check( IsBundleInProgress() ) check( !IsMessageInProgress() ) + check( state_ == SUCCESS ) EndElement( messageCursor_ ); @@ -354,6 +355,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const BundleTerminator& OutboundPacketStream& OutboundPacketStream::operator<<( const BeginMessage& rhs ) { check( !IsMessageInProgress() ) + check( state_ == SUCCESS ) state_ = CheckForAvailableMessageSpace( rhs.addressPattern ); @@ -387,6 +389,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const MessageTerminator& (void) rhs; check( IsMessageInProgress() ) + check( state_ == SUCCESS ) std::size_t typeTagsCount = end_ - typeTagsCurrent_; @@ -436,6 +439,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const MessageTerminator& OutboundPacketStream& OutboundPacketStream::operator<<( bool rhs ) { + check( state_ == SUCCESS ) state_ = CheckForAvailableArgumentSpace(0); if(state_ == SUCCESS) { @@ -449,6 +453,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( bool rhs ) OutboundPacketStream& OutboundPacketStream::operator<<( const NilType& rhs ) { (void) rhs; + check( state_ == SUCCESS ) state_ = CheckForAvailableArgumentSpace(0); if(state_ == SUCCESS) { @@ -462,6 +467,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const NilType& rhs ) OutboundPacketStream& OutboundPacketStream::operator<<( const InfinitumType& rhs ) { (void) rhs; + check( state_ == SUCCESS ) state_ = CheckForAvailableArgumentSpace(0); if(state_ == SUCCESS) { @@ -474,6 +480,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const InfinitumType& rhs OutboundPacketStream& OutboundPacketStream::operator<<( int32 rhs ) { + check( state_ == SUCCESS ) state_ = CheckForAvailableArgumentSpace(4); if(state_ == SUCCESS) { @@ -488,6 +495,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( int32 rhs ) OutboundPacketStream& OutboundPacketStream::operator<<( float rhs ) { + check( state_ == SUCCESS ) state_ = CheckForAvailableArgumentSpace(4); if(state_ == SUCCESS) { @@ -518,6 +526,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( float rhs ) OutboundPacketStream& OutboundPacketStream::operator<<( char rhs ) { + check( state_ == SUCCESS ) state_ = CheckForAvailableArgumentSpace(4); if(state_ == SUCCESS) { @@ -532,6 +541,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( char rhs ) OutboundPacketStream& OutboundPacketStream::operator<<( const RgbaColor& rhs ) { + check( state_ == SUCCESS ) state_ = CheckForAvailableArgumentSpace(4); if(state_ == SUCCESS) { @@ -546,6 +556,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const RgbaColor& rhs ) OutboundPacketStream& OutboundPacketStream::operator<<( const MidiMessage& rhs ) { + check( state_ == SUCCESS ) state_ = CheckForAvailableArgumentSpace(4); if(state_ == SUCCESS) { @@ -560,6 +571,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const MidiMessage& rhs ) OutboundPacketStream& OutboundPacketStream::operator<<( int64 rhs ) { + check( state_ == SUCCESS ) state_ = CheckForAvailableArgumentSpace(8); if(state_ == SUCCESS) { @@ -574,6 +586,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( int64 rhs ) OutboundPacketStream& OutboundPacketStream::operator<<( const TimeTag& rhs ) { + check( state_ == SUCCESS ) state_ = CheckForAvailableArgumentSpace(8); if(state_ == SUCCESS) { @@ -588,6 +601,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const TimeTag& rhs ) OutboundPacketStream& OutboundPacketStream::operator<<( double rhs ) { + check( state_ == SUCCESS ) state_ = CheckForAvailableArgumentSpace(8); if(state_ == SUCCESS) { @@ -622,6 +636,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( double rhs ) OutboundPacketStream& OutboundPacketStream::operator<<( const char *rhs ) { + check( state_ == SUCCESS ) state_ = CheckForAvailableArgumentSpace( RoundUp4(std::strlen(rhs) + 1) ); if(state_ == SUCCESS) { @@ -644,6 +659,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const char *rhs ) OutboundPacketStream& OutboundPacketStream::operator<<( const Symbol& rhs ) { + check( state_ == SUCCESS ) state_ = CheckForAvailableArgumentSpace( RoundUp4(std::strlen(rhs) + 1) ); if(state_ == SUCCESS) { @@ -666,6 +682,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const Symbol& rhs ) OutboundPacketStream& OutboundPacketStream::operator<<( const Blob& rhs ) { + check( state_ == SUCCESS ) state_ = CheckForAvailableArgumentSpace( 4 + RoundUp4(rhs.size) ); if(state_ == SUCCESS) { @@ -690,6 +707,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const Blob& rhs ) OutboundPacketStream& OutboundPacketStream::operator<<( const ArrayInitiator& rhs ) { (void) rhs; + check( state_ == SUCCESS ) state_ = CheckForAvailableArgumentSpace(0); if(state_ == SUCCESS) { @@ -702,6 +720,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const ArrayInitiator& rh OutboundPacketStream& OutboundPacketStream::operator<<( const ArrayTerminator& rhs ) { (void) rhs; + check( state_ == SUCCESS ) state_ = CheckForAvailableArgumentSpace(0); if(state_ == SUCCESS) {