From c29becea880b0b16fef00d5db4ed78930137984c Mon Sep 17 00:00:00 2001 From: monsieurgustav Date: Sun, 26 Oct 2014 13:05:58 +0100 Subject: [PATCH] add multicast --- OSC/Source/OSC/Private/OscModule.cpp | 33 ++++++--- OSC/Source/OSC/Private/OscSettings.cpp | 55 +++++++++++---- OSC/Source/OSC/Private/OscSettings.h | 18 ++++- .../OSC/Private/Receive/OscDispatcher.cpp | 67 ++++++++++--------- .../OSC/Private/Receive/OscDispatcher.h | 4 +- 5 files changed, 122 insertions(+), 55 deletions(-) diff --git a/OSC/Source/OSC/Private/OscModule.cpp b/OSC/Source/OSC/Private/OscModule.cpp index f66ea05..cdfcb21 100644 --- a/OSC/Source/OSC/Private/OscModule.cpp +++ b/OSC/Source/OSC/Private/OscModule.cpp @@ -16,11 +16,9 @@ public: return; } - auto settings = GetMutableDefault(); - _dispatcher = UOscDispatcher::Get(); - _dispatcher->Listen(settings->ReceivePort); - settings->UpdateSendAddresses(); + + HandleSettingsSaved(); // register settings ISettingsModule* settingsModule = ISettingsModule::Get(); @@ -29,6 +27,7 @@ public: FSettingsSectionDelegates settingsDelegates; settingsDelegates.ModifiedDelegate = FOnSettingsSectionModified::CreateRaw(this, &FOscModule::HandleSettingsSaved); + auto settings = GetMutableDefault(); settingsModule->RegisterSettings("Project", "Plugins", "OSC", LOCTEXT("OscSettingsName", "OSC"), LOCTEXT("OscSettingsDescription", "Configure the OSC plug-in."), @@ -54,13 +53,31 @@ public: bool HandleSettingsSaved() { - UE_LOG(LogOSC, Display, TEXT("Update settings")); - UOscSettings* settings = GetMutableDefault(); - if(_dispatcher.IsValid()) + if(!_dispatcher.IsValid()) { - _dispatcher->Listen(settings->ReceivePort); + UE_LOG(LogOSC, Warning, TEXT("Cannot update settings")); + return false; } + + UE_LOG(LogOSC, Display, TEXT("Update settings")); + + auto settings = GetMutableDefault(); + + // receive settings + FIPv4Address receiveAddress(0); + uint32_t receivePort; + if(UOscSettings::Parse(settings->ReceiveFrom, &receiveAddress, &receivePort)) + { + _dispatcher->Listen(receiveAddress, receivePort); + } + else + { + UE_LOG(LogOSC, Warning, TEXT("Fail to parse receive address: %s"), *settings->ReceiveFrom); + } + + // send settings settings->UpdateSendAddresses(); + return true; } diff --git a/OSC/Source/OSC/Private/OscSettings.cpp b/OSC/Source/OSC/Private/OscSettings.cpp index 3292d70..4b2d240 100644 --- a/OSC/Source/OSC/Private/OscSettings.cpp +++ b/OSC/Source/OSC/Private/OscSettings.cpp @@ -3,7 +3,7 @@ UOscSettings::UOscSettings( const class FPostConstructInitializeProperties& PCIP ) : Super(PCIP), - ReceivePort(8000), + ReceiveFrom("8000"), _sendSocket(FUdpSocketBuilder(TEXT("OscSender")).Build()) { SendTargets.Add(TEXT("127.0.0.1:8000")); @@ -21,18 +21,18 @@ void UOscSettings::UpdateSendAddresses() if(_sendAddresses[i].first != SendTargets[i]) { - int32 sep = 0; - bool isValid = false; - if(SendTargets[i].FindChar(TEXT(':'), sep)) + FIPv4Address address(0); + uint32_t port; + if(Parse(SendTargets[i], &address, &port) && address != FIPv4Address::Any) { - const FString ip = SendTargets[i].Left(sep).Trim(); - _sendAddresses[i].second->SetIp(&ip.GetCharArray()[0], isValid); - if(isValid) - { - const int32 port = FCString::Atoi(&SendTargets[i].GetCharArray()[sep+1]); - _sendAddresses[i].second->SetPort(port); - _sendAddresses[i].first = SendTargets[i]; - } + _sendAddresses[i].second->SetIp(address.GetValue()); + _sendAddresses[i].second->SetPort(port); + + _sendAddresses[i].first = SendTargets[i]; + } + else + { + UE_LOG(LogOSC, Warning, TEXT("Fail to parse or invalid send address: %s"), *SendTargets[i]); } } } @@ -56,3 +56,34 @@ void UOscSettings::Send(const uint8 *buffer, int32 length, int32 targetIndex) UE_LOG(LogOSC, Warning, TEXT("Cannot send OSC: invalid targetIndex %d"), targetIndex); } } + +bool UOscSettings::Parse(const FString & address_port, FIPv4Address * address, uint32_t * port) +{ + if(address_port.IsEmpty()) + { + return false; + } + + FIPv4Address addressResult(0); + uint32_t portResult; + + int32 sep = -1; + if(address_port.FindChar(TEXT(':'), sep)) + { + const auto ip = address_port.Left(sep).Trim(); + if(!FIPv4Address::Parse(ip, addressResult)) + { + return false; + } + } + + portResult = FCString::Atoi(&address_port.GetCharArray()[sep+1]); + if(portResult == 0) + { + return false; + } + + *address = addressResult; + *port = portResult; + return true; +} diff --git a/OSC/Source/OSC/Private/OscSettings.h b/OSC/Source/OSC/Private/OscSettings.h index b398ce2..9b48a90 100644 --- a/OSC/Source/OSC/Private/OscSettings.h +++ b/OSC/Source/OSC/Private/OscSettings.h @@ -13,8 +13,16 @@ class UOscSettings : public UObject public: + /** + * Specify the [address:]port to listen to. + * + * e.g. + * - "8000" listen to messages from any sender on port 8000. [default] + * - "224.0.0.100:8000" listen multi-cast messages of group 224.0.0.100 on port 8000. + * - "192.168.0.1:8000" listen messages addressed specifically to 192.168.0.1 on port 8000, useful if there are several addresses for this machine. + */ UPROPERTY(Config, EditAnywhere, Category=Receive) - int32 ReceivePort; + FString ReceiveFrom; UPROPERTY(Config, EditAnywhere, Category=Send) TArray SendTargets; @@ -24,6 +32,14 @@ public: void Send(const uint8 *buffer, int32 length, int32 targetIndex); +public: + + /** + * @brief Parse "8000" and "192.168.0.12" to IP and port values. + * @return true if succeed + */ + static bool Parse(const FString & address_port, FIPv4Address * address, uint32_t * port); + private: TSharedRef _sendSocket; TArray>> _sendAddresses; diff --git a/OSC/Source/OSC/Private/Receive/OscDispatcher.cpp b/OSC/Source/OSC/Private/Receive/OscDispatcher.cpp index 89992c3..01a6e7f 100644 --- a/OSC/Source/OSC/Private/Receive/OscDispatcher.cpp +++ b/OSC/Source/OSC/Private/Receive/OscDispatcher.cpp @@ -11,7 +11,7 @@ UOscDispatcher::UOscDispatcher(const class FPostConstructInitializeProperties& PCIP) : Super(PCIP), - _currentPort(0), + _listening(FIPv4Address(0), 0), _socket(nullptr), _socketReceiver(nullptr), _pendingMessages(64) @@ -23,19 +23,30 @@ UOscDispatcher * UOscDispatcher::Get() return UOscDispatcher::StaticClass()->GetDefaultObject(); } -void UOscDispatcher::Listen(uint32_t port) +void UOscDispatcher::Listen(FIPv4Address address, uint32_t port) { - if(_currentPort != port) + if(_listening != std::make_pair(address, port)) { Stop(); - _socket = FUdpSocketBuilder(TEXT("OscListener")).AsNonBlocking().BoundToAddress(FIPv4Address::Any).BoundToPort(port).Build(); + FUdpSocketBuilder builder(TEXT("OscListener")); + builder.BoundToPort(port); + if(address.IsMulticastAddress()) + { + builder.JoinedToGroup(address); + } + else + { + builder.BoundToAddress(address); + } + + _socket = builder.Build(); if(_socket) { _socketReceiver = new FUdpSocketReceiver(_socket, FTimespan::FromMilliseconds(100), TEXT("OSCListener")); _socketReceiver->OnDataReceived().BindUObject(this, &UOscDispatcher::Callback); - _currentPort = port; + _listening = std::make_pair(address, port); UE_LOG(LogOSC, Display, TEXT("Listen to port %d"), port); } else @@ -58,7 +69,7 @@ void UOscDispatcher::Stop() _socket = nullptr; } - _currentPort = 0; + _listening = std::make_pair(FIPv4Address(0), 0); } void UOscDispatcher::RegisterReceiver(IOscReceiverInterface * receiver) @@ -133,35 +144,27 @@ static void SendBundle(TCircularQueue> & _pendi void UOscDispatcher::Callback(const FArrayReaderPtr& data, const FIPv4Endpoint&) { UE_LOG(LogOSC, Verbose, TEXT("OSC Received")); - try + const osc::ReceivedPacket packet((const char *)data->GetData(), data->Num()); + if(packet.IsBundle()) { - const osc::ReceivedPacket packet((const char *)data->GetData(), data->Num()); - - if(packet.IsBundle()) - { - SendBundle(_pendingMessages, osc::ReceivedBundle(packet)); - } - else - { - SendMessage(_pendingMessages, osc::ReceivedMessage(packet)); - } - - if(!_pendingMessages.IsEmpty()) - { - FSimpleDelegateGraphTask::CreateAndDispatchWhenReady( - FSimpleDelegateGraphTask::FDelegate::CreateUObject(this, &UOscDispatcher::CallbackMainThread), -#if OSC_ENGINE_VERSION < 40500 - TEXT("OscDispatcherProcessMessages"), -#else - TStatId(), -#endif - nullptr, - ENamedThreads::GameThread); - } + SendBundle(_pendingMessages, osc::ReceivedBundle(packet)); } - catch(osc::MalformedPacketException &e) + else { - UE_LOG(LogOSC, Warning, TEXT("Malformed OSC message: %s"), e.what()); + SendMessage(_pendingMessages, osc::ReceivedMessage(packet)); + } + + if(!_pendingMessages.IsEmpty()) + { + FSimpleDelegateGraphTask::CreateAndDispatchWhenReady( + FSimpleDelegateGraphTask::FDelegate::CreateUObject(this, &UOscDispatcher::CallbackMainThread), +#if OSC_ENGINE_VERSION < 40500 + TEXT("OscDispatcherProcessMessages"), +#else + TStatId(), +#endif + nullptr, + ENamedThreads::GameThread); } } diff --git a/OSC/Source/OSC/Private/Receive/OscDispatcher.h b/OSC/Source/OSC/Private/Receive/OscDispatcher.h index a4f0a28..5641271 100644 --- a/OSC/Source/OSC/Private/Receive/OscDispatcher.h +++ b/OSC/Source/OSC/Private/Receive/OscDispatcher.h @@ -16,7 +16,7 @@ class UOscDispatcher : public UObject friend class OscModule; - void Listen(uint32_t port); + void Listen(FIPv4Address address, uint32_t port); void Stop(); public: @@ -41,7 +41,7 @@ private: private: TArray _receivers; - uint32_t _currentPort; + std::pair _listening; FSocket * _socket; FUdpSocketReceiver * _socketReceiver; TCircularQueue> _pendingMessages;