]> gitweb.fperrin.net Git - GpsPrune.git/blob - src/tim/prune/function/PlayAudioFunction.java
2ac71e93b6e38bbbaab727aa1a6d7d421c4a117a
[GpsPrune.git] / src / tim / prune / function / PlayAudioFunction.java
1 package tim.prune.function;
2
3 import java.io.BufferedOutputStream;
4 import java.io.ByteArrayInputStream;
5 import java.io.File;
6 import java.io.FileOutputStream;
7 import java.io.IOException;
8 import java.lang.reflect.InvocationTargetException;
9
10 import javax.sound.sampled.AudioInputStream;
11 import javax.sound.sampled.AudioSystem;
12 import javax.sound.sampled.Clip;
13
14 import tim.prune.App;
15 import tim.prune.GenericFunction;
16 import tim.prune.data.AudioClip;
17
18 /**
19  * Class to play the current audio clip
20  */
21 public class PlayAudioFunction extends GenericFunction implements Runnable
22 {
23         /** Audio clip used for playing within java */
24         private Clip _clip = null;
25
26
27         /**
28          * Constructor
29          * @param inApp app object
30          */
31         public PlayAudioFunction(App inApp) {
32                 super(inApp);
33         }
34
35         /**
36          * @return name key
37          */
38         public String getNameKey() {
39                 return "function.playaudio";
40         }
41
42         /**
43          * Perform function
44          */
45         public void begin()
46         {
47                 // Launch new thread if clip isn't currently playing
48                 if (_clip == null) {
49                         new Thread(this).start();
50                 }
51         }
52
53         /**
54          * Play the audio in a new thread
55          */
56         public void run()
57         {
58                 AudioClip audio = _app.getTrackInfo().getCurrentAudio();
59                 File audioFile = audio.getFile();
60                 boolean played = false;
61                 if (audioFile != null && audioFile.exists() && audioFile.isFile() && audioFile.canRead())
62                 {
63                         // First choice is to play using java
64                         played = playClip(audio);
65                         // If this didn't work, then try to play the file another way
66                         if (!played) {
67                                 played = playAudioFile(audioFile);
68                         }
69                 }
70                 else if (audioFile == null && audio.getByteData() != null)
71                 {
72                         // Try to play audio clip using byte array
73                         played = playClip(audio);
74                         // If this didn't work, then need to copy the byte data to a file and play it from there
75                         if (!played)
76                         {
77                                 try
78                                 {
79                                         String suffix = getSuffix(audio.getName());
80                                         File tempFile = File.createTempFile("gpsaudio", suffix);
81                                         tempFile.deleteOnExit();
82                                         // Copy byte data to this file
83                                         BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tempFile));
84                                         bos.write(audio.getByteData(), 0, audio.getByteData().length);
85                                         bos.close();
86                                         played = playAudioFile(tempFile);
87                                 }
88                                 catch (IOException ignore) {
89                                         System.err.println("Error: " + ignore.getClass().getName() + " - " + ignore.getMessage());
90                                 }
91                         }
92                 }
93                 if (!played)
94                 {
95                         // If still not worked, show error message
96                         _app.showErrorMessage(getNameKey(), "error.playaudiofailed");
97                 }
98         }
99
100         /**
101          * Try to play the sound file using built-in java libraries
102          * @param inAudio audio clip to play
103          * @return true if play was successful
104          */
105         private boolean playClip(AudioClip inClip)
106         {
107                 boolean success = false;
108                 AudioInputStream audioInputStream = null;
109                 _clip = null;
110                 try
111                 {
112                         if (inClip.getFile() != null)
113                                 audioInputStream = AudioSystem.getAudioInputStream(inClip.getFile());
114                         else if (inClip.getByteData() != null)
115                                 audioInputStream = AudioSystem.getAudioInputStream(new ByteArrayInputStream(inClip.getByteData()));
116                         else return false;
117                         _clip = AudioSystem.getClip();
118                         _clip.open(audioInputStream);
119                         // play the clip
120                         _clip.start();
121                         _clip.drain();
122                         success = true;
123                 } catch (Exception e) {
124                         System.err.println(e.getClass().getName() + " - " + e.getMessage());
125                 } finally {
126                         // close the stream to clean up
127                         try {
128                                 _clip.close();
129                                 audioInputStream.close();
130                         } catch (Exception e) {}
131                         _clip = null;
132                 }
133                 return success;
134         }
135
136         /**
137          * Try to play the specified audio file
138          * @param inFile file to play
139          * @return true if play was successful
140          */
141         private boolean playAudioFile(File inFile)
142         {
143                 boolean played = false;
144                 // Try the Desktop library from java 6, if available
145                 if (!played)
146                 {
147                         try
148                         {
149                                 Class<?> d = Class.forName("java.awt.Desktop");
150                                 d.getDeclaredMethod("open", new Class[] {File.class}).invoke(
151                                         d.getDeclaredMethod("getDesktop").invoke(null), new Object[] {inFile});
152                                 //above code mimics: Desktop.getDesktop().open(audioFile);
153                                 played = true;
154                         }
155                         catch (InvocationTargetException e) {
156                                 System.err.println("ITE: " + e.getCause().getClass().getName() + " - " + e.getCause().getMessage());
157                                 played = false;
158                         }
159                         catch (Exception ignore) {
160                                 System.err.println(ignore.getClass().getName() + " - " + ignore.getMessage());
161                                 played = false;
162                         }
163                 }
164
165                 // If the Desktop call failed, need to try backup methods
166                 if (!played)
167                 {
168                         // If system looks like a Mac, try the open command
169                         String osName = System.getProperty("os.name").toLowerCase();
170                         boolean isMacOsx = osName.indexOf("mac os") >= 0 || osName.indexOf("darwin") >= 0;
171                         if (isMacOsx)
172                         {
173                                 String[] command = new String[] {"open", inFile.getAbsolutePath()};
174                                 try {
175                                         Runtime.getRuntime().exec(command);
176                                         played = true;
177                                 }
178                                 catch (IOException ioe) {}
179                         }
180                 }
181                 return played;
182         }
183
184         /**
185          * Try to stop a currently playing clip
186          */
187         public void stopClip()
188         {
189                 if (_clip != null && _clip.isActive()) {
190                         try {
191                                 _clip.stop();
192                                 _clip.flush();
193                         }
194                         catch (Exception e) {}
195                 }
196         }
197
198         /**
199          * @return percentage of clip currently played, or -1 if not playing
200          */
201         public int getPercentage()
202         {
203                 int percent = -1;
204                 if (_clip != null && _clip.isActive())
205                 {
206                         long clipLen = _clip.getMicrosecondLength();
207                         if (clipLen > 0) {
208                                 percent = (int) (_clip.getMicrosecondPosition() * 100.0 / clipLen);
209                         }
210                 }
211                 return percent;
212         }
213
214         /**
215          * @param inName name of audio file
216          * @return suffix (rest of name after the dot) - expect mp3, wav, ogg
217          */
218         private static final String getSuffix(String inName)
219         {
220                 if (inName == null || inName.equals("")) {return ".tmp";}
221                 final int dotPos = inName.lastIndexOf('.');
222                 if (dotPos < 0) {return inName;} // no dot found
223                 return inName.substring(dotPos);
224         }
225 }