I'm making a music player using vlcj 4.8.0, and I was looking to implement its MediaDiscovery component to find directories containing audio files (in the local music folder). Until now, I'd been using a DirectoryChooser and file.listFiles(File::isDirectory)
to obtain them, but I figured it'd be more practical to let a MediaDiscoverer take care of this function.
I made some modifications to this example from vlcj's examples repository to obtain only directories that contain music files.
public class MediaDiscovererTest {
private static final List<String> musicDirectories = new ArrayList<>();
public static void main(String[] args) throws Exception {
MediaPlayerFactory factory = new MediaPlayerFactory();
List<MediaDiscovererDescription> discoverers = factory.mediaDiscoverers().discoverers(MediaDiscovererCategory.LOCAL_DIRS);
if (discoverers.isEmpty()) {
return;
}
Iterator<MediaDiscovererDescription> iterator = discoverers.iterator();
while (iterator.hasNext()) {
MediaDiscovererDescription discoverer = iterator.next();
if (discoverer.name().equals("picture_dir") || discoverer.name().equals("video_dir")) {
iterator.remove(); // as I'm only interested in audio directories
}
}
for (MediaDiscovererDescription description : discoverers) {
final String name = description.name();
MediaDiscoverer discoverer = factory.mediaDiscoverers().discoverer(name);
MediaList list = discoverer.newMediaList();
MediaListEventAdapter mediaListEventAdapter = new MediaListEventAdapter() {
@Override
public void mediaListItemAdded(MediaList mediaList, MediaRef item, int index) {
Media newMedia = item.newMedia();
System.out.println(newMedia.info().mrl());
// Adding a new directory to the list
musicDirectories.add(newMedia.info().mrl());
newMedia.release();
}
};
list.events().addMediaListEventListener(mediaListEventAdapter);
discoverer.start();
// list.events().removeMediaListEventListener(mediaListEventAdapter);
// discoverer.release();
// list.release();
}
System.out.println(musicDirectories.size()); // <- In this test's current state, this will always be 0
Thread.currentThread().join();
}
}
Whenever a new item is incorporated into the MediaList, its path is printed to the console and saved to musicDirectories. This works as intended. However, I lack clarity on how to monitor the advancement of the discovery process. Specifically, I want to determine when it concludes, so I can ensure my program only proceeds once the discovery process is done.
When dealing with similar processes, like parsing a Media, an asynchronous operation, it is possible to know when the parsing has finished by attaching a MediaEventListener to a MediaPlayer:
mediaPlayer.events().addMediaEventListener(new MediaEventListener() {
@Override
public void mediaParsedChanged(Media media, MediaParsedStatus newStatus) {
if (newStatus == MediaParsedStatus.DONE) {
// Do something
}
}
});
Regrettably, I am uncertain about how to implement such a method for a MediaDiscoverer, as I've read the documentation for it and couldn't find anything of the sort. The only rudimentary solution I have discovered is to use Thread.sleep(2000); immediately after discoverer.start();
, but this is evidently not an ideal approach. Is there a more reliable way to determine when the discovery process is completed?
Media discoverers run continually until they are stopped.
This means, in principle at least, that say you have a media discoverer that looks for media in the user's standard videos directory, it will discover the current set of items in that directory and then update (raise new events) if items are added or remove to/from that directory.
So, in this sense, the discovery is never finished.
In practice then this means that your application should be coded in such a way as to handle dynamically changing lists of media, not a fixed list.
It's not like you stop your application until discovery completes and then present the discovered items, it's more that your application has a dynamic playlist that is constantly listening for events when items are being added/removed by the discoverer.
You do not of course need to use the native media discoverers at all, you can look in the standard places media is contained yourself just using normal Java IO (which is what you originally did, and that is perfectly fine).