Configuring client and server using OSC in Unity - c#

I'm trying to utilize a library for Unity called UnityOSC, which allows you to receive OSC messages, presumably, from other applications. I have an application which transmits data via UDP at the following address:
host: 127.0.0.1
port: 33433
I now need to configure UnityOSC to listen for that data. The library has a script called OSCHandler.cs, and in the init function, you can set up your client and server. I'm just not sure how to set this up.
Currently, I'm attempting this:
public void Init()
{
CreateClient("FaceClient", IPAddress.Parse("127.0.0.1"), 33433);
CreateServer("FaceServer", 6666);
}
I've matched the client parameters to those of the application transmiting the data, and the server is just random - but honestly I'm not sure what to put in either one of these. Theoretically, if I set the client / server up properly, I should be able to register information in my update function like this:
void Update() {
OSCHandler.Instance.UpdateLogs();
//clients = OSCHandler.Instance.Clients;
servers = OSCHandler.Instance.Servers;
foreach(KeyValuePair<string, ServerLog> item in servers)
{
// If we have received at least one packet,
// show the last received from the log in the Debug console
if(item.Value.log.Count > 0)
{
int lastPacketIndex = item.Value.packets.Count - 1;
UnityEngine.Debug.Log(String.Format("SERVER: {0} ADDRESS: {1} VALUE 0: {2}",
item.Key, // Server name
item.Value.packets[lastPacketIndex].Address, // OSC address
item.Value.packets[lastPacketIndex].Data[0].ToString())); //First data value
}
}
}
But so far nothing is registering to the debugger. Any idea what I'm doing wrong?

Two things, keeping in mind I did this from the command line and not in the Unity editor so things might be different.
First, line 50 in OSCPacket.cs throws an exception in the command line version. Not sure if Unity picks up Trace.Assert or not but nothing is hurt by removing the line:
Trace.Assert(string.IsNullOrEmpty(_address) == false);
I'm guessing the UnityOSC author meant to do something like:
Trace.Assert(string.IsNullOrEmpty(value) == false);
Otherwise I'm not sure how that assertion would pass since OSCMessage, a derived class of OSCPacket, directly calls the Address property in its ctor.
Secondly, if you're trying to test this on a local machine, your ports need to match:
public void Init()
{
CreateServer("Server", 5555);
CreateClient("Client", IPAddress.Parse("127.0.0.1"), 5555);
}
Lastly, my manual creation:
OSCHandler handler = new OSCHandler();
handler.Init();
handler.SendMessageToClient<string>("Client", "127.0.0.1", "TestMessage");
handler.UpdateLogs();
I had to slightly modify the authors code to get it to work outside of Unity but only slightly.

I went a different route to get this working in Unity - based off of an older project called openTSPS from James George. You can download it here - it accepts all OSC data:
https://github.com/heaversm/UnityOSC_FS

Related

how to get real time log via perforce api similar to p4v log

I am facing issue with perforce api (.net), as i am unable to pull sync logs in real time.
- What am I trying to do
I am trying to pull real time logs as Sync is triggered using the
Perforce.P4.Client.SyncFiles() command. Similar to the P4V GUI Logs, which update when we try to sync any files.
- What is happening now
As the output is generated only after the command is done execution its not something intended for.
Also tried looking into Perforce.P4.P4Server.RunCommand() which does provide detailed report but only after the execution of the command.
Looked into this
Reason is -
I am trying to add a status update to the Tool i am working on which shows which Perforce file is currently being sync'd.
Please advise. Thanks in Advance.
-Bharath
In the C++ client API (which is what P4V is built on), the client receives an OutputInfo callback (or OutputStat in tagged mode) for each file as it begins syncing.
Looking over the .NET documentation I think the equivalents are the P4CallBacks.InfoResultsDelegate and P4CallBacks.TaggedOutputDelegate which handle events like P4Server.InfoResultsReceived etc.
I ended up with the same issue, and I struggled quite a bit to get it to work, so I will share the solution I found:
First, you should use the P4Server class instead of the Perforce.P4.Connection. They are two classes doing more or less the same thing, but when I tried using the P4.Connection.TaggedOutputReceived events, I simply got nothing back. So instead I tried with the P4Server.TaggedOutputReceived, and there, finally, I got the TaggedOutput just like I wanted.
So, here is a small example:
P4Server p4Server = new P4Server(cwdPath); //In my case I use P4Config, so no need to set user or to login, but you can do all that with the p4Server here.
p4Server.TaggedOutputReceived += P4ServerTaggedOutputEvent;
p4Server.ErrorReceived += P4ServerErrorReceived;
bool syncSuccess=false;
try
{
P4Command syncCommand = new P4Command(p4Server, "sync", true, syncPath + "\\...");
P4CommandResult rslt = syncCommand.Run();
syncSuccess=true;
//Here you can read the content of the P4CommandResult
//But it will only be accessible when the command is finished.
}
catch (P4Exception ex) //Will be caught only when the command has failed
{
Console.WriteLine("P4Command failed: " + ex.Message);
}
And the method to handle the error messages or the taggedOutput:
private void P4ServerErrorReceived(uint cmdId, int severity, int errorNumber, string data)
{
Console.WriteLine("P4ServerErrorReceived:" + data);
}
private void P4ServerTaggedOutputEvent(uint cmdId, int ObjId, TaggedObject Obj)
{
Console.WriteLine("P4ServerTaggedOutputEvent:" + Obj["clientFile"]); //Write the synced file name.
//Note that I used this only for a 'Sync' command, for other commands, I guess there might not be any Obj["clientFile"], so you should check for that.
}

