diff --git a/src/node/main.c b/src/node/main.c index 0c66865..2676978 100644 --- a/src/node/main.c +++ b/src/node/main.c @@ -187,6 +187,7 @@ struct Display_Slot { /* No-signal animation */ int no_signal_fps; /* 0 → default 15 */ + double last_frame_t; /* wall time of last successfully displayed frame */ double last_no_signal_t; /* Viewer — created and used only on the main thread */ @@ -521,21 +522,25 @@ static void display_loop_tick(struct Node *node) } pthread_mutex_unlock(&d->mutex); + struct timespec _ts; + clock_gettime(CLOCK_MONOTONIC, &_ts); + double now = (double)_ts.tv_sec + (double)_ts.tv_nsec * 1e-9; + if (fdata) { struct Proto_Video_Frame vf; if (APP_IS_OK(proto_read_video_frame(fdata, flen, &vf))) { xorg_viewer_push_mjpeg(d->viewer, vf.data, vf.data_len); + d->last_frame_t = now; } free(fdata); - } else { - /* No live frame — render no-signal animation at configured fps */ - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - double now = (double)ts.tv_sec + (double)ts.tv_nsec * 1e-9; + } + + /* Render no-signal only when stream has been silent for ≥1 s */ + if (now - d->last_frame_t >= 1.0) { double interval = 1.0 / (double)(d->no_signal_fps > 0 ? d->no_signal_fps : 15); if (now - d->last_no_signal_t >= interval) { - /* Wrap to [0, 1000) to preserve float32 fractional precision in shader */ - xorg_viewer_render_no_signal(d->viewer, (float)fmod(now, 1000.0), 80.0f); + /* Wrap to [0, 1000) to preserve float32 fractional precision */ + xorg_viewer_render_no_signal(d->viewer, (float)fmod(now, 1000.0), 80.0f); d->last_no_signal_t = now; } }