Cazra
Cazra

Reputation: 143

Java Multi-threaded sound crash

I'm working on a game project in Java in which I need to be able to play multiple sounds at the same time in real time. I've implemented a sound system that generates new threads to play SourceDataLine sounds on.

The game works completely fine on my computer, but for one of my testers, the sound system keeps crashing on him at random intervals. We're both running the same version of java (jre 1.6.0_29) on Windows 7, and after several rounds of testing and google-searching, I haven't been able to figure out why it always works fine for me, but crashes on him.

Here is an SSCCE demonstrating the part of my code where my problem is occurring. The important bits are the SoundPlayer, Sound, and SoundThread classes. You will need to include two sound files named shortSound.wav and longerSound.wav in the same directory you save the SSCCE in.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.sound.sampled.*;
import java.util.HashMap;
import java.util.Collection;
import java.io.*;
import java.net.URL;
import java.util.LinkedList;

public class SoundSSCCE extends JFrame
{

    private JPanel screenP;
    private JPanel bgFraming;

    /**
    *   Constructor
    *   Preconditions: None.
    *   Postconditions: The window for the SSCCE is created.
    **/

    public SoundSSCCE()
    {
        super("Sound problem SSCCE");
        this.setSize(200,100);

        // instantiate main window panel

        screenP = new SSCCEPanel(this);
        this.add(screenP);

        // finishing touches on Game window

        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);

        System.out.println("Game Window successfully created!!!");
    }


    public static void main(String[] args)
    {
        SoundSSCCE gui = new SoundSSCCE();      
    }
}




/**
*   SSCCEPanel is the JPanel that manages the example's timer, painting, and logic. 
**/

class SSCCEPanel extends JPanel
{
    public Frame parentFrame;
    private Timer timer;
    public int logicLoops;
    public double prevFPS;
    boolean timerReady;

    // The SoundPlayer object is used by the example to play the sounds.

    public SoundPlayer soundPlayer;

    public SSCCEPanel(Frame parent)
    {
        super(true);
        parentFrame = parent;
        this.setFocusable(true);

        Toolkit.getDefaultToolkit().sync();
        logicLoops = 0;

        soundPlayer = new SoundPlayer();

        TimerListener timerListener = new TimerListener();
        prevFPS = 0;
        timerReady = true;
        timer = new Timer(0,timerListener);
        this.setFPS(60);
        timer.start();
    }

    /** 
    *   setFPS()
    *   Preconditions: fps is a quantity of frames per second
    *   Postconditions: Sets the timer's refresh rate so that it 
    *       fires fps times per second.
    **/

    public void setFPS(int fps)
    {
        int mspf = (int) (1000.0 /fps + 0.5);
        timer.setDelay(mspf);
    }


    /**
    *   This is the JPanel's timer listener. It runs the example's logic and repaint
    *   methods each time it gets a timer signal.
    **/

    private class TimerListener implements ActionListener
    {
        long startTime = System.currentTimeMillis();
        long lastTime = this.startTime;
        int ticks = 0;

        public void actionPerformed(ActionEvent e)
        {
            Object source = e.getSource();
            if(source == timer)
            {
                // perform a loop through the game's logic and repaint.

                synchronized(this)
                {
                    if(timerReady)
                    {
                        timerReady = false;
                        runSSCCELogic();
                        repaint();
                        timerReady = true;
                    }
                }

                // Logic for Frames per Second counter

                this.ticks++;

                long currentTime = System.currentTimeMillis();

                if(currentTime - startTime >= 500) 
                {
                    prevFPS =  1000.0 * ticks/(1.0*currentTime - startTime);
                    System.out.println(prevFPS);
                    startTime = currentTime;
                    ticks = 0;
                }

                lastTime = currentTime;
            }
        }
    }


    /**
    *   repaints the SSCCE.
    *   This just shows the current FPS and the number of sounds currently playing.
    **/

    public void paintComponent(Graphics g)
    {
            super.paintComponent(g);

            Graphics2D g2D = (Graphics2D) g;
            double roundedFPS = Math.round(prevFPS*10)/10.0;

            g2D.setColor(new Color(0x000000));
            g2D.drawString("FPS: " + roundedFPS, 20,20);
            g2D.drawString("Sounds playing: " + soundPlayer.soundsPlaying(), 20,50);
            g.dispose();
    }