c# Bluetooth LE - write configuration error - ValueChanged never called

So I try to connect my c# WPF program to a BLE device and this is the code to connect to the device:
private async Task ConnectToWatcher(DeviceInformation deviceInfo) {
try {
// get the device
BluetoothLEDevice device = await BluetoothLEDevice.FromIdAsync(deviceInfo.Id);
// get the GATT service
Thread.Sleep(150);
var gattServicesResult = await device.GetGattServicesForUuidAsync(new Guid(RX_SERVICE_UUID));
service = gattServicesResult.Services[0];
// get the GATT characteristic
Thread.Sleep(150);
var gattCharacteristicsResult = await service.GetCharacteristicsForUuidAsync(new Guid(RX_CHAR_UUID));
characteristic = gattCharacteristicsResult.Characteristics[0];
// register for notifications
Thread.Sleep(150);
characteristic.ValueChanged += (sender, args) => {
Debug.WriteLine($"[{device.Name}] Received notification containing {args.CharacteristicValue.Length} bytes");
};
GattWriteResult result =
await characteristic.WriteClientCharacteristicConfigurationDescriptorWithResultAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify);
Debug.WriteLine($"Characteristics write result: status={result.Status}, protocolError={result.ProtocolError}");
} catch (Exception ex) when ((uint)ex.HResult == 0x800710df) {
Debug.WriteLine("bluetooth error 1");
// ERROR_DEVICE_NOT_AVAILABLE because the Bluetooth radio is not on.
}
}
The line
Debug.WriteLine($"Characteristics write result: status={result.Status}, protocolError={result.ProtocolError}"
creates the output
Characteristics write result: status=protocolError, protocolError=3
I couldn't find anywhere whats that supposed to mean. The effect is the Method characteristic.ValueChanged never gets called.
Do I have to do more to have the characteristic configurated? And has anybody any idea why the method isn't called or what that error message means?
Thanks a bunch.
Apparently, some Windows 10 builds have a COM security bug.
Solution was to register for Windows-Insider-Program and update Windows.
Update:
There are two more solutions to this:
1) Calling CoInitializeSecurity from outside your c#-code (didn't bring it to work)
- or-
2) Writing two new keys into the windows registry. You cann create a file "Bluetooth.reg", which will add those two keys on a doubleklick. This answer from https://social.msdn.microsoft.com/Forums/en-US/58da3fdb-a0e1-4161-8af3-778b6839f4e1/bluetooth-bluetoothledevicefromidasync-does-not-complete-on-10015063?forum=wdk was my solution:
Hi Kamen, I have experienced exactly same issue. You can give a quick try of the following:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID{C6BFD646-3DF0-4DE5-B7AF-5FFFACB844A5}]
"AccessPermission"=hex:01,00,04,80,9c,00,00,00,ac,00,00,00,00,00,00,00,14,00,\
00,00,02,00,88,00,06,00,00,00,00,00,14,00,07,00,00,00,01,01,00,00,00,00,00,\
05,0a,00,00,00,00,00,14,00,03,00,00,00,01,01,00,00,00,00,00,05,12,00,00,00,\
00,00,18,00,07,00,00,00,01,02,00,00,00,00,00,05,20,00,00,00,20,02,00,00,00,\
00,18,00,03,00,00,00,01,02,00,00,00,00,00,0f,02,00,00,00,01,00,00,00,00,00,\
14,00,03,00,00,00,01,01,00,00,00,00,00,05,13,00,00,00,00,00,14,00,03,00,00,\
00,01,01,00,00,00,00,00,05,14,00,00,00,01,02,00,00,00,00,00,05,20,00,00,00,\
20,02,00,00,01,02,00,00,00,00,00,05,20,00,00,00,20,02,00,00
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID\YOURAPP.exe]
"AppID"="{C6BFD646-3DF0-4DE5-B7AF-5FFFACB844A5}"
Copy above content to a text file.
Replace 'YOURAPP.EXE' with your executable name
Optionally replace GUIDs (I have created a new one for you)
Save text file with an extension as .reg
Double click on the file.
You would see a message 'The Keys and values contained in ..... .reg have been successfully added to the registry.'
With this, I don't need to call CoInitializeSecurity from my app.
you need to call CoInitializeSecurity before
more info here. couple of weeks I spent looking for solution :)
https://social.msdn.microsoft.com/Forums/en-US/58da3fdb-a0e1-4161-8af3-778b6839f4e1/

