001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018:
019: package org.apache.tools.ant.taskdefs.optional.sound;
020:
021: // ant includes
022: import java.io.File;
023: import java.io.IOException;
024: import javax.sound.sampled.AudioFormat;
025: import javax.sound.sampled.AudioInputStream;
026: import javax.sound.sampled.AudioSystem;
027: import javax.sound.sampled.Clip;
028: import javax.sound.sampled.DataLine;
029: import javax.sound.sampled.Line;
030: import javax.sound.sampled.LineEvent;
031: import javax.sound.sampled.LineListener;
032: import javax.sound.sampled.LineUnavailableException;
033: import javax.sound.sampled.UnsupportedAudioFileException;
034: import org.apache.tools.ant.BuildEvent;
035: import org.apache.tools.ant.BuildListener;
036: import org.apache.tools.ant.Project;
037:
038: /**
039: * This class is designed to be used by any AntTask that requires audio output.
040: *
041: * It implements the BuildListener interface to listen for BuildEvents and could
042: * be easily extended to provide audio output upon any specific build events occuring.
043: *
044: * I have only tested this with .WAV and .AIFF sound file formats. Both seem to work fine.
045: *
046: */
047:
048: public class AntSoundPlayer implements LineListener, BuildListener {
049:
050: private File fileSuccess = null;
051: private int loopsSuccess = 0;
052: private Long durationSuccess = null;
053:
054: private File fileFail = null;
055: private int loopsFail = 0;
056: private Long durationFail = null;
057:
058: /** Constructor for AntSoundPlayer. */
059: public AntSoundPlayer() {
060: }
061:
062: /**
063: * @param file the location of the audio file to be played when the
064: * build is successful
065: * @param loops the number of times the file should be played when
066: * the build is successful
067: * @param duration the number of milliseconds the file should be
068: * played when the build is successful
069: */
070: public void addBuildSuccessfulSound(File file, int loops,
071: Long duration) {
072: this .fileSuccess = file;
073: this .loopsSuccess = loops;
074: this .durationSuccess = duration;
075: }
076:
077: /**
078: * @param fileFail the location of the audio file to be played
079: * when the build fails
080: * @param loopsFail the number of times the file should be played
081: * when the build is fails
082: * @param durationFail the number of milliseconds the file should be
083: * played when the build fails
084: */
085: public void addBuildFailedSound(File fileFail, int loopsFail,
086: Long durationFail) {
087: this .fileFail = fileFail;
088: this .loopsFail = loopsFail;
089: this .durationFail = durationFail;
090: }
091:
092: /**
093: * Plays the file for duration milliseconds or loops.
094: */
095: private void play(Project project, File file, int loops,
096: Long duration) {
097:
098: Clip audioClip = null;
099:
100: AudioInputStream audioInputStream = null;
101:
102: try {
103: audioInputStream = AudioSystem.getAudioInputStream(file);
104: } catch (UnsupportedAudioFileException uafe) {
105: project.log("Audio format is not yet supported: "
106: + uafe.getMessage());
107: } catch (IOException ioe) {
108: ioe.printStackTrace();
109: }
110:
111: if (audioInputStream != null) {
112: AudioFormat format = audioInputStream.getFormat();
113: DataLine.Info info = new DataLine.Info(Clip.class, format,
114: AudioSystem.NOT_SPECIFIED);
115: try {
116: audioClip = (Clip) AudioSystem.getLine(info);
117: audioClip.addLineListener(this );
118: audioClip.open(audioInputStream);
119: } catch (LineUnavailableException e) {
120: project
121: .log("The sound device is currently unavailable");
122: return;
123: } catch (IOException e) {
124: e.printStackTrace();
125: }
126:
127: if (duration != null) {
128: playClip(audioClip, duration.longValue());
129: } else {
130: playClip(audioClip, loops);
131: }
132: audioClip.drain();
133: audioClip.close();
134: } else {
135: project.log("Can't get data from file " + file.getName());
136: }
137: }
138:
139: private void playClip(Clip clip, int loops) {
140:
141: clip.loop(loops);
142: while (clip.isRunning()) {
143: // Empty block
144: }
145: }
146:
147: private void playClip(Clip clip, long duration) {
148: clip.loop(Clip.LOOP_CONTINUOUSLY);
149: try {
150: Thread.sleep(duration);
151: } catch (InterruptedException e) {
152: // Ignore Exception
153: }
154: }
155:
156: /**
157: * This is implemented to listen for any line events and closes the
158: * clip if required.
159: * @param event the line event to follow
160: */
161: public void update(LineEvent event) {
162: if (event.getType().equals(LineEvent.Type.STOP)) {
163: Line line = event.getLine();
164: line.close();
165: } else if (event.getType().equals(LineEvent.Type.CLOSE)) {
166: /*
167: * There is a bug in JavaSound 0.90 (jdk1.3beta).
168: * It prevents correct termination of the VM.
169: * So we have to exit ourselves.
170: */
171: //System.exit(0);
172: }
173: }
174:
175: /**
176: * Fired before any targets are started.
177: * @param event ignored
178: */
179: public void buildStarted(BuildEvent event) {
180: }
181:
182: /**
183: * Fired after the last target has finished. This event
184: * will still be thrown if an error occurred during the build.
185: * @param event the build finished event.
186: * @see BuildEvent#getException()
187: */
188: public void buildFinished(BuildEvent event) {
189: if (event.getException() == null && fileSuccess != null) {
190: // build successfull!
191: play(event.getProject(), fileSuccess, loopsSuccess,
192: durationSuccess);
193: } else if (event.getException() != null && fileFail != null) {
194: play(event.getProject(), fileFail, loopsFail, durationFail);
195: }
196: }
197:
198: /**
199: * Fired when a target is started.
200: * @param event ignored.
201: * @see BuildEvent#getTarget()
202: */
203: public void targetStarted(BuildEvent event) {
204: }
205:
206: /**
207: * Fired when a target has finished. This event will
208: * still be thrown if an error occurred during the build.
209: * @param event ignored.
210: * @see BuildEvent#getException()
211: */
212: public void targetFinished(BuildEvent event) {
213: }
214:
215: /**
216: * Fired when a task is started.
217: * @param event ignored.
218: * @see BuildEvent#getTask()
219: */
220: public void taskStarted(BuildEvent event) {
221: }
222:
223: /**
224: * Fired when a task has finished. This event will still
225: * be throw if an error occurred during the build.
226: * @param event ignored.
227: * @see BuildEvent#getException()
228: */
229: public void taskFinished(BuildEvent event) {
230: }
231:
232: /**
233: * Fired whenever a message is logged.
234: * @param event the build event
235: * @see BuildEvent#getMessage()
236: * @see BuildEvent#getPriority()
237: */
238: public void messageLogged(BuildEvent event) {
239: }
240: }
|