Search code examples
javaeclipseswtjlayer

JLayer Player overwrites refesh of SWT widgets when placed in a loop


I am attempting to make an application that retrieves images and .mp3 files and transitions from one image to the next once the audio has finished. The underlying framework of how I transition between these images is a little convoluted, but I have managed to get an action in SWT that successfully enables me to manually transition from one to the next. However, a problem has arisen when I've tried to automate it; when placed into a loop, my playAudio() method begins before all of the calls I make in my displayShow() method have resolved, which results in a blank window, despite the audio still playing.

Here is the run method for the action that I want to start the show:

            Action startAction = new Action("Start") {
            public void run() {

                //do {
                    displayShow();
                    playAudio();
                //} while(true);            
            }
        };

Here is playAudio(). I am able to PLAY the audio without incident:

    public void playAudio() {

    final String audio = "Happy_Birthday.mp3";
    audioLatch = new CountDownLatch(1);
    audioThread = new Thread() {
        public void run() {

            try {               
                Player player = new Player
                                    (new BufferedInputStream
                                        (new FileInputStream(audio)));

                player.play();  
                audioLatch.countDown();

            } catch (JavaLayerException e) {

            } catch (FileNotFoundException e) {

            } catch (Exception e) {

            }
        }   
    };
    audioThread.start();
    try {
        audioLatch.await();
    } catch (InterruptedException e) {

    }   
}

And here is displayShow():

    private void displayShow() {

    new Thread() {
        public void run() {
            Display.getDefault().asyncExec(new Runnable() {
                public void run() {
                    Control[] children = container.getChildren();

                    for (int i = 0; i < children.length; i++) {
                        children[i].dispose();
                    }

                    show.showSlide(container);
                    container.layout();
                }
            });
        }
    }.start();
}

show.showSlide returns a composite whose parent is container, which is the immediate child of the highest parent composite. Within the newly created composite, an image is added to a label and the label's parent is assigned to composite. I realize whether displayShow() is in a separate thread or not seems to be immaterial; this was just the last thing I tried.

It is not solely the addition of the loop that causes the refresh to not execute. The only way I can get the manual transition to work is if I remove the CountDownLatch from the playAudio() method. Were I to remove this latch, the only way to encase these two methods in a loop would be embedded while loops, which seem to hog a fair amount of the CPU and still does not solve my problem. Am I missing anything?


Solution

  • The audioLatch.await() is blocking the main program thread, this is the thread that all SWT operations run on so the Display.asyncExec runnables are just being queued until the thread is available.

    If you really must wait in the playAudio method you could run the display event loop there until the background thread is finished:

    while (! background thread finished)
     {
       if (!display.readAndDispatch())
         display.sleep();
     }