Skip to content

Commit

Permalink
Merge pull request #77 from cprepos/cprepos-fix-ui-freeze
Browse files Browse the repository at this point in the history
Cprepos fix UI freeze
  • Loading branch information
brunchboy authored Jun 2, 2024
2 parents 99181ed + d633445 commit 0d5df67
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 18 deletions.
26 changes: 20 additions & 6 deletions src/main/java/org/deepsymmetry/beatlink/VirtualRekordbox.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.deepsymmetry.beatlink;

import org.apiguardian.api.API;
import org.deepsymmetry.beatlink.data.MetadataFinder;
import org.deepsymmetry.beatlink.data.OpusProvider;
import org.deepsymmetry.beatlink.data.SlotReference;
import org.slf4j.Logger;
Expand Down Expand Up @@ -314,15 +315,21 @@ public static String getDeviceName() {
0x01, 0x02, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00
};

/**
* Packet used to tell Opus device we want PSSI data once for all players with loaded songs.
*/
private static final byte[] requestPSSIBytes = {
0x51, 0x73, 0x70, 0x74, 0x31, 0x57, 0x6d, 0x4a, 0x4f, 0x4c, 0x55, 0x72, 0x65, 0x6b, 0x6f, 0x72,
0x64, 0x62, 0x6f, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x00, 0x17, 0x00, 0x08, 0x36, 0x00, 0x00, 0x00, 0x0a, 0x02, 0x03, 0x01
};

private static final byte[] deviceName = "rekordbox".getBytes();

