Path: blob/master/test/jdk/javax/sound/sampled/DirectAudio/bug6372428.java
41153 views
/*1* Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223import javax.sound.sampled.AudioFormat;24import javax.sound.sampled.AudioSystem;25import javax.sound.sampled.DataLine;26import javax.sound.sampled.LineUnavailableException;27import javax.sound.sampled.SourceDataLine;28import javax.sound.sampled.TargetDataLine;2930/*31* @test32* @bug 637242833* @summary playback and capture doesn't interrupt after terminating thread that34* calls start()35* @run main bug637242836*/37public class bug6372428 {38public bug6372428() {39}4041public static void main(final String[] args) {42bug6372428 pThis = new bug6372428();43boolean failed1 = false;44boolean failed2 = false;45log("");46log("****************************************************************");47log("*** Playback Test");48log("****************************************************************");49log("");50try {51pThis.testPlayback();52} catch (IllegalArgumentException | LineUnavailableException e) {53System.out.println("Playback test is not applicable. Skipped");54} catch (Exception ex) {55ex.printStackTrace();56failed1 = true;57}58log("");59log("");60log("****************************************************************");61log("*** Capture Test");62log("****************************************************************");63log("");64try {65pThis.testRecord();66} catch (IllegalArgumentException | LineUnavailableException e) {67System.out.println("Record test is not applicable. Skipped");68} catch (Exception ex) {69ex.printStackTrace();70failed2 = true;71}72log("");73log("");74log("****************************************************************");75if (failed1 || failed2) {76String s = "";77if (failed1 && failed2)78s = "playback and capture";79else if (failed1)80s = "playback only";81else82s = "capture only";83throw new RuntimeException("Test FAILED (" + s + ")");84}85log("*** All tests passed successfully.");86}8788final static int DATA_LENGTH = 15; // in seconds89final static int PLAYTHREAD_DELAY = 5; // in seconds9091// playback test classes/routines9293class PlayThread extends Thread {94SourceDataLine line;95public PlayThread(SourceDataLine line) {96this.line = line;97this.setDaemon(true);98}99100public void run() {101log("PlayThread: starting...");102line.start();103log("PlayThread: delaying " + (PLAYTHREAD_DELAY * 1000) + "ms...");104delay(PLAYTHREAD_DELAY * 1000);105log("PlayThread: exiting...");106}107}108109class WriteThread extends Thread {110SourceDataLine line;111byte[] data;112volatile int remaining;113volatile boolean stopRequested = false;114public WriteThread(SourceDataLine line, byte[] data) {115this.line = line;116this.data = data;117remaining = data.length;118this.setDaemon(true);119}120121public void run() {122while (remaining > 0 && !stopRequested) {123int avail = line.available();124if (avail > 0) {125if (avail > remaining)126avail = remaining;127int written = line.write(data, data.length - remaining, avail);128remaining -= written;129log("WriteThread: " + written + " bytes written");130} else {131delay(100);132}133}134if (remaining == 0) {135log("WriteThread: all data has been written, draining");136line.drain();137} else {138log("WriteThread: stop requested");139}140log("WriteThread: stopping");141line.stop();142log("WriteThread: exiting");143}144145public boolean isCompleted() {146return (remaining <= 0);147}148149public void requestStop() {150stopRequested = true;151}152}153154void testPlayback() throws LineUnavailableException {155// prepare audio data156AudioFormat format = new AudioFormat(22050, 8, 1, false, false);157byte[] soundData = new byte[(int) (format.getFrameRate() * format.getFrameSize() * DATA_LENGTH)];158159// create & open source data line160//SourceDataLine line = AudioSystem.getSourceDataLine(format);161DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);162SourceDataLine line = (SourceDataLine)AudioSystem.getLine(info);163164line.open(format);165166// start write data thread167WriteThread p1 = new WriteThread(line, soundData);168p1.start();169170// start line171PlayThread p2 = new PlayThread(line);172p2.start();173174// monitor line175long lineTime1 = line.getMicrosecondPosition() / 1000;176long realTime1 = currentTimeMillis();177while (true) {178delay(500);179if (!line.isActive()) {180log("audio data played completely");181break;182}183long lineTime2 = line.getMicrosecondPosition() / 1000;184long realTime2 = currentTimeMillis();185long dLineTime = lineTime2 - lineTime1;186long dRealTime = realTime2 - realTime1;187log("line pos: " + lineTime2 + "ms" + ", thread is " + (p2.isAlive() ? "alive" : "DIED"));188if (dLineTime < 0) {189throw new RuntimeException("ERROR: line position have decreased from " + lineTime1 + " to " + lineTime2);190}191if (dRealTime < 450) {192// delay() has been interrupted?193continue;194}195lineTime1 = lineTime2;196realTime1 = realTime2;197}198}199200201// recording test classes/routines202203class RecordThread extends Thread {204TargetDataLine line;205public RecordThread(TargetDataLine line) {206this.line = line;207this.setDaemon(true);208}209210public void run() {211log("RecordThread: starting...");212line.start();213log("RecordThread: delaying " + (PLAYTHREAD_DELAY * 1000) + "ms...");214delay(PLAYTHREAD_DELAY * 1000);215log("RecordThread: exiting...");216}217}218219class ReadThread extends Thread {220TargetDataLine line;221byte[] data;222volatile int remaining;223public ReadThread(TargetDataLine line, byte[] data) {224this.line = line;225this.data = data;226remaining = data.length;227this.setDaemon(true);228}229230public void run() {231log("ReadThread: buffer size is " + data.length + " bytes");232delay(200);233while ((remaining > 0) && line.isOpen()) {234int avail = line.available();235if (avail > 0) {236if (avail > remaining)237avail = remaining;238int read = line.read(data, data.length - remaining, avail);239remaining -= read;240log("ReadThread: " + read + " bytes read");241} else {242delay(100);243}244if (remaining <= 0) {245log("ReadThread: record buffer is full, exiting");246break;247}248}249if (remaining > 0) {250log("ReadThread: line has been stopped, exiting");251}252}253254public int getCount() {255return data.length - remaining;256}257public boolean isCompleted() {258return (remaining <= 0);259}260}261262void testRecord() throws LineUnavailableException {263// prepare audio data264AudioFormat format = new AudioFormat(22050, 8, 1, false, false);265266// create & open target data line267//TargetDataLine line = AudioSystem.getTargetDataLine(format);268DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);269TargetDataLine line = (TargetDataLine)AudioSystem.getLine(info);270271line.open(format);272273// start read data thread274byte[] data = new byte[(int) (format.getFrameRate() * format.getFrameSize() * DATA_LENGTH)];275ReadThread p1 = new ReadThread(line, data);276p1.start();277278// start line279//new RecordThread(line).start();280RecordThread p2 = new RecordThread(line);281p2.start();282283// monitor line284long endTime = currentTimeMillis() + DATA_LENGTH * 1000;285286long realTime1 = currentTimeMillis();287long lineTime1 = line.getMicrosecondPosition() / 1000;288289while (realTime1 < endTime && !p1.isCompleted()) {290delay(100);291long lineTime2 = line.getMicrosecondPosition() / 1000;292long realTime2 = currentTimeMillis();293long dLineTime = lineTime2 - lineTime1;294long dRealTime = realTime2 - realTime1;295log("line pos: " + lineTime2 + "ms" + ", thread is " + (p2.isAlive() ? "alive" : "DIED"));296if (dLineTime < 0) {297line.stop();298line.close();299throw new RuntimeException("ERROR: line position have decreased from " + lineTime1 + " to " + lineTime2);300}301if (dRealTime < 450) {302// delay() has been interrupted?303continue;304}305lineTime1 = lineTime2;306realTime1 = realTime2;307}308log("stopping line...");309line.stop();310line.close();311312/*313log("");314log("");315log("");316log("recording completed, delaying 5 sec");317log("recorded " + p1.getCount() + " bytes, " + DATA_LENGTH + " seconds: " + (p1.getCount() * 8 / DATA_LENGTH) + " bit/sec");318log("");319log("");320log("");321delay(5000);322log("starting playing...");323playRecorded(format, data);324*/325}326327void playRecorded(AudioFormat format, byte[] data) throws Exception {328//SourceDataLine line = AudioSystem.getSourceDataLine(format);329DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);330SourceDataLine line = (SourceDataLine)AudioSystem.getLine(info);331332line.open();333line.start();334335int remaining = data.length;336while (remaining > 0) {337int avail = line.available();338if (avail > 0) {339if (avail > remaining)340avail = remaining;341int written = line.write(data, data.length - remaining, avail);342remaining -= written;343log("Playing: " + written + " bytes written");344} else {345delay(100);346}347}348349line.drain();350line.stop();351}352353// helper routines354static long startTime = currentTimeMillis();355static long currentTimeMillis() {356//return System.nanoTime() / 1000000L;357return System.currentTimeMillis();358}359static void log(String s) {360long time = currentTimeMillis() - startTime;361long ms = time % 1000;362time /= 1000;363long sec = time % 60;364time /= 60;365long min = time % 60;366time /= 60;367System.out.println(""368+ (time < 10 ? "0" : "") + time369+ ":" + (min < 10 ? "0" : "") + min370+ ":" + (sec < 10 ? "0" : "") + sec371+ "." + (ms < 10 ? "00" : (ms < 100 ? "0" : "")) + ms372+ " (" + Thread.currentThread().getName() + ") " + s);373}374static void delay(int millis) {375try {376Thread.sleep(millis);377} catch (InterruptedException e) {}378}379}380381382