Moved most player tasks to ForkJoin.

This system works a bit better.
This commit is contained in:
Markil3
2021-09-18 16:04:37 -06:00
parent 2e2748f9e9
commit 0ffa626cb7
7 changed files with 366 additions and 262 deletions

View File

@@ -0,0 +1,41 @@
package edu.regis.universeplayer;
import java.util.concurrent.ForkJoinTask;
/**
* An abstract {@link ForkJoinTask} that has getters and setters automatically
* set up.
*
* @param <T>
*/
public abstract class AbstractTask<T> extends ForkJoinTask<T>
{
private T value;
/**
* Returns the result that would be returned by {@link #join}, even if this
* task completed abnormally, or {@code null} if this task is not known to
* have been completed. This method is designed to aid debugging, as well
* as to support extensions. Its use in any other context is discouraged.
*
* @return the result, or {@code null} if not completed
*/
@Override
public T getRawResult()
{
return this.value;
}
/**
* Forces the given value to be returned as a result. This method is
* designed to support extensions, and should not in general be called
* otherwise.
*
* @param value the value
*/
@Override
protected void setRawResult(T value)
{
this.value = value;
}
}

View File

@@ -17,6 +17,8 @@ import java.util.Map;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import java.util.Scanner; import java.util.Scanner;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -149,66 +151,47 @@ public class PlayerEnvironment
Queue queue = Queue.getInstance(); Queue queue = Queue.getInstance();
PlayerManager playback = PlayerManager.getPlayers(); PlayerManager playback = PlayerManager.getPlayers();
queue.addSongChangeListener(queue1 -> { queue.addSongChangeListener(queue1 -> ForkJoinPool.commonPool().submit(() -> {
QueryFuture<Void> command = PlayerManager.getPlayers() ForkJoinTask<Void> command = PlayerManager.getPlayers()
.stopSong(); .stopSong();
try command.join();
if (command.isCompletedAbnormally())
{ {
if (command != null && !command.getConfirmation() logger.error("Could not run command",
.wasSuccessful()) command.getException());
if (Interface.getInstance() != null)
{ {
JOptionPane
.showMessageDialog(Interface.getInstance(),
command.getException(),
command.getException().getMessage(),
JOptionPane.ERROR_MESSAGE);
}
}
else if (queue1.getCurrentSong() != null)
{
command =
PlayerManager.getPlayers()
.playSong(queue1.getCurrentSong());
command.join();
if (command.isCompletedAbnormally())
{
logger.error("Could not run command",
command.getException());
if (Interface.getInstance() != null) if (Interface.getInstance() != null)
{ {
JOptionPane JOptionPane
.showMessageDialog(Interface.getInstance(), .showMessageDialog(Interface.getInstance(),
command.getConfirmation() command.getException(),
.getError(), command.getException().getMessage(),
command.getConfirmation()
.getMessage(),
JOptionPane.ERROR_MESSAGE); JOptionPane.ERROR_MESSAGE);
} }
logger.error("Could not run command",
command.getConfirmation().getError());
}
else if (queue1.getCurrentSong() != null)
{
command =
PlayerManager.getPlayers()
.playSong(queue1.getCurrentSong());
if (!command.getConfirmation().wasSuccessful())
{
if (Interface.getInstance() != null)
{
JOptionPane.showMessageDialog(Interface
.getInstance(),
command.getConfirmation().getError(),
command.getConfirmation().getMessage(),
JOptionPane.ERROR_MESSAGE);
}
logger.error("Could not run command",
command.getConfirmation().getError());
}
else
{
}
} }
} }
catch (ExecutionException | InterruptedException e) }));
{
logger.error("Could not get current playback status", e);
if (Interface.getInstance() != null)
{
JOptionPane
.showMessageDialog(Interface.getInstance(), e
.getMessage()
, langs
.getString(
"error.command"), JOptionPane.ERROR_MESSAGE);
}
}
});
playback.addPlaybackListener(status -> { playback.addPlaybackListener(status -> {
logger.info("Receiving {} from {}", status.getInfo(), status.getSource()); logger.info("Receiving {} from {}", status.getInfo(), status
.getSource());
if (status.getInfo().getStatus() == PlaybackStatus.FINISHED) if (status.getInfo().getStatus() == PlaybackStatus.FINISHED)
{ {
Queue.getInstance().skipNext(); Queue.getInstance().skipNext();
@@ -411,16 +394,9 @@ public class PlayerEnvironment
out.println("Clearing"); out.println("Clearing");
} }
case "status" -> { case "status" -> {
QueryFuture<PlaybackStatus> status = ForkJoinTask<PlaybackStatus> status =
PlayerManager.getPlayers().getStatus(); PlayerManager.getPlayers().getStatus();
try out.println(status.join());
{
out.println(status.get());
}
catch (InterruptedException | ExecutionException e)
{
e.printStackTrace(out);
}
} }
case "song" -> { case "song" -> {
Song song = PlayerManager.getPlayers().getCurrentSong(); Song song = PlayerManager.getPlayers().getCurrentSong();

View File

@@ -29,6 +29,7 @@ import java.util.Locale;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinTask;
/** /**
* The Interface class serves as the primary GUI that the player interacts * The Interface class serves as the primary GUI that the player interacts
@@ -76,8 +77,6 @@ public class Interface extends JFrame implements SongDisplayListener, ComponentL
*/ */
private final PlayerControls controls; private final PlayerControls controls;
private int currentPlayer = -1;
public static Interface getInstance() public static Interface getInstance()
{ {
return INSTANCE; return INSTANCE;
@@ -230,41 +229,23 @@ public class Interface extends JFrame implements SongDisplayListener, ComponentL
* thread. * thread.
* *
* @return the computed result * @return the computed result
* @throws Exception if unable to compute a result
*/ */
@Override @Override
protected Void doInBackground() throws Exception protected Void doInBackground()
{ {
QueryFuture<Void> command = PlayerManager ForkJoinTask<Void> command = PlayerManager
.getPlayers().throwError(false); .getPlayers().throwError(false);
try command.join();
if (command.isCompletedAbnormally())
{ {
if (!command.getConfirmation() logger.error("Could not run command",
.wasSuccessful()) command.getException());
{
logger.error("Could not run command",
command.getConfirmation()
.getError());
JOptionPane
.showMessageDialog(Interface.this,
command.getConfirmation()
.getError(),
command.getConfirmation()
.getMessage(),
JOptionPane.ERROR_MESSAGE);
}
}
catch (ExecutionException | InterruptedException executionException)
{
logger.error("Error" +
" creating " +
"debug " +
"message", executionException);
JOptionPane JOptionPane
.showMessageDialog(Interface.this, executionException .showMessageDialog(Interface.this,
.getMessage(), langs command.getException(),
.getString( command.getException()
"error.command"), JOptionPane.ERROR_MESSAGE); .getMessage(),
JOptionPane.ERROR_MESSAGE);
} }
return null; return null;
} }
@@ -298,7 +279,8 @@ public class Interface extends JFrame implements SongDisplayListener, ComponentL
if (this.isEnabled()) if (this.isEnabled())
{ {
collectionTypes collectionTypes
.triggerSongDisplayListeners(new ArrayList<>(PlayerEnvironment.getSongs() .triggerSongDisplayListeners(new ArrayList<>(PlayerEnvironment
.getSongs()
.getSongs())); .getSongs()));
} }
} }
@@ -314,7 +296,8 @@ public class Interface extends JFrame implements SongDisplayListener, ComponentL
if (this.isEnabled()) if (this.isEnabled())
{ {
collectionTypes collectionTypes
.triggerCollectionDisplayListeners(CollectionType.albumArtist, PlayerEnvironment.getAlbums() .triggerCollectionDisplayListeners(CollectionType.albumArtist, PlayerEnvironment
.getAlbums()
.getAlbumArtists()); .getAlbumArtists());
} }
} }
@@ -330,7 +313,8 @@ public class Interface extends JFrame implements SongDisplayListener, ComponentL
if (this.isEnabled()) if (this.isEnabled())
{ {
collectionTypes collectionTypes
.triggerCollectionDisplayListeners(CollectionType.album, PlayerEnvironment.getSongs() .triggerCollectionDisplayListeners(CollectionType.album, PlayerEnvironment
.getSongs()
.getAlbums()); .getAlbums());
} }
} }
@@ -346,7 +330,8 @@ public class Interface extends JFrame implements SongDisplayListener, ComponentL
if (this.isEnabled()) if (this.isEnabled())
{ {
collectionTypes collectionTypes
.triggerCollectionDisplayListeners(CollectionType.genre, PlayerEnvironment.getAlbums() .triggerCollectionDisplayListeners(CollectionType.genre, PlayerEnvironment
.getAlbums()
.getGenres()); .getGenres());
} }
} }
@@ -362,7 +347,8 @@ public class Interface extends JFrame implements SongDisplayListener, ComponentL
if (this.isEnabled()) if (this.isEnabled())
{ {
collectionTypes collectionTypes
.triggerCollectionDisplayListeners(CollectionType.year, PlayerEnvironment.getAlbums() .triggerCollectionDisplayListeners(CollectionType.year, PlayerEnvironment
.getAlbums()
.getYears()); .getYears());
} }
} }

