1/* 2 * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24import java.io.File; 25import java.io.IOException; 26 27import javax.sound.sampled.AudioFormat; 28import javax.sound.sampled.AudioInputStream; 29import javax.sound.sampled.AudioSystem; 30import javax.sound.sampled.DataLine; 31import javax.sound.sampled.LineUnavailableException; 32import javax.sound.sampled.Mixer; 33import javax.sound.sampled.SourceDataLine; 34 35/** 36 * @test 37 * @bug 4834461 38 * @summary Applet hang when you load it during sound card is in use 39 * @run main/manual PlaySine 40 */ 41public class PlaySine { 42 43 static int sampleRate = 8000; 44 static double frequency = 2000.0; 45 static double RAD = 2.0 * Math.PI; 46 47 static byte[] audioData = new byte[sampleRate/2]; 48 static SourceDataLine source; 49 static Mixer mixer = null; 50 51 static AudioInputStream ais = null; 52 static AudioFormat audioFormat; 53 static String filename; 54 55 public static void constructAIS() { 56 try { 57 ais = AudioSystem.getAudioInputStream(new File(filename)); 58 } catch (Exception e) { 59 println("ERROR: could not open "+filename+": "+e.getMessage()); 60 } 61 } 62 63 public static void print(String s) { 64 System.out.print(s); 65 } 66 public static void println(String s) { 67 System.out.println(s); 68 } 69 70 public static void key() { 71 println(""); 72 print("Press ENTER to continue..."); 73 try { 74 System.in.read(); 75 } catch (IOException ioe) { 76 } 77 } 78 79 static int audioLen = -1; 80 static int audioOffset = -1; 81 82 public static void writeData() { 83 if (audioLen == -1) { 84 audioLen = audioData.length; 85 } 86 if (audioOffset < 0) { 87 audioOffset = audioLen; 88 } 89 try { 90 if (audioOffset >= audioLen) { 91 audioOffset = 0; 92 if (ais!=null) { 93 do { 94 audioLen = ais.read(audioData, 0, audioData.length); 95 if (audioLen < 0) { 96 constructAIS(); 97 } 98 } while (audioLen < 0); 99 } 100 } 101 int toWrite = audioLen - audioOffset; 102 int written = source.write(audioData, audioOffset, toWrite); 103 audioOffset+=written; 104 } catch (Exception e) { 105 e.printStackTrace(); 106 } 107 } 108 109 110 public static int play(boolean shouldPlay) { 111 int res = 0; 112 DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat); 113 try { 114 println("Getting line from mixer..."); 115 source = (SourceDataLine) mixer.getLine(info); 116 println("Opening line..."); 117 println(" -- if the program is hanging here, kill the process that has blocks the audio device now."); 118 source.open(audioFormat); 119 println("Starting line..."); 120 source.start(); 121 println("Writing audio data for 1 second..."); 122 long startTime = System.currentTimeMillis(); 123 while (System.currentTimeMillis() - startTime < 1000) { 124 writeData(); 125 Thread.sleep(100); 126 } 127 res = 1; 128 } catch (IllegalArgumentException iae) { 129 println("IllegalArgumentException: "+iae.getMessage()); 130 println("Sound device cannot handle this audio format."); 131 println("ERROR: Test environment not correctly set up."); 132 if (source!=null) { 133 source.close(); 134 } 135 return 3; 136 } catch (LineUnavailableException lue) { 137 println("LineUnavailableException: "+lue.getMessage()); 138 if (shouldPlay) { 139 println("ERROR: the line should be available now!."); 140 println(" Verify that you killed the other audio process."); 141 } else { 142 println("Correct behavior! the bug is fixed."); 143 } 144 res = 2; 145 } catch (Exception e) { 146 println("Unexpected Exception: "+e.toString()); 147 } 148 if (source != null) { 149 println("Draining..."); 150 try { 151 source.drain(); 152 } catch (NullPointerException npe) { 153 println("(NullPointerException: bug fixed in J2SE 1.4.2"); 154 } 155 println("Stopping..."); 156 source.stop(); 157 println("Closing..."); 158 source.close(); 159 source = null; 160 } 161 return res; 162 } 163 164 public static void main(String[] args) throws Exception { 165 println("This is an interactive test. You can run it with a filename as argument"); 166 println("It is only meant to be run on linux, with the (old) OSS kernel drivers (/dev/dsp)"); 167 println("This test should not be run on systems with ALSA installed, or kernel 2.6 or higher."); 168 println(""); 169 println("The test verifies that Java Sound fails correctly if another process is blocking"); 170 println("the audio device."); 171 println(""); 172 println("Checking sanity..."); 173 Mixer.Info[] mixers=null; 174 175 mixers = AudioSystem.getMixerInfo(); 176 for (int i=0; i<mixers.length; i++) { 177 try { 178 Mixer thisMixer = AudioSystem.getMixer(mixers[i]); 179 String mixerName = thisMixer.getMixerInfo().getName(); 180 if (mixerName.indexOf("Java Sound")>=0 181 && mixerName.indexOf("Engine")>=0) { 182 mixer = thisMixer; 183 break; 184 } 185 } catch (Exception e) { 186 e.printStackTrace(); 187 } 188 } 189 if (mixer == null) { 190 if (mixers.length==0) { 191 System.out.println("ERROR: No mixers available!"); 192 } else { 193 println("ERROR: Java Sound Engine could not be found."); 194 } 195 println("Cannot run this test."); 196 return; 197 } 198 println(" ...using mixer "+mixer.getMixerInfo()); 199 200 String osname = System.getProperty("os.name"); 201 if ((osname == null) || (osname.toLowerCase().indexOf("linux")<0)) { 202 println("ERROR: not running on linux (you are running on "+osname+")"); 203 return; 204 } 205 println(" ...running on "+osname); 206 println(" ...sanity test OK."); 207 208 filename = null; 209 if (args.length>0) { 210 File f = new File(args[0]); 211 if (f.exists()) { 212 filename = args[0]; 213 println("Opening "+filename); 214 constructAIS(); 215 if (ais!=null) { 216 audioFormat = ais.getFormat(); 217 } 218 } 219 } 220 if (ais == null) { 221 println("Using self-generated sine wave for playback"); 222 audioFormat = new AudioFormat((float)sampleRate, 8, 1, true, true); 223 for (int i=0; i<audioData.length; i++) { 224 audioData[i] = (byte)(Math.sin(RAD*frequency/sampleRate*i)*127.0); 225 } 226 } 227 228 println(""); 229 println("Now, on a second console, run the following command:"); 230 println(" cat - < /dev/zero > /dev/dsp"); 231 key(); 232 println("After you press ENTER now, the mixer will be opened."); 233 println("There are 3 possible cases that can occur:"); 234 println("1) you'll hear a sine wave"); 235 println(" -> you are running with mixing OSS drivers. "); 236 println(" Some soundcards only provide mixing OSS drivers."); 237 println(" Test environment not valid. "); 238 println(" Repeat on another machine where you can reproduce the bug first."); 239 println("2) this program stops doing anything after 'Opening line...'"); 240 println(" -> this is the bug."); 241 println(" Kill the command on the other console with Ctrl-C, this program"); 242 println(" should continue working then."); 243 println("3) this program reports a LineUnavailableException"); 244 println(" -> bug is fixed."); 245 println(" OR you run with non-blocking OSS drivers."); 246 println(" make sure that you can reproduce this bug first with e.g. J2SE 1.4.1"); 247 key(); 248 int playedFirst = play(false); 249 int playedSecond = 0; 250 251 if (playedFirst == 2) { 252 println(""); 253 println("Now kill the other process with Ctrl-C."); 254 println("After that, this program should be able to play "); 255 println("the sine wave without problems."); 256 key(); 257 playedSecond = play(true); 258 } 259 println(""); 260 if (playedFirst == 1) { 261 println("Test FAILED."); 262 } 263 else if (playedFirst == 2 && playedSecond == 1) { 264 println("Test SUCCESSFUL"); 265 } else { 266 println("Test not failed (but not successful either...)."); 267 } 268 } 269} 270