CreateJS / SoundJS

A Javascript library for working with Audio. It provides a consistent API for loading and playing audio on different browsers and devices. Currently supports WebAudio, HTML5 Audio, Cordova / PhoneGap, and a Flash fallback.
http://createjs.com/
MIT License
4.42k stars 838 forks source link

How to pause all sounds when device is locked? #250

Open francescom opened 7 years ago

francescom commented 7 years ago

Thanks for Soundjs. and Createjs in general, I really like them. This is my issue: when users turn off their phone, my nice animated website goes on playing music and effects. That is ok if I have a way to pause them.

There should be a way to pause all sounds and restart them without knowing which sounds are playing, which are looping, what volume, at what point in time, etc.. for situations like when the main window goes off view or device is locked (standby button).

$(window).focus(function() {
    createjs.Sound.pauseAllSounds();
}).blur(function() {
    createjs.Sound.resumeAllSounds();
});

The problem is I don't have knowledge of what sounds are currently playing and what needs to be looping, and tracks volume, so if I just stop() how can I resume a situation similar to the one before the pause?

I have a list of all instances played since site startup. Maybe I could iterate all sound instances that have been started and, for each one, test if it is playing and if it is looping, maybe its position, and save all that info. Then stop() all sounds. Or pause them one by one. At resume, collect all sounds information and for each one issue a play (or remove paused state).

This sounds a bit complicated and more like it should be part of the library.

francescom commented 7 years ago

In the end, this is the code I used, JQuery is given for granted, but only for $(window).focus,$(window).blur, you can use DOM for that:

var playedSounds={};
// Here I save all sounds used
// playedSounds["soundId"]=createjs.Sound.play(id, ...);
// playedSounds["soundId"].stop();

$(window).focus(function() { 
    restoreAllSounds();
    restoreTimeline();
}); 

$(window).blur(function() { 
    pauseAllSounds();
    pauseTimeline();
}); 

var pausedSoundsInfo=[];
var isPaused=false;

function pauseAllSounds() {
    for(var id in playedSounds) if(playedSounds.hasOwnProperty(id)) {
        var theSoundInstance=playedSounds[id];
        var state=theSoundInstance.playState;
        if(
            // !theSoundInstance.paused && 

            state!= createjs.Sound.PLAY_INTERRUPTED
            && state!= createjs.Sound.PLAY_FAILED
            && state!= createjs.Sound.PLAY_FINISHED
        ) {
            pausedSoundsInfo.push(id);
            theSoundInstance.paused=true;
        }
    }
    isPaused=true;
}

function restoreAllSounds() {
    for(var i=0;i<pausedSoundsInfo.length;i++) {
        var id=pausedSoundsInfo[i];
        playedSounds[id].paused=false;
    }
    pausedSoundsInfo=[];
    isPaused=false;
}

function pauseTimeline() {
}
function restoreTimeline() {
}

// ...

// I play sounds only using this function that saves their instance in playedSounds

function playSound(id, loop) {
    playedSounds[id] = createjs.Sound.play(id, createjs.Sound.INTERRUPT_EARLY, 0, 0, loop);
    if(isPaused) {
        // if the sounds are paused (window is blurred), but playSound gets called...
        playedSounds[id].paused=true; // ...new sounds are created paused...
        pausedSoundsInfo.push(id); // ...and remembered (will play when window is focused)
    }
    return playedSounds[id];
}
function stopSound(id) {
    if(playedSounds.hasOwnProperty(id)) {
        playedSounds[id].stop();
    }
}

Not the cleanest code, it just seems to do the job for me. I definitely think this (or some pieces of it, or some other way to do it) should be part of the library as it could use Sound._instances to retrieve all sounds

lannymcnie commented 7 years ago

Might be a good idea to handle this in the library somehow. We don't necessarily want to mute/stop audio on blur() always -- but maybe on mobile we should do it.

Note to developer: We should flag the pre-muted/playing values so we don't unmute/resume on focus() if the user or app muted the audio themselves.

lannymcnie commented 7 years ago

Related to #208