diff --git a/lib/helpers/soap.js b/lib/helpers/soap.js index d83c5ac7..14335ea6 100644 --- a/lib/helpers/soap.js +++ b/lib/helpers/soap.js @@ -44,7 +44,7 @@ const TEMPLATES = Object.freeze({ [TYPE.Previous]: '0', [TYPE.Mute]: '0Master{mute}', [TYPE.GroupMute]: '0Master{mute}', - [TYPE.Volume]: '0Master{volume}', + [TYPE.Volume]: '0{channel}{volume}', [TYPE.Seek]: '0{unit}{value}', [TYPE.RemoveAllTracksFromQueue]: '0', [TYPE.RemoveTrackFromQueue]: '0Q:0/{track}', diff --git a/lib/models/Player.js b/lib/models/Player.js index 76c5d07b..441ca083 100644 --- a/lib/models/Player.js +++ b/lib/models/Player.js @@ -146,6 +146,9 @@ function getState(playerInternal, coordinatorInternal, sub) { const state = { volume: playerInternal.volume, + volumeLeft: playerInternal.volumeLeft, + volumeRight: playerInternal.volumeRight, + balance: playerInternal.balance, mute: playerInternal.mute, equalizer: playerInternal.equalizer, currentTrack: coordinatorInternal.currentTrack, @@ -191,10 +194,25 @@ function Player(data, listener, system) { get: () => state }); _this.ownVolumeEvents = []; - _this._setVolume = function _setVolume(level) { - state.volume = level; + _this._setVolume = function _setVolume(level, channel) { + switch(channel) { + case 'LF': + state.volumeLeft = level; + break; + case 'RF': + state.volumeRight = level; + break; + default: + //Master or null (which by legacy is Master) + state.volume = level; + } }; + _this._setBalance = function _setBalance(level) { + console.log("_setBalance:" + level); + state.balance = level; + } + let uri = url.parse(data.location); _this.baseUrl = `${uri.protocol}//${uri.host}`; @@ -498,28 +516,66 @@ Player.prototype.muteGroup = function muteGroup() { { mute: 1 }); }; -Player.prototype.setVolume = function setVolume(level) { +Player.prototype.setVolume = function setVolume(level, channel) { if (this.outputFixed) { return Promise.resolve(); } - - // If prefixed with + or - - if (/^[+\-]/.test(level)) { - level = this.state.volume + parseInt(level); + switch(channel) { + case 'LF': + // If prefixed with + or - + if (/^[+\-]/.test(level)) { + level = this.state.volumeLeft + parseInt(level); + } + break; + case 'RF': + // If prefixed with + or - + if (/^[+\-]/.test(level)) { + level = this.state.volumeRight + parseInt(level); + } + break; + default: + // If prefixed with + or - + if (/^[+\-]/.test(level)) { + level = this.state.volume + parseInt(level); + } + channel = 'Master'; } if (level < 0) level = 0; - this._setVolume(level); + this._setVolume(level, channel); // stash this update to ignore the event when it comes back. - this.ownVolumeEvents.push(level); + this.ownVolumeEvents.push(level, channel); return soap.invoke( `${this.baseUrl}/MediaRenderer/RenderingControl/Control`, TYPE.Volume, - { volume: level }); + { volume: level, channel: channel }); }; +Player.prototype.setBalance = function setBalance(level) { + + console.log("setBalance: "+level); + let volumeLeft = 100; + let volumeRight = 100; + + console.log("Balance: "+level); + + const adjustment = (level-50)*2; + if (adjustment < 0) { + volumeRight = 100+adjustment; + } else if(level > 50) { + volumeLeft = 100-adjustment; + } + + this.setVolume(volumeLeft, 'LF'); + this.setVolume(volumeRight, 'RF'); + + this._setBalance(level); + + return Promise.resolve("success"); +} + Player.prototype.timeSeek = function timeSeek(seconds) { let formattedTime = formatTime(seconds); return soap.invoke(