diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/service/JukeboxMediaPlayer.java b/ultrasonic/src/main/java/org/moire/ultrasonic/service/JukeboxMediaPlayer.java index e6764129..26ecdc30 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/service/JukeboxMediaPlayer.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/service/JukeboxMediaPlayer.java @@ -73,7 +73,7 @@ public class JukeboxMediaPlayer private final Context context; // TODO: These create circular references, try to refactor - private final Lazy mediaPlayerControllerLazy = inject(MediaPlayerControllerImpl.class); + private final Lazy mediaPlayerControllerLazy = inject(MediaPlayerController.class); private final Downloader downloader; // TODO: Report warning if queue fills up. diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/service/MediaPlayerController.java b/ultrasonic/src/main/java/org/moire/ultrasonic/service/MediaPlayerController.java index 4384ad90..7ffd904a 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/service/MediaPlayerController.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/service/MediaPlayerController.java @@ -18,112 +18,595 @@ */ package org.moire.ultrasonic.service; +import android.content.Context; +import android.content.Intent; +import timber.log.Timber; + +import org.koin.java.KoinJavaComponent; +import org.moire.ultrasonic.data.ActiveServerProvider; +import org.moire.ultrasonic.domain.MusicDirectory; import org.moire.ultrasonic.domain.MusicDirectory.Entry; import org.moire.ultrasonic.domain.PlayerState; import org.moire.ultrasonic.domain.RepeatMode; +import org.moire.ultrasonic.domain.UserInfo; +import org.moire.ultrasonic.featureflags.Feature; +import org.moire.ultrasonic.featureflags.FeatureStorage; +import org.moire.ultrasonic.util.ShufflePlayBuffer; +import org.moire.ultrasonic.util.Util; +import java.util.Iterator; import java.util.List; +import kotlin.Lazy; + +import static org.koin.java.KoinJavaComponent.inject; + /** - * This interface contains all functions which are necessary for the Application UI + * The implementation of the Media Player Controller. + * This class contains everything that is necessary for the Application UI * to control the Media Player implementation. * - * @author Sindre Mehus + * @author Sindre Mehus, Joshua Bahnsen * @version $Id$ */ -public interface MediaPlayerController +public class MediaPlayerController { - void download(List songs, boolean save, boolean autoplay, boolean playNext, boolean shuffle, boolean newPlaylist); + private boolean created = false; + private String suggestedPlaylistName; + private boolean keepScreenOn; - void downloadBackground(List songs, boolean save); + private boolean showVisualization; + private boolean autoPlayStart; - void setShufflePlayEnabled(boolean enabled); + private final Context context; + private final Lazy jukeboxMediaPlayer = inject(JukeboxMediaPlayer.class); + private final Lazy activeServerProvider = inject(ActiveServerProvider.class); - boolean isShufflePlayEnabled(); + private final DownloadQueueSerializer downloadQueueSerializer; + private final ExternalStorageMonitor externalStorageMonitor; + private final Downloader downloader; + private final ShufflePlayBuffer shufflePlayBuffer; + private final LocalMediaPlayer localMediaPlayer; - void shuffle(); + public MediaPlayerController(Context context, DownloadQueueSerializer downloadQueueSerializer, + ExternalStorageMonitor externalStorageMonitor, Downloader downloader, + ShufflePlayBuffer shufflePlayBuffer, LocalMediaPlayer localMediaPlayer) + { + this.context = context; + this.downloadQueueSerializer = downloadQueueSerializer; + this.externalStorageMonitor = externalStorageMonitor; + this.downloader = downloader; + this.shufflePlayBuffer = shufflePlayBuffer; + this.localMediaPlayer = localMediaPlayer; - RepeatMode getRepeatMode(); + Timber.i("MediaPlayerController constructed"); + } - void setRepeatMode(RepeatMode repeatMode); + public void onCreate() + { + if (created) return; + this.externalStorageMonitor.onCreate(this::reset); - boolean getKeepScreenOn(); + setJukeboxEnabled(activeServerProvider.getValue().getActiveServer().getJukeboxByDefault()); + created = true; - void setKeepScreenOn(boolean screenOn); + Timber.i("MediaPlayerController created"); + } - boolean getShowVisualization(); + public void onDestroy() + { + if (!created) return; + externalStorageMonitor.onDestroy(); + context.stopService(new Intent(context, MediaPlayerService.class)); + downloader.onDestroy(); + created = false; - void setShowVisualization(boolean showVisualization); + Timber.i("MediaPlayerController destroyed"); + } + public synchronized void restore(List songs, final int currentPlayingIndex, final int currentPlayingPosition, final boolean autoPlay, boolean newPlaylist) + { + download(songs, false, false, false, false, newPlaylist); - void clear(); + if (currentPlayingIndex != -1) + { + MediaPlayerService.executeOnStartedMediaPlayerService(context, (mediaPlayerService) -> + { + mediaPlayerService.play(currentPlayingIndex, autoPlayStart); - void clearIncomplete(); + if (localMediaPlayer.currentPlaying != null) + { + if (autoPlay && jukeboxMediaPlayer.getValue().isEnabled()) + { + jukeboxMediaPlayer.getValue().skip(downloader.getCurrentPlayingIndex(), currentPlayingPosition / 1000); + } + else + { + if (localMediaPlayer.currentPlaying.isCompleteFileAvailable()) + { + localMediaPlayer.play(localMediaPlayer.currentPlaying, currentPlayingPosition, autoPlay); + } + } + } + autoPlayStart = false; + return null; + } + ); + } + } - void remove(DownloadFile downloadFile); + public synchronized void preload() + { + MediaPlayerService.getInstance(context); + } - void play(int index); + public synchronized void play(final int index) + { + MediaPlayerService.executeOnStartedMediaPlayerService(context, (mediaPlayerService) -> { + mediaPlayerService.play(index, true); + return null; + } + ); + } - void seekTo(int position); + public synchronized void play() + { + MediaPlayerService.executeOnStartedMediaPlayerService(context, (mediaPlayerService) -> { - void previous(); + mediaPlayerService.play(); + return null; + } + ); + } - void next(); + public synchronized void resumeOrPlay() + { + MediaPlayerService.executeOnStartedMediaPlayerService(context, (mediaPlayerService) -> { + mediaPlayerService.resumeOrPlay(); + return null; + } + ); + } - void pause(); + public synchronized void togglePlayPause() + { + if (localMediaPlayer.playerState == PlayerState.IDLE) autoPlayStart = true; + MediaPlayerService.executeOnStartedMediaPlayerService(context, (mediaPlayerService) -> { + mediaPlayerService.togglePlayPause(); + return null; + } + ); + } - void stop(); + public synchronized void start() + { + MediaPlayerService.executeOnStartedMediaPlayerService(context, (mediaPlayerService) -> { + mediaPlayerService.start(); + return null; + } + ); + } - void start(); + public synchronized void seekTo(final int position) + { + MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); + if (mediaPlayerService != null) mediaPlayerService.seekTo(position); + } - void reset(); + public synchronized void pause() + { + MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); + if (mediaPlayerService != null) mediaPlayerService.pause(); + } - PlayerState getPlayerState(); + public synchronized void stop() + { + MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); + if (mediaPlayerService != null) mediaPlayerService.stop(); + } - int getPlayerPosition(); + public synchronized void download(List songs, boolean save, boolean autoPlay, boolean playNext, boolean shuffle, boolean newPlaylist) + { + downloader.download(songs, save, autoPlay, playNext, newPlaylist); + jukeboxMediaPlayer.getValue().updatePlaylist(); - int getPlayerDuration(); + if (shuffle) shuffle(); - void delete(List songs); + if (!playNext && !autoPlay && (downloader.downloadList.size() - 1) == downloader.getCurrentPlayingIndex()) + { + MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); + if (mediaPlayerService != null) mediaPlayerService.setNextPlaying(); + } - void unpin(List songs); + if (autoPlay) + { + play(0); + } + else + { + if (localMediaPlayer.currentPlaying == null && downloader.downloadList.size() > 0) + { + localMediaPlayer.currentPlaying = downloader.downloadList.get(0); + localMediaPlayer.currentPlaying.setPlaying(true); + } - void setSuggestedPlaylistName(String name); + downloader.checkDownloads(); + } - String getSuggestedPlaylistName(); + downloadQueueSerializer.serializeDownloadQueue(downloader.downloadList, downloader.getCurrentPlayingIndex(), getPlayerPosition()); + } - boolean isJukeboxEnabled(); + public synchronized void downloadBackground(List songs, boolean save) + { + downloader.downloadBackground(songs, save); + downloadQueueSerializer.serializeDownloadQueue(downloader.downloadList, downloader.getCurrentPlayingIndex(), getPlayerPosition()); + } - boolean isJukeboxAvailable(); + public synchronized void setCurrentPlaying(DownloadFile currentPlaying) + { + MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); + if (mediaPlayerService != null) localMediaPlayer.setCurrentPlaying(currentPlaying); + } - void setJukeboxEnabled(boolean b); + public synchronized void setCurrentPlaying(int index) + { + MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); + if (mediaPlayerService != null) mediaPlayerService.setCurrentPlaying(index); + } - void adjustJukeboxVolume(boolean up); + public synchronized void setPlayerState(PlayerState state) + { + MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); + if (mediaPlayerService != null) localMediaPlayer.setPlayerState(state); + } - void togglePlayPause(); + public void stopJukeboxService() + { + jukeboxMediaPlayer.getValue().stopJukeboxService(); + } - void setVolume(float volume); + public synchronized void setShufflePlayEnabled(boolean enabled) + { + shufflePlayBuffer.isEnabled = enabled; + if (enabled) + { + clear(); + downloader.checkDownloads(); + } + } - void restore(List songs, int currentPlayingIndex, int currentPlayingPosition, boolean autoPlay, boolean newPlaylist); + public boolean isShufflePlayEnabled() + { + return shufflePlayBuffer.isEnabled; + } - void stopJukeboxService(); + public synchronized void shuffle() + { + downloader.shuffle(); - void updateNotification(); + downloadQueueSerializer.serializeDownloadQueue(downloader.downloadList, downloader.getCurrentPlayingIndex(), getPlayerPosition()); + jukeboxMediaPlayer.getValue().updatePlaylist(); - void setSongRating(final int rating); + MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); + if (mediaPlayerService != null) mediaPlayerService.setNextPlaying(); + } - DownloadFile getCurrentPlaying(); + public RepeatMode getRepeatMode() + { + return Util.getRepeatMode(); + } - int getPlaylistSize(); + public synchronized void setRepeatMode(RepeatMode repeatMode) + { + Util.setRepeatMode(repeatMode); + MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); + if (mediaPlayerService != null) mediaPlayerService.setNextPlaying(); + } - int getCurrentPlayingNumberOnPlaylist(); + public boolean getKeepScreenOn() + { + return keepScreenOn; + } - DownloadFile getCurrentDownloading(); + public void setKeepScreenOn(boolean keepScreenOn) + { + this.keepScreenOn = keepScreenOn; + } - List getPlayList(); + public boolean getShowVisualization() + { + return showVisualization; + } - long getPlayListUpdateRevision(); + public void setShowVisualization(boolean showVisualization) + { + this.showVisualization = showVisualization; + } - long getPlayListDuration(); + public synchronized void clear() + { + clear(true); + } - DownloadFile getDownloadFileForSong(Entry song); -} + public synchronized void clear(boolean serialize) + { + MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); + if (mediaPlayerService != null) { + mediaPlayerService.clear(serialize); + } else { + // If no MediaPlayerService is available, just empty the playlist + downloader.clear(); + if (serialize) { + downloadQueueSerializer.serializeDownloadQueue(downloader.downloadList, + downloader.getCurrentPlayingIndex(), getPlayerPosition()); + } + } + + jukeboxMediaPlayer.getValue().updatePlaylist(); + } + + public synchronized void clearIncomplete() + { + reset(); + Iterator iterator = downloader.downloadList.iterator(); + + while (iterator.hasNext()) + { + DownloadFile downloadFile = iterator.next(); + if (!downloadFile.isCompleteFileAvailable()) + { + iterator.remove(); + } + } + + downloadQueueSerializer.serializeDownloadQueue(downloader.downloadList, downloader.getCurrentPlayingIndex(), getPlayerPosition()); + jukeboxMediaPlayer.getValue().updatePlaylist(); + } + + public synchronized void remove(DownloadFile downloadFile) + { + if (downloadFile == localMediaPlayer.currentPlaying) + { + reset(); + setCurrentPlaying(null); + } + + downloader.removeDownloadFile(downloadFile); + + downloadQueueSerializer.serializeDownloadQueue(downloader.downloadList, downloader.getCurrentPlayingIndex(), getPlayerPosition()); + jukeboxMediaPlayer.getValue().updatePlaylist(); + + if (downloadFile == localMediaPlayer.nextPlaying) + { + MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); + if (mediaPlayerService != null) mediaPlayerService.setNextPlaying(); + } + } + + public synchronized void delete(List songs) + { + for (MusicDirectory.Entry song : songs) + { + downloader.getDownloadFileForSong(song).delete(); + } + } + + public synchronized void unpin(List songs) + { + for (MusicDirectory.Entry song : songs) + { + downloader.getDownloadFileForSong(song).unpin(); + } + } + + public synchronized void previous() + { + int index = downloader.getCurrentPlayingIndex(); + if (index == -1) + { + return; + } + + // Restart song if played more than five seconds. + if (getPlayerPosition() > 5000 || index == 0) + { + play(index); + } + else + { + play(index - 1); + } + } + + public synchronized void next() + { + int index = downloader.getCurrentPlayingIndex(); + if (index != -1) + { + switch (getRepeatMode()) + { + case SINGLE: + case OFF: + if (index + 1 >= 0 && index + 1 < downloader.downloadList.size()) { + play(index + 1); + } + break; + case ALL: + play((index + 1) % downloader.downloadList.size()); + break; + default: + break; + } + } + } + + public synchronized void reset() + { + MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); + if (mediaPlayerService != null) localMediaPlayer.reset(); + } + + public synchronized int getPlayerPosition() + { + MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); + if (mediaPlayerService == null) return 0; + return mediaPlayerService.getPlayerPosition(); + } + + public synchronized int getPlayerDuration() + { + if (localMediaPlayer.currentPlaying != null) + { + Integer duration = localMediaPlayer.currentPlaying.getSong().getDuration(); + if (duration != null) + { + return duration * 1000; + } + } + + MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); + if (mediaPlayerService == null) return 0; + return mediaPlayerService.getPlayerDuration(); + } + + public PlayerState getPlayerState() { return localMediaPlayer.playerState; } + + public void setSuggestedPlaylistName(String name) + { + this.suggestedPlaylistName = name; + } + + public String getSuggestedPlaylistName() + { + return suggestedPlaylistName; + } + + public boolean isJukeboxEnabled() + { + return jukeboxMediaPlayer.getValue().isEnabled(); + } + + public boolean isJukeboxAvailable() + { + try + { + String username = activeServerProvider.getValue().getActiveServer().getUserName(); + UserInfo user = MusicServiceFactory.getMusicService().getUser(username); + return user.getJukeboxRole(); + } + catch (Exception e) + { + Timber.w(e, "Error getting user information"); + } + + return false; + } + + public void setJukeboxEnabled(boolean jukeboxEnabled) + { + jukeboxMediaPlayer.getValue().setEnabled(jukeboxEnabled); + setPlayerState(PlayerState.IDLE); + + if (jukeboxEnabled) + { + jukeboxMediaPlayer.getValue().startJukeboxService(); + + reset(); + + // Cancel current download, if necessary. + if (downloader.currentDownloading != null) + { + downloader.currentDownloading.cancelDownload(); + } + } + else + { + jukeboxMediaPlayer.getValue().stopJukeboxService(); + } + } + + public void adjustJukeboxVolume(boolean up) + { + jukeboxMediaPlayer.getValue().adjustVolume(up); + } + + public void setVolume(float volume) + { + MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); + if (mediaPlayerService != null) localMediaPlayer.setVolume(volume); + } + + public void updateNotification() + { + MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); + if (mediaPlayerService != null) mediaPlayerService.updateNotification(localMediaPlayer.playerState, localMediaPlayer.currentPlaying); + } + + public void toggleSongStarred() { + if (localMediaPlayer.currentPlaying == null) + return; + + final Entry song = localMediaPlayer.currentPlaying.getSong(); + + // Trigger an update + localMediaPlayer.setCurrentPlaying(localMediaPlayer.currentPlaying); + + song.setStarred(!song.getStarred()); + } + + public void setSongRating(final int rating) + { + if (!KoinJavaComponent.get(FeatureStorage.class).isFeatureEnabled(Feature.FIVE_STAR_RATING)) + return; + + if (localMediaPlayer.currentPlaying == null) + return; + + final Entry song = localMediaPlayer.currentPlaying.getSong(); + song.setUserRating(rating); + + new Thread(() -> { + try + { + MusicServiceFactory.getMusicService().setRating(song.getId(), rating); + } + catch (Exception e) + { + Timber.e(e); + } + }).start(); + + updateNotification(); + } + + public DownloadFile getCurrentPlaying() { + return localMediaPlayer.currentPlaying; + } + + public int getPlaylistSize() { + return downloader.downloadList.size(); + } + + public int getCurrentPlayingNumberOnPlaylist() { + return downloader.getCurrentPlayingIndex(); + } + + public DownloadFile getCurrentDownloading() { + return downloader.currentDownloading; + } + + public List getPlayList() { + return downloader.downloadList; + } + + public long getPlayListUpdateRevision() { + return downloader.getDownloadListUpdateRevision(); + } + + public long getPlayListDuration() { + return downloader.getDownloadListDuration(); + } + + public DownloadFile getDownloadFileForSong(Entry song) { + return downloader.getDownloadFileForSong(song); + } +} \ No newline at end of file diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/service/MediaPlayerControllerImpl.java b/ultrasonic/src/main/java/org/moire/ultrasonic/service/MediaPlayerControllerImpl.java deleted file mode 100644 index 7a9d6af6..00000000 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/service/MediaPlayerControllerImpl.java +++ /dev/null @@ -1,661 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package org.moire.ultrasonic.service; - -import android.content.Context; -import android.content.Intent; -import timber.log.Timber; - -import org.koin.java.KoinJavaComponent; -import org.moire.ultrasonic.data.ActiveServerProvider; -import org.moire.ultrasonic.domain.MusicDirectory; -import org.moire.ultrasonic.domain.MusicDirectory.Entry; -import org.moire.ultrasonic.domain.PlayerState; -import org.moire.ultrasonic.domain.RepeatMode; -import org.moire.ultrasonic.domain.UserInfo; -import org.moire.ultrasonic.featureflags.Feature; -import org.moire.ultrasonic.featureflags.FeatureStorage; -import org.moire.ultrasonic.util.ShufflePlayBuffer; -import org.moire.ultrasonic.util.Util; - -import java.util.Iterator; -import java.util.List; - -import kotlin.Lazy; - -import static org.koin.java.KoinJavaComponent.inject; - -/** - * The implementation of the Media Player Controller. - * This class contains everything that is necessary for the Application UI - * to control the Media Player implementation. - * - * @author Sindre Mehus, Joshua Bahnsen - * @version $Id$ - */ -public class MediaPlayerControllerImpl implements MediaPlayerController -{ - private boolean created = false; - private String suggestedPlaylistName; - private boolean keepScreenOn; - - private boolean showVisualization; - private boolean autoPlayStart; - - private final Context context; - private final Lazy jukeboxMediaPlayer = inject(JukeboxMediaPlayer.class); - private final Lazy activeServerProvider = inject(ActiveServerProvider.class); - - private final DownloadQueueSerializer downloadQueueSerializer; - private final ExternalStorageMonitor externalStorageMonitor; - private final Downloader downloader; - private final ShufflePlayBuffer shufflePlayBuffer; - private final LocalMediaPlayer localMediaPlayer; - - public MediaPlayerControllerImpl(Context context, DownloadQueueSerializer downloadQueueSerializer, - ExternalStorageMonitor externalStorageMonitor, Downloader downloader, - ShufflePlayBuffer shufflePlayBuffer, LocalMediaPlayer localMediaPlayer) - { - this.context = context; - this.downloadQueueSerializer = downloadQueueSerializer; - this.externalStorageMonitor = externalStorageMonitor; - this.downloader = downloader; - this.shufflePlayBuffer = shufflePlayBuffer; - this.localMediaPlayer = localMediaPlayer; - - Timber.i("MediaPlayerControllerImpl constructed"); - } - - public void onCreate() - { - if (created) return; - this.externalStorageMonitor.onCreate(this::reset); - - setJukeboxEnabled(activeServerProvider.getValue().getActiveServer().getJukeboxByDefault()); - created = true; - - Timber.i("MediaPlayerControllerImpl created"); - } - - public void onDestroy() - { - if (!created) return; - externalStorageMonitor.onDestroy(); - context.stopService(new Intent(context, MediaPlayerService.class)); - downloader.onDestroy(); - created = false; - - Timber.i("MediaPlayerControllerImpl destroyed"); - } - - @Override - public synchronized void restore(List songs, final int currentPlayingIndex, final int currentPlayingPosition, final boolean autoPlay, boolean newPlaylist) - { - download(songs, false, false, false, false, newPlaylist); - - if (currentPlayingIndex != -1) - { - MediaPlayerService.executeOnStartedMediaPlayerService(context, (mediaPlayerService) -> - { - mediaPlayerService.play(currentPlayingIndex, autoPlayStart); - - if (localMediaPlayer.currentPlaying != null) - { - if (autoPlay && jukeboxMediaPlayer.getValue().isEnabled()) - { - jukeboxMediaPlayer.getValue().skip(downloader.getCurrentPlayingIndex(), currentPlayingPosition / 1000); - } - else - { - if (localMediaPlayer.currentPlaying.isCompleteFileAvailable()) - { - localMediaPlayer.play(localMediaPlayer.currentPlaying, currentPlayingPosition, autoPlay); - } - } - } - autoPlayStart = false; - return null; - } - ); - } - } - - public synchronized void preload() - { - MediaPlayerService.getInstance(context); - } - - @Override - public synchronized void play(final int index) - { - MediaPlayerService.executeOnStartedMediaPlayerService(context, (mediaPlayerService) -> { - mediaPlayerService.play(index, true); - return null; - } - ); - } - - public synchronized void play() - { - MediaPlayerService.executeOnStartedMediaPlayerService(context, (mediaPlayerService) -> { - - mediaPlayerService.play(); - return null; - } - ); - } - - public synchronized void resumeOrPlay() - { - MediaPlayerService.executeOnStartedMediaPlayerService(context, (mediaPlayerService) -> { - mediaPlayerService.resumeOrPlay(); - return null; - } - ); - } - - - @Override - public synchronized void togglePlayPause() - { - if (localMediaPlayer.playerState == PlayerState.IDLE) autoPlayStart = true; - MediaPlayerService.executeOnStartedMediaPlayerService(context, (mediaPlayerService) -> { - mediaPlayerService.togglePlayPause(); - return null; - } - ); - } - - - @Override - public synchronized void start() - { - MediaPlayerService.executeOnStartedMediaPlayerService(context, (mediaPlayerService) -> { - mediaPlayerService.start(); - return null; - } - ); - } - - @Override - public synchronized void seekTo(final int position) - { - MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); - if (mediaPlayerService != null) mediaPlayerService.seekTo(position); - } - - @Override - public synchronized void pause() - { - MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); - if (mediaPlayerService != null) mediaPlayerService.pause(); - } - - @Override - public synchronized void stop() - { - MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); - if (mediaPlayerService != null) mediaPlayerService.stop(); - } - - @Override - public synchronized void download(List songs, boolean save, boolean autoPlay, boolean playNext, boolean shuffle, boolean newPlaylist) - { - downloader.download(songs, save, autoPlay, playNext, newPlaylist); - jukeboxMediaPlayer.getValue().updatePlaylist(); - - if (shuffle) shuffle(); - - if (!playNext && !autoPlay && (downloader.downloadList.size() - 1) == downloader.getCurrentPlayingIndex()) - { - MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); - if (mediaPlayerService != null) mediaPlayerService.setNextPlaying(); - } - - if (autoPlay) - { - play(0); - } - else - { - if (localMediaPlayer.currentPlaying == null && downloader.downloadList.size() > 0) - { - localMediaPlayer.currentPlaying = downloader.downloadList.get(0); - localMediaPlayer.currentPlaying.setPlaying(true); - } - - downloader.checkDownloads(); - } - - downloadQueueSerializer.serializeDownloadQueue(downloader.downloadList, downloader.getCurrentPlayingIndex(), getPlayerPosition()); - } - - @Override - public synchronized void downloadBackground(List songs, boolean save) - { - downloader.downloadBackground(songs, save); - downloadQueueSerializer.serializeDownloadQueue(downloader.downloadList, downloader.getCurrentPlayingIndex(), getPlayerPosition()); - } - - public synchronized void setCurrentPlaying(DownloadFile currentPlaying) - { - MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); - if (mediaPlayerService != null) localMediaPlayer.setCurrentPlaying(currentPlaying); - } - - public synchronized void setCurrentPlaying(int index) - { - MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); - if (mediaPlayerService != null) mediaPlayerService.setCurrentPlaying(index); - } - - public synchronized void setPlayerState(PlayerState state) - { - MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); - if (mediaPlayerService != null) localMediaPlayer.setPlayerState(state); - } - - @Override - public void stopJukeboxService() - { - jukeboxMediaPlayer.getValue().stopJukeboxService(); - } - - @Override - public synchronized void setShufflePlayEnabled(boolean enabled) - { - shufflePlayBuffer.isEnabled = enabled; - if (enabled) - { - clear(); - downloader.checkDownloads(); - } - } - - @Override - public boolean isShufflePlayEnabled() - { - return shufflePlayBuffer.isEnabled; - } - - @Override - public synchronized void shuffle() - { - downloader.shuffle(); - - downloadQueueSerializer.serializeDownloadQueue(downloader.downloadList, downloader.getCurrentPlayingIndex(), getPlayerPosition()); - jukeboxMediaPlayer.getValue().updatePlaylist(); - - MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); - if (mediaPlayerService != null) mediaPlayerService.setNextPlaying(); - } - - @Override - public RepeatMode getRepeatMode() - { - return Util.getRepeatMode(); - } - - @Override - public synchronized void setRepeatMode(RepeatMode repeatMode) - { - Util.setRepeatMode(repeatMode); - MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); - if (mediaPlayerService != null) mediaPlayerService.setNextPlaying(); - } - - @Override - public boolean getKeepScreenOn() - { - return keepScreenOn; - } - - @Override - public void setKeepScreenOn(boolean keepScreenOn) - { - this.keepScreenOn = keepScreenOn; - } - - @Override - public boolean getShowVisualization() - { - return showVisualization; - } - - @Override - public void setShowVisualization(boolean showVisualization) - { - this.showVisualization = showVisualization; - } - - @Override - public synchronized void clear() - { - clear(true); - } - - public synchronized void clear(boolean serialize) - { - MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); - if (mediaPlayerService != null) { - mediaPlayerService.clear(serialize); - } else { - // If no MediaPlayerService is available, just empty the playlist - downloader.clear(); - if (serialize) { - downloadQueueSerializer.serializeDownloadQueue(downloader.downloadList, - downloader.getCurrentPlayingIndex(), getPlayerPosition()); - } - } - - jukeboxMediaPlayer.getValue().updatePlaylist(); - } - - @Override - public synchronized void clearIncomplete() - { - reset(); - Iterator iterator = downloader.downloadList.iterator(); - - while (iterator.hasNext()) - { - DownloadFile downloadFile = iterator.next(); - if (!downloadFile.isCompleteFileAvailable()) - { - iterator.remove(); - } - } - - downloadQueueSerializer.serializeDownloadQueue(downloader.downloadList, downloader.getCurrentPlayingIndex(), getPlayerPosition()); - jukeboxMediaPlayer.getValue().updatePlaylist(); - } - - @Override - public synchronized void remove(DownloadFile downloadFile) - { - if (downloadFile == localMediaPlayer.currentPlaying) - { - reset(); - setCurrentPlaying(null); - } - - downloader.removeDownloadFile(downloadFile); - - downloadQueueSerializer.serializeDownloadQueue(downloader.downloadList, downloader.getCurrentPlayingIndex(), getPlayerPosition()); - jukeboxMediaPlayer.getValue().updatePlaylist(); - - if (downloadFile == localMediaPlayer.nextPlaying) - { - MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); - if (mediaPlayerService != null) mediaPlayerService.setNextPlaying(); - } - } - - @Override - public synchronized void delete(List songs) - { - for (MusicDirectory.Entry song : songs) - { - downloader.getDownloadFileForSong(song).delete(); - } - } - - @Override - public synchronized void unpin(List songs) - { - for (MusicDirectory.Entry song : songs) - { - downloader.getDownloadFileForSong(song).unpin(); - } - } - - @Override - public synchronized void previous() - { - int index = downloader.getCurrentPlayingIndex(); - if (index == -1) - { - return; - } - - // Restart song if played more than five seconds. - if (getPlayerPosition() > 5000 || index == 0) - { - play(index); - } - else - { - play(index - 1); - } - } - - @Override - public synchronized void next() - { - int index = downloader.getCurrentPlayingIndex(); - if (index != -1) - { - switch (getRepeatMode()) - { - case SINGLE: - case OFF: - if (index + 1 >= 0 && index + 1 < downloader.downloadList.size()) { - play(index + 1); - } - break; - case ALL: - play((index + 1) % downloader.downloadList.size()); - break; - default: - break; - } - } - } - - @Override - public synchronized void reset() - { - MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); - if (mediaPlayerService != null) localMediaPlayer.reset(); - } - - @Override - public synchronized int getPlayerPosition() - { - MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); - if (mediaPlayerService == null) return 0; - return mediaPlayerService.getPlayerPosition(); - } - - @Override - public synchronized int getPlayerDuration() - { - if (localMediaPlayer.currentPlaying != null) - { - Integer duration = localMediaPlayer.currentPlaying.getSong().getDuration(); - if (duration != null) - { - return duration * 1000; - } - } - - MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); - if (mediaPlayerService == null) return 0; - return mediaPlayerService.getPlayerDuration(); - } - - @Override - public PlayerState getPlayerState() { return localMediaPlayer.playerState; } - - @Override - public void setSuggestedPlaylistName(String name) - { - this.suggestedPlaylistName = name; - } - - @Override - public String getSuggestedPlaylistName() - { - return suggestedPlaylistName; - } - - @Override - public boolean isJukeboxEnabled() - { - return jukeboxMediaPlayer.getValue().isEnabled(); - } - - @Override - public boolean isJukeboxAvailable() - { - try - { - String username = activeServerProvider.getValue().getActiveServer().getUserName(); - UserInfo user = MusicServiceFactory.getMusicService().getUser(username); - return user.getJukeboxRole(); - } - catch (Exception e) - { - Timber.w(e, "Error getting user information"); - } - - return false; - } - - @Override - public void setJukeboxEnabled(boolean jukeboxEnabled) - { - jukeboxMediaPlayer.getValue().setEnabled(jukeboxEnabled); - setPlayerState(PlayerState.IDLE); - - if (jukeboxEnabled) - { - jukeboxMediaPlayer.getValue().startJukeboxService(); - - reset(); - - // Cancel current download, if necessary. - if (downloader.currentDownloading != null) - { - downloader.currentDownloading.cancelDownload(); - } - } - else - { - jukeboxMediaPlayer.getValue().stopJukeboxService(); - } - } - - @Override - public void adjustJukeboxVolume(boolean up) - { - jukeboxMediaPlayer.getValue().adjustVolume(up); - } - - @Override - public void setVolume(float volume) - { - MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); - if (mediaPlayerService != null) localMediaPlayer.setVolume(volume); - } - - @Override - public void updateNotification() - { - MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); - if (mediaPlayerService != null) mediaPlayerService.updateNotification(localMediaPlayer.playerState, localMediaPlayer.currentPlaying); - } - - public void toggleSongStarred() { - if (localMediaPlayer.currentPlaying == null) - return; - - final Entry song = localMediaPlayer.currentPlaying.getSong(); - - // Trigger an update - localMediaPlayer.setCurrentPlaying(localMediaPlayer.currentPlaying); - - song.setStarred(!song.getStarred()); - } - - public void setSongRating(final int rating) - { - if (!KoinJavaComponent.get(FeatureStorage.class).isFeatureEnabled(Feature.FIVE_STAR_RATING)) - return; - - if (localMediaPlayer.currentPlaying == null) - return; - - final Entry song = localMediaPlayer.currentPlaying.getSong(); - song.setUserRating(rating); - - new Thread(() -> { - try - { - MusicServiceFactory.getMusicService().setRating(song.getId(), rating); - } - catch (Exception e) - { - Timber.e(e); - } - }).start(); - - updateNotification(); - } - - @Override - public DownloadFile getCurrentPlaying() { - return localMediaPlayer.currentPlaying; - } - - @Override - public int getPlaylistSize() { - return downloader.downloadList.size(); - } - - @Override - public int getCurrentPlayingNumberOnPlaylist() { - return downloader.getCurrentPlayingIndex(); - } - - @Override - public DownloadFile getCurrentDownloading() { - return downloader.currentDownloading; - } - - @Override - public List getPlayList() { - return downloader.downloadList; - } - - @Override - public long getPlayListUpdateRevision() { - return downloader.getDownloadListUpdateRevision(); - } - - @Override - public long getPlayListDuration() { - return downloader.getDownloadListDuration(); - } - - @Override - public DownloadFile getDownloadFileForSong(Entry song) { - return downloader.getDownloadFileForSong(song); - } -} \ No newline at end of file diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/service/MediaPlayerLifecycleSupport.java b/ultrasonic/src/main/java/org/moire/ultrasonic/service/MediaPlayerLifecycleSupport.java index 10abc831..5357b0dd 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/service/MediaPlayerLifecycleSupport.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/service/MediaPlayerLifecycleSupport.java @@ -44,14 +44,14 @@ public class MediaPlayerLifecycleSupport { private boolean created = false; private DownloadQueueSerializer downloadQueueSerializer; // From DI - private final MediaPlayerControllerImpl mediaPlayerController; // From DI + private final MediaPlayerController mediaPlayerController; // From DI private final Downloader downloader; // From DI private Context context; private BroadcastReceiver headsetEventReceiver; public MediaPlayerLifecycleSupport(Context context, DownloadQueueSerializer downloadQueueSerializer, - final MediaPlayerControllerImpl mediaPlayerController, final Downloader downloader) + final MediaPlayerController mediaPlayerController, final Downloader downloader) { this.downloadQueueSerializer = downloadQueueSerializer; this.mediaPlayerController = mediaPlayerController; diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/MediaPlayerModule.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/MediaPlayerModule.kt index 33cddf3e..1811a053 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/MediaPlayerModule.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/MediaPlayerModule.kt @@ -9,7 +9,6 @@ import org.moire.ultrasonic.service.ExternalStorageMonitor import org.moire.ultrasonic.service.JukeboxMediaPlayer import org.moire.ultrasonic.service.LocalMediaPlayer import org.moire.ultrasonic.service.MediaPlayerController -import org.moire.ultrasonic.service.MediaPlayerControllerImpl import org.moire.ultrasonic.service.MediaPlayerLifecycleSupport import org.moire.ultrasonic.util.ShufflePlayBuffer @@ -17,9 +16,7 @@ import org.moire.ultrasonic.util.ShufflePlayBuffer * This Koin module contains the registration of classes related to the media player */ val mediaPlayerModule = module { - single { - MediaPlayerControllerImpl(androidContext(), get(), get(), get(), get(), get()) - } + single { MediaPlayerController(androidContext(), get(), get(), get(), get(), get()) } single { JukeboxMediaPlayer(androidContext(), get()) } single { MediaPlayerLifecycleSupport(androidContext(), get(), get(), get()) } @@ -31,5 +28,5 @@ val mediaPlayerModule = module { single { AudioFocusHandler(get()) } // TODO Ideally this can be cleaned up when all circular references are removed. - single { MediaPlayerControllerImpl(androidContext(), get(), get(), get(), get(), get()) } + single { MediaPlayerController(androidContext(), get(), get(), get(), get(), get()) } }