Fix EOS loop freeze and playback rate not sticking on start
Throttle the EOS loop-restart seek so a fast-looping clip can't fire back-to-back blocking flush seeks on gnome-shell's main loop, which was severe enough to freeze the whole desktop. Also apply the configured playback rate immediately on start instead of only from the first loop restart. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+56
-6
@@ -78,6 +78,8 @@ export class LiveWallpaperManager {
|
||||
|
||||
this._settingsSignals = [];
|
||||
this._busWatchId = 0;
|
||||
this._eosSeekTimeoutId = 0;
|
||||
this._lastEosSeekTimeMs = 0;
|
||||
this._monitorsChangedId = 0;
|
||||
this._fullscreenChangedId = 0;
|
||||
this._upowerProxy = null;
|
||||
@@ -277,6 +279,11 @@ export class LiveWallpaperManager {
|
||||
this._applyMute();
|
||||
const stateChangeResult = this._playbin.set_state(Gst.State.PLAYING);
|
||||
this._logger.debug(`playbin.set_state(PLAYING) returned ${stateChangeResult}`);
|
||||
// set_state(PLAYING) alone always starts at native rate 1.0 —
|
||||
// without this, a configured custom speed only ever took effect
|
||||
// once the first EOS loop-restart seek ran.
|
||||
if (this._settings.get_double(SettingsKey.LIVE_WALLPAPER_PLAYBACK_RATE) !== 1.0)
|
||||
this._seekToLoopStart();
|
||||
|
||||
this._frameCount = 0;
|
||||
this._pollCount = 0;
|
||||
@@ -399,13 +406,9 @@ export class LiveWallpaperManager {
|
||||
_onBusMessage(message) {
|
||||
const Gst = this._Gst;
|
||||
switch (message.type) {
|
||||
case Gst.MessageType.EOS: {
|
||||
const rate = this._settings.get_double(SettingsKey.LIVE_WALLPAPER_PLAYBACK_RATE);
|
||||
this._playbin.seek(
|
||||
rate, Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT,
|
||||
Gst.SeekType.SET, 0, Gst.SeekType.NONE, -1);
|
||||
case Gst.MessageType.EOS:
|
||||
this._loopPlayback();
|
||||
break;
|
||||
}
|
||||
case Gst.MessageType.ERROR: {
|
||||
const [error, debug] = message.parse_error();
|
||||
this._logger.error(error, `Live wallpaper playback error (${debug ?? 'no debug info'})`);
|
||||
@@ -426,6 +429,48 @@ export class LiveWallpaperManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restarts playback at EOS. `seek()` with GST_SEEK_FLAG_FLUSH blocks
|
||||
* the calling thread until the pipeline flushes — and since this whole
|
||||
* extension runs on gnome-shell's own main loop, that blocks the entire
|
||||
* desktop for as long as it takes. At rate 1.0 that's one blocking call
|
||||
* per full playthrough, tolerable; at higher rates a short clip loops
|
||||
* (and EOS fires) many times a second, turning it into a sustained
|
||||
* back-to-back stall that reads as a hard freeze. Throttling to at most
|
||||
* one restart per EOS_SEEK_MIN_INTERVAL_MS gives the main loop room to
|
||||
* breathe between them.
|
||||
*/
|
||||
_loopPlayback() {
|
||||
const nowMs = GLib.get_monotonic_time() / 1000;
|
||||
const elapsedMs = nowMs - this._lastEosSeekTimeMs;
|
||||
const minIntervalMs = 150;
|
||||
|
||||
if (elapsedMs >= minIntervalMs) {
|
||||
this._seekToLoopStart();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._eosSeekTimeoutId)
|
||||
return;
|
||||
this._eosSeekTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, minIntervalMs - elapsedMs, () => {
|
||||
this._eosSeekTimeoutId = 0;
|
||||
this._seekToLoopStart();
|
||||
return GLib.SOURCE_REMOVE;
|
||||
});
|
||||
}
|
||||
|
||||
_seekToLoopStart() {
|
||||
if (!this._playbin)
|
||||
return;
|
||||
|
||||
this._lastEosSeekTimeMs = GLib.get_monotonic_time() / 1000;
|
||||
const Gst = this._Gst;
|
||||
const rate = this._settings.get_double(SettingsKey.LIVE_WALLPAPER_PLAYBACK_RATE);
|
||||
this._playbin.seek(
|
||||
rate, Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT,
|
||||
Gst.SeekType.SET, 0, Gst.SeekType.NONE, -1);
|
||||
}
|
||||
|
||||
_stateName(state) {
|
||||
const Gst = this._Gst;
|
||||
return Object.keys(Gst.State).find(name => Gst.State[name] === state) ?? String(state);
|
||||
@@ -610,6 +655,11 @@ export class LiveWallpaperManager {
|
||||
this._pollTimeoutId = 0;
|
||||
}
|
||||
|
||||
if (this._eosSeekTimeoutId) {
|
||||
GLib.source_remove(this._eosSeekTimeoutId);
|
||||
this._eosSeekTimeoutId = 0;
|
||||
}
|
||||
|
||||
if (this._playbin) {
|
||||
const Gst = this._Gst;
|
||||
const bus = this._playbin.get_bus();
|
||||
|
||||
Reference in New Issue
Block a user