private synchronized void cleanup() { Iterator<DownloadFile> iterator = cleanupCandidates.iterator(); while (iterator.hasNext()) { DownloadFile downloadFile = iterator.next(); if (downloadFile != currentPlaying && downloadFile != currentDownloading) { if (downloadFile.cleanup()) { iterator.remove(); } } } }
public BufferTask(DownloadFile downloadFile, int position) { this.downloadFile = downloadFile; this.position = position; partialFile = downloadFile.getPartialFile(); // Calculate roughly how many bytes BUFFER_LENGTH_SECONDS corresponds to. int bitRate = downloadFile.getBitRate(); long byteCount = Math.max(100000, bitRate * 1024 / 8 * BUFFER_LENGTH_SECONDS); // Find out how large the file should grow before resuming playback. expectedFileSize = partialFile.length() + byteCount; }
@Override public synchronized void clearIncomplete() { reset(); Iterator<DownloadFile> iterator = downloadList.iterator(); while (iterator.hasNext()) { DownloadFile downloadFile = iterator.next(); if (!downloadFile.isCompleteFileAvailable()) { iterator.remove(); } } lifecycleSupport.serializeDownloadQueue(); updateJukeboxPlaylist(); }
@Override public synchronized DownloadFile forSong(MusicDirectory.Entry song) { for (DownloadFile downloadFile : downloadList) { if (downloadFile.getSong().equals(song)) { return downloadFile; } } DownloadFile downloadFile = downloadFileCache.get(song); if (downloadFile == null) { downloadFile = new DownloadFile(this, song); downloadFileCache.put(song, downloadFile); } return downloadFile; }
@Override public synchronized void download( List<MusicDirectory.Entry> songs, boolean save, boolean autoplay, boolean playNext) { shufflePlay = false; int offset = 1; if (songs.isEmpty()) { return; } if (save) { for (MusicDirectory.Entry song : songs) { DownloadFile downloadFile = forSong(song); downloadFile.pin(); if (!downloadFile.isWorkDone() && !downloadList.contains(downloadFile)) { downloadList.add(downloadFile); } } } else if (playNext) { if (autoplay && getCurrentPlayingIndex() >= 0) { offset = 0; } for (MusicDirectory.Entry song : songs) { DownloadFile downloadFile = new DownloadFile(this, song); downloadList.add(getCurrentPlayingIndex() + offset, downloadFile); offset++; } } else { for (MusicDirectory.Entry song : songs) { DownloadFile downloadFile = new DownloadFile(this, song); downloadList.add(downloadFile); } } revision++; updateJukeboxPlaylist(); if (autoplay) { play(0); } else { if (currentPlaying == null) { currentPlaying = downloadList.get(0); } checkDownloads(); } lifecycleSupport.serializeDownloadQueue(); }
synchronized void setCurrentPlaying(DownloadFile currentPlaying) { this.currentPlaying = currentPlaying; MusicDirectory.Entry song = currentPlaying != null ? currentPlaying.getSong() : null; Util.broadcastNewTrackInfo(this, song); NotificationUtil.updateNotification(this, this, handler, song, song != null); }
public void restore( List<MusicDirectory.Entry> songs, int currentPlayingIndex, int currentPlayingPosition) { download(songs, false, false, false); if (currentPlayingIndex != -1) { play(currentPlayingIndex, false); if (currentPlaying.isCompleteFileAvailable()) { doPlay(currentPlaying, currentPlayingPosition, false); } } }
@Override public void setJukeboxEnabled(boolean jukeboxEnabled) { this.jukeboxEnabled = jukeboxEnabled; jukeboxService.setEnabled(jukeboxEnabled); if (jukeboxEnabled) { reset(); // Cancel current download, if necessary. if (currentDownloading != null) { currentDownloading.cancelDownload(); } } }
@Override public synchronized void remove(DownloadFile downloadFile) { if (downloadFile == currentDownloading) { currentDownloading.cancelDownload(); currentDownloading = null; } if (downloadFile == currentPlaying) { reset(); setCurrentPlaying(null); } downloadList.remove(downloadFile); revision++; lifecycleSupport.serializeDownloadQueue(); updateJukeboxPlaylist(); }
public synchronized void clear(boolean serialize) { reset(); downloadList.clear(); revision++; if (currentDownloading != null) { currentDownloading.cancelDownload(); currentDownloading = null; } setCurrentPlaying(null); if (serialize) { lifecycleSupport.serializeDownloadQueue(); } updateJukeboxPlaylist(); }
private boolean bufferComplete() { boolean completeFileAvailable = downloadFile.isCompleteFileAvailable(); long size = partialFile.length(); LOG.info( "Buffering " + partialFile + " (" + size + "/" + expectedFileSize + ", " + completeFileAvailable + ")"); return completeFileAvailable || size >= expectedFileSize; }
@Override public synchronized int getPlayerDuration() { if (currentPlaying != null) { Integer duration = currentPlaying.getSong().getDuration(); if (duration != null) { return duration * 1000; } } if (playerState != IDLE && playerState != DOWNLOADING && playerState != PlayerState.PREPARING) { try { return mediaPlayer.getDuration(); } catch (Exception x) { handleError(x); } } return 0; }
synchronized void setPlayerState(PlayerState playerState) { LOG.info(this.playerState.name() + " -> " + playerState.name() + " (" + currentPlaying + ")"); if (playerState == PAUSED) { lifecycleSupport.serializeDownloadQueue(); } Util.broadcastPlaybackStatusChange(this, playerState); this.playerState = playerState; if (playerState == STARTED) { scrobbler.scrobble(this, currentPlaying, false); NotificationUtil.setNotificationHiddenByUser(this, false); } else if (playerState == COMPLETED) { scrobbler.scrobble(this, currentPlaying, true); } MusicDirectory.Entry song = currentPlaying == null ? null : currentPlaying.getSong(); NotificationUtil.updateNotification(this, this, handler, song, this.playerState == STARTED); }
protected synchronized void checkDownloads() { if (!Util.isExternalStoragePresent() || !lifecycleSupport.isExternalStorageAvailable()) { return; } if (shufflePlay) { checkShufflePlay(); } if (jukeboxEnabled || !Util.isNetworkConnected(this)) { return; } if (downloadList.isEmpty()) { return; } // Need to download current playing? if (currentPlaying != null && currentPlaying != currentDownloading && !currentPlaying.isCompleteFileAvailable()) { // Cancel current download, if necessary. if (currentDownloading != null) { currentDownloading.cancelDownload(); } currentDownloading = currentPlaying; currentDownloading.download(); cleanupCandidates.add(currentDownloading); } // Find a suitable target for download. else if (currentDownloading == null || currentDownloading.isWorkDone() || currentDownloading.isFailed()) { int n = size(); if (n == 0) { return; } int preloaded = 0; int start = currentPlaying == null ? 0 : getCurrentPlayingIndex(); int i = start; do { DownloadFile downloadFile = downloadList.get(i); if (!downloadFile.isWorkDone()) { if (downloadFile.shouldSave() || preloaded < Util.getPreloadCount(this)) { currentDownloading = downloadFile; currentDownloading.download(); cleanupCandidates.add(currentDownloading); break; } } else if (currentPlaying != downloadFile) { preloaded++; } i = (i + 1) % n; } while (i != start); } // Delete obsolete .partial and .complete files. cleanup(); }
private synchronized void doPlay(final DownloadFile downloadFile, int position, boolean start) { try { final File file = downloadFile.isCompleteFileAvailable() ? downloadFile.getCompleteFile() : downloadFile.getPartialFile(); downloadFile.updateModificationDate(); mediaPlayer.setOnCompletionListener(null); mediaPlayer.reset(); setPlayerState(IDLE); mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mediaPlayer.setDataSource(file.getPath()); setPlayerState(PREPARING); mediaPlayer.prepare(); setPlayerState(PREPARED); mediaPlayer.setOnCompletionListener( new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mediaPlayer) { // Acquire a temporary wakelock, since when we return from // this callback the MediaPlayer will release its wakelock // and allow the device to go to sleep. wakeLock.acquire(60000); setPlayerState(COMPLETED); // If COMPLETED and not playing partial file, we are *really" finished // with the song and can move on to the next. if (!file.equals(downloadFile.getPartialFile())) { onSongCompleted(); return; } // If file is not completely downloaded, restart the playback from the current // position. int pos = mediaPlayer.getCurrentPosition(); synchronized (DownloadServiceImpl.this) { // Work-around for apparent bug on certain phones: If close (less than ten seconds) // to the end // of the song, skip to the next rather than restarting it. Integer duration = downloadFile.getSong().getDuration() == null ? null : downloadFile.getSong().getDuration() * 1000; if (duration != null) { if (Math.abs(duration - pos) < 10000) { LOG.info("Skipping restart from " + pos + " of " + duration); onSongCompleted(); return; } } LOG.info("Requesting restart from " + pos + " of " + duration); reset(); bufferTask = new BufferTask(downloadFile, pos); bufferTask.start(); } } }); if (position != 0) { LOG.info("Restarting player from position " + position); mediaPlayer.seekTo(position); } if (start) { mediaPlayer.start(); setPlayerState(STARTED); } else { setPlayerState(PAUSED); } lifecycleSupport.serializeDownloadQueue(); } catch (Exception x) { handleError(x); } }