Skip to content

Commit 33bc0ad

Browse files
authored
Merge pull request #84 from FedeDP/pipewire_support
Pipewire support + some global fixes
2 parents d6c65ac + caabd84 commit 33bc0ad

31 files changed

Lines changed: 1212 additions & 417 deletions

.build.yml

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,20 @@ packages:
1313
- libjpeg-turbo
1414
- wayland
1515
- libdrm
16+
- pipewire
1617
sources:
1718
- https://github.com/FedeDP/Clightd
1819
tasks:
1920
- prepare: |
2021
cd Clightd
21-
mkdir build build-no-gamma build-no-dpms build-no-ddc build-no-screen build-no-yoctolight build-no-extras
22-
(cd build && cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_GAMMA=1 -DENABLE_DPMS=1 -DENABLE_DDC=1 -DENABLE_SCREEN=1 -DENABLE_YOCTOLIGHT=1 ..)
23-
(cd build-no-gamma && cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_DPMS=1 -DENABLE_DDC=1 -DENABLE_SCREEN=1 -DENABLE_YOCTOLIGHT=1 ..)
24-
(cd build-no-dpms && cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_GAMMA=1 -DENABLE_DDC=1 -DENABLE_SCREEN=1 -DENABLE_YOCTOLIGHT=1 ..)
25-
(cd build-no-ddc && cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_GAMMA=1 -DENABLE_DPMS=1 -DENABLE_SCREEN=1 -DENABLE_YOCTOLIGHT=1 ..)
26-
(cd build-no-screen && cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_GAMMA=1 -DENABLE_DPMS=1 -DENABLE_DDC=1 -DENABLE_YOCTOLIGHT=1 ..)
27-
(cd build-no-yoctolight && cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_GAMMA=1 -DENABLE_DPMS=1 -DENABLE_DDC=1 -DENABLE_SCREEN=1 ..)
22+
mkdir build build-no-gamma build-no-dpms build-no-ddc build-no-screen build-no-yoctolight build-no-pipewire build-no-extras
23+
(cd build && cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_GAMMA=1 -DENABLE_DPMS=1 -DENABLE_DDC=1 -DENABLE_SCREEN=1 -DENABLE_YOCTOLIGHT=1 -DENABLE_PIPEWIRE=1 ..)
24+
(cd build-no-gamma && cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_DPMS=1 -DENABLE_DDC=1 -DENABLE_SCREEN=1 -DENABLE_YOCTOLIGHT=1 -DENABLE_PIPEWIRE=1 ..)
25+
(cd build-no-dpms && cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_GAMMA=1 -DENABLE_DDC=1 -DENABLE_SCREEN=1 -DENABLE_YOCTOLIGHT=1 -DENABLE_PIPEWIRE=1 ..)
26+
(cd build-no-ddc && cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_GAMMA=1 -DENABLE_DPMS=1 -DENABLE_SCREEN=1 -DENABLE_YOCTOLIGHT=1 -DENABLE_PIPEWIRE=1 ..)
27+
(cd build-no-screen && cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_GAMMA=1 -DENABLE_DPMS=1 -DENABLE_DDC=1 -DENABLE_YOCTOLIGHT=1 -DENABLE_PIPEWIRE=1 ..)
28+
(cd build-no-yoctolight && cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_GAMMA=1 -DENABLE_DPMS=1 -DENABLE_DDC=1 -DENABLE_SCREEN=1 -DENABLE_PIPEWIRE=1 ..)
29+
(cd build-no-pipewire && cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_GAMMA=1 -DENABLE_DPMS=1 -DENABLE_DDC=1 -DENABLE_SCREEN=1 -DENABLE_YOCTOLIGHT=1 ..)
2830
(cd build-no-extras && cmake -DCMAKE_BUILD_TYPE=Debug ..)
2931
- build: |
3032
cd Clightd
@@ -34,6 +36,7 @@ tasks:
3436
(cd build-no-ddc && make)
3537
(cd build-no-screen && make)
3638
(cd build-no-yoctolight && make)
39+
(cd build-no-pipewire && make)
3740
(cd build-no-extras && make)
3841
triggers:
3942
- action: email

CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ optional_dep(DPMS "x11;xext;libdrm;wayland-client" "DPMS" protocol/org_kde_kwin_
9999
optional_dep(SCREEN "x11" "screen emitted brightness" protocol/wlr-screencopy-unstable-v1.xml src/modules/screen_plugins)
100100
optional_dep(DDC "ddcutil>=0.9.5" "external monitor backlight")
101101
optional_dep(YOCTOLIGHT "libusb-1.0" "Yoctolight usb als devices support")
102+
optional_dep(PIPEWIRE "libpipewire-0.3" "Enable pipewire camera sensor support")
102103

103104
# Convert ld flag list from list to space separated string.
104105
string(REPLACE ";" " " COMBINED_LDFLAGS "${COMBINED_LDFLAGS}")
@@ -111,7 +112,7 @@ set_target_properties(
111112

112113
# Installation of targets (must be before file configuration to work)
113114
install(TARGETS ${PROJECT_NAME}
114-
RUNTIME DESTINATION "${CMAKE_INSTALL_LIBEXECDIR}")
115+
RUNTIME DESTINATION "${CMAKE_INSTALL_FULL_LIBEXECDIR}")
115116

116117
set(SCRIPT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/Scripts")
117118

@@ -142,6 +143,8 @@ if(SYSTEMD_BASE_FOUND)
142143

143144
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/clightd.service
144145
DESTINATION ${SYSTEMD_SERVICE_DIR})
146+
147+
set(SYSTEMD_SERVICE "SystemdService=clightd.service")
145148
endif()
146149

147150
# Install dbus service

Scripts/clightd.service

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,14 @@ Requires=@POLKIT_NAME@.service
77
Type=dbus
88
BusName=org.clightd.clightd
99
User=root
10-
# Default backlight vcp code; update if needed
10+
# Default backlight vcp code; update if needed.
11+
# Moreover, you can also specify per-monitor BL VCP value,
12+
# using CLIGHTD_BL_VCP_$mon_id, where mon_id is the monitor identifier
13+
# as seen by Clightd; you can explore them using:
14+
# $ busctl call org.clightd.clightd /org/clightd/clightd/Backlight2 org.clightd.clightd.Backlight2 Get
1115
Environment=CLIGHTD_BL_VCP=0x10
16+
# Default pipewire runtime dir watched by Clightd
17+
Environment=CLIGHTD_PIPEWIRE_RUNTIME_DIR=/run/user/1000/
1218
ExecStart=@CMAKE_INSTALL_FULL_LIBEXECDIR@/clightd
1319
Restart=on-failure
1420
RestartSec=5

Scripts/org.clightd.clightd.service

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
Name=org.clightd.clightd
33
Exec=@CMAKE_INSTALL_FULL_LIBEXECDIR@/clightd
44
User=root
5-
SystemdService=clightd.service
5+
@SYSTEMD_SERVICE@

TODO.md

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,22 +30,59 @@
3030
- [x] Drop bl_store_vpcode() and only load vpcode from CLIGHTD_BL_VCP env?
3131
- [x] Add CLIGHTD_BL_VCP Environment variable to systemd script with a comment thus it is simple to update it if needed
3232
- [x] Expose Max and Internal properties
33-
- [ ] Update dbus api wiki
33+
- [x] Update dbus api wiki
3434
- [x] add a page about monitor hotplugging (dep on ddcutil >= 1.2.0 and refresh time!)
3535
- [x] Investigate memleaks (related to ddca_redetect_displays()?) -> see here: https://github.com/rockowitz/ddcutil/issues/202
3636
- [x] Instead of 30s sleep, use an udev_monitor on drm subsystem?
37+
- [x] Add support for monitor id specific CLIGHTD_BL_VCP env
3738

3839
### KbdBacklight
3940
- [x] call sd_bus_emit_object_added() sd_bus_emit_object_removed() When object path are created/deleted
4041
- [x] Fix: udev_reference is a snapshot of an udev device at a current time. Wrong!
42+
- [x] Fixed (small) memleak
43+
44+
### ALS
45+
- [x] Fix: avoid using cached udev_dev reference in loop (thus always returning same ambient brightness read during a Capture request)
46+
- [x] Fixed EIO errors
47+
48+
### Sensor
49+
- [x] Only emit Sensor.Changed signal for added/removed devices
50+
51+
### Pipewire
52+
- [x] Support pipewire for Camera sensor? This would allow multiple application sharing camera
53+
- [x] Pipewire run as root needs XDG_RUNTIME_DIR env -> workaround: find the first /run/user folder and use that
54+
- [x] Unify camera settings between camera and pipewire sensors... ?
55+
- [x] Support monitor sensor api for pipewire
56+
- [x] Fix segfault
57+
- [x] Fix subsequent Capture
58+
- [x] Add a CLIGHTD_PW_RUNTIME_DIR env variable (in clightd.service, see CLIGHTD_BL_CODE) that defaults to /run/user/1000/. If the env variable is empty -> disable pipewire. If folder does not exist: disable pipewire. Otherwise: inotify on folder to wait for socket to appear. If socket is already there, immediately start monitoring.
59+
- [x] Document the new env variable!
60+
- [x] Use caller uid instead of defaulting to first found user during Capture!
61+
- [x] Use a map to store list of nodes?
62+
- [x] Free list of nodes upon exit!
63+
- [x] Fix xdg_runtime_dir set to create monitor
64+
- [x] Fix memleaks
65+
- [x] Support crop settings
66+
- [x] Test crop
67+
- [x] Drop crop API support for both pipewire and webcam; they add lots of complexity while giving no real perf improvements considering we are using small frames
68+
- [x] Fix: pipewire capture while webcam is already owned by another app freezes during pw_loop_iterate()
4169

4270
### Generic
4371
- [x] When built with ddcutil, clightd.service should be started after systemd-modules-load.service
4472
- [x] Show commit hash in version
73+
- [x] All api that require eg Xauth or xdg rutime user, fallback at automatically fetching a default value given the caller:
74+
- [x] test X
75+
- [x] test wl
76+
- [x] Document the new behavior!
77+
- [x] Fix clightd not cleanly exiting when built with DDC or YOCTOLIGHT (most probably libusb or whatever is creating another thread that is stealing the signal!)
78+
- [x] do not use strlen() to only check that strign is not empty
4579

4680
## 5.x
4781
- [ ] Keep it up to date with possible ddcutil api changes
4882

83+
### Pipewire
84+
- [ ] Fix set_camera_setting() impl -> how to get current value? how to set a new value?
85+
4986
## 6.x (api break release)
5087

5188
### Generic
@@ -54,9 +91,15 @@
5491
- [ ] Drop old BACKLIGHT module -> in case, drop {Lower,Raise,Set}All from clightd polkit policy
5592
- [ ] Rename Backlight2 to Backlight
5693

57-
### Pipewire
58-
- [ ] merge pipewire work
94+
### Move to user service (?)
5995
- [ ] move clightd to user service
96+
- [ ] Drop polkit and use sd_session_is_active()
97+
- [ ] Add udev rules for yoctolight, als, keyboard and backlight modules for "clightd"
98+
- [ ] Drop useless API params (eg: DISPLAY, XAUTHORITY, XDG_RUNTIME_DIR etc etc)
99+
- [ ] # groupadd clightd
100+
- [ ] # usermod -aG clightd myusername
101+
- [ ] # echo 'KERNEL=="i2c-[0-9]*", GROUP="clightd"' >> /etc/udev/rules.d/10-local_i2c_group.rules
102+
... would break https://github.com/FedeDP/Clight/issues/144 ...
60103

61104
## Ideas
62105
- [ ] follow ddcci kernel driver and in case, drop ddcutil and add the kernel driver as clightd opt-dep

src/commons.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@
2020
#include <module/module_easy.h>
2121

2222
#define SIZE(x) (sizeof(x) / sizeof(*x))
23-
#define _ctor_ __attribute__((constructor (101))) // Used for Sensors registering
24-
#define _dtor_ __attribute__((destructor (101))) // Used for libusb dtor
23+
24+
#define _ctor_ __attribute__((constructor (101))) // Used for plugins registering (sensor, gamma, dpms, screen) and libusb/libpipewire init
25+
#define _dtor_ __attribute__((destructor (101))) // Used for libusb and libpipewire dtor
2526

2627
/* Used by dpms, gamma and screen*/
2728
#define UNSUPPORTED INT_MIN

src/modules/backlight2.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#define BL_SUBSYSTEM "backlight"
88
#define DRM_SUBSYSTEM "drm"
9+
#define BL_VCP_ENV "CLIGHTD_BL_VCP"
910

1011
typedef struct {
1112
double target_pct;
@@ -104,14 +105,14 @@ MODULE("BACKLIGHT2");
104105
static DDCA_Vcp_Feature_Code br_code = 0x10;
105106

106107
static void bl_load_vpcode(void) {
107-
if (getenv("CLIGHTD_BL_VCP")) {
108-
br_code = strtol(getenv("CLIGHTD_BL_VCP"), NULL, 16);
109-
m_log("Set 0x%x vcp code.\n", br_code);
108+
if (getenv(BL_VCP_ENV)) {
109+
br_code = strtol(getenv(BL_VCP_ENV), NULL, 16);
110+
m_log("Set default 0x%x vcp code.\n", br_code);
110111
}
111112
}
112113

113114
static void get_info_id(char *id, const int size, const DDCA_Display_Info *dinfo) {
114-
if (!strlen(dinfo->sn) || !strcasecmp(dinfo->sn, "Unspecified")) {
115+
if ((dinfo->sn[0] == '\0') || !strcasecmp(dinfo->sn, "Unspecified")) {
115116
switch(dinfo->path.io_mode) {
116117
case DDCA_IO_I2C:
117118
snprintf(id, size, "/dev/i2c-%d", dinfo->path.path.i2c_busno);
@@ -423,9 +424,17 @@ static int set_external_backlight(bl_t *bl, int value) {
423424
#ifdef DDC_PRESENT
424425
DDCA_Display_Handle dh = NULL;
425426
if (!ddca_open_display2(bl->dev, false, &dh)) {
427+
DDCA_Vcp_Feature_Code specific_br_code;
428+
char specific_br_env[64];
429+
snprintf(specific_br_env, sizeof(specific_br_env), BL_VCP_ENV"_%s", bl->sn);
430+
if (getenv(specific_br_env)) {
431+
specific_br_code = strtol(getenv(specific_br_env), NULL, 16);
432+
} else {
433+
specific_br_code = br_code;
434+
}
426435
int8_t new_sh = (value >> 8) & 0xff;
427436
int8_t new_sl = value & 0xff;
428-
ret = ddca_set_non_table_vcp_value(dh, br_code, new_sh, new_sl);
437+
ret = ddca_set_non_table_vcp_value(dh, specific_br_code, new_sh, new_sl);
429438
ddca_close_display(dh);
430439
}
431440
#endif

src/modules/dpms.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include "dpms.h"
44
#include "polkit.h"
5+
#include "bus_utils.h"
56

67
static int method_getdpms(sd_bus_message *m, void *userdata, sd_bus_error *ret_error);
78
static int method_setdpms(sd_bus_message *m, void *userdata, sd_bus_error *ret_error);
@@ -94,6 +95,8 @@ static int method_getdpms(sd_bus_message *m, void *userdata, sd_bus_error *ret_e
9495
return r;
9596
}
9697

98+
bus_sender_fill_creds(m); // used by PW plugin
99+
97100
/*
98101
* Note: this is freed by drm plugin if it is an empty string
99102
* to get a default drm device.
@@ -148,6 +151,8 @@ static int method_setdpms(sd_bus_message *m, void *userdata, sd_bus_error *ret_e
148151
return -EINVAL;
149152
}
150153

154+
bus_sender_fill_creds(m); // used by PW plugin
155+
151156
/*
152157
* Note: this is freed by drm plugin if it is an empty string
153158
* to get a default drm device.

src/modules/dpms_plugins/xorg.c

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
#include <X11/Xlib.h>
1+
#include "xorg_utils.h"
22
#include <X11/extensions/dpms.h>
33
#include "dpms.h"
4+
#include "bus_utils.h"
45

56
DPMS("Xorg");
67

@@ -17,9 +18,7 @@ static int get(const char **display, const char *xauthority) {
1718
CARD16 s;
1819
int ret = WRONG_PLUGIN;
1920

20-
setenv("XAUTHORITY", xauthority, 1);
21-
22-
Display *dpy = XOpenDisplay(*display);
21+
Display *dpy = fetch_xorg_display(display, xauthority);
2322
if (dpy) {
2423
if (DPMSCapable(dpy)) {
2524
DPMSInfo(dpy, &s, &onoff);
@@ -28,19 +27,14 @@ static int get(const char **display, const char *xauthority) {
2827
ret = UNSUPPORTED;
2928
}
3029
XCloseDisplay(dpy);
31-
}
32-
33-
unsetenv("XAUTHORITY");
30+
}
3431
return ret;
3532
}
3633

3734
static int set(const char **display, const char *xauthority, int dpms_level) {
3835
int ret = WRONG_PLUGIN;
3936

40-
/* set xauthority cookie */
41-
setenv("XAUTHORITY", xauthority, 1);
42-
43-
Display *dpy = XOpenDisplay(*display);
37+
Display *dpy = fetch_xorg_display(display, xauthority);
4438
if (dpy) {
4539
if (DPMSCapable(dpy)) {
4640
DPMSEnable(dpy);
@@ -52,8 +46,5 @@ static int set(const char **display, const char *xauthority, int dpms_level) {
5246
}
5347
XCloseDisplay(dpy);
5448
}
55-
56-
/* Drop xauthority cookie */
57-
unsetenv("XAUTHORITY");
5849
return ret;
5950
}

src/modules/gamma.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <module/map.h>
1111
#include <math.h>
1212
#include "gamma.h"
13+
#include "bus_utils.h"
1314

1415
static unsigned short get_red(int temp);
1516
static unsigned short get_green(int temp);
@@ -269,6 +270,8 @@ static int method_setgamma(sd_bus_message *m, void *userdata, sd_bus_error *ret_
269270
if (temp < 1000 || temp > 10000) {
270271
error = EINVAL;
271272
} else {
273+
bus_sender_fill_creds(m);
274+
272275
gamma_client *sc = map_get(clients, display);
273276
if (!sc) {
274277
sc = fetch_client(userdata, display, env, &error);
@@ -311,6 +314,8 @@ static int method_getgamma(sd_bus_message *m, void *userdata, sd_bus_error *ret_
311314
return r;
312315
}
313316

317+
bus_sender_fill_creds(m); // used by PW plugin
318+
314319
gamma_client *cl = map_get(clients, display);
315320
if (cl) {
316321
temp = cl->current_temp;

0 commit comments

Comments
 (0)