X-Git-Url: http://gitweb.fperrin.net/?p=GpsPrune.git;a=blobdiff_plain;f=src%2Ftim%2Fprune%2Ffunction%2FPlayAudioFunction.java;fp=src%2Ftim%2Fprune%2Ffunction%2FPlayAudioFunction.java;h=2ac71e93b6e38bbbaab727aa1a6d7d421c4a117a;hp=0000000000000000000000000000000000000000;hb=ce6f2161b8596f7018d6a76bff79bc9e571f35fd;hpb=2d8cb72e84d5cc1089ce77baf1e34ea3ea2f8465 diff --git a/src/tim/prune/function/PlayAudioFunction.java b/src/tim/prune/function/PlayAudioFunction.java new file mode 100644 index 0000000..2ac71e9 --- /dev/null +++ b/src/tim/prune/function/PlayAudioFunction.java @@ -0,0 +1,225 @@ +package tim.prune.function; + +import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; + +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; + +import tim.prune.App; +import tim.prune.GenericFunction; +import tim.prune.data.AudioClip; + +/** + * Class to play the current audio clip + */ +public class PlayAudioFunction extends GenericFunction implements Runnable +{ + /** Audio clip used for playing within java */ + private Clip _clip = null; + + + /** + * Constructor + * @param inApp app object + */ + public PlayAudioFunction(App inApp) { + super(inApp); + } + + /** + * @return name key + */ + public String getNameKey() { + return "function.playaudio"; + } + + /** + * Perform function + */ + public void begin() + { + // Launch new thread if clip isn't currently playing + if (_clip == null) { + new Thread(this).start(); + } + } + + /** + * Play the audio in a new thread + */ + public void run() + { + AudioClip audio = _app.getTrackInfo().getCurrentAudio(); + File audioFile = audio.getFile(); + boolean played = false; + if (audioFile != null && audioFile.exists() && audioFile.isFile() && audioFile.canRead()) + { + // First choice is to play using java + played = playClip(audio); + // If this didn't work, then try to play the file another way + if (!played) { + played = playAudioFile(audioFile); + } + } + else if (audioFile == null && audio.getByteData() != null) + { + // Try to play audio clip using byte array + played = playClip(audio); + // If this didn't work, then need to copy the byte data to a file and play it from there + if (!played) + { + try + { + String suffix = getSuffix(audio.getName()); + File tempFile = File.createTempFile("gpsaudio", suffix); + tempFile.deleteOnExit(); + // Copy byte data to this file + BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tempFile)); + bos.write(audio.getByteData(), 0, audio.getByteData().length); + bos.close(); + played = playAudioFile(tempFile); + } + catch (IOException ignore) { + System.err.println("Error: " + ignore.getClass().getName() + " - " + ignore.getMessage()); + } + } + } + if (!played) + { + // If still not worked, show error message + _app.showErrorMessage(getNameKey(), "error.playaudiofailed"); + } + } + + /** + * Try to play the sound file using built-in java libraries + * @param inAudio audio clip to play + * @return true if play was successful + */ + private boolean playClip(AudioClip inClip) + { + boolean success = false; + AudioInputStream audioInputStream = null; + _clip = null; + try + { + if (inClip.getFile() != null) + audioInputStream = AudioSystem.getAudioInputStream(inClip.getFile()); + else if (inClip.getByteData() != null) + audioInputStream = AudioSystem.getAudioInputStream(new ByteArrayInputStream(inClip.getByteData())); + else return false; + _clip = AudioSystem.getClip(); + _clip.open(audioInputStream); + // play the clip + _clip.start(); + _clip.drain(); + success = true; + } catch (Exception e) { + System.err.println(e.getClass().getName() + " - " + e.getMessage()); + } finally { + // close the stream to clean up + try { + _clip.close(); + audioInputStream.close(); + } catch (Exception e) {} + _clip = null; + } + return success; + } + + /** + * Try to play the specified audio file + * @param inFile file to play + * @return true if play was successful + */ + private boolean playAudioFile(File inFile) + { + boolean played = false; + // Try the Desktop library from java 6, if available + if (!played) + { + try + { + Class d = Class.forName("java.awt.Desktop"); + d.getDeclaredMethod("open", new Class[] {File.class}).invoke( + d.getDeclaredMethod("getDesktop").invoke(null), new Object[] {inFile}); + //above code mimics: Desktop.getDesktop().open(audioFile); + played = true; + } + catch (InvocationTargetException e) { + System.err.println("ITE: " + e.getCause().getClass().getName() + " - " + e.getCause().getMessage()); + played = false; + } + catch (Exception ignore) { + System.err.println(ignore.getClass().getName() + " - " + ignore.getMessage()); + played = false; + } + } + + // If the Desktop call failed, need to try backup methods + if (!played) + { + // If system looks like a Mac, try the open command + String osName = System.getProperty("os.name").toLowerCase(); + boolean isMacOsx = osName.indexOf("mac os") >= 0 || osName.indexOf("darwin") >= 0; + if (isMacOsx) + { + String[] command = new String[] {"open", inFile.getAbsolutePath()}; + try { + Runtime.getRuntime().exec(command); + played = true; + } + catch (IOException ioe) {} + } + } + return played; + } + + /** + * Try to stop a currently playing clip + */ + public void stopClip() + { + if (_clip != null && _clip.isActive()) { + try { + _clip.stop(); + _clip.flush(); + } + catch (Exception e) {} + } + } + + /** + * @return percentage of clip currently played, or -1 if not playing + */ + public int getPercentage() + { + int percent = -1; + if (_clip != null && _clip.isActive()) + { + long clipLen = _clip.getMicrosecondLength(); + if (clipLen > 0) { + percent = (int) (_clip.getMicrosecondPosition() * 100.0 / clipLen); + } + } + return percent; + } + + /** + * @param inName name of audio file + * @return suffix (rest of name after the dot) - expect mp3, wav, ogg + */ + private static final String getSuffix(String inName) + { + if (inName == null || inName.equals("")) {return ".tmp";} + final int dotPos = inName.lastIndexOf('.'); + if (dotPos < 0) {return inName;} // no dot found + return inName.substring(dotPos); + } +}