View File

@@ -29,6 +29,7 @@ import java.util.Locale;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
/** /**
* This panel contains the buttons necessary for controlling the playback of * This panel contains the buttons necessary for controlling the playback of
@@ -181,27 +182,15 @@ public class PlayerControls extends JPanel implements PlaybackListener
private void seek(float value) private void seek(float value)
{ {
this.service.execute(() -> { this.service.execute(() -> {
QueryFuture<Void> command = PlayerManager.getPlayers().seek(value); ForkJoinTask<Void> status = PlayerManager.getPlayers().seek(value);
try status.join();
{ if (status.isCompletedAbnormally())
if (command != null && !command.getConfirmation()
.wasSuccessful())
{
logger.error("Could not run command",
command.getConfirmation().getError());
JOptionPane.showMessageDialog(this,
command.getConfirmation().getError(),
command.getConfirmation().getMessage(),
JOptionPane.ERROR_MESSAGE);
}
}
catch (ExecutionException | InterruptedException e)
{ {
logger.error("Could not run command", logger.error("Could not run command",
e); status.getException());
JOptionPane.showMessageDialog(this, JOptionPane.showMessageDialog(this,
e, status.getException(),
e.getMessage(), status.getException().getMessage(),
JOptionPane.ERROR_MESSAGE); JOptionPane.ERROR_MESSAGE);
} }
}); });
@@ -213,16 +202,15 @@ public class PlayerControls extends JPanel implements PlaybackListener
this.service.execute(() -> { this.service.execute(() -> {
try try
{ {
QueryFuture<PlaybackStatus> status = ForkJoinTask status =
PlayerManager.getPlayers().getStatus(); PlayerManager.getPlayers().getStatus();
CommandConfirmation confirmation = status.getConfirmation(); status.join();
if (status.getConfirmation().wasSuccessful()) if (status.isCompletedNormally())
{ {
switch (status.get()) switch ((PlaybackStatus) status.get())
{ {
case PAUSED -> confirmation = PlayerManager.getPlayers() case PAUSED -> status = PlayerManager.getPlayers()
.play() .play();
.getConfirmation();
case STOPPED, EMPTY -> { case STOPPED, EMPTY -> {
if (Queue.getInstance().size() > 0) if (Queue.getInstance().size() > 0)
{ {
@@ -230,23 +218,30 @@ public class PlayerControls extends JPanel implements PlaybackListener
.getCurrentSong() == null) .getCurrentSong() == null)
{ {
Queue.getInstance().skipToSong(0); Queue.getInstance().skipToSong(0);
status = null;
} }
else else
{ {
confirmation = PlayerManager.getPlayers().play() status = PlayerManager.getPlayers().play();
.getConfirmation();
} }
} }
} }
default -> {
status = null;
}
}
if (status != null)
{
status.join();
} }
} }
if (confirmation != null && !confirmation.wasSuccessful()) if (status != null && status.isCompletedAbnormally())
{ {
logger.error("Could not run command", logger.error("Could not run command",
confirmation.getError()); status.getException());
JOptionPane.showMessageDialog(this, JOptionPane.showMessageDialog(this,
confirmation.getError(), status.getException(),
confirmation.getMessage(), status.getException().getMessage(),
JOptionPane.ERROR_MESSAGE); JOptionPane.ERROR_MESSAGE);
} }
} }
@@ -266,25 +261,25 @@ public class PlayerControls extends JPanel implements PlaybackListener
this.service.execute(() -> { this.service.execute(() -> {
try try
{ {
QueryFuture<PlaybackStatus> status = ForkJoinTask status =
PlayerManager.getPlayers().getStatus(); PlayerManager.getPlayers().getStatus();
CommandConfirmation confirmation = status.getConfirmation(); status.join();
if (status.getConfirmation().wasSuccessful()) if (status.isCompletedNormally())
{ {
if (status.get() == PlaybackStatus.PLAYING) if (status.get() == PlaybackStatus.PLAYING)
{ {
confirmation = status =
PlayerManager.getPlayers().pause() PlayerManager.getPlayers().pause();
.getConfirmation(); status.join();
} }
} }
if (confirmation != null && !confirmation.wasSuccessful()) if (status.isCompletedAbnormally())
{ {
logger.error("Could not run command", logger.error("Could not run command",
confirmation.getError()); status.getException());
JOptionPane.showMessageDialog(this, JOptionPane.showMessageDialog(this,
confirmation.getError(), status.getException(),
confirmation.getMessage(), status.getException().getMessage(),
JOptionPane.ERROR_MESSAGE); JOptionPane.ERROR_MESSAGE);
} }
} }
@@ -307,19 +302,17 @@ public class PlayerControls extends JPanel implements PlaybackListener
this.service.execute(() -> { this.service.execute(() -> {
try try
{ {
QueryFuture<PlaybackStatus> status = ForkJoinTask status =
PlayerManager.getPlayers().getStatus(); PlayerManager.getPlayers().getStatus();
CommandConfirmation confirmation = status.getConfirmation(); status.join();
if (status.getConfirmation().wasSuccessful()) if (status.isCompletedNormally())
{ {
switch (status.get()) switch ((PlaybackStatus) status.get())
{ {
case PAUSED -> confirmation = PlayerManager.getPlayers() case PAUSED -> status = PlayerManager.getPlayers()
.play() .play();
.getConfirmation(); case PLAYING -> status = PlayerManager.getPlayers()
case PLAYING -> confirmation = PlayerManager.getPlayers() .pause();
.pause()
.getConfirmation();
case STOPPED, EMPTY -> { case STOPPED, EMPTY -> {
if (Queue.getInstance().size() > 0) if (Queue.getInstance().size() > 0)
{ {
@@ -327,24 +320,29 @@ public class PlayerControls extends JPanel implements PlaybackListener
.getCurrentSong() == null) .getCurrentSong() == null)
{ {
Queue.getInstance().skipToSong(0); Queue.getInstance().skipToSong(0);
status = null;
} }
else else
{ {
confirmation = PlayerManager.getPlayers().play() status = PlayerManager.getPlayers().play();
.getConfirmation();
} }
} }
} }
default -> status = null;
}
if (status != null)
{
status.join();
} }
} }
if (confirmation != null && !confirmation.wasSuccessful()) if (status != null && status.isCompletedAbnormally())
{ {
JOptionPane.showMessageDialog(this,
confirmation.getError(),
confirmation.getMessage(),
JOptionPane.ERROR_MESSAGE);
logger.error("Could not run command", logger.error("Could not run command",
confirmation.getError()); status.getException());
JOptionPane.showMessageDialog(this,
status.getException(),
status.getException().getMessage(),
JOptionPane.ERROR_MESSAGE);
} }
} }
catch (ExecutionException | InterruptedException e) catch (ExecutionException | InterruptedException e)

View File

@@ -5,6 +5,7 @@ package edu.regis.universeplayer.player;
import com.intervigil.wave.WaveReader; import com.intervigil.wave.WaveReader;
import edu.regis.universeplayer.AbstractTask;
import edu.regis.universeplayer.PlaybackInfo; import edu.regis.universeplayer.PlaybackInfo;
import edu.regis.universeplayer.PlaybackListener; import edu.regis.universeplayer.PlaybackListener;
import edu.regis.universeplayer.PlaybackStatus; import edu.regis.universeplayer.PlaybackStatus;
@@ -48,6 +49,7 @@ public class LocalPlayer implements Player<LocalSong>, MediaPlayerEventListener
private final MediaPlayerFactory playerFactory; private final MediaPlayerFactory playerFactory;
private final AudioPlayerComponent player; private final AudioPlayerComponent player;
private final ForkJoinPool service = new ForkJoinPool();
private final LinkedList<PlaybackListener> listeners = new LinkedList<>(); private final LinkedList<PlaybackListener> listeners = new LinkedList<>();
private int currentId; private int currentId;
@@ -55,8 +57,6 @@ public class LocalPlayer implements Player<LocalSong>, MediaPlayerEventListener
private LocalSong currentSong; private LocalSong currentSong;
private AudioFile currentFile; private AudioFile currentFile;
private final ExecutorService service = Executors.newSingleThreadExecutor();
public LocalPlayer() public LocalPlayer()
{ {
this.playerFactory = new MediaPlayerFactory(); this.playerFactory = new MediaPlayerFactory();
@@ -118,112 +118,196 @@ public class LocalPlayer implements Player<LocalSong>, MediaPlayerEventListener
} }
@Override @Override
public QueryFuture<Void> loadSong(LocalSong song) public ForkJoinTask<Void> loadSong(LocalSong song)
{ {
if (this.currentSong != null) return this.service.submit(new AbstractTask<>()
{ {
this.stopSong(); @Override
} protected boolean exec()
this.currentSong = song; {
if (!this.player.mediaPlayer().media() if (currentSong != null)
.play(song.file.getAbsolutePath())) {
{ stopSong();
return new NullFuture<>(new RuntimeException("Could not play " + }
"song " + song)); currentSong = song;
} if (!player.mediaPlayer().media()
else .play(song.file.getAbsolutePath()))
{ {
return new NullFuture<>(); this.completeExceptionally(new RuntimeException("Could not play " +
} "song " + song));
return false;
}
else
{
return true;
}
}
});
} }
@Override @Override
public QueryFuture<Void> play() public ForkJoinTask<Void> play()
{
this.player.mediaPlayer().submit(() -> this.player.mediaPlayer()
.controls()
.play());
return new AbstractTask<>()
{
@Override
protected boolean exec()
{
return true;
}
};
}
@Override
public ForkJoinTask<Void> pause()
{ {
this.player.mediaPlayer() this.player.mediaPlayer()
.submit((WrappedRunnable) () -> this.player.mediaPlayer() .submit(() -> this.player.mediaPlayer()
.controls() .controls()
.play()); .pause());
return new NullFuture<>(); return new AbstractTask<>()
{
@Override
protected boolean exec()
{
return true;
}
};
} }
@Override @Override
public QueryFuture<Void> pause() public ForkJoinTask<Void> togglePlayback()
{
return this.service.submit(new AbstractTask<>()
{
@Override
protected boolean exec()
{
ForkJoinTask<Void> command;
if (player.mediaPlayer().status().isPlaying())
{
command = pause();
}
else
{
command = play();
}
command.join();
if (command.isCompletedAbnormally())
{
this.completeExceptionally(command.getException());
return false;
}
else
{
return true;
}
}
});
}
@Override
public ForkJoinTask<Void> stopSong()
{ {
this.player.mediaPlayer() this.player.mediaPlayer()
.submit((WrappedRunnable) () -> this.player.mediaPlayer() .submit(() -> this.player.mediaPlayer()
.controls() .controls()
.pause()); .stop());
return new NullFuture<>(); return new AbstractTask<>()
{
@Override
protected boolean exec()
{
return true;
}
};
} }
@Override @Override
public QueryFuture<Void> togglePlayback() public ForkJoinTask<Void> seek(float time)
{
if (this.player.mediaPlayer().status().isPlaying())
{
return this.pause();
}
else
{
return this.play();
}
}
@Override
public QueryFuture<Void> stopSong()
{ {
this.player.mediaPlayer() this.player.mediaPlayer()
.submit((WrappedRunnable) () -> this.player.mediaPlayer() .submit(() -> this.player.mediaPlayer()
.controls() .controls()
.stop()); .setTime((long) (time * 1000)));
return new NullFuture<>(); return new AbstractTask<>()
}
@Override
public QueryFuture<Void> seek(float time)
{
this.player.mediaPlayer()
.submit((WrappedRunnable) () -> this.player.mediaPlayer()
.controls()
.setTime((long) (time * 1000)));
return new NullFuture<>();
}
@Override
public QueryFuture<PlaybackStatus> getStatus()
{
PlaybackStatus returnStatus;
StatusApi status = this.player.mediaPlayer().status();
switch (status.state())
{ {
case NOTHING_SPECIAL -> returnStatus = PlaybackStatus.EMPTY; @Override
case PLAYING -> returnStatus = PlaybackStatus.PLAYING; protected boolean exec()
case PAUSED -> returnStatus = PlaybackStatus.PAUSED; {
default -> returnStatus = PlaybackStatus.STOPPED; return true;
} }
return new NullFuture<>(returnStatus); };
} }
@Override @Override
public QueryFuture<Float> getCurrentTime() public ForkJoinTask<PlaybackStatus> getStatus()
{ {
return new NullFuture<>(this.player.mediaPlayer().status() return this.service.submit(new AbstractTask<>()
.time() / 1000F); {
@Override
protected boolean exec()
{
PlaybackStatus returnStatus;
StatusApi status = player.mediaPlayer().status();
switch (status.state())
{
case NOTHING_SPECIAL -> returnStatus = PlaybackStatus.EMPTY;
case PLAYING -> returnStatus = PlaybackStatus.PLAYING;
case PAUSED -> returnStatus = PlaybackStatus.PAUSED;
default -> returnStatus = PlaybackStatus.STOPPED;
}
this.complete(returnStatus);
return true;
}
});
} }
@Override @Override
public QueryFuture<Float> getLength() public ForkJoinTask<Float> getCurrentTime()
{ {
return new NullFuture<>(this.player.mediaPlayer().status() return this.service.submit(new AbstractTask<>()
.length() / 1000F); {
@Override
protected boolean exec()
{
complete(player.mediaPlayer().status()
.time() / 1000F);
return true;
}
});
} }
@Override @Override
public QueryFuture<Void> close() public ForkJoinTask<Float> getLength()
{ {
this.player.release(); return this.service.submit(new AbstractTask<>()
return new NullFuture<>(); {
@Override
protected boolean exec()
{
complete(player.mediaPlayer().status()
.length() / 1000F);
return true;
}
});
}
@Override
public ForkJoinTask<Void> close()
{
return this.service.submit(new AbstractTask<>()
{
@Override
protected boolean exec()
{
player.release();
return true;
}
});
} }
@Override @Override

View File

@@ -10,6 +10,7 @@ import edu.regis.universeplayer.browserCommands.QueryFuture;
import edu.regis.universeplayer.data.Song; import edu.regis.universeplayer.data.Song;
import java.util.HashMap; import java.util.HashMap;
import java.util.concurrent.ForkJoinTask;
/** /**
* This interface serves as the connection to a music player of some sort, whether it be * This interface serves as the connection to a music player of some sort, whether it be
@@ -34,33 +35,33 @@ public interface Player<T extends Song>
* @param song - The song to load. * @param song - The song to load.
* @return A confirmation of whether the command was successful or not. * @return A confirmation of whether the command was successful or not.
*/ */
QueryFuture<Void> loadSong(T song); ForkJoinTask<Void> loadSong(T song);
/** /**
* Enables playback of the current song, if one is active. * Enables playback of the current song, if one is active.
* *
* @return A confirmation of whether the command was successful or not. * @return A confirmation of whether the command was successful or not.
*/ */
QueryFuture<Void> play(); ForkJoinTask<Void> play();
/** /**
* Pauses playback of the current song. * Pauses playback of the current song.
* *
* @return A confirmation of whether the command was successful or not. * @return A confirmation of whether the command was successful or not.
*/ */
QueryFuture<Void> pause(); ForkJoinTask<Void> pause();
/** /**
* Toggles between playing and pausing the current song. * Toggles between playing and pausing the current song.
* *
* @return A confirmation of whether the command was successful or not. * @return A confirmation of whether the command was successful or not.
*/ */
QueryFuture<Void> togglePlayback(); ForkJoinTask<Void> togglePlayback();
/** /**
* Stops playback of the current song. * Stops playback of the current song.
*/ */
QueryFuture<Void> stopSong(); ForkJoinTask<Void> stopSong();
/** /**
* Sets the current song time to the specified position. * Sets the current song time to the specified position.
@@ -68,34 +69,34 @@ public interface Player<T extends Song>
* @param time - The specified time in the song, in seconds. * @param time - The specified time in the song, in seconds.
* @return A confirmation of whether the command was successful or not. * @return A confirmation of whether the command was successful or not.
*/ */
QueryFuture<Void> seek(float time); ForkJoinTask<Void> seek(float time);
/** /**
* Obtains the player's current playback status. * Obtains the player's current playback status.
* @return A future for the request. * @return A future for the request.
*/ */
QueryFuture<PlaybackStatus> getStatus(); ForkJoinTask<PlaybackStatus> getStatus();
/** /**
* Obtains the time we are currently at in the current song. * Obtains the time we are currently at in the current song.
* *
* @return - The current song position in seconds, or -1 if no song is playing. * @return - The current song position in seconds, or -1 if no song is playing.
*/ */
QueryFuture<Float> getCurrentTime(); ForkJoinTask<Float> getCurrentTime();
/** /**
* Gets the length of the current song. * Gets the length of the current song.
* *
* @return The song length, in seconds. * @return The song length, in seconds.
*/ */
QueryFuture<Float> getLength(); ForkJoinTask<Float> getLength();
/** /**
* Closes the player. * Closes the player.
* *
* @return A confirmation of whether the player was successfully closed. * @return A confirmation of whether the player was successfully closed.
*/ */
QueryFuture<Void> close(); ForkJoinTask<Void> close();
/** /**
* Adds a listener for playback status updates. * Adds a listener for playback status updates.

View File

@@ -7,11 +7,13 @@ import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.concurrent.CancellationException; import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import edu.regis.universeplayer.AbstractTask;
import edu.regis.universeplayer.PlaybackListener; import edu.regis.universeplayer.PlaybackListener;
import edu.regis.universeplayer.PlaybackStatus; import edu.regis.universeplayer.PlaybackStatus;
import edu.regis.universeplayer.browserCommands.CommandConfirmation; import edu.regis.universeplayer.browserCommands.CommandConfirmation;
@@ -150,10 +152,10 @@ public class PlayerManager implements PlaybackListener
*/ */
private <T> QueryFuture<T> getNullPlayer(String message, T returnValue) private <T> QueryFuture<T> getNullPlayer(String message, T returnValue)
{ {
return new QueryFuture<T>() return new QueryFuture<>()
{ {
@Override @Override
public CommandConfirmation getConfirmation() throws CancellationException, ExecutionException, InterruptedException public CommandConfirmation getConfirmation() throws CancellationException
{ {
if (returnValue instanceof Throwable) if (returnValue instanceof Throwable)
{ {
@@ -166,7 +168,7 @@ public class PlayerManager implements PlaybackListener
} }
@Override @Override
public CommandConfirmation getConfirmation(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException public CommandConfirmation getConfirmation(long timeout, TimeUnit unit)
{ {
return this.getConfirmation(); return this.getConfirmation();
} }
@@ -190,13 +192,13 @@ public class PlayerManager implements PlaybackListener
} }
@Override @Override
public T get() throws InterruptedException, ExecutionException public T get()
{ {
return returnValue; return returnValue;
} }
@Override @Override
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException public T get(long timeout, TimeUnit unit)
{ {
return this.get(); return this.get();
} }
@@ -211,16 +213,16 @@ public class PlayerManager implements PlaybackListener
*/ */
private <T> QueryFuture<T> getNullPlayer(Throwable message, T returnValue) private <T> QueryFuture<T> getNullPlayer(Throwable message, T returnValue)
{ {
return new QueryFuture<T>() return new QueryFuture<>()
{ {
@Override @Override
public CommandConfirmation getConfirmation() throws CancellationException, ExecutionException, InterruptedException public CommandConfirmation getConfirmation() throws CancellationException
{ {
return new CommandConfirmation(message); return new CommandConfirmation(message);
} }
@Override @Override
public CommandConfirmation getConfirmation(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException public CommandConfirmation getConfirmation(long timeout, TimeUnit unit)
{ {
return this.getConfirmation(); return this.getConfirmation();
} }
@@ -244,20 +246,20 @@ public class PlayerManager implements PlaybackListener
} }
@Override @Override
public T get() throws InterruptedException, ExecutionException public T get()
{ {
return returnValue; return returnValue;
} }
@Override @Override
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException public T get(long timeout, TimeUnit unit)
{ {
return this.get(); return this.get();
} }
}; };
} }
public QueryFuture<Void> playSong(Song song) public ForkJoinTask<Void> playSong(Song song)
{ {
if (this.currentSong != null) if (this.currentSong != null)
{ {
@@ -274,16 +276,24 @@ public class PlayerManager implements PlaybackListener
return this.currentPlayer.loadSong(song); return this.currentPlayer.loadSong(song);
} }
public QueryFuture<PlaybackStatus> getStatus() public ForkJoinTask<PlaybackStatus> getStatus()
{ {
if (this.currentPlayer != null) if (this.currentPlayer != null)
{ {
return this.currentPlayer.getStatus(); return this.currentPlayer.getStatus();
} }
return this.getNullPlayer("Command successful", PlaybackStatus.EMPTY); return new AbstractTask<>()
{
@Override
protected boolean exec()
{
complete(PlaybackStatus.EMPTY);
return true;
}
};
} }
public QueryFuture<Void> seek(float time) public ForkJoinTask<Void> seek(float time)
{ {
if (this.currentPlayer != null) if (this.currentPlayer != null)
{ {
@@ -292,7 +302,7 @@ public class PlayerManager implements PlaybackListener
return null; return null;
} }
public QueryFuture<Void> play() public ForkJoinTask<Void> play()
{ {
if (this.currentPlayer != null && this.currentSong != null) if (this.currentPlayer != null && this.currentSong != null)
{ {
@@ -301,7 +311,7 @@ public class PlayerManager implements PlaybackListener
return null; return null;
} }
public QueryFuture<Void> pause() public ForkJoinTask<Void> pause()
{ {
if (this.currentPlayer != null && this.currentSong != null) if (this.currentPlayer != null && this.currentSong != null)
{ {
@@ -310,7 +320,7 @@ public class PlayerManager implements PlaybackListener
return null; return null;
} }
public QueryFuture<Void> toggle() public ForkJoinTask<Void> toggle()
{ {
if (this.currentPlayer != null && this.currentSong != null) if (this.currentPlayer != null && this.currentSong != null)
{ {
@@ -319,7 +329,7 @@ public class PlayerManager implements PlaybackListener
return null; return null;
} }
public QueryFuture<Void> stopSong() public ForkJoinTask<Void> stopSong()
{ {
if (this.currentPlayer != null && this.currentSong != null) if (this.currentPlayer != null && this.currentSong != null)
{ {
@@ -370,14 +380,22 @@ public class PlayerManager implements PlaybackListener
* script or a background script. * script or a background script.
* @return The command future. * @return The command future.
*/ */
public QueryFuture<Void> throwError(boolean forward) public ForkJoinTask<Void> throwError(boolean forward)
{ {
BrowserPlayer player = BrowserPlayer player =
(BrowserPlayer) this.players.get(InternetSong.class); (BrowserPlayer) this.players.get(InternetSong.class);
if (player == null) if (player == null)
{ {
return this.getNullPlayer(new NullPointerException( return new AbstractTask<>()
"No browser found"), null); {
@Override
protected boolean exec()
{
completeExceptionally(new NullPointerException("Couldn't " +
"find internet player"));
return false;
}
};
} }
return player.throwError(forward); return player.throwError(forward);
} }