Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 33 additions & 11 deletions src/platform/linux/pipewire.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,18 @@
constexpr int SPA_VIDEO_TRANSFER_SMPTE2084 = 14;
#endif

#if PW_CHECK_VERSION(0, 3, 75)
// Runtime linked library version checks are available. Check for pipewire 0.3.64 which documented object serial support and deprecated node id.
const bool SUNSHINE_USE_PIPEWIRE_OBJECT_SERIAL = pw_check_library_version(0, 3, 64);
#elifdef PW_KEY_TARGET_OBJECT
// Runtime linked library version checks are UNAVAILABLE but necessary PW_KEY_TARGET_OBJECT for object serial support is available.
constexpr bool SUNSHINE_USE_PIPEWIRE_OBJECT_SERIAL = true;
#else
// Pipewire object serials are unsupported without PW_KEY_TARGET_OBJECT (we define it here so compilation won't break but don't use it).
constexpr bool SUNSHINE_USE_PIPEWIRE_OBJECT_SERIAL = false;
#define PW_KEY_TARGET_OBJECT "target.object"
#endif

namespace {
// Buffer and limit constants
constexpr int SPA_POD_BUFFER_SIZE = 4096;
Expand Down Expand Up @@ -216,6 +228,7 @@ namespace pipewire {

int ensure_stream(const platf::mem_type_e mem_type, const uint32_t width, const uint32_t height, const uint32_t refresh_rate, const struct dmabuf_format_info_t *dmabuf_infos, const int n_dmabuf_infos, const bool display_is_nvidia) {
pw_thread_loop_lock(loop);
int result = 0;
if (!stream_data.stream) {
if (!core) {
BOOST_LOG(debug) << "[pipewire] PW core not available. Cannot ensure stream."sv;
Expand All @@ -224,14 +237,6 @@ namespace pipewire {
}

struct pw_properties *props = pw_properties_new(PW_KEY_MEDIA_TYPE, "Video", PW_KEY_MEDIA_CATEGORY, "Capture", PW_KEY_MEDIA_ROLE, "Screen", nullptr);
#ifdef PW_KEY_TARGET_OBJECT
// If pipewire supports setting a PW_KEY_TARGET_OBJECT via object serial and the serial is valid (lower 32-bits not SPA_ID_INVALID, see PW_KEY_OBJECT_SERIAL docs), use it.
if ((object_serial & SPA_ID_INVALID) != SPA_ID_INVALID) {
BOOST_LOG(debug) << "[pipewire] Set PW stream target object to serial: "sv << object_serial;
pw_properties_setf(props, PW_KEY_TARGET_OBJECT, "%" PRIu64, object_serial);
node = PW_ID_ANY; // Force pw_connect_stream to connect via object serial in PW_KEY_TARGET_OBJECT with this value.
}
#endif

BOOST_LOG(debug) << "[pipewire] Create PW stream"sv;
stream_data.stream = pw_stream_new(core, "Sunshine Video Capture", props);
Expand Down Expand Up @@ -264,11 +269,28 @@ namespace pipewire {
params[n_params] = format_param;
n_params++;
}
BOOST_LOG(debug) << "[pipewire] Connect PW stream - fd: "sv << fd << " node: "sv << node << " object serial: "sv << object_serial;
pw_stream_connect(stream_data.stream, PW_DIRECTION_INPUT, node, (enum pw_stream_flags)(PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_MAP_BUFFERS), params.data(), n_params);

// Connection via pipewire object serial if it is supported and the serial is valid (lower 32-bits != SPA_ID_INVALID, see also PW_KEY_OBJECT_SERIAL docs)
if (SUNSHINE_USE_PIPEWIRE_OBJECT_SERIAL && (object_serial & SPA_ID_INVALID) != SPA_ID_INVALID) {
pw_properties_setf(props, PW_KEY_TARGET_OBJECT, "%" PRIu64, object_serial);
BOOST_LOG(debug) << "[pipewire] Connect PW stream - fd: "sv << fd << " object serial: "sv << object_serial;
result = pw_stream_connect(stream_data.stream, PW_DIRECTION_INPUT, PW_ID_ANY, (enum pw_stream_flags)(PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_MAP_BUFFERS), params.data(), n_params);
if (result < 0) {
// Unset object serial for retry with node id
pw_properties_set(props, PW_KEY_TARGET_OBJECT, nullptr);
}
} else {
result = -1; // Mark failed so we try to connect via node id
}
// Connection via legacy (and deprecated) pipewire node id
if (result < 0) {
BOOST_LOG(debug) << "[pipewire] Connect PW stream - fd: "sv << fd << " node: "sv << node;
result = pw_stream_connect(stream_data.stream, PW_DIRECTION_INPUT, node, (enum pw_stream_flags)(PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_MAP_BUFFERS), params.data(), n_params);
}
}

pw_thread_loop_unlock(loop);
return 0;
return result;
}

static void close_img_fds(egl::img_descriptor_t *img_descriptor) {
Expand Down
Loading