用于声音管理的Java ThreadPoolExecutor表现出特殊的bug

时间:2014-03-12 02:01:37

标签: java audio threadpoolexecutor

我创建了一个扩展Java的ThreadPoolExecutor的类,它使用它的线程来播放声音。此执行程序接收我创建的Sound类的对象,以允许一些基本操作(循环,暂停,恢复)。乍一看似乎完美无缺,除了一件事:如果我在Sound类的代码中删除了System.out.println调用(如下所示),我的声音可以暂停,但是他们拒绝恢复。如果我让println进入,恢复工作将完美无缺。

SoundController类

public class SoundController extends ThreadPoolExecutor
{
    public SoundController()
    {
        super(2, Integer.MAX_VALUE, 60, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
        setThreadFactory(new SoundThreadFactory());
        prestartAllCoreThreads();
    }

    @Override
    protected void beforeExecute(Thread thread, Runnable target)
    {
        super.beforeExecute(thread, target);

        Sound sound = (Sound) target;
        SoundThread soundthread = (SoundThread) thread;

        sound.setLine(soundthread.getLine());
        soundthread.setPriority(sound.getPriority());
    }

    protected static class SoundThreadFactory implements ThreadFactory
    {
        @Override
        public SoundThread newThread(Runnable target)
        {
            return new SoundThread(target);
        }
    }

    // When a new thread is created, create a new sound line for it to use.
    private static class SoundThread extends Thread
    {
        private SourceDataLine line;

        public SoundThread(Runnable target)
        {
            super(target);
            setDaemon(true);

            AudioFormat format = Core.loader().getSoundFormat();
            int buffersize = Core.loader().getSoundBufferSize();

            try
            {
                line = AudioSystem.getSourceDataLine(format);
                line.open(format, buffersize);
                line.start();
            }
            catch (LineUnavailableException e)
            {
                Core.loader().logException(e);
            }
        }

        public SourceDataLine getLine()
        {
            return line;
        }
    }
}

声音等级

public class Sound implements Runnable
{
    private enum SoundState
    {
        IDLE,
        FINISHED,
        PAUSED,
        PLAYING,
    }

    private String url;
    private int loopcount, priority;

    private SourceDataLine line;
    private SoundState state;

    /**
     * Creates a new Sound.
     * @param url the sound's url
     * @param loopcount the sound's loop count
     * @param priority the sound's priority
     */
    public Sound(String url, int loopcount, int priority)
    {
        this.url = url;
        this.loopcount = loopcount;
        this.priority = priority;
        state = SoundState.IDLE;
    }

    /**
     * Returns the priority of the sound.
     * @return returns the sound's priority
     */
    public int getPriority()
    {
        return priority;
    }

    /**
     * Checks whether the sound has been paused.
     * @return returns true if the sound is paused
     */
    public boolean isPaused()
    {
        return state == SoundState.PAUSED;
    }

    /**
     * Changes the data line to play the sound on.
     * @param line a new source data line
     */
    public void setLine(SourceDataLine line)
    {
        this.line = line;
    }

    /**
     * Pauses the sound.
     */
    public void pause()
    {
        state = SoundState.PAUSED;
    }

    /**
     * Unpauses the sound.
     */
    public void unpause()
    {
        state = SoundState.PLAYING;
    }

    /**
     * Starts the sound.
     */
    public void start()
    {
        // Equal to soundcontroller.execute(this)
        Core.fireEvent(new Engine.AddSoundEvent(this));
    }

    /**
     * Stops the sound.
     */
    public void stop()
    {
        state = SoundState.FINISHED;
    }

    @Override
    public void run()
    {       
        AudioFormat format = Core.loader().getSoundFormat();
        int buffersize = Core.loader().getSoundBufferSize();
        byte[] buffer = new byte[buffersize];
        state = SoundState.PLAYING;
        int loop = loopcount;

        while(state != SoundState.FINISHED)
        {
            try(AudioInputStream filestream = AudioSystem.getAudioInputStream(new File(url)))
            {   
                try(AudioInputStream stream = AudioSystem.getAudioInputStream(format, filestream))
                {
                    int bytecount = 0;
                    while(bytecount != -1)
                    {
                        // REMOVING THIS CALL RESULTS IN THE SOUND FAILING TO RESUME!
                        System.out.println(state);
                        if(state == SoundState.PLAYING)
                        {
                            bytecount = stream.read(buffer, 0, buffer.length);
                            if(bytecount != -1)
                            {
                                line.write(buffer, 0, bytecount);
                            }
                        }                           
                    }   
                }
            }
            catch(Exception e) 
            {
                Core.loader().logException(e);
            }

            if(loop != -1)
            {
                loop--;
                if(loop == 0)
                {
                    state = SoundState.FINISHED;
                }
            }
        }
    }
}

0 个答案:

没有答案