// TODO this (and the arrays above) need JavaDoc.
/**
* This imitates the request RekordboxLighting sends to get PSSI data from Opus Quad device
* (and maybe more devices in the future).
*
* @throws IOException
*/
@API(status = API.Status.EXPERIMENTAL)
public void requestPSSI() throws IOException{
if (DeviceFinder.getInstance().isRunning() && !DeviceFinder.getInstance().getCurrentDevices().isEmpty()) {
Expand All @@ -346,10 +353,17 @@ public void requestPSSI() throws IOException{
/**
* Clear both player caches so that we can reload the data. This usually happens when we load an archive
* in OpusProvider.
*
* @param usbSlotNumber the slot we have the archive loaded in
*/

/**
*
* @param usbSlotNumber
*/
public void clearPlayerCaches(){
playerSongStructures.clear();
playerTrackSourceSlots.clear();
public void clearPlayerCaches(int usbSlotNumber){
playerSongStructures.remove(usbSlotNumber);
playerTrackSourceSlots.remove(usbSlotNumber);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,9 @@ private void recordMount(SlotReference slot) {
logger.warn("Problem trying to request media details for {}", slot, e);
}
}
if (OpusProvider.getInstance().isRunning()) {
OpusProvider.getInstance().pollAndSendMediaDetails(slot.player);
}
}

/**
Expand Down
66 changes: 54 additions & 12 deletions src/main/java/org/deepsymmetry/beatlink/data/OpusProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;

/**
Expand Down Expand Up @@ -114,6 +114,14 @@ public FileSystem getFileSystem() {
*/
private final Map<Integer, RekordboxUsbArchive> usbArchiveMap = new ConcurrentHashMap<>();

/**
* Contains a queue per slot number which allows us to slow down sending VirtualCdj.deliverMediaDetailsUpdate
* when we attach metadata archives until the application is actually ready to do so.
*
* Queues are initiated in constructor and should never be null.
*/
private final Map<Integer, LinkedBlockingQueue<MediaDetails>> archiveAttachQueueMap = new ConcurrentHashMap<>();

/**
* Attach a metadata archive to supply information for the media mounted a USB slot of the Opus Quad.
* This must be a file created using {@link org.deepsymmetry.cratedigger.Archivist#createArchive(Database, File)}
Expand All @@ -135,13 +143,23 @@ public synchronized void attachMetadataArchive(File archiveFile, int usbSlotNumb
// First close and remove any archive we had previously attached for this slot.
final RekordboxUsbArchive formerArchive = usbArchiveMap.remove(usbSlotNumber);

// Report archive closed.
final SlotReference emptySlotReference = SlotReference.getSlotReference(usbSlotNumber, null);
final MediaDetails emptyDetails = new MediaDetails(emptySlotReference, CdjStatus.TrackType.REKORDBOX, "",
0, 0, 0);

archiveAttachQueueMap.get(usbSlotNumber).add(emptyDetails);

if (formerArchive != null) {
try {
logger.info("Detached metadata archive {} from USB{}", formerArchive, formerArchive.usbSlot);
formerArchive.getDatabase().close();
//noinspection ResultOfMethodCallIgnored
formerArchive.getDatabase().sourceFile.delete();
formerArchive.getFileSystem().close();

// Clear player caches as matching data is not applicable anymore.
VirtualRekordbox.getInstance().clearPlayerCaches(usbSlotNumber);
} catch (IOException e) {
logger.error("Problem closing database or FileSystem for USB{}", usbSlotNumber, e);
}
Expand Down Expand Up @@ -175,21 +193,13 @@ public synchronized void attachMetadataArchive(File archiveFile, int usbSlotNumb
// Send a media update so clients know this media is mounted.
final SlotReference slotReference = SlotReference.getSlotReference(usbSlotNumber, CdjStatus.TrackSourceSlot.USB_SLOT);
final MediaDetails newDetails = new MediaDetails(slotReference, CdjStatus.TrackType.REKORDBOX, filesystem.toString(),
database.trackIndex.size(), database.playlistIndex.size(), database.sourceFile.lastModified());

// Wait for media mount to exist before continuing otherwise we might not properly register the drive
// and wind up in a bad state.
while (!MetadataFinder.getInstance().getMountedMediaSlots().contains(slotReference)) {
Thread.sleep(50);
}

// Clear player caches as matching data might not be applicable anymore.
VirtualRekordbox.getInstance().clearPlayerCaches();
database.trackIndex.size(), database.playlistIndex.size(), database.sourceFile.lastModified());

// Request initial PSSIs for track matching. After this we will request PSSI data on song change.
VirtualRekordbox.getInstance().requestPSSI();

VirtualCdj.getInstance().deliverMediaDetailsUpdate(newDetails);
// Put new MediaDetails into queue.
archiveAttachQueueMap.get(usbSlotNumber).put(newDetails);
} catch (Exception e) {
filesystem.close();
throw new IOException("Problem reading export.pdb from metadata archive " + archiveFile, e);
Expand All @@ -212,6 +222,24 @@ public RekordboxUsbArchive findArchive(int usbSlotNumber) {
return usbArchiveMap.get(usbSlotNumber);
}

/**
* Grab MediaDetails off of archiveAttachStatusMap and deliver it to VirtualCdj listeners. Message is null
* if not exists.
*
* @param usbSlotNumber
*/
@API(status = API.Status.EXPERIMENTAL)
public void pollAndSendMediaDetails(int usbSlotNumber){
if (usbSlotNumber > 0 && usbSlotNumber < 4) {
// Only send media details if there is something in the queue.
MediaDetails mediaDetails = archiveAttachQueueMap.get(usbSlotNumber).poll();

if (mediaDetails != null) {
VirtualCdj.getInstance().deliverMediaDetailsUpdate(mediaDetails);
}
}
}

/**
* Format the filename prefix that will be used to store files downloaded from a particular USB slot.
* This allows them all to be cleaned up when that slot media is detached.
Expand Down Expand Up @@ -586,6 +614,16 @@ public int findMatchingUsbSlotForTrack(int rekordboxId, int player, ByteBuffer s
return 0;
}

/**
* Get a message from archive attached queue for your slot message to see if we want to send MediaDetails to liteners.
*
* @return MediaDetails for the specific the USB slot number.
*/
@API(status = API.Status.EXPERIMENTAL)
public synchronized MediaDetails pollFromArchiveAttachedQueue(int usbSlotNumber){
return archiveAttachQueueMap.get(usbSlotNumber).poll();
}

/**
* Start proxying track metadata from mounted archives for the Opus Quad decks.
*/
Expand Down Expand Up @@ -634,6 +672,10 @@ public static OpusProvider getInstance() {
*/
private OpusProvider() {
extractDirectory = CrateDigger.createDownloadDirectory();
// Create MediaDetails Queues, one per USB slot 1-3.
for (int i = 1; i <= 3; i++) {
archiveAttachQueueMap.put(i, new LinkedBlockingQueue<>());
}
}

@Override
Expand Down

0 comments on commit 0d5df67

Please sign in to comment.