Defer initial playback-rate seek to ASYNC_DONE
An early seek right after set_state(PLAYING) raced the pipeline's preroll and GStreamer silently dropped it, so a configured custom rate only took effect after the first EOS loop-restart. Instead, flag the pending seek and fire it from the first ASYNC_DONE bus message, once the pipeline is actually ready to seek. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+30
-8
@@ -80,6 +80,7 @@ export class LiveWallpaperManager {
|
|||||||
this._busWatchId = 0;
|
this._busWatchId = 0;
|
||||||
this._eosSeekTimeoutId = 0;
|
this._eosSeekTimeoutId = 0;
|
||||||
this._lastEosSeekTimeMs = 0;
|
this._lastEosSeekTimeMs = 0;
|
||||||
|
this._pendingInitialRateSeek = false;
|
||||||
this._monitorsChangedId = 0;
|
this._monitorsChangedId = 0;
|
||||||
this._fullscreenChangedId = 0;
|
this._fullscreenChangedId = 0;
|
||||||
this._upowerProxy = null;
|
this._upowerProxy = null;
|
||||||
@@ -279,11 +280,17 @@ export class LiveWallpaperManager {
|
|||||||
this._applyMute();
|
this._applyMute();
|
||||||
const stateChangeResult = 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._logger.debug(`playbin.set_state(PLAYING) returned ${stateChangeResult}`);
|
||||||
// set_state(PLAYING) alone always starts at native rate 1.0 —
|
// Seeking here immediately would race the pipeline's preroll —
|
||||||
// without this, a configured custom speed only ever took effect
|
// GStreamer can only seek once a state change has actually
|
||||||
// once the first EOS loop-restart seek ran.
|
// completed, so an early seek is silently dropped and playback
|
||||||
if (this._settings.get_double(SettingsKey.LIVE_WALLPAPER_PLAYBACK_RATE) !== 1.0)
|
// sticks at native 1.0x. Instead, defer to the first ASYNC_DONE
|
||||||
this._seekToLoopStart();
|
// bus message (handled in _onBusMessage), which fires once the
|
||||||
|
// pipeline is actually ready to seek.
|
||||||
|
const initialRate = this._settings.get_double(SettingsKey.LIVE_WALLPAPER_PLAYBACK_RATE);
|
||||||
|
this._pendingInitialRateSeek = initialRate !== 1.0;
|
||||||
|
this._logger.debug(
|
||||||
|
`Live wallpaper: configured playback rate ${initialRate}, ` +
|
||||||
|
`deferring initial seek to ASYNC_DONE: ${this._pendingInitialRateSeek}`);
|
||||||
|
|
||||||
this._frameCount = 0;
|
this._frameCount = 0;
|
||||||
this._pollCount = 0;
|
this._pollCount = 0;
|
||||||
@@ -409,6 +416,14 @@ export class LiveWallpaperManager {
|
|||||||
case Gst.MessageType.EOS:
|
case Gst.MessageType.EOS:
|
||||||
this._loopPlayback();
|
this._loopPlayback();
|
||||||
break;
|
break;
|
||||||
|
case Gst.MessageType.ASYNC_DONE:
|
||||||
|
this._logger.debug(
|
||||||
|
`Live wallpaper: ASYNC_DONE received (pending initial rate seek: ${this._pendingInitialRateSeek})`);
|
||||||
|
if (this._pendingInitialRateSeek) {
|
||||||
|
this._pendingInitialRateSeek = false;
|
||||||
|
this._seekToLoopStart();
|
||||||
|
}
|
||||||
|
break;
|
||||||
case Gst.MessageType.ERROR: {
|
case Gst.MessageType.ERROR: {
|
||||||
const [error, debug] = message.parse_error();
|
const [error, debug] = message.parse_error();
|
||||||
this._logger.error(error, `Live wallpaper playback error (${debug ?? 'no debug info'})`);
|
this._logger.error(error, `Live wallpaper playback error (${debug ?? 'no debug info'})`);
|
||||||
@@ -466,9 +481,11 @@ export class LiveWallpaperManager {
|
|||||||
this._lastEosSeekTimeMs = GLib.get_monotonic_time() / 1000;
|
this._lastEosSeekTimeMs = GLib.get_monotonic_time() / 1000;
|
||||||
const Gst = this._Gst;
|
const Gst = this._Gst;
|
||||||
const rate = this._settings.get_double(SettingsKey.LIVE_WALLPAPER_PLAYBACK_RATE);
|
const rate = this._settings.get_double(SettingsKey.LIVE_WALLPAPER_PLAYBACK_RATE);
|
||||||
this._playbin.seek(
|
const ok = this._playbin.seek(
|
||||||
rate, Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT,
|
rate, Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT,
|
||||||
Gst.SeekType.SET, 0, Gst.SeekType.NONE, -1);
|
Gst.SeekType.SET, 0, Gst.SeekType.NONE, -1);
|
||||||
|
this._logger.debug(
|
||||||
|
`Live wallpaper: loop-restart seek to rate ${rate} ${ok ? 'succeeded' : 'FAILED (seek() returned false)'}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
_stateName(state) {
|
_stateName(state) {
|
||||||
@@ -488,12 +505,17 @@ export class LiveWallpaperManager {
|
|||||||
const Gst = this._Gst;
|
const Gst = this._Gst;
|
||||||
const rate = this._settings.get_double(SettingsKey.LIVE_WALLPAPER_PLAYBACK_RATE);
|
const rate = this._settings.get_double(SettingsKey.LIVE_WALLPAPER_PLAYBACK_RATE);
|
||||||
const [ok, position] = this._playbin.query_position(Gst.Format.TIME);
|
const [ok, position] = this._playbin.query_position(Gst.Format.TIME);
|
||||||
if (!ok)
|
if (!ok) {
|
||||||
|
this._logger.debug('Live wallpaper: applyPlaybackRate aborted, query_position() failed');
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this._playbin.seek(
|
const seekOk = this._playbin.seek(
|
||||||
rate, Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.ACCURATE,
|
rate, Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.ACCURATE,
|
||||||
Gst.SeekType.SET, position, Gst.SeekType.NONE, -1);
|
Gst.SeekType.SET, position, Gst.SeekType.NONE, -1);
|
||||||
|
this._logger.debug(
|
||||||
|
`Live wallpaper: applyPlaybackRate to ${rate} at position ${position} ` +
|
||||||
|
`${seekOk ? 'succeeded' : 'FAILED (seek() returned false)'}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user