diff --git a/lib/helpers/all-player-announcement.js b/lib/helpers/all-player-announcement.js index a55a1ce2..64f66132 100644 --- a/lib/helpers/all-player-announcement.js +++ b/lib/helpers/all-player-announcement.js @@ -39,90 +39,99 @@ function saveAll(system) { } function announceAll(system, uri, volume, duration) { - let abortTimer; + if (!(restrictParallelAnnouncements && announceAllActive)) { + // total time to group + play announcement + restore + const announceAllActiveTimeout = duration + systemGroupUngroupDuration; + announceAllActive = setTimeout(allPresetsRestored, announceAllActiveTimeout); + + let abortTimer; + + // Save all players + var backupPresets = saveAll(system); + + // find biggest group and all players + const allPlayers = []; + let biggestZone = {}; + system.zones.forEach(function (zone) { + if (!biggestZone.members || zone.members.length > biggestZone.members.length) { + biggestZone = zone; + } + }); - // Save all players - var backupPresets = saveAll(system); + const coordinator = biggestZone.coordinator; - // find biggest group and all players - const allPlayers = []; - let biggestZone = {}; - system.zones.forEach(function (zone) { - if (!biggestZone.members || zone.members.length > biggestZone.members.length) { - biggestZone = zone; - } - }); + allPlayers.push({ roomName: coordinator.roomName, volume }); - const coordinator = biggestZone.coordinator; + system.players.forEach(player => { + if (player.uuid == coordinator.uuid) return; + allPlayers.push({ roomName: player.roomName, volume }); + }); - allPlayers.push({ roomName: coordinator.roomName, volume }); + const preset = { + uri, + players: allPlayers, + playMode: { + repeat: false + }, + pauseOthers: true, + state: 'STOPPED' + }; - system.players.forEach(player => { - if (player.uuid == coordinator.uuid) return; - allPlayers.push({ roomName: player.roomName, volume }); - }); + const oneGroupPromise = new Promise((resolve) => { + const onTopologyChanged = (topology) => { + if (topology.length === 1) { + return resolve(); + } + // Not one group yet, continue listening + system.once('topology-change', onTopologyChanged); + }; - const preset = { - uri, - players: allPlayers, - playMode: { - repeat: false - }, - pauseOthers: true, - state: 'STOPPED' - }; - - const oneGroupPromise = new Promise((resolve) => { - const onTopologyChanged = (topology) => { - if (topology.length === 1) { - return resolve(); - } - // Not one group yet, continue listening system.once('topology-change', onTopologyChanged); - }; - - system.once('topology-change', onTopologyChanged); - }); + }); - const restoreTimeout = duration + 2000; - return system.applyPreset(preset) - .then(() => { - if (system.zones.length === 1) return; - return oneGroupPromise; - }) - .then(() => { - coordinator.play(); - return new Promise((resolve) => { - const transportChange = (state) => { - logger.debug(`Player changed to state ${state.playbackState}`); - if (state.playbackState === 'STOPPED') { - return resolve(); - } - - coordinator.once('transport-state', transportChange); - }; - setTimeout(() => { - coordinator.once('transport-state', transportChange); - }, duration / 2); - - logger.debug(`Setting restore timer for ${restoreTimeout} ms`); - abortTimer = setTimeout(resolve, restoreTimeout); + const restoreTimeout = duration + 2000; + return system.applyPreset(preset) + .then(() => { + if (system.zones.length === 1) return; + return oneGroupPromise; + }) + .then(() => { + coordinator.play(); + return new Promise((resolve) => { + const transportChange = (state) => { + logger.debug(`Player changed to state ${state.playbackState}`); + if (state.playbackState === 'STOPPED') { + return resolve(); + } + + coordinator.once('transport-state', transportChange); + }; + setTimeout(() => { + coordinator.once('transport-state', transportChange); + }, duration / 2); + + logger.debug(`Setting restore timer for ${restoreTimeout} ms`); + abortTimer = setTimeout(resolve, restoreTimeout); + }); + }) + .then(() => { + clearTimeout(abortTimer); + }) + .then(() => { + return backupPresets.reduce((promise, preset) => { + logger.trace('Restoring preset', preset); + return promise.then(() => system.applyPreset(preset)); + }, Promise.resolve()); + }) + .catch((err) => { + logger.error(err.stack); + throw err; }); - }) - .then(() => { - clearTimeout(abortTimer); - }) - .then(() => { - return backupPresets.reduce((promise, preset) => { - logger.trace('Restoring preset', preset); - return promise.then(() => system.applyPreset(preset)); - }, Promise.resolve()); - }) - .catch((err) => { - logger.error(err.stack); - throw err; - }); + } +} +function allPresetsRestored() { + announceAllActive = null; } module.exports = announceAll; diff --git a/settings.js b/settings.js index f2531e2d..d8837324 100644 --- a/settings.js +++ b/settings.js @@ -24,6 +24,11 @@ var settings = { announceVolume: 40 }; +// manage concurrent 'xxxall' actions +global.restrictParallelAnnouncements = true; // True discards parallel requests to the helper 'all-player-announcement' +global.announceAllActive = null; // Timer tag also used to detect an active timer +global.systemGroupUngroupDuration = 10000; // milliseconds, approx time for the system to form one group and return to the original state + // load user settings const settingsFileFullPath = path.resolve(__dirname, 'settings.json'); const userSettings = tryLoadJson(settingsFileFullPath);