Warning: Can't use blame annotator:
svn blame failed on trunk/src/tmcsim/cadsimulator/SoundPlayer.java: ("Can't find a temporary directory: Internal error", 20014)

source: tmcsimulator/trunk/src/tmcsim/cadsimulator/SoundPlayer.java @ 16

Revision 16, 8.1 KB checked in by jdalbey, 10 years ago (diff)

Added SoundPlayerTest?, fixed defect in SoundPlayer?, update 18701.mp3 to a version that works with SoundPlayer?. Change .wav to .mp3 in full_script.

RevLine 
1package tmcsim.cadsimulator;
2
3import java.io.File;
4import java.io.FileInputStream;
5import java.util.Timer;
6import java.util.TimerTask;
7import java.util.Vector;
8import java.util.logging.Level;
9import java.util.logging.Logger;
10
11import sun.audio.AudioPlayer;
12import sun.audio.AudioStream;
13import tmcsim.client.cadclientgui.data.IncidentEvent;
14
15/**
16 * SoundPlayer is used to play audio files associated with IncidentEvents that
17 * occur during a simulation.  When the SoundPlayer has been enabled audio
18 * clips are enqueued by calling the enqueueClip() method.  The audio files
19 * are played in order of receipt and when finished, the IncidentEvent is
20 * notified.  Audio playing may be disabled or enabled through the
21 * setAudioEnabled() method.  Disabling audio will cause a currently
22 * playing audio clip to stop and be requeued at the front of the queue. 
23 * Re-enabling the audio will then continue playing all queued clips.  The
24 * deQueueAll() method is used to clear the list of audio clips that have
25 * been queued.
26 *
27 * @author Matthew Cechini (mcechini@calpoly.edu)
28 * @version $Date: 2006/06/06 20:46:41 $ $Revision: 1.3 $
29 */
30public class SoundPlayer extends Thread {
31   
32    /** Error Logger. */
33    private Logger soundLogger = Logger.getLogger("tmcsim.cadsimulator");
34                               
35    /** The base location that wav files are referenced from */             
36    private String baseAudioDir = "";
37                               
38    /** The private vector of audioClips used during a simulation */
39    private Vector<AudioClipInfo> enqueuedClips = null;
40   
41    /** The audio clip that is currently being played by the AudioPlayer. */
42    private AudioClipInfo currentClip = null;
43   
44    /** Audio stream for playing audio files. */
45    private AudioStream audioStream = null;
46   
47    /**
48     * Flag to designate when an audio file is playing. This prevents
49     * multiple audio files from being played simultaneously.
50     * Flag is initialized to false.
51     */
52    private boolean audioPlaying = false;   
53   
54    /** Flag to designate whether audio playing is enabled.  If audio is disabled,
55     *  then enquque events will be ignored.  Flag is initialized to false.
56     */
57    private boolean audioEnabled = false;
58   
59    /** Timer used to pause audio player during an audio file. */
60    private Timer timer = null;
61   
62    /** Inner class used to contain the audio file's name and duration. */
63    private class AudioClipInfo {
64        String fileName;
65        int duration;
66        IncidentEvent theEvent;
67       
68        AudioClipInfo(IncidentEvent ie) {
69            fileName = ie.waveFile;
70            duration = ie.waveLength;   
71            theEvent = ie;
72        }       
73               
74        AudioClipInfo(String name, int dur) {
75            fileName = name;
76            duration = dur; 
77            theEvent = null;
78        }   
79       
80        public void wavePlayed() {
81            if(theEvent != null)
82                theEvent.wavePlayed();
83        }   
84    }
85 
86    /**
87     * Constructor.  Establish the base file path for wav file referencing.
88     *
89     * @param wavFilePath Pathname for where the simulation wav files will be referenced.
90     */
91    public SoundPlayer(String baseFilePath) {
92       
93        baseAudioDir  = baseFilePath;
94        audioPlaying  = false;
95        audioEnabled  = true;
96        timer         = new Timer();                       
97        enqueuedClips = new Vector<AudioClipInfo>();
98    }
99
100    /**
101     * Add a audioClipInfo object to the audioClips Vector.  The enqueued audio file will play
102     * when all previously enqueued audio files have been played.  If audio is not enabled, the
103     * clip will not be queued, and the incident event will be notified that the audio clip
104     * has finished playing to allow the simulation to continue.
105     *
106     * @param ie The Incident Event to enqueue to the current list of events.
107     */
108    public void enqueueClip (IncidentEvent ie) {
109
110        if(audioEnabled) {
111            synchronized(enqueuedClips)  {
112                enqueuedClips.add(new AudioClipInfo(ie));
113            }
114        }
115        else {
116            ie.wavePlayed();
117        }
118    } 
119   
120    /**
121     * Method called when user presses reset in simulation.  All queued events need
122     * to be deQueued.
123     */
124    public void deQueueAll() {
125        synchronized(enqueuedClips) {
126            enqueuedClips.clear();
127        }       
128    } 
129   
130    /**
131     * Get the current audio enabled status.
132     *
133     * @return True if enabled, false if disabled.
134     */
135    public boolean getAudioEnabled() {
136        return audioEnabled;
137    }   
138   
139    /**
140     * Set the current audio enabled status.  A false value will cause all
141     * enqueue events to be ignored.  A currently playing audio file will be
142     * stopped and requeued.  All other queued events will remain in the queue.
143     *
144     * @param enable True if enabling, false if disabling.
145     */
146    public void setAudioEnabled(boolean enable) {
147       
148        if(!enable) {           
149            timer.cancel();
150            AudioPlayer.player.stop(audioStream);
151           
152            if(currentClip != null) {
153                enqueuedClips.add(0, currentClip);
154            }           
155           
156            audioPlaying = false;
157        }
158       
159        audioEnabled = enable;
160    }
161   
162       
163    /**
164     * Method declaration for the Thread.run() method.  While this thread is not
165     * interrupted, check if there are enqueued audio files.  If so, remove the
166     * first one(FIFO) create an AudioClip object, and play the audio file.
167     * A timer tis then started for the duration of the audio file.  When the
168     * timer expires the audioPlaying flag is reset to false and the corresponding
169     * incident event is notified of the audio file's completion.
170     */
171    public void run() {
172        AudioClipInfo theClip = null;
173       
174        while(!isInterrupted()) {
175           
176            synchronized(enqueuedClips) {
177                if(enqueuedClips.size() > 0 && !audioPlaying && audioEnabled)
178                    theClip = enqueuedClips.remove(0);                 
179            }
180               
181            //if nothing to play, wait a second
182            if(theClip == null) {
183                try { Thread.sleep(1000);} catch (Exception e) {}
184            }
185            else {
186                       
187                try{
188                   
189                    if(theClip.duration > 0) {             
190                       
191                        File audioFile = new File(baseAudioDir + theClip.fileName);
192                       
193                        if(audioFile.exists()) {
194                            audioStream = new AudioStream (new FileInputStream(audioFile));     
195                            AudioPlayer.player.start(audioStream); 
196                        }
197                        else {
198                            throw new Exception();
199                        } 
200                    }
201                   
202                    currentClip  = theClip;                                             
203                    audioPlaying = true;
204                   
205                    timer = new Timer();
206                    timer.schedule(new TimerTask () {
207                        public void run() {
208                            clipPlayed();
209                            audioPlaying = false;                       
210                        }
211                    }, theClip.duration * 1000);
212                   
213                    theClip = null;                     
214                } 
215                catch (Exception e) {
216                    soundLogger.logp(Level.WARNING, "SoundPlayer", "run", 
217                            "Unable to play audio file: " + baseAudioDir + theClip.fileName, e);
218   
219                    theClip.theEvent.wavePlayed();
220                    theClip = null;
221                    timer.cancel();
222                }   
223            }                               
224        }                       
225    }
226   
227       
228    /**
229     * Called when audio file finishes playing.  Notifies the corresponding
230     * Incident Event that its audio file has finished playing.
231     */
232    private void clipPlayed() {
233        currentClip.wavePlayed();
234    } 
235}
Note: See TracBrowser for help on using the repository browser.