kshoji / USB-MIDI-Driver

USB MIDI Driver for Android 3.1 or later
Apache License 2.0
290 stars 106 forks source link

How to get usb midi device product name? #28

Closed sinosoidal closed 9 years ago

sinosoidal commented 9 years ago

Hi,

I cannot find a way of getting product device name without consulting the usb descriptors. Am I missing something? In case you don't have support for this I have a fix suggestion.

Looking forward to hear something from you.

Regards,

Nuno

kshoji commented 9 years ago

Hi,

The MidiInputDevice / MidiOutputDevice have getter of UsbDevice, so I had not feel necessity to provide device name getter. Currently, the device name can be obtained from UsbDevice instance.

On my another library, BLE MIDI library's MidiInputDevice / MidiOutputDevice provides the getter method of the device name. With following the library implementation, I'll add the getter method.

Regards, Kaoru

kshoji commented 9 years ago

The product name means UsbDevice.getDeviceName() 's result? This method returns the linux device path, like '/dev/bus/usb/001/001'.

With API Level 21, there is UsbDevice.getProductName(), it will return the product name. This library is using API Level 12, so it can't use the getProductName method. Did you know another way to get the product name?

Regards, Kaoru

planethcom commented 9 years ago

Guess there’s no other way. But you add something like:

@SuppressLint("NewApi")

public String getDeviceName()

{

if (Build.VERSION.SDK_INT >= 21)

{

    return attachedDevice.getManufacturerName() + " " + attachedDevice.getProductName();

}

else

{

    attachedDevice.getDeviceName();

}

}

That way at least Android 5 users get the real device name.

Von: Kaoru Shoji [mailto:notifications@github.com] Gesendet: Dienstag, 24. Februar 2015 05:50 An: kshoji/USB-MIDI-Driver Betreff: Re: [USB-MIDI-Driver] How to get usb midi device product name? (#28)

The product name means UsbDevice.getDeviceName() 's result? This method returns the linux device path, like '/dev/bus/usb/001/001'.

With API Level 21, there is UsbDevice.getProductName(), it will return the product name. This library is using API Level 12, so it can't use the getProductName method. Did you know another way to get the product name?

Regards, Kaoru

— Reply to this email directly or view it on GitHub https://github.com/kshoji/USB-MIDI-Driver/issues/28#issuecomment-75699147 .Das Bild wurde vom Absender entfernt.

sinosoidal commented 9 years ago

Hi,

There is in fact another way, which could benefit all other users with a lower API OS. For example, my app will be targeted for API 15. It is a shame that my users can’t see the product name. Would be really bad.

When the device is open, you can access it’s device descriptors with custom usb control requests.

I have already done this in the past in plain C but I have found an answer in stack overflow for the same problem in Java. I have tested the code within usb-midi-driver. It works.

http://stackoverflow.com/questions/13217755/usb-interface-in-android http://stackoverflow.com/questions/13217755/usb-interface-in-android

    int STD_USB_REQUEST_GET_DESCRIPTOR = 0x06;
        int LIBUSB_DT_STRING = 0x03;

        //deviceConnection.claimInterface(intf, true);

        // getRawDescriptors can be used to access descriptors 
        // not supported directly via the higher level APIs, 
        // like getting the manufacturer and product names.
        // because it returns bytes, you can get a variety of
        // different data types.
        byte[] rawDescs = deviceConnection.getRawDescriptors();
        String manufacturer = "", product = "";

        try
        {
            byte[] buffer = new byte[255];
            int idxMan = rawDescs[14];
            int idxPrd = rawDescs[15];

            int rdo = deviceConnection.controlTransfer(UsbConstants.USB_DIR_IN | UsbConstants.USB_TYPE_STANDARD, STD_USB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_STRING << 8) | idxMan, 0, buffer, 0xFF, 0);
            manufacturer = new String(buffer, 2, rdo - 2, "UTF-16LE");

            rdo = deviceConnection.controlTransfer(UsbConstants.USB_DIR_IN | UsbConstants.USB_TYPE_STANDARD, STD_USB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_STRING << 8) | idxPrd, 0, buffer, 0xFF, 0);
            product = new String(buffer, 2, rdo - 2, "UTF-16LE");

        } 
        catch (UnsupportedEncodingException e)
        {
            e.printStackTrace();
        }

        Log.d(Constants.TAG, "Manufacturer: " + manufacturer + " Product: " + product);

I’m calling this code just before onDeviceAttached on the UsbMidiDriver class.

The only problem is that the whole UsbMidiDriverClass is not officially prepared to handle this. I wanted to pass the device name as a parameter to the onAttachedDevice but that has some great implications over the code. I’m also thinking in having an hash table in the UsbMidiDriver class for path/product name. I started using this project a little time ago, so I have limited knowledge about it’s overall architecture. I just want to contribute with this enhancement because I think it will greatly improve it.

Looking forward to hear your opinion on this.

Regards,

Nuno

On 24/02/2015, at 06:38, planethcom notifications@github.com wrote:

