add multicast

This commit is contained in:
monsieurgustav
2014-10-26 13:05:58 +01:00
parent cb3d2d8abb
commit c29becea88
5 changed files with 122 additions and 55 deletions
+25 -8
View File
@@ -16,11 +16,9 @@ public:
return; return;
} }
auto settings = GetMutableDefault<UOscSettings>();
_dispatcher = UOscDispatcher::Get(); _dispatcher = UOscDispatcher::Get();
_dispatcher->Listen(settings->ReceivePort);
settings->UpdateSendAddresses(); HandleSettingsSaved();
// register settings // register settings
ISettingsModule* settingsModule = ISettingsModule::Get(); ISettingsModule* settingsModule = ISettingsModule::Get();
@@ -29,6 +27,7 @@ public:
FSettingsSectionDelegates settingsDelegates; FSettingsSectionDelegates settingsDelegates;
settingsDelegates.ModifiedDelegate = FOnSettingsSectionModified::CreateRaw(this, &FOscModule::HandleSettingsSaved); settingsDelegates.ModifiedDelegate = FOnSettingsSectionModified::CreateRaw(this, &FOscModule::HandleSettingsSaved);
auto settings = GetMutableDefault<UOscSettings>();
settingsModule->RegisterSettings("Project", "Plugins", "OSC", settingsModule->RegisterSettings("Project", "Plugins", "OSC",
LOCTEXT("OscSettingsName", "OSC"), LOCTEXT("OscSettingsName", "OSC"),
LOCTEXT("OscSettingsDescription", "Configure the OSC plug-in."), LOCTEXT("OscSettingsDescription", "Configure the OSC plug-in."),
@@ -54,13 +53,31 @@ public:
bool HandleSettingsSaved() bool HandleSettingsSaved()
{ {
UE_LOG(LogOSC, Display, TEXT("Update settings")); if(!_dispatcher.IsValid())
UOscSettings* settings = GetMutableDefault<UOscSettings>();
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<UOscSettings>();
// 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(); settings->UpdateSendAddresses();
return true; return true;
} }
+43 -12
View File
@@ -3,7 +3,7 @@
UOscSettings::UOscSettings( const class FPostConstructInitializeProperties& PCIP ) UOscSettings::UOscSettings( const class FPostConstructInitializeProperties& PCIP )
: Super(PCIP), : Super(PCIP),
ReceivePort(8000), ReceiveFrom("8000"),
_sendSocket(FUdpSocketBuilder(TEXT("OscSender")).Build()) _sendSocket(FUdpSocketBuilder(TEXT("OscSender")).Build())
{ {
SendTargets.Add(TEXT("127.0.0.1:8000")); SendTargets.Add(TEXT("127.0.0.1:8000"));
@@ -21,18 +21,18 @@ void UOscSettings::UpdateSendAddresses()
if(_sendAddresses[i].first != SendTargets[i]) if(_sendAddresses[i].first != SendTargets[i])
{ {
int32 sep = 0; FIPv4Address address(0);
bool isValid = false; uint32_t port;
if(SendTargets[i].FindChar(TEXT(':'), sep)) if(Parse(SendTargets[i], &address, &port) && address != FIPv4Address::Any)
{ {
const FString ip = SendTargets[i].Left(sep).Trim(); _sendAddresses[i].second->SetIp(address.GetValue());
_sendAddresses[i].second->SetIp(&ip.GetCharArray()[0], isValid); _sendAddresses[i].second->SetPort(port);
if(isValid)
{ _sendAddresses[i].first = SendTargets[i];
const int32 port = FCString::Atoi(&SendTargets[i].GetCharArray()[sep+1]); }
_sendAddresses[i].second->SetPort(port); else
_sendAddresses[i].first = SendTargets[i]; {
} 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); 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;
}
+17 -1
View File
@@ -13,8 +13,16 @@ class UOscSettings : public UObject
public: 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) UPROPERTY(Config, EditAnywhere, Category=Receive)
int32 ReceivePort; FString ReceiveFrom;
UPROPERTY(Config, EditAnywhere, Category=Send) UPROPERTY(Config, EditAnywhere, Category=Send)
TArray<FString> SendTargets; TArray<FString> SendTargets;
@@ -24,6 +32,14 @@ public:
void Send(const uint8 *buffer, int32 length, int32 targetIndex); 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: private:
TSharedRef<FSocket> _sendSocket; TSharedRef<FSocket> _sendSocket;
TArray<std::pair<FString, TSharedRef<FInternetAddr>>> _sendAddresses; TArray<std::pair<FString, TSharedRef<FInternetAddr>>> _sendAddresses;
@@ -11,7 +11,7 @@
UOscDispatcher::UOscDispatcher(const class FPostConstructInitializeProperties& PCIP) UOscDispatcher::UOscDispatcher(const class FPostConstructInitializeProperties& PCIP)
: Super(PCIP), : Super(PCIP),
_currentPort(0), _listening(FIPv4Address(0), 0),
_socket(nullptr), _socket(nullptr),
_socketReceiver(nullptr), _socketReceiver(nullptr),
_pendingMessages(64) _pendingMessages(64)
@@ -23,19 +23,30 @@ UOscDispatcher * UOscDispatcher::Get()
return UOscDispatcher::StaticClass()->GetDefaultObject<UOscDispatcher>(); return UOscDispatcher::StaticClass()->GetDefaultObject<UOscDispatcher>();
} }
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(); 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) if(_socket)
{ {
_socketReceiver = new FUdpSocketReceiver(_socket, FTimespan::FromMilliseconds(100), TEXT("OSCListener")); _socketReceiver = new FUdpSocketReceiver(_socket, FTimespan::FromMilliseconds(100), TEXT("OSCListener"));
_socketReceiver->OnDataReceived().BindUObject(this, &UOscDispatcher::Callback); _socketReceiver->OnDataReceived().BindUObject(this, &UOscDispatcher::Callback);
_currentPort = port; _listening = std::make_pair(address, port);
UE_LOG(LogOSC, Display, TEXT("Listen to port %d"), port); UE_LOG(LogOSC, Display, TEXT("Listen to port %d"), port);
} }
else else
@@ -58,7 +69,7 @@ void UOscDispatcher::Stop()
_socket = nullptr; _socket = nullptr;
} }
_currentPort = 0; _listening = std::make_pair(FIPv4Address(0), 0);
} }
void UOscDispatcher::RegisterReceiver(IOscReceiverInterface * receiver) void UOscDispatcher::RegisterReceiver(IOscReceiverInterface * receiver)
@@ -133,35 +144,27 @@ static void SendBundle(TCircularQueue<std::pair<FName, FOscDataStruct>> & _pendi
void UOscDispatcher::Callback(const FArrayReaderPtr& data, const FIPv4Endpoint&) void UOscDispatcher::Callback(const FArrayReaderPtr& data, const FIPv4Endpoint&)
{ {
UE_LOG(LogOSC, Verbose, TEXT("OSC Received")); 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()); SendBundle(_pendingMessages, osc::ReceivedBundle(packet));
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);
}
} }
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);
} }
} }
@@ -16,7 +16,7 @@ class UOscDispatcher : public UObject
friend class OscModule; friend class OscModule;
void Listen(uint32_t port); void Listen(FIPv4Address address, uint32_t port);
void Stop(); void Stop();
public: public:
@@ -41,7 +41,7 @@ private:
private: private:
TArray<IOscReceiverInterface *> _receivers; TArray<IOscReceiverInterface *> _receivers;
uint32_t _currentPort; std::pair<FIPv4Address, uint32_t> _listening;
FSocket * _socket; FSocket * _socket;
FUdpSocketReceiver * _socketReceiver; FUdpSocketReceiver * _socketReceiver;
TCircularQueue<std::pair<FName, FOscDataStruct>> _pendingMessages; TCircularQueue<std::pair<FName, FOscDataStruct>> _pendingMessages;