Caprica Software

vlcj 4.x Tutorial

Thread Model

This section contains very important information regarding the threading model used by vlcj-4.

It is slightly different to that used in vlcj-3, so please consider it carefully.


Background Information

With vlcj-4, every native event coming from LibVLC is processed on the native callback thread. This should give some small performance gains when compared with vlcj-3.

The critical issue is that it is generally not permitted to call back into LibVLC from the event callback thread. Doing so may cause subtle failures or outright hard Java Virtual Machine crashes.

Example

A prime example of the sort of trap waiting for you is the very common case of handling a media player finished event so that you can then play the next item in a play-list:

mediaPlayer.events().addMediaPlayerEventListener(new MediaPlayerEventAdapter() {
@Override
public void finished(MediaPlayer mediaPlayer) {
mediaPlayer.media().play(nextMrl); // <-- This is VERY BAD INDEED
}
});

In this example, the finished method is being invoked on a native callback thread owned by LibVLC. The implementation of this method is calling back into LibVLC when it invokes play. This is very likely to cause a JVM crash and kill your application.

In cases such as this, you should make use of an asynchronous task-executor queue conveniently provided by the MediaPlayer object passed to the listener method:

mediaPlayer.events().addMediaPlayerEventListener(new MediaPlayerEventAdapter() {
@Override
public void finished(final MediaPlayer mediaPlayer) {
mediaPlayer.submit(new Runnable() {
@Override
public void run() {
mediaPlayer.media().play(nextMrl);
}
});
}
});

You should not use this mechanism for all of your event handlers, only those that will call back into LibVLC.

Other high-level vlcj components may also provide their own asynchronous task executor, it is not limited to the media player.

An added caveat for vlcj-4 is that when you implement event handling you must be sure to execute quickly, and to not block the native thread with any long-running operation.

Your event handler implementations must not throw an Exception, failure of your event handlers to catch and handle any thrown exception may prevent other listeners from being notified of the event.

If you are attempting to use multiple media players in your application, or using media players from multiple threads, you may need to take some extra care so that you do not have multiple threads calling into LibVLC concurrently. You may encounter subtle bugs and races that are very difficult to diagnose.

In addition, you must take care not to update Swing UI components from the native thread - all Swing UI updates are supposed to go via the Swing Event Dispatch Thread (EDT).

You can achieve this in the usual way by using SwingUtilities#invokeLater in your event handler:

mediaPlayer.events().addMediaPlayerEventListener(new MediaPlayerEventAdapter() {
@Override
public void finished(MediaPlayer mediaPlayer) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
// ...change UI state here...
}
});
}
});