Skip to content

Commit ed38479

Browse files
committed
WIP: Make XDG notification end stream trigger on pipewire error
Instead of stopping the stream by detecting the same resolution/position do so based on the pipewire error (no target node available). This persists until the portal is restarted (either by invalidation or Sunshine restart)
1 parent 33be5db commit ed38479

1 file changed

Lines changed: 33 additions & 29 deletions

File tree

src/platform/linux/portalgrab.cpp

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -741,8 +741,10 @@ namespace portal {
741741
}
742742

743743
dbus_.reset();
744-
745744
valid_ = false;
745+
746+
// Reset cached no target node indicator as the portal was reset
747+
no_target_node_ = false;
746748
}
747749
} catch (const std::exception &e) {
748750
BOOST_LOG(error) << "[portalgrab] Exception during session invalidation: "sv << e.what();
@@ -759,6 +761,14 @@ namespace portal {
759761
maxframerate_failed_ = true;
760762
}
761763

764+
bool has_no_target_node() const {
765+
return no_target_node_;
766+
}
767+
768+
void set_no_target_node() {
769+
no_target_node_ = true;
770+
}
771+
762772
private:
763773
session_cache_t() = default;
764774

@@ -779,6 +789,7 @@ namespace portal {
779789
std::vector<pipewire_screenstream_t> pipewire_streams_;
780790
bool valid_ = false;
781791
bool maxframerate_failed_ = false;
792+
bool no_target_node_ = false;
782793
};
783794

784795
session_cache_t &session_cache_t::instance() {
@@ -1111,6 +1122,10 @@ namespace portal {
11111122
}
11121123
break;
11131124
case PW_STREAM_STATE_ERROR:
1125+
if (std::string(err_msg).contains("no target node available") && !session_cache_t::instance().has_no_target_node()) {
1126+
BOOST_LOG(warning) << "[portalgrab] Pipewire node unavailable"sv;
1127+
session_cache_t::instance().set_no_target_node();
1128+
}else
11141129
if (old != PW_STREAM_STATE_STREAMING && !session_cache_t::instance().is_maxframerate_failed()) {
11151130
BOOST_LOG(warning) << "[portalgrab] Negotiation failed, will retry without maxFramerate"sv;
11161131
session_cache_t::instance().set_maxframerate_failed();
@@ -1294,7 +1309,6 @@ namespace portal {
12941309
if (session_cache_t::instance().get_or_create_session(pipewire_fd, pipewire_streams) < 0) {
12951310
return -1;
12961311
}
1297-
12981312
// Match display_name to a stream from the pipewire_streams vector
12991313
pipewire_screenstream_t stream = match_display_name_to_stream(pipewire_streams, display_name);
13001314
if (!display_name.empty() && (stream.width < 0 || stream.height < 0)) {
@@ -1320,6 +1334,12 @@ namespace portal {
13201334

13211335
framerate = config.framerate;
13221336

1337+
// Fail if the session cache indicates that there is no target node available (e.g. after user cancel)
1338+
if (session_cache_t::instance().has_no_target_node()) {
1339+
BOOST_LOG(warning) << "[portalgrab] Display init failed as PipeWire stream was stopped by user."sv;
1340+
return -1;
1341+
}
1342+
13231343
if (!shared_state) {
13241344
shared_state = std::make_shared<shared_state_t>();
13251345
} else {
@@ -1331,7 +1351,6 @@ namespace portal {
13311351

13321352
// Start PipeWire now so format negotiation can proceed before capture start
13331353
pipewire.ensure_stream(mem_type, width, height, framerate, dmabuf_infos.data(), n_dmabuf_infos, display_is_nvidia);
1334-
13351354
int timeout_ms = 1500;
13361355
int negotiated_w = 0;
13371356
int negotiated_h = 0;
@@ -1346,23 +1365,18 @@ namespace portal {
13461365
timeout_ms -= 10;
13471366
}
13481367

1349-
// Check previous logical dimensions
1350-
// FIXME: Handle switch_display_events that go to the same display without disconnecting the stream
1351-
// if (previous_width.load() == width && previous_height.load() == height && previous_pos_x.load() == pos_x && previous_pos_y.load() == pos_y) {
1352-
// if (capture_running.load()) {
1353-
// {
1354-
// std::scoped_lock lock(pipewire.frame_mutex());
1355-
// stream_stopped.store(true);
1356-
// }
1357-
// pipewire.frame_cv().notify_all();
1358-
// }
1359-
// } else {
1360-
previous_width.store(width);
1361-
previous_height.store(height);
1362-
previous_pos_x.store(pos_x);
1363-
previous_pos_y.store(pos_y);
1364-
// }
1368+
// Stop running capture if the pipewire stream is not connected for any reason or the use ended the portal session
1369+
if ((timeout_ms <= 0 && !shared_state->stream_connected.load()) || session_cache_t::instance().has_no_target_node()) {
1370+
if (capture_running.load()) {
1371+
{
1372+
std::scoped_lock lock(pipewire.frame_mutex());
1373+
stream_stopped.store(true);
1374+
}
1375+
pipewire.frame_cv().notify_all();
1376+
}
1377+
}
13651378

1379+
// Set width and height to the values negotiated by pipewire
13661380
if (negotiated_w > 0 && negotiated_h > 0 && (negotiated_w != width || negotiated_h != height)) {
13671381
BOOST_LOG(info) << "[portalgrab] Using negotiated resolution "sv
13681382
<< negotiated_w << "x" << negotiated_h;
@@ -1441,8 +1455,6 @@ namespace portal {
14411455
BOOST_LOG(warning) << "[portalgrab] PipeWire stream stopped by user."sv;
14421456
capture_running.store(false);
14431457
stream_stopped.store(false);
1444-
previous_height.store(0);
1445-
previous_width.store(0);
14461458
pipewire.frame_cv().notify_all();
14471459
return platf::capture_e::error;
14481460
}
@@ -1471,8 +1483,6 @@ namespace portal {
14711483
case platf::capture_e::interrupted:
14721484
capture_running.store(false);
14731485
stream_stopped.store(false);
1474-
previous_height.store(0);
1475-
previous_width.store(0);
14761486
pipewire.frame_cv().notify_all();
14771487
return status;
14781488
case platf::capture_e::timeout:
@@ -1481,8 +1491,6 @@ namespace portal {
14811491
BOOST_LOG(info) << "[portalgrab] PipeWire: timeout -> interrupt nudge";
14821492
capture_running.store(false);
14831493
stream_stopped.store(false);
1484-
previous_height.store(0);
1485-
previous_width.store(0);
14861494
pipewire.frame_cv().notify_all();
14871495
return platf::capture_e::interrupted;
14881496
}
@@ -1724,10 +1732,6 @@ namespace portal {
17241732
std::optional<std::uint64_t> last_seq {};
17251733
std::uint64_t sequence {};
17261734
uint32_t framerate;
1727-
static inline std::atomic<uint32_t> previous_height {0};
1728-
static inline std::atomic<uint32_t> previous_width {0};
1729-
static inline std::atomic<uint32_t> previous_pos_x {0};
1730-
static inline std::atomic<uint32_t> previous_pos_y {0};
17311735
static inline std::atomic<bool> stream_stopped {false};
17321736
static inline std::atomic<bool> capture_running {false};
17331737
std::shared_ptr<shared_state_t> shared_state;

0 commit comments

Comments
 (0)