ruffle-rs / ruffle

A Flash Player emulator written in Rust
https://ruffle.rs
Other
15.52k stars 805 forks source link

Destroying/removing the player does nothing while the player is loading #9233

Open GrantGryczan opened 1 year ago

GrantGryczan commented 1 year ago

Describe the bug

If the destroy method is called on a Ruffle player while it's loading the SWF, it does nothing. Furthermore, if the player is removed from the DOM while loading, that also does nothing.

Reproduction 1 (showing the issue occurs with calling destroy):

const ruffle = window.RufflePlayer.newest();
const player = ruffle.createPlayer();
document.body.appendChild(player);
player.load('https://file.garden/XCPqPLRNCCnrWl8t/rd/0171.swf');
player.destroy();

Reproduction 2 (showing the issue occurs with removing from DOM):

const ruffle = window.RufflePlayer.newest();
const player = ruffle.createPlayer();
document.body.appendChild(player);
player.load('https://file.garden/XCPqPLRNCCnrWl8t/rd/0171.swf');
document.body.removeChild(player);

In both these cases, you can hear the music from the Flash start playing despite the player supposedly being destroyed/removed. In my single-page web application, this race condition is easy to trigger if the user quickly switches pages after opening a page with a Flash embed using the Ruffle API on it, causing unstoppable music to play.

Expected behavior

At best, the destroy method should cancel the loading and destroy the player immediately. If that isn't feasible, it should automatically wait until the player finishes loading and then destroy the player (which is my current workaround.)

Additionally, to accommodate removing the player from the DOM, I would also expect the player to check if it's in the DOM when it finishes loading, and destroy the player if it isn't.

Affected platform

Self-hosted version

Operating system

Windows 10

Browser

Chrome 109

Additional information

No response

GrantGryczan commented 1 year ago

Note that I am not completely confident that the condition for this race condition to occur is precisely that the player is still loading while the player is destroyed/removed, since wrapping the removal/destruction code in setTimeout causes the issue not to occur. But it does seem to be a bug whether that's the condition for it or not.