Class 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 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 desired
        trackType - 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 (if folder is false), or the list of playlists and folders inside the specified playlist folder (if folder is true).
        Parameters:
        player - the player number whose playlist entries are of interest
        slot - the slot in which the playlist can be found
        sortOrder - the order in which responses should be sorted, 0 for default, see the Packet Analysis document for details
        playlistOrFolderId - the database ID of the desired playlist or folder
        folder - 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 class LifecycleParticipant
        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, and WaveformFinder) 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, or false 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, and WaveformFinder) 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, or false 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 the MenuLoader, and they are valid as SlotReference 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. If listener is null 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 implements MediaDetailsListener, 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. If listener is null 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. If listener is null 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. If listener is null 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 call MetadataProvider.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, or null 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 the VirtualCdj 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 the DeviceFinder (which is also needed by the VirtualCdj) so we can keep track of the comings and goings of players themselves. We start the ConnectionManager 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.