mirror of
https://repo.dec05eba.com/gpu-screen-recorder
synced 2026-04-02 01:36:06 +09:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f23308444a | ||
|
|
fadf9b64de | ||
|
|
e6f1d47eef | ||
|
|
7af4f106e7 | ||
|
|
a26aa2dd3e | ||
|
|
8364aaadad | ||
|
|
5f3a14d3f6 | ||
|
|
0129ab140d | ||
|
|
0fff47cc58 | ||
|
|
902556b143 | ||
|
|
6024a54551 | ||
|
|
23122ce9b0 | ||
|
|
f071d8c373 |
@@ -68,7 +68,8 @@ Here are some known unofficial packages:
|
||||
* Nix: [NixOS wiki](https://wiki.nixos.org/wiki/Gpu-screen-recorder)
|
||||
* openSUSE: [openSUSE software repository](https://software.opensuse.org/package/gpu-screen-recorder)
|
||||
* Fedora: [Copr](https://copr.fedorainfracloud.org/coprs/brycensranch/gpu-screen-recorder-git/)
|
||||
* OpenMandriva: [gpu-screen-recorder](https://github.com/OpenMandrivaAssociation/gpu-screen-recorder/tree/master)
|
||||
* OpenMandriva: [gpu-screen-recorder](https://github.com/OpenMandrivaAssociation/gpu-screen-recorder)
|
||||
* Solus: [gpu-screen-recorder](https://github.com/getsolus/packages/tree/main/packages/g/gpu-screen-recorder)
|
||||
|
||||
# Dependencies
|
||||
GPU Screen Recorder uses meson build system so you need to install `meson` to build GPU Screen Recorder.
|
||||
|
||||
4
TODO
4
TODO
@@ -241,4 +241,6 @@ Support reconnecting (and setting things up again) if the audio server is restar
|
||||
|
||||
Find out how nvidia-smi fixes nvenc not working on opensuse and do that ourselves instead of relying on nvidia-smi that is not always installed.
|
||||
|
||||
Pulseaudio code: add "running" variable to loops to allow stopping the running code when quitting.
|
||||
Pulseaudio code: add "running" variable to loops to allow stopping the running code when quitting.
|
||||
|
||||
Scale screenshot frame libswscale or implement lanczos shader for improved scaline for video as well.
|
||||
|
||||
@@ -37,7 +37,11 @@ void gsr_dbus_deinit(gsr_dbus *self);
|
||||
/* The follow functions should be called in order to setup ScreenCast properly */
|
||||
/* These functions that return an int return the response status code */
|
||||
int gsr_dbus_screencast_create_session(gsr_dbus *self, char **session_handle);
|
||||
int gsr_dbus_screencast_select_sources(gsr_dbus *self, const char *session_handle, gsr_portal_capture_type capture_type, gsr_portal_cursor_mode cursor_mode);
|
||||
/*
|
||||
|capture_type| is a bitmask of gsr_portal_capture_type values. gsr_portal_capture_type values that are not supported by the desktop portal will be ignored.
|
||||
|gsr_portal_cursor_mode| is a bitmask of gsr_portal_cursor_mode values. gsr_portal_cursor_mode values that are not supported will be ignored.
|
||||
*/
|
||||
int gsr_dbus_screencast_select_sources(gsr_dbus *self, const char *session_handle, uint32_t capture_type, uint32_t cursor_mode);
|
||||
int gsr_dbus_screencast_start(gsr_dbus *self, const char *session_handle, uint32_t *pipewire_node);
|
||||
bool gsr_dbus_screencast_open_pipewire_remote(gsr_dbus *self, const char *session_handle, int *pipewire_fd);
|
||||
const char* gsr_dbus_screencast_get_restore_token(gsr_dbus *self);
|
||||
|
||||
@@ -80,6 +80,7 @@ typedef struct {
|
||||
|
||||
struct pw_proxy *metadata_proxy;
|
||||
struct spa_hook metadata_listener;
|
||||
struct spa_hook metadata_proxy_listener;
|
||||
char default_output_device_name[128];
|
||||
char default_input_device_name[128];
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
|
||||
typedef struct {
|
||||
int drmfd;
|
||||
drmModePlaneResPtr planes;
|
||||
} gsr_drm;
|
||||
|
||||
typedef struct {
|
||||
@@ -289,21 +288,31 @@ static int drm_prime_handles_to_fds(gsr_drm *drm, drmModeFB2Ptr drmfb, int *fb_f
|
||||
return GSR_KMS_MAX_DMA_BUFS;
|
||||
}
|
||||
|
||||
static int kms_get_fb(gsr_drm *drm, gsr_kms_response *response, connector_to_crtc_map *c2crtc_map) {
|
||||
static int kms_get_fb(gsr_drm *drm, gsr_kms_response *response) {
|
||||
int result = -1;
|
||||
|
||||
response->result = KMS_RESULT_OK;
|
||||
response->err_msg[0] = '\0';
|
||||
response->num_items = 0;
|
||||
|
||||
for(uint32_t i = 0; i < drm->planes->count_planes && response->num_items < GSR_KMS_MAX_ITEMS; ++i) {
|
||||
connector_to_crtc_map c2crtc_map;
|
||||
c2crtc_map.num_maps = 0;
|
||||
map_crtc_to_connector_ids(drm, &c2crtc_map);
|
||||
|
||||
drmModePlaneResPtr planes = drmModeGetPlaneResources(drm->drmfd);
|
||||
if(!planes) {
|
||||
fprintf(stderr, "kms server error: failed to get plane resources, error: %s\n", strerror(errno));
|
||||
goto done;
|
||||
}
|
||||
|
||||
for(uint32_t i = 0; i < planes->count_planes && response->num_items < GSR_KMS_MAX_ITEMS; ++i) {
|
||||
drmModePlanePtr plane = NULL;
|
||||
drmModeFB2Ptr drmfb = NULL;
|
||||
|
||||
plane = drmModeGetPlane(drm->drmfd, drm->planes->planes[i]);
|
||||
plane = drmModeGetPlane(drm->drmfd, planes->planes[i]);
|
||||
if(!plane) {
|
||||
response->result = KMS_RESULT_FAILED_TO_GET_PLANE;
|
||||
snprintf(response->err_msg, sizeof(response->err_msg), "failed to get drm plane with id %u, error: %s\n", drm->planes->planes[i], strerror(errno));
|
||||
snprintf(response->err_msg, sizeof(response->err_msg), "failed to get drm plane with id %u, error: %s\n", planes->planes[i], strerror(errno));
|
||||
fprintf(stderr, "kms server error: %s\n", response->err_msg);
|
||||
goto next;
|
||||
}
|
||||
@@ -346,7 +355,7 @@ static int kms_get_fb(gsr_drm *drm, gsr_kms_response *response, connector_to_crt
|
||||
|
||||
const int item_index = response->num_items;
|
||||
|
||||
const connector_crtc_pair *crtc_pair = get_connector_pair_by_crtc_id(c2crtc_map, plane->crtc_id);
|
||||
const connector_crtc_pair *crtc_pair = get_connector_pair_by_crtc_id(&c2crtc_map, plane->crtc_id);
|
||||
if(crtc_pair && crtc_pair->hdr_metadata_blob_id) {
|
||||
response->items[item_index].has_hdr_metadata = get_hdr_metadata(drm->drmfd, crtc_pair->hdr_metadata_blob_id, &response->items[item_index].hdr_metadata);
|
||||
} else {
|
||||
@@ -389,6 +398,11 @@ static int kms_get_fb(gsr_drm *drm, gsr_kms_response *response, connector_to_crt
|
||||
drmModeFreePlane(plane);
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
if(planes)
|
||||
drmModeFreePlaneResources(planes);
|
||||
|
||||
if(response->num_items > 0)
|
||||
response->result = KMS_RESULT_OK;
|
||||
|
||||
@@ -499,7 +513,6 @@ int main(int argc, char **argv) {
|
||||
int socket_fd = 0;
|
||||
gsr_drm drm;
|
||||
drm.drmfd = 0;
|
||||
drm.planes = NULL;
|
||||
|
||||
if(argc != 3) {
|
||||
fprintf(stderr, "usage: gsr-kms-server <domain_socket_path> <card_path>\n");
|
||||
@@ -532,17 +545,6 @@ int main(int argc, char **argv) {
|
||||
fprintf(stderr, "kms server warning: drmSetClientCap DRM_CLIENT_CAP_ATOMIC failed, error: %s. The wrong monitor may be captured as a result\n", strerror(errno));
|
||||
}
|
||||
|
||||
drm.planes = drmModeGetPlaneResources(drm.drmfd);
|
||||
if(!drm.planes) {
|
||||
fprintf(stderr, "kms server error: failed to get plane resources, error: %s\n", strerror(errno));
|
||||
res = 2;
|
||||
goto done;
|
||||
}
|
||||
|
||||
connector_to_crtc_map c2crtc_map;
|
||||
c2crtc_map.num_maps = 0;
|
||||
map_crtc_to_connector_ids(&drm, &c2crtc_map);
|
||||
|
||||
fprintf(stderr, "kms server info: connecting to the client\n");
|
||||
bool connected = false;
|
||||
const double connect_timeout_sec = 5.0;
|
||||
@@ -642,7 +644,7 @@ int main(int argc, char **argv) {
|
||||
response.version = GSR_KMS_PROTOCOL_VERSION;
|
||||
response.num_items = 0;
|
||||
|
||||
if(kms_get_fb(&drm, &response, &c2crtc_map) == 0) {
|
||||
if(kms_get_fb(&drm, &response) == 0) {
|
||||
if(send_msg_to_client(socket_fd, &response) == -1)
|
||||
fprintf(stderr, "kms server error: failed to respond to client KMS_REQUEST_TYPE_GET_KMS request\n");
|
||||
} else {
|
||||
@@ -681,8 +683,6 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
done:
|
||||
if(drm.planes)
|
||||
drmModeFreePlaneResources(drm.planes);
|
||||
if(drm.drmfd > 0)
|
||||
close(drm.drmfd);
|
||||
if(socket_fd > 0)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
project('gpu-screen-recorder', ['c', 'cpp'], version : '5.2.0', default_options : ['warning_level=2'])
|
||||
project('gpu-screen-recorder', ['c', 'cpp'], version : '5.2.3', default_options : ['warning_level=2'])
|
||||
|
||||
add_project_arguments('-Wshadow', language : ['c', 'cpp'])
|
||||
if get_option('buildtype') == 'debug'
|
||||
@@ -22,8 +22,8 @@ src = [
|
||||
'src/codec_query/vaapi.c',
|
||||
'src/codec_query/vulkan.c',
|
||||
'src/window/window.c',
|
||||
'src/window/window_x11.c',
|
||||
'src/window/window_wayland.c',
|
||||
'src/window/x11.c',
|
||||
'src/window/wayland.c',
|
||||
'src/egl.c',
|
||||
'src/cuda.c',
|
||||
'src/xnvctrl.c',
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "gpu-screen-recorder"
|
||||
type = "executable"
|
||||
version = "5.2.0"
|
||||
version = "5.2.3"
|
||||
platforms = ["posix"]
|
||||
|
||||
[config]
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
window=$(xdotool selectwindow)
|
||||
window_name=$(xdotool getwindowname "$window" || xdotool getwindowclassname "$window" || echo "Game")
|
||||
window_name="$(echo "$window_name" | tr '/\\' '_')"
|
||||
gpu-screen-recorder -w "$window" -f 60 -c mkv -a default_output -r 60 -o "$HOME/Videos/Replays/$window_name"
|
||||
gpu-screen-recorder -w "$window" -f 60 -c mkv -a default_output -bm cbr -q 45000 -r 60 -o "$HOME/Videos/Replays/$window_name"
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
pidof -q gpu-screen-recorder && exit 0
|
||||
video_path="$HOME/Videos"
|
||||
mkdir -p "$video_path"
|
||||
gpu-screen-recorder -w screen -f 60 -a default_output -c mkv -r 30 -o "$video_path"
|
||||
gpu-screen-recorder -w screen -f 60 -a default_output -c mkv -bm cbr -q 45000 -r 30 -o "$video_path"
|
||||
|
||||
34
src/dbus.c
34
src/dbus.c
@@ -614,9 +614,41 @@ int gsr_dbus_screencast_create_session(gsr_dbus *self, char **session_handle) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gsr_dbus_screencast_select_sources(gsr_dbus *self, const char *session_handle, gsr_portal_capture_type capture_type, gsr_portal_cursor_mode cursor_mode) {
|
||||
static uint32_t unset_unsupported_capture_types(uint32_t requested_capture_types, uint32_t available_capture_types) {
|
||||
if(!(available_capture_types & GSR_PORTAL_CAPTURE_TYPE_MONITOR))
|
||||
requested_capture_types &= ~GSR_PORTAL_CAPTURE_TYPE_MONITOR;
|
||||
if(!(available_capture_types & GSR_PORTAL_CAPTURE_TYPE_WINDOW))
|
||||
requested_capture_types &= ~GSR_PORTAL_CAPTURE_TYPE_WINDOW;
|
||||
if(!(available_capture_types & GSR_PORTAL_CAPTURE_TYPE_VIRTUAL))
|
||||
requested_capture_types &= ~GSR_PORTAL_CAPTURE_TYPE_VIRTUAL;
|
||||
return requested_capture_types;
|
||||
}
|
||||
|
||||
static uint32_t unset_unsupported_cursor_modes(uint32_t requested_cursor_modes, uint32_t available_cursor_modes) {
|
||||
if(!(available_cursor_modes & GSR_PORTAL_CURSOR_MODE_HIDDEN))
|
||||
requested_cursor_modes &= ~GSR_PORTAL_CURSOR_MODE_HIDDEN;
|
||||
if(!(available_cursor_modes & GSR_PORTAL_CURSOR_MODE_EMBEDDED))
|
||||
requested_cursor_modes &= ~GSR_PORTAL_CURSOR_MODE_EMBEDDED;
|
||||
if(!(available_cursor_modes & GSR_PORTAL_CURSOR_MODE_METADATA))
|
||||
requested_cursor_modes &= ~GSR_PORTAL_CURSOR_MODE_METADATA;
|
||||
return requested_cursor_modes;
|
||||
}
|
||||
|
||||
int gsr_dbus_screencast_select_sources(gsr_dbus *self, const char *session_handle, uint32_t capture_type, uint32_t cursor_mode) {
|
||||
assert(session_handle);
|
||||
|
||||
uint32_t available_source_types = 0;
|
||||
gsr_dbus_desktop_portal_get_property(self, "org.freedesktop.portal.ScreenCast", "AvailableSourceTypes", &available_source_types);
|
||||
if(available_source_types == 0)
|
||||
fprintf(stderr, "gsr error: gsr_dbus_screencast_select_sources: no source types are available\n");
|
||||
capture_type = unset_unsupported_capture_types(capture_type, available_source_types);
|
||||
|
||||
uint32_t available_cursor_modes = 0;
|
||||
gsr_dbus_desktop_portal_get_property(self, "org.freedesktop.portal.ScreenCast", "AvailableCursorModes", &available_cursor_modes);
|
||||
if(available_cursor_modes == 0)
|
||||
fprintf(stderr, "gsr error: gsr_dbus_screencast_select_sources: no cursors modes are available\n");
|
||||
cursor_mode = unset_unsupported_cursor_modes(cursor_mode, available_cursor_modes);
|
||||
|
||||
char handle_token[64];
|
||||
gsr_dbus_portal_get_unique_handle_token(self, handle_token, sizeof(handle_token));
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@ extern "C" {
|
||||
#include "../include/codec_query/nvenc.h"
|
||||
#include "../include/codec_query/vaapi.h"
|
||||
#include "../include/codec_query/vulkan.h"
|
||||
#include "../include/window/window_x11.h"
|
||||
#include "../include/window/window_wayland.h"
|
||||
#include "../include/window/x11.h"
|
||||
#include "../include/window/wayland.h"
|
||||
#include "../include/egl.h"
|
||||
#include "../include/utils.h"
|
||||
#include "../include/damage.h"
|
||||
|
||||
@@ -329,22 +329,20 @@ static const struct pw_metadata_events metadata_events = {
|
||||
static void on_metadata_proxy_removed_cb(void *data) {
|
||||
gsr_pipewire_audio *self = data;
|
||||
if(self->metadata_proxy) {
|
||||
// TODO:
|
||||
//pw_proxy_destroy(self->metadata_proxy);
|
||||
//self->metadata_proxy = NULL;
|
||||
pw_proxy_destroy(self->metadata_proxy);
|
||||
self->metadata_proxy = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void on_metadata_proxy_destroy_cb(void *data) {
|
||||
gsr_pipewire_audio *self = data;
|
||||
|
||||
// TODO:
|
||||
//spa_hook_remove(&metadata->metadata_listener);
|
||||
//spa_hook_remove(&metadata->proxy_listener);
|
||||
//spa_zero(metadata->metadata_listener);
|
||||
//spa_zero(metadata->proxy_listener);
|
||||
spa_hook_remove(&self->metadata_listener);
|
||||
spa_hook_remove(&self->metadata_proxy_listener);
|
||||
spa_zero(self->metadata_listener);
|
||||
spa_zero(self->metadata_proxy_listener);
|
||||
|
||||
//self->metadata_proxy = NULL;
|
||||
self->metadata_proxy = NULL;
|
||||
}
|
||||
|
||||
static const struct pw_proxy_events metadata_proxy_events = {
|
||||
@@ -365,11 +363,8 @@ static bool gsr_pipewire_audio_listen_on_metadata(gsr_pipewire_audio *self, uint
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO:
|
||||
pw_proxy_add_object_listener(self->metadata_proxy, &self->metadata_listener, &metadata_events, self);
|
||||
|
||||
//struct spa_hook proxy_listener;
|
||||
//pw_proxy_add_listener(self->metadata_proxy, &proxy_listener, &metadata_proxy_events, self);
|
||||
pw_proxy_add_listener(self->metadata_proxy, &self->metadata_proxy_listener, &metadata_proxy_events, self);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -549,15 +544,14 @@ bool gsr_pipewire_audio_init(gsr_pipewire_audio *self) {
|
||||
|
||||
pw_context_load_module(self->context, "libpipewire-module-link-factory", NULL, NULL);
|
||||
|
||||
pw_thread_loop_lock(self->thread_loop);
|
||||
|
||||
if(pw_thread_loop_start(self->thread_loop) < 0) {
|
||||
fprintf(stderr, "gsr error: gsr_pipewire_audio_init: failed to start thread\n");
|
||||
pw_thread_loop_unlock(self->thread_loop);
|
||||
gsr_pipewire_audio_deinit(self);
|
||||
return false;
|
||||
}
|
||||
|
||||
pw_thread_loop_lock(self->thread_loop);
|
||||
|
||||
self->core = pw_context_connect(self->context, pw_properties_new(PW_KEY_REMOTE_NAME, NULL, NULL), 0);
|
||||
if(!self->core) {
|
||||
pw_thread_loop_unlock(self->thread_loop);
|
||||
@@ -568,11 +562,12 @@ bool gsr_pipewire_audio_init(gsr_pipewire_audio *self) {
|
||||
// TODO: Error check
|
||||
pw_core_add_listener(self->core, &self->core_listener, &core_events, self);
|
||||
|
||||
self->server_version_sync = pw_core_sync(self->core, PW_ID_CORE, 0);
|
||||
pw_thread_loop_wait(self->thread_loop);
|
||||
|
||||
self->registry = pw_core_get_registry(self->core, PW_VERSION_REGISTRY, 0);
|
||||
pw_registry_add_listener(self->registry, &self->registry_listener, ®istry_events, self);
|
||||
|
||||
self->server_version_sync = pw_core_sync(self->core, PW_ID_CORE, 0);
|
||||
pw_thread_loop_wait(self->thread_loop);
|
||||
pw_thread_loop_unlock(self->thread_loop);
|
||||
return true;
|
||||
}
|
||||
@@ -592,7 +587,11 @@ void gsr_pipewire_audio_deinit(gsr_pipewire_audio *self) {
|
||||
self->num_virtual_sink_proxies = 0;
|
||||
|
||||
if(self->metadata_proxy) {
|
||||
spa_hook_remove(&self->metadata_listener);
|
||||
spa_hook_remove(&self->metadata_proxy_listener);
|
||||
pw_proxy_destroy(self->metadata_proxy);
|
||||
spa_zero(self->metadata_listener);
|
||||
spa_zero(self->metadata_proxy_listener);
|
||||
self->metadata_proxy = NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -413,6 +413,7 @@ static void renegotiate_format(void *data, uint64_t expirations) {
|
||||
uint8_t params_buffer[4096];
|
||||
struct spa_pod_builder pod_builder = SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer));
|
||||
if (!gsr_pipewire_video_build_format_params(self, &pod_builder, params, &num_video_formats)) {
|
||||
fprintf(stderr, "gsr error: renegotiate_format: failed to build formats\n");
|
||||
pw_thread_loop_unlock(self->thread_loop);
|
||||
return;
|
||||
}
|
||||
@@ -509,6 +510,9 @@ static bool gsr_pipewire_video_setup_stream(gsr_pipewire_video *self) {
|
||||
// TODO: Error check
|
||||
pw_core_add_listener(self->core, &self->core_listener, &core_events, self);
|
||||
|
||||
self->server_version_sync = pw_core_sync(self->core, PW_ID_CORE, 0);
|
||||
pw_thread_loop_wait(self->thread_loop);
|
||||
|
||||
gsr_pipewire_video_init_modifiers(self);
|
||||
|
||||
// TODO: Cleanup?
|
||||
@@ -519,9 +523,6 @@ static bool gsr_pipewire_video_setup_stream(gsr_pipewire_video *self) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
self->server_version_sync = pw_core_sync(self->core, PW_ID_CORE, 0);
|
||||
pw_thread_loop_wait(self->thread_loop);
|
||||
|
||||
self->stream = pw_stream_new(self->core, "com.dec05eba.gpu_screen_recorder",
|
||||
pw_properties_new(PW_KEY_MEDIA_TYPE, "Video",
|
||||
PW_KEY_MEDIA_CATEGORY, "Capture",
|
||||
|
||||
@@ -101,7 +101,7 @@ static void subscribe_update_default_devices(pa_context*, const pa_server_info *
|
||||
if(server_info->default_sink_name) {
|
||||
// TODO: Size check
|
||||
snprintf(handle->default_output_device_name, sizeof(handle->default_output_device_name), "%s.monitor", server_info->default_sink_name);
|
||||
if(handle->device_type == DeviceType::DEFAULT_OUTPUT && strcmp(handle->device_name, server_info->default_sink_name) != 0) {
|
||||
if(handle->device_type == DeviceType::DEFAULT_OUTPUT && strcmp(handle->device_name, handle->default_output_device_name) != 0) {
|
||||
handle->reconnect = true;
|
||||
handle->reconnect_last_tried_seconds = clock_get_monotonic_seconds();
|
||||
// TODO: Size check
|
||||
@@ -112,7 +112,7 @@ static void subscribe_update_default_devices(pa_context*, const pa_server_info *
|
||||
if(server_info->default_source_name) {
|
||||
// TODO: Size check
|
||||
snprintf(handle->default_input_device_name, sizeof(handle->default_input_device_name), "%s", server_info->default_source_name);
|
||||
if(handle->device_type == DeviceType::DEFAULT_INPUT && strcmp(handle->device_name, server_info->default_sink_name) != 0) {
|
||||
if(handle->device_type == DeviceType::DEFAULT_INPUT && strcmp(handle->device_name, handle->default_input_device_name) != 0) {
|
||||
handle->reconnect = true;
|
||||
handle->reconnect_last_tried_seconds = clock_get_monotonic_seconds();
|
||||
// TODO: Size check
|
||||
@@ -124,7 +124,7 @@ static void subscribe_update_default_devices(pa_context*, const pa_server_info *
|
||||
static void subscribe_cb(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
|
||||
(void)idx;
|
||||
pa_handle *handle = (pa_handle*)userdata;
|
||||
if(t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
|
||||
if((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SERVER) {
|
||||
pa_operation *pa = pa_context_get_server_info(c, subscribe_update_default_devices, handle);
|
||||
if(pa)
|
||||
pa_operation_unref(pa);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "../../include/window/window_wayland.h"
|
||||
#include "../../include/window/wayland.h"
|
||||
|
||||
#include "../../include/vec2.h"
|
||||
#include "../../include/defs.h"
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "../../include/window/window_x11.h"
|
||||
#include "../../include/window/x11.h"
|
||||
|
||||
#include "../../include/vec2.h"
|
||||
#include "../../include/defs.h"
|
||||
Reference in New Issue
Block a user