Como reproduzir arquivo de som em Java de forma eficiente?

Eu já fiz uso de 2 classes para reprodução de som em Java(AudioClip e Clip), Recentemente usei
a classe Clip junto ao AudioInputStream para ter mais controle sobre a reprodução. Agora o problema
que tive em ambas é: o programa consome muito CPU e memória RAM, nesta última classe isso acontece quando eu crio muitas instâncias e reproduzo em uma frequência alta, a memória é alocada, mas só uma pequena parte é liberada, mesmo depois do fim das reproduções. Tentei resolver chamando o close() das classes Clip e AudioInputStream ao fim da reprodução de cada som. Liberou um pouco mais de memória, mas não chega nem perto de liberar tudo que foi alocado, antes das chamadas ao close() chegava a consumir 400MB de Ram, agora consome 100MB, mas aplicação sem o áudio consome só uns 25MB. Gostaria de saber como liberar a memória após a reprodução, e também como reduzir o consumo da CPU.

Boa tarde, você tem que ver se está declarando muita variável, se o problema realmente está na classe do aúdio, já tentou depurar pra ver o perfil do projeto? Onde mais faz requisições?

Já desabilitei(comentei os métodos da classe de áudio), e melhorou muito a performance. Foi de 400MB de RAM, para 25MB sem o áudio. Com o áudio, ele ocupa a memória RAM conforme crio instâncias da minha classe de áudio. Inicialmente ocupa pouco, mas daí vai acumulando, quando passei a fechar os streams ele chega no máximo a uns 100MB, mas ainda é muito, tendo em vista que inicialmente não é isso tudo. Basicamente sempre que um áudio é reproduzido ele cria uma instância, após encerrar ele fecha os steam de áudio. Mas ainda sim acumula espaço alocado na RAM.

Entendi. Você está usando a classe Timer?

Manda o código pra a gente dar uma analisada!

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package demo;

import java.io.IOException;
import java.net.URL;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineListener;

/**
 *
 * @author João Hudson
 */
public class PlayerSound {
    
    private Clip player;
    private AudioInputStream stream;
    private boolean finished;
    
    /**
     * Cria um PlayerSound para reproduzir um
     * arquivo de áudio específico.
     * 
     * @param url A URL para o arquivo de áudio. 
     */
    public PlayerSound(URL url)
    {
        finished = false;
        try
        {
            stream = AudioSystem.getAudioInputStream(url);
            player = AudioSystem.getClip();
            player.open(stream);
            player.addLineListener(new Finisher());
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }
    
    /**
     * Inicia a reprodução do áudio
     * de onde ela parou.
     */
    public void play()
    {
        if(!finished)
            player.loop(0);
    }
    
    /**
     * Reproduz o áudio repetidamente.
     */
    public void loop()
    {
        if(!finished)
            player.loop(Clip.LOOP_CONTINUOUSLY);
    }
    
    /**
     * Pausa a reprodução.
     */
    public void pause()
    {
        if(!finished)
            player.stop();
    }
    
    /**
     * Encerra a reprodução
     */
    public synchronized void stop()
    {
        if(!finished)
        {
            player.stop();
            finished = true;
        }
    }
    
    /**
     * Altera o ponto da reprodução para o tempo especificado.
     * 
     * @param time O tempo da reprodução.
     */
    public void setTime(long time)
    {
        if(!finished)
            player.setMicrosecondPosition(time);
    }
    
    /**
     * Obtém o tempo atual da reprodução.
     * 
     * @return O tempo atual da reprodução.
     */
    public long getTime()
    {
        if(!finished)
            return player.getMicrosecondPosition();
        
        return 0;
    }
    
    /**
     *  Fecha os streams de áudio.
     */
    private void close()
    {
        try
        {
            player.flush();
            player.close();
            stream.close();
            player = null;
            stream = null;
        }
        catch(IOException e)
        {
            e.printStackTrace();
        }
    }
    
    //Fecha os streams de áudio ao serem encerrados:
    private class Finisher implements LineListener
    {

        @Override
        public void update(LineEvent event) 
        {
            //se o áudio foi encerrado...
            if(event.getType() == LineEvent.Type.STOP)
            {
                close();
            }
        }
        
    }
}

Você usa todos os recursos? Eu uso assim, e na hora de tocar som, teve uma alteração de 1mb

public void tocarSomErro() {
        try {
            // Carrega o arquivo de áudio (não funciona com .mp3, só .wav)
            File diretorio = new File("caminho");
            //URL oUrl = new URL("http://www.soundjay.com/button/beep-02.wav");
            oClip = AudioSystem.getClip();
            AudioInputStream oStream = AudioSystem.getAudioInputStream(diretorio);
            oClip.open(oStream);

            oClip.loop(0); // Toca uma vez
            //clip.loop(Clip.LOOP_CONTINUOUSLY); // Toca continuamente (para o caso de músicas)

        } catch (LineUnavailableException | IOException | UnsupportedAudioFileException ex) {
           oClip.flush(); //Ele da uma despejada simples na memoria
    }

Eu instancio aquela classe varias vezes em um curto intervalo de tempo, vou testar do jeito que você fez. Mas parece ser igual de certa forma, também usei o flush(), e ainda usei o close(). Ex.: reproduzir o som de um projétil a cada tiro, isso acaba acumulando memória a cada objeto de som instanciado, cada um tem o seu próprio para reproduzir simultaneamente.

1 curtida

Se eu chamasse o .close, o meu som nem tocava

Vish.

Usar bibliotecas externas não é opção?

estou com o mesmo problema, vc conseguiu resolver?

Deveria ter somente uma instância de cada som e aí reproduzir o mesmo objeto.