Skip to content

Commit

Permalink
Fix "Sources not selected" crash on Wayland (#264)
Browse files Browse the repository at this point in the history
* Log the exception stack traces in getXdgStreamDetails

* Refactor getXdgStreamDetails dbus signal handler

* Wait until source selection is ready

* Remove old workarounds on getXdgStreamDetails

These are simply not needed anymore when the code is properly
synchronized.
  • Loading branch information
Ape authored Jan 6, 2025
1 parent b96c17c commit 4a0e4fe
Showing 1 changed file with 30 additions and 21 deletions.
51 changes: 30 additions & 21 deletions src/main/java/org/dpsoftware/managers/PipelineManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ public static XdgStreamDetails getXdgStreamDetails() {
try {
AtomicBoolean restoreTokenMatch = new AtomicBoolean(false);
AtomicBoolean alertShown = new AtomicBoolean(false);
CompletableFuture<Void> sourcesSelectedMaybe = new CompletableFuture<>();
CompletableFuture<String> sessionHandleMaybe = new CompletableFuture<>();
CompletableFuture<Integer> streamIdMaybe = new CompletableFuture<>();
DBusConnection dBusConnection = DBusConnectionBuilder.forSessionBus().build(); // cannot free/close this for the duration of the capture
Expand All @@ -101,24 +102,38 @@ public static XdgStreamDetails getXdgStreamDetails() {
&& signal.getParameters()[1] instanceof LinkedHashMap
&& ((UInt32) signal.getParameters()[0]).intValue() == 0 // verify success-code
) {
var parameters = (LinkedHashMap<?, ?>) signal.getParameters()[1];

// parse signal & set appropriate Future as the result
if (((LinkedHashMap<?, ?>) signal.getParameters()[1]).containsKey("session_handle")) {
sessionHandleMaybe.complete((String) (((Variant<?>) ((LinkedHashMap<?, ?>) signal.getParameters()[1]).get("session_handle")).getValue()));
} else if (((LinkedHashMap<?, ?>) signal.getParameters()[1]).containsKey("streams")) {
if (((LinkedHashMap<?, ?>) signal.getParameters()[1]).get("restore_token") != null) {
if (parameters.isEmpty()) {
sourcesSelectedMaybe.complete(null);
} else if (parameters.containsKey("session_handle")) {
var sessionHandle = (Variant<?>) parameters.get("session_handle");
sessionHandleMaybe.complete((String) sessionHandle.getValue());
} else if (parameters.containsKey("streams")) {
var restoreTokenVariant = (Variant<?>) parameters.get("restore_token");

if (restoreTokenVariant != null) {
restoreTokenMatch.set(true);
String restoreToken = (String) ((Variant<?>) ((LinkedHashMap<?, ?>) signal.getParameters()[1]).get("restore_token")).getValue();
String restoreToken = (String) restoreTokenVariant.getValue();

try {
if (!restoreToken.equals(MainSingleton.getInstance().config.getScreenCastRestoreToken())) {
MainSingleton.getInstance().config.setScreenCastRestoreToken((String) ((Variant<?>) ((LinkedHashMap<?, ?>) signal.getParameters()[1]).get("restore_token")).getValue());
MainSingleton.getInstance().config.setScreenCastRestoreToken(restoreToken);
StorageManager storageManager = new StorageManager();
storageManager.writeConfig(MainSingleton.getInstance().config, null);
}
} catch (IOException e) {
log.error("Can't write config file.");
log.error("Can't write config file.", e);
}
}
streamIdMaybe.complete(((UInt32) ((Object[]) ((List<?>) (((Variant<?>) ((LinkedHashMap<?, ?>) signal.getParameters()[1]).get("streams")).getValue())).get(0))[0]).intValue());

// Extract stream ID
var streamsVariant = (Variant<?>) parameters.get("streams");
var streams = (List<?>) streamsVariant.getValue();
var streamData = (Object[]) streams.get(0);
var streamId = (UInt32) streamData[0];
streamIdMaybe.complete(streamId.intValue());
}
}
} catch (DBusException e) {
Expand All @@ -136,30 +151,24 @@ public static XdgStreamDetails getXdgStreamDetails() {
if (restoreToken != null && !restoreToken.isEmpty()) {
selectSourcesMap.put("restore_token", new Variant<>(restoreToken));
}

screenCastIface.SelectSources(receivedSessionHandle, selectSourcesMap);
sourcesSelectedMaybe.get(); // Wait until source selection is ready

if (NativeExecutor.isWayland() && (MainSingleton.getInstance().config.getScreenCastRestoreToken() == null || MainSingleton.getInstance().config.getScreenCastRestoreToken().isEmpty())) {
showChooseDisplayAlert();
alertShown.set(true);
}
try {
screenCastIface.Start(receivedSessionHandle, "", Collections.emptyMap());
} catch (org.freedesktop.dbus.exceptions.DBusExecutionException e) {
if (NativeExecutor.isWayland() && alertShown.get() == false) {
log.info("Screen cast restore token is invalid or expired. Requesting a new one.");
showChooseDisplayAlert();
screenCastIface.Start(receivedSessionHandle, "", Collections.emptyMap());
} else {
throw e;
}
}
CommonUtility.sleepMilliseconds(200);

screenCastIface.Start(receivedSessionHandle, "", Collections.emptyMap());

var c = streamIdMaybe.thenApply(streamId -> {
FileDescriptor fileDescriptor = screenCastIface.OpenPipeWireRemote(receivedSessionHandle, Collections.emptyMap()); // block until stream started before calling OpenPipeWireRemote
return new XdgStreamDetails(streamId, fileDescriptor);
}).get();
return c;
} catch (Exception e) {
log.error(e.getMessage());
log.error(e.getMessage(), e);
}
return null;
}
Expand Down

0 comments on commit 4a0e4fe

Please sign in to comment.