diff options
Diffstat (limited to 'packages/meshbay-client/src/cast-chromecast.js')
| -rw-r--r-- | packages/meshbay-client/src/cast-chromecast.js | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/packages/meshbay-client/src/cast-chromecast.js b/packages/meshbay-client/src/cast-chromecast.js index 7fc8079..55deb5b 100644 --- a/packages/meshbay-client/src/cast-chromecast.js +++ b/packages/meshbay-client/src/cast-chromecast.js @@ -174,6 +174,7 @@ class CastChromecast { player.on('status', (status) => { debug(`[cast-chromecast] player status: ${status.playerState}`); + this._noteStatus(status); }); debug(`[cast-chromecast] loading with ${subtitle?.url ? 'subtitles' : 'no subtitles'}`); @@ -185,6 +186,7 @@ class CastChromecast { }); }); + this._noteStatus(status); debug(`[cast-chromecast] loaded on "${device.name}", state: ${status.playerState}`); return { deviceName: device.name, playerState: status.playerState }; } @@ -200,6 +202,7 @@ class CastChromecast { resolve(s); }); }); + this._noteStatus(status); debug(`[cast-chromecast] reloaded, state: ${status.playerState}`); return { playerState: status.playerState }; } @@ -215,10 +218,55 @@ class CastChromecast { this._cleanup(); } + /** + * What the receiver last said, kept so the page can show where the + * *television* is: its playhead is not the local one, which started earlier + * and drifts. `currentTime` is on the stream's timeline — zero at the point + * the relay started — and the page adds that start. + */ + _noteStatus(status) { + if (!status) return; + this._lastStatus = { + playerState: status.playerState || null, + idleReason: status.idleReason || null, + position: Number(status.currentTime) || 0, + at: Date.now(), + }; + } + + /** The receiver's position now: extrapolated while it plays, as its own clock does. */ + _position() { + const s = this._lastStatus; + if (!s) return null; + return s.playerState === 'PLAYING' ? s.position + (Date.now() - s.at) / 1000 : s.position; + } + + async pause() { + if (!this._player) throw new Error('Not connected'); + const status = await new Promise((resolve, reject) => { + this._player.pause((err, s) => (err ? reject(err) : resolve(s))); + }); + this._noteStatus(status); + return { playerState: status && status.playerState }; + } + + async play() { + if (!this._player) throw new Error('Not connected'); + const status = await new Promise((resolve, reject) => { + this._player.play((err, s) => (err ? reject(err) : resolve(s))); + }); + this._noteStatus(status); + return { playerState: status && status.playerState }; + } + getStatus() { + const s = this._lastStatus; return { connected: this._client !== null, deviceName: this._connectedDevice?.name || null, + playerState: s ? s.playerState : null, + idleReason: s ? s.idleReason : null, + position: this._client !== null ? this._position() : null, }; } @@ -229,6 +277,7 @@ class CastChromecast { this._client = null; this._player = null; this._connectedDevice = null; + this._lastStatus = null; } } |