Class MetadataFinder
- java.lang.Object
-
- org.deepsymmetry.beatlink.LifecycleParticipant
-
- org.deepsymmetry.beatlink.data.MetadataFinder
-
public class MetadataFinder extends LifecycleParticipant
Watches for new tracks to be loaded on players, and queries the appropriate player for the metadata information when that happens.
Maintains a hot cache of metadata about any track currently loaded in a player, either on the main playback deck, or as a hot cue, since those tracks could start playing instantly.
- Author:
- James Elliott
-
-
Field Summary
Fields Modifier and Type Field Description static int
MENU_TIMEOUT
How many seconds are we willing to wait to lock the database client for menu operations.
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Modifier and Type Method Description void
addMetadataProvider(MetadataProvider provider)
Adds a metadata provider that will be consulted to see if it can provide metadata for newly-loaded tracks before we try to retrieve it from the players.void
addMountListener(MountListener listener)
Adds the specified mount update listener to receive updates when media is mounted or unmounted by any player.void
addTrackMetadataListener(TrackMetadataListener listener)
Adds the specified track metadata listener to receive updates when the track metadata for a player changes.static MetadataFinder
getInstance()
Get the singleton instance of this class.TrackMetadata
getLatestMetadataFor(int player)
Look up the track metadata we have for the track loaded in the main deck of a given player number.TrackMetadata
getLatestMetadataFor(DeviceUpdate update)
Look up the track metadata we have for a given player, identified by a status update received from that player.Map<DeckReference,TrackMetadata>
getLoadedTracks()
Get the metadata of all tracks currently loaded in any player, either on the play deck, or in a hot cue.MediaDetails
getMediaDetailsFor(SlotReference slot)
Look up the details we know about the media mounted in a particular slotSet<MetadataProvider>
getMetadataProviders(MediaDetails sourceMedia)
Get the set of metadata providers that can offer metadata for tracks loaded from the specified media.Collection<MediaDetails>
getMountedMediaDetails()
Get the details we know about all mounted media.Set<SlotReference>
getMountedMediaSlots()
Returns the set of media slots on the network that currently have media mounted in them.Set<MountListener>
getMountListeners()
Get the set of currently-registered mount update listeners.Set<TrackMetadataListener>
getTrackMetadataListeners()
Get the set of currently-registered track metadata update listeners.boolean
isPassive()
Check whether we are configured to use metadata only from caches and downloaded metadata exports, never actively requesting it from a player.boolean
isRunning()
Check whether we are currently running.void
removeMetadataProvider(MetadataProvider provider)
Removes a metadata provider, so it will no longer be consulted to provide metadata for tracks loaded from any media.void
removeMountListener(MountListener listener)
Removes the specified mount update listener so that it no longer receives updates when a player mounts or unmounts media in one of its media slots.void
removeTrackMetadataListener(TrackMetadataListener listener)
Removes the specified track metadata update listener so that it no longer receives updates when track metadata for a player changes.TrackMetadata
requestMetadataFrom(CdjStatus status)
Given a status update from a CDJ, find the metadata for the track that it has loaded, if any.TrackMetadata
requestMetadataFrom(DataReference track, CdjStatus.TrackType trackType)
Ask the specified player for metadata about the track in the specified slot with the specified rekordbox ID, unless we have a metadata download available for the specified media slot, in which case that will be used instead.List<Message>
requestPlaylistItemsFrom(int player, CdjStatus.TrackSourceSlot slot, int sortOrder, int playlistOrFolderId, boolean folder)
Ask the specified player's dbserver for the playlist entries of the specified playlist (iffolder
isfalse
), or the list of playlists and folders inside the specified playlist folder (iffolder
istrue
).void
setPassive(boolean passive)
Set whether we are configured to use metadata only from caches or downloaded metadata exports, never actively requesting it from a player.void
start()
Start finding track metadata for all active players.void
stop()
Stop finding track metadata for all active players.String
toString()
-
Methods inherited from class org.deepsymmetry.beatlink.LifecycleParticipant
addLifecycleListener, deliverLifecycleAnnouncement, ensureRunning, getLifecycleListeners, removeLifecycleListener
-
-
-
-
Field Detail
-
MENU_TIMEOUT
public static final int MENU_TIMEOUT
How many seconds are we willing to wait to lock the database client for menu operations.- See Also:
- Constant Field Values
-
-
Method Detail
-
requestMetadataFrom
public TrackMetadata requestMetadataFrom(CdjStatus status)
Given a status update from a CDJ, find the metadata for the track that it has loaded, if any. If there is an appropriate metadata file downloaded, will use that, otherwise makes a query to the player's dbserver.- Parameters:
status
- the CDJ status update that will be used to determine the loaded track and ask the appropriate player for metadata about it- Returns:
- the metadata that was obtained, if any
-
requestMetadataFrom
public TrackMetadata requestMetadataFrom(DataReference track, CdjStatus.TrackType trackType)
Ask the specified player for metadata about the track in the specified slot with the specified rekordbox ID, unless we have a metadata download available for the specified media slot, in which case that will be used instead.- Parameters:
track
- uniquely identifies the track whose metadata is desiredtrackType
- identifies the type of track being requested, which affects the type of metadata request message that must be used- Returns:
- the metadata, if any
-
requestPlaylistItemsFrom
public List<Message> requestPlaylistItemsFrom(int player, CdjStatus.TrackSourceSlot slot, int sortOrder, int playlistOrFolderId, boolean folder) throws Exception
Ask the specified player's dbserver for the playlist entries of the specified playlist (iffolder
isfalse
), or the list of playlists and folders inside the specified playlist folder (iffolder
istrue
).- Parameters:
player
- the player number whose playlist entries are of interestslot
- the slot in which the playlist can be foundsortOrder
- the order in which responses should be sorted, 0 for default, see the Packet Analysis document for detailsplaylistOrFolderId
- the database ID of the desired playlist or folderfolder
- indicates whether we are asking for the contents of a folder or playlist- Returns:
- the items that are found in the specified playlist or folder; they will be tracks if we are asking for a playlist, or playlists and folders if we are asking for a folder
- Throws:
Exception
- if there is a problem obtaining the playlist information
-
isRunning
public boolean isRunning()
Check whether we are currently running. Unless we are in passive mode, we will also automatically request metadata from the appropriate player when a new track is loaded that is not found in the hot cache.- Specified by:
isRunning
in classLifecycleParticipant
- Returns:
- true if track metadata is being kept track of for all active players
- See Also:
isPassive()
-
isPassive
public boolean isPassive()
Check whether we are configured to use metadata only from caches and downloaded metadata exports, never actively requesting it from a player. Note that this will implicitly mean all of the metadata-related finders (ArtFinder
,BeatGridFinder
, andWaveformFinder
) are in passive mode as well, because their activity is triggered by the availability of new track metadata.- Returns:
true
if only cached metadata will be used, orfalse
if metadata will be requested from a player if a track is loaded from a media slot for which no metadata has been downloaded
-
setPassive
public void setPassive(boolean passive)
Set whether we are configured to use metadata only from caches or downloaded metadata exports, never actively requesting it from a player. Note that this will implicitly put all of the metadata-related finders (ArtFinder
,BeatGridFinder
, andWaveformFinder
) into a passive mode as well, because their activity is triggered by the availability of new track metadata.- Parameters:
passive
-true
if only cached metadata will be used, orfalse
if metadata will be requested from a player if a track is loaded from a media slot for which no metadata has been downloaded
-
getLoadedTracks
public Map<DeckReference,TrackMetadata> getLoadedTracks()
Get the metadata of all tracks currently loaded in any player, either on the play deck, or in a hot cue.- Returns:
- the track information reported by all current players, including any tracks loaded in their hot cue slots
- Throws:
IllegalStateException
- if the MetadataFinder is not running
-
getLatestMetadataFor
public TrackMetadata getLatestMetadataFor(int player)
Look up the track metadata we have for the track loaded in the main deck of a given player number.- Parameters:
player
- the device number whose track metadata for the playing track is desired- Returns:
- information about the track loaded on that player, if available
- Throws:
IllegalStateException
- if the MetadataFinder is not running
-
getLatestMetadataFor
public TrackMetadata getLatestMetadataFor(DeviceUpdate update)
Look up the track metadata we have for a given player, identified by a status update received from that player.- Parameters:
update
- a status update from the player for which track metadata is desired- Returns:
- information about the track loaded on that player, if available
- Throws:
IllegalStateException
- if the MetadataFinder is not running
-
getMountedMediaSlots
public Set<SlotReference> getMountedMediaSlots()
Returns the set of media slots on the network that currently have media mounted in them. Note that computers running rekordbox are included; their collections are valid media databases to explore with theMenuLoader
, and they are valid asSlotReference
arguments to tell players to load tracks from.- Returns:
- the slots with media currently available on the network, including rekordbox instances
-
getMountedMediaDetails
public Collection<MediaDetails> getMountedMediaDetails()
Get the details we know about all mounted media.- Returns:
- the media details the Virtual CDJ has been able to find for us about the mounted slots.
-
getMediaDetailsFor
public MediaDetails getMediaDetailsFor(SlotReference slot)
Look up the details we know about the media mounted in a particular slot- Parameters:
slot
- the slot whose media is of interest- Returns:
- the details, or
null
if we don't have any
-
addMountListener
public void addMountListener(MountListener listener)
Adds the specified mount update listener to receive updates when media is mounted or unmounted by any player. Iflistener
isnull
or already present in the set of registered listeners, no exception is thrown and no action is performed.Note that at the time a mount is detected, we will not yet know any details about the mounted media. If
listener
also implementsMediaDetailsListener
, then as soon as the media details have been reported by the mounting player,MediaDetailsListener.detailsAvailable(MediaDetails)
will be called with them.To reduce latency, updates are delivered to listeners directly on the thread that is receiving packets from the network, so if you want to interact with user interface objects in listener methods, you need to use
javax.swing.SwingUtilities.invokeLater(Runnable)
to do so on the Event Dispatch Thread.Even if you are not interacting with user interface objects, any code in the listener method must finish quickly, or it will add latency for other listeners, and updates will back up. If you want to perform lengthy processing of any sort, do so on another thread.
- Parameters:
listener
- the mount update listener to add
-
removeMountListener
public void removeMountListener(MountListener listener)
Removes the specified mount update listener so that it no longer receives updates when a player mounts or unmounts media in one of its media slots. Iflistener
isnull
or not present in the set of registered listeners, no exception is thrown and no action is performed.- Parameters:
listener
- the mount update listener to remove
-
getMountListeners
public Set<MountListener> getMountListeners()
Get the set of currently-registered mount update listeners.- Returns:
- the listeners that are currently registered for mount updates
-
addTrackMetadataListener
public void addTrackMetadataListener(TrackMetadataListener listener)
Adds the specified track metadata listener to receive updates when the track metadata for a player changes. Iflistener
isnull
or already present in the set of registered listeners, no exception is thrown and no action is performed.To reduce latency, updates are delivered to listeners directly on the thread that is receiving packets from the network, so if you want to interact with user interface objects in listener methods, you need to use
javax.swing.SwingUtilities.invokeLater(Runnable)
to do so on the Event Dispatch Thread.Even if you are not interacting with user interface objects, any code in the listener method must finish quickly, or it will add latency for other listeners, and updates will back up. If you want to perform lengthy processing of any sort, do so on another thread.
- Parameters:
listener
- the track metadata update listener to add
-
removeTrackMetadataListener
public void removeTrackMetadataListener(TrackMetadataListener listener)
Removes the specified track metadata update listener so that it no longer receives updates when track metadata for a player changes. Iflistener
isnull
or not present in the set of registered listeners, no exception is thrown and no action is performed.- Parameters:
listener
- the track metadata update listener to remove
-
getTrackMetadataListeners
public Set<TrackMetadataListener> getTrackMetadataListeners()
Get the set of currently-registered track metadata update listeners.- Returns:
- the listeners that are currently registered for track metadata updates
-
addMetadataProvider
public void addMetadataProvider(MetadataProvider provider)
Adds a metadata provider that will be consulted to see if it can provide metadata for newly-loaded tracks before we try to retrieve it from the players. This function will immediately callMetadataProvider.supportedMedia()
and will only consult the provider for tracks loaded from the media mentioned in the response. The function is only called once, when initially adding the provider, so if the set of supported media changes, you will need to remove the provider and re-add it. Providers that can provide metadata for all media can simply return an empty list of supported media, and they will always be consulted. Only do this if they truly can always provide metadata, or you will slow down the lookup process by having them frequently called in vain.- Parameters:
provider
- the object that can supply metadata about tracks
-
removeMetadataProvider
public void removeMetadataProvider(MetadataProvider provider)
Removes a metadata provider, so it will no longer be consulted to provide metadata for tracks loaded from any media.- Parameters:
provider
- the metadata provider to remove.
-
getMetadataProviders
public Set<MetadataProvider> getMetadataProviders(MediaDetails sourceMedia)
Get the set of metadata providers that can offer metadata for tracks loaded from the specified media.- Parameters:
sourceMedia
- the media whose metadata providers are desired, ornull
to get the set of metadata providers that can offer metadata for all media.- Returns:
- any registered metadata providers that reported themselves as supporting tracks from that media
-
start
public void start() throws Exception
Start finding track metadata for all active players. Starts theVirtualCdj
if it is not already running, because we need it to send us device status updates to notice when new tracks are loaded; this starts theDeviceFinder
(which is also needed by theVirtualCdj
) so we can keep track of the comings and goings of players themselves. We start theConnectionManager
in order to make queries to obtain metadata.- Throws:
Exception
- if there is a problem starting the required components
-
stop
public void stop()
Stop finding track metadata for all active players.
-
getInstance
public static MetadataFinder getInstance()
Get the singleton instance of this class.- Returns:
- the only instance of this class which exists.
-
-