diff options
author | Scott Jackson <daneren2005@gmail.com> | 2012-07-02 21:24:02 -0700 |
---|---|---|
committer | Scott Jackson <daneren2005@gmail.com> | 2012-07-02 21:24:02 -0700 |
commit | a1a18f77a50804e0127dfa4b0f5240c49c541184 (patch) | |
tree | 19a38880afe505beddb5590379a8134d7730a277 /subsonic-main/src/main/java/net/sourceforge/subsonic/service/JukeboxService.java | |
parent | b61d787706979e7e20f4c3c4f93c1f129d92273f (diff) | |
download | dsub-a1a18f77a50804e0127dfa4b0f5240c49c541184.tar.gz dsub-a1a18f77a50804e0127dfa4b0f5240c49c541184.tar.bz2 dsub-a1a18f77a50804e0127dfa4b0f5240c49c541184.zip |
Initial Commit
Diffstat (limited to 'subsonic-main/src/main/java/net/sourceforge/subsonic/service/JukeboxService.java')
-rw-r--r-- | subsonic-main/src/main/java/net/sourceforge/subsonic/service/JukeboxService.java | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/service/JukeboxService.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/service/JukeboxService.java new file mode 100644 index 00000000..9f2eff22 --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/service/JukeboxService.java @@ -0,0 +1,206 @@ +/* + 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 <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.service; + +import net.sourceforge.subsonic.Logger; +import net.sourceforge.subsonic.domain.MediaFile; +import net.sourceforge.subsonic.domain.Player; +import net.sourceforge.subsonic.domain.PlayQueue; +import net.sourceforge.subsonic.domain.Transcoding; +import net.sourceforge.subsonic.domain.TransferStatus; +import net.sourceforge.subsonic.domain.User; +import net.sourceforge.subsonic.domain.VideoTranscodingSettings; +import net.sourceforge.subsonic.service.jukebox.AudioPlayer; +import net.sourceforge.subsonic.util.FileUtil; +import org.apache.commons.io.IOUtils; + +import java.io.InputStream; + +import static net.sourceforge.subsonic.service.jukebox.AudioPlayer.State.EOM; + +/** + * Plays music on the local audio device. + * + * @author Sindre Mehus + */ +public class JukeboxService implements AudioPlayer.Listener { + + private static final Logger LOG = Logger.getLogger(JukeboxService.class); + + private AudioPlayer audioPlayer; + private TranscodingService transcodingService; + private AudioScrobblerService audioScrobblerService; + private StatusService statusService; + private SettingsService settingsService; + private SecurityService securityService; + + private Player player; + private TransferStatus status; + private MediaFile currentPlayingFile; + private float gain = 0.5f; + private int offset; + private MediaFileService mediaFileService; + + /** + * Updates the jukebox by starting or pausing playback on the local audio device. + * + * @param player The player in question. + * @param offset Start playing after this many seconds into the track. + */ + public synchronized void updateJukebox(Player player, int offset) throws Exception { + User user = securityService.getUserByName(player.getUsername()); + if (!user.isJukeboxRole()) { + LOG.warn(user.getUsername() + " is not authorized for jukebox playback."); + return; + } + + if (player.getPlayQueue().getStatus() == PlayQueue.Status.PLAYING) { + this.player = player; + MediaFile result; + synchronized (player.getPlayQueue()) { + result = player.getPlayQueue().getCurrentFile(); + } + play(result, offset); + } else { + if (audioPlayer != null) { + audioPlayer.pause(); + } + } + } + + private synchronized void play(MediaFile file, int offset) { + InputStream in = null; + try { + + // Resume if possible. + boolean sameFile = file != null && file.equals(currentPlayingFile); + boolean paused = audioPlayer != null && audioPlayer.getState() == AudioPlayer.State.PAUSED; + if (sameFile && paused && offset == 0) { + audioPlayer.play(); + } else { + this.offset = offset; + if (audioPlayer != null) { + audioPlayer.close(); + if (currentPlayingFile != null) { + onSongEnd(currentPlayingFile); + } + } + + if (file != null) { + TranscodingService.Parameters parameters = new TranscodingService.Parameters(file, new VideoTranscodingSettings(0, 0, offset)); + String command = settingsService.getJukeboxCommand(); + parameters.setTranscoding(new Transcoding(null, null, null, null, command, null, null, false)); + in = transcodingService.getTranscodedInputStream(parameters); + audioPlayer = new AudioPlayer(in, this); + audioPlayer.setGain(gain); + audioPlayer.play(); + onSongStart(file); + } + } + + currentPlayingFile = file; + + } catch (Exception x) { + LOG.error("Error in jukebox: " + x, x); + IOUtils.closeQuietly(in); + } + } + + public synchronized void stateChanged(AudioPlayer audioPlayer, AudioPlayer.State state) { + if (state == EOM) { + player.getPlayQueue().next(); + MediaFile result; + synchronized (player.getPlayQueue()) { + result = player.getPlayQueue().getCurrentFile(); + } + play(result, 0); + } + } + + public synchronized float getGain() { + return gain; + } + + public synchronized int getPosition() { + return audioPlayer == null ? 0 : offset + audioPlayer.getPosition(); + } + + /** + * Returns the player which currently uses the jukebox. + * + * @return The player, may be {@code null}. + */ + public Player getPlayer() { + return player; + } + + private void onSongStart(MediaFile file) { + LOG.info(player.getUsername() + " starting jukebox for \"" + FileUtil.getShortPath(file.getFile()) + "\""); + status = statusService.createStreamStatus(player); + status.setFile(file.getFile()); + status.addBytesTransfered(file.getFileSize()); + mediaFileService.incrementPlayCount(file); + scrobble(file, false); + } + + private void onSongEnd(MediaFile file) { + LOG.info(player.getUsername() + " stopping jukebox for \"" + FileUtil.getShortPath(file.getFile()) + "\""); + if (status != null) { + statusService.removeStreamStatus(status); + } + scrobble(file, true); + } + + private void scrobble(MediaFile file, boolean submission) { + if (player.getClientId() == null) { // Don't scrobble REST players. + audioScrobblerService.register(file, player.getUsername(), submission); + } + } + + public synchronized void setGain(float gain) { + this.gain = gain; + if (audioPlayer != null) { + audioPlayer.setGain(gain); + } + } + + public void setTranscodingService(TranscodingService transcodingService) { + this.transcodingService = transcodingService; + } + + public void setAudioScrobblerService(AudioScrobblerService audioScrobblerService) { + this.audioScrobblerService = audioScrobblerService; + } + + public void setStatusService(StatusService statusService) { + this.statusService = statusService; + } + + public void setSettingsService(SettingsService settingsService) { + this.settingsService = settingsService; + } + + public void setSecurityService(SecurityService securityService) { + this.securityService = securityService; + } + + public void setMediaFileService(MediaFileService mediaFileService) { + this.mediaFileService = mediaFileService; + } +} |