1

My app uses some short sounds for user feedback. I use the following code:

private void playSound(String fileName) {
    try {
        FileSystemStorage fss = FileSystemStorage.getInstance();
        String sep = fss.getFileSystemSeparator() + "";
        String soundDir; // sounds must be in a directory
        if (fss.getAppHomePath().endsWith(sep)) {
            soundDir = fss.getAppHomePath() + "sounds"; // device
        } else {
            soundDir = fss.getAppHomePath() + sep + "sounds"; // simulator/windows
        }
        if (!fss.exists(soundDir)) {
            // first time a sound is played: create directory
            fss.mkdir(soundDir);
        }
        String filePath = soundDir + sep + fileName;
        if (!fss.exists(filePath)) {
            // first time this sound is played: copy from resources (place file in <project>/src)
            InputStream  is = Display.getInstance().getResourceAsStream(getClass(), "/" + fileName);
            OutputStream os = fss.openOutputStream(filePath);
            com.codename1.io.Util.copy(is, os);
        }
        Media media = MediaManager.createMedia(filePath, false);
        //media.setVolume(100);
        media.play();
    } catch (IOException ex) {
        log("Error playing " + fileName + " " + ex.getMessage());
    }
}

Example call:

playSound("error.mp3");

This works fine on devices and in the simulator. However, if I do a long automatic test in the simulator (using Windows), playing a sound about every second, this eats up all the RAM until Windows crashes. The Windows task manager, however, shows no exceptional memory usage of NetBeans and the Java process.

So my questions are: Is my code correct? Can this happen on devices too? Or else is there a way to prevent this in the simulator/Windows?

P.S.

I also tried the code from How to bundle sounds with Codename One?. That has the same problem and also some sounds get lost (are not played).

I also tried the simple code from Codename One - Play a sound but that doesn't work.

J-J
  • 419
  • 2
  • 12

1 Answers1

1

We generally recommend keeping the Media instance for this sort of use case. But if you can't just make sure to call cleanup when you're done:

MediaManager.addCompletionHandler(media, () -> media.cleanup());
media.play();
Shai Almog
  • 51,749
  • 5
  • 35
  • 65
  • Thanks, adding MediaManager.addCompletionHandler(media, () -> media.cleanup()); works. I don't understand how keeping the media instance would help, since you cannot play it twice, says the Javadoc (I tried it and it does work in the simulator but not on an Android device). – J-J May 23 '21 at 18:36
  • The Javadoc also says 'that an audio is "auto destroyed" on completion' but you still need to clean it up, apparently. So I suggest to improve the documentation on this subject. – J-J May 23 '21 at 18:45
  • This was historically the case and was changed based on user feedback as users wanted the ability to reuse media. I guess those places were missed in the change. I fixed this in the javadoc. Thanks! – Shai Almog May 24 '21 at 01:35