Project 01
Konduit
In developmentCast your Linux desktop to a TV, projector or classroom display.
A native KDE Plasma app for Miracast (Wi-Fi Display) receivers.
Free and open source, under the GNU GPL version 2 or later. The source code will be published with the first release.
At a glance
- Platform
- Linux (CachyOS), KDE Plasma 6 on Wayland
- Works with
- Miracast (Wi-Fi Display) receivers: TVs, projectors and classroom adapters
- Built with
- C++, Qt 6 and KDE Frameworks 6
- Status
- Early development. Used day to day on Arch Linux / CachyOS and tested with ScreenBeam classroom adapters.
- License
- GNU GPL version 2 or later (GPL-2.0-or-later)
- Source code
- To be announced
- Download
- To be announced
Screenshots
Select a screenshot to see it full size.
-
Find a display Nearby displays with favourites, search and colour-coded signal quality. -
Casting Live details while casting: resolution, encoder, bitrate and dropped frames. -
Choose what to share The whole screen, a single window, or extend the desktop onto the display. -
Quick options Picture quality, Smooth Motion, sound, automatic reconnect and the preview window, one click away. -
Quick connect Meta+Shift+K opens a small picker of nearby displays. -
Preview window When extending the desktop, a live preview shows what the display is showing. -
Test pattern Colour bars and a clock that flashes with an audible tick, for checking picture and lip sync. -
Casting settings What to share, picture quality, sound and quick connect, each explained in plain language. -
Picture and encoding Encoder, bitrate, keyframes and resolution, for enthusiasts. -
Readiness Check A read-only check of the computer that explains what is worth a look, with commands to copy. -
NetworkManager patch Optional, step-by-step help for displays such as ScreenBeam adapters, including what it costs and how to undo it. -
About Konduit Version, license and the libraries in use.
-
Find a display Nearby displays with favourites, search and colour-coded signal quality. -
Casting Live details while casting: resolution, encoder, bitrate and dropped frames. -
Choose what to share The whole screen, a single window, or extend the desktop onto the display. -
Quick options Picture quality, Smooth Motion, sound, automatic reconnect and the preview window, one click away. -
Quick connect Meta+Shift+K opens a small picker of nearby displays. -
Preview window When extending the desktop, a live preview shows what the display is showing. -
Test pattern Colour bars and a clock that flashes with an audible tick, for checking picture and lip sync. -
Casting settings What to share, picture quality, sound and quick connect, each explained in plain language. -
Picture and encoding Encoder, bitrate, keyframes and resolution, for enthusiasts. -
Readiness Check A read-only check of the computer that explains what is worth a look, with commands to copy. -
NetworkManager patch Optional, step-by-step help for displays such as ScreenBeam adapters, including what it costs and how to undo it. -
About Konduit Version, license and the libraries in use.
Casting, without the cables
Konduit casts your desktop to Miracast receivers: TVs, projectors and classroom adapters such as Actiontec ScreenBeam. It connects directly over Wi-Fi Direct, so no cables, dongles or internet connection are needed, and nothing leaves the room.
Casting to these displays has long been easy on Windows and largely missing on Linux. Comparable Linux tools tend to find displays but struggle to connect to them. Konduit is built to connect reliably, and to explain clearly when something on the computer needs attention.
What makes it different
Connects reliably
It is built to connect, not just to find displays. If the display drops, even through an adapter reboot, Konduit reconnects on its own.
Says what needs attention
When something on the computer needs a look, Konduit explains it in plain language, with commands to copy. It never blocks you from connecting.
Native to Plasma
Written from scratch in C++ with Qt 6 and KDE Frameworks 6, for Plasma 6 on Wayland.
Light on the laptop
Automatic hardware encoding, where the display supports it, keeps CPU use low.
Features today
Find and connect
Nearby displays with search, sorting by name or signal strength, pinned favourites and colour-coded signal quality.
Quick connect
A global shortcut, Meta+Shift+K, opens a small picker, and a tray icon offers your favourites and the last display used.
Three ways to share
The whole screen, a single window, or extend the desktop onto the display as a new screen.
Preview window
When extending, a live preview can be pinned above other windows, can highlight the mouse pointer (adjustable size), and has a disconnect button.
Sound
Desktop audio plays on the display while the laptop stays quiet, with adjustable audio delay.
Picture
Quality presets, a 1080p60 Smooth Motion mode, and automatic hardware encoding where the display supports it, for low CPU use.
Test pattern
Colour bars, a timer and a clock that flashes with an audible tick, for checking picture and lip sync.
Advanced settings
Encoder, bitrate, resolution, scaling, keyframes and more, for enthusiasts. Settings that can safely change mid-cast apply live.
Reliability
Automatic reconnect if the display drops. The display blanks when the computer locks, the computer stays awake while casting, and there's a clean hand-off whenever casting ends.
Privacy and security
Everything stays on a direct local link, and Konduit only accepts a connection from the display it is casting to.
Readiness Check
A friendly, read-only check of NetworkManager, Wi-Fi card, firewall, screen sharing, sound and encoding. It runs on first launch and explains what to look at, with commands to copy.
Optional helper
For a NetworkManager limitation that stops some displays, such as ScreenBeam, from connecting: the patch, a commented build script and step-by-step instructions, including how to undo it. Konduit never changes the system on its own.
konduitctl
A command-line companion for scanning, connecting and running the readiness check.
The NetworkManager patch
Some displays, such as ScreenBeam classroom adapters, already run their own Wi-Fi Direct group and expect a computer to join it, as Windows and Android do. NetworkManager always asks to start a new group instead. These displays answer, but never finish setting it up, so the connection gives up after 45 seconds.
This small patch to NetworkManager checks whether the display already runs a group and, if it does, joins it. Displays that don't keep connecting exactly as before. It is written to be offered to NetworkManager itself; until it's part of a release, Konduit includes an optional, commented script that builds Arch's own NetworkManager package with the patch added.
- Needed for
- Displays that run their own group, such as Actiontec ScreenBeam adapters. Other displays work without it.
- Tested
- NetworkManager 1.58.1 with a ScreenBeam 1000 EDU: connects in about five seconds, where it times out without the patch.
- Build
- About 3 minutes with
--faston an 8-thread laptop. Konduit never changes the system on its own. - Undo
sudo pacman -S networkmanager libnm, thensudo systemctl restart NetworkManager
@@ -601,6 +601,7 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason)
NMSettingWirelessSecurityWpsMethod wps_method;
const char *wps_pin;
const char *wps_method_str;
+ gboolean join;
if (nm_clear_g_source_inst(&priv->find_peer_timeout_source))
nm_assert_not_reached();
@@ -677,10 +678,20 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason)
break;
}
+ /* A peer that already runs a group, such as a Miracast sink operating as
+ * an autonomous or persistent GO, may answer GO negotiation without ever
+ * enabling its WPS registrar, so the connection would time out. Join its
+ * group instead: wpa_supplicant sends a Provision Discovery Request and
+ * then connects to the GO, which is what such peers expect. */
+ join = nm_wifi_p2p_peer_get_is_group_owner(peer);
+ if (join)
+ _LOGD(LOGD_WIFI, "Activation: (wifi-p2p) peer is a group owner, joining its group");
+
nm_supplicant_interface_p2p_connect(priv->mgmt_iface,
nm_wifi_p2p_peer_get_supplicant_path(peer),
wps_method_str,
- wps_pin);
+ wps_pin,
+ join);
/* Set up a timeout on the connect attempt */
if (!priv->sup_timeout_source) {
@@ -55,6 +55,8 @@ struct _NMWifiP2PPeerPrivate {
guint16 wps_config_methods;
+ guint8 group_capab;
+
guint8 strength;
NM80211ApFlags flags; /* General flags */
@@ -311,6 +313,15 @@ nm_wifi_p2p_peer_set_wps_config_methods(NMWifiP2PPeer *peer, guint16 wps_config_
return TRUE;
}
+gboolean
+nm_wifi_p2p_peer_get_is_group_owner(const NMWifiP2PPeer *peer)
+{
+ g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), FALSE);
+
+ /* Group Capability bit 0: "P2P Group Owner" */
+ return NM_FLAGS_HAS(NM_WIFI_P2P_PEER_GET_PRIVATE(peer)->group_capab, 0x01);
+}
+
const char *const *
nm_wifi_p2p_peer_get_groups(const NMWifiP2PPeer *peer)
{
@@ -440,6 +451,9 @@ nm_wifi_p2p_peer_update_from_properties(NMWifiP2PPeer *peer, const NMSupplicantP
changed |= nm_wifi_p2p_peer_set_wps_config_methods(peer, peer_info->config_methods);
changed |= nm_wifi_p2p_peer_set_last_seen(peer, peer_info->last_seen_msec / 1000u);
+ /* Only used internally, to join a group that the peer already runs. */
+ priv->group_capab = peer_info->group_capab;
+
/* We currently only use the groups information internally to check if
* the peer is still joined. */
if (!nm_strv_equal(priv->groups, peer_info->groups)) {
@@ -77,6 +77,8 @@ gboolean nm_wifi_p2p_peer_set_wps_config_methods(NMWifiP2PPeer *peer, guint16 wp
const char *const *nm_wifi_p2p_peer_get_groups(const NMWifiP2PPeer *peer);
+gboolean nm_wifi_p2p_peer_get_is_group_owner(const NMWifiP2PPeer *peer);
+
const char *nm_wifi_p2p_peer_get_address(const NMWifiP2PPeer *peer);
gboolean nm_wifi_p2p_peer_set_address(NMWifiP2PPeer *peer, const char *addr);
gint8 nm_wifi_p2p_peer_get_strength(NMWifiP2PPeer *peer);
@@ -1009,6 +1009,13 @@ _peer_info_properties_changed(NMSupplicantInterface *self,
peer_info->config_methods = v_u16;
}
+ {
+ guint8 v_u8;
+
+ if (nm_g_variant_lookup(properties, "groupcapability", "y", &v_u8))
+ peer_info->group_capab = v_u8;
+ }
+
_peer_info_changed_emit(self, peer_info, TRUE);
}
@@ -3072,7 +3079,8 @@ void
nm_supplicant_interface_p2p_connect(NMSupplicantInterface *self,
const char *peer,
const char *wps_method,
- const char *wps_pin)
+ const char *wps_pin,
+ gboolean join)
{
GVariantBuilder builder;
@@ -3084,7 +3092,7 @@ nm_supplicant_interface_p2p_connect(NMSupplicantInterface *self,
if (wps_pin)
g_variant_builder_add(&builder, "{sv}", "pin", g_variant_new_string(wps_pin));
g_variant_builder_add(&builder, "{sv}", "peer", g_variant_new_object_path(peer));
- g_variant_builder_add(&builder, "{sv}", "join", g_variant_new_boolean(FALSE));
+ g_variant_builder_add(&builder, "{sv}", "join", g_variant_new_boolean(join));
g_variant_builder_add(&builder, "{sv}", "persistent", g_variant_new_boolean(FALSE));
g_variant_builder_add(&builder, "{sv}", "go_intent", g_variant_new_int32(7));
@@ -188,7 +188,8 @@ void nm_supplicant_interface_p2p_set_device_name(NMSupplicantInterface *self, co
void nm_supplicant_interface_p2p_connect(NMSupplicantInterface *self,
const char *peer,
const char *wps_method,
- const char *wps_pin);
+ const char *wps_pin,
+ gboolean join);
void nm_supplicant_interface_p2p_cancel_connect(NMSupplicantInterface *self);
void nm_supplicant_interface_p2p_disconnect(NMSupplicantInterface *self);
@@ -225,6 +225,10 @@ typedef struct _NMSupplicantPeerInfo {
guint16 config_methods;
+ /* P2P Group Capability bitmap (Wi-Fi P2P spec, 4.1.4); bit 0 is
+ * "P2P Group Owner", set while the peer runs a group. */
+ guint8 group_capab;
+
guint8 address[6 /* ETH_ALEN */];
gint8 signal_percent;
Coming next
- Contemplating a public release, packaged for Arch Linux / CachyOS (AUR).
- Getting the NetworkManager fix accepted upstream, so no patch is needed.
- Chromecast / Google Cast support.
Links
Source and download links will appear here when Konduit is ready to share.