-
Bug
-
Resolution: Fixed
-
P3
-
5.0
-
b01
-
x86
-
windows
Issue | Fix Version | Assignee | Priority | Status | Resolution | Resolved In Build |
---|---|---|---|---|---|---|
JDK-2133350 | 6 | Alex Menkov | P3 | Resolved | Fixed | b76 |
When the thread that calls SourceDataLine.start() exits, the sound will stop playing (sound card starts to click, line position increases very slow and sometimes jumps back).
Due this bug JMF (All-Java version) doesn't work with latest java releases (1.5 and above)
Code example (works with 1.4.2, fails with 1.5 and 1.6):
import java.io.*;
import javax.sound.sampled.*;
import java.net.URL;
public class Test {
public Test() {
}
public static void main(String[] args) throws Exception {
Test pThis = new Test();
try {
pThis.testPlayback();
} catch (Exception ex) {
ex.printStackTrace();
throw ex;
}
}
final static int DATA_LENGTH = 15; // in seconds
final static int PLAYTHREAD_DELAY = 5; // in seconds
// playback test classes/routines
class PlayThread extends Thread {
SourceDataLine line;
public PlayThread(SourceDataLine line) {
this.line = line;
this.setDaemon(true);
}
public void run() {
log("PlayThread: starting...");
line.start();
log("PlayThread: delaying " + (PLAYTHREAD_DELAY * 1000) + "ms...");
delay(PLAYTHREAD_DELAY * 1000);
log("PlayThread: exiting...");
}
}
class WriteThread extends Thread {
SourceDataLine line;
byte[] data;
int pos = 0;
public WriteThread(SourceDataLine line, byte[] data) {
this.line = line;
this.data = data;
this.setDaemon(true);
}
public void run() {
int remain = data.length;
while (remain > 0) {
int avail = line.available();
if (avail > 0) {
if (avail > remain)
avail = remain;
int written = line.write(data, pos, avail);
pos += written;
remain -= written;
log("WriteThread: " + written + " bytes written");
} else {
delay(100);
}
}
log("WriteThread: all data has been written, draining");
line.drain();
log("WriteThread: stopping");
line.stop();
log("WriteThread: exiting");
}
public boolean isCompleted() {
return (pos >= data.length-1);
}
}
void testPlayback() throws Exception {
// prepare audio data
AudioFormat format = new AudioFormat(22050, 8, 1, false, false);
byte[] soundData = new byte[(int) (format.getFrameRate() * format.getFrameSize() * DATA_LENGTH)];
// create & open source data line
DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
SourceDataLine line = (SourceDataLine)AudioSystem.getLine(info);
//SourceDataLine line = AudioSystem.getSourceDataLine(format);
line.open(format);
// start write data thread
new WriteThread(line, soundData).start();
// start line
new PlayThread(line).start();
// monitor line
long lineTime1 = line.getMicrosecondPosition() / 1000;
long realTime1 = currentTimeMillis();
while (true) {
delay(500);
if (!line.isActive()) {
log("audio data played completely");
break;
}
long lineTime2 = line.getMicrosecondPosition() / 1000;
long realTime2 = currentTimeMillis();
long dLineTime = lineTime2 - lineTime1;
long dRealTime = realTime2 - realTime1;
log("line pos: " + lineTime2 + "ms");
if (dLineTime < 0) {
throw new RuntimeException("ERROR: line position have decreased from " + lineTime1 + " to " + lineTime2);
}
if (dRealTime < 450) {
// delay() has been interrupted?
continue;
}
if (dLineTime < 250) {
throw new RuntimeException("ERROR: line position increased too slow: " + dLineTime + "ms during " + dRealTime + "ms");
}
lineTime1 = lineTime2;
realTime1 = realTime2;
}
}
// helper routines
static long currentTimeMillis() {
//return System.nanoTime() / 1000000L;
return System.currentTimeMillis();
}
static void log(String s) {
System.out.println(s);
}
static void delay(int millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {}
}
}
Due this bug JMF (All-Java version) doesn't work with latest java releases (1.5 and above)
Code example (works with 1.4.2, fails with 1.5 and 1.6):
import java.io.*;
import javax.sound.sampled.*;
import java.net.URL;
public class Test {
public Test() {
}
public static void main(String[] args) throws Exception {
Test pThis = new Test();
try {
pThis.testPlayback();
} catch (Exception ex) {
ex.printStackTrace();
throw ex;
}
}
final static int DATA_LENGTH = 15; // in seconds
final static int PLAYTHREAD_DELAY = 5; // in seconds
// playback test classes/routines
class PlayThread extends Thread {
SourceDataLine line;
public PlayThread(SourceDataLine line) {
this.line = line;
this.setDaemon(true);
}
public void run() {
log("PlayThread: starting...");
line.start();
log("PlayThread: delaying " + (PLAYTHREAD_DELAY * 1000) + "ms...");
delay(PLAYTHREAD_DELAY * 1000);
log("PlayThread: exiting...");
}
}
class WriteThread extends Thread {
SourceDataLine line;
byte[] data;
int pos = 0;
public WriteThread(SourceDataLine line, byte[] data) {
this.line = line;
this.data = data;
this.setDaemon(true);
}
public void run() {
int remain = data.length;
while (remain > 0) {
int avail = line.available();
if (avail > 0) {
if (avail > remain)
avail = remain;
int written = line.write(data, pos, avail);
pos += written;
remain -= written;
log("WriteThread: " + written + " bytes written");
} else {
delay(100);
}
}
log("WriteThread: all data has been written, draining");
line.drain();
log("WriteThread: stopping");
line.stop();
log("WriteThread: exiting");
}
public boolean isCompleted() {
return (pos >= data.length-1);
}
}
void testPlayback() throws Exception {
// prepare audio data
AudioFormat format = new AudioFormat(22050, 8, 1, false, false);
byte[] soundData = new byte[(int) (format.getFrameRate() * format.getFrameSize() * DATA_LENGTH)];
// create & open source data line
DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
SourceDataLine line = (SourceDataLine)AudioSystem.getLine(info);
//SourceDataLine line = AudioSystem.getSourceDataLine(format);
line.open(format);
// start write data thread
new WriteThread(line, soundData).start();
// start line
new PlayThread(line).start();
// monitor line
long lineTime1 = line.getMicrosecondPosition() / 1000;
long realTime1 = currentTimeMillis();
while (true) {
delay(500);
if (!line.isActive()) {
log("audio data played completely");
break;
}
long lineTime2 = line.getMicrosecondPosition() / 1000;
long realTime2 = currentTimeMillis();
long dLineTime = lineTime2 - lineTime1;
long dRealTime = realTime2 - realTime1;
log("line pos: " + lineTime2 + "ms");
if (dLineTime < 0) {
throw new RuntimeException("ERROR: line position have decreased from " + lineTime1 + " to " + lineTime2);
}
if (dRealTime < 450) {
// delay() has been interrupted?
continue;
}
if (dLineTime < 250) {
throw new RuntimeException("ERROR: line position increased too slow: " + dLineTime + "ms during " + dRealTime + "ms");
}
lineTime1 = lineTime2;
realTime1 = realTime2;
}
}
// helper routines
static long currentTimeMillis() {
//return System.nanoTime() / 1000000L;
return System.currentTimeMillis();
}
static void log(String s) {
System.out.println(s);
}
static void delay(int millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {}
}
}
- backported by
-
JDK-2133350 REGRESSION: playback fails after exiting from thread that has started it (Windows)
- Resolved