1

I am trying to play mp3's in my java application. The user has the ability to click a button and change the sound.

The sound and switching works...however when a user tries to switch sounds, the new song begins playing over the old one for about a second, before the old one stops playing. I am trying use threads to handle everything.

My MP3 class:

import java.applet.*;
import javazoom.jl.player.Player;
import java.io.*;
import java.io.FileInputStream;
import java.net.*;

public class mp3 extends Thread implements Runnable{

    private Player sound;
    private InputStream path;  
    public mp3(String file_name) {
        path = mp3.class.getClassLoader().getResourceAsStream(file_name);  
    }
    public void run(){
        try {
            Player sound=new Player(path);
            sound.play();
        } catch(Exception e) {System.out.println(e);}
    }
}

And this is how I attempt to run the code in my main game. The MP3 object is called song.

When the application initializes, the following code is run:

song = new mp3("default.mp3");
song.start();

somebody tries to change it, the following code is run:

song.stop();
song = new mp3(t+".mp3");
song.start();

Where t is a parameter of the file name.

I'm pretty sure the problem relies in the run function of the MP3 object. I am completely new to threading so I would appreciate some help.

Again, the delay is about 1 second from the time "stop" is called and the time it actually stops playing. So maybe throw a wait in there somewhere?

Thanks!

EDIT: I am using code based off of here now:

http://introcs.cs.princeton.edu/java/faq/mp3/MP3.java.html

I have created a play and close function defined as follows:

    public void close() { if (player != null) player.close(); }

    // play the MP3 file to the sound card
    public void play() {
        try {
            FileInputStream fis     = new FileInputStream(filename);
            BufferedInputStream bis = new BufferedInputStream(fis);
            player = new Player(bis);
        } catch (Exception e) {
            System.out.println("Problem playing file " + filename);
            System.out.println(e);
        }

        // run in new thread to play in background
        new Thread() {
            public void run() {
                try { player.play(); }
                catch (Exception e) { System.out.println(e); }
            }
        }.start();

My problem is with the close function...the player object is always null and the close function does not execute...even though the play function initializes it. Why is it null?

Gray
  • 115,027
  • 24
  • 293
  • 354
Katherine Perotta
  • 125
  • 1
  • 5
  • 15
  • 1
    `Thread.stop()` is a deprecated method and should not be used. – Gray Apr 17 '12 at 05:09
  • You might have better luck with [`Clip`](http://docs.oracle.com/javase/7/docs/api/javax/sound/sampled/Clip.html) or [`BigClip`](http://stackoverflow.com/a/9470886/418556). – Andrew Thompson Apr 17 '12 at 08:33
  • Either extend Thread or implement Runnable. There's no need to do both. Shutting the thread is most probably NOT the correct way to immediately stop the sound. There should be some method provided by Javazoom's Player. If there isn't, then that is a defect of their object. Also, each instance of the Player should probably be in its own thread, rather than attempting to reuse. – Phil Freihofner Apr 18 '12 at 04:41
  • I'ved edited my answer. You need to make `player` `volatile` if it being accessed by multiple threads. – Gray Apr 18 '12 at 14:35

1 Answers1

1

Edit:

In your edit, if multiple threads are accessing the player field then it should be made volatile. Without seeing how player is defined, it's hard to guess at the problem otherwise.


I think that you will need to make sure that the Player has completed the previous mp3 before you start the next. Looking the javadocs for Player I see:

`player.isComplete()`

To quote:

Returns true if all available MPEG audio frames have been decoded, or false otherwise

If you want to stop the previous audio when the new sound starts you should use close() on the older player.

Closes this player. Any audio currently playing is stopped immediately

Sounds to me that you need to close the current running Player object (if any) and start a new Player object to play the new sound. If you are doing this in multiple threads then you will need to do something like:

  1. lock some final Object lock object
  2. if you want the current sound to finish, check the current Player object (if any) has completed in a loop with sleep
  3. close() the current Player object and create a new Player if you want to kill the current sound
  4. call play() the next mp3,
  5. unlock the lock object.

As far as I know, the play() method does not wait for the sound to be played but returns immediately after loading the sound into the audio buffers. I'm not sure what happens if the audio file is large though.

Gray
  • 115,027
  • 24
  • 293
  • 354
  • Thanks for the response. I tried creating a function that calls sound.close when I need to change the sound. However, after changing the sound file, it seems to prevent that sound from being used again. I get a null pointer exception. Is close() some kind of destructor? – Katherine Perotta Apr 17 '12 at 05:32
  • It could be @Katherine. Yeah, looking at the doc you may have to create a new `Player` object. I've changed my answer a bit to compensate for that. – Gray Apr 17 '12 at 13:36