Basic Events
Building on previous tutorials, we will now add some basic media player event handlers.
Background Information
The most important thing to realise with media player events is that they are
executed in the context of a background thread. This means that you must
not update any user interface state directly inside one of your event
handlers. You can update user interface state if you use
SwingUtilities.invokeLater()
- this is not specific to vlcj, this a common
use-case for multi-threaded Swing applications in general.
The next thing to realise with media player events is more technical and you usually will not care about it - it is however worth mentioning: ordinarily with LibVLC it is not possible to invoke a method on the media player from inside an event handler, it will cause a dead-lock if you try it. This is a severe constraint because it is often a very useful thing to do.
There is no such constraint in vlcj, your event handlers are free to invoke methods on the media player. This is possible because vlcj guarantees that all native events are delivered on an application thread (not the native thead), and more than this vlcj guarantees that all native events received will be delivered to listeners serially and in the order that they were received.
These two things together can greatly simplify your application's use of media player events and allow you to reason more easily about the threading behaviour of your application.
Let's Get Started
You should now already have a basic template for how to create a vlcj application, so this tutorial will no longer duplicate all of the code each time - instead we'll just show the new code fragments.
Adding an Event Listener
Media player event listeners are similar to regular Swing event listeners. You
simply add an instance of a MediaPlayerEventListener
to your media player.
In common with many other Swing event listeners, an equivalent adapter class is
provided with default empty implementations for all of the media player event
listeners. Your application need then extend (via sub-classing)
MediaPlayerEventAdapter
and provide bespoke implementations for only the
events you are interested in.
We'll start by adding our listener using an empty adapter implementation, and fill in methods for the events we're intersted in later. The listener is added before the frame is shown.
You can add as many different event listeners as you want. This can be useful when you have different components needing to act on different events.
Add Event Handlers
The basic events usually of interest to all applications are playing
,
finished
and error
. There are numerous other events but we will cover just
those basic events here:
Using Template Methods
The EmbeddedMediaPlayerComponent
also provides template methods for all media
player events. You may find it more convenient to create a sub-class of
EmbeddedMediaPlayerComponent
and override the methods you are interested in.
This fragment shows the equivalent template method usage to the listener added previously:
It is up to you to choose which method - either one, other or both of adding listeners and overriding template methods.
Add Event Handler Implementations
The playing
event is raised when the media starts playback.
Here we get the media meta data to get the title. We then change the title of the application frame to show this media title:
The finished
notification is raised when the media has finished playback
normally.
Here we simply close the main frame and exit the application:
The error
notification is somewhat more interesting. When playing media it is
actually an asynchronous method call - the media player playMedia
method will
return immediately and LibVLC will asynchronously try and start playing the
media. In practical terms, you won't immediately get a success/error indicator
until some time later. The way you get the success/error indicator is via the
corresponding media player events, i.e. playing
or error
.
In this tutorial, we'll display a standard error dialog in response to an error, before closing the main frame and exiting the application:
All of these event handler implementations update user interface state so must
be executed on the Swing Event Dispatch Thread via SwingUtilities.invokeLater
- in your own application this may not always be the case for certain events.
The closeWindow
method is just a simple private helper method that raises a
WINDOW_CLOSING
event as though the user had closed the main application frame
themselves. This allows us to consolidate the clean-up handling code in one
place.
Summary
Here is the finished code:
This tutorial has shown how to hook up media player event listeners. The actual vlcj code is minimal and very simple. Most of the code deals with updating the user interface state and is standard Swing code.