UI Development on Linux


AI
Last updated on

Fyne

Creating GUI applications with Fyne is incredibly convenient, and today, with the help of AI, I developed an application featuring two windows and integrated a system tray feature. However, interacting with PipeWire has proven challenging due to the lack of a straightforward binding package for Go. While attempting to utilize PortAudio, it became apparent that it couldn’t enumerate the monitor sink.

For instance, using command-line tools:

  • With pactl:

    Terminal window
    pactl list short | grep monitor
    579 alsa_output.pci-0000_27_00.1.hdmi-stereo.monitor PipeWire s32le 2ch 48000Hz RUNNING
    580 alsa_output.pci-0000_29_00.3.iec958-stereo.monitor PipeWire s32le 2ch 48000Hz RUNNING
    582 alsa_output.usb-0b0e_Jabra_Evolve2_85_6CFBED22224D-00.analog-stereo.monitor PipeWire s16le 2ch 48000Hz RUNNING
  • Or with pw-cli:

    Terminal window
    pw-cli ls Node | grep -B11 Audio/Sink
    id 40, type PipeWire:Interface:Node/3
    object.serial = "580"
    object.path = "alsa:pcm:1:iec958:1:playback"
    factory.id = "18"
    client.id = "33"
    device.id = "82"
    priority.session = "736"
    priority.driver = "736"
    node.description = "Family 17h (Models 00h-0fh) HD Audio Controller Digital Stereo (IEC958)"
    node.name = "alsa_output.pci-0000_29_00.3.iec958-stereo"
    node.nick = "ALC892 Digital"
    media.class = "Audio/Sink"
    id 42, type PipeWire:Interface:Node/3
    object.serial = "579"
    object.path = "alsa:pcm:0:hdmi:0:playback"
    factory.id = "18"
    client.id = "33"
    device.id = "56"
    priority.session = "696"
    priority.driver = "696"
    node.description = "GP104 High Definition Audio Controller Digital Stereo (HDMI)"
    node.name = "alsa_output.pci-0000_27_00.1.hdmi-stereo"
    node.nick = "U27U2D"
    media.class = "Audio/Sink"
    --
    id 49, type PipeWire:Interface:Node/3
    object.serial = "582"
    object.path = "alsa:pcm:2:front:2:playback"
    factory.id = "18"
    client.id = "33"
    device.id = "46"
    priority.session = "1009"
    priority.driver = "1009"
    node.description = "Jabra Evolve2 85 Analog Stereo"
    node.name = "alsa_output.usb-0b0e_Jabra_Evolve2_85_6CFBED22224D-00.analog-stereo"
    node.nick = "Jabra Evolve2 85"
    media.class = "Audio/Sink"

In the object.serial output from pw-cli ls Node, it matches the id from pactl list short.

I will explore alternative methods, such as using C bindings in Go, although I am not familiar with C programming. Alternatively, learning Rust could be beneficial since it offers robust libraries for PipeWire integration.

Rust

Using Rust, integrating PipeWire becomes much easier with the available bindings, such as pipewire-rs. Additionally, Rust has two system tray crates: tray-item-rs and ksni.

Moreover, Rust provides Slint for creating UI layouts, which might be an attractive option. Nonetheless, learning Rust would be a significant undertaking, adding to the overall complexity.

© 2025 Jennings Liu. All rights reserved.