mirror of
https://github.com/storytold/UE4-OSC.git
synced 2026-10-13 23:53:20 +00:00
add multicast
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user