From b5da03468704a1d5a93dcc25523aeac5bf1cf142 Mon Sep 17 00:00:00 2001 From: silas Date: Mon, 1 Oct 2018 22:41:59 +0200 Subject: [PATCH] Audio im Background stop --- public/js/app.js | 141 ++++++++++++++++++++++++++++++++++----- src/js/lib/pwa-assets.js | 131 +++++++++++++++++++++++++++++++++--- src/js/lib/pwa-lib.js | 12 ++-- 3 files changed, 251 insertions(+), 33 deletions(-) diff --git a/public/js/app.js b/public/js/app.js index 9145988..016e83a 100755 --- a/public/js/app.js +++ b/public/js/app.js @@ -3167,11 +3167,11 @@ function applyPolyfills() { }; elem.addEventListener("transitionend", transEndLis); elem.addEventListener("transitioncancel", transCancelledLis); + //Fallback + setTimeout(() => { + resolve(false); + }, (time + delay) * 1000); }); - //Fallback - setTimeout(() => { - resolve(false); - }, (time+delay)*1000); //Nach Seitenneuzeichnen, damit chrome das immer macht (und FF auch) requestAnimationFrame(function () { @@ -3208,13 +3208,13 @@ function applyPolyfills() { elem.addEventListener("transitionend", transEndLis); elem.addEventListener("transitioncancel", transCancelledLis); - if (getComputedStyle(elem).getPropertyValue("opacity") === "1"){ + if (getComputedStyle(elem).getPropertyValue("opacity") === "1") { resolve(false); } //Fallback setTimeout(() => { resolve(false); - }, (time+delay)*1000); + }, (time + delay) * 1000); //Nach Seitenneuzeichnen, damit chrome das immer macht (und FF auch) requestAnimationFrame(function () { @@ -4812,6 +4812,96 @@ class ScaleHelper { } } +class AudioChain { + + constructor(context, sourceBuffer, chainFunction) { + this.buffer = sourceBuffer; + this.shouldLoop = false; + this.loopStart = null; + this.loopEnd = null; + this.chainFunction = chainFunction; + this.context = context; + + this.startTime = null; + this.pauseTime = null; + this.source = null; + } + + setBuffer(buffer) { + this.buffer = buffer; + } + + setLooping(shouldLoop, loopStart, loopEnd) { + this.shouldLoop = shouldLoop; + + if (Helper.isNotNull(loopStart)) { + this.loopStart = loopStart; + } + if (Helper.isNotNull(loopEnd)) { + this.loopEnd = loopEnd; + } + } + + async start(delay, offset, duration) + { + let source = this.context.createBufferSource(); + + source.loop = this.shouldLoop; + if (Helper.isNotNull(this.loopStart)) { + source.loopStart = this.loopStart; + } + if (Helper.isNotNull(this.loopEnd)) { + source.loopEnd = this.loopEnd; + } + source.buffer = this.buffer; + await this.chainFunction(source); + + source.start(delay, offset, duration); + this.startTime = (new Date()).getTime(); + this.source = source; + } + + async stop(delay){ + if (Helper.isNotNull(this.source)){ + this.pauseTime = ((new Date()).getTime())-this.startTime; + return this.source.stop(delay); + } + return null; + } + + async resume(){ + console.log("resume-Time:", Helper.nonNull(this.pauseTime, 0)/1000.0); + return this.start(null, Helper.nonNull(this.pauseTime, 0)/1000.0); + } +} + +class InitPromise$1 +{ + static addPromise(promise) + { + if (typeof promise === 'function') + { + let func = promise; + promise = InitPromise$1.mainPromise.then(function(app){ + return (func(app)); + }); + } + InitPromise$1.promises.push(promise); + } + + static resolve(app) + { + InitPromise$1.mainResolver(app); + return InitPromise$1.mainPromise.then(function(){ + return Promise.all(InitPromise$1.promises); + }); + } +} +InitPromise$1.promises = []; +InitPromise$1.mainPromise = new Promise(function(resolver){ + InitPromise$1.mainResolver = resolver; +}); + class SoundManager { static getInstance() { if (Helper.isNull(SoundManager.instance)) { @@ -4823,6 +4913,10 @@ class SoundManager { constructor() { this.channels = {}; this.context = new AudioContext(); + + window.addEventListener("visibilitychange", () => { + this.handleVisibilityChange(); + }); } set(options, channel) { @@ -4867,20 +4961,20 @@ class SoundManager { if (!this.channels[channel].muted) { let buffer = await this.channels[channel].loadedPromise; - let source = this.context.createBufferSource(); - let gain = this.context.createGain(); + let source = new AudioChain(this.context, buffer, (sourceNode) => { + let gain = this.context.createGain(); + gain.gain.value = this.channels[channel].volume; - source.buffer = buffer; - source.loop = this.channels[channel].loop; - gain.gain.value = this.channels[channel].volume; + sourceNode.connect(gain); + gain.connect(this.context.destination); + }); + + source.setBuffer(buffer); //to prevent gap in mp3-files - source.loopStart = 0.3; - source.loopEnd = buffer.duration-0.3; + source.setLooping(this.channels[channel].loop, 0.3, buffer.duration-0.3); - source.connect(gain); - gain.connect(this.context.destination); - source.start(0); + source.start(); this.channels[channel].source = source; } @@ -4899,6 +4993,21 @@ class SoundManager { channel = Helper.nonNull(channel, SoundManager.CHANNELS.DEFAULT); return this.channels[channel]; } + + handleVisibilityChange() { + if (document.hidden){ + for (let k in this.channels){ + this.channels[k].source.stop(); + } + } + else{ + for (let k in this.channels){ + if (!this.channels[k].muted){ + this.channels[k].source.resume(); + } + } + } + } } SoundManager.CHANNELS = { diff --git a/src/js/lib/pwa-assets.js b/src/js/lib/pwa-assets.js index 758e973..743c04e 100755 --- a/src/js/lib/pwa-assets.js +++ b/src/js/lib/pwa-assets.js @@ -233,6 +233,96 @@ class ScaleHelper { } } +class AudioChain { + + constructor(context, sourceBuffer, chainFunction) { + this.buffer = sourceBuffer; + this.shouldLoop = false; + this.loopStart = null; + this.loopEnd = null; + this.chainFunction = chainFunction; + this.context = context; + + this.startTime = null; + this.pauseTime = null; + this.source = null; + } + + setBuffer(buffer) { + this.buffer = buffer; + } + + setLooping(shouldLoop, loopStart, loopEnd) { + this.shouldLoop = shouldLoop; + + if (Helper.isNotNull(loopStart)) { + this.loopStart = loopStart; + } + if (Helper.isNotNull(loopEnd)) { + this.loopEnd = loopEnd; + } + } + + async start(delay, offset, duration) + { + let source = this.context.createBufferSource(); + + source.loop = this.shouldLoop; + if (Helper.isNotNull(this.loopStart)) { + source.loopStart = this.loopStart; + } + if (Helper.isNotNull(this.loopEnd)) { + source.loopEnd = this.loopEnd; + } + source.buffer = this.buffer; + await this.chainFunction(source); + + source.start(delay, offset, duration); + this.startTime = (new Date()).getTime(); + this.source = source; + } + + async stop(delay){ + if (Helper.isNotNull(this.source)){ + this.pauseTime = ((new Date()).getTime())-this.startTime; + return this.source.stop(delay); + } + return null; + } + + async resume(){ + console.log("resume-Time:", Helper.nonNull(this.pauseTime, 0)/1000.0); + return this.start(null, Helper.nonNull(this.pauseTime, 0)/1000.0); + } +} + +class InitPromise$1 +{ + static addPromise(promise) + { + if (typeof promise === 'function') + { + let func = promise; + promise = InitPromise$1.mainPromise.then(function(app){ + return (func(app)); + }); + } + InitPromise$1.promises.push(promise); + } + + static resolve(app) + { + InitPromise$1.mainResolver(app); + return InitPromise$1.mainPromise.then(function(){ + return Promise.all(InitPromise$1.promises); + }); + } +} +InitPromise$1.promises = []; +InitPromise$1.mainPromise = new Promise(function(resolver){ + InitPromise$1.mainResolver = resolver; +}); + class SoundManager { static getInstance() { if (Helper.isNull(SoundManager.instance)) { @@ -244,6 +334,10 @@ class SoundManager { constructor() { this.channels = {}; this.context = new AudioContext(); + + window.addEventListener("visibilitychange", () => { + this.handleVisibilityChange(); + }); } set(options, channel) { @@ -288,20 +382,20 @@ class SoundManager { if (!this.channels[channel].muted) { let buffer = await this.channels[channel].loadedPromise; - let source = this.context.createBufferSource(); - let gain = this.context.createGain(); + let source = new AudioChain(this.context, buffer, (sourceNode) => { + let gain = this.context.createGain(); + gain.gain.value = this.channels[channel].volume; - source.buffer = buffer; - source.loop = this.channels[channel].loop; - gain.gain.value = this.channels[channel].volume; + sourceNode.connect(gain); + gain.connect(this.context.destination); + }); + + source.setBuffer(buffer); //to prevent gap in mp3-files - source.loopStart = 0.3; - source.loopEnd = buffer.duration-0.3; + source.setLooping(this.channels[channel].loop, 0.3, buffer.duration-0.3); - source.connect(gain); - gain.connect(this.context.destination); - source.start(0); + source.start(); this.channels[channel].source = source; } @@ -320,6 +414,21 @@ class SoundManager { channel = Helper.nonNull(channel, SoundManager.CHANNELS.DEFAULT); return this.channels[channel]; } + + handleVisibilityChange() { + if (document.hidden){ + for (let k in this.channels){ + this.channels[k].source.stop(); + } + } + else{ + for (let k in this.channels){ + if (!this.channels[k].muted){ + this.channels[k].source.resume(); + } + } + } + } } SoundManager.CHANNELS = { @@ -393,4 +502,4 @@ class TabbedFragment extends Fragment { } } -export { DelayPromise, Matomo, RotateHelper, ScaleHelper, SoundManager, TabbedFragment }; +export { DelayPromise, Matomo, RotateHelper, ScaleHelper, AudioChain, SoundManager, TabbedFragment }; diff --git a/src/js/lib/pwa-lib.js b/src/js/lib/pwa-lib.js index a122e30..4fafd21 100755 --- a/src/js/lib/pwa-lib.js +++ b/src/js/lib/pwa-lib.js @@ -4155,11 +4155,11 @@ function applyPolyfills() { }; elem.addEventListener("transitionend", transEndLis); elem.addEventListener("transitioncancel", transCancelledLis); + //Fallback + setTimeout(() => { + resolve(false); + }, (time + delay) * 1000); }); - //Fallback - setTimeout(() => { - resolve(false); - }, (time+delay)*1000); //Nach Seitenneuzeichnen, damit chrome das immer macht (und FF auch) requestAnimationFrame(function () { @@ -4196,13 +4196,13 @@ function applyPolyfills() { elem.addEventListener("transitionend", transEndLis); elem.addEventListener("transitioncancel", transCancelledLis); - if (getComputedStyle(elem).getPropertyValue("opacity") === "1"){ + if (getComputedStyle(elem).getPropertyValue("opacity") === "1") { resolve(false); } //Fallback setTimeout(() => { resolve(false); - }, (time+delay)*1000); + }, (time + delay) * 1000); //Nach Seitenneuzeichnen, damit chrome das immer macht (und FF auch) requestAnimationFrame(function () {