    /**
    *   runSSCCEELogic()
    *   This is where the run-time logic for the SSCCE example is. 
    *   All it will do is play sounds at regular narrowly-spaced intervals.
    *   The sounds are stored in the same directory as the SSCCE. Substitute any .wav
    *   file here in place of shortSound.wav and longerSound.wav.
    **/

    public void runSSCCELogic()
    {
        if(logicLoops % 4 == 0)
        {
            soundPlayer.play("shortSound.wav");
        }
        if(logicLoops% 40 == 0)
        {
            soundPlayer.play("longerSound.wav");
        }
        logicLoops++;
    }


}



/**
*   My game uses makes method calls to the SoundPlayer object whenever it
*   needs to play any sounds. This separates the main game code from the lower-level 
*   mucking-about with Sound object code. It also makes it easier for me to make changes to 
*   my Sound class without having to make changes any lines in my game where I play sounds.
**/


class SoundPlayer
{
    private HashMap<String,Sound> sounds;
    private double volume;
    private int soundsPlaying;

    public SoundPlayer()
    {
        sounds = new HashMap<String,Sound>();
        volume = 1.0;
        soundsPlaying = 0;
    }


    /**
    *   playSound(String path)
    *   creates and plays a Sound specified by path.
    *   Preconditions: path is the file path for the sound.
    *   Postconditions: The sound is loaded and begins playing. 
    *       This method returns a reference to that sound.
    **/

    public Sound play(String path)
    {       
        Sound newSound;

        if(volume == 0)
            return null;

        if(sounds.containsKey(path))
        {
            newSound = sounds.get(path);
        }
        else
        {
            newSound = new Sound(path);
            sounds.put(path,newSound);
        }

        newSound.play(volume);

        return newSound;
    }

    /**
    *   load(String path)
    *   preloads a sound to be play instances of at a later time
    *   Preconditions: path is the file path for the sound.
    *   Postconditions: The sound is loaded. This method returns 
    *       a reference to that sound.
    **/

    public Sound load(String path)
    {
        Sound newSound;

        if(sounds.containsKey(path))
        {
            newSound = sounds.get(path);
        }
        else
        {
            newSound = new Sound(path);
            sounds.put(path,newSound);
        }
        return newSound;
    }

    public int soundsPlaying()
    {
        int count = 0;

        Collection<Sound> soundsIterable = sounds.values();
        for(Sound sound : soundsIterable)
        {
            count += sound.instances;
        }
        return count;
    }

    public int soundsLoaded()
    {
        return sounds.size();
    }


    public void setVolume(double vol)
    {
        this.volume = vol;
    }

}


/**
*   Sound objects store the path to a given sound file and spawn new threads
*   to play instances of their sound when the SoundPlayer tells them to play.
**/

class Sound
{
    public String path;
    protected int instances;
    protected URL soundURL;

    public Sound(String name)
    {
        try
        {
            soundURL =  getClass().getClassLoader().getResource(name);
            instances = 0;
            path = name;
        }
        catch(Exception ex)
        {
            System.out.println("An error occured while loading the sound file: " + name);
            System.out.println(ex.getMessage());
            ex.printStackTrace();
        }
    }

    /**
    *   play(double volume)
    *   Preconditions: volume is between 0.0 and 1.0 inclusive, where 1.0 is 
    *       at full volume and 0.0 is silent.
    *   Postconditions: The Sound spawns a new thread to play an instance
    *       of itself.
    **/

    public void play(double volume)
    {
        try
        {
            SoundThread clip = new SoundThread(this);
            synchronized(this)
            {
                // increment the count of its instances. The SoundThread
                //  will automatically decrement the sound instance when it finishes. 

                instances++;
            }
            clip.setVolume(volume);
            clip.start();

        }
        catch(Exception e)
        {
            System.out.println("Sound error: Error playing sound");
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
    }
}


/**
*   SoundThread is a thread that Sound objects spawn to play instances 
*   of their sounds. This supports multiple sounds being played simultaneously. 
**/

class SoundThread extends Thread
{
    public SourceDataLine clip;
    public AudioInputStream stream;
    private int bufferSize = 50;
    private Sound parent;

