Skip to content

Commit

Permalink
PlatformPlayer: Explicitly handle meta and line event listeners
Browse files Browse the repository at this point in the history
Don't let the JVM garbage collect the implicitly, as it can fail
to do so. Instead, hint at when they're apt to be GC'ed by explicitly
creating one per player, and marking it as unused on deallocate and
close.

Fixes memory leaks in Final Fantasy, and likely many others.
  • Loading branch information
AShiningRay committed Dec 9, 2024
1 parent f375963 commit d59812f
Showing 1 changed file with 62 additions and 26 deletions.
88 changes: 62 additions & 26 deletions src/org/recompile/mobile/PlatformPlayer.java
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,7 @@ private class midiPlayer extends audioplayer
private Sequencer midi;
private Sequence midiSequence;
private int numLoops = 0;
private MetaEventListener metaListener = null;

public midiPlayer() // For when a Locator call (usually for tones) is issued
{
Expand Down Expand Up @@ -479,24 +480,28 @@ public void start()
* We have to listen for END_OF_MEDIA events, or else jars that rely on this
* won't work in the expected way.
*/
midi.addMetaEventListener(new MetaEventListener()
if (metaListener == null)
{
@Override
public void meta(MetaMessage meta)
metaListener = new MetaEventListener()
{
if (meta.getType() == 0x2F) // 0x2F = END_OF_MEDIA in Sequencer
@Override
public void meta(MetaMessage meta)
{
state = Player.PREFETCHED;
notifyListeners(PlayerListener.END_OF_MEDIA, getMediaTime());
if(numLoops != 0)
if (meta.getType() == 0x2F) // 0x2F = END_OF_MEDIA in Sequencer
{
if(numLoops > 0) { numLoops--; } // If numLoops = -1, we're looping indefinitely
setMediaTime(0);
start();
state = Player.PREFETCHED;
notifyListeners(PlayerListener.END_OF_MEDIA, getMediaTime());
if(numLoops != 0)
{
if(numLoops > 0) { numLoops--; } // If numLoops = -1, we're looping indefinitely
setMediaTime(0);
start();
}
}
}
}
});
};
midi.addMetaEventListener(metaListener);
}
state = Player.STARTED;
notifyListeners(PlayerListener.STARTED, getMediaTime());
}
Expand All @@ -508,10 +513,23 @@ public void stop()
notifyListeners(PlayerListener.STOPPED, getMediaTime());
}

public void deallocate() { midi.close(); }
public void deallocate()
{
if(metaListener != null)
{
midi.removeMetaEventListener(metaListener);
metaListener = null;
}
midi.close();
}

public void close()
{
if (metaListener != null)
{
midi.removeMetaEventListener(metaListener);
metaListener = null;
}
midi.close();
midiSequence = null;
}
Expand Down Expand Up @@ -582,6 +600,7 @@ private class wavPlayer extends audioplayer
private Clip wavClip;
private int[] wavHeaderData = new int[4];
private int numLoops = 0;
private LineListener lineListener = null;

public wavPlayer(InputStream stream)
{
Expand Down Expand Up @@ -641,24 +660,28 @@ public void start()
wavClip.start();

/* Like for midi, we need to listen for END_OF_MEDIA events here too. */
wavClip.addLineListener(new LineListener()
if (lineListener == null)
{
@Override
public void update(LineEvent event)
lineListener = new LineListener()
{
if (event.getType() == LineEvent.Type.STOP)
@Override
public void update(LineEvent event)
{
state = Player.PREFETCHED;
notifyListeners(PlayerListener.END_OF_MEDIA, getMediaTime());
if(numLoops != 0)
if (event.getType() == LineEvent.Type.STOP)
{
if(numLoops > 0) { numLoops--; } // If numLoops = -1, we're looping indefinitely
setMediaTime(0);
start();
state = Player.PREFETCHED;
notifyListeners(PlayerListener.END_OF_MEDIA, getMediaTime());
if(numLoops != 0)
{
if(numLoops > 0) { numLoops--; } // If numLoops = -1, we're looping indefinitely
setMediaTime(0);
start();
}
}
}
}
});
};
wavClip.addLineListener(lineListener);
}

state = Player.STARTED;
notifyListeners(PlayerListener.STARTED, getMediaTime());
Expand All @@ -671,10 +694,23 @@ public void stop()
notifyListeners(PlayerListener.STOPPED, getMediaTime());
}

public void deallocate() { wavClip.close(); }
public void deallocate()
{
if (lineListener != null)
{
wavClip.removeLineListener(lineListener);
lineListener = null;
}
wavClip.close();
}

public void close()
{
if (lineListener != null)
{
wavClip.removeLineListener(lineListener);
lineListener = null;
}
wavClip.close();
wavClip = null;
wavStream = null;
Expand Down

0 comments on commit d59812f

Please sign in to comment.