Nix configurations for my homelab
1From 8142629da7fd5e400fd00658d5ddaa8ea78cba53 Mon Sep 17 00:00:00 2001
2From: CToID <funk443@icloud.com>
3Date: Sun, 5 Apr 2026 23:24:45 +0800
4Subject: [PATCH] screencast: drive the Pipewire graph by ourselves.
5
6---
7 src/screencast/pipewire_screencast.c | 56 +++++++++++++++++-----------
8 1 file changed, 35 insertions(+), 21 deletions(-)
9
10diff --git a/src/screencast/pipewire_screencast.c b/src/screencast/pipewire_screencast.c
11index 102a0f2b..04f3341b 100644
12--- a/src/screencast/pipewire_screencast.c
13+++ b/src/screencast/pipewire_screencast.c
14@@ -16,6 +16,7 @@
15 #include "wlr_screencast.h"
16 #include "xdpw.h"
17 #include "logger.h"
18+#include "timespec_util.h"
19
20 #define DAMAGE_REGION_COUNT 16
21
22@@ -328,6 +329,31 @@ void xdpw_pwr_enqueue_buffer(struct xdpw_screencast_instance *cast) {
23 cast->current_frame.pw_buffer = NULL;
24 }
25
26+static void pwr_capture_one(void *data) {
27+ struct xdpw_screencast_instance *cast = data;
28+
29+ if (!cast->pwr_stream_state) {
30+ logprint(INFO, "pipewire: not streaming");
31+ return;
32+ }
33+
34+ if (cast->current_frame.pw_buffer) {
35+ logprint(DEBUG, "pipewire: buffer already exported");
36+ goto trigger_graph;
37+ }
38+
39+ xdpw_pwr_dequeue_buffer(cast);
40+ if (!cast->current_frame.pw_buffer) {
41+ logprint(WARN, "pipewire: unable to export buffer");
42+ goto trigger_graph;
43+ }
44+
45+ xdpw_wlr_frame_capture(cast);
46+
47+trigger_graph:
48+ pw_stream_trigger_process(cast->stream);
49+}
50+
51 void pwr_update_stream_param(struct xdpw_screencast_instance *cast) {
52 logprint(TRACE, "pipewire: stream update parameters");
53 struct pw_stream *stream = cast->stream;
54@@ -359,6 +385,7 @@ static void pwr_handle_stream_state_changed(void *data,
55 switch (state) {
56 case PW_STREAM_STATE_STREAMING:
57 cast->pwr_stream_state = true;
58+ pwr_capture_one(cast);
59 break;
60 case PW_STREAM_STATE_PAUSED:
61 if (old == PW_STREAM_STATE_STREAMING) {
62@@ -586,27 +613,13 @@ static void pwr_handle_stream_remove_buffer(void *data, struct pw_buffer *buffer
63 buffer->user_data = NULL;
64 }
65
66-static void pwr_handle_stream_on_process(void *data) {
67+static void pwr_handle_stream_trigger_done(void *data) {
68 struct xdpw_screencast_instance *cast = data;
69-
70- logprint(TRACE, "pipewire: on process event handle");
71-
72- if (!cast->pwr_stream_state) {
73- logprint(INFO, "pipewire: not streaming");
74- return;
75- }
76-
77- if (cast->current_frame.pw_buffer) {
78- logprint(DEBUG, "pipewire: buffer already exported");
79- return;
80+ uint64_t delay_ns = fps_limit_measure_end(&cast->fps_limit, cast->framerate);
81+ if (delay_ns <= 0) {
82+ delay_ns = (1.0 / cast->framerate) * TIMESPEC_NSEC_PER_SEC;
83 }
84-
85- xdpw_pwr_dequeue_buffer(cast);
86- if (!cast->current_frame.pw_buffer) {
87- logprint(WARN, "pipewire: unable to export buffer");
88- return;
89- }
90- xdpw_wlr_frame_capture(cast);
91+ xdpw_add_timer(cast->ctx->state, delay_ns, pwr_capture_one, cast);
92 }
93
94 static const struct pw_stream_events pwr_stream_events = {
95@@ -615,7 +628,7 @@ static const struct pw_stream_events pwr_stream_events = {
96 .param_changed = pwr_handle_stream_param_changed,
97 .add_buffer = pwr_handle_stream_add_buffer,
98 .remove_buffer = pwr_handle_stream_remove_buffer,
99- .process = pwr_handle_stream_on_process,
100+ .trigger_done = pwr_handle_stream_trigger_done,
101 };
102
103 void xdpw_pwr_stream_create(struct xdpw_screencast_instance *cast) {
104@@ -652,7 +665,8 @@ void xdpw_pwr_stream_create(struct xdpw_screencast_instance *cast) {
105 pw_stream_connect(cast->stream,
106 PW_DIRECTION_OUTPUT,
107 PW_ID_ANY,
108- PW_STREAM_FLAG_ALLOC_BUFFERS,
109+ (PW_STREAM_FLAG_ALLOC_BUFFERS |
110+ PW_STREAM_FLAG_DRIVER),
111 params.data, params.size / sizeof(struct spa_pod *));
112
113 spa_pod_dynamic_builder_clean(&builder);