1. /*
  2. * Copyright 2000-2002,2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant.taskdefs.optional.sound;
  18. // ant includes
  19. import java.io.File;
  20. import java.io.IOException;
  21. import javax.sound.sampled.AudioFormat;
  22. import javax.sound.sampled.AudioInputStream;
  23. import javax.sound.sampled.AudioSystem;
  24. import javax.sound.sampled.Clip;
  25. import javax.sound.sampled.DataLine;
  26. import javax.sound.sampled.Line;
  27. import javax.sound.sampled.LineEvent;
  28. import javax.sound.sampled.LineListener;
  29. import javax.sound.sampled.LineUnavailableException;
  30. import javax.sound.sampled.UnsupportedAudioFileException;
  31. import org.apache.tools.ant.BuildEvent;
  32. import org.apache.tools.ant.BuildListener;
  33. import org.apache.tools.ant.Project;
  34. /**
  35. * This class is designed to be used by any AntTask that requires audio output.
  36. *
  37. * It implements the BuildListener interface to listen for BuildEvents and could
  38. * be easily extended to provide audio output upon any specific build events occuring.
  39. *
  40. * I have only tested this with .WAV and .AIFF sound file formats. Both seem to work fine.
  41. *
  42. * @version $Revision: 1.13.2.5 $, $Date: 2004/03/09 17:01:53 $
  43. */
  44. public class AntSoundPlayer implements LineListener, BuildListener {
  45. private File fileSuccess = null;
  46. private int loopsSuccess = 0;
  47. private Long durationSuccess = null;
  48. private File fileFail = null;
  49. private int loopsFail = 0;
  50. private Long durationFail = null;
  51. public AntSoundPlayer() {
  52. }
  53. /**
  54. * @param file the location of the audio file to be played when the
  55. * build is successful
  56. * @param loops the number of times the file should be played when
  57. * the build is successful
  58. * @param duration the number of milliseconds the file should be
  59. * played when the build is successful
  60. */
  61. public void addBuildSuccessfulSound(File file, int loops, Long duration) {
  62. this.fileSuccess = file;
  63. this.loopsSuccess = loops;
  64. this.durationSuccess = duration;
  65. }
  66. /**
  67. * @param fileFail the location of the audio file to be played
  68. * when the build fails
  69. * @param loopsFail the number of times the file should be played
  70. * when the build is fails
  71. * @param durationFail the number of milliseconds the file should be
  72. * played when the build fails
  73. */
  74. public void addBuildFailedSound(File fileFail, int loopsFail, Long durationFail) {
  75. this.fileFail = fileFail;
  76. this.loopsFail = loopsFail;
  77. this.durationFail = durationFail;
  78. }
  79. /**
  80. * Plays the file for duration milliseconds or loops.
  81. */
  82. private void play(Project project, File file, int loops, Long duration) {
  83. Clip audioClip = null;
  84. AudioInputStream audioInputStream = null;
  85. try {
  86. audioInputStream = AudioSystem.getAudioInputStream(file);
  87. } catch (UnsupportedAudioFileException uafe) {
  88. project.log("Audio format is not yet supported: "
  89. + uafe.getMessage());
  90. } catch (IOException ioe) {
  91. ioe.printStackTrace();
  92. }
  93. if (audioInputStream != null) {
  94. AudioFormat format = audioInputStream.getFormat();
  95. DataLine.Info info = new DataLine.Info(Clip.class, format,
  96. AudioSystem.NOT_SPECIFIED);
  97. try {
  98. audioClip = (Clip) AudioSystem.getLine(info);
  99. audioClip.addLineListener(this);
  100. audioClip.open(audioInputStream);
  101. } catch (LineUnavailableException e) {
  102. project.log("The sound device is currently unavailable");
  103. return;
  104. } catch (IOException e) {
  105. e.printStackTrace();
  106. }
  107. if (duration != null) {
  108. playClip(audioClip, duration.longValue());
  109. } else {
  110. playClip(audioClip, loops);
  111. }
  112. audioClip.drain();
  113. audioClip.close();
  114. } else {
  115. project.log("Can't get data from file " + file.getName());
  116. }
  117. }
  118. private void playClip(Clip clip, int loops) {
  119. clip.loop(loops);
  120. while (clip.isRunning()) {
  121. }
  122. }
  123. private void playClip(Clip clip, long duration) {
  124. clip.loop(Clip.LOOP_CONTINUOUSLY);
  125. try {
  126. Thread.sleep(duration);
  127. } catch (InterruptedException e) {
  128. }
  129. }
  130. /**
  131. * This is implemented to listen for any line events and closes the
  132. * clip if required.
  133. */
  134. public void update(LineEvent event) {
  135. if (event.getType().equals(LineEvent.Type.STOP)) {
  136. Line line = event.getLine();
  137. line.close();
  138. } else if (event.getType().equals(LineEvent.Type.CLOSE)) {
  139. /*
  140. * There is a bug in JavaSound 0.90 (jdk1.3beta).
  141. * It prevents correct termination of the VM.
  142. * So we have to exit ourselves.
  143. */
  144. //System.exit(0);
  145. }
  146. }
  147. /**
  148. * Fired before any targets are started.
  149. */
  150. public void buildStarted(BuildEvent event) {
  151. }
  152. /**
  153. * Fired after the last target has finished. This event
  154. * will still be thrown if an error occurred during the build.
  155. *
  156. * @see BuildEvent#getException()
  157. */
  158. public void buildFinished(BuildEvent event) {
  159. if (event.getException() == null && fileSuccess != null) {
  160. // build successfull!
  161. play(event.getProject(), fileSuccess, loopsSuccess, durationSuccess);
  162. } else if (event.getException() != null && fileFail != null) {
  163. play(event.getProject(), fileFail, loopsFail, durationFail);
  164. }
  165. }
  166. /**
  167. * Fired when a target is started.
  168. *
  169. * @see BuildEvent#getTarget()
  170. */
  171. public void targetStarted(BuildEvent event) {
  172. }
  173. /**
  174. * Fired when a target has finished. This event will
  175. * still be thrown if an error occurred during the build.
  176. *
  177. * @see BuildEvent#getException()
  178. */
  179. public void targetFinished(BuildEvent event) {
  180. }
  181. /**
  182. * Fired when a task is started.
  183. *
  184. * @see BuildEvent#getTask()
  185. */
  186. public void taskStarted(BuildEvent event) {
  187. }
  188. /**
  189. * Fired when a task has finished. This event will still
  190. * be throw if an error occurred during the build.
  191. *
  192. * @see BuildEvent#getException()
  193. */
  194. public void taskFinished(BuildEvent event) {
  195. }
  196. /**
  197. * Fired whenever a message is logged.
  198. *
  199. * @see BuildEvent#getMessage()
  200. * @see BuildEvent#getPriority()
  201. */
  202. public void messageLogged(BuildEvent event) {
  203. }
  204. }