/**
* MediaFrame is an Open Source streaming media platform in Java
* which provides a fast, easy to implement and extremely small applet
* that enables to view your audio/video content without having
* to rely on external player applications or bulky plug-ins.
*
* Copyright (C) 2004/5 MediaFrame (http://www.mediaframe.org).
*
* This program 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 2
* of the License, or (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
package mediaframe.mpeg4.audio;
import java.io.InputStream;
import org.ripple.power.config.LSystem;
/**
* The <code>AudioPlayer</code> is an abstract parent class for audio players
* which able to play the audio binary stream. It contains the methods that
* allows to control the playback of the audio stream:
* <ul>
* <li>play, stop, pause and continue the playback;
* <li>set mute state and the volume of the audio stream).
* </ul>
* Also it contains the method that allows to check if the sound is supported by
* the current system.
*/
public abstract class AudioPlayer {
/** The main working thread of the <code>AudioPlayer</code>. */
protected volatile Thread audioPlayerThread = null;
/** The output audio device. */
protected AudioDevice audioDevice;
/**
* <tt>True</tt>, if the <code>AudioPlayer</code> is ready to play the audio
* stream.
*/
protected boolean readyToPlay = false;
/**
* <tt>True</tt>, if the <code>AudioPlayer</code> is decoding the audio
* stream.
*/
protected boolean decoding = true;
/**
* Constructs an <code>AudioPlayer</code> object.
*
* @throws Exception
* raises if there is an error occurs (in most cases if no
* output audio devices have been found).
*/
public AudioPlayer() throws Exception {
super();
readyToPlay = false;
if (audioDevice == null) {
audioDevice = detectSoundDevice();
}
if (audioDevice == null) {
throw new Exception("The Audio Device does not found!");
}
}
/**
* Detects support of AAC or MP3 audio streams and returns the proper audio
* player.
*
* @param is
* the MP3 or AAC audio input stream.
* @param audioHeaderSize
* the size of the audio header (normally zero for MP3 streams).
* @return the detected audio player or null if there are no available audio
* players have been found.
*/
public static AudioPlayer createAudioPlayer(InputStream is,
int audioHeaderSize) throws Exception {
// true, if the player should try AAC support first
boolean try_AAC_first = audioHeaderSize > 0;
try {
try {
Class.forName(try_AAC_first ? "mediaframe.mpeg4.audio.AAC.AACDecoder"
: "javazoom.jlme.decoder.Decoder");
if (try_AAC_first) {
return new AACAudioPlayer(is, audioHeaderSize);
} else {
return new MP3AudioPlayer(is);
}
} catch (Exception ex) {
ex.printStackTrace();
}
} catch (Exception ex) {
try {
if (try_AAC_first) {
return new MP3AudioPlayer(is);
} else {
return new AACAudioPlayer(is, 0);
}
} catch (Exception ex2) {
ex.printStackTrace();
}
}
return null;
}
/**
* Detects and returns the available audio device. On the first step detects
* support of the Java2 Sound API and then, if the first step fails, tries
* to use the Java1 compatible audio device.
*
* @return the detected audio device or null if there are no available audio
* devices have been found.
*/
protected static AudioDevice detectSoundDevice() {
try {
try {
Class.forName("javax.sound.sampled.SourceDataLine");
return new Java2AudioDevice();
} catch (Exception ex) {
return null;
}
} catch (Exception ex) {
try {
return new Java1AudioDevice();
} catch (Exception ex2) {
ex.printStackTrace();
}
}
return null;
}
/**
* Stops the playback of the audio stream.
*/
public synchronized void stop() {
if (audioPlayerThread != null) {
Thread workThread = audioPlayerThread;
audioPlayerThread = null;
workThread.interrupt();
try {
workThread.join(2000);
} catch (Exception ex) {
}
}
if (audioDevice != null) {
audioDevice.close();
}
}
/**
* Starts to play the audio stream.
*
* @throws InterruptedException
* raises if the current thread has been interrupted.
*/
public void play() throws InterruptedException {
if (audioDevice != null) {
synchronized (this) {
if (!readyToPlay) {
// waits up to 5 seconds for the audio process
wait(5000);
// adds small pause for the audio channel
Thread.sleep(LSystem.SECOND);
}
}
audioDevice.play();
}
}
/**
* Pauses the playback of the audio stream.
*/
public void pause() {
if (audioDevice != null) {
audioDevice.pause();
}
}
/**
* Sets the mute state of the audio player.
*
* @param mute
* the mute state to set.
*/
public void setMute(boolean mute) {
if (audioDevice != null) {
audioDevice.setMute(mute);
}
}
/**
* Sets the volume of the audio stream.
*
* @param volume
* the volume to set.
*/
public void setVolume(int volume) {
if (audioDevice != null) {
audioDevice.setVolume(volume);
}
}
/**
* Returns <tt>true</tt>, if the player has been detected the audio device
* and is able to play the sound.
*/
public static boolean isSoundEnabled() {
return detectSoundDevice() != null;
}
/**
* Returns <tt>true</tt>, if the <code>AudioPlayer</code> is decoding the
* audio stream.
*/
public boolean isDecoding() {
return decoding;
}
}