Native messaging from chrome extension to native host written in C#

I'm trying to receive a message from my chrome extension via native messaging. The popup.html console indicates that the message is being sent, but my host is not receiving it for some reason. I can see that the host native.exe is being launched in task manager, but the host is not receive the sent data.
popup.js
document.addEventListener('DOMContentLoaded', function() {
var downloadButton= document.getElementById('Button');
downloadButton.addEventListener('click', function () {
chrome.tabs.query({currentWindow: true, active: true}, function (tabs) {
chrome.tabs.executeScript(tabs[0].id, {file: "myScript.js"}, function (data) {
sendNativeMessage(data[0]);
});
});
});
});
function sendNativeMessage(msg) {
var hostName = "com.google.example";
console.log("Connecting to host: " + hostName);
port = chrome.runtime.connectNative(hostName);
message = {"text": msg};
port.postMessage(message);
console.log("Sent message: " + JSON.stringify(message));
}
Now, when I send the message from my Chrome Extension, I can see the console log for popup.html and the message is correct.
I tried to test everything by using some code that someone claimed to have worked, from Native Messaging Chrome. Specifically, I have
native.exe
static void Main(string[] args) {
while (OpenStandardStreamIn() != null || OpenStandardStreamIn() != "")
{
Console.WriteLine(OpenStandardStreamIn());
}
}
private static string OpenStandardStreamIn()
{
//Read first four bytes for length information
System.IO.Stream stdin = Console.OpenStandardInput();
int length = 0;
byte[] bytes = new byte[4];
stdin.Read(bytes, 0, 4);
length = System.BitConverter.ToInt32(bytes, 0);
string input = "";
for (int i = 0; i < length; i++)
input += (char)stdin.ReadByte();
return input;
}
I'm still trying to wrap my head around nativeMessaging, but since I can see the message being sent via the console logs, I have to assume the error is with my .exe. I have created the registry keys, HKCU, and created the host's manifest.json file. Since the extension is launching the .exe, I'm pretty sure all of that is working fine as well.
If anyone could provide some assistance with this, that would be much appreciated. Thanks!
EDIT: After changing absolutely nothing, I cannot get my native.exe to launch anymore from my extension. In an effort to fix this, I tried rewriting my sender to not open a port:
...
chrome.tabs.executeScript(tabs[0].id, {file: "myScript.js"}, function (data) {
chrome.runtime.sendNativeMessage('com.google.example', {"text":data[0]}, function(response) {
if (chrome.runtime.lastError)
console.log("ERROR");
} else {
console.log("Response: " + response);
}
});
});
...
This doesn't work at all either. I have no idea what I'm doing wrong, or why my host .exe stopped launching when I sent a message from my extension.
EDIT #2
Good news!
I deleted my registry key and then added it again, this time into the Local Machine registry (i.e. HKLM). Again, I used the code from Native Messaging Chrome to send and receive from my host. Now, when I look at my extension's log, I can see the correct response from my host. I am using the "no-port" method by simply calling chrome.runtime.sendNativeMessage(...), which is fine for my purposes. Unfortunately, I am not receiving the message FROM the extension TO the host. Also, my host.exe never exits, even after the message has been received. I'm not sure why, but if anyone can help out, I would appreciate it.
In my host, I'm attempting to write the incoming message to a file just to test that I'm getting the message:
System.IO.File.WriteAllText(#"path_to_file.txt", OpenStandardStreamIn());
Note: The message that I'm passing FROM the extension TO the host is around 250KB (it varies from message to message).
The problem is:
Nothing is written to the file. It's completely blank.
The file takes a long time to create (~4 seconds).
My host.exe instance never terminates. It's still running (I can view it in the task manager).
In order to get my extension working, I followed the following steps:
I deleted my registry key and then re-added it in my HKLM registry.
Although unnecessary,host.exe really only needed to receive one message from the extension, so I changed my previous "open port" messaging to a "no port" message, i.e.
chrome.runtime.sendNativeMessage(...);
Importantly, when I changed the text I was sending from {"text":data[0]} to a simple string {"text":"Hello from Chrome!"}, everything began working smoothly. data[0] was a string of about 250KB, which should definitely be an acceptable message size according to the developer's site. However, I have created a different question for this problem, as I was able to solve the general message sending and receiving problem I was experiencing.

How do I look up a Corba service with C# and IIOP.NET?

I am writing a C# client for a Corba server and I am using IIOP.NET, going by the example on the following page: http://iiop-net.sourceforge.net/rmiAdderDNClient.html
I have gotten this far without errors:
// Register channel
IiopClientChannel channel = new IiopClientChannel();
ChannelServices.RegisterChannel(channel, false);
// Access COS naming context
CorbaInit init = CorbaInit.GetInit();
NamingContext context = init.GetNameService(host, port);
The variable "host" is a string with the computer name of the server and "port" is an int representing the port number. The values for these are currently used by other systems to connect to the server so I can confirm that they are correct.
However, trying to connect to the trader service yields an exception in runtime. Here is the code I use to do that:
// Looking up VB Trader
NameComponent[] names = new NameComponent[] { new NameComponent("TraderInterface") };
object obj = context.resolve(names);
And here is the error message I'm getting:
"CORBA system exception : omg.org.CORBA.INV_OBJREF, completed: Completed_No minor: 10102."
This seems to suggest an invalid object reference, but what does that mean? Is the string I am passing to the resolve method incorrectly formatted? I have tried many different names for this service as used in other systems, but I always get the same error, which makes me wonder whether I am even interpreting it correctly.
Incidentally, in my desperation, I have also attempted to obtain an object reference from the IOR, but this again throws a different exception (namely omg.org.CORBA.ORB_package.InvalidName).
OrbServices orb = OrbServices.GetSingleton();
object obj = orb.resolve_initial_references(traderIOR);
Any advice is welcome.
I was never able to reach my server with any of the above methods, however the following code is what finally got the communication working:
Hashtable props = new Hashtable();
props[IiopChannel.BIDIR_KEY] = true;
props[IiopServerChannel.PORT_KEY] = port;
// register corba services
IiopChannel channel = new IiopChannel(props);
ChannelServices.RegisterChannel(channel, false);
MyInterface obj = (MyInterface)RemotingServices.Connect(typeof(MyInterface), ior);
I'm not entirely sure why I had to use this (seemingly) unconventional way. Perhaps it is due to the lack of a naming service running on the server. Whatever the cause, I hope this helps somebody out there.

Problem with WebSockets Draft

I'm having some trobule with Web Sockets and Microsoft's Draft implementation. I'm using the API provided by them for the server back and as well as the Silverlight fix for browsers that don't natively support Web Sockets. The information i'm working off of comes from http://channel9.msdn.com/Events/MIX/MIX11/HTM10 and http://html5labs.interoperabilitybridges.com/prototypes/websockets/websockets/info
My code compiles okay, it starts to open the connection, then fails. Here's my backend server code (in a C# Console App)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.ServiceModel.WebSockets;
namespace ChatBackend
{
class Program
{
static void Main(string[] args)
{
var host = new WebSocketsHost<MessageHandler>();
host.AddWebSocketsEndpoint("ws://localhost:4502/MessageHandler");
host.Open();
Console.ReadLine();
}
}
}
Here's the MessageHandler class:
class MessageHandler : WebSocketsService
{
public override void OnMessage(string value)
{
string returnMessage = "You just said '" + value + "'";
Console.WriteLine(value);
SendMessage(returnMessage);
}
}
This backend part seems to work fine. Here's the client end:
$(document).ready(function () {
setTimeout(connect, 2050);
});
function connect() {
websocket = new WebSocketDraft("ws://localhost:4502/MessageHandler");
websocket.onopen = function() {
websocket.send("test");
};
websocket.onclose = function () {
alert("DIED");
};
websocket.onmessage = function(event) {
sendMessage(new message(0, event.data, 0));
};
}
EDIT: I checked my firewall and allowed the port i was using. Now the connection just hangs - it doesn't close, it doesn't open. Any ideas?
EDIT 2: I did some more research, turns out i need to remove the clientaccesspolicy.xml. Also turns out i never had it, but i WAS returning a custom 302 redirect instead of a 404 not found. Fixed that, but no progress. It just hangs.
EDIT 3: Tried turning off Anti-Virus and Firewall, no change
Thanks - let me know if i need anymore code or information up here.
Can you use Firebug or something and put a breakpoint on this line in jquery.slws.js (assuming its the one you're using!)
this.slws = slCtl.Content.services.createObject("websocket");
And then step through and see where it fails ?
Your URL definitely looks like it matches the setting on your server side. It's really hard to find any examples of WebSockets actually being used since it's still such a new technology, but from what I could follow of the only working example I could find (it was on the html5labs site), I think maybe you're trying to write to the socket before it's finished opening. In the example I found, it looked like they check the readyState property of the socket, and only try to send if readyState === 1. The socket in that example gets opened by tying into the $(document).ready event, and send gets called from a button click.
Finally got this working! Turns out i had to add clientaccesspolicy.xml to the root folder of the default website on my server. I thought i had to delete it - i misread some information and promptly forgot about it. Moral of the story: read the readme!

Categories