Guess there’s no other way. But you add something like:

@SuppressLint("NewApi")

public String getDeviceName()

{

if (Build.VERSION.SDK_INT >= 21)

{

return attachedDevice.getManufacturerName() + " " + attachedDevice.getProductName();

}

else

{

attachedDevice.getDeviceName();

}

}

That way at least Android 5 users get the real device name.

Von: Kaoru Shoji [mailto:notifications@github.com] Gesendet: Dienstag, 24. Februar 2015 05:50 An: kshoji/USB-MIDI-Driver Betreff: Re: [USB-MIDI-Driver] How to get usb midi device product name? (#28)

The product name means UsbDevice.getDeviceName() 's result? This method returns the linux device path, like '/dev/bus/usb/001/001'.

With API Level 21, there is UsbDevice.getProductName(), it will return the product name. This library is using API Level 12, so it can't use the getProductName method. Did you know another way to get the product name?

Regards, Kaoru

— Reply to this email directly or view it on GitHub https://github.com/kshoji/USB-MIDI-Driver/issues/28#issuecomment-75699147 .Das Bild wurde vom Absender entfernt.

— Reply to this email directly or view it on GitHub https://github.com/kshoji/USB-MIDI-Driver/issues/28#issuecomment-75707124.

sinosoidal commented 9 years ago

You were quick! :)

Need to try your changes. I will let you know the results than.

Regards,

Nuno

On 02 Mar 2015, at 03:37, Kaoru Shoji notifications@github.com wrote:

Closed #28 https://github.com/kshoji/USB-MIDI-Driver/issues/28.

— Reply to this email directly or view it on GitHub https://github.com/kshoji/USB-MIDI-Driver/issues/28#event-244110407.

planethcom commented 9 years ago

Works perfectly!

Thanks a lot, both of you.

Regards, Andreas

Von: sinosoidal [mailto:notifications@github.com] Gesendet: Montag, 2. März 2015 15:10 An: kshoji/USB-MIDI-Driver Cc: planethcom Betreff: Re: [USB-MIDI-Driver] How to get usb midi device product name? (#28)

You were quick! :)

Need to try your changes. I will let you know the results than.

Regards,

Nuno

On 02 Mar 2015, at 03:37, Kaoru Shoji notifications@github.com wrote:

Closed #28 https://github.com/kshoji/USB-MIDI-Driver/issues/28.

— Reply to this email directly or view it on GitHub https://github.com/kshoji/USB-MIDI-Driver/issues/28#event-244110407.

— Reply to this email directly or view it on GitHub https://github.com/kshoji/USB-MIDI-Driver/issues/28#issuecomment-76717225 .Das Bild wurde vom Absender entfernt.

finndesolace commented 9 years ago

I'm testing in kitkat with roland um one and still get midiOutputDevice.getUsbDevice().getDeviceName() nullpointerexception.

