Midi transmission crash when unplugging USB


#1

Hi all

I am working on an application that communicates with a USB Midi device using Sysex packages. The routines handling the midi connection and midi data is called from a timer interupt.
Sometimes the application “hangs” after I unplug the USB cable and it seems to happend if I unplug the cable while a transmission of data has just been initiated. When the application
"hangs" the timercallback handling the midi connection is no longer called and when I stop the debugger (windows)the code executed is:

bool WaitableEvent::wait (const int timeOutMillisecs) const noexcept
{
return WaitForSingleObject (internal, (DWORD) timeOutMillisecs) == WAIT_OBJECT_0;
}
This code is located in “juce_win32_Threads.cpp”

If I run the code on a Mac and stops the debugger when the application hangs the code being executed is:

bool WaitableEvent::wait (const int timeOutMillisecs) const noexcept
{
return static_cast <WaitableEventImpl*> (internal)->wait (timeOutMillisecs);
}
This code is located in “juce_posix_SharedCode.h”

Any suggestions on how to make the code stable even if the cable is being unplugged while a transmission is taking place is highly appreciated.
Other suggestions are also welcome.

Mery xmas
John


#2

Very hard to know what’s wrong based on that info… Saying that something is using a wait() method, without giving a full stack trace of the relevant threads isn’t very helpful.


#3

[attachment=0]CallStackOSX.png[/attachment][attachment=1]CallStackWindows.PNG[/attachment]

Hi Jules

Thank you for your repsonse. I see your point and I have (tried) to attach a screen dump of the call stacks on both Windows/VS 2010 and Mac/XCode.
Hope this can help.

Thanks

John


#4

Those threads are completely normal - if you pause any running application at any time, that’s what you’d expect to see.

You need to examine all the threads, and figure out which ones are really having a problem.


#5

Hi Jules

Ok, thanks for your repsonse. I am aware that these are the normal threads, I just thought it might be a clue, that the timercallback for the midiconnection class is not called anymore.
I tried to create a thread in my contentcomponent class and let this thread ask if the midiconnection class timer was running and even when the problem occured this would still
return true but the callback is not called anyway. I will follow your advice and look into the running threads.

Thanks

John


#6

Update.

I found out that the Timer thread is still running but the timers are not called.
I asume that the message thread is also stopped from running since I can see that the runDispatchLoopUntil method is never called.
So now I “just” need to figure out what has stopped things from working when I unplugged the USB cable.

Best regards

John


#7

Another update.

A have been doing some more debugging of my application (from Visual Studio) and found out that the last thing that happens before the application “hangs” is a call to midiOutLongMsg from MidiOutput::sendMessageNow.

This method never returns. Any ideas on how this could happend? I have assumed that the midi API can handle that the user unplugs the cable while a transmission it taking place but maybe this assumption is wrong?

Best regards

John


#8

Yet another update

Just tried a little modification to the Juce demo to see how this would handle a similar situation. Added a timercallback to the Audio page demo class that would output some midi data each 10 ms to a default midi output.
When I unplug the USB cable to the device the Juce demo hangs exacly like my own application. Of course I can still have misunderstood something about timer callbacks and midi functionality but I am pretty sure I do things
the right way.

Best regards

John


#9

Ok, but where exactly is it hanging? In the system driver call, or before that in some juce code?


#10

Hi Jules

By inserting some debugging counters, I found out that it never returns from the call to midiOutLongMsg called from MidiOutput::sendMessageNow. I guess that this will cause the message thread to be stalled since the call to midiOutLongMsg is done from a timer callback, right? So it is not hanging in the Juce code but I do not see a way to recover from this issue without shutting down the application.

Best regards

John


#11

Ok, well that’s the driver itself that’s locking-up, so bad luck!

However, it could be because something inside the midi driver is waiting for the message thread to become free before it can continue, and hence getting an internal deadlock. If that’s the case, then using a background thread to send your messages might avoid it.


#12

Ok, thanks. Since I am also repeatedly calling MidiInput::GetDevices () from the timer callback I guess this still needs to be done from the messageThread as I understood by reading another thread on this forum:

http://www.rawmaterialsoftware.com/viewtopic.php?f=2&t=8322&hilit=getDevices

Is it only the GetDevices () method in the midi class that needs to be called from the message thread or are their other methods?

If this is the case I will try to move the data transmission functionality only to a backround thread as you suggests. Thanks

John


#13

I wouldn’t have thought there’d be any problems with threading, but this could just be a bug/quirk of your particular driver.


#14

Happy new year Jules

I have now moved the midi transmission part into a separate thread and it does seem to work well, but I need to test it further to ensure that the problem is gone.

You mention that it might be a problem with my particular driver, that migth be the case, but I am using the plug and play OSX/Windows USB Audio midi drivers and
do not want to develop my own drivers as it is important to me that the customers does not need to install anything before using this application.

Thank you for your help

John Parbo Andersen


#15

Hi

I was just looking at this post, and then I found this : http://social.msdn.microsoft.com/Forums/en-US/windowspro-audiodevelopment/thread/ccc9bcfa-ee7a-4784-9694-1db633ebdebe/

It looks like the Microsoft guy is saying that there’s a fundamental problem in the way JUCE handles MIDI input, since the callback can ultimately end up calling back into another multimedia function.

The path is : midiInCallback -> handleMessage/handleSysEx -> writeFinishedBlocks -> writeIfFinished -> midiInUnprepareHeader

Would you agree with this, and if so should new headers be prepared on a background worker thread or something along those lines?


#16

Ok… I was always under the impression that unpreparing headers was one of the few things allowed in the callback, but I guess not. Maybe some devices can handle it and others can’t.

I’ve checked in some code that avoids calling unprepareHeader, but I’ve not tested it - would appreciate some feedback on whether it helps!


#17

Nice, that was easy - so it looks like they only need to be prepared just once. I’m not directly working on this but I did a few quick tests and it appears to be OK.

Yes the docs are pretty scant. They just say ‘don’t call any multimedia functions in the callback’, but midiInAddBuffer() falls in this bracket yet I assume that’s fine.


#18

Hi CowTipper

Thank you for pointing this out, it is actually me who started that other thread you posted a link to.

Best regards

John