1 /*
   2  * Copyright (c) 2005, 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 
  24 import javax.sound.sampled.AudioFormat;
  25 import javax.sound.sampled.AudioSystem;
  26 import javax.sound.sampled.Clip;
  27 import javax.sound.sampled.DataLine;
  28 import javax.sound.sampled.LineEvent;
  29 import javax.sound.sampled.LineListener;
  30 import javax.sound.sampled.LineUnavailableException;
  31 
  32 /**
  33  * @test
  34  * @bug 6251460 8047222
  35  * @requires (os.family == "windows" | os.family == "mac")
  36  * @summary Tests that JavaSound plays short sounds (less then 1 second)
  37  */
  38 public class bug6251460 {
  39     private static final class MutableBoolean {
  40         public boolean value;
  41 
  42         public MutableBoolean(boolean initialValue) {
  43             value = initialValue;
  44         }
  45     }
  46 
  47     // static helper routines
  48     static long startTime = currentTimeMillis();
  49     static long currentTimeMillis() {
  50         return System.nanoTime() / 1000000L;
  51     }
  52     static void log(String s) {
  53         long time = currentTimeMillis() - startTime;
  54         long ms = time % 1000;
  55         time /= 1000;
  56         long sec = time % 60;
  57         time /= 60;
  58         long min = time % 60;
  59         time /= 60;
  60         System.out.println(""
  61             + (time < 10 ? "0" : "") + time
  62             + ":" + (min < 10 ? "0" : "") + min
  63             + ":" + (sec < 10 ? "0" : "") + sec
  64             + "." + (ms < 10 ? "00" : (ms < 100 ? "0" : "")) + ms
  65             + " " + s);
  66     }
  67 
  68 
  69     static private int countErrors = 0;
  70     static private final int LOOP_COUNT = 30;
  71 
  72     static AudioFormat format = new AudioFormat(8000, 16, 1, true, false);
  73     // create a 250-ms clip
  74     static byte[] soundData = new byte[(int) (format.getFrameRate() * format.getFrameSize() * 0.25)];
  75 
  76     static protected void test()
  77             throws LineUnavailableException, InterruptedException {
  78         DataLine.Info info = new DataLine.Info(Clip.class, format);
  79         Clip clip = (Clip)AudioSystem.getLine(info);
  80         final MutableBoolean clipStoppedEvent = new MutableBoolean(false);
  81         clip.addLineListener(new LineListener() {
  82             @Override
  83             public void update(LineEvent event) {
  84                 if (event.getType() == LineEvent.Type.STOP) {
  85                     synchronized (clipStoppedEvent) {
  86                         clipStoppedEvent.value = true;
  87                         clipStoppedEvent.notifyAll();
  88                     }
  89                 }
  90             }
  91         });
  92         clip.open(format, soundData, 0, soundData.length);
  93 
  94         long lengthClip = clip.getMicrosecondLength() / 1000;
  95         log("Clip length " + lengthClip + " ms");
  96         log("Playing...");
  97         for (int i=1; i<=LOOP_COUNT; i++) {
  98             long startTime = currentTimeMillis();
  99             log(" Loop " + i);
 100             clip.start();
 101 
 102             synchronized (clipStoppedEvent) {
 103                 while (!clipStoppedEvent.value) {
 104                     clipStoppedEvent.wait();
 105                 }
 106                 clipStoppedEvent.value = false;
 107             }
 108 
 109             long endTime = currentTimeMillis();
 110             long lengthPlayed = endTime - startTime;
 111 
 112             if (lengthClip > lengthPlayed + 20) {
 113                 log(" ERR: Looks like sound didn't play: played " + lengthPlayed + " ms instead " + lengthClip);
 114                 countErrors++;
 115             } else {
 116                 log(" OK: played " + lengthPlayed + " ms");
 117             }
 118             clip.setFramePosition(0);
 119 
 120         }
 121         log("Played " + LOOP_COUNT + " times, " + countErrors + " errors detected.");
 122     }
 123 
 124     public static void main(String[] args) throws InterruptedException {
 125         try {
 126             test();
 127         } catch (LineUnavailableException | IllegalArgumentException
 128                 | IllegalStateException ignored) {
 129             System.out.println("Test is not applicable. Automatically passed");
 130             return;
 131         }
 132         if (countErrors > 0) {
 133             throw new RuntimeException(
 134                     "Test FAILED: " + countErrors + " error detected (total "
 135                             + LOOP_COUNT + ")");
 136         }
 137     }
 138 }