Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-6372428

REGRESSION: playback fails after exiting from thread that has started it (Windows)

    Details

    • Subcomponent:
    • Resolved In Build:
      b01
    • CPU:
      x86
    • OS:
      windows

      Backports

        Description

        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) {}
            }
        }

          Attachments

            Issue Links

              Activity

                People

                • Assignee:
                  amenkov Alex Menkov
                  Reporter:
                  amenkov Alex Menkov
                • Votes:
                  0 Vote for this issue
                  Watchers:
                  0 Start watching this issue

                  Dates

                  • Created:
                    Updated:
                    Resolved:
                    Imported:
                    Indexed: