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;
}
auto settings = GetMutableDefault<UOscSettings>();
_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<UOscSettings>();
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<UOscSettings>();
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<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();
return true;
}
+43 -12
View File
@@ -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;
}
+17 -1
View File
@@ -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<FString> 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<FSocket> _sendSocket;
TArray<std::pair<FString, TSharedRef<FInternetAddr>>> _sendAddresses;
@@ -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<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();
_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<std::pair<FName, FOscDataStruct>> & _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);
}
}
@@ -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<IOscReceiverInterface *> _receivers;
uint32_t _currentPort;
std::pair<FIPv4Address, uint32_t> _listening;
FSocket * _socket;
FUdpSocketReceiver * _socketReceiver;
TCircularQueue<std::pair<FName, FOscDataStruct>> _pendingMessages;