Pipewire doesn't work in snaps

Please ignore the previous post, I dug around the JVM source code and got some answers and the content was basically pointless keeping around with them so I’d set it to delete.

Whilst I don’t believe Java should have a direct libpipewire dependency itself, it does. My concern was that this implies it directly accesses pipewires internal recording mechanism, but the source code reveals it should actually use the Desktop Portals, and should work in Snaps, even in Wayland.

What does look sus is this:

pipewire_libhandle = dlopen(VERSIONED_JNI_LIB_NAME("pipewire-0.3", "0"),
            RTLD_LAZY | RTLD_LOCAL);

Java seems to explicitly want pipewire-0.3, and any other version isn’t good enough. I.E if snap did upgrade to 1.2, Java would break with the same error regardless.

However, it’s both 0.3 in the Core22 and Core24 repositories, so it’s presumably not a problem with compatibility going on here.

I’ll give it a little extra inspection

2 Likes

Thanks for your research!

Meanwhile I was able to find the source of the odd message in the terminal:

https://patch-diff.githubusercontent.com/raw/openjdk/jdk/pull/13803.diff

+        if (!(Toolkit.getDefaultToolkit() instanceof UNIXToolkit tk
+              && tk.loadGTK())
+              || !loadPipewire(SCREENCAST_DEBUG)) {
+
+            System.err.println(
+                    "Could not load native libraries for ScreencastHelper"
+            );
+
+            loadFailed = true;
+        }

This also explains, why it is not been logged as error - it doesn’t throw an exception, it just does a System.err.println (!)

If the JVM couldn’t load the pipewire_libhandle (the one you mentioned), then it would:

+    if (!pipewire_libhandle) {
+        DEBUG_SCREENCAST("could not load pipewire library\n", NULL);
+        return FALSE;
+    }

@James-Carroll Fortunately your concerns about future versions will break the loading of the libpipewire because of the “hard coded” version number seem to be unfounded:

The 0.3 part of the library’s name is not related to the pipewire version - even the newest pipewire 1.0.7-1~ubuntu24.04 comes with libpipewire-0.3-0:

https://launchpad.net/~pipewire-debian/+archive/ubuntu/pipewire-upstream/+sourcepub/16155980/+listing-archive-extra

1 Like

The Pipewire package you’ve installed in the snap is attempting to install the entire Pipewire stack, which yes is 1.07. Unless you’re packaging something like a desktop environment , or Pipewire itself to handle audio for IOT/Ubuntu Core, the version of PIpewire itself doesn’t really matter because you’re interacting with the version installed on the host anyway, the version you package in the snap isn’t getting used and is wasted space at best and potentially a cause for errors at worst (though probably not in this case, but ideally packages would be as minimal as possible).

Explicitly, Ubuntu could backport packages and etc, but pipewire contains significantly more than libpipewire which is all Java seems to need, and that does need to explicitly be 0.3. I think it’s unlikely that will change anytime soon though and that’s fine for us (0.3 remains API compatible with Pipewire 1.0).

That was part of my original confusion in the now deleted comment. To compare to e.g Pulseaudio, you’d install libpulse0 for the libraries, but not pulseaudio in it’s entirety because it simply wouldn’t work (outside of Ubuntu Core edge cases).

Ok, so if I understand you correctly, I should remove pipewire from the stage packages and wait until the upcoming pipewire version 1.2 is available on the host system.

Which of course is somewhat uncertain, as it can be any distribution/version - right?

For example, Debian Bookworm currently ships pipewire 0.3.65, while Ubuntu Noble ships with 1.0.5 - and both aren’t collaborating with JRE 21 in a snap.

Maybe the JVM tries to load that library at runtime, and searches for it in a specific place. In my system it is at /usr/lib/x86_64-linux-gnu, and has some soft links. Also in the same folder is the pipewire-0.3 folder with the modules. Maybe mapping those files into /usr/lib/x86_64-linux-gnu can do the trick.

Thanks for your suggestion!

But no, creating those symlinks doesn’t solve the issue :frowning:

Probably /usr/lib/x86_64-linux-gnu/pipewire-0.3 should somehow end up in the JVMs java.library.path.

I tried that in the snapcraft.yaml:

    environment:
      LD_LIBRARY_PATH: $LD_LIBRARY_PATH:/usr/lib/x86_64-linux-gnu/pipewire-0.3

But it doesn’t get added.

Is there similar library name available after pipewire installation at hand? Sometimes what worked for me was a simple symlink to the name software expected at certain path. Maybe will work there too? :thinking:

I already tried this after @SergioCostas suggested it. I created symlinks for each lib inside the pipewire-0.3 folder to its parent folder ( /usr/lib/x86_64-linux-gnu) which is part of the JVMs library path - but no luck…

