-
Notifications
You must be signed in to change notification settings - Fork 105
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
MIDI Input Broken on Android 4 #58
Comments
I experienced the exact same problem on an Android tablet running 4.4. However, while your fix allowed me to receive events, it caused crashes when disconnecting the device. Instead I implemented a different solution. the midiEventListener is initialized to null. inside the waiterThread, after the sleeping I check if the listener is null, if so I 'continue' the loop, else I allow processing to continue. This solved the race condition you identified, and also resolved my crashing problem. |
I had got the same issue and resolved by this solution:
public void start2Work() {
if (!waiterThread.isAlive()) {
waiterThread.start();
}
}
|
Still doesn't work for me, even with FlyingFishBird solution... any idea ? :/ |
Ok now i get midi input but on large sysex receptions sometimes the sysex gets mangled, any idea ? |
This is most likely a problem with the USB MIDI interface.
Some interfaces (e.g. the Roland UM-ONE) have reported exactly this problem.
I’d recommend to try a different interface, e.g. the ESI MIDIMate II works perfectly.
Von: AlGrenadine [mailto:[email protected]]
Gesendet: Freitag, 25. November 2016 10:59
An: kshoji/USB-MIDI-Driver
Betreff: Re: [kshoji/USB-MIDI-Driver] MIDI Input Broken on Android 4 (#58)
Ok now i get midi input but on large sysex receptions sometimes the sysex gets mangled, any idea ?
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub <#58 (comment)> , or mute the thread <https://github.com/notifications/unsubscribe-auth/AF5BLI0uc_5EHrcDuw84BxY8q6vSz00_ks5rBrFZgaJpZM4JDeW0> .Das Bild wurde vom Absender entfernt.
|
Yes i use a Roland UM One, but then why does it work if i use Marshmallow's midi feature ? With android 6, the sysex is not mangled, so it's not the interface the culprit... |
The UM-One is overall a good interface.
I actually use one by myself for testing.
And yes, it works with the Android Marshmallow MIDI api (if you set the interface to class-compliant using the small dip switch on the interface).
But it has some weird technical internals, different to other interfaces.
That it works with the Android 6 does not proof that it also works with raw usb bulk transfer.
However, what you can try is to check (by debuggning) if there are running multiple MidiInputDevices (in other words multiple threads listening to the same in port).
That could theoretically result in such a problem, and the fact that there are 2 IN threads running could be a result of the UM-One.
Try do boot your device, then start the app the first time, then plug in the interface and test sysex…
If that worked, unplug it and reconnect it again, then test sysex again…
Can you force the error to happen that way?
Btw. I’m not the dev of the MIDI driver, I’ve just derived my old pre marshmallow midi driver from it a couple of years ago.
I just remember approximately the same discussion with some other user a while ago, and there it turned out that the UM-One was the problem.
Von: AlGrenadine [mailto:[email protected]]
Gesendet: Freitag, 25. November 2016 11:51
An: kshoji/USB-MIDI-Driver
Cc: planethcom; Comment
Betreff: Re: [kshoji/USB-MIDI-Driver] MIDI Input Broken on Android 4 (#58)
Yes i use a Roland UM One, but then why does it work if i use Marshmallow's midi feature ? With android 6, the sysex is not mangled, so it's not the interface the culprit...
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub <#58 (comment)> , or mute the thread <https://github.com/notifications/unsubscribe-auth/AF5BLHXXMdxrjJZdQGQyxj3EwjDJZtXlks5rBr2IgaJpZM4JDeW0> .Das Bild wurde vom Absender entfernt.
|
Yes i can reproduce the problem everytime, not only with um one but also with an usb midi class compliant device. |
That would explain why it’s only affecting sysex messages.
Regular midi messages are all small enough to fit into one usb transmission packet (max packet size on android is usually 64bytes as far as I remember).
A sysex message might be transmitted in multiple packets.. and if another thread grabs some of the packets in between, the result would be mangled.
Hope that helps getting it solved
Von: AlGrenadine [mailto:[email protected]]
Gesendet: Freitag, 25. November 2016 13:13
An: kshoji/USB-MIDI-Driver
Cc: planethcom; Comment
Betreff: Re: [kshoji/USB-MIDI-Driver] MIDI Input Broken on Android 4 (#58)
Yes i can reproduce the problem everytime, not only with um one but also with an usb midi class compliant device.
I'll check the MidiInputDevices, that's a good idea, thanks
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub <#58 (comment)> , or mute the thread <https://github.com/notifications/unsubscribe-auth/AF5BLKOuJwnUYzx-PDhOvPPbxJQbOxQHks5rBtCwgaJpZM4JDeW0> .Das Bild wurde vom Absender entfernt.
|
Sadly, i only have 1 MidiInputDevice thread running... |
Here are the USB descriptors of the midi interface : *** ERROR: Descriptor has errors! *** Connection Information:Connection status: Device connected Device Descriptor:0x12 bLength Device Qualifier Descriptor:0x0A bLength Configuration Descriptor:0x09 bLength Interface Association Descriptor:0x08 bLength Interface Descriptor:0x09 bLength AC Interface Header Descriptor:0x09 bLength AC Clock Source Descriptor:0x08 bLength AC Input Terminal Descriptor:0x11 bLength AC Output Terminal Descriptor:0x0C bLength AC Input Terminal Descriptor:0x11 bLength AC Output Terminal Descriptor:0x0C bLength Interface Descriptor:0x09 bLength Interface Descriptor:0x09 bLength AS Interface Descriptor:0x10 bLength AS Format Type 1 Descriptor:0x06 bLength Endpoint Descriptor:0x07 bLength AS Isochronous Data Endpoint Descriptor:0x08 bLength Interface Descriptor:0x09 bLength Interface Descriptor:0x09 bLength AS Interface Descriptor:0x10 bLength AS Format Type 1 Descriptor:0x06 bLength Endpoint Descriptor:0x07 bLength AS Isochronous Data Endpoint Descriptor:0x08 bLength Interface Descriptor:0x09 bLength AC Interface Header Descriptor:0x09 bLength Interface Descriptor:0x09 bLength MS Interface Header Descriptor:0x07 bLength MS MIDI IN Jack Descriptor:0x06 bLength MS MIDI IN Jack Descriptor:0x06 bLength MS MIDI OUT Jack Descriptor:0x09 bLength MS MIDI OUT Jack Descriptor:0x09 bLength Endpoint Descriptor (Audio/MIDI):0x09 bLength MS Bulk Data Endpoint Descriptor:0x05 bLength Endpoint Descriptor (Audio/MIDI):0x09 bLength MS Bulk Data Endpoint Descriptor:0x05 bLength Configuration Descriptor:0x09 bLength Interface Association Descriptor:0x08 bLength Interface Descriptor:0x09 bLength AC Interface Header Descriptor:0x09 bLength AC Clock Source Descriptor:0x08 bLength AC Input Terminal Descriptor:0x11 bLength AC Output Terminal Descriptor:0x0C bLength AC Input Terminal Descriptor:0x11 bLength AC Output Terminal Descriptor:0x0C bLength Interface Descriptor:0x09 bLength Interface Descriptor:0x09 bLength AS Interface Descriptor:0x10 bLength AS Format Type 1 Descriptor:0x06 bLength Endpoint Descriptor:0x07 bLength AS Isochronous Data Endpoint Descriptor:0x08 bLength Interface Descriptor:0x09 bLength Interface Descriptor:0x09 bLength AS Interface Descriptor:0x10 bLength AS Format Type 1 Descriptor:0x06 bLength Endpoint Descriptor:0x07 bLength AS Isochronous Data Endpoint Descriptor:0x08 bLength Interface Descriptor:0x09 bLength AC Interface Header Descriptor:0x09 bLength Interface Descriptor:0x09 bLength MS Interface Header Descriptor:0x07 bLength MS MIDI IN Jack Descriptor:0x06 bLength MS MIDI IN Jack Descriptor:0x06 bLength MS MIDI OUT Jack Descriptor:0x09 bLength MS MIDI OUT Jack Descriptor:0x09 bLength Endpoint Descriptor (Audio/MIDI):0x09 bLength MS Bulk Data Endpoint Descriptor:0x05 bLength Endpoint Descriptor (Audio/MIDI):0x09 bLength MS Bulk Data Endpoint Descriptor:0x05 bLength *** ERROR: Invalid descriptor type (Exp:0x07 Got:0x02)
|
I've debugged the MidiInputDevice and when my sysex gets bad, it misses 4 bytes. The usb bulk transfer already misses 4 bytes, so should it be an usb buffer overrun ? If yes, how can i prevent this ? |
It seems bulkTransfer is buggy : http://stackoverflow.com/questions/9108548/android-usb-host-bulktransfer-is-losing-data |
Testing with UsbRequest is definitely a good idea.
For real-time midi, UsbRequest is way too laggy, but for sysex, it wouldn’t make a big difference as timing is no concern.
Von: AlGrenadine [mailto:[email protected]]
Gesendet: Freitag, 25. November 2016 14:40
An: kshoji/USB-MIDI-Driver
Cc: planethcom; Comment
Betreff: Re: [kshoji/USB-MIDI-Driver] MIDI Input Broken on Android 4 (#58)
It seems bulkTransfer is buggy : http://stackoverflow.com/questions/9108548/android-usb-host-bulktransfer-is-losing-data
I'm gonna try using UsbRequest
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub <#58 (comment)> , or mute the thread <https://github.com/notifications/unsubscribe-auth/AF5BLLuaMIVXFL6Gj9jkyDCcksUpkkrDks5rBuVEgaJpZM4JDeW0> .Das Bild wurde vom Absender entfernt.
|
Exactly the same problem with UsbRequest... |
Was to be expected since UsbRequest does nothing else than bulkTransfer internally.
What you can try:
Completely disable any midi out functionality, so that the midioutputdevice and its thread gets not started at all. As far as I remember, the um one does in and out over the same endpoint, and that could be the problem.
Definitely worth a try.
On Nov 25, 2016 3:06 PM, AlGrenadine <[email protected]> wrote:Exactly the same problem with UsbRequest...
—You are receiving this because you commented.Reply to this email directly, view it on GitHub, or mute the thread.
|
But my USB midi device has the same problem and its endpoints are different as you can see in the above USB descriptors... |
Just found the original issue I was referring to. Maybe that's helpful.
#40
On Nov 25, 2016 3:20 PM, AlGrenadine <[email protected]> wrote:But my USB midi device has the same problem and its endpoints are different as you can see in the above USB descriptors...
—You are receiving this because you commented.Reply to this email directly, view it on GitHub, or mute the thread.
|
Yes i saw this fix in the code, it already filters MidiInputDevice creation on the same endpoints. But my problem is not the same, my midi input has only 1 endpoint... |
Ok, understood.
So it looks like the only thing you can do is to debug it bit by bit and search for the missing 4 bytes.
If it's in bulk transfer, then it simply won't work with these older android versions.
On Nov 25, 2016 3:31 PM, AlGrenadine <[email protected]> wrote:Yes i saw this fix in the code, it already filters MidiInputDevice creation on the same endpoints. But my problem is not the same, my midi input has only 1 endpoint...
—You are receiving this because you commented.Reply to this email directly, view it on GitHub, or mute the thread.
|
It's now working with um one. |
That makes sense, yes.
Just wondering, how did you get it to work with the um one?
What you can do to avoid the buffer underruns is to put the incoming sysex data into a queue and process it in another thread. That way the midiinputdevice thread is less time intensive and probably fast enough to get the bulkdata in time.
On Nov 25, 2016 4:01 PM, AlGrenadine <[email protected]> wrote:It's now working with um one.
The problem persists on usb device, where speed is crucial.
So for what I understand it seems the data handling in InputMidiDevice is too slow and some data gets lost between 2 bulk reads, because the usb internal buffer may be overrun...
—You are receiving this because you commented.Reply to this email directly, view it on GitHub, or mute the thread.
|
Yes that's what i plan to do but i'm very new to Android and Java dev... Any directions on how to achieve this? |
I'd simply create an ArrayDeque (it's the fastest java queue type) and then put the data into it instead of processing it. Then in another thread that you create, process it the same way as it is now in midiindevice.
That way you give your engine all the time it needs to process.
If it's not real-time you can just instantiate new buffer arrays to fill the data into, no pooling mandatory.
To get the very best performance you can pre-instantiate the buffer arrays and pool them for reuse (also in another ArrayDeque).
On Nov 25, 2016 5:46 PM, AlGrenadine <[email protected]> wrote:Yes that's what i plan to do but i'm very new to Android and Java dev... Any directions on how to achieve this?
—You are receiving this because you commented.Reply to this email directly, view it on GitHub, or mute the thread.
|
The ArrayDeque and second Thread handling the raw usb data was the solution :) |
Talked too fast, still have some bytes missing... |
Which solution did you implement?
I'd recommend to go for the second I mentioned, the one with the pre-initialized buffer pool. That's much faster than instantiating byte arrays at runtime.
You can still have a fallback in case of a pool underrun, where you just resize the pool if required.
On Nov 28, 2016 2:27 PM, AlGrenadine <[email protected]> wrote:Talked too fast, still have some bytes missing...
—You are receiving this because you commented.Reply to this email directly, view it on GitHub, or mute the thread.
|
I used the ArrayDeque, i'm now trying with a https://developer.android.com/reference/java/util/concurrent/BlockingQueue.html |
Blocking queue is slower.
What I mean is to use 2 ArrayDeques, one as queue, and one as byte array pool, so that you can reuse the arrays once they are processed. Also the pool should be pre-initialized during startup. Allocating continuous heap memory at runtime takes a lot of time in java since it triggers the garbage collector.
On Nov 28, 2016 2:37 PM, AlGrenadine <[email protected]> wrote:I used the ArrayDeque, i'm now trying with a https://developer.android.com/reference/java/util/concurrent/BlockingQueue.html
—You are receiving this because you commented.Reply to this email directly, view it on GitHub, or mute the thread.
|
Oh ok that may be my problem, is still allocate new arrays . Trying to implement what you said, thanks ;) |
Still doesn't work, i can't see why, here is the code in MidiInputDevice : |
I’d use ArrayDeque, it’s the only queue without any unwanted memory allocation overhead.
Just be sure to instantiate it big enough at the beginning, so that no resizing is required.
Then, do not fill it with the raw arrays.
Create a buffer item, which contains a byte array and a size int (important: int, not Integer, Integer is a wrapper class, it’s slower than int and has more memory overhead).
Something like:
class BufferItem
{
Byte[] data;
Int dataSize;
}
Then preinit the pool with instances of BufferItem.
That way you don’t need 2 collections for the queue alone.
The problem with most of the java collection classes (and many other classes if the standard library) is that they all have hidden memory allocations.
I usually write my own collections, as slim as possible, without any unrequired stuff and logic inside.
The Java standard library is great, but not in a mobile environment if you need high performance.
Von: AlGrenadine [mailto:[email protected]]
Gesendet: Montag, 28. November 2016 14:55
An: kshoji/USB-MIDI-Driver
Cc: planethcom; Comment
Betreff: Re: [kshoji/USB-MIDI-Driver] MIDI Input Broken on Android 4 (#58)
Still doesn't work, i can't see why, here is the code in MidiInputDevice :
http://pastebin.com/hAR8WHpQ
If you have an idea...
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub <#58 (comment)> , or mute the thread <https://github.com/notifications/unsubscribe-auth/AF5BLFPd0EUkFlQgriTuXjXsQIAiYj2bks5rCt0_gaJpZM4JDeW0> .Das Bild wurde vom Absender entfernt.
|
If you're still having any problems with this, you might find my solution helpful. Cheers |
I've reproduced this issue many times on Android 4.4.2 with Samsung Galaxy Note 2. I've only occasionally reproduced on Android 5, and never on Android 6, and haven't the ability to test Android 3.
The problem is that in MIDIInputDevice, waiterThread is almost always started before midiEventListener reference is set, and therefore incoming MIDI data is never passed to the event listener.
Locally, I have fixed the issue by starting waiterThread in setMidiEventListener. I am very new to this library, as well as to GitHub, so I thought it better to report it here, rather than commit the change.
The text was updated successfully, but these errors were encountered: