Song plays first time, but doesn't play once: clip in Java

I am using Clip in java to play a song like this:

        MR.clip= (Clip) AudioSystem.getLine(MR.info[docIdOfSelectedSong]);
        MR.clip.open(MR.sounds[docIdOfSelectedSong]);
        MR.clip.setMicrosecondPosition(5* 1000000);
        MR.clip.start();

      

where MR.sounds is an array of type AudioInputStream

and MR.info is an array of type DataLine.info

. When I click the button the above code is called to play the song. Also, I have another button to stop the song that calls the below code

public static void stopSong(){

    MR.clip.close();

}

      

The problem is that when I play the song for the first time, the play and stop button works fine. But when I try to play this song a second time, I can't hear the song. Any suggestions on what is going wrong?

+3


source to share


4 answers


Like all other InputStreams, an AudioInputStream can only be read once (if it cannot be . Reset () ). You can try calling .reset () on the AudioInputStream before trying to play the sound again, but AudioInputStream may not support .reset (). InputStreams are not required to support reset. Also see markSupported () .

If .reset () doesn't work then consider creating a new AudioInputStream every time you need to start playing.




UPDATE: I made an example of caching audio data in memory and used Clip to play those sounds. This example uses AudioInputStream.reset (). So how can this work? In fact, AudioInputStream supports reset () if and only if the underlying InputStream supports .reset (). So my example creates an AudioInputStream which is backed by a ByteArrayInputStream. Since ByteArrayInputStream supports reset, these cached AudioInputStreams also support .reset (), allowing them to be reused.

Note that if you are going to play any one cached audio at the same time, you probably shouldn't cache AudioInputStream

s, but rather cache byte[]

and build AudioInputStream

for each play. This is due to the fact that it AudioInputStream

has state, so passing one instance from it to two simultaneously executing clips or discarding the stream during one click playback will result in a state conflict.

public class CachedSoundClipTest
{
    static ArrayList<AudioInputStream> cachedSounds = 
        new ArrayList<AudioInputStream>();

    public static void main(String[] args) throws Exception
    {
        File[] audioFiles = new File("/audio_storage_directory").listFiles();
        for (File file : audioFiles)
        {
            AudioInputStream reusableAudioInputStream = 
                createReusableAudioInputStream(file);
            cachedSounds.add(reusableAudioInputStream);
        }

        while(true)
        {
            System.out.println("Press enter to play next clip");
            BufferedReader br = 
                new BufferedReader(new InputStreamReader(System.in));
            br.readLine();
            playCachedSound(0);
        }
    }

    private static void playCachedSound(int i) 
        throws IOException, LineUnavailableException
    {
        AudioInputStream stream = cachedSounds.get(i);
        stream.reset();
        Clip clip = AudioSystem.getClip();
        clip.open(stream);
        clip.start();
    }

    private static AudioInputStream createReusableAudioInputStream(File file) 
        throws IOException, UnsupportedAudioFileException
    {
        AudioInputStream ais = null;
        try
        {
            ais = AudioSystem.getAudioInputStream(file);
            byte[] buffer = new byte[1024 * 32];
            int read = 0;
            ByteArrayOutputStream baos = 
                new ByteArrayOutputStream(buffer.length);
            while ((read = ais.read(buffer, 0, buffer.length)) != -1)
            {
                baos.write(buffer, 0, read);
            }
            AudioInputStream reusableAis = 
                new AudioInputStream(
                        new ByteArrayInputStream(baos.toByteArray()),
                        ais.getFormat(),
                        AudioSystem.NOT_SPECIFIED);
            return reusableAis;
        }
        finally
        {
            if (ais != null)
            {
                ais.close();
            }
        }
    }
}

      

+6


source


Focus to reset the clip's current position at the start.

clip.stop();
clip.setMicrosecondPosition(0);
clip.start();

      



With this method, there is no need to download the same resource multiple times. The clip only needs to be loaded once and stored as an instance variable or something.

+5


source


In the code example using Clip, you should use the stop () method instead of the close () method. Then, when you reboot, it will pick up where it left off. If you want to restart from the beginning, you can use setMicrosecondPosition () or setFramePosition () to 0 and use start ().

For details, see "Using the Clip" below.

http://docs.oracle.com/javase/tutorial/sound/playing.html

SourceDataLine can only be used once and cannot be reset. Yes?

+3


source


I had a similar issue on OS X where a clip would sometimes not play if you tried to stop it during playback and then restart it from the beginning. This was fixed by calling flush()

immediately after stop()

:

if(clip.isActive() || clip.isRunning()) {
    clip.stop();
    clip.flush();
}

      

Definitely don't use close()

, use stop()

if you want to play your clip again.

+1


source







All Articles