Can you show it in your manifest?

1 Like

Ok, here is my current version of the manifest:

name: dayon
title: Dayon!
adopt-info: dayon
summary: An easy-to-use, cross-platform remote desktop assistance solution
description: ...
license: GPL-3.0
grade: stable
base: core22
confinement: strict
architectures:
  - build-on: [amd64]
    build-for: [amd64]
  - build-on: [arm64]
    build-for: [arm64]
  - build-on: [armhf]
    build-for: [armhf]
  - build-on: [riscv64]
    build-for: [riscv64]
    
    
lint:
  ignore:
    - library:
        - usr/lib/jvm/java-*/lib/*.so

apps:    
  assisted:
    extensions:
      [gnome]
    environment:
      JAVA_HOME: $SNAP/usr/lib/jvm/java-21-openjdk-$SNAP_ARCH
      PATH: $JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH
      LD_LIBRARY_PATH: /usr/lib/x86_64-linux-gnu/pipewire-0.3
    command: bin/dayon.launcher $SNAP/jar/dayon.jar $1 $2 $3 $4 $5
    desktop: ../parts/dayon/build/target/dayon.assisted.desktop
    plugs:
      [home, network, desktop, wayland]

  assistant:
    extensions:
      [gnome]
    environment:
      JAVA_HOME: $SNAP/usr/lib/jvm/java-21-openjdk-$SNAP_ARCH
      PATH: $JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH
    command: bin/dayon.launcher $SNAP/jar/dayon.jar assistant $1 $2 $3
    desktop: ../parts/dayon/build/target/dayon.assistant.desktop
    plugs:
      [home, network, desktop]

  browser:
    extensions:
      [gnome]
    command: bin/dayon.browser
    plugs:
      [home, network, desktop]

parts:
  dayon:
    plugin: maven
    source: https://github.com/retgal/dayon.git
    source-tag: trace
    source-type: git
    maven-parameters:
      [-Psnap]
    build-attributes:
     - enable-patchelf

    override-pull: |
      craftctl default
      craftctl set version=$(git describe --tags | sed 's/^v//' | cut -d "-" -f1)

    build-packages:
      [openjdk-21-jdk, maven]

    override-build: |
      craftctl default
      cp target/dayon.browser $CRAFT_PART_INSTALL/bin/
      cp target/dayon.launcher $CRAFT_PART_INSTALL/bin/
      cp target/dayon.png $CRAFT_PART_INSTALL/bin/
      rm $CRAFT_PART_INSTALL/jar/original-dayon.jar
      rm $CRAFT_PART_INSTALL/jar/WaifUPnP-*.jar
      rm $CRAFT_PART_INSTALL/jar/xz-*.jar

    stage-packages:
      [openjdk-21-jre]

    override-prime: |
      craftctl default
      rm -r usr/share/doc
      rm -r usr/share/man	

With this syntax: LD_LIBRARY_PATH: /usr/lib/x86_64-linux-gnu/pipewire-0.3 I was able to add the java.library.path to the JVM in the snap, pointing to the location of the pipewire libraries on the host.

But it didn’t change anything - it still logs Could not load native libraries for ScreencastHelper in the exact moment, when the dialog for sharing the screen should be displayed.

What @SergioCostas suggested is to create a layout for pipewire. It’ll done in this way.

layouts:
  /usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/pipewire-0.3:
    bind: $SNAP/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/pipewire-0.3

Thus, whenever a software tries to look into this path, snap will say, okay so you mean this path in bind.

Ah, thanks, then I misunderstood that part!

But shouldn’t it be the other way around? I mean, when the JVM in the snap wants to load the libraries, it should be directed to the pipewire libraries on the host.

1 Like

You can never, that’s what confinement is all about, unless you say, “Classic!” :rofl:

Okay, probably this should be the correct one, because you’re not shipping pipewire in the snap itself.

layouts:
  /usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/pipewire-0.3:
    bind: $SNAP/gnome-platform/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/pipewire-0.3

Perfect, thanks a lot for your help!

I’m gonna build and test this approach this morning - it’s getting late here :sleeping:

Unfortunately that didn’t help either.

1 Like

Finally got it working with Debian testing (13) as host OS - thanks to pipewire 1.2:

pipewire --version
pipewire
Compiled with libpipewire 1.2.0
Linked with libpipewire 1.2.0
dpkg -l pipewire
ii pipewire:amd64 1.2.0-1

This means that screen capturing on Ubuntu Noble as the host operating system will work as soon as its version of Pipewire is also updated to version 1.2.

Now all we can do is to hope that this will happen as soon as possible!