/*
* Copyright 2008-2013, ETH Zürich, Samuel Welten, Michael Kuhn, Tobias Langner,
* Sandro Affentranger, Lukas Bossard, Michael Grob, Rahul Jain,
* Dominic Langenegger, Sonia Mayor Alonso, Roger Odermatt, Tobias Schlueter,
* Yannick Stucki, Sebastian Wendland, Samuel Zehnder, Samuel Zihlmann,
* Samuel Zweifel
*
* This file is part of Jukefox.
*
* Jukefox is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or any later version. Jukefox is
* distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* Jukefox. If not, see <http://www.gnu.org/licenses/>.
*/
package ch.ethz.dcg.jukefox.controller.player;
import java.util.ArrayList;
import java.util.List;
import ch.ethz.dcg.jukefox.commons.utils.Log;
import ch.ethz.dcg.jukefox.controller.player.playbackcontroller.IPlaybackController;
import ch.ethz.dcg.jukefox.controller.player.playlistmanager.IPlaylistManager;
import ch.ethz.dcg.jukefox.model.AbstractCollectionModelManager;
import ch.ethz.dcg.jukefox.model.AbstractPlayerModelManager;
import ch.ethz.dcg.jukefox.model.collection.BaseAlbum;
import ch.ethz.dcg.jukefox.model.collection.BaseArtist;
import ch.ethz.dcg.jukefox.model.collection.IPlaylist;
import ch.ethz.dcg.jukefox.model.collection.IReadOnlyPlaylist;
import ch.ethz.dcg.jukefox.model.collection.Playlist;
import ch.ethz.dcg.jukefox.model.collection.PlaylistSong;
import ch.ethz.dcg.jukefox.model.commons.EmptyPlaylistException;
import ch.ethz.dcg.jukefox.model.commons.NoNextSongException;
import ch.ethz.dcg.jukefox.model.commons.PlaylistPositionOutOfRangeException;
import ch.ethz.dcg.jukefox.model.player.PlayModeType;
import ch.ethz.dcg.jukefox.model.player.PlayerState;
import ch.ethz.dcg.jukefox.playmode.IPlayMode;
/**
* Manager for everything player or playlist related. This class can be used safely once isReady returns true.
*/
public abstract class AbstractPlayerController implements IPlayerController, IPlaylistManager,
IPlaybackInfoBroadcaster, IPlayerListenerInformer, IPlaylistListenerInformer {
@SuppressWarnings("unused")
private final static String TAG = AbstractPlayerController.class.getSimpleName();
protected final AbstractCollectionModelManager collectionModel;
protected final AbstractPlayerModelManager playerModel;
protected IPlaylistManager currentPlaylistManager;
protected IPlaybackController playbackController;
// Playlist state change is handled here.
private final List<IOnPlaylistStateChangeListener> playlistStateChangeListeners = new ArrayList<IOnPlaylistStateChangeListener>();
// Player state change is handled here.
private final List<IOnPlayerStateChangeListener> playerStateChangeListeners = new ArrayList<IOnPlayerStateChangeListener>();
private boolean isReady = false;
public AbstractPlayerController(AbstractCollectionModelManager model, AbstractPlayerModelManager playerModel) {
this.collectionModel = model;
this.playerModel = playerModel;
this.currentPlaylistManager = createPlaylistManager(this, collectionModel, playerModel);
// TODO: do decision if it should create a gapless player or not
this.playbackController = createPlaybackController(this, collectionModel, playerModel, currentPlaylistManager);
if (currentPlaylistManager.getCurrentPlaylist() == null) {
// Ensure that we have a valid playlist from the beginning
currentPlaylistManager.setPlaylist(new Playlist());
}
playerModel.getPlayLog().setPlayerController(this);
playerModel.getContextProvider().setPlayerController(this);
isReady = true;
}
@Override
public boolean isReady() {
return isReady;
}
protected abstract IPlaybackController createPlaybackController(IPlaybackInfoBroadcaster listenerInformer,
AbstractCollectionModelManager collectionModel, AbstractPlayerModelManager playerModel,
IPlaylistManager playlistManager);
protected abstract IPlaylistManager createPlaylistManager(IPlaybackInfoBroadcaster listenerInformer,
AbstractCollectionModelManager collectionModel, AbstractPlayerModelManager playerModel);
@Override
public int getDuration() {
return playbackController.getDuration();
}
@Override
public PlayerState getPlayerState() {
return playbackController.getPlayerState();
}
@Override
public int getPlaybackPosition() {
return playbackController.getPlaybackPosition();
}
@Override
public void jumpToPlaylistPosition(int position) {
playbackController.jumpToPlaylistPosition(position);
}
@Override
public void mute() {
playbackController.mute();
}
@Override
public void pause() {
playbackController.pause();
}
@Override
public void play() {
// Log.v(TAG, "playerController: " + playbackController.toString());
playbackController.play();
}
@Override
public void addOnPlayerStateChangeListener(IOnPlayerStateChangeListener listener) {
if (listener != null) {
playerStateChangeListeners.add(listener);
}
}
@Override
public void removeOnPlayerStateChangeListener(IOnPlayerStateChangeListener listener) {
if (listener != null) {
playerStateChangeListeners.remove(listener);
}
}
@Override
public void seekTo(int position) {
playbackController.seekTo(position);
}
@Override
public void stop() {
playbackController.stop();
}
@Override
public void unmute() {
playbackController.unmute();
}
// Below here are the methods implementing IPlaylistController.
@Override
public void addOnPlaylistStateChangeListener(IOnPlaylistStateChangeListener listener) {
synchronized (playlistStateChangeListeners) {
if (listener != null) {
playlistStateChangeListeners.add(listener);
}
}
}
@Override
public void removeOnPlaylistStateChangeListener(IOnPlaylistStateChangeListener listener) {
if (listener != null) {
synchronized (playlistStateChangeListeners) {
playlistStateChangeListeners.remove(listener);
}
}
}
@Override
public void appendSongAtEnd(PlaylistSong<BaseArtist, BaseAlbum> song) {
currentPlaylistManager.appendSongAtEnd(song);
}
@Override
public void appendSongsAtEnd(List<PlaylistSong<BaseArtist, BaseAlbum>> songs) {
currentPlaylistManager.appendSongsAtEnd(songs);
}
@Override
public void clearPlaylist() {
playbackController.stop();
currentPlaylistManager.clearPlaylist();
currentPlaylistManager.getPlayMode().reset();
}
@Override
public IReadOnlyPlaylist getCurrentPlaylist() {
return currentPlaylistManager.getCurrentPlaylist();
}
@Override
public int getCurrentSongIndex() throws EmptyPlaylistException {
return currentPlaylistManager.getCurrentSongIndex();
}
@Override
public void setCurrentSongIndex(int index) throws PlaylistPositionOutOfRangeException {
currentPlaylistManager.setCurrentSongIndex(index);
}
@Override
public PlaylistSong<BaseArtist, BaseAlbum> getCurrentSong() throws EmptyPlaylistException {
return currentPlaylistManager.getCurrentSong();
}
@Override
public IPlayMode getPlayMode() {
// Log.v(TAG, playbackController.toString());
// Log.v(TAG,
// playbackController.getCurrentPlaylistManager().toString());
// Log.v(TAG,
// playbackController.getCurrentPlaylistManager().getPlayMode().toString());
return currentPlaylistManager.getPlayMode();
}
@Override
public void insertSongAtPosition(PlaylistSong<BaseArtist, BaseAlbum> song, int position)
throws PlaylistPositionOutOfRangeException {
currentPlaylistManager.insertSongAtPosition(song, position);
}
@Override
public void insertSongsAtPosition(List<PlaylistSong<BaseArtist, BaseAlbum>> songs, int position)
throws PlaylistPositionOutOfRangeException {
currentPlaylistManager.insertSongsAtPosition(songs, position);
}
@Override
public void insertSongAsNext(PlaylistSong<BaseArtist, BaseAlbum> song) {
currentPlaylistManager.insertSongAsNext(song);
}
@Override
public void insertSongsAsNext(List<PlaylistSong<BaseArtist, BaseAlbum>> songs)
throws PlaylistPositionOutOfRangeException, EmptyPlaylistException {
currentPlaylistManager.insertSongsAsNext(songs);
}
@Override
public boolean isPlaylistEmptyOrAtEnd() {
return currentPlaylistManager.isPlaylistEmptyOrAtEnd();
}
@Override
public void setPlaylist(IPlaylist playlist) {
playbackController.setPlaylist(playlist);
}
@Override
public void moveSong(int oldPosition, int newPosition) throws EmptyPlaylistException,
PlaylistPositionOutOfRangeException {
currentPlaylistManager.moveSong(oldPosition, newPosition);
}
@Override
public void playNext() throws EmptyPlaylistException, NoNextSongException {
playbackController.next();
}
@Override
public void playSongAtPosition(int position) throws PlaylistPositionOutOfRangeException {
playbackController.jumpToPlaylistPosition(position);
playbackController.play();
}
@Override
public void loadSongAtPosition(int position) throws PlaylistPositionOutOfRangeException {
playbackController.jumpToPlaylistPosition(position);
}
@Override
public void playPrevious() throws EmptyPlaylistException, NoNextSongException {
playbackController.previous();
playbackController.play();
}
@Override
public void removeSongFromPlaylist(int position) throws EmptyPlaylistException, PlaylistPositionOutOfRangeException {
currentPlaylistManager.removeSongFromPlaylist(position);
}
// Below here are the methods implementing IPlayListener.
@Override
public void informPlaylistChangeListener(IReadOnlyPlaylist playlist) {
synchronized (playlistStateChangeListeners) {
for (IOnPlaylistStateChangeListener listener : playlistStateChangeListeners) {
listener.onPlaylistChanged(playlist);
}
}
}
@Override
public void informPlayModeChangeListener(IPlayMode newPlayMode) {
if (newPlayMode == null) {
return;
}
synchronized (playlistStateChangeListeners) {
for (IOnPlaylistStateChangeListener listener : playlistStateChangeListeners) {
listener.onPlayModeChanged(newPlayMode);
}
}
}
@Override
public void informCurrentSongChangeListener(PlaylistSong<BaseArtist, BaseAlbum> newSong) {
if (newSong == null) {
return;
}
synchronized (playlistStateChangeListeners) {
for (IOnPlaylistStateChangeListener listener : playlistStateChangeListeners) {
listener.onCurrentSongChanged(newSong);
}
}
}
@Override
public void informSongCompletedListeners(PlaylistSong<BaseArtist, BaseAlbum> song) {
if (song == null) {
return;
}
Log.v(TAG, "song completed informer start");
for (IOnPlayerStateChangeListener listener : playerStateChangeListeners) {
listener.onSongCompleted(song);
}
Log.v(TAG, "song completed informer end");
}
@Override
public void informSongSkippedListeners(PlaylistSong<BaseArtist, BaseAlbum> song) {
if (song == null) {
return;
}
Log.v(TAG, "song completed informer start");
for (IOnPlayerStateChangeListener listener : playerStateChangeListeners) {
listener.onSongSkipped(song, playbackController.getPlaybackPosition());
}
// Log.v(TAG,"song completed informer end");
}
@Override
public void informSongStartedListeners(PlaylistSong<BaseArtist, BaseAlbum> song) {
if (song == null) {
return;
}
Log.v(TAG, "informSongStartedListeners()");
for (IOnPlayerStateChangeListener listener : playerStateChangeListeners) {
if (listener != null) {
listener.onSongStarted(song);
Log.v(TAG, "informSongStartedListeners() inform");
}
}
Log.v(TAG, "informSongStartedListeners() 2");
}
@Override
public void informPlayerStateChangedListeners(PlayerState playerState) {
if (playerState == null) {
return;
}
Log.v(TAG, "informPlayerStateChanged started");
for (IOnPlayerStateChangeListener listener : playerStateChangeListeners) {
listener.onPlayerStateChanged(playerState);
}
Log.v(TAG, "informPlayerStateChanged ended");
}
// public void loadPlaylist(String name, boolean readPositionInfo) throws
// IOException {
// PlaylistReader.loadPlaylistFromFileByName(this, playerController,
// collectionModel.getDbWrapper(), name,
// readPositionInfo);
// }
//
// public void loadVideoPlaylist(String name, boolean readPositionInfo)
// throws IOException {
// PlaylistReader.loadVideoPlaylistFromFileByName(this, playerController,
// collectionModel.getDbWrapper(), name,
// readPositionInfo);
// }
// public void savePlaylist(IReadOnlyPlaylist playlist, String name) {
// PlaylistWriter
// .writePlaylistToFile(collectionModel.getDbWrapper(), this,
// playerController, playlist, name, true);
// }
@Override
public void setPlayMode(PlayModeType playModeType, int artistAvoidance, int songAvoidance) {
playbackController.setPlayMode(playModeType, artistAvoidance, songAvoidance);
}
@Override
public void setPlayMode(IPlayMode playMode) {
playbackController.setPlayMode(playMode);
}
@Override
public void shufflePlaylist(int startPosition) {
currentPlaylistManager.shufflePlaylist(startPosition);
}
}