ArthurVasseur / USB-Midi-Android-Plugin

A USB MIDI plugin for Android 6.0 and above
MIT License
9 stars 2 forks source link

Problems on Meta Quest Pro #4

Closed trzy closed 1 year ago

trzy commented 1 year ago

Hi Arthur,

Thanks for making this Unity plugin available. I'm using it on a Meta Quest Pro headset and am encountering some problems. Namely:

  1. If I plug in my keyboard via USB-C before launching my app, I do not receive any DeviceAttached event.
  2. If I plug in the keyboard while the app is running, this event fires. It seems like this event should fire when the plugin is initialized and finds an existing device attached, no?

More importantly, in both cases, I never receive any notes. I'm quite certain it is not my MIDI device because it does work with another app (PianoVision AR).

I'm wondering if you have any advice on how to debug further?

Thank you,

Bart

trzy commented 1 year ago

Also, an additional comment: are the callbacks to Unity thread safe? It looks like you run a thread per MIDI device and then call directly back to Unity from that thread via an AndroiJavaProxy. But this will execute outside of the Unity main thread, right?

trzy commented 1 year ago

Trying to build the project. First time using Android Studio -- where is the AAR generated? I only see a .jar file in one of the build/ directories.

ArthurVasseur commented 1 year ago

Hello ! Thanks for the issue !

I don't know why the device is not detected when the keyboard is plugged before the app is launched (I will investigate on the next week)

In the past I used a TCP connection between the java app and the computer.

If you want to debug on Unity side here's the code :

using System.Net.Sockets;
using System.Text;

public class NetworkLogger
{
    public static NetworkLogger Instance = new NetworkLogger();
    private TcpClient _client;

    public NetworkLogger()
    {
        _client = new TcpClient("192.168.1.10", 2121);
    }

    public void Write(string message)
    {
        var stream = _client.GetStream();
        var bytes = Encoding.ASCII.GetBytes(message);
        stream.Write(bytes, 0, bytes.Length);

    }
}

or on the java side :

// not tested
public class TCPLogger {
    public static TCPLogger Instance = new TCPLogger();
    private Socket socket;
    private PrintWriter out;
    private String host;
    private int port;

    public TCPLogger() {
        socket = new Socket("192.168.1.10", 2121);
        out = new PrintWriter(socket.getOutputStream(), true);
    }

    public void log(String message) {
        out.println(message);
    }
}

//And then from the others class you can call : 
// TCPLogger.Instace.log("hello world");

The callbacks are not thread safe, It could be a good idea to add a thread safe callbacks ! For building the aar you need to execute the make task. Then you can find the debug & release file under USB-Midi-Android-Plugin\USBMidiAndroid\build\outputs\aar

If you find a fix don't hesitate to make a merge request, and if you have any questions don't hesitate to ask me !

trzy commented 1 year ago

Thanks, Arthur! I found the problem. It was indeed my device. Turns out my keyboard's fairly complex "zone" system only causes MIDI to be transmitted when certain zones are active by default.

Re: thread safety, I did notice that the callbacks fire on multiple threads. No big deal but might be good to make that clear in examples :) In the case that someone wants to be really clever and handle this themselves, having the raw callbacks is a good idea. Perhaps a good solution would be to provide an object, e.g. MidiReceiver, that implements IMidiCallback and dumps everything into a concurrent queue. If this object is a MonoBehaviour, you could add delegates for each of the callbacks and in its Update() method, the MIDI events can be pulled from the queue and the appropriate callbacks fired. Alternatively, the object need not be a MonoBehaviour but instead provide a Poll() method that takes four callbacks (for each of the MIDI events), and purges the queue, executing callbacks accordingly. Users can optionally use this object if it meets their needs or they can implement IMidiCallback themselves. I might in fact implement one of these solutions myself this weekend and would be happy to contribute via PR.

For debugging things, I ended up just adding a PrintMessageFromAndroid() to the MIDI callback interface and used that to log in Unity, then dropped in an asset that displays a log window in the scene itself.

Re: building, I'll try figuring out how to do this but currently what I found works is to "Rebuild" the project.

I guess the only change that might be necessary is ensuring that the device attached callback fires if the device is already attached and discovered at startup? Not very high priority and if I need this, I can make the change sometime in the next few days and submit a PR.

Great work and thanks for making this open source!

ArthurVasseur commented 1 year ago

Thank you for your feed back !