this is my logcat output:: 04-26 13:21:52.115: D/ActivityThread(12568): handleBindApplication:com.example.miditest 04-26 13:21:52.115: D/ActivityThread(12568): setTargetHeapUtilization:0.75 04-26 13:21:52.115: D/ActivityThread(12568): setTargetHeapMinFree:2097152 04-26 13:21:52.165: I/dalvikvm(12568): Could not find method android.hardware.usb.UsbDevice.getManufacturerName, referenced from method jp.kshoji.driver.midi.util.UsbMidiDeviceUtils.getManufacturerName 04-26 13:21:52.165: W/dalvikvm(12568): VFY: unable to resolve virtual method 639: Landroid/hardware/usb/UsbDevice;.getManufacturerName ()Ljava/lang/String; 04-26 13:21:52.165: D/dalvikvm(12568): VFY: replacing opcode 0x6e at 0x0006 04-26 13:21:52.165: I/dalvikvm(12568): Could not find method android.hardware.usb.UsbDevice.getProductName, referenced from method jp.kshoji.driver.midi.util.UsbMidiDeviceUtils.getProductName 04-26 13:21:52.165: W/dalvikvm(12568): VFY: unable to resolve virtual method 641: Landroid/hardware/usb/UsbDevice;.getProductName ()Ljava/lang/String; 04-26 13:21:52.165: D/dalvikvm(12568): VFY: replacing opcode 0x6e at 0x0006 04-26 13:21:52.175: D/MIDIDriver(12568): attached deviceName:/dev/bus/usb/001/002, device:UsbDevice[mName=/dev/bus/usb/001/002,mVendorId=1410,mProductId=298,mClass=255,mSubclass=0,mProtocol=255,mInterfaces=[Landroid.os.Parcelable;@41aab6e0] 04-26 13:21:52.225: D/MIDIDriver(12568): Device /dev/bus/usb/001/002 has been attached. 04-26 13:21:52.255: I/Adreno-EGL(12568): : EGL 1.4 QUALCOMM build: AU_LINUX_ANDROID_LNX.LA.3.5.2.2_RB1.04.04.04.087.028_msm8974_LNX.LA.3.5.2.2_RB1__release_AU () 04-26 13:21:52.255: I/Adreno-EGL(12568): OpenGL ES Shader Compiler Version: E031.24.00.15 04-26 13:21:52.255: I/Adreno-EGL(12568): Build Date: 07/31/14 Thu 04-26 13:21:52.255: I/Adreno-EGL(12568): Local Branch: 04-26 13:21:52.255: I/Adreno-EGL(12568): Remote Branch: quic/LNX.LA.3.5.2.2_rb1 04-26 13:21:52.255: I/Adreno-EGL(12568): Local Patches: NONE 04-26 13:21:52.255: I/Adreno-EGL(12568): Reconstruct Branch: AU_LINUX_ANDROID_LNX.LA.3.5.2.2_RB1.04.04.04.087.028 + NOTHING 04-26 13:21:52.295: D/OpenGLRenderer(12568): Enabling debug mode 0 04-26 13:21:52.355: W/IInputConnectionWrapper(12568): showStatusIcon on inactive InputConnection 04-26 13:21:52.365: I/Timeline(12568): Timeline: Activity_idle id: android.os.BinderProxy@41a95f70 time:56582671 04-26 13:21:53.985: I/Timeline(12568): Timeline: Activity_idle id: android.os.BinderProxy@41a95f70 time:56584292 04-26 13:21:55.535: D/AndroidRuntime(12568): Shutting down VM 04-26 13:21:55.535: W/dalvikvm(12568): threadid=1: thread exiting with uncaught exception (group=0x415dfdb8) 04-26 13:21:55.545: E/AndroidRuntime(12568): FATAL EXCEPTION: main 04-26 13:21:55.545: E/AndroidRuntime(12568): Process: com.example.miditest, PID: 12568 04-26 13:21:55.545: E/AndroidRuntime(12568): java.lang.IllegalStateException: Could not execute method of the activity 04-26 13:21:55.545: E/AndroidRuntime(12568): at android.view.View$1.onClick(View.java:3830) 04-26 13:21:55.545: E/AndroidRuntime(12568): at android.view.View.performClick(View.java:4445) 04-26 13:21:55.545: E/AndroidRuntime(12568): at android.view.View$PerformClick.run(View.java:18446) 04-26 13:21:55.545: E/AndroidRuntime(12568): at android.os.Handler.handleCallback(Handler.java:733) 04-26 13:21:55.545: E/AndroidRuntime(12568): at android.os.Handler.dispatchMessage(Handler.java:95) 04-26 13:21:55.545: E/AndroidRuntime(12568): at android.os.Looper.loop(Looper.java:136) 04-26 13:21:55.545: E/AndroidRuntime(12568): at android.app.ActivityThread.main(ActivityThread.java:5146) 04-26 13:21:55.545: E/AndroidRuntime(12568): at java.lang.reflect.Method.invokeNative(Native Method) 04-26 13:21:55.545: E/AndroidRuntime(12568): at java.lang.reflect.Method.invoke(Method.java:515) 04-26 13:21:55.545: E/AndroidRuntime(12568): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:732) 04-26 13:21:55.545: E/AndroidRuntime(12568): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:566) 04-26 13:21:55.545: E/AndroidRuntime(12568): at dalvik.system.NativeStart.main(Native Method) 04-26 13:21:55.545: E/AndroidRuntime(12568): Caused by: java.lang.reflect.InvocationTargetException 04-26 13:21:55.545: E/AndroidRuntime(12568): at java.lang.reflect.Method.invokeNative(Native Method) 04-26 13:21:55.545: E/AndroidRuntime(12568): at java.lang.reflect.Method.invoke(Method.java:515) 04-26 13:21:55.545: E/AndroidRuntime(12568): at android.view.View$1.onClick(View.java:3825) 04-26 13:21:55.545: E/AndroidRuntime(12568): ... 11 more 04-26 13:21:55.545: E/AndroidRuntime(12568): Caused by: java.lang.NullPointerException 04-26 13:21:55.545: E/AndroidRuntime(12568): at com.example.miditest.MainActivity.testgetdevicename(MainActivity.java:41) 04-26 13:21:55.545: E/AndroidRuntime(12568): at com.example.miditest.MainActivity.test(MainActivity.java:35) 04-26 13:21:55.545: E/AndroidRuntime(12568): ... 14 more 04-26 13:21:57.955: I/Process(12568): Sending signal. PID: 12568 SIG: 9

Also thus

byte[] presetReq = new byte[] { (byte) 0xf0, 0x00, 0x01, 0x55, 0x12, 0x01, 0x63, 0x00, 0x00, (byte) 0xf7 }; midiOutputDevice.sendMidiSystemExclusive(0, presetReq)

Does not seem to work.

Could you help me out?

finndesolace commented 9 years ago

Okay So I've found that since i'm doing midiOutputDevice = getMidiOutputDevice(); and afterwards using that in another method; i get a nullpointerexception

But I think that has to do with the lifecycle. So everytime i'd send a message i have to use getMidiOutputDevice()

And that solves my problem.