Add live wallpaper pipeline diagnostics
A user's live wallpaper reached "started" with zero errors (Cogl and GStreamer both loading fine, actor added to _backgroundGroup) but never actually appeared on screen, and no code path here could tell us why: the bus handler only looked at EOS/ERROR, silently discarding WARNING and STATE_CHANGED messages where a stalled negotiation or preroll would actually show up. Adds: WARNING message logging, PLAYING/PAUSED/etc. state-changed logging for the playbin itself, a frame counter with first-frame and periodic debug logs, and a one-shot watchdog that logs an explicit warning if zero frames arrive within 4s of set_state(PLAYING). Also switched appsink's pull-sample from an emitted action signal to the plain pull_sample() method, which is the more directly supported GstApp.AppSink API and one less variable while debugging. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019RDqbdjsiisSU7CbQke4g8
This commit is contained in:
+46
-4
@@ -48,6 +48,9 @@ export class LiveWallpaperManager {
|
|||||||
this._fullscreenChangedId = 0;
|
this._fullscreenChangedId = 0;
|
||||||
this._upowerProxy = null;
|
this._upowerProxy = null;
|
||||||
this._upowerSignalId = 0;
|
this._upowerSignalId = 0;
|
||||||
|
|
||||||
|
this._frameCount = 0;
|
||||||
|
this._noFrameWatchdogId = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
get isAvailable() {
|
get isAvailable() {
|
||||||
@@ -155,7 +158,20 @@ export class LiveWallpaperManager {
|
|||||||
this._busWatchId = bus.connect('message', (_bus, message) => this._onBusMessage(message));
|
this._busWatchId = bus.connect('message', (_bus, message) => this._onBusMessage(message));
|
||||||
|
|
||||||
this._applyMute();
|
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._setActive(true);
|
||||||
this._paused = false;
|
this._paused = false;
|
||||||
@@ -169,7 +185,7 @@ export class LiveWallpaperManager {
|
|||||||
|
|
||||||
_onNewSample(sink) {
|
_onNewSample(sink) {
|
||||||
const Gst = this._Gst;
|
const Gst = this._Gst;
|
||||||
const sample = sink.emit('pull-sample');
|
const sample = sink.pull_sample();
|
||||||
if (!sample)
|
if (!sample)
|
||||||
return Gst.FlowReturn.OK;
|
return Gst.FlowReturn.OK;
|
||||||
|
|
||||||
@@ -185,6 +201,11 @@ export class LiveWallpaperManager {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
this._updateFrame(mapInfo.data, width, height);
|
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 {
|
} finally {
|
||||||
buffer.unmap(mapInfo);
|
buffer.unmap(mapInfo);
|
||||||
}
|
}
|
||||||
@@ -221,12 +242,28 @@ export class LiveWallpaperManager {
|
|||||||
Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT, 0);
|
Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT, 0);
|
||||||
break;
|
break;
|
||||||
case Gst.MessageType.ERROR: {
|
case Gst.MessageType.ERROR: {
|
||||||
const [error] = message.parse_error();
|
const [error, debug] = message.parse_error();
|
||||||
this._logger.error(error, 'Live wallpaper playback error');
|
this._logger.error(error, `Live wallpaper playback error (${debug ?? 'no debug info'})`);
|
||||||
this._stop();
|
this._stop();
|
||||||
break;
|
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() {
|
_applyMute() {
|
||||||
@@ -326,6 +363,11 @@ export class LiveWallpaperManager {
|
|||||||
_stop() {
|
_stop() {
|
||||||
this._disconnectPowerWatches();
|
this._disconnectPowerWatches();
|
||||||
|
|
||||||
|
if (this._noFrameWatchdogId) {
|
||||||
|
GLib.source_remove(this._noFrameWatchdogId);
|
||||||
|
this._noFrameWatchdogId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (this._playbin) {
|
if (this._playbin) {
|
||||||
const bus = this._playbin.get_bus();
|
const bus = this._playbin.get_bus();
|
||||||
if (this._busWatchId) {
|
if (this._busWatchId) {
|
||||||
|
|||||||
Reference in New Issue
Block a user