    public SoundThread(Sound parentSound)
    {
        try
        {
            parent = parentSound;

            // obtains input stream from AudioSystem to read from the file.

            stream = AudioSystem.getAudioInputStream(parentSound.soundURL); 
            AudioFormat format = stream.getFormat();

            // obtains the sound file's line

            DataLine.Info info = new DataLine.Info(SourceDataLine.class, format); 

            // loads the line into the clip

            clip = (SourceDataLine) AudioSystem.getLine(info); 

            // opens the clip onto the stream

            clip.open(format); 
            System.out.println("Sound buffer size: " + clip.getBufferSize());
        }
        catch(Exception e)
        {
            System.out.println("error playing sound");
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
    }


    public void run()
    {
        try
        {
            // I start my sourceDataLine and begin reading data 
            // from the stream into its buffer.

            clip.start();
            int bytesRead = 0;
            byte[] soundData = new byte[bufferSize];

            // read data from the stream into the sourceDataLine until there
            // is no more data to read

            while(bytesRead != -1)
            {
                bytesRead = stream.read(soundData,0,bufferSize);
                if(bytesRead >= 0)
                {
                    clip.write(soundData, 0, bytesRead);
                }
                else
                {
                    // Here I drain and close the line and its stream when
                    //  the sound is finished playing (it has read all the bytes from its stream).
                    // My tester's log suggests that SourceDataLine.drain() is where it
                    // is crashing.

                    clip.drain();
                    clip.close();
                    stream.close();
                }
            }

            // decrement the count of the Sound's instances.

            synchronized(parent)
            {
                parent.instances--;
            }
        }
        catch(Exception e)
        {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
    }



    public void setVolume(double vol)
    {
        try
        {
            FloatControl volCtrl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
            if(vol > 1.0)
                vol = 1.0;
            if(vol < 0.0)
                vol = 0.0;

            // tricky, confusing sound math stuff.

            float dB = (float) (Math.log(vol) / Math.log(10.0) * 20.0);
            if(dB > volCtrl.getMaximum())
                dB = volCtrl.getMaximum();
            if(dB < volCtrl.getMinimum())
                dB = volCtrl.getMinimum();
            volCtrl.setValue(dB);
        }
        catch(Exception e)
        {
            System.out.println("set volume failed");
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
    }
}

Here's a log file generated by my tester's jre when the game crashes.

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x0000000000000000, pid=5212, tid=5524
#
# JRE version: 6.0_29-b11
# Java VM: Java HotSpot(TM) 64-Bit Server VM (20.4-b02 mixed mode windows-amd64 compressed oops)
# Problematic frame:
# C  0x0000000000000000
#
# If you would like to submit a bug report, please visit:
#   http://java.sun.com/webapps/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#

---------------  T H R E A D  ---------------

Current thread (0x00000000097c4000):  JavaThread "Thread-651" [_thread_in_native, id=5524, stack(0x000000000ecf0000,0x000000000edf0000)]

siginfo: ExceptionCode=0xc0000005, ExceptionInformation=0x0000000000000008 0x0000000000000000

Registers:
RAX=0x0000000000000000, RBX=0x00000000148ef5b0, RCX=0x00000000097c41d0, RDX=0x0000000000000002
RSP=0x000000000edef4f8, RBP=0x000000000edef6e0, RSI=0x00000000097c41d0, RDI=0x00000000097c41d0
R8 =0x000000000edef520, R9 =0x0000000000000000, R10=0x2b11000000000000, R11=0x0000000006146b00
R12=0x00000000148a1f00, R13=0x0000000000000000, R14=0x000000000edef710, R15=0x00000000097c4000
RIP=0x0000000000000000, EFLAGS=0x0000000000010246

Top of Stack: (sp=0x000000000edef4f8)
0x000000000edef4f8:   000000006d515842 000000000edef5a0
0x000000000edef508:   0000000000000000 000000000bfbbd18
0x000000000edef518:   000000006d525264 00000000148ef5b0
0x000000000edef528:   0000000006146b00 000000001491ddb0
0x000000000edef538:   2b11000000001f44 00000000096b0108
0x000000000edef548:   0000000000000000 000000006d90a5cb
0x000000000edef558:   000000006d511ed4 00000000097c41d0
0x000000000edef568:   000000006d511ed4 00000000148ef5b0
0x000000000edef578:   000000006d516055 0000000000000000
0x000000000edef588:   0000000000000000 0000000000000000
0x000000000edef598:   0000000000000000 00000000148ef5b0
0x000000000edef5a8:   0000000006146b00 000000001491ed56
0x000000000edef5b8:   2b11000000000000 00000000096b0108
0x000000000edef5c8:   0000000000000000 000000006d90a5cb
0x000000000edef5d8:   000000006d52b54b 00000000000005c8
0x000000000edef5e8:   00000000bc162e50 0000000000000000 

Instructions: (pc=0x0000000000000000)
0xffffffffffffffe0:   


Register to memory mapping:

RAX=0x0000000000000000 is an unknown value
RBX=0x00000000148ef5b0 is an unknown value
RCX=0x00000000097c41d0 is an unknown value
RDX=0x0000000000000002 is an unknown value
RSP=0x000000000edef4f8 is pointing into the stack for thread: 0x00000000097c4000
RBP=0x000000000edef6e0 is pointing into the stack for thread: 0x00000000097c4000
RSI=0x00000000097c41d0 is an unknown value
RDI=0x00000000097c41d0 is an unknown value
R8 =0x000000000edef520 is pointing into the stack for thread: 0x00000000097c4000
R9 =0x0000000000000000 is an unknown value
R10=0x2b11000000000000 is an unknown value
R11=0x0000000006146b00 is a global jni handle
R12=0x00000000148a1f00 is an unknown value
R13=0x0000000000000000 is an unknown value
R14=0x000000000edef710 is pointing into the stack for thread: 0x00000000097c4000
R15=0x00000000097c4000 is a thread


Stack: [0x000000000ecf0000,0x000000000edf0000],  sp=0x000000000edef4f8,  free space=1021k
Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j  com.sun.media.sound.MixerSourceLine.nDrain(J)V+0
j  com.sun.media.sound.MixerSourceLine.drain()V+26
J  gameEngine.SoundThread.run()V
v  ~StubRoutines::call_stub

---------------  P R O C E S S  ---------------

Java Threads: ( => current thread )
  0x0000000009959000 JavaThread "Thread-1843" [_thread_in_native, id=4748, stack(0x0000000015780000,0x0000000015880000)]
  0x000000000995c000 JavaThread "Thread-1842" [_thread_in_native, id=10632, stack(0x00000000146b0000,0x00000000147b0000)]
  0x0000000009959800 JavaThread "Thread-1841" [_thread_in_native, id=4240, stack(0x0000000015a80000,0x0000000015b80000)]
  0x0000000009958800 JavaThread "Thread-1828" [_thread_blocked, id=632, stack(0x00000000145b0000,0x00000000146b0000)]
  0x000000000995c800 JavaThread "Thread-1754" [_thread_in_native, id=11188, stack(0x0000000015980000,0x0000000015a80000)]
  0x0000000009957800 JavaThread "Thread-1699" [_thread_in_native, id=8788, stack(0x00000000144b0000,0x00000000145b0000)]
  0x000000000995a800 JavaThread "Thread-1650" [_thread_in_native, id=10860, stack(0x000000000fe20000,0x000000000ff20000)]
  0x00000000097bc000 JavaThread "Java Sound Sequencer" [_thread_blocked, id=11096, stack(0x0000000006cc0000,0x0000000006dc0000)]
  0x0000000009957000 JavaThread "Thread-1285" [_thread_in_native, id=10608, stack(0x00000000142b0000,0x00000000143b0000)]
  0x00000000097c3800 JavaThread "Thread-1223" [_thread_in_native, id=6968, stack(0x000000000eff0000,0x000000000f0f0000)]
  0x00000000097c9000 JavaThread "Thread-1157" [_thread_in_vm, id=9260, stack(0x00000000143b0000,0x00000000144b0000)]
  0x00000000097c0800 JavaThread "Thread-1139" [_thread_in_native, id=10544, stack(0x00000000141b0000,0x00000000142b0000)]
  0x00000000097ca800 JavaThread "Thread-1138" [_thread_in_native, id=8456, stack(0x00000000140b0000,0x00000000141b0000)]
  0x00000000097c6800 JavaThread "Thread-1113" [_thread_in_native, id=10536, stack(0x000000000fa20000,0x000000000fb20000)]
  0x00000000097c8800 JavaThread "Thread-1110" [_thread_in_native, id=7780, stack(0x000000000edf0000,0x000000000eef0000)]
  0x00000000097c5800 JavaThread "Thread-1054" [_thread_in_native, id=10472, stack(0x000000000eef0000,0x000000000eff0000)]
  0x00000000097c1800 JavaThread "Thread-1046" [_thread_in_native, id=6148, stack(0x0000000013fb0000,0x00000000140b0000)]
  0x00000000097c0000 JavaThread "Thread-1030" [_thread_in_native, id=10720, stack(0x000000000e3a0000,0x000000000e4a0000)]
  0x00000000097c8000 JavaThread "Thread-963" [_thread_in_native, id=3148, stack(0x000000000ac50000,0x000000000ad50000)]
  0x00000000097c2000 JavaThread "Thread-923" [_thread_in_native, id=10492, stack(0x000000000fd20000,0x000000000fe20000)]
  0x00000000097c7000 JavaThread "Thread-791" [_thread_in_native, id=2044, stack(0x000000000e5a0000,0x000000000e6a0000)]
  0x00000000097c2800 JavaThread "Thread-751" [_thread_in_native, id=2780, stack(0x000000000e4a0000,0x000000000e5a0000)]
=>0x00000000097c4000 JavaThread "Thread-651" [_thread_in_native, id=5524, stack(0x000000000ecf0000,0x000000000edf0000)]
  0x00000000097bf000 JavaThread "DestroyJavaVM" [_thread_blocked, id=10636, stack(0x0000000002370000,0x0000000002470000)]
  0x00000000097be800 JavaThread "D3D Screen Updater" daemon [_thread_blocked, id=10044, stack(0x000000000d940000,0x000000000da40000)]
  0x00000000097bd800 JavaThread "AWT-EventQueue-0" [_thread_blocked, id=3036, stack(0x000000000cc50000,0x000000000cd50000)]
  0x00000000097bd000 JavaThread "AWT-Shutdown" [_thread_blocked, id=10372, stack(0x000000000cb50000,0x000000000cc50000)]
  0x0000000009633800 JavaThread "TimerQueue" daemon [_thread_blocked, id=10840, stack(0x000000000b650000,0x000000000b750000)]
  0x0000000009631000 JavaThread "Headspace mixer frame proc thread" daemon [_thread_blocked, id=10808, stack(0x000000000ae50000,0x000000000af50000)]
  0x00000000095f0800 JavaThread "Java Sound Event Dispatcher" daemon [_thread_blocked, id=8628, stack(0x000000000a950000,0x000000000aa50000)]
  0x00000000062c1000 JavaThread "Java Sound Event Dispatcher" daemon [_thread_blocked, id=10864, stack(0x000000000a850000,0x000000000a950000)]
  0x000000000618c000 JavaThread "AWT-Windows" daemon [_thread_in_native, id=10984, stack(0x0000000006dc0000,0x0000000006ec0000)]
  0x0000000006189800 JavaThread "Java2D Disposer" daemon [_thread_blocked, id=1848, stack(0x0000000006bc0000,0x0000000006cc0000)]
  0x0000000006145000 JavaThread "Low Memory Detector" daemon [_thread_blocked, id=7160, stack(0x00000000066f0000,0x00000000067f0000)]
  0x000000000052d800 JavaThread "C2 CompilerThread1" daemon [_thread_blocked, id=10604, stack(0x00000000065f0000,0x00000000066f0000)]
  0x0000000000526800 JavaThread "C2 CompilerThread0" daemon [_thread_blocked, id=2820, stack(0x00000000064f0000,0x00000000065f0000)]
  0x0000000000524800 JavaThread "Attach Listener" daemon [_thread_blocked, id=1616, stack(0x00000000063f0000,0x00000000064f0000)]
  0x0000000000523800 JavaThread "Signal Dispatcher" daemon [_thread_blocked, id=9476, stack(0x00000000062f0000,0x00000000063f0000)]
  0x000000000050f800 JavaThread "Finalizer" daemon [_thread_blocked, id=9472, stack(0x0000000005ff0000,0x00000000060f0000)]
  0x0000000000506800 JavaThread "Reference Handler" daemon [_thread_blocked, id=8864, stack(0x0000000005ef0000,0x0000000005ff0000)]

Other Threads:
  0x00000000004fe000 VMThread [stack: 0x0000000005df0000,0x0000000005ef0000] [id=3480]
  0x0000000006160800 WatcherThread [stack: 0x00000000067f0000,0x00000000068f0000] [id=6728]

VM state:not at safepoint (normal execution)

VM Mutex/Monitor currently owned by a thread: None

Heap
 PSYoungGen      total 10240K, used 4696K [0x00000000ead60000, 0x00000000eb980000, 0x0000000100000000)
  eden space 10112K, 45% used [0x00000000ead60000,0x00000000eb1de278,0x00000000eb740000)
  from space 128K, 75% used [0x00000000eb770000,0x00000000eb788000,0x00000000eb790000)
  to   space 1152K, 0% used [0x00000000eb860000,0x00000000eb860000,0x00000000eb980000)
 PSOldGen        total 43392K, used 23839K [0x00000000c0800000, 0x00000000c3260000, 0x00000000ead60000)
  object space 43392K, 54% used [0x00000000c0800000,0x00000000c1f47f00,0x00000000c3260000)
 PSPermGen       total 21248K, used 12322K [0x00000000bb600000, 0x00000000bcac0000, 0x00000000c0800000)
  object space 21248K, 57% used [0x00000000bb600000,0x00000000bc208830,0x00000000bcac0000)

Code Cache  [0x0000000002470000, 0x00000000026f0000, 0x0000000005470000)
 total_blobs=1022 nmethods=599 adapters=376 free_code_cache=47801344 largest_free_block=16000

Dynamic libraries:
0x0000000000400000 - 0x000000000042e000     C:\Windows\system32\java.exe
0x00000000774b0000 - 0x0000000077659000     C:\Windows\SYSTEM32\ntdll.dll
0x0000000077020000 - 0x000000007713f000     C:\Windows\system32\kernel32.dll
0x000007fefda00000 - 0x000007fefda6c000     C:\Windows\system32\KERNELBASE.dll
0x000007feff4e0000 - 0x000007feff5bb000     C:\Windows\system32\ADVAPI32.dll
0x000007feff6a0000 - 0x000007feff73f000     C:\Windows\system32\msvcrt.dll
0x000007fefe490000 - 0x000007fefe4af000     C:\Windows\SYSTEM32\sechost.dll
0x000007fefe4b0000 - 0x000007fefe5dd000     C:\Windows\system32\RPCRT4.dll
0x000000006d7f0000 - 0x000000006dfa8000     C:\Program Files\Java\jre6\bin\server\jvm.dll
0x0000000076dd0000 - 0x0000000076eca000     C:\Windows\system32\USER32.dll
0x000007feff740000 - 0x000007feff7a7000     C:\Windows\system32\GDI32.dll
0x000007fefde60000 - 0x000007fefde6e000     C:\Windows\system32\LPK.dll
0x000007fefdd10000 - 0x000007fefddd9000     C:\Windows\system32\USP10.dll
0x000007fefb970000 - 0x000007fefb9ab000     C:\Windows\system32\WINMM.dll
0x000007fefdce0000 - 0x000007fefdd0e000     C:\Windows\system32\IMM32.DLL
0x000007fefe5e0000 - 0x000007fefe6e9000     C:\Windows\system32\MSCTF.dll
0x000000006d760000 - 0x000000006d76e000     C:\Program Files\Java\jre6\bin\verify.dll
0x000000006d3b0000 - 0x000000006d3d7000     C:\Program Files\Java\jre6\bin\java.dll
0x000000006d7b0000 - 0x000000006d7c2000     C:\Program Files\Java\jre6\bin\zip.dll
0x000000006d000000 - 0x000000006d1c3000     C:\Program Files\Java\jre6\bin\awt.dll
0x000007fefb9b0000 - 0x000007fefba21000     C:\Windows\system32\WINSPOOL.DRV
0x000007fefdf80000 - 0x000007fefe183000     C:\Windows\system32\ole32.dll
0x000007fefe750000 - 0x000007feff4d8000     C:\Windows\system32\SHELL32.dll
0x000007fefdde0000 - 0x000007fefde51000     C:\Windows\system32\SHLWAPI.dll
0x000007fefc3b0000 - 0x000007fefc5a4000     C:\Windows\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.7601.17514_none_fa396087175ac9ac\COMCTL32.dll
0x000007fefbd70000 - 0x000007fefbd88000     C:\Windows\system32\DWMAPI.DLL
0x000007fefc1d0000 - 0x000007fefc226000     C:\Windows\system32\uxtheme.dll
0x000000006d2a0000 - 0x000000006d306000     C:\Program Files\Java\jre6\bin\fontmanager.dll
0x000007fefd840000 - 0x000007fefd84f000     C:\Windows\system32\CRYPTBASE.dll
0x000007feee310000 - 0x000007feee50f000     C:\Windows\system32\d3d9.dll
0x000007fefca70000 - 0x000007fefca7c000     C:\Windows\system32\VERSION.dll
0x000007fefbad0000 - 0x000007fefbad7000     C:\Windows\system32\d3d8thk.dll
0x000007feea170000 - 0x000007feeaabb000     C:\Windows\system32\nvd3dumx.dll
0x000007fefbb00000 - 0x000007fefbb2c000     C:\Windows\system32\powrprof.dll
0x000007fefe210000 - 0x000007fefe3e7000     C:\Windows\system32\SETUPAPI.dll
0x000007fefd9c0000 - 0x000007fefd9f6000     C:\Windows\system32\CFGMGR32.dll
0x000007feff5c0000 - 0x000007feff697000     C:\Windows\system32\OLEAUT32.dll
0x000007fefdcc0000 - 0x000007fefdcda000     C:\Windows\system32\DEVOBJ.dll
0x000000006d510000 - 0x000000006d53e000     C:\Program Files\Java\jre6\bin\jsound.dll
0x000007fefbd90000 - 0x000007fefbddb000     C:\Windows\system32\MMDevAPI.DLL
0x000007fefc230000 - 0x000007fefc35c000     C:\Windows\system32\PROPSYS.dll
0x000007fef3590000 - 0x000007fef35cb000     C:\Windows\system32\wdmaud.drv
0x0000000074b10000 - 0x0000000074b16000     C:\Windows\system32\ksuser.dll
0x000007fefbea0000 - 0x000007fefbea9000     C:\Windows\system32\AVRT.dll
0x000007fefb5c0000 - 0x000007fefb60f000     C:\Windows\system32\AUDIOSES.DLL
0x000007fef40f0000 - 0x000007fef40fa000     C:\Windows\system32\msacm32.drv
0x000007fef40d0000 - 0x000007fef40e8000     C:\Windows\system32\MSACM32.dll
0x000007fef3580000 - 0x000007fef3589000     C:\Windows\system32\midimap.dll
0x000007fefe3f0000 - 0x000007fefe489000     C:\Windows\system32\CLBCatQ.DLL
0x0000000010000000 - 0x0000000010065000     C:\Program Files\WIDCOMM\Bluetooth Software\btmmhook.dll
0x0000000077670000 - 0x0000000077677000     C:\Windows\system32\PSAPI.DLL
0x000000006d600000 - 0x000000006d617000     C:\Program Files\Java\jre6\bin\net.dll
0x000007fefdf30000 - 0x000007fefdf7d000     C:\Windows\system32\WS2_32.dll
0x000007feff7b0000 - 0x000007feff7b8000     C:\Windows\system32\NSI.dll
0x000007fefd140000 - 0x000007fefd195000     C:\Windows\system32\mswsock.dll
0x000007fefd130000 - 0x000007fefd137000     C:\Windows\System32\wship6.dll
0x000000006d620000 - 0x000000006d62b000     C:\Program Files\Java\jre6\bin\nio.dll
0x0000000009540000 - 0x0000000009571000     C:\Program Files\WIDCOMM\Bluetooth Software\btkeyind.dll

VM Arguments:
java_command: MyGameMain
Launcher Type: SUN_STANDARD

Environment Variables:
CLASSPATH=.;C:\Program Files (x86)\Java\jre6\lib\ext\QTJava.zip
PATH=C:\Program Files\Common Files\Microsoft Shared\Windows Live;C:\Program Files (x86)\PC Connectivity Solution\;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files\Broadcom\Broadcom 802.11\Driver;C:\Program Files\WIDCOMM\Bluetooth Software\;C:\Program Files\WIDCOMM\Bluetooth Software\syswow64;C:\Program Files\Java\jdk1.6.0_21\bin;C:\MinGW\bin;C:\Program Files (x86)\QuickTime\QTSystem\;C:\Windows\system32\wbem;C:\Program Files (x86)\IVT Corporation\BlueSoleil\Mobile;c:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\;c:\Program Files\Microsoft SQL Server\100\Tools\Binn\;c:\Program Files\Microsoft SQL Server\100\DTS\Binn\;C:\Program Files\Common Files\Microsoft Shared\Windows Live
USERNAME=***********
OS=Windows_NT
PROCESSOR_IDENTIFIER=Intel64 Family 6 Model 23 Stepping 6, GenuineIntel



---------------  S Y S T E M  ---------------

OS: Windows 7 , 64 bit Build 7601 Service Pack 1

CPU:total 2 (2 cores per cpu, 1 threads per core) family 6 model 23 stepping 6, cmov, cx8, fxsr, mmx, sse, sse2, sse3, ssse3, sse4.1

Memory: 4k page, physical 4160724k(2268648k free), swap 8319600k(5448724k free)

vm_info: Java HotSpot(TM) 64-Bit Server VM (20.4-b02) for windows-amd64 JRE (1.6.0_29-b11), built on Oct  3 2011 01:06:42 by "java_re" with MS VC++ 8.0 (VS2005)

time: Sat Feb 04 09:25:56 2012
elapsed time: 145 seconds

The log files suggest that the crash is happening during the sound threads when a sound finishes and calls SourceDataLine.drain() to get rid of any remaining data in the sound's buffer. I'm not sure what I'm doing wrong for this to cause my tester's jre to crash mid-game though...

Any insight from you sound/threading gurus out there would be helpful.

Upvotes: 2

Views: 2206

Answers (4)

Steve Caughey
Steve Caughey

Reputation: 21

Probably too late for any help for you but just in case anyone else is interested -

In SoundThread::run you're checking bytesRead but if stream.read returns zero (and maybe it shouldn't) then you're stuck in an infinite loop.

This may depend on the precise length of the sound being played and may explain why one person only is seeing the problem.

Upvotes: 2

Cazra
Cazra

Reputation: 143

This problem has remained unresolved. In conclusion, the problem is likely inherent in the machine(s) that the problem is occurring on and is probably not worth pursuing any further in native Java.

Upvotes: 0

Phil Freihofner
Phil Freihofner

Reputation: 7910

This is enough of a different answer that I'm not going to revise the previous suggestion about writing a custom Clip (which a valid albeit very different approach).

BTW: I was confused by the use of the variable name 'clip' for a SourceDataLine. Really should refactor that sort of thing!

OK. Looking at your code, you omit three steps that I include on an app where I play back overlapping SDL's.

line.drain();
line.stop();
line.close();
line = null;

aiStream.close();
aiStream = null;

where "line" is a SourceDataLine, and aiStream is the AudioInputStream.

I think setting these to null might be the key steps. Not sure how important the omitted stop() step is. And I couldn't tell you exactly why this is needed, but it made a difference in my app.

Upvotes: 0

Phil Freihofner
Phil Freihofner

Reputation: 7910

At the risk of getting dinged for not answering your question directly, I would like to make a suggestion. It is possible to create a custom "Clip" object that allows both multiple playback and playback at varying speeds. If the ClipTrack (my name for it) has multiple cursors, their outputs can be summed and sent out as a single audio value.

I demonstrate the use of such here: ClipTrack

There are links on that site that point to the Java code, posted at Java-Gaming.org, which you are welcome to use. But you'll probably want to edit the source code a LOT. I know I have since originally posting it. I am only an intermediate level Java programmer, and am teaching myself about sound. There are many things that should be done differently (the object "hands off" data to a mixer I wrote rather than playing it directly--but you can rewrite that, also the use of a CopyOnWriteArrayList is probably not optimal, if a totally non-blocking method of managing the cursors can be designed).

But, at least the basic idea can be seen there. :)

The potential gains of this approach include reducing the number of threads. Also, you will never have more than one copy of the raw audio data in memory at one time (as opposed to making multiple copies in all your Clips).

I have found working with javax.sound Clips very annoying and am happy to no longer be tangling with them.

Upvotes: 0

Related Questions