diff --git a/lib/liveWallpaper.js b/lib/liveWallpaper.js index 335c67c..566192f 100644 --- a/lib/liveWallpaper.js +++ b/lib/liveWallpaper.js @@ -48,6 +48,9 @@ export class LiveWallpaperManager { this._fullscreenChangedId = 0; this._upowerProxy = null; this._upowerSignalId = 0; + + this._frameCount = 0; + this._noFrameWatchdogId = 0; } get isAvailable() { @@ -155,7 +158,20 @@ export class LiveWallpaperManager { this._busWatchId = bus.connect('message', (_bus, message) => this._onBusMessage(message)); this._applyMute(); - this._playbin.set_state(Gst.State.PLAYING); + const stateChangeResult = this._playbin.set_state(Gst.State.PLAYING); + this._logger.debug(`playbin.set_state(PLAYING) returned ${stateChangeResult}`); + + this._frameCount = 0; + this._noFrameWatchdogId = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 4, () => { + this._noFrameWatchdogId = 0; + if (this._active && this._frameCount === 0) { + this._logger.warn( + 'Live wallpaper: no frames received 4s after starting playback. ' + + 'The pipeline likely stalled during caps negotiation or preroll without ' + + 'raising an error — check for GStreamer WARNING messages logged above.'); + } + return GLib.SOURCE_REMOVE; + }); this._setActive(true); this._paused = false; @@ -169,7 +185,7 @@ export class LiveWallpaperManager { _onNewSample(sink) { const Gst = this._Gst; - const sample = sink.emit('pull-sample'); + const sample = sink.pull_sample(); if (!sample) return Gst.FlowReturn.OK; @@ -185,6 +201,11 @@ export class LiveWallpaperManager { try { this._updateFrame(mapInfo.data, width, height); + this._frameCount++; + if (this._frameCount === 1) + this._logger.debug(`Live wallpaper: first frame received (${width}x${height})`); + else if (this._frameCount % 120 === 0) + this._logger.debug(`Live wallpaper: ${this._frameCount} frames rendered so far`); } finally { buffer.unmap(mapInfo); } @@ -221,12 +242,28 @@ export class LiveWallpaperManager { Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT, 0); break; case Gst.MessageType.ERROR: { - const [error] = message.parse_error(); - this._logger.error(error, 'Live wallpaper playback error'); + const [error, debug] = message.parse_error(); + this._logger.error(error, `Live wallpaper playback error (${debug ?? 'no debug info'})`); this._stop(); break; } + case Gst.MessageType.WARNING: { + const [warning, debug] = message.parse_warning(); + this._logger.warn(`Live wallpaper GStreamer warning: ${warning.message} (${debug ?? 'no debug info'})`); + break; } + case Gst.MessageType.STATE_CHANGED: + if (message.src === this._playbin) { + const [, newState] = message.parse_state_changed(); + this._logger.debug(`Live wallpaper pipeline state changed to ${this._stateName(newState)}`); + } + break; + } + } + + _stateName(state) { + const Gst = this._Gst; + return Object.keys(Gst.State).find(name => Gst.State[name] === state) ?? String(state); } _applyMute() { @@ -326,6 +363,11 @@ export class LiveWallpaperManager { _stop() { this._disconnectPowerWatches(); + if (this._noFrameWatchdogId) { + GLib.source_remove(this._noFrameWatchdogId); + this._noFrameWatchdogId = 0; + } + if (this._playbin) { const bus = this._playbin.get_bus(); if (this._busWatchId) {