]> gitweb.fperrin.net Git - GpsPrune.git/blob - src/tim/prune/function/PlayAudioFunction.java
Version 20.4, May 2021
[GpsPrune.git] / src / tim / prune / function / PlayAudioFunction.java
1 package tim.prune.function;
2
3 import java.awt.Desktop;
4 import java.io.BufferedOutputStream;
5 import java.io.ByteArrayInputStream;
6 import java.io.File;
7 import java.io.FileOutputStream;
8 import java.io.IOException;
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                                 Desktop.getDesktop().open(inFile);
150                                 played = true;
151                         }
152                         catch (IOException ignore) {
153                                 System.err.println(ignore.getClass().getName() + " - " + ignore.getMessage());
154                                 played = false;
155                         }
156                 }
157
158                 // If the Desktop call failed, need to try backup methods
159                 if (!played)
160                 {
161                         // If system looks like a Mac, try the open command
162                         String osName = System.getProperty("os.name").toLowerCase();
163                         boolean isMacOsx = osName.indexOf("mac os") >= 0 || osName.indexOf("darwin") >= 0;
164                         if (isMacOsx)
165                         {
166                                 String[] command = new String[] {"open", inFile.getAbsolutePath()};
167                                 try {
168                                         Runtime.getRuntime().exec(command);
169                                         played = true;
170                                 }
171                                 catch (IOException ioe) {}
172                         }
173                 }
174                 return played;
175         }
176
177         /**
178          * Try to stop a currently playing clip
179          */
180         public void stopClip()
181         {
182                 if (_clip != null && _clip.isActive()) {
183                         try {
184                                 _clip.stop();
185                                 _clip.flush();
186                         }
187                         catch (Exception e) {}
188                 }
189         }
190
191         /**
192          * @return percentage of clip currently played, or -1 if not playing
193          */
194         public int getPercentage()
195         {
196                 int percent = -1;
197                 if (_clip != null && _clip.isActive())
198                 {
199                         long clipLen = _clip.getMicrosecondLength();
200                         if (clipLen > 0) {
201                                 percent = (int) (_clip.getMicrosecondPosition() * 100.0 / clipLen);
202                         }
203                 }
204                 return percent;
205         }
206
207         /**
208          * @param inName name of audio file
209          * @return suffix (rest of name after the dot) - expect mp3, wav, ogg
210          */
211         private static final String getSuffix(String inName)
212         {
213                 if (inName == null || inName.equals("")) {return ".tmp";}
214                 final int dotPos = inName.lastIndexOf('.');
215                 if (dotPos < 0) {return inName;} // no dot found
216                 return inName.substring(dotPos);
217         }
218 }