diff options
Diffstat (limited to 'subsonic-main/src/main/java/net/sourceforge/subsonic/service/jukebox/AudioPlayer.java')
-rw-r--r-- | subsonic-main/src/main/java/net/sourceforge/subsonic/service/jukebox/AudioPlayer.java | 207 |
1 files changed, 0 insertions, 207 deletions
diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/service/jukebox/AudioPlayer.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/service/jukebox/AudioPlayer.java deleted file mode 100644 index 902387be..00000000 --- a/subsonic-main/src/main/java/net/sourceforge/subsonic/service/jukebox/AudioPlayer.java +++ /dev/null @@ -1,207 +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 <http://www.gnu.org/licenses/>. - - Copyright 2009 (C) Sindre Mehus - */ -package net.sourceforge.subsonic.service.jukebox; - -import java.io.BufferedInputStream; -import java.io.InputStream; -import java.util.concurrent.atomic.AtomicReference; - -import javax.sound.sampled.AudioFormat; -import javax.sound.sampled.AudioSystem; -import javax.sound.sampled.FloatControl; -import javax.sound.sampled.SourceDataLine; - -import org.apache.commons.io.IOUtils; - -import net.sourceforge.subsonic.Logger; -import net.sourceforge.subsonic.service.JukeboxService; - -import static net.sourceforge.subsonic.service.jukebox.AudioPlayer.State.*; - -/** - * A simple wrapper for playing sound from an input stream. - * <p/> - * Supports pause and resume, but not restarting. - * - * @author Sindre Mehus - * @version $Id$ - */ -public class AudioPlayer { - - private static final Logger LOG = Logger.getLogger(JukeboxService.class); - - private final InputStream in; - private final Listener listener; - private final SourceDataLine line; - private final AtomicReference<State> state = new AtomicReference<State>(PAUSED); - private FloatControl gainControl; - - public AudioPlayer(InputStream in, Listener listener) throws Exception { - this.in = new BufferedInputStream(in); - this.listener = listener; - - AudioFormat format = AudioSystem.getAudioFileFormat(this.in).getFormat(); - line = AudioSystem.getSourceDataLine(format); - line.open(format); - LOG.debug("Opened line " + line); - - if (line.isControlSupported(FloatControl.Type.MASTER_GAIN)) { - gainControl = (FloatControl) line.getControl(FloatControl.Type.MASTER_GAIN); - setGain(0.5f); - } - new AudioDataWriter(); - } - - /** - * Starts (or resumes) the player. This only has effect if the current state is - * {@link State#PAUSED}. - */ - public synchronized void play() { - if (state.get() == PAUSED) { - line.start(); - setState(PLAYING); - } - } - - /** - * Pauses the player. This only has effect if the current state is - * {@link State#PLAYING}. - */ - public synchronized void pause() { - if (state.get() == PLAYING) { - setState(PAUSED); - line.stop(); - line.flush(); - } - } - - /** - * Closes the player, releasing all resources. After this the player state is - * {@link State#CLOSED} (unless the current state is {@link State#EOM}). - */ - public synchronized void close() { - if (state.get() != CLOSED && state.get() != EOM) { - setState(CLOSED); - } - - try { - line.stop(); - } catch (Throwable x) { - LOG.warn("Failed to stop player: " + x, x); - } - try { - if (line.isOpen()) { - line.close(); - LOG.debug("Closed line " + line); - } - } catch (Throwable x) { - LOG.warn("Failed to close player: " + x, x); - } - IOUtils.closeQuietly(in); - } - - /** - * Returns the player state. - */ - public State getState() { - return state.get(); - } - - /** - * Sets the gain. - * - * @param gain The gain between 0.0 and 1.0. - */ - public void setGain(float gain) { - if (gainControl != null) { - - double minGainDB = gainControl.getMinimum(); - double maxGainDB = gainControl.getMaximum(); - double ampGainDB = 0.5f * maxGainDB - minGainDB; - double cste = Math.log(10.0) / 20; - double valueDB = minGainDB + (1 / cste) * Math.log(1 + (Math.exp(cste * ampGainDB) - 1) * gain); - - valueDB = Math.min(valueDB, maxGainDB); - valueDB = Math.max(valueDB, minGainDB); - - gainControl.setValue((float) valueDB); - } - } - - /** - * Returns the position in seconds. - */ - public int getPosition() { - return (int) (line.getMicrosecondPosition() / 1000000L); - } - - private void setState(State state) { - if (this.state.getAndSet(state) != state && listener != null) { - listener.stateChanged(this, state); - } - } - - private class AudioDataWriter implements Runnable { - - public AudioDataWriter() { - new Thread(this).start(); - } - - public void run() { - try { - byte[] buffer = new byte[8192]; - - while (true) { - - switch (state.get()) { - case CLOSED: - case EOM: - return; - case PAUSED: - Thread.sleep(250); - break; - case PLAYING: - int n = in.read(buffer); - if (n == -1) { - setState(EOM); - return; - } - line.write(buffer, 0, n); - break; - } - } - } catch (Throwable x) { - LOG.warn("Error when copying audio data: " + x, x); - } finally { - close(); - } - } - } - - public interface Listener { - void stateChanged(AudioPlayer player, State state); - } - - public static enum State { - PAUSED, - PLAYING, - CLOSED, - EOM - } -} |