diff --git a/Containerfile b/Containerfile
index dcf5ec1cbf..80187d8e5a 100644
--- a/Containerfile
+++ b/Containerfile
@@ -447,7 +447,6 @@ RUN /tmp/image-info.sh && \
systemctl disable rpm-ostreed-automatic.timer && \
systemctl enable ublue-update.timer && \
systemctl enable gamescope-workaround.service && \
- systemctl enable sunshine-workaround.service && \
systemctl enable waydroid-workaround.service && \
systemctl enable bazzite-hardware-setup.service && \
systemctl enable tailscaled.service && \
diff --git a/README-ID.md b/README-ID.md
index e858c68e2e..d268c9682c 100644
--- a/README-ID.md
+++ b/README-ID.md
@@ -4,21 +4,24 @@
[![build-bazzite](https://github.com/ublue-os/bazzite/actions/workflows/build.yml/badge.svg)](https://github.com/ublue-os/bazzite/actions/workflows/build.yml)
+# [🇺🇸](https://github.com/ublue-os/bazzite/blob/main/README.md) [🇪🇸](https://github.com/ublue-os/bazzite/blob/main/README-SPA.md) [🇮🇩](https://github.com/ublue-os/bazzite/blob/main/README-ID.md)
+
---
+
# Daftar Isi
-- [Fitur untuk **SEMUA** Image Bazzite](https://github.com/ublue-os/bazzite#about--features)
- - [Fitur untuk Image **Desktop** ](https://github.com/ublue-os/bazzite#desktop)
- - [Fitur untuk Image **Steam Deck / HTPC**](https://github.com/ublue-os/bazzite#steam-deckhome-theater-pcs-htpcs)
- - [Fitur untuk Image **GNOME** ](https://github.com/ublue-os/bazzite#gnome)
- - [Fitur dari upstream](https://github.com/ublue-os/bazzite#features-from-upstream)
-- [Alasan](https://github.com/ublue-os/bazzite#why)
-- [Showcase](https://github.com/ublue-os/bazzite#showcase)
-- [Dokumentasi & Buletin](https://github.com/ublue-os/bazzite#documentation--newsletters)
-- [Paket Kustom](https://github.com/ublue-os/bazzite#custom-packages)
-- [Verifikasi & Metrik](https://github.com/ublue-os/bazzite#verification)
-- [Ucapan Terimakasih](https://github.com/ublue-os/bazzite#special-thanks)
-- [Membuat Image Anda Sendiri](https://github.com/ublue-os/bazzite#build-your-own)
-- [Komunitas](https://github.com/ublue-os/bazzite#join-the-community)
+- [Fitur untuk **SEMUA** Image Bazzite](#tentang--fitur)
+ - [Fitur untuk Image **Desktop** ](#desktop)
+ - [Fitur untuk Image **Steam Deck / HTPC**](#steam-deckhome-theater-pcs-htpcs)
+ - [Fitur untuk Image **GNOME** ](#gnome)
+ - [Fitur dari upstream](#fitur-dari-upstream)
+- [Alasan](#alasan)
+- [Pameran](#pameran)
+- [Dokumentasi & Buletin](#dokumentasi--buletin)
+- [Paket Kustom](#paket-kustom)
+- [Verifikasi & Metrik](#paket-kustom)
+- [Ucapan Terimakasih](#ucapan-terimakasih)
+- [Membuat Image Anda Sendiri](#membuat-image-anda-sendiri)
+- [Komunitas](#bergabung-dengan-komunitas)
---
## Tentang & Fitur
@@ -35,13 +38,13 @@ Bazzite dibentuk dari [ublue-os/main](https://github.com/ublue-os/main) and [ubl
- Dukungan untuk [Wallpaper Engine](https://www.wallpaperengine.io/en). (Hanya ada di KDE)
- Disediakan [Ekstensi shell untuk ROM Properties Page ](https://github.com/GerbilSoft/rom-properties).
- Dukungan penuh untuk [Winesync/Fastsync/NTsync](https://github.com/Frogging-Family/wine-tkg-git/issues/936).
-- Pra-install [Distrobox](https://github.com/89luca89/distrobox) preinstalled dengan update otomatis untuk kontainer yang dibuat.
-- Otomatisasi layanan `duperemove` dan `rmlint`untuk mengurangi penggunaan penyimpanan yang digunakan untuk konten prefix wine.
+- Pra-install [Distrobox](https://github.com/89luca89/distrobox) dengan update otomatis untuk kontainer yang dibuat.
+- Otomatisasi layanan `duperemove` dan `rmlint`untuk mengurangi penggunaan penyimpanan yang digunakan prefix wine.
- Dukungan untuk HDMI CEC dengan [libCEC](https://libcec.pulse-eight.com/).
-- Pra-install [System76-Scheduler](https://github.com/pop-os/system76-scheduler), menyediakan otomatisasi providing automatic process priority tweaks to your focused application and keeping CPU time for background processes to a minimum.
+- Pra-install [System76-Scheduler](https://github.com/pop-os/system76-scheduler), menyediakan otomatisasi dan oprekan untuk proses yang berjalan dilatar belakang, serta meminimalkan CPU untuk proses latar belakang.
- Menkustomisasi konfigurasi System76-Scheduler dengan aturan tambahan.
- Menggunakan [Google's BBR TCP congestion control](https://github.com/google/bbr) secara bawaan.
-- Pra-install[Input Remapper](https://github.com/sezanzeb/input-remapper) dan diaktifkan secara bawaan. (Dimatikan secara bawaan di varian Deck tapi tersedia dan dapat diaktifkan dengan `ujust enable-input-remapper`)
+- Pra-install [Input Remapper](https://github.com/sezanzeb/input-remapper) dan diaktifkan secara bawaan. (Dinonaktifkan secara bawaan di varian Deck tapi tersedia dan dapat diaktifkan dengan `ujust enable-input-remapper`)
- Portal Bazzite menyediakan cara mudah untuk menginstall berbagai macam aplikasi dan oprekan, termasuk menginstall [LACT](https://github.com/ilya-zlobintsev/LACT) dan [GreenWithEnvy](https://gitlab.com/leinardi/gwe).
- Manajemen paket [Nix](https://nixos.org/) dengan [Fleek](https://getfleek.dev/) tersedia secara optional dan dapat diinstall dengan `ujust`.
- Manajemen paket [Brew](https://brew.sh/) tersedia secara optional dan dapat diinstall dengan Portal Bazzite.
@@ -49,13 +52,13 @@ Bazzite dibentuk dari [ublue-os/main](https://github.com/ublue-os/main) and [ubl
- Mengatur aplikasi dengan [Flatseal](https://github.com/tchx84/Flatseal), [Warehouse](https://github.com/flattool/warehouse), dan [Gear Lever](https://github.com/mijorus/gearlever).
- [OpenRGB](https://gitlab.com/CalcProgrammer1/OpenRGB) driver i2c-piix4 dan i2c-nct6775 untuk mengatur RGB di beberapa jenis motherboard.
- Disediakan secara bawaan driver [OpenRazer](https://openrazer.github.io), Pilih OpenRazer di portal bazzite atau jalankan perintah `ujust install-openrazer` diterminal untuk menggunakannya.
-- Disediakan secara bawaan [OpenTabletDriver](https://opentabletdriver.net/) udev rules , dengan perangkat lunaknya yang dapat diinstall dengan portal bazzite atau dengan mengetikkan `ujust install-opentabletdriver` di terminal.
-- Driver [GCAdapter_OC](https://github.com/hannesmann/gcadapter-oc-kmod) untuk men-overclocking Kontroller Gamecube Nintendo sampai dengan 1000hz polling.
+- Disediakan secara bawaan [OpenTabletDriver](https://opentabletdriver.net/) udev rules, dengan perangkat lunaknya yang dapat dipasang dengan portal bazzite atau dengan mengetikkan `ujust install-opentabletdriver` di terminal.
+- Driver [GCAdapter_OC](https://github.com/hannesmann/gcadapter-oc-kmod) untuk men-overclocking Kontroller Nintendo Gamecube sampai dengan 1000hz polling.
- Dukungan untuk keyboard [Wooting](https://wooting.io/).
-- Dukungan untuk kartu grafis Southern Islands (HD 7000) and Sea Islands (HD 8000) AMD GPUs dengan driver `amdgpu`.
+- Dukungan untuk kartu grafis Southern Islands (HD 7000) and Sea Islands (HD 8000) dengan driver `amdgpu`.
- Memperbaiki masalah untuk [game yang menggunakan engine Source 1 (Contoh: TF2)](https://github.com/ValveSoftware/Source-1-Games/issues/5043) yang membuat game-nya crash saat dijalankan `ujust patch-source1-tcmalloc`
- [XwaylandVideoBridge](https://invent.kde.org/system/xwaylandvideobridge) untuk Discord screensharing di Wayland.
-- [Webapp Manager](https://github.com/linuxmint/webapp-manager) tersedia untuk membuat aplikasi dari situs web dengan berbagai macam peramban, termasuk Firefox.
+- [Webapp Manager](https://github.com/linuxmint/webapp-manager) tersedia untuk membuat aplikasi dari situs web dengan berbagai macam peramban, termasuk Firefox.
### Desktop
@@ -86,28 +89,28 @@ Perangkat yang bukan Steam Deck masih bisa menggunakan image bazzite-deck, tetap
Varian `bazzite-deck` ini didesain untuk digunakan sebagai alternatif untuk SteamOS di perangkat Steam Deck dan HTPC dengan pengalaman seperti konsol:
- Langsung boot ke Gamemode seperti SteamOS.
-- **Automatic `duperemove` greatly trims the size of compatdata.**
-- **Latest version of Mesa creates smaller shader caches and does not require them to prevent stutter.**
-- **Able to be booted even if the drive is full.**
-- **Support for every language supported by upstream Fedora.**
+- **`duperemove` secara otomatis yang berguna untuk mengurangi ukuran folder compatdata.**
+- **Versi terbaru dari Mesa yang menghasilkan ukuran shaders cache yang lebih kecil dan tidak diperlukan lagi untuk mencegah stutter.**
+- **Langsung bisa booting walaupun diska penuh.**
+- **Dukungan untuk setiap bahasa yang disupport oleh Fedora.**
- **Menggunakan Wayland di desktop dengan [dukungan untuk Steam input](https://github.com/Supreeeme/extest).**
- Fitur yang diporting dari SteamOS meliputi driver, pembaruan perangkat tegar, dan pengatur kecepatan kipas [dari repositori evlaV ](https://gitlab.com/evlaV).
- Mesa yang dipatch untuk mengatur framerate di Gamescope.
- Hadir dengan patch dari [SteamOS BTRFS](https://gitlab.com/popsulfr/steamos-btrfs) untuk dukungan BTRFS di SD Card secara bawaan.
- [SDGyroDSU](https://github.com/kmicki/SteamDeckGyroDSU) tersedia dan diaktifkan secara bawaan.
- Pilihan untuk menginstall [Decky Loader](https://github.com/SteamDeckHomebrew/decky-loader), [EmuDeck](https://www.emudeck.com/), [RetroDECK](https://retrodeck.net/), dan [ProtonUp-Qt](https://davidotek.github.io/protonup-qt/), serta berbagai macam paket/aplikasi yang berguna selama pemasangan.
-- Sistem pembaruan kustom memungkinkan Sistem Operasi,Flatpal,Paket Nix(dengan fleek), dan Distrobox image untuk diupdate dari Gamemode UI.
+- Sistem pembaruan kustom memungkinkan Sistem Operasi,Flatpak,Paket Nix(dengan fleek), dan Distrobox image untuk diupdate dari Gamemode UI.
- Dukungan untuk dual-boot dengan Windows karena GRUB dari Fedora.
-- Pembaruan merusak sesuatu? tinggal rollback ke versi sebelumnya berkat fitur rollback`rpm-ostree`. Anda bisa memilih versi image sebelumnya di boot menuY.
+- Pembaruan merusak sesuatu? tinggal rollback ke versi sebelumnya berkat fitur rollback `rpm-ostree`. Anda bisa memilih versi image sebelumnya di boot menu.
- Pra-install Steam dan Lutris sebagai paket sistem.
-- Pra-install [Discover Overlay](https://github.com/trigg/Discover) untuk Discord dan otomatis diluncurkan di Gamemode,dan di desktop jika Discord terinstall. [Lihat dokumentasinya disini](https://trigg.github.io/Discover/bazzite).
+- Pra-install [Discover Overlay](https://github.com/trigg/Discover) untuk Discord dan otomatis diluncurkan di Gamemode,dan di desktop jika Discord terinstall, [Lihat dokumentasinya disini](https://trigg.github.io/Discover/bazzite).
- Menggunakan ZRAM(4GB) dengan kompresi ZSTD secara bawaan dengan opsi untuk menggunakan 1GB swap file dan bisa diatur sesuai kebutuhan.
-- Penjadwal I/O untuk mencegah I/O starvation ketika memasang game atau ketika proses latar belakang `duperemove` dan `rmlint`.
+- Penjadwal I/O untuk mencegah I/O starvation ketika memasang game atau ketika proses latar belakang `duperemove` dan `rmlint` bekerja.
- Mengaplikasikan parameter kernel dari SteamOS.
- Kalibrasi Warna Layar untuk layar matte dan reflektif Steam Deck.
- Fitur-fitur pengguna advance yang tidak diaktifkan secara bawaan seperti:
- - Service untuk undervolting Steam Deck yang beresiko rendah dengan [RyzenAdj](https://github.com/FlyGoat/RyzenAdj) dan [Ryzen SMU](https://gitlab.com/leogx9r/ryzen_smu), anda bisa mencek `ryzenadj.service` dan `/etc/default/ryzenadj`.
- - Service untuk membatasi kapasitas maksimal saat mengisi ulang, anda bisa mencek `batterylimit.service` dan `/etc/default/batterylimit`. (Bekerja walaupun perangkat dalam posisi non aktif)
+ - Service untuk undervolting Steam Deck yang beresiko rendah dengan [RyzenAdj](https://github.com/FlyGoat/RyzenAdj) dan [Ryzen SMU](https://gitlab.com/leogx9r/ryzen_smu), anda bisa mengecek `ryzenadj.service` dan `/etc/default/ryzenadj`.
+ - Service untuk membatasi kapasitas maksimal saat mengisi ulang, anda bisa mengeceknya di `batterylimit.service` dan `/etc/default/batterylimit`. (Bekerja walaupun perangkat dalam posisi non aktif)
- Dukungan bawaan untuk overclocking layar. Contohnya seperti ini, anda menambahkan `GAMESCOPE_OVERRIDE_REFRESH_RATE=40,70` di `/etc/environment`.
- Anda bisa menggunakan X11 jika diperlukan dengan mengedit `/etc/default/desktop-wayland`.
- Lu punya RAM 32 GB? anda bisa memakai 2x lipat VRAM yang diaplikasikan secara otomatis!. (Coba bagikan skill ngesolder lu dong)
@@ -128,7 +131,7 @@ rpm-ostree rebase ostree-unverified-registry:ghcr.io/ublue-os/bazzite-deck:lates
### GNOME
-Varian desktop GNOME tersedia dalam versi desktop dan GNOME.varian ini memiliki beberapa fitur tambahan seperti :
+Varian desktop GNOME tersedia dalam versi desktop dan deck.varian ini memiliki beberapa fitur tambahan seperti :
- [Dukungan untuk Variable refresh rate dan fractional scaling di sesi wayland secara bawaan](https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1154).
- Menu kustom di bar atas untuk kembali ke game mode, meluncurkan Steam, dan membuka berbagai macam peralatan yang berguna.
@@ -178,19 +181,18 @@ rpm-ostree rebase ostree-unverified-registry:ghcr.io/ublue-os/bazzite-deck-gnome
- Paket sistem yang terbarukan.
- Layer paket fedora tanpa perlu takut paket tersebut hilang saat memperbarui sistem.
- Pra-install [SELinux](https://github.com/SELinuxProject/selinux) untuk keamanan dan telah dikonfigurasi secara bawaan.
-- The ability to rebase to different Fedora libostree images, if desired, without losing user data.
-- Bisa rebase ke image Fedora ostree yang lain jika mau, tanpa kehilangan data pengguna.
-- Dukungan printing berkat [CUPS](https://www.cups.org/) yang terinstall secara bawaan
+- Bisa rebase ke image Fedora ostree yang lain jika mau,tanpa kehilangan data pengguna.
+- Dukungan printing berkat [CUPS](https://www.cups.org/) yang terinstall secara bawaan.
## Alasan
Bazzite dimulai sebagai proyek untuk menyelesaikan berbagai masalah yang ada di SteamOS, terutama paket-paket yang tidak terbarukan (walaupun menggunakan ArchLinux sebagai base) dan tidak ada manajemen paket yang fungsional.
-Walaupun proyek ini juga menggunakan image. anda masih bisa menginstall berbagai macam paket Fedora dari perintah shell. Paket-paket ini akan tetap bertahan setelah pembaruan (Jadi anda bisa install aplikasi VPN yang anda g bisa install di SteamOS).
+Walaupun proyek ini juga menggunakan image. anda masih bisa menginstall berbagai macam paket Fedora dari perintah shell. Paket-paket ini akan tetap bertahan setelah pembaruan (Jadi anda bisa install aplikasi VPN yang anda g bisa install di SteamOS).
Sebagai tambahan, Bazzite sering diupdate beberapa kali dalam satu minggu dengan paket-paket dari upstream Fedora, memberikan anda performa terbaik dan fitur-fitur terbaru di base yang stabil.
Bazzite hadir dengan versi Linux kernel yang terbaru dan SELinux diaktifkan secara bawaan dengan dukungan penuh untuk secure boot (Jalankan `ujust enroll-secure-boot-key` dan masukan password `ublue-os` jika diperintahkan untuk menroll key dari kita)
-dan enkripsi disk membuat ini aman dan sempurna untuk komputasi general. (Yes, lu bisa ngeprint dari Bazzite!).
+dan enkripsi disk membuat ini aman dan sempurna untuk komputasi general. (Yes, anda bisa ngeprint dari Bazzite!).
Baca [FAQ](https://universal-blue.discourse.group/docs?topic=33) untuk tahu apa saja yang membuat Bazzite beda dari Sistem Operasi Linux yang lain.
@@ -214,7 +216,7 @@ Baca [FAQ](https://universal-blue.discourse.group/docs?topic=33) untuk tahu apa
Temukan dokumentasi tambahan project ini [disini](https://universal-blue.discourse.group/docs).
-Cek [buletin](https://universal-blue.discourse.group/tag/bazzite-buzz) kami yang selalu update secara regular tentang project ini.
+Cek [buletin](https://universal-blue.discourse.group/tag/bazzite-buzz) kami yang selalu update secara regular tentang proyek ini.
## Paket Kustom
Paket-paket ini diporting dari SteamOS dan ChimeraOS, dan digunakan oleh Bazzite dan dibuat di Copr [bazzite](https://copr.fedorainfracloud.org/coprs/kylegospo/bazzite/) and [bazzite-multilib](https://copr.fedorainfracloud.org/coprs/kylegospo/bazzite-multilib/).
@@ -282,7 +284,7 @@ Sebagai tambahan, paket-paket berikut ini digunakan dari repository Copr:
## Verifikasi
-Image berikut ini telah disigned oleh sigstore's [cosign](https://docs.sigstore.dev/cosign/overview/).Anda bisa menverifikasi signature dengan mengunduh key `cosign.pub` dari repo ini dan menjalankan perintah ini:
+Image berikut ini telah disigned oleh sigstore's [cosign](https://docs.sigstore.dev/cosign/overview/). Anda bisa menverifikasi signature dengan mengunduh key `cosign.pub` dari repo ini dan menjalankan perintah ini:
```bash
cosign verify --key cosign.pub ghcr.io/ublue-os/bazzite
@@ -290,11 +292,12 @@ cosign verify --key cosign.pub ghcr.io/ublue-os/bazzite
## Secure Boot
-Secure boot didukung dengan key dari kami. Pub key dapat ditemukan di root repositori ini[disini bro](https://github.com/ublue-os/bazzite/blob/main/secure_boot_key.der).
+Secure boot didukung dengan key dari kami. Pub key dapat ditemukan di root repositori [ini](https://github.com/ublue-os/bazzite/blob/main/secure_boot.der).
Jika anda ingin menenroll key ini sebelum instalasi, unduh key ini dan jalankan:
```bash
-sudo mokutil --import secure_boot_key.der
+sudo mokutil --timeout -1
+sudo mokutil --import secure_boot.der
```
### Metrik Kontribusi
diff --git a/README-SPA.md b/README-SPA.md
index 8a63d77d4d..fefe1ca71b 100644
--- a/README-SPA.md
+++ b/README-SPA.md
@@ -4,24 +4,26 @@
![build-bazzite](https://github.com/ublue-os/bazzite/actions/workflows/build.yml/badge.svg)
+# [🇺🇸](https://github.com/ublue-os/bazzite/blob/main/README.md) [🇪🇸](https://github.com/ublue-os/bazzite/blob/main/README-SPA.md) [🇮🇩](https://github.com/ublue-os/bazzite/blob/main/README-ID.md)
+
---
# Tabla de Contenidos
-- [Características de **todas** las imágenes de Bazzite](https://github.com/ublue-os/bazzite#about--features)
- - [Características de las imágenes para **Computadoras de Escritorio**](https://github.com/ublue-os/bazzite#desktop)
- - [Características de las imágenes para **Steam Deck/HTPC**](https://github.com/ublue-os/bazzite#steam-deckhome-theater-pcs-htpcs)
- - [Características de las imágenes con el entorno de escritorio **GNOME**](https://github.com/ublue-os/bazzite#gnome)
- - [Características del Upstream](https://github.com/ublue-os/bazzite#features-from-upstream)
-- [¿Por qué?](https://github.com/ublue-os/bazzite#why)
-- [Mira como luce Bazzite (Capturas de Pantalla)](https://github.com/ublue-os/bazzite#showcase)
-- [Documentación y Boletín informativo/Newsletters (En inglés)](https://github.com/ublue-os/bazzite#documentation--newsletters)
-- [Paquetes Personalizados](https://github.com/ublue-os/bazzite#custom-packages)
-- [Arranque Seguro (Secure Boot)](https://github.com/ublue-os/bazzite#secure-boot)
-- [Verificación y Métricas](https://github.com/ublue-os/bazzite#verification)
-- [Gracias Especiales](https://github.com/ublue-os/bazzite#special-thanks)
-- [Créalo tu Mismo](https://github.com/ublue-os/bazzite#build-your-own)
-- [Comunidad (en inglés)](https://github.com/ublue-os/bazzite#join-the-community)
+- [Características de **todas** las imágenes de Bazzite](#about--features)
+ - [Características de las imágenes para **Computadoras de Escritorio**](#desktop)
+ - [Características de las imágenes para **Steam Deck/HTPC**](#steam-deckhome-theater-pcs-htpcs)
+ - [Características de las imágenes con el entorno de escritorio **GNOME**](#gnome)
+ - [Características del Upstream](#features-from-upstream)
+- [¿Por qué?](#why)
+- [Mira como luce Bazzite (Capturas de Pantalla)](#showcase)
+- [Documentación y Boletín informativo/Newsletters (En inglés)](#documentation--newsletters)
+- [Paquetes Personalizados](#custom-packages)
+- [Arranque Seguro (Secure Boot)](#secure-boot)
+- [Verificación y Métricas](#verification)
+- [Gracias Especiales](#special-thanks)
+- [Créalo tu Mismo](#build-your-own)
+- [Comunidad (en inglés)](#join-the-community)
---
@@ -315,13 +317,14 @@ cosign verify --key cosign.pub ghcr.io/ublue-os/bazzite
## Arranque Seguro (Secure Boot)
-El Arranque Seguro (Secure Boot) tiene soporte gracias a nuestra llave digital personalizada. La llave pública puede encontrarse en la raíz de [este](https://github.com/ublue-os/bazzite/blob/main/secure_boot_key.der) repositorio.
+El Arranque Seguro (Secure Boot) tiene soporte gracias a nuestra llave digital personalizada. La llave pública puede encontrarse en la raíz de [este](https://github.com/ublue-os/bazzite/blob/main/secure_boot.der) repositorio.
Si gustas registrar esta llave antes de instalar Bazzite, descarga la llave y ejecuta el siguiente comando en una terminal:
```bash
-sudo mokutil --import secure_boot_key.der
+sudo mokutil --timeout -1
+sudo mokutil --import secure_boot.der
```
### Métricas de Contribución
diff --git a/README.md b/README.md
index c896b0dc69..bdd38f021f 100644
--- a/README.md
+++ b/README.md
@@ -4,23 +4,26 @@
[![build-bazzite](https://github.com/ublue-os/bazzite/actions/workflows/build.yml/badge.svg)](https://github.com/ublue-os/bazzite/actions/workflows/build.yml)
+# [🇺🇸](https://github.com/ublue-os/bazzite/blob/main/README.md) [🇪🇸](https://github.com/ublue-os/bazzite/blob/main/README-SPA.md) [🇮🇩](https://github.com/ublue-os/bazzite/blob/main/README-ID.md)
+
---
+
# Table of Contents
-- [Features for **All** Bazzite Images](https://github.com/ublue-os/bazzite#about--features)
- - [Features for **Desktop** Images](https://github.com/ublue-os/bazzite#desktop)
- - [Features for **Steam Deck / HTPC** Images](https://github.com/ublue-os/bazzite#steam-deckhome-theater-pcs-htpcs)
- - [Features for **GNOME** Images](https://github.com/ublue-os/bazzite#gnome)
- - [Features from Upstream](https://github.com/ublue-os/bazzite#features-from-upstream)
-- [Why](https://github.com/ublue-os/bazzite#why)
-- [Showcase](https://github.com/ublue-os/bazzite#showcase)
-- [Documentation & Newsletters](https://github.com/ublue-os/bazzite#documentation--newsletters)
-- [Custom Packages](https://github.com/ublue-os/bazzite#custom-packages)
-- [Image Verification](https://github.com/ublue-os/bazzite#verification)
-- [Secure Boot](https://github.com/ublue-os/bazzite#secure-boot)
-- [Metrics](https://github.com/ublue-os/bazzite#contributor-metrics)
-- [Special Thanks](https://github.com/ublue-os/bazzite#special-thanks)
-- [Building Your Own](https://github.com/ublue-os/bazzite#build-your-own)
-- [Community](https://github.com/ublue-os/bazzite#join-the-community)
+- [Features for **All** Bazzite Images](#about--features)
+ - [Features for **Desktop** Images](#desktop)
+ - [Features for **Steam Deck / HTPC** Images](#steam-deckhome-theater-pcs-htpcs)
+ - [Features for **GNOME** Images](#gnome)
+ - [Features from Upstream](#features-from-upstream)
+- [Why](#why)
+- [Showcase](#showcase)
+- [Documentation & Newsletters](#documentation--newsletters)
+- [Custom Packages](#custom-packages)
+- [Image Verification](#verification)
+- [Secure Boot](#secure-boot)
+- [Metrics](#contributor-metrics)
+- [Special Thanks](#special-thanks)
+- [Building Your Own](#build-your-own)
+- [Community](#join-the-community)
---
## About & Features
@@ -30,8 +33,7 @@ Bazzite is an OCI image that serves as an alternative operating system for the [
Bazzite is built from [ublue-os/main](https://github.com/ublue-os/main) and [ublue-os/nvidia](https://github.com/ublue-os/nvidia) using [Fedora](https://fedoraproject.org/) technology, which means expanded hardware support and built in drivers are included. Additionally, Bazzite adds the following features:
- Uses the [fsync kernel](https://copr.fedorainfracloud.org/coprs/sentry/kernel-fsync/) to achieve HDR and expanded hardware support, among numerous other included patches.
-- HDR available in Gamescope Session.
-- Proprietary Nvidia drivers pre-installed.
+- HDR available in Game mode.
- NVK available on non-Nvidia builds.
- Full hardware accelerated codec support for H264 decoding.
- Full support for AMD's ROCM OpenCL/HIP run-times.
@@ -87,7 +89,7 @@ or for devices with Nvidia GPUs:
rpm-ostree rebase ostree-unverified-registry:ghcr.io/ublue-os/bazzite-nvidia:latest
```
-**For users with Secure Boot enabled:** Run `ujust enroll-secure-boot-key` and enter the password `ublue-os` if prompted to enroll the required key.
+**For users with Secure Boot enabled:** Follow our [secure boot documentation](#secure-boot) prior to rebasing.
### Steam Deck/Home Theater PCs (HTPCs)
> [!IMPORTANT]
@@ -95,7 +97,7 @@ Devices that are NOT the Steam Deck can still use the bazzite-deck images, but m
Variant designed for usage as an alternative to SteamOS on the Steam Deck, and for a console-like experience on HTPCs, available as `bazzite-deck`:
-- Directly boots to Gamemode matching SteamOS's behavior.
+- Directly boots to Game mode matching SteamOS's behavior.
- **Automatic `duperemove` greatly trims the size of compatdata.**
- **Latest version of Mesa creates smaller shader caches and does not require them to prevent stutter.**
- **Able to be booted even if the drive is full.**
@@ -107,11 +109,11 @@ Variant designed for usage as an alternative to SteamOS on the Steam Deck, and f
- Comes with patches from [SteamOS BTRFS](https://gitlab.com/popsulfr/steamos-btrfs) for full BTRFS support for the SD card by default.
- Ships with a ported copy of [SDGyroDSU](https://github.com/kmicki/SteamDeckGyroDSU), enabled by default.
- Option to install [Decky Loader](https://github.com/SteamDeckHomebrew/decky-loader), [EmuDeck](https://www.emudeck.com/), [RetroDECK](https://retrodeck.net/), and [ProtonUp-Qt](https://davidotek.github.io/protonup-qt/), among numerous other useful packages on installation.
-- Custom update system allows for the OS, Flatpaks, Nix packages (Via Fleek), and Distrobox images to be updated directly from the Gamemode UI.
+- Custom update system allows for the OS, Flatpaks, Nix packages (Via Fleek), and Distrobox images to be updated directly from the Game mode UI.
- Built in support for Windows dual-boot thanks to Fedora's installation of GRUB being left intact.
- Update break something? Easily roll back to the previous version of Bazzite thanks to `rpm-ostree`'s rollback functionality. You can even select previous images at boot.
- Steam and Lutris preinstalled on the image as layered packages.
-- [Discover Overlay](https://github.com/trigg/Discover) for Discord pre-installed and automatically launches in both Gamemode and on the Desktop if Discord is installed. [View the official documentation here](https://trigg.github.io/Discover/bazzite).
+- [Discover Overlay](https://github.com/trigg/Discover) for Discord pre-installed and automatically launches in both Game mode and on the Desktop if Discord is installed. [View the official documentation here](https://trigg.github.io/Discover/bazzite).
- Uses ZRAM(4GB) with the ZSTD compression algorithm by default with the option to switch back to a 1GB swap file and set a custom size for it if desired.
- Kyber I/O scheduler to prevent I/O starvation when installing games or during background `duperemove` and `rmlint` processes.
- Applies SteamOS's kernel parameters.
@@ -122,7 +124,7 @@ Variant designed for usage as an alternative to SteamOS on the Steam Deck, and f
- Built in support for display overclocking. For example, add `GAMESCOPE_OVERRIDE_REFRESH_RATE=40,70` to `/etc/environment`.
- Ability to use X11 on the desktop if desired by editing `/etc/default/desktop-wayland`.
- 32GB RAM mod your Steam Deck? Enjoy double the maximum VRAM amount, automatically applied. (Can you share your soldering skills?)
-- Steam Deck hardware-specific services can be disabled by running `ujust disable-deck-services` in the terminal, useful for trying this image on other handhelds or for use on HTPCs.
+- Steam Deck hardware-specific services can be disabled by running `ujust disable-bios-updates` and `ujust disable-firmware-updates` in the terminal. These are automatically disabled on non-Deck hardware, and on Decks with DeckHD displays or 32GB RAM mods.
- More information can be found [here](https://universal-blue.discourse.group/docs?topic=37) on the Bazzite Steam Deck images.
> [!WARNING]
@@ -172,10 +174,13 @@ To rebase an existing ostree system to the **Steam Deck/HTPC** release:
rpm-ostree rebase ostree-unverified-registry:ghcr.io/ublue-os/bazzite-deck-gnome:latest
```
+**For users with Secure Boot enabled:** Follow our [secure boot documentation](#secure-boot) prior to rebasing.
+
### Features from Upstream
#### Universal Blue
+- Proprietary Nvidia drivers pre-installed.
- Flathub is enabled by default.
- [`ujust`](https://github.com/casey/just) commands for convenience.
- Multi-media codecs out of the box.
@@ -277,6 +282,7 @@ Additionally, the following packages are used from other Copr repos:
| [joycond](https://copr.fedorainfracloud.org/coprs/kylegospo/joycond/) | ![Build Status](https://copr.fedorainfracloud.org/coprs/kylegospo/joycond/package/joycond/status_image/last_build.png?) |
| [kernel-fsync](https://copr.fedorainfracloud.org/coprs/sentry/kernel-fsync/) | ![Build Status](https://copr.fedorainfracloud.org/coprs/sentry/kernel-fsync/package/kernel/status_image/last_build.png?) |
| [latencyflex-vulkan-layer](https://copr.fedorainfracloud.org/coprs/kylegospo/LatencyFleX/) | ![Build Status](https://copr.fedorainfracloud.org/coprs/kylegospo/LatencyFleX/package/latencyflex-vulkan-layer/status_image/last_build.png?) |
+| [nerd-fonts](https://copr.fedorainfracloud.org/coprs/che/nerd-fonts/) | ![Build Status](https://copr.fedorainfracloud.org/coprs/che/nerd-fonts/package/nerd-fonts/status_image/last_build.png?) |
| [noise-suppression-for-voice](https://copr.fedorainfracloud.org/coprs/ycollet/audinux/) | ![Build Status](https://copr.fedorainfracloud.org/coprs/ycollet/audinux/package/noise-suppression-for-voice/status_image/last_build.png?) |
| [obs-vkcapture](https://copr.fedorainfracloud.org/coprs/kylegospo/obs-vkcapture/) | ![Build Status](https://copr.fedorainfracloud.org/coprs/kylegospo/obs-vkcapture/package/obs-vkcapture/status_image/last_build.png?) |
| [prompt](https://gitlab.gnome.org/chergert/prompt) | ![Build Status](https://copr.fedorainfracloud.org/coprs/kylegospo/prompt/package/prompt/status_image/last_build.png?) |
@@ -297,17 +303,32 @@ cosign verify --key cosign.pub ghcr.io/ublue-os/bazzite
## Secure Boot
-Secure boot is supported with our custom key. The pub key can be found in the root of this repository [here](https://github.com/ublue-os/bazzite/blob/main/secure_boot_key.der).
-If you'd like to enroll this key prior to installation, download the key and run the following:
+Secure boot is supported with our custom key. The pub key can be found in the root of this repository [here](https://github.com/ublue-os/bazzite/blob/main/secure_boot.der).
+If you'd like to enroll this key prior to installation or rebase, download the key and run the following:
```bash
-sudo mokutil --import secure_boot_key.der
+sudo mokutil --timeout -1
+sudo mokutil --import secure_boot.der
```
+For users already on a Universal Blue image, you may instead run `ujust enroll-secure-boot-key`.
+
+If asked for a password, use `ublue-os`.
+
### Contributor Metrics
![Bazzite](https://repobeats.axiom.co/api/embed/86b500d79c613015ad16f56df76c8e13f3fd98ae.svg "Repobeats analytics image")
+#### Star History
+
+
+
+
+
## Special Thanks
Bazzite is a community effort and wouldn't exist without everyone's support. Below are some of the people who've helped us along the way:
diff --git a/secure_boot_key.der b/secure_boot.der
similarity index 100%
rename from secure_boot_key.der
rename to secure_boot.der
diff --git a/spec_files/jupiter-fan-control/fedora.patch b/spec_files/jupiter-fan-control/fedora.patch
index 631324ae12..95076df6f9 100644
--- a/spec_files/jupiter-fan-control/fedora.patch
+++ b/spec_files/jupiter-fan-control/fedora.patch
@@ -16,3 +16,12 @@ diff -ur usr/share/jupiter-fan-control/PID.py usr/share/jupiter-fan-control/PID.
#
# This file is part of IvPID.
# Copyright (C) 2015 Ivmech Mechatronics Ltd.
+@@ -64,7 +64,7 @@
+ """Calculates PID value for given reference feedback
+
+ .. math::
+- u(t) = K_p e(t) + K_i \int_{0}^{t} e(t)dt + K_d {de}/{dt}
++ u(t) = K_p e(t) + K_i \\int_{0}^{t} e(t)dt + K_d {de}/{dt}
+
+ .. figure:: images/pid_1.png
+ :align: center
diff --git a/spec_files/jupiter-hw-support/bazzite.png b/spec_files/jupiter-hw-support/bazzite.png
new file mode 100644
index 0000000000..8674610f31
Binary files /dev/null and b/spec_files/jupiter-hw-support/bazzite.png differ
diff --git a/spec_files/jupiter-hw-support/jupiter-hw-support-btrfs.spec b/spec_files/jupiter-hw-support/jupiter-hw-support-btrfs.spec
index 4d75fed237..aae12f1752 100644
--- a/spec_files/jupiter-hw-support/jupiter-hw-support-btrfs.spec
+++ b/spec_files/jupiter-hw-support/jupiter-hw-support-btrfs.spec
@@ -10,9 +10,10 @@ License: GPLv3
URL: https://github.com/ublue-os/bazzite
Source: https://gitlab.com/evlaV/%{packagename}/-/archive/%{packagever}/%{packagename}-%{packagever}.tar.gz
+Source2: bazzite.png
Patch0: fedora.patch
Patch1: selinux.patch
-Patch2: btrfs-automount.patch
+Patch2: btrfs-automount.patch
Patch3: btrfs-format.patch
Patch4: user.patch
Patch5: bazzite-btrfs.patch
@@ -69,6 +70,7 @@ cp -rv usr/lib/udev %{buildroot}%{_prefix}/lib/udev
cp -rv usr/bin/* %{buildroot}%{_bindir}
cp -rv usr/lib/systemd/system/* %{buildroot}%{_unitdir}
cp -rv etc/* %{buildroot}%{_sysconfdir}
+cp %{SOURCE2} %{buildroot}%{_datadir}/plymouth/themes/steamos/bazzite.png
sed -i 's@steamos-cursor.png@usr/share/steamos/steamos-cursor.png@g' usr/share/steamos/steamos-cursor-config
xcursorgen usr/share/steamos/steamos-cursor-config %{buildroot}%{_datadir}/icons/steam/cursors/default
# Remove unneeded files
diff --git a/spec_files/mesa/0001-intel-compiler-fix-release-build-unused-variable.patch b/spec_files/mesa/0001-intel-compiler-fix-release-build-unused-variable.patch
deleted file mode 100644
index 7cce8273e7..0000000000
--- a/spec_files/mesa/0001-intel-compiler-fix-release-build-unused-variable.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From b32d3c9251e18c77b4d58db61b43797ffb7b05cf Mon Sep 17 00:00:00 2001
-From: Dave Airlie
-Date: Wed, 3 Jan 2024 16:31:23 +1000
-Subject: [PATCH] intel/compiler: fix release build unused variable.
-
-This is only used in an assert.
-
-Fixes: 158ac265dfd0 ("intel/fs: Make helpers for saving/restoring instruction order")
----
- src/intel/compiler/brw_fs.cpp | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/intel/compiler/brw_fs.cpp b/src/intel/compiler/brw_fs.cpp
-index 696b5db8d9d..aa01a2241ce 100644
---- a/src/intel/compiler/brw_fs.cpp
-+++ b/src/intel/compiler/brw_fs.cpp
-@@ -6834,7 +6834,7 @@ save_instruction_order(const struct cfg_t *cfg)
- static void
- restore_instruction_order(struct cfg_t *cfg, fs_inst **inst_arr)
- {
-- int num_insts = cfg->last_block()->end_ip + 1;
-+ ASSERTED int num_insts = cfg->last_block()->end_ip + 1;
-
- int ip = 0;
- foreach_block (block, cfg) {
---
-2.43.0
-
diff --git a/spec_files/mesa/0001-intel-compiler-reemit-boolean-resolve-for-inverted-i.patch b/spec_files/mesa/0001-intel-compiler-reemit-boolean-resolve-for-inverted-i.patch
deleted file mode 100644
index dd7a9b540f..0000000000
--- a/spec_files/mesa/0001-intel-compiler-reemit-boolean-resolve-for-inverted-i.patch
+++ /dev/null
@@ -1,42 +0,0 @@
-From 56a72e014fcda3c52cf119115cb71fce2fad86d8 Mon Sep 17 00:00:00 2001
-From: Dave Airlie
-Date: Thu, 21 Dec 2023 10:39:08 +1000
-Subject: [PATCH] intel/compiler: reemit boolean resolve for inverted if on
- gen5
-
-Gen5 adds some boolean conversion instructions after nir emits,
-but that nir srcs don't line up with them, so reemit the boolean
-conversion if we reemit the inot.
-
-Reviewed-by: Lionel Landwerlin
-Fixes: 31b5f5a51f3a ("nir/opt_if: Simplify if's with general conditions")
-Part-of:
----
- src/intel/compiler/brw_fs_nir.cpp | 11 +++++++++++
- 1 file changed, 11 insertions(+)
-
-diff --git a/src/intel/compiler/brw_fs_nir.cpp b/src/intel/compiler/brw_fs_nir.cpp
-index 33f2a4046b2..ccdd0fe7db8 100644
---- a/src/intel/compiler/brw_fs_nir.cpp
-+++ b/src/intel/compiler/brw_fs_nir.cpp
-@@ -422,6 +422,17 @@ fs_visitor::nir_emit_if(nir_if *if_stmt)
- invert = true;
- cond_reg = get_nir_src(cond->src[0].src);
- cond_reg = offset(cond_reg, bld, cond->src[0].swizzle[0]);
-+
-+ if (devinfo->ver <= 5 &&
-+ (cond->instr.pass_flags & BRW_NIR_BOOLEAN_MASK) == BRW_NIR_BOOLEAN_NEEDS_RESOLVE) {
-+ /* redo boolean resolve on gen5 */
-+ fs_reg masked = bld.vgrf(BRW_REGISTER_TYPE_D);
-+ bld.AND(masked, cond_reg, brw_imm_d(1));
-+ masked.negate = true;
-+ fs_reg tmp = bld.vgrf(cond_reg.type);
-+ bld.MOV(retype(tmp, BRW_REGISTER_TYPE_D), masked);
-+ cond_reg = tmp;
-+ }
- } else {
- invert = false;
- cond_reg = get_nir_src(if_stmt->condition);
---
-2.43.0
-
diff --git a/spec_files/mesa/disable-zink-egl-fallback.patch b/spec_files/mesa/disable-zink-egl-fallback.patch
deleted file mode 100644
index c036acead2..0000000000
--- a/spec_files/mesa/disable-zink-egl-fallback.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c
-index d50be23e871..e3697622635 100644
---- a/src/egl/main/eglapi.c
-+++ b/src/egl/main/eglapi.c
-@@ -695,17 +695,21 @@ eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
- if (disp->Options.ForceSoftware)
- RETURN_EGL_ERROR(disp, EGL_NOT_INITIALIZED, EGL_FALSE);
- else {
-+#if 0
- bool success = false;
- if (!disp->Options.Zink && !getenv("GALLIUM_DRIVER")) {
- disp->Options.Zink = EGL_TRUE;
- success = _eglDriver.Initialize(disp);
- }
- if (!success) {
-+#endif
- disp->Options.Zink = EGL_FALSE;
- disp->Options.ForceSoftware = EGL_TRUE;
- if (!_eglDriver.Initialize(disp))
- RETURN_EGL_ERROR(disp, EGL_NOT_INITIALIZED, EGL_FALSE);
-+#if 0
- }
-+#endif
- }
- }
-
diff --git a/spec_files/mesa/mesa-meson-c99.patch b/spec_files/mesa/mesa-meson-c99.patch
new file mode 100644
index 0000000000..6cbb053621
--- /dev/null
+++ b/spec_files/mesa/mesa-meson-c99.patch
@@ -0,0 +1,42 @@
+meson: C type error in strtod_l/strtof_l probe
+
+Future compilers will fail compilation due to the C type error:
+
+…/testfile.c: In function 'main':
+…/testfile.c:12:30: error: passing argument 2 of 'strtod_l' from incompatible pointer type
+ 12 | double d = strtod_l(s, end, loc);
+ | ^~~
+ | |
+ | char *
+/usr/include/stdlib.h:416:43: note: expected 'char ** restrict' but argument is of type 'char *'
+ 416 | char **__restrict __endptr, locale_t __loc)
+ | ~~~~~~~~~~~~~~~~~~^~~~~~~~
+…/testfile.c:13:29: error: passing argument 2 of 'strtof_l' from incompatible pointer type
+ 13 | float f = strtof_l(s, end, loc);
+ | ^~~
+ | |
+ | char *
+/usr/include/stdlib.h:420:42: note: expected 'char ** restrict' but argument is of type 'char *'
+ 420 | char **__restrict __endptr, locale_t __loc)
+ | ~~~~~~~~~~~~~~~~~~^~~~~~~~
+
+This means that the probe no longer tests is objective and always
+fails.
+
+Submitted upstream:
+
+diff --git a/meson.build b/meson.build
+index 35cc5f1cd5fd9079..1a5d2ba492be0b31 100644
+--- a/meson.build
++++ b/meson.build
+@@ -1425,8 +1425,8 @@ if cc.links('''
+ locale_t loc = newlocale(LC_CTYPE_MASK, "C", NULL);
+ const char *s = "1.0";
+ char *end;
+- double d = strtod_l(s, end, loc);
+- float f = strtof_l(s, end, loc);
++ double d = strtod_l(s, &end, loc);
++ float f = strtof_l(s, &end, loc);
+ freelocale(loc);
+ return 0;
+ }''',
diff --git a/spec_files/mesa/mesa.spec b/spec_files/mesa/mesa.spec
index 3eeb61545e..5d3971e335 100644
--- a/spec_files/mesa/mesa.spec
+++ b/spec_files/mesa/mesa.spec
@@ -61,7 +61,7 @@
Name: mesa
Summary: Mesa graphics libraries
-%global ver 23.3.2
+%global ver 23.3.3
Version: %{lua:ver = string.gsub(rpm.expand("%{ver}"), "-", "~"); print(ver)}
Release: 100.bazzite.{{{ git_dir_version }}}
License: MIT AND BSD-3-Clause AND SGI-B-2.0
@@ -74,9 +74,8 @@ Source0: https://archive.mesa3d.org/mesa-%{ver}.tar.xz
Source1: Mesa-MLAA-License-Clarification-Email.txt
Patch10: gnome-shell-glthread-disable.patch
-Patch11: 0001-intel-compiler-reemit-boolean-resolve-for-inverted-i.patch
-Patch12: 0001-intel-compiler-fix-release-build-unused-variable.patch
-Patch13: disable-zink-egl-fallback.patch
+Patch11: zink-fix-resizable-bar-detection-logic.patch
+Patch12: mesa-meson-c99.patch
# https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/26105/
Patch30: 26105.patch
diff --git a/spec_files/mesa/zink-fix-resizable-bar-detection-logic.patch b/spec_files/mesa/zink-fix-resizable-bar-detection-logic.patch
new file mode 100644
index 0000000000..4a5e916d52
--- /dev/null
+++ b/spec_files/mesa/zink-fix-resizable-bar-detection-logic.patch
@@ -0,0 +1,39 @@
+From a077c14f150f1c4f670dce381ac2eb548f1a4ac2 Mon Sep 17 00:00:00 2001
+From: Alessandro Astone
+Date: Wed, 10 Jan 2024 17:24:30 +0100
+Subject: [PATCH] zink: Fix resizable BAR detection logic
+
+This was broken in two ways:
+* When looking for the MAX biggest_ram it was actually comparing
+ a candidate against biggest_vis_ram
+
+* mem_props.memoryTypes[] should be accessed with the memory type
+ index as found in heap_map
+
+Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/10341
+Cc: 23.3
+Part-of:
+---
+ src/gallium/drivers/zink/zink_screen.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/gallium/drivers/zink/zink_screen.c b/src/gallium/drivers/zink/zink_screen.c
+index 5a6d17cb4fa3..6697d7ab938c 100644
+--- a/src/gallium/drivers/zink/zink_screen.c
++++ b/src/gallium/drivers/zink/zink_screen.c
+@@ -3258,10 +3258,10 @@ zink_internal_create_screen(const struct pipe_screen_config *config, int64_t dev
+ {
+ uint64_t biggest_vis_vram = 0;
+ for (unsigned i = 0; i < screen->heap_count[ZINK_HEAP_DEVICE_LOCAL_VISIBLE]; i++)
+- biggest_vis_vram = MAX2(biggest_vis_vram, screen->info.mem_props.memoryHeaps[screen->info.mem_props.memoryTypes[i].heapIndex].size);
++ biggest_vis_vram = MAX2(biggest_vis_vram, screen->info.mem_props.memoryHeaps[screen->info.mem_props.memoryTypes[screen->heap_map[ZINK_HEAP_DEVICE_LOCAL_VISIBLE][i]].heapIndex].size);
+ uint64_t biggest_vram = 0;
+ for (unsigned i = 0; i < screen->heap_count[ZINK_HEAP_DEVICE_LOCAL]; i++)
+- biggest_vram = MAX2(biggest_vis_vram, screen->info.mem_props.memoryHeaps[screen->info.mem_props.memoryTypes[i].heapIndex].size);
++ biggest_vram = MAX2(biggest_vram, screen->info.mem_props.memoryHeaps[screen->info.mem_props.memoryTypes[screen->heap_map[ZINK_HEAP_DEVICE_LOCAL][i]].heapIndex].size);
+ /* determine if vis vram is roughly equal to total vram */
+ if (biggest_vis_vram > biggest_vram * 0.9)
+ screen->resizable_bar = true;
+--
+GitLab
+
diff --git a/spec_files/pipewire/pipewire.spec b/spec_files/pipewire/pipewire.spec
index d941963c56..bb931bc013 100644
--- a/spec_files/pipewire/pipewire.spec
+++ b/spec_files/pipewire/pipewire.spec
@@ -1,6 +1,6 @@
%global majorversion 1
%global minorversion 0
-%global microversion 0
+%global microversion 1
%global apiversion 0.3
%global spaversion 0.2
@@ -81,7 +81,7 @@ Source1: pipewire.sysusers
# Holo: TODO: Bug reference
Patch0: bc435841c141ad38768b6cb1a7ad45e8bb13c7d2.patch
# Holo: TODO: Bug reference
-Patch1: acf7c0af0bf31b937c41e916a73c67ae0a253632.patch
+#Patch1: acf7c0af0bf31b937c41e916a73c67ae0a253632.patch
# Holo: upstream MR 1792
Patch2: 0001-Bluez5-backend-native-HSP-AG-release-SCO-link-on-AT-.patch
@@ -818,6 +818,12 @@ systemctl --no-reload preset --global pipewire.socket >/dev/null 2>&1 || :
%endif
%changelog
+* Thu Jan 11 2024 Wim Taymans - 1.0.1-1
+- Update version to 1.0.1
+
+* Thu Dec 14 2023 Wim Taymans - 1.0.0-2
+- Add patch to avoid crash in deviceprovider.
+
* Sun Nov 26 2023 Wim Taymans - 1.0.0-1
- Update version to 1.0.0
- Disable ROC until updated in Fedora.
diff --git a/spec_files/steamdeck-dsp/bazzite.patch b/spec_files/steamdeck-dsp/bazzite.patch
new file mode 100644
index 0000000000..be71df44a2
--- /dev/null
+++ b/spec_files/steamdeck-dsp/bazzite.patch
@@ -0,0 +1,57 @@
+--- a/wireplumber/hardware-profiles/wireplumber-hwconfig
++++ b/wireplumber/hardware-profiles/wireplumber-hwconfig
+@@ -45,39 +45,23 @@
+ install_hwprofile ()
+ {
+ local -r prpath="$1"
+- local -r runconf=/run/wireplumber
++ local -r confdir=/usr/share/wireplumber
+ local confd
+ local conffile
+
+- echo "Installing wireplumber hardware profile from '$prpath' in $runconf"
+-
+- rm -rf $runconf
++ echo "Installing wireplumber hardware profile from '$prpath' in $confdir"
+
+ for confd in "${confdirs[@]}"
+ do
+ if [ -d "$prpath"/"$confd" ]
+ then
+- mkdir -p $runconf/"$confd"
++ mkdir -p $confdir/"$confd"
+ for conffile in "$prpath"/"$confd"/*.lua
+ do
+- cp -av $conffile $runconf/"$confd"
++ /usr/bin/cp -avf $conffile $confdir/"$confd"
+ done
+ fi
+ done
+-
+- cat - < $runconf/README
+-This configuration was:
+-
+- - installed in $runconf
+- - by $0
+- - from $prpath
+-
+-It will be regenerated every time the system restarts.
+-
+-To alter it permanently either:
+- - edit $prpath
+- - override in \$XDG_CONFIG_DIR/wireplumber/
+-EOF
+ }
+
+ unidentified ()
+--- a/wireplumber/systemd/system/wireplumber-sysconf.service
++++ b/wireplumber/systemd/system/wireplumber-sysconf.service
+@@ -11,7 +11,7 @@
+ Description=Hardware Specific Wireplumber Configuration
+ After=multi-user.target
+ Requisite=multi-user.target
+-ConditionPathIsDirectory=/run
++Requires=wireplumber-workaround.service
+ Before=shutdown.target
+
+ [Service]
diff --git a/spec_files/steamdeck-dsp/steamdeck-dsp.spec b/spec_files/steamdeck-dsp/steamdeck-dsp.spec
index 134e667c47..2fccf73e12 100644
--- a/spec_files/steamdeck-dsp/steamdeck-dsp.spec
+++ b/spec_files/steamdeck-dsp/steamdeck-dsp.spec
@@ -7,6 +7,7 @@ URL: https://github.com/ublue-os/bazzite
Source: https://gitlab.com/evlaV/valve-hardware-audio-processing/-/archive/main/valve-hardware-audio-processing-main.tar.gz
Patch0: fedora.patch
+Patch1: bazzite.patch
Requires: pipewire-module-filter-chain-lv2
Requires: ladspa-noise-suppression-for-voice
@@ -29,8 +30,7 @@ Steamdeck Audio Processing
%define debug_package %{nil}
%prep
-%setup -n valve-hardware-audio-processing-main
-%patch 0 -p1
+%autosetup -n valve-hardware-audio-processing-main -p1
%build
%make_build FAUSTINC="/usr/include/faust" FAUSTLIB="/usr/share/faust"
diff --git a/spec_files/steamdeck-kde-presets/bazzite_logo.patch b/spec_files/steamdeck-kde-presets/bazzite_logo.patch
new file mode 100644
index 0000000000..0f5b39af02
--- /dev/null
+++ b/spec_files/steamdeck-kde-presets/bazzite_logo.patch
@@ -0,0 +1,24 @@
+diff -Naur a/usr/share/plasma/look-and-feel/com.valve.vapor.desktop/contents/splash/Splash.qml b/usr/share/plasma/look-and-feel/com.valve.vapor.desktop/contents/splash/Splash.qml
+--- a/usr/share/plasma/look-and-feel/com.valve.vapor.desktop/contents/splash/Splash.qml
++++ b/usr/share/plasma/look-and-feel/com.valve.vapor.desktop/contents/splash/Splash.qml
+@@ -42,7 +42,7 @@
+
+ anchors.centerIn: parent
+
+- source: "images/deck_logo.svgz"
++ source: "images/bazzite_logo.svgz"
+
+ sourceSize.width: 128
+ sourceSize.height: 128
+diff -Naur a/usr/share/plasma/look-and-feel/com.valve.vgui.desktop/contents/splash/Splash.qml b/usr/share/plasma/look-and-feel/com.valve.vgui.desktop/contents/splash/Splash.qml
+--- a/usr/share/plasma/look-and-feel/com.valve.vgui.desktop/contents/splash/Splash.qml
++++ b/usr/share/plasma/look-and-feel/com.valve.vgui.desktop/contents/splash/Splash.qml
+@@ -42,7 +42,7 @@
+
+ anchors.centerIn: parent
+
+- source: "images/deck_logo.svgz"
++ source: "images/bazzite_logo.svgz"
+
+ sourceSize.width: 128
+ sourceSize.height: 128
diff --git a/spec_files/steamdeck-kde-presets/bazzite_logo.svgz b/spec_files/steamdeck-kde-presets/bazzite_logo.svgz
new file mode 100644
index 0000000000..94510627da
Binary files /dev/null and b/spec_files/steamdeck-kde-presets/bazzite_logo.svgz differ
diff --git a/spec_files/steamdeck-kde-presets/steamdeck-kde-presets-desktop.spec b/spec_files/steamdeck-kde-presets/steamdeck-kde-presets-desktop.spec
index 782f58a735..9dedec1271 100644
--- a/spec_files/steamdeck-kde-presets/steamdeck-kde-presets-desktop.spec
+++ b/spec_files/steamdeck-kde-presets/steamdeck-kde-presets-desktop.spec
@@ -8,8 +8,10 @@ URL: https://github.com/ublue-os/bazzite
Source0: https://gitlab.com/evlaV/steamdeck-kde-presets/-/archive/master/steamdeck-kde-presets-master.tar.gz
Source1: kdeglobals-desktop
Source2: steamdeck-le.svg
+Source3: bazzite_logo.svgz
Patch0: multiuser.patch
Patch1: lockscreen.patch
+Patch2: bazzite_logo.patch
BuildArch: noarch
@@ -61,6 +63,10 @@ rm %{buildroot}%{_sysconfdir}/xdg/baloofilerc
rm %{buildroot}%{_sysconfdir}/xdg/kdeglobals
rm %{buildroot}%{_sysconfdir}/xdg/kcm-about-distrorc
cp %{SOURCE1} %{buildroot}%{_sysconfdir}/xdg/kdeglobals
+rm %{buildroot}%{_datadir}/plasma/look-and-feel/com.valve.vapor.desktop/contents/splash/images/deck_logo.svgz
+rm %{buildroot}%{_datadir}/plasma/look-and-feel/com.valve.vgui.desktop/contents/splash/images/deck_logo.svgz
+cp %{SOURCE3} %{buildroot}%{_datadir}/plasma/look-and-feel/com.valve.vapor.desktop/contents/splash/images/bazzite_logo.svgz
+cp %{SOURCE3} %{buildroot}%{_datadir}/plasma/look-and-feel/com.valve.vgui.desktop/contents/splash/images/bazzite_logo.svgz
# Do post-installation
%post
diff --git a/spec_files/steamdeck-kde-presets/steamdeck-kde-presets.spec b/spec_files/steamdeck-kde-presets/steamdeck-kde-presets.spec
index 03b7f8a52b..fc62fb3e3f 100644
--- a/spec_files/steamdeck-kde-presets/steamdeck-kde-presets.spec
+++ b/spec_files/steamdeck-kde-presets/steamdeck-kde-presets.spec
@@ -7,10 +7,12 @@ URL: https://github.com/ublue-os/bazzite
Source0: https://gitlab.com/evlaV/%{name}/-/archive/master/%{name}-master.tar.gz
Source1: steamdeck-le.svg
+Source2: bazzite_logo.svgz
BuildArch: noarch
Patch0: fedora.patch
Patch1: nested-desktop-resolution.patch
Patch2: kdeglobals.patch
+Patch3: bazzite_logo.patch
Requires: kde-filesystem
@@ -47,6 +49,10 @@ rm %{buildroot}%{_datadir}/applications/org.mozilla.firefox.desktop
rm %{buildroot}%{_sysconfdir}/profile.d/kde.sh
rm %{buildroot}%{_sysconfdir}/xdg/kcm-about-distrorc
rm %{buildroot}%{_sysconfdir}/X11/Xsession.d/50rotate-screen
+rm %{buildroot}%{_datadir}/plasma/look-and-feel/com.valve.vapor.desktop/contents/splash/images/deck_logo.svgz
+rm %{buildroot}%{_datadir}/plasma/look-and-feel/com.valve.vgui.desktop/contents/splash/images/deck_logo.svgz
+cp %{SOURCE2} %{buildroot}%{_datadir}/plasma/look-and-feel/com.valve.vapor.desktop/contents/splash/images/bazzite_logo.svgz
+cp %{SOURCE2} %{buildroot}%{_datadir}/plasma/look-and-feel/com.valve.vgui.desktop/contents/splash/images/bazzite_logo.svgz
# Do post-installation
%post
diff --git a/spec_files/wireplumber/steamdeck.patch b/spec_files/wireplumber/valve.patch
similarity index 53%
rename from spec_files/wireplumber/steamdeck.patch
rename to spec_files/wireplumber/valve.patch
index dcd8e7c5a3..f0e97df8ba 100644
--- a/spec_files/wireplumber/steamdeck.patch
+++ b/spec_files/wireplumber/valve.patch
@@ -1,25 +1,14 @@
-diff --git a/modules/meson.build b/modules/meson.build
-index 4930bfae..4a337017 100644
---- a/modules/meson.build
-+++ b/modules/meson.build
-@@ -159,6 +159,17 @@ shared_library(
- dependencies : [wp_dep, pipewire_dep],
- )
-
-+shared_library(
-+ 'wireplumber-module-filters-api',
-+ [
-+ 'module-filters-api.c',
-+ ],
-+ c_args : [common_c_args, '-DG_LOG_DOMAIN="m-filters-api"'],
-+ install : true,
-+ install_dir : wireplumber_module_dir,
-+ dependencies : [wp_dep, pipewire_dep],
-+)
-+
- if libsystemd_dep.found() or libelogind_dep.found()
- shared_library(
- 'wireplumber-module-logind',
+From 9911c8532eb9072d93eb39b02aa94699f0a735a1 Mon Sep 17 00:00:00 2001
+From: Julian Bouzas
+Date: Tue, 21 Mar 2023 09:18:30 -0400
+Subject: [PATCH 01/11] m-default-nodes: remove echo-cancel configuration
+
+This will be possible to do with the new module-filters-api.
+---
+ modules/module-default-nodes.c | 75 --------------------
+ src/config/main.lua.d/40-device-defaults.lua | 9 ---
+ 2 files changed, 84 deletions(-)
+
diff --git a/modules/module-default-nodes.c b/modules/module-default-nodes.c
index aaf29389..3bb93f00 100644
--- a/modules/module-default-nodes.c
@@ -178,12 +167,84 @@ index aaf29389..3bb93f00 100644
NULL));
return TRUE;
}
+diff --git a/src/config/main.lua.d/40-device-defaults.lua b/src/config/main.lua.d/40-device-defaults.lua
+index 19202914..91c4e189 100644
+--- a/src/config/main.lua.d/40-device-defaults.lua
++++ b/src/config/main.lua.d/40-device-defaults.lua
+@@ -10,15 +10,6 @@ device_defaults.properties = {
+ -- the default volumes to apply to ACP device nodes, in the linear scale
+ --["default-volume"] = 0.064,
+ --["default-input-volume"] = 1.0,
+-
+- -- Whether to auto-switch to echo cancel sink and source nodes or not
+- ["auto-echo-cancel"] = true,
+-
+- -- Sets the default echo-cancel-sink node name to automatically switch to
+- ["echo-cancel-sink-name"] = "echo-cancel-sink",
+-
+- -- Sets the default echo-cancel-source node name to automatically switch to
+- ["echo-cancel-source-name"] = "echo-cancel-source",
+ }
+
+ -- Sets persistent device profiles that should never change when wireplumber is
+--
+2.42.0
+
+
+From a9b6f3bcb4c525c1e257873875feb6223fa6b660 Mon Sep 17 00:00:00 2001
+From: Julian Bouzas
+Date: Fri, 17 Mar 2023 11:06:11 -0400
+Subject: [PATCH 02/11] modules: add new module-filters-api to enable smart
+ filter policy
+
+This module provides an API to link filter nodes using the logic configured in
+'policy.lua.d/30-filters-config.lua'. This configuration file allows grouping
+filters together (sorted by priority) to use a common target node. A node is
+considered a filter node if it has the node.link-group property.
+
+This is disabled by default. You can enable smart filters policy in the
+'10-default-policy.lya' configuration file.
+---
+ modules/meson.build | 11 +
+ modules/module-filters-api.c | 905 ++++++++++++++++++
+ modules/module-lua-scripting/api/json.c | 2 +-
+ src/config/policy.lua.d/10-default-policy.lua | 9 +
+ src/config/policy.lua.d/30-filters-config.lua | 73 ++
+ src/scripts/filters-metadata.lua | 39 +
+ src/scripts/policy-node.lua | 120 ++-
+ 7 files changed, 1156 insertions(+), 3 deletions(-)
+ create mode 100644 modules/module-filters-api.c
+ create mode 100644 src/config/policy.lua.d/30-filters-config.lua
+ create mode 100644 src/scripts/filters-metadata.lua
+
+diff --git a/modules/meson.build b/modules/meson.build
+index 4930bfae..4a337017 100644
+--- a/modules/meson.build
++++ b/modules/meson.build
+@@ -159,6 +159,17 @@ shared_library(
+ dependencies : [wp_dep, pipewire_dep],
+ )
+
++shared_library(
++ 'wireplumber-module-filters-api',
++ [
++ 'module-filters-api.c',
++ ],
++ c_args : [common_c_args, '-DG_LOG_DOMAIN="m-filters-api"'],
++ install : true,
++ install_dir : wireplumber_module_dir,
++ dependencies : [wp_dep, pipewire_dep],
++)
++
+ if libsystemd_dep.found() or libelogind_dep.found()
+ shared_library(
+ 'wireplumber-module-logind',
diff --git a/modules/module-filters-api.c b/modules/module-filters-api.c
new file mode 100644
-index 00000000..8852a6c5
+index 00000000..32c67c85
--- /dev/null
+++ b/modules/module-filters-api.c
-@@ -0,0 +1,920 @@
+@@ -0,0 +1,905 @@
+/* WirePlumber
+ *
+ * Copyright © 2023 Collabora Ltd.
@@ -235,12 +296,6 @@ index 00000000..8852a6c5
+};
+typedef struct _Filter Filter;
+
-+struct _Target {
-+ gboolean exclusive;
-+ WpNode *node;
-+};
-+typedef struct _Target Target;
-+
+static guint
+get_filter_priority (const gchar *link_group)
+{
@@ -279,22 +334,6 @@ index 00000000..8852a6c5
+ g_free (f);
+}
+
-+static Target *
-+target_new (gboolean exclusive, WpNode *node)
-+{
-+ Target *t = g_malloc0 (sizeof (Target));
-+ t->exclusive = exclusive;
-+ t->node = node ? g_object_ref (node) : NULL;
-+ return t;
-+}
-+
-+static void
-+target_free (Target *t)
-+{
-+ g_clear_object (&t->node);
-+ g_free (t);
-+}
-+
+static gint
+filter_equal_func (const Filter *f, const gchar *link_group)
+{
@@ -341,18 +380,16 @@ index 00000000..8852a6c5
+ return found->enabled;
+}
+
-+static WpSpaJson *
++static gint
+wp_filters_api_get_filter_target (WpFiltersApi * self, const gchar *direction,
+ const gchar *link_group)
+{
+ WpDirection dir = WP_DIRECTION_INPUT;
+ GList *filters;
+ Filter *found;
-+ g_autoptr (WpSpaJson) res = wp_spa_json_new_object (
-+ "exclusive", "b", FALSE, "bound_id", "i", -1, NULL);
+
-+ g_return_val_if_fail (direction, g_steal_pointer (&res));
-+ g_return_val_if_fail (link_group, g_steal_pointer (&res));
++ g_return_val_if_fail (direction, -1);
++ g_return_val_if_fail (link_group, -1);
+
+ /* Get the filters for the given direction */
+ if (g_str_equal (direction, "output") || g_str_equal (direction, "Output"))
@@ -363,10 +400,10 @@ index 00000000..8852a6c5
+ filters = g_list_find_custom (filters, link_group,
+ (GCompareFunc) filter_equal_func);
+ if (!filters)
-+ return g_steal_pointer (&res);
++ return -1;
+ found = filters->data;
+ if (!found->enabled)
-+ return g_steal_pointer (&res);
++ return -1;
+
+ /* Return the previous filter with matching target that is enabled */
+ while ((filters = g_list_previous (filters))) {
@@ -374,27 +411,18 @@ index 00000000..8852a6c5
+ if ((prev->target == found->target ||
+ (prev->target && found->target &&
+ g_str_equal (prev->target, found->target))) &&
-+ prev->enabled) {
-+ return wp_spa_json_new_object (
-+ "exclusive", "b", FALSE,
-+ "bound_id", "i", wp_proxy_get_bound_id (WP_PROXY (prev->node)),
-+ NULL);
-+ }
++ prev->enabled)
++ return wp_proxy_get_bound_id (WP_PROXY (prev->node));
+ }
+
+ /* Find the target */
+ if (found->target) {
-+ Target *t = g_hash_table_lookup (self->targets, found->target);
-+ if (t) {
-+ return wp_spa_json_new_object (
-+ "exclusive", "b", t->exclusive,
-+ "bound_id", "i",
-+ t->node ? (gint)wp_proxy_get_bound_id (WP_PROXY (t->node)) : -1,
-+ NULL);
-+ }
++ WpNode *node = g_hash_table_lookup (self->targets, found->target);
++ if (node)
++ return wp_proxy_get_bound_id (WP_PROXY (node));
+ }
+
-+ return g_steal_pointer (&res);
++ return -1;
+}
+
+static gint
@@ -417,17 +445,12 @@ index 00000000..8852a6c5
+ /* Find the first target matching target_id */
+ while (filters) {
+ Filter *f = (Filter *) filters->data;
-+ if (f->enabled) {
-+ gint f_target_id;
-+ g_autoptr (WpSpaJson) f_target = wp_filters_api_get_filter_target (self,
-+ direction, f->link_group);
-+ if (f_target && wp_spa_json_is_object (f_target) &&
-+ wp_spa_json_object_get (f_target, "bound_id", "i", &f_target_id, NULL)
-+ && f_target_id == target_id) {
-+ target = f->target;
-+ found = TRUE;
-+ break;
-+ }
++ gint f_target_id = wp_filters_api_get_filter_target (self, direction,
++ f->link_group);
++ if (f_target_id == target_id && f->enabled) {
++ target = f->target;
++ found = TRUE;
++ break;
+ }
+
+ /* Advance */
@@ -454,6 +477,33 @@ index 00000000..8852a6c5
+ return res;
+}
+
++static gint
++wp_filters_api_get_default_filter (WpFiltersApi * self, const gchar *direction)
++{
++ WpDirection dir = WP_DIRECTION_INPUT;
++ GList *filters;
++
++ g_return_val_if_fail (direction, -1);
++
++ /* Get the filters for the given direction */
++ if (g_str_equal (direction, "output") || g_str_equal (direction, "Output"))
++ dir = WP_DIRECTION_OUTPUT;
++ filters = self->filters[dir];
++
++ /* The default filter is the highest priority filter without target, this is
++ * the first filer that is enabled because the list is sorted by priority */
++ while (filters) {
++ Filter *f = (Filter *) filters->data;
++ if (f->enabled && !f->target)
++ return wp_proxy_get_bound_id (WP_PROXY (f->node));
++
++ /* Advance */
++ filters = g_list_next (filters);
++ }
++
++ return -1;
++}
++
+static void
+sync_changed (WpCore * core, GAsyncResult * res, WpFiltersApi * self)
+{
@@ -547,11 +597,9 @@ index 00000000..8852a6c5
+ for (; wp_iterator_next (it, &item); g_value_unset (&item)) {
+ WpSpaJson *j = g_value_get_boxed (&item);
+ g_autofree gchar *key = NULL;
-+ WpSpaJson *value;
-+ gboolean exclusive = FALSE;
-+ g_autoptr (WpSpaJson) props = NULL;
-+ g_autoptr (WpNode) target_node = NULL;
-+ Target *curr_target;
++ WpSpaJson *props;
++ g_autoptr (WpNode) target = NULL;
++ WpNode *curr_target;
+
+ key = wp_spa_json_parse_string (j);
+ g_value_unset (&item);
@@ -560,36 +608,27 @@ index 00000000..8852a6c5
+ "Could not get valid key-value pairs from target object");
+ break;
+ }
-+ value = g_value_get_boxed (&item);
-+ if (!value || !wp_spa_json_is_object (value)) {
-+ wp_warning_object (self, "Target value must be a JSON object");
-+ break;
-+ }
-+
-+ /* Get exclusive */
-+ wp_spa_json_object_get (value, "exclusive", "b", &exclusive, NULL);
-+
-+ /* Get target node */
-+ wp_spa_json_object_get (value, "props", "J", &props, NULL);
-+ if (props)
-+ target_node = find_target_node (self, props);
++ props = g_value_get_boxed (&item);
+
-+ /* Update values if target exists in the table, otherwise add new target */
++ /* Get current target */
+ curr_target = g_hash_table_lookup (self->targets, key);
-+ if (curr_target) {
-+ if (curr_target->exclusive != exclusive) {
-+ curr_target->exclusive = exclusive;
-+ changed = TRUE;
-+ }
-+ if (curr_target->node != target_node) {
-+ g_clear_object (&curr_target->node);
-+ curr_target->node = g_steal_pointer (&target_node);
-+ changed = TRUE;
++
++ /* Find the node and insert it into the table if found */
++ target = find_target_node (self, props);
++ if (target) {
++ /* Check if the target changed */
++ if (curr_target) {
++ guint32 target_bound_id = wp_proxy_get_bound_id (WP_PROXY (target));
++ guint32 curr_bound_id = wp_proxy_get_bound_id (WP_PROXY (curr_target));
++ if (target_bound_id != curr_bound_id)
++ changed = TRUE;
+ }
-+ } else {
++
+ g_hash_table_insert (self->targets, g_strdup (key),
-+ target_new (exclusive, target_node));
-+ changed = TRUE;
++ g_steal_pointer (&target));
++ } else {
++ if (curr_target)
++ changed = TRUE;
+ }
+ }
+
@@ -1025,7 +1064,7 @@ index 00000000..8852a6c5
+ g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (self));
+
+ self->targets = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
-+ (GDestroyNotify) target_free);
++ g_object_unref);
+
+ /* Create the metadata object manager */
+ self->metadata_om = wp_object_manager_new ();
@@ -1080,7 +1119,7 @@ index 00000000..8852a6c5
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ (GCallback) wp_filters_api_get_filter_target,
+ NULL, NULL, NULL,
-+ WP_TYPE_SPA_JSON, 2, G_TYPE_STRING, G_TYPE_STRING);
++ G_TYPE_INT, 2, G_TYPE_STRING, G_TYPE_STRING);
+
+ signals[ACTION_GET_FILTER_FROM_TARGET] = g_signal_new_class_handler (
+ "get-filter-from-target", G_TYPE_FROM_CLASS (klass),
@@ -1089,6 +1128,13 @@ index 00000000..8852a6c5
+ NULL, NULL, NULL,
+ G_TYPE_INT, 2, G_TYPE_STRING, G_TYPE_INT);
+
++ signals[ACTION_GET_DEFAULT_FILTER] = g_signal_new_class_handler (
++ "get-default-filter", G_TYPE_FROM_CLASS (klass),
++ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
++ (GCallback) wp_filters_api_get_default_filter,
++ NULL, NULL, NULL,
++ G_TYPE_INT, 1, G_TYPE_STRING);
++
+ signals[SIGNAL_CHANGED] = g_signal_new (
+ "changed", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
@@ -1117,62 +1163,8 @@ index 2883a021..3d486be8 100644
lua_typename(L, lua_type(L, -1)));
break;
}
-diff --git a/src/config/main.lua.d/40-device-defaults.lua b/src/config/main.lua.d/40-device-defaults.lua
-index 19202914..b87eec51 100644
---- a/src/config/main.lua.d/40-device-defaults.lua
-+++ b/src/config/main.lua.d/40-device-defaults.lua
-@@ -10,15 +10,6 @@ device_defaults.properties = {
- -- the default volumes to apply to ACP device nodes, in the linear scale
- --["default-volume"] = 0.064,
- --["default-input-volume"] = 1.0,
--
-- -- Whether to auto-switch to echo cancel sink and source nodes or not
-- ["auto-echo-cancel"] = true,
--
-- -- Sets the default echo-cancel-sink node name to automatically switch to
-- ["echo-cancel-sink-name"] = "echo-cancel-sink",
--
-- -- Sets the default echo-cancel-source node name to automatically switch to
-- ["echo-cancel-source-name"] = "echo-cancel-source",
- }
-
- -- Sets persistent device profiles that should never change when wireplumber is
-@@ -48,13 +39,13 @@ device_defaults.profile_priorities = {
- },
- -- lower the index higher the priority
- priorities = {
-- -- "a2dp-sink-sbc",
-- -- "a2dp-sink-aptx_ll",
-- -- "a2dp-sink-aptx",
-- -- "a2dp-sink-aptx_hd",
-- -- "a2dp-sink-ldac",
-- -- "a2dp-sink-aac",
-- -- "a2dp-sink-sbc_xq",
-+ "a2dp-sink-aptx_ll",
-+ "a2dp-sink-aptx",
-+ "a2dp-sink-aptx_hd",
-+ "a2dp-sink-ldac",
-+ "a2dp-sink-aac",
-+ "a2dp-sink-sbc",
-+ "a2dp-sink-sbc_xq",
- }
- },
- }
-diff --git a/src/config/main.lua.d/40-stream-defaults.lua b/src/config/main.lua.d/40-stream-defaults.lua
-index b869099b..d25aab0d 100644
---- a/src/config/main.lua.d/40-stream-defaults.lua
-+++ b/src/config/main.lua.d/40-stream-defaults.lua
-@@ -6,7 +6,7 @@ stream_defaults.properties = {
- ["restore-props"] = true,
-
- -- whether to restore the last stream target or not
-- ["restore-target"] = true,
-+ ["restore-target"] = false,
-
- -- the default channel volume for new streams whose props were never saved
- -- previously. This is only used if "restore-props" is set to true.
diff --git a/src/config/policy.lua.d/10-default-policy.lua b/src/config/policy.lua.d/10-default-policy.lua
-index 83d0a3b2..412d47a8 100644
+index 83d0a3b2..d3621a73 100644
--- a/src/config/policy.lua.d/10-default-policy.lua
+++ b/src/config/policy.lua.d/10-default-policy.lua
@@ -12,6 +12,9 @@ default_policy.policy = {
@@ -1180,7 +1172,7 @@ index 83d0a3b2..412d47a8 100644
["filter.forward-format"] = false,
+ -- Whether to enable smart filter policy or not (experimental feature)
-+ ["filter.smart"] = true,
++ ["filter.smart"] = false,
+
-- Set to 'true' to disable channel splitting & merging on nodes and enable
-- passthrough of audio in the same format as the format of the device.
@@ -1200,10 +1192,10 @@ index 83d0a3b2..412d47a8 100644
diff --git a/src/config/policy.lua.d/30-filters-config.lua b/src/config/policy.lua.d/30-filters-config.lua
new file mode 100644
-index 00000000..8e8725fc
+index 00000000..76aecad0
--- /dev/null
+++ b/src/config/policy.lua.d/30-filters-config.lua
-@@ -0,0 +1,80 @@
+@@ -0,0 +1,73 @@
+-- The smart filter policy configuration.
+-- You need to enable "filter.smart" in 10-default-policy.lua
+--
@@ -1265,31 +1257,24 @@ index 00000000..8e8725fc
+ }
+ },
+
-+ -- The filter targets
++ -- The target node properties (any node properties can be defined)
+ ["targets"] = {
+ ["speakers"] = {
-+ ["exclusive"] = false,
-+ ["props"] = {
-+ ["media.class"] = "Audio/Sink",
-+ ["alsa.card_name"] = "sof-nau8821-max",
-+ ["device.profile.description"] = "Speaker",
-+ }
++ ["media.class"] = "Audio/Sink",
++ ["alsa.card_name"] = "my-speakers-card-name",
+ },
+ ["microphone"] = {
-+ ["exclusive"] = false,
-+ ["props"] = {
-+ ["media.class"] = "Audio/Source",
-+ ["alsa.card_name"] = "sof-nau8821-max",
-+ }
++ ["media.class"] = "Audio/Source",
++ ["alsa.card_name"] = "my-microphone-card-name",
+ }
+ }
+}
diff --git a/src/scripts/filters-metadata.lua b/src/scripts/filters-metadata.lua
new file mode 100644
-index 00000000..49b4d0e8
+index 00000000..04e3e6c6
--- /dev/null
+++ b/src/scripts/filters-metadata.lua
-@@ -0,0 +1,42 @@
+@@ -0,0 +1,39 @@
+-- WirePlumber
+--
+-- Copyright © 2023 Collabora Ltd.
@@ -1322,87 +1307,15 @@ index 00000000..49b4d0e8
+
+ -- Set targets metadata
+ local targets = {}
-+ for name, value in pairs(config["targets"]) do
-+ targets[name] = Json.Object {
-+ exclusive = value.exclusive and true or false,
-+ props = Json.Object (value.props)
-+ }
++ for name, props in pairs(config["targets"]) do
++ targets[name] = Json.Object (props)
+ end
+ local targets_json = Json.Object (targets)
+ m:set (0, "filters.configured.targets", "Spa:String:JSON",
+ targets_json:to_string())
+end)
-diff --git a/src/scripts/policy-device-profile.lua b/src/scripts/policy-device-profile.lua
-index af10f9b7..8d3a6d7e 100644
---- a/src/scripts/policy-device-profile.lua
-+++ b/src/scripts/policy-device-profile.lua
-@@ -34,12 +34,12 @@ createIntrestObjects(self.config.persistent)
- createIntrestObjects(self.config.priorities)
-
- -- Checks whether a device profile is persistent or not
--function isProfilePersistent(device_props, profile_name)
-- for _, p in ipairs(self.config.persistent or {}) do
-+function isProfilePersistent (device_props, profile_name)
-+ for _, p in ipairs (self.config.persistent or {}) do
- if p.profile_names then
-- for _, interest in ipairs(p.interests) do
-- if interest:matches(device_props) then
-- for _, pn in ipairs(p.profile_names) do
-+ for _, interest in ipairs (p.interests) do
-+ if interest:matches (device_props) then
-+ for _, pn in ipairs (p.profile_names) do
- if pn == profile_name then
- return true
- end
-@@ -72,7 +72,7 @@ function setDeviceProfile (device, dev_id, dev_name, profile)
- index = profile.index,
- }
- Log.info ("Setting profile " .. profile.name .. " on " .. dev_name)
-- device:set_param("Profile", param)
-+ device:set_param ("Profile", param)
- end
-
- function findDefaultProfile (device)
-@@ -85,8 +85,8 @@ function findDefaultProfile (device)
- return nil
- end
-
-- for p in device:iterate_params("EnumProfile") do
-- local profile = parseParam(p, "EnumProfile")
-+ for p in device:iterate_params ("EnumProfile") do
-+ local profile = parseParam (p, "EnumProfile")
- if profile.name == def_name then
- return profile
- end
-@@ -189,7 +189,7 @@ function handleProfiles (device, new_device)
- isProfilePersistent (device.properties, self.active_profiles[dev_id].name) and
- def_profile ~= nil and
- self.active_profiles[dev_id].name == def_profile.name
-- then
-+ then
- local active_profile = self.active_profiles[dev_id].name
- Log.info ("Device profile " .. active_profile .. " is persistent for " .. dev_name)
- return
-@@ -233,14 +233,14 @@ self.om = ObjectManager {
- }
- }
-
--self.om:connect("object-added", function (_, device)
-+self.om:connect ("object-added", function(_, device)
- device:connect ("params-changed", onDeviceParamsChanged)
- handleProfiles (device, true)
- end)
-
--self.om:connect("object-removed", function (_, device)
-+self.om:connect ("object-removed", function(_, device)
- local dev_id = device["bound-id"]
- self.active_profiles[dev_id] = nil
- end)
-
--self.om:activate()
-+self.om:activate ()
diff --git a/src/scripts/policy-node.lua b/src/scripts/policy-node.lua
-index 99ad8473..035c3006 100644
+index 99ad8473..f249f343 100644
--- a/src/scripts/policy-node.lua
+++ b/src/scripts/policy-node.lua
@@ -18,6 +18,7 @@ self.scanning = false
@@ -1523,42 +1436,45 @@ index 99ad8473..035c3006 100644
-- Determine if we can handle item by this policy
if endpoints_om:get_n_objects () > 0 and
si_props["item.factory.name"] == "si-audio-adapter" then
-@@ -652,6 +718,34 @@ function checkFollowDefault (si, si_target, has_node_defined_target)
+@@ -652,6 +718,37 @@ function checkFollowDefault (si, si_target, has_node_defined_target)
end
end
+function findFilterTarget (si)
++ local node = si:get_associated_proxy ("node")
++ local direction = getTargetDirection (si.properties)
++ local link_group = node.properties["node.link-group"]
++ local target_id = -1
++
+ -- always return nil if filters API is not loaded
+ if self.filters_api == nil then
-+ return nil, false
++ return nil
+ end
+
-+ -- always return nil if this is not a filter
-+ local node = si:get_associated_proxy ("node")
-+ local link_group = node.properties["node.link-group"]
+ if link_group == nil then
-+ return nil, false
++ -- if this is a client stream that is not a filter, link it to the highest
++ -- priority filter that does not have a group, if any.
++ target_id = self.filters_api:call("get-default-filter", direction)
++ else
++ -- if this is a filter, get its target
++ target_id = self.filters_api:call("get-filter-target",
++ direction, link_group)
+ end
+
-+ -- get the filter target
-+ local direction = getTargetDirection (si.properties)
-+ local target_json = self.filters_api:call("get-filter-target", direction, link_group)
-+ if target_json == nil then
-+ return nil, false
++ if (target_id == -1) then
++ return nil
+ end
-+ target = target_json:parse()
+
-+ Log.info (".. filter target ID is " .. tostring(target.bound_id) ..
-+ " (" .. tostring (target.exclusive) .. ")")
++ Log.info (".. filter target ID is " .. tostring(target_id))
+ return linkables_om:lookup {
-+ Constraint { "node.id", "=", tostring(target.bound_id) }
-+ }, target.exclusive
++ Constraint { "node.id", "=", tostring(target_id) }
++ }
+end
+
function handleLinkable (si)
if checkPending () then
return
-@@ -683,11 +777,23 @@ function handleLinkable (si)
+@@ -683,11 +780,19 @@ function handleLinkable (si)
local si_target, has_defined_target, has_node_defined_target
= findDefinedTarget(si_props)
local can_passthrough = si_target and canPassthrough(si, si_target)
@@ -1569,11 +1485,7 @@ index 99ad8473..035c3006 100644
+ -- find filter target (always returns nil for non filters)
+ if si_target == nil then
-+ si_target, exclusive = findFilterTarget(si)
-+ -- don't fallback if filter target is not found and exclusive is true
-+ if si_target == nil and exclusive then
-+ return
-+ end
++ si_target = findFilterTarget(si)
+ local can_passthrough = si_target and canPassthrough(si, si_target)
+ if si_target and si_must_passthrough and not can_passthrough then
+ si_target = nil
@@ -1583,7 +1495,7 @@ index 99ad8473..035c3006 100644
-- if the client has seen a target that we haven't yet prepared, schedule
-- a rescan one more time and hope for the best
local si_id = si.id
-@@ -876,6 +982,17 @@ if config.follow and default_nodes ~= nil then
+@@ -876,6 +981,17 @@ if config.follow and default_nodes ~= nil then
end)
end
@@ -1601,3 +1513,1301 @@ index 99ad8473..035c3006 100644
-- listen for target.node metadata changes if config.move is enabled
if config.move then
metadata_om:connect("object-added", function (om, metadata)
+--
+2.42.0
+
+
+From bea7195a12ba1014f62e40f80c0f2e127a1aaa2e Mon Sep 17 00:00:00 2001
+From: Julian Bouzas
+Date: Thu, 23 Mar 2023 09:26:45 -0400
+Subject: [PATCH 03/11] config: do not restore stream target by default
+
+---
+ src/config/main.lua.d/40-stream-defaults.lua | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/config/main.lua.d/40-stream-defaults.lua b/src/config/main.lua.d/40-stream-defaults.lua
+index b869099b..d25aab0d 100644
+--- a/src/config/main.lua.d/40-stream-defaults.lua
++++ b/src/config/main.lua.d/40-stream-defaults.lua
+@@ -6,7 +6,7 @@ stream_defaults.properties = {
+ ["restore-props"] = true,
+
+ -- whether to restore the last stream target or not
+- ["restore-target"] = true,
++ ["restore-target"] = false,
+
+ -- the default channel volume for new streams whose props were never saved
+ -- previously. This is only used if "restore-props" is set to true.
+--
+2.42.0
+
+
+From f4d88774670d561b3a2d37c0d6534b204cdcb14f Mon Sep 17 00:00:00 2001
+From: Julian Bouzas
+Date: Thu, 23 Mar 2023 09:41:23 -0400
+Subject: [PATCH 04/11] config: enable smart filter policy
+
+---
+ src/config/policy.lua.d/10-default-policy.lua | 2 +-
+ src/config/policy.lua.d/30-filters-config.lua | 5 +++--
+ 2 files changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/src/config/policy.lua.d/10-default-policy.lua b/src/config/policy.lua.d/10-default-policy.lua
+index d3621a73..412d47a8 100644
+--- a/src/config/policy.lua.d/10-default-policy.lua
++++ b/src/config/policy.lua.d/10-default-policy.lua
+@@ -13,7 +13,7 @@ default_policy.policy = {
+ ["filter.forward-format"] = false,
+
+ -- Whether to enable smart filter policy or not (experimental feature)
+- ["filter.smart"] = false,
++ ["filter.smart"] = true,
+
+ -- Set to 'true' to disable channel splitting & merging on nodes and enable
+ -- passthrough of audio in the same format as the format of the device.
+diff --git a/src/config/policy.lua.d/30-filters-config.lua b/src/config/policy.lua.d/30-filters-config.lua
+index 76aecad0..8d919fb7 100644
+--- a/src/config/policy.lua.d/30-filters-config.lua
++++ b/src/config/policy.lua.d/30-filters-config.lua
+@@ -63,11 +63,12 @@ default_policy.filters_metadata = {
+ ["targets"] = {
+ ["speakers"] = {
+ ["media.class"] = "Audio/Sink",
+- ["alsa.card_name"] = "my-speakers-card-name",
++ ["alsa.card_name"] = "acp5x",
++ ["device.profile.description"] = "Speaker",
+ },
+ ["microphone"] = {
+ ["media.class"] = "Audio/Source",
+- ["alsa.card_name"] = "my-microphone-card-name",
++ ["alsa.card_name"] = "acp5x",
+ }
+ }
+ }
+--
+2.42.0
+
+
+From 30d26697a83ce11c4a2343c0ad4ddb113e64f72b Mon Sep 17 00:00:00 2001
+From: Ashok Sidipotu
+Date: Wed, 12 Jul 2023 10:17:37 +0530
+Subject: [PATCH 05/11] policy-device-profile.lua: introduce user profile
+ priority list
+
+---
+ src/config/main.lua.d/40-device-defaults.lua | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/src/config/main.lua.d/40-device-defaults.lua b/src/config/main.lua.d/40-device-defaults.lua
+index 91c4e189..b87eec51 100644
+--- a/src/config/main.lua.d/40-device-defaults.lua
++++ b/src/config/main.lua.d/40-device-defaults.lua
+@@ -39,13 +39,13 @@ device_defaults.profile_priorities = {
+ },
+ -- lower the index higher the priority
+ priorities = {
+- -- "a2dp-sink-sbc",
+- -- "a2dp-sink-aptx_ll",
+- -- "a2dp-sink-aptx",
+- -- "a2dp-sink-aptx_hd",
+- -- "a2dp-sink-ldac",
+- -- "a2dp-sink-aac",
+- -- "a2dp-sink-sbc_xq",
++ "a2dp-sink-aptx_ll",
++ "a2dp-sink-aptx",
++ "a2dp-sink-aptx_hd",
++ "a2dp-sink-ldac",
++ "a2dp-sink-aac",
++ "a2dp-sink-sbc",
++ "a2dp-sink-sbc_xq",
+ }
+ },
+ }
+--
+2.42.0
+
+
+From 4c6762c41a0d8f6298e2f35cea42a86ea3ef8ff9 Mon Sep 17 00:00:00 2001
+From: Julian Bouzas
+Date: Fri, 3 Nov 2023 09:24:59 -0400
+Subject: [PATCH 06/11] m-filters-api: remove get-default-filter API
+
+This was redundant as you can get the default filter by calling
+'get-filter-from-target' using the default target. The policy logic
+should not change.
+---
+ modules/module-filters-api.c | 34 ----------------------------------
+ src/scripts/policy-node.lua | 17 +++++++----------
+ 2 files changed, 7 insertions(+), 44 deletions(-)
+
+diff --git a/modules/module-filters-api.c b/modules/module-filters-api.c
+index 32c67c85..d7dc781a 100644
+--- a/modules/module-filters-api.c
++++ b/modules/module-filters-api.c
+@@ -230,33 +230,6 @@ wp_filters_api_get_filter_from_target (WpFiltersApi * self,
+ return res;
+ }
+
+-static gint
+-wp_filters_api_get_default_filter (WpFiltersApi * self, const gchar *direction)
+-{
+- WpDirection dir = WP_DIRECTION_INPUT;
+- GList *filters;
+-
+- g_return_val_if_fail (direction, -1);
+-
+- /* Get the filters for the given direction */
+- if (g_str_equal (direction, "output") || g_str_equal (direction, "Output"))
+- dir = WP_DIRECTION_OUTPUT;
+- filters = self->filters[dir];
+-
+- /* The default filter is the highest priority filter without target, this is
+- * the first filer that is enabled because the list is sorted by priority */
+- while (filters) {
+- Filter *f = (Filter *) filters->data;
+- if (f->enabled && !f->target)
+- return wp_proxy_get_bound_id (WP_PROXY (f->node));
+-
+- /* Advance */
+- filters = g_list_next (filters);
+- }
+-
+- return -1;
+-}
+-
+ static void
+ sync_changed (WpCore * core, GAsyncResult * res, WpFiltersApi * self)
+ {
+@@ -881,13 +854,6 @@ wp_filters_api_class_init (WpFiltersApiClass * klass)
+ NULL, NULL, NULL,
+ G_TYPE_INT, 2, G_TYPE_STRING, G_TYPE_INT);
+
+- signals[ACTION_GET_DEFAULT_FILTER] = g_signal_new_class_handler (
+- "get-default-filter", G_TYPE_FROM_CLASS (klass),
+- G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+- (GCallback) wp_filters_api_get_default_filter,
+- NULL, NULL, NULL,
+- G_TYPE_INT, 1, G_TYPE_STRING);
+-
+ signals[SIGNAL_CHANGED] = g_signal_new (
+ "changed", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
+diff --git a/src/scripts/policy-node.lua b/src/scripts/policy-node.lua
+index f249f343..c5a15ec6 100644
+--- a/src/scripts/policy-node.lua
++++ b/src/scripts/policy-node.lua
+@@ -719,9 +719,6 @@ function checkFollowDefault (si, si_target, has_node_defined_target)
+ end
+
+ function findFilterTarget (si)
+- local node = si:get_associated_proxy ("node")
+- local direction = getTargetDirection (si.properties)
+- local link_group = node.properties["node.link-group"]
+ local target_id = -1
+
+ -- always return nil if filters API is not loaded
+@@ -729,16 +726,16 @@ function findFilterTarget (si)
+ return nil
+ end
+
++ -- always return nil if this is not a filter
++ local node = si:get_associated_proxy ("node")
++ local link_group = node.properties["node.link-group"]
+ if link_group == nil then
+- -- if this is a client stream that is not a filter, link it to the highest
+- -- priority filter that does not have a group, if any.
+- target_id = self.filters_api:call("get-default-filter", direction)
+- else
+- -- if this is a filter, get its target
+- target_id = self.filters_api:call("get-filter-target",
+- direction, link_group)
++ return nil
+ end
+
++ -- get the filter target
++ local direction = getTargetDirection (si.properties)
++ target_id = self.filters_api:call("get-filter-target", direction, link_group)
+ if (target_id == -1) then
+ return nil
+ end
+--
+2.42.0
+
+
+From 1acb97e5606dfd842a71c9a2de520ee665f17fd0 Mon Sep 17 00:00:00 2001
+From: Julian Bouzas
+Date: Fri, 3 Nov 2023 11:44:57 -0400
+Subject: [PATCH 07/11] m-filters-api: add support for exclusive targets
+
+Filters whose target are exclusive won't be linked to the default device if the
+target does not exist.
+---
+ modules/module-filters-api.c | 127 ++++++++++++------
+ src/config/policy.lua.d/30-filters-config.lua | 18 ++-
+ src/scripts/filters-metadata.lua | 7 +-
+ src/scripts/policy-node.lua | 26 ++--
+ 4 files changed, 120 insertions(+), 58 deletions(-)
+
+diff --git a/modules/module-filters-api.c b/modules/module-filters-api.c
+index d7dc781a..8852a6c5 100644
+--- a/modules/module-filters-api.c
++++ b/modules/module-filters-api.c
+@@ -49,6 +49,12 @@ struct _Filter {
+ };
+ typedef struct _Filter Filter;
+
++struct _Target {
++ gboolean exclusive;
++ WpNode *node;
++};
++typedef struct _Target Target;
++
+ static guint
+ get_filter_priority (const gchar *link_group)
+ {
+@@ -87,6 +93,22 @@ filter_free (Filter *f)
+ g_free (f);
+ }
+
++static Target *
++target_new (gboolean exclusive, WpNode *node)
++{
++ Target *t = g_malloc0 (sizeof (Target));
++ t->exclusive = exclusive;
++ t->node = node ? g_object_ref (node) : NULL;
++ return t;
++}
++
++static void
++target_free (Target *t)
++{
++ g_clear_object (&t->node);
++ g_free (t);
++}
++
+ static gint
+ filter_equal_func (const Filter *f, const gchar *link_group)
+ {
+@@ -133,16 +155,18 @@ wp_filters_api_is_filter_enabled (WpFiltersApi * self, const gchar *direction,
+ return found->enabled;
+ }
+
+-static gint
++static WpSpaJson *
+ wp_filters_api_get_filter_target (WpFiltersApi * self, const gchar *direction,
+ const gchar *link_group)
+ {
+ WpDirection dir = WP_DIRECTION_INPUT;
+ GList *filters;
+ Filter *found;
++ g_autoptr (WpSpaJson) res = wp_spa_json_new_object (
++ "exclusive", "b", FALSE, "bound_id", "i", -1, NULL);
+
+- g_return_val_if_fail (direction, -1);
+- g_return_val_if_fail (link_group, -1);
++ g_return_val_if_fail (direction, g_steal_pointer (&res));
++ g_return_val_if_fail (link_group, g_steal_pointer (&res));
+
+ /* Get the filters for the given direction */
+ if (g_str_equal (direction, "output") || g_str_equal (direction, "Output"))
+@@ -153,10 +177,10 @@ wp_filters_api_get_filter_target (WpFiltersApi * self, const gchar *direction,
+ filters = g_list_find_custom (filters, link_group,
+ (GCompareFunc) filter_equal_func);
+ if (!filters)
+- return -1;
++ return g_steal_pointer (&res);
+ found = filters->data;
+ if (!found->enabled)
+- return -1;
++ return g_steal_pointer (&res);
+
+ /* Return the previous filter with matching target that is enabled */
+ while ((filters = g_list_previous (filters))) {
+@@ -164,18 +188,27 @@ wp_filters_api_get_filter_target (WpFiltersApi * self, const gchar *direction,
+ if ((prev->target == found->target ||
+ (prev->target && found->target &&
+ g_str_equal (prev->target, found->target))) &&
+- prev->enabled)
+- return wp_proxy_get_bound_id (WP_PROXY (prev->node));
++ prev->enabled) {
++ return wp_spa_json_new_object (
++ "exclusive", "b", FALSE,
++ "bound_id", "i", wp_proxy_get_bound_id (WP_PROXY (prev->node)),
++ NULL);
++ }
+ }
+
+ /* Find the target */
+ if (found->target) {
+- WpNode *node = g_hash_table_lookup (self->targets, found->target);
+- if (node)
+- return wp_proxy_get_bound_id (WP_PROXY (node));
++ Target *t = g_hash_table_lookup (self->targets, found->target);
++ if (t) {
++ return wp_spa_json_new_object (
++ "exclusive", "b", t->exclusive,
++ "bound_id", "i",
++ t->node ? (gint)wp_proxy_get_bound_id (WP_PROXY (t->node)) : -1,
++ NULL);
++ }
+ }
+
+- return -1;
++ return g_steal_pointer (&res);
+ }
+
+ static gint
+@@ -198,12 +231,17 @@ wp_filters_api_get_filter_from_target (WpFiltersApi * self,
+ /* Find the first target matching target_id */
+ while (filters) {
+ Filter *f = (Filter *) filters->data;
+- gint f_target_id = wp_filters_api_get_filter_target (self, direction,
+- f->link_group);
+- if (f_target_id == target_id && f->enabled) {
+- target = f->target;
+- found = TRUE;
+- break;
++ if (f->enabled) {
++ gint f_target_id;
++ g_autoptr (WpSpaJson) f_target = wp_filters_api_get_filter_target (self,
++ direction, f->link_group);
++ if (f_target && wp_spa_json_is_object (f_target) &&
++ wp_spa_json_object_get (f_target, "bound_id", "i", &f_target_id, NULL)
++ && f_target_id == target_id) {
++ target = f->target;
++ found = TRUE;
++ break;
++ }
+ }
+
+ /* Advance */
+@@ -323,9 +361,11 @@ reevaluate_targets (WpFiltersApi *self)
+ for (; wp_iterator_next (it, &item); g_value_unset (&item)) {
+ WpSpaJson *j = g_value_get_boxed (&item);
+ g_autofree gchar *key = NULL;
+- WpSpaJson *props;
+- g_autoptr (WpNode) target = NULL;
+- WpNode *curr_target;
++ WpSpaJson *value;
++ gboolean exclusive = FALSE;
++ g_autoptr (WpSpaJson) props = NULL;
++ g_autoptr (WpNode) target_node = NULL;
++ Target *curr_target;
+
+ key = wp_spa_json_parse_string (j);
+ g_value_unset (&item);
+@@ -334,27 +374,36 @@ reevaluate_targets (WpFiltersApi *self)
+ "Could not get valid key-value pairs from target object");
+ break;
+ }
+- props = g_value_get_boxed (&item);
++ value = g_value_get_boxed (&item);
++ if (!value || !wp_spa_json_is_object (value)) {
++ wp_warning_object (self, "Target value must be a JSON object");
++ break;
++ }
+
+- /* Get current target */
+- curr_target = g_hash_table_lookup (self->targets, key);
++ /* Get exclusive */
++ wp_spa_json_object_get (value, "exclusive", "b", &exclusive, NULL);
+
+- /* Find the node and insert it into the table if found */
+- target = find_target_node (self, props);
+- if (target) {
+- /* Check if the target changed */
+- if (curr_target) {
+- guint32 target_bound_id = wp_proxy_get_bound_id (WP_PROXY (target));
+- guint32 curr_bound_id = wp_proxy_get_bound_id (WP_PROXY (curr_target));
+- if (target_bound_id != curr_bound_id)
+- changed = TRUE;
+- }
++ /* Get target node */
++ wp_spa_json_object_get (value, "props", "J", &props, NULL);
++ if (props)
++ target_node = find_target_node (self, props);
+
+- g_hash_table_insert (self->targets, g_strdup (key),
+- g_steal_pointer (&target));
+- } else {
+- if (curr_target)
++ /* Update values if target exists in the table, otherwise add new target */
++ curr_target = g_hash_table_lookup (self->targets, key);
++ if (curr_target) {
++ if (curr_target->exclusive != exclusive) {
++ curr_target->exclusive = exclusive;
++ changed = TRUE;
++ }
++ if (curr_target->node != target_node) {
++ g_clear_object (&curr_target->node);
++ curr_target->node = g_steal_pointer (&target_node);
+ changed = TRUE;
++ }
++ } else {
++ g_hash_table_insert (self->targets, g_strdup (key),
++ target_new (exclusive, target_node));
++ changed = TRUE;
+ }
+ }
+
+@@ -790,7 +839,7 @@ wp_filters_api_enable (WpPlugin * plugin, WpTransition * transition)
+ g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (self));
+
+ self->targets = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
+- g_object_unref);
++ (GDestroyNotify) target_free);
+
+ /* Create the metadata object manager */
+ self->metadata_om = wp_object_manager_new ();
+@@ -845,7 +894,7 @@ wp_filters_api_class_init (WpFiltersApiClass * klass)
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ (GCallback) wp_filters_api_get_filter_target,
+ NULL, NULL, NULL,
+- G_TYPE_INT, 2, G_TYPE_STRING, G_TYPE_STRING);
++ WP_TYPE_SPA_JSON, 2, G_TYPE_STRING, G_TYPE_STRING);
+
+ signals[ACTION_GET_FILTER_FROM_TARGET] = g_signal_new_class_handler (
+ "get-filter-from-target", G_TYPE_FROM_CLASS (klass),
+diff --git a/src/config/policy.lua.d/30-filters-config.lua b/src/config/policy.lua.d/30-filters-config.lua
+index 8d919fb7..bf4b8d75 100644
+--- a/src/config/policy.lua.d/30-filters-config.lua
++++ b/src/config/policy.lua.d/30-filters-config.lua
+@@ -59,16 +59,22 @@ default_policy.filters_metadata = {
+ }
+ },
+
+- -- The target node properties (any node properties can be defined)
++ -- The filter targets
+ ["targets"] = {
+ ["speakers"] = {
+- ["media.class"] = "Audio/Sink",
+- ["alsa.card_name"] = "acp5x",
+- ["device.profile.description"] = "Speaker",
++ ["exclusive"] = false,
++ ["props"] = {
++ ["media.class"] = "Audio/Sink",
++ ["alsa.card_name"] = "acp5x",
++ ["device.profile.description"] = "Speaker",
++ }
+ },
+ ["microphone"] = {
+- ["media.class"] = "Audio/Source",
+- ["alsa.card_name"] = "acp5x",
++ ["exclusive"] = false,
++ ["props"] = {
++ ["media.class"] = "Audio/Source",
++ ["alsa.card_name"] = "acp5x",
++ }
+ }
+ }
+ }
+diff --git a/src/scripts/filters-metadata.lua b/src/scripts/filters-metadata.lua
+index 04e3e6c6..49b4d0e8 100644
+--- a/src/scripts/filters-metadata.lua
++++ b/src/scripts/filters-metadata.lua
+@@ -30,8 +30,11 @@ f_metadata:activate(Features.ALL, function (m, e)
+
+ -- Set targets metadata
+ local targets = {}
+- for name, props in pairs(config["targets"]) do
+- targets[name] = Json.Object (props)
++ for name, value in pairs(config["targets"]) do
++ targets[name] = Json.Object {
++ exclusive = value.exclusive and true or false,
++ props = Json.Object (value.props)
++ }
+ end
+ local targets_json = Json.Object (targets)
+ m:set (0, "filters.configured.targets", "Spa:String:JSON",
+diff --git a/src/scripts/policy-node.lua b/src/scripts/policy-node.lua
+index c5a15ec6..035c3006 100644
+--- a/src/scripts/policy-node.lua
++++ b/src/scripts/policy-node.lua
+@@ -719,31 +719,31 @@ function checkFollowDefault (si, si_target, has_node_defined_target)
+ end
+
+ function findFilterTarget (si)
+- local target_id = -1
+-
+ -- always return nil if filters API is not loaded
+ if self.filters_api == nil then
+- return nil
++ return nil, false
+ end
+
+ -- always return nil if this is not a filter
+ local node = si:get_associated_proxy ("node")
+ local link_group = node.properties["node.link-group"]
+ if link_group == nil then
+- return nil
++ return nil, false
+ end
+
+ -- get the filter target
+ local direction = getTargetDirection (si.properties)
+- target_id = self.filters_api:call("get-filter-target", direction, link_group)
+- if (target_id == -1) then
+- return nil
++ local target_json = self.filters_api:call("get-filter-target", direction, link_group)
++ if target_json == nil then
++ return nil, false
+ end
++ target = target_json:parse()
+
+- Log.info (".. filter target ID is " .. tostring(target_id))
++ Log.info (".. filter target ID is " .. tostring(target.bound_id) ..
++ " (" .. tostring (target.exclusive) .. ")")
+ return linkables_om:lookup {
+- Constraint { "node.id", "=", tostring(target_id) }
+- }
++ Constraint { "node.id", "=", tostring(target.bound_id) }
++ }, target.exclusive
+ end
+
+ function handleLinkable (si)
+@@ -783,7 +783,11 @@ function handleLinkable (si)
+
+ -- find filter target (always returns nil for non filters)
+ if si_target == nil then
+- si_target = findFilterTarget(si)
++ si_target, exclusive = findFilterTarget(si)
++ -- don't fallback if filter target is not found and exclusive is true
++ if si_target == nil and exclusive then
++ return
++ end
+ local can_passthrough = si_target and canPassthrough(si, si_target)
+ if si_target and si_must_passthrough and not can_passthrough then
+ si_target = nil
+--
+2.42.0
+
+
+From 0010f03fafa2841f7618dad4b609466b6dad11c7 Mon Sep 17 00:00:00 2001
+From: Julian Bouzas
+Date: Mon, 6 Nov 2023 14:33:34 -0500
+Subject: [PATCH 08/11] policy-bluetooth: remove application names array and
+ use BT loopback filter
+
+Uses a BT loopback filter to know when an application wants to capture audio
+from the current BT device. If the BT loopback filter is used, wireplumber will
+automatically switch the device to HSP/HFP profile, otherwise the BT device
+profile is always set to A2DP.
+---
+ src/config/policy.lua.d/10-default-policy.lua | 10 --
+ src/config/policy.lua.d/30-filters-config.lua | 17 ++-
+ src/config/wireplumber.conf | 20 +++
+ src/scripts/policy-bluetooth.lua | 139 ++++++++++--------
+ 4 files changed, 110 insertions(+), 76 deletions(-)
+
+diff --git a/src/config/policy.lua.d/10-default-policy.lua b/src/config/policy.lua.d/10-default-policy.lua
+index 412d47a8..7d4ea77c 100644
+--- a/src/config/policy.lua.d/10-default-policy.lua
++++ b/src/config/policy.lua.d/10-default-policy.lua
+@@ -33,16 +33,6 @@ bluetooth_policy.policy = {
+
+ -- Whether to use headset profile in the presence of an input stream.
+ ["media-role.use-headset-profile"] = true,
+-
+- -- Application names correspond to application.name in stream properties.
+- -- Applications which do not set media.role but which should be considered
+- -- for role based profile switching can be specified here.
+- ["media-role.applications"] = {
+- "Firefox", "Chromium input", "Google Chrome input", "Brave input",
+- "Microsoft Edge input", "Vivaldi input", "ZOOM VoiceEngine",
+- "Telegram Desktop", "telegram-desktop", "linphone", "Mumble",
+- "WEBRTC VoiceEngine", "Skype", "Firefox Developer Edition",
+- },
+ }
+
+ dsp_policy = {}
+diff --git a/src/config/policy.lua.d/30-filters-config.lua b/src/config/policy.lua.d/30-filters-config.lua
+index bf4b8d75..88429cdc 100644
+--- a/src/config/policy.lua.d/30-filters-config.lua
++++ b/src/config/policy.lua.d/30-filters-config.lua
+@@ -33,11 +33,19 @@ default_policy.filters_metadata = {
+ },
+
+ -- Output filters (meant to be linked with Audio/Source device nodes)
++ {
++ ["stream-name"] = "virtual-bluetooth-source-in", -- loopback bluetooth capture
++ ["node-name"] = "virtual-bluetooth-source-out", -- loopback bluetooth source
++ ["direction"] = "output", -- can only be 'input' or 'output'
++ ["target"] = "bluetooth-source", -- if nil, the default node will be used as target
++ ["mode"] = "always", -- can be 'always', 'never', 'playback-only' or 'capture-only'
++ ["priority"] = 30,
++ },
+ {
+ ["stream-name"] = "input.virtual-source", -- loopback capture
+ ["node-name"] = "output.virtual-source", -- loopback source
+ ["direction"] = "output", -- can only be 'input' or 'output'
+- ["target"] = nil, -- if nil, the default node will be used as target
++ ["target"] = "microphone", -- if nil, the default node will be used as target
+ ["mode"] = "always", -- can be 'always', 'never', 'playback-only' or 'capture-only'
+ ["priority"] = 30,
+ },
+@@ -75,6 +83,13 @@ default_policy.filters_metadata = {
+ ["media.class"] = "Audio/Source",
+ ["alsa.card_name"] = "acp5x",
+ }
++ },
++ ["bluetooth-source"] = {
++ ["exclusive"] = true,
++ ["props"] = {
++ ["media.class"] = "Audio/Source",
++ ["device.api"] = "bluez5"
++ }
+ }
+ }
+ }
+diff --git a/src/config/wireplumber.conf b/src/config/wireplumber.conf
+index 85d7be12..4c9dd568 100644
+--- a/src/config/wireplumber.conf
++++ b/src/config/wireplumber.conf
+@@ -77,6 +77,26 @@ context.modules = [
+
+ # Provides factories to make SPA node objects.
+ { name = libpipewire-module-spa-node-factory }
++
++ # Virtual Bluetooth Source
++ {
++ name = libpipewire-module-loopback
++ args = {
++ capture.props = {
++ node.name = virtual-bluetooth-source-in
++ node.description = "Virtual Bluetooth Source In"
++ audio.position = [ MONO ]
++ stream.dont-remix = true
++ node.passive = true
++ }
++ playback.props = {
++ node.name = virtual-bluetooth-source-out
++ node.description = "Virtual Bluetooth Source Out"
++ audio.position = [ MONO ]
++ media.class = Audio/Source
++ }
++ }
++ }
+ ]
+
+ wireplumber.components = [
+diff --git a/src/scripts/policy-bluetooth.lua b/src/scripts/policy-bluetooth.lua
+index f8f69a14..7aecb8b0 100644
+--- a/src/scripts/policy-bluetooth.lua
++++ b/src/scripts/policy-bluetooth.lua
+@@ -26,7 +26,6 @@
+
+ local config = ...
+ local use_persistent_storage = config["use-persistent-storage"] or false
+-local applications = {}
+ local use_headset_profile = config["media-role.use-headset-profile"] or false
+ local profile_restore_timeout_msec = 2000
+
+@@ -41,17 +40,6 @@ local last_profiles = {}
+ local active_streams = {}
+ local previous_streams = {}
+
+-for _, value in ipairs(config["media-role.applications"] or {}) do
+- applications[value] = true
+-end
+-
+-metadata_om = ObjectManager {
+- Interest {
+- type = "metadata",
+- Constraint { "metadata.name", "=", "default" },
+- }
+-}
+-
+ devices_om = ObjectManager {
+ Interest {
+ type = "device",
+@@ -68,6 +56,16 @@ streams_om = ObjectManager {
+ }
+ }
+
++nodes_om = ObjectManager {
++ Interest {
++ type = "node",
++ Constraint { "node.name", "=", "virtual-bluetooth-source-out", type = "pw-global" },
++ Constraint { "media.class", "matches", "Audio/Source", type = "pw-global" },
++ }
++}
++
++links_om = ObjectManager { Interest { type = "link" } }
++
+ local function parseParam(param_to_parse, id)
+ local param = param_to_parse:parse()
+ if param.pod_type == "Object" and param.object_id == id then
+@@ -117,19 +115,6 @@ local function isSwitched(device)
+ return getSavedLastProfile(device) ~= nil
+ end
+
+-local function isBluez5AudioSink(sink_name)
+- if sink_name and string.find(sink_name, "bluez_output.") ~= nil then
+- return true
+- end
+- return false
+-end
+-
+-local function isBluez5DefaultAudioSink()
+- local metadata = metadata_om:lookup()
+- local default_audio_sink = metadata:find(0, "default.audio.sink")
+- return isBluez5AudioSink(default_audio_sink)
+-end
+-
+ local function findProfile(device, index, name)
+ for p in device:iterate_params("EnumProfile") do
+ local profile = parseParam(p, "EnumProfile")
+@@ -228,7 +213,6 @@ local function switchProfile()
+ end
+
+ local cur_profile_name = getCurrentProfile(device)
+- saveLastProfile(device, cur_profile_name)
+
+ _, index, name = findProfile(device, nil, cur_profile_name)
+ if hasProfileInputRoute(device, index) then
+@@ -251,6 +235,8 @@ local function switchProfile()
+ index = index
+ }
+
++ saveLastProfile(device, cur_profile_name)
++
+ Log.info("Setting profile of '"
+ .. device.properties["device.description"]
+ .. "' from: " .. cur_profile_name
+@@ -270,8 +256,6 @@ local function restoreProfile()
+ local profile_name = getSavedLastProfile(device)
+ local cur_profile_name = getCurrentProfile(device)
+
+- saveLastProfile(device, nil)
+-
+ if cur_profile_name then
+ Log.info("Setting saved headset profile to: " .. cur_profile_name)
+ saveHeadsetProfile(device, cur_profile_name)
+@@ -286,6 +270,8 @@ local function restoreProfile()
+ index = index
+ }
+
++ saveLastProfile(device, nil)
++
+ Log.info("Restoring profile of '"
+ .. device.properties["device.description"]
+ .. "' from: " .. cur_profile_name
+@@ -312,18 +298,14 @@ local function triggerRestoreProfile()
+ end)
+ end
+
+--- We consider a Stream of interest to have role Communication if it has
+--- media.role set to Communication in props or it is in our list of
+--- applications as these applications do not set media.role correctly or at
+--- all.
+-local function checkStreamStatus(stream)
+- local app_name = stream.properties["application.name"]
+- local stream_role = stream.properties["media.role"]
++function parseBool(var)
++ return var and (var:lower() == "true" or var == "1")
++end
+
+- if not (stream_role == "Communication" or applications[app_name]) then
+- return false
+- end
+- if not isBluez5DefaultAudioSink() then
++local function checkStreamStatus (stream)
++ -- Ignore monitor streams
++ local is_monitor = parseBool (stream.properties["stream.monitor"])
++ if is_monitor then
+ return false
+ end
+
+@@ -334,7 +316,25 @@ local function checkStreamStatus(stream)
+ return false
+ end
+
+- return true
++ -- Make sure the virtual BT filter node exists
++ local node = nodes_om:lookup ()
++ if node == nil then
++ return false
++ end
++
++ -- Check if the stream is linked to the bluetooth loopback filter
++ local stream_id = tonumber(stream["bound-id"])
++ local bt_out_id = tonumber(node["bound-id"])
++ for l in links_om:iterate() do
++ local p = l.properties
++ local out_id = tonumber(p["link.output.node"])
++ local in_id = tonumber(p["link.input.node"])
++ if in_id == stream_id and out_id == bt_out_id then
++ return true
++ end
++ end
++
++ return false
+ end
+
+ local function handleStream(stream)
+@@ -361,38 +361,47 @@ local function handleAllStreams()
+ end
+ end
+
+-streams_om:connect("object-added", function (_, stream)
+- stream:connect("state-changed", function (stream, old_state, cur_state)
+- handleStream(stream)
+- end)
+- stream:connect("params-changed", handleStream)
+- handleStream(stream)
+-end)
+-
+-streams_om:connect("object-removed", function (_, stream)
+- active_streams[stream["bound-id"]] = nil
+- previous_streams[stream["bound-id"]] = nil
+- triggerRestoreProfile()
+-end)
+-
+ devices_om:connect("object-added", function (_, device)
+ -- Devices are unswitched initially
+- if isSwitched(device) then
+- saveLastProfile(device, nil)
+- end
++ saveLastProfile(device, nil)
+ handleAllStreams()
+ end)
+
+-metadata_om:connect("object-added", function (_, metadata)
+- metadata:connect("changed", function (m, subject, key, t, value)
+- if (use_headset_profile and subject == 0 and key == "default.audio.sink"
+- and isBluez5AudioSink(value)) then
+- -- If bluez sink is set as default, rescan for active input streams
+- handleAllStreams()
++links_om:connect("object-added", function (_, link)
++ if handleAllStreams then
++ local p = link.properties
++ for stream in streams_om:iterate {
++ Constraint { "media.class", "matches", "Stream/Input/Audio", type = "pw-global" },
++ Constraint { "stream.monitor", "!", "true" }
++ } do
++ local in_id = tonumber(p["link.input.node"])
++ local stream_id = tonumber(stream["bound-id"])
++ if in_id == stream_id then
++ handleStream(stream)
++ end
+ end
+- end)
++ end
++end)
++
++links_om:connect("object-removed", function (_, link)
++ if handleAllStreams then
++ local p = link.properties
++ for stream in streams_om:iterate {
++ Constraint { "media.class", "matches", "Stream/Input/Audio", type = "pw-global" },
++ Constraint { "stream.monitor", "!", "true" }
++ } do
++ local in_id = tonumber(p["link.input.node"])
++ local stream_id = tonumber(stream["bound-id"])
++ if in_id == stream_id then
++ active_streams[stream["bound-id"]] = nil
++ previous_streams[stream["bound-id"]] = nil
++ triggerRestoreProfile()
++ end
++ end
++ end
+ end)
+
+-metadata_om:activate()
+ devices_om:activate()
+ streams_om:activate()
++nodes_om:activate()
++links_om:activate()
+--
+2.42.0
+
+
+From ae7cde6dd7c7660da5bbd07f27fe18a624c8c67d Mon Sep 17 00:00:00 2001
+From: Ethan Geller
+Date: Mon, 13 Nov 2023 22:10:05 -0800
+Subject: [PATCH 09/11] fix speaker tunings for galileo
+
+---
+ src/config/policy.lua.d/30-filters-config.lua | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/config/policy.lua.d/30-filters-config.lua b/src/config/policy.lua.d/30-filters-config.lua
+index 88429cdc..a4b617d8 100644
+--- a/src/config/policy.lua.d/30-filters-config.lua
++++ b/src/config/policy.lua.d/30-filters-config.lua
+@@ -73,7 +73,7 @@ default_policy.filters_metadata = {
+ ["exclusive"] = false,
+ ["props"] = {
+ ["media.class"] = "Audio/Sink",
+- ["alsa.card_name"] = "acp5x",
++ ["alsa.card_name"] = "sof-nau8821-max",
+ ["device.profile.description"] = "Speaker",
+ }
+ },
+--
+2.42.0
+
+
+From 0ed6dc783bcb4033fb82c0f9b3e2c26977c3e19e Mon Sep 17 00:00:00 2001
+From: Ethan Geller
+Date: Wed, 15 Nov 2023 14:32:56 -0800
+Subject: [PATCH 10/11] Revert "policy-bluetooth: remove application names
+ array and use BT loopback filter"
+
+This reverts commit 5a760629b6e81268383f32406119fbb4ac3a42b0.
+---
+ src/config/policy.lua.d/10-default-policy.lua | 10 ++
+ src/config/policy.lua.d/30-filters-config.lua | 17 +--
+ src/config/wireplumber.conf | 20 ---
+ src/scripts/policy-bluetooth.lua | 139 ++++++++----------
+ 4 files changed, 76 insertions(+), 110 deletions(-)
+
+diff --git a/src/config/policy.lua.d/10-default-policy.lua b/src/config/policy.lua.d/10-default-policy.lua
+index 7d4ea77c..412d47a8 100644
+--- a/src/config/policy.lua.d/10-default-policy.lua
++++ b/src/config/policy.lua.d/10-default-policy.lua
+@@ -33,6 +33,16 @@ bluetooth_policy.policy = {
+
+ -- Whether to use headset profile in the presence of an input stream.
+ ["media-role.use-headset-profile"] = true,
++
++ -- Application names correspond to application.name in stream properties.
++ -- Applications which do not set media.role but which should be considered
++ -- for role based profile switching can be specified here.
++ ["media-role.applications"] = {
++ "Firefox", "Chromium input", "Google Chrome input", "Brave input",
++ "Microsoft Edge input", "Vivaldi input", "ZOOM VoiceEngine",
++ "Telegram Desktop", "telegram-desktop", "linphone", "Mumble",
++ "WEBRTC VoiceEngine", "Skype", "Firefox Developer Edition",
++ },
+ }
+
+ dsp_policy = {}
+diff --git a/src/config/policy.lua.d/30-filters-config.lua b/src/config/policy.lua.d/30-filters-config.lua
+index a4b617d8..37badd80 100644
+--- a/src/config/policy.lua.d/30-filters-config.lua
++++ b/src/config/policy.lua.d/30-filters-config.lua
+@@ -33,19 +33,11 @@ default_policy.filters_metadata = {
+ },
+
+ -- Output filters (meant to be linked with Audio/Source device nodes)
+- {
+- ["stream-name"] = "virtual-bluetooth-source-in", -- loopback bluetooth capture
+- ["node-name"] = "virtual-bluetooth-source-out", -- loopback bluetooth source
+- ["direction"] = "output", -- can only be 'input' or 'output'
+- ["target"] = "bluetooth-source", -- if nil, the default node will be used as target
+- ["mode"] = "always", -- can be 'always', 'never', 'playback-only' or 'capture-only'
+- ["priority"] = 30,
+- },
+ {
+ ["stream-name"] = "input.virtual-source", -- loopback capture
+ ["node-name"] = "output.virtual-source", -- loopback source
+ ["direction"] = "output", -- can only be 'input' or 'output'
+- ["target"] = "microphone", -- if nil, the default node will be used as target
++ ["target"] = nil, -- if nil, the default node will be used as target
+ ["mode"] = "always", -- can be 'always', 'never', 'playback-only' or 'capture-only'
+ ["priority"] = 30,
+ },
+@@ -83,13 +75,6 @@ default_policy.filters_metadata = {
+ ["media.class"] = "Audio/Source",
+ ["alsa.card_name"] = "acp5x",
+ }
+- },
+- ["bluetooth-source"] = {
+- ["exclusive"] = true,
+- ["props"] = {
+- ["media.class"] = "Audio/Source",
+- ["device.api"] = "bluez5"
+- }
+ }
+ }
+ }
+diff --git a/src/config/wireplumber.conf b/src/config/wireplumber.conf
+index 4c9dd568..85d7be12 100644
+--- a/src/config/wireplumber.conf
++++ b/src/config/wireplumber.conf
+@@ -77,26 +77,6 @@ context.modules = [
+
+ # Provides factories to make SPA node objects.
+ { name = libpipewire-module-spa-node-factory }
+-
+- # Virtual Bluetooth Source
+- {
+- name = libpipewire-module-loopback
+- args = {
+- capture.props = {
+- node.name = virtual-bluetooth-source-in
+- node.description = "Virtual Bluetooth Source In"
+- audio.position = [ MONO ]
+- stream.dont-remix = true
+- node.passive = true
+- }
+- playback.props = {
+- node.name = virtual-bluetooth-source-out
+- node.description = "Virtual Bluetooth Source Out"
+- audio.position = [ MONO ]
+- media.class = Audio/Source
+- }
+- }
+- }
+ ]
+
+ wireplumber.components = [
+diff --git a/src/scripts/policy-bluetooth.lua b/src/scripts/policy-bluetooth.lua
+index 7aecb8b0..f8f69a14 100644
+--- a/src/scripts/policy-bluetooth.lua
++++ b/src/scripts/policy-bluetooth.lua
+@@ -26,6 +26,7 @@
+
+ local config = ...
+ local use_persistent_storage = config["use-persistent-storage"] or false
++local applications = {}
+ local use_headset_profile = config["media-role.use-headset-profile"] or false
+ local profile_restore_timeout_msec = 2000
+
+@@ -40,6 +41,17 @@ local last_profiles = {}
+ local active_streams = {}
+ local previous_streams = {}
+
++for _, value in ipairs(config["media-role.applications"] or {}) do
++ applications[value] = true
++end
++
++metadata_om = ObjectManager {
++ Interest {
++ type = "metadata",
++ Constraint { "metadata.name", "=", "default" },
++ }
++}
++
+ devices_om = ObjectManager {
+ Interest {
+ type = "device",
+@@ -56,16 +68,6 @@ streams_om = ObjectManager {
+ }
+ }
+
+-nodes_om = ObjectManager {
+- Interest {
+- type = "node",
+- Constraint { "node.name", "=", "virtual-bluetooth-source-out", type = "pw-global" },
+- Constraint { "media.class", "matches", "Audio/Source", type = "pw-global" },
+- }
+-}
+-
+-links_om = ObjectManager { Interest { type = "link" } }
+-
+ local function parseParam(param_to_parse, id)
+ local param = param_to_parse:parse()
+ if param.pod_type == "Object" and param.object_id == id then
+@@ -115,6 +117,19 @@ local function isSwitched(device)
+ return getSavedLastProfile(device) ~= nil
+ end
+
++local function isBluez5AudioSink(sink_name)
++ if sink_name and string.find(sink_name, "bluez_output.") ~= nil then
++ return true
++ end
++ return false
++end
++
++local function isBluez5DefaultAudioSink()
++ local metadata = metadata_om:lookup()
++ local default_audio_sink = metadata:find(0, "default.audio.sink")
++ return isBluez5AudioSink(default_audio_sink)
++end
++
+ local function findProfile(device, index, name)
+ for p in device:iterate_params("EnumProfile") do
+ local profile = parseParam(p, "EnumProfile")
+@@ -213,6 +228,7 @@ local function switchProfile()
+ end
+
+ local cur_profile_name = getCurrentProfile(device)
++ saveLastProfile(device, cur_profile_name)
+
+ _, index, name = findProfile(device, nil, cur_profile_name)
+ if hasProfileInputRoute(device, index) then
+@@ -235,8 +251,6 @@ local function switchProfile()
+ index = index
+ }
+
+- saveLastProfile(device, cur_profile_name)
+-
+ Log.info("Setting profile of '"
+ .. device.properties["device.description"]
+ .. "' from: " .. cur_profile_name
+@@ -256,6 +270,8 @@ local function restoreProfile()
+ local profile_name = getSavedLastProfile(device)
+ local cur_profile_name = getCurrentProfile(device)
+
++ saveLastProfile(device, nil)
++
+ if cur_profile_name then
+ Log.info("Setting saved headset profile to: " .. cur_profile_name)
+ saveHeadsetProfile(device, cur_profile_name)
+@@ -270,8 +286,6 @@ local function restoreProfile()
+ index = index
+ }
+
+- saveLastProfile(device, nil)
+-
+ Log.info("Restoring profile of '"
+ .. device.properties["device.description"]
+ .. "' from: " .. cur_profile_name
+@@ -298,14 +312,18 @@ local function triggerRestoreProfile()
+ end)
+ end
+
+-function parseBool(var)
+- return var and (var:lower() == "true" or var == "1")
+-end
++-- We consider a Stream of interest to have role Communication if it has
++-- media.role set to Communication in props or it is in our list of
++-- applications as these applications do not set media.role correctly or at
++-- all.
++local function checkStreamStatus(stream)
++ local app_name = stream.properties["application.name"]
++ local stream_role = stream.properties["media.role"]
+
+-local function checkStreamStatus (stream)
+- -- Ignore monitor streams
+- local is_monitor = parseBool (stream.properties["stream.monitor"])
+- if is_monitor then
++ if not (stream_role == "Communication" or applications[app_name]) then
++ return false
++ end
++ if not isBluez5DefaultAudioSink() then
+ return false
+ end
+
+@@ -316,25 +334,7 @@ local function checkStreamStatus (stream)
+ return false
+ end
+
+- -- Make sure the virtual BT filter node exists
+- local node = nodes_om:lookup ()
+- if node == nil then
+- return false
+- end
+-
+- -- Check if the stream is linked to the bluetooth loopback filter
+- local stream_id = tonumber(stream["bound-id"])
+- local bt_out_id = tonumber(node["bound-id"])
+- for l in links_om:iterate() do
+- local p = l.properties
+- local out_id = tonumber(p["link.output.node"])
+- local in_id = tonumber(p["link.input.node"])
+- if in_id == stream_id and out_id == bt_out_id then
+- return true
+- end
+- end
+-
+- return false
++ return true
+ end
+
+ local function handleStream(stream)
+@@ -361,47 +361,38 @@ local function handleAllStreams()
+ end
+ end
+
+-devices_om:connect("object-added", function (_, device)
+- -- Devices are unswitched initially
+- saveLastProfile(device, nil)
+- handleAllStreams()
++streams_om:connect("object-added", function (_, stream)
++ stream:connect("state-changed", function (stream, old_state, cur_state)
++ handleStream(stream)
++ end)
++ stream:connect("params-changed", handleStream)
++ handleStream(stream)
+ end)
+
+-links_om:connect("object-added", function (_, link)
+- if handleAllStreams then
+- local p = link.properties
+- for stream in streams_om:iterate {
+- Constraint { "media.class", "matches", "Stream/Input/Audio", type = "pw-global" },
+- Constraint { "stream.monitor", "!", "true" }
+- } do
+- local in_id = tonumber(p["link.input.node"])
+- local stream_id = tonumber(stream["bound-id"])
+- if in_id == stream_id then
+- handleStream(stream)
+- end
+- end
++streams_om:connect("object-removed", function (_, stream)
++ active_streams[stream["bound-id"]] = nil
++ previous_streams[stream["bound-id"]] = nil
++ triggerRestoreProfile()
++end)
++
++devices_om:connect("object-added", function (_, device)
++ -- Devices are unswitched initially
++ if isSwitched(device) then
++ saveLastProfile(device, nil)
+ end
++ handleAllStreams()
+ end)
+
+-links_om:connect("object-removed", function (_, link)
+- if handleAllStreams then
+- local p = link.properties
+- for stream in streams_om:iterate {
+- Constraint { "media.class", "matches", "Stream/Input/Audio", type = "pw-global" },
+- Constraint { "stream.monitor", "!", "true" }
+- } do
+- local in_id = tonumber(p["link.input.node"])
+- local stream_id = tonumber(stream["bound-id"])
+- if in_id == stream_id then
+- active_streams[stream["bound-id"]] = nil
+- previous_streams[stream["bound-id"]] = nil
+- triggerRestoreProfile()
+- end
++metadata_om:connect("object-added", function (_, metadata)
++ metadata:connect("changed", function (m, subject, key, t, value)
++ if (use_headset_profile and subject == 0 and key == "default.audio.sink"
++ and isBluez5AudioSink(value)) then
++ -- If bluez sink is set as default, rescan for active input streams
++ handleAllStreams()
+ end
+- end
++ end)
+ end)
+
++metadata_om:activate()
+ devices_om:activate()
+ streams_om:activate()
+-nodes_om:activate()
+-links_om:activate()
+--
+2.42.0
+
+
+From 043390080937c05df74a48eaff5a9713ff0ea12f Mon Sep 17 00:00:00 2001
+From: Ethan Geller
+Date: Wed, 15 Nov 2023 14:35:00 -0800
+Subject: [PATCH 11/11] fix filter chain targeting for mic.
+
+---
+ src/config/policy.lua.d/30-filters-config.lua | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/config/policy.lua.d/30-filters-config.lua b/src/config/policy.lua.d/30-filters-config.lua
+index 37badd80..8e8725fc 100644
+--- a/src/config/policy.lua.d/30-filters-config.lua
++++ b/src/config/policy.lua.d/30-filters-config.lua
+@@ -73,7 +73,7 @@ default_policy.filters_metadata = {
+ ["exclusive"] = false,
+ ["props"] = {
+ ["media.class"] = "Audio/Source",
+- ["alsa.card_name"] = "acp5x",
++ ["alsa.card_name"] = "sof-nau8821-max",
+ }
+ }
+ }
+--
+2.42.0
+
diff --git a/spec_files/wireplumber/wireplumber.spec b/spec_files/wireplumber/wireplumber.spec
index c7b30f446b..e426426d87 100644
--- a/spec_files/wireplumber/wireplumber.spec
+++ b/spec_files/wireplumber/wireplumber.spec
@@ -1,5 +1,5 @@
Name: wireplumber
-Version: 0.4.16
+Version: 0.4.17
Release: 1%{?dist}.bazzite.{{{ git_dir_version }}}
Summary: A modular session/policy manager for PipeWire
@@ -8,7 +8,7 @@ URL: https://pipewire.pages.freedesktop.org/wireplumber/
Source0: https://gitlab.freedesktop.org/pipewire/%{name}/-/archive/%{version}/%{name}-%{version}.tar.bz2
## upstream patches
-Patch0: steamdeck.patch
+Patch0: valve.patch
## upstreamable patches
@@ -70,8 +70,7 @@ managing PipeWire.
-Dsystemd=enabled \
-Dsystemd-user-service=true \
-Dintrospection=enabled \
- -Delogind=disabled \
- --sysconfdir=%{_rundir}
+ -Delogind=disabled
%meson_build
%install
@@ -80,6 +79,9 @@ managing PipeWire.
# Create local config skeleton
mkdir -p %{buildroot}%{_sysconfdir}/wireplumber/{bluetooth.lua.d,common,main.lua.d,policy.lua.d}
+# Create missing empty system config dirs for other packages to drop files in
+mkdir -p %{buildroot}%{_datadir}/wireplumber/wireplumber.conf.d
+
%find_lang %{name}
%posttrans
@@ -105,6 +107,7 @@ fi
%dir %{_sysconfdir}/wireplumber/main.lua.d
%dir %{_sysconfdir}/wireplumber/policy.lua.d
%{_datadir}/wireplumber/
+%dir %{_datadir}/wireplumber/wireplumber.conf.d
%{_datadir}/zsh/site-functions/_wpctl
%{_userunitdir}/wireplumber.service
%{_userunitdir}/wireplumber@.service
@@ -123,6 +126,12 @@ fi
%{_datadir}/gir-1.0/Wp-0.4.gir
%changelog
+* Mon Dec 4 2023 Wim Taymans - 0.4.17-1
+- wireplumber 0.4.17
+
+* Mon Dec 4 2023 Hector Martin - 0.4.16-2
+- Create and own /usr/share/wireplumber/wireplumber.conf.d
+
* Thu Nov 23 2023 Wim Taymans - 0.4.16-1
- wireplumber 0.4.16
diff --git a/system_files/deck/shared/usr/libexec/bazzite-handle-legion-go-rotation b/system_files/deck/shared/usr/libexec/bazzite-rotation-fix
similarity index 81%
rename from system_files/deck/shared/usr/libexec/bazzite-handle-legion-go-rotation
rename to system_files/deck/shared/usr/libexec/bazzite-rotation-fix
index 58cebb2276..c620e0d3a5 100755
--- a/system_files/deck/shared/usr/libexec/bazzite-handle-legion-go-rotation
+++ b/system_files/deck/shared/usr/libexec/bazzite-rotation-fix
@@ -3,6 +3,8 @@
# This script fixes the screen orientation in the Desktop Mode in Bazzite-Deck KDE
# Author: d3Xt3r
+SYS_ID="$(cat /sys/devices/virtual/dmi/id/product_name)"
+
sleep 1
echo $(date '+%Y-%m-%d %H:%M:%S') Starting Bazzite Desktop Orientation Fix script...| tee -a /tmp/bazrotfix.log
@@ -28,7 +30,11 @@ kscreen-doctor --outputs 2>&1 | tee -a /tmp/bazrotfix.log
# Fix desktop orientation
# Rotation options: right, normal, left, inverted
echo $(date '+%Y-%m-%d %H:%M:%S') Fixing desktop orientation... | tee -a /tmp/bazrotfix.log
-kscreen-doctor output.1.rotation.left 2>&1 | tee -a /tmp/bazrotfix.log
+if [[ ":83E1:" =~ ":$SYS_ID" ]]; then
+ kscreen-doctor output.1.rotation.left 2>&1 | tee -a /tmp/bazrotfix.log
+else
+ kscreen-doctor output.1.rotation.normal 2>&1 | tee -a /tmp/bazrotfix.log
+fi
echo $(date '+%Y-%m-%d %H:%M:%S') Ending Bazzite Desktop Orientation Fix script >> /tmp/bazrotfix.log
echo -e '\n' >> /tmp/bazrotfix.log
diff --git a/system_files/deck/shared/usr/share/ublue-os/just/80-bazzite.just b/system_files/deck/shared/usr/share/ublue-os/just/80-bazzite.just
index e1207c2821..1ac55189c1 100644
--- a/system_files/deck/shared/usr/share/ublue-os/just/80-bazzite.just
+++ b/system_files/deck/shared/usr/share/ublue-os/just/80-bazzite.just
@@ -60,15 +60,22 @@ configure-waydroid:
# Install Sunshine
install-sunshine:
#!/usr/bin/bash
- flatpak install --system --noninteractive flathub dev.lizardbyte.app.Sunshine
- flatpak run --command=additional-install.sh app/dev.lizardbyte.app.Sunshine/x86_64/stable || true
- echo "Sunshine is installed!"
+ sudo sed -i '0,/enabled=0/s//enabled=1/' /etc/yum.repos.d/rpmfusion-nonfree.repo
+ sudo sed -i '0,/enabled=0/s//enabled=1/' /etc/yum.repos.d/rpmfusion-nonfree-updates.repo
+ sudo systemctl enable sunshine-workaround.service
+ ublue-update --wait
+ rpm-ostree install -y sunshine
+ echo "Sunshine is installed, please reboot to apply changes."
# Remove Sunshine
remove-sunshine:
#!/usr/bin/bash
- flatpak run --command=remove-additional-install.sh app/dev.lizardbyte.app.Sunshine/x86_64/stable || true
- flatpak uninstall --delete-data --noninteractive dev.lizardbyte.sunshine
+ sudo sed -i '0,/enabled=1/s//enabled=0/' /etc/yum.repos.d/rpmfusion-nonfree.repo
+ sudo sed -i '0,/enabled=1/s//enabled=0/' /etc/yum.repos.d/rpmfusion-nonfree-updates.repo
+ sudo systemctl disable sunshine-workaround.service
+ ublue-update --wait
+ rpm-ostree remove -y sunshine
+ echo "Sunshine has been uninstalled, please reboot to apply changes."
# Autostart Sunshine
autostart-sunshine:
@@ -154,7 +161,7 @@ get-steamcmd:
install-openrazer:
sudo wget https://download.opensuse.org/repositories/hardware:/razer/Fedora_$(rpm -E %fedora)/hardware:razer.repo -O /etc/yum.repos.d/hardware:razer.repo && \
ublue-update --wait && \
- rpm-ostree install openrazer-meta razergenie && \
+ rpm-ostree install -y openrazer-meta razergenie && \
if ! grep -q "plugdev" /etc/group; then \
sudo bash -c 'grep "plugdev" /lib/group >> /etc/group' \
; fi && \
diff --git a/system_files/desktop/shared/usr/bin/bazzite-flatpak-manager b/system_files/desktop/shared/usr/bin/bazzite-flatpak-manager
index 67ed0aefd6..2096e10e14 100755
--- a/system_files/desktop/shared/usr/bin/bazzite-flatpak-manager
+++ b/system_files/desktop/shared/usr/bin/bazzite-flatpak-manager
@@ -1,7 +1,7 @@
#!/usr/bin/bash
# SCRIPT VERSION
-VER=13
+VER=14
VER_FILE="/etc/bazzite/flatpak_manager_version"
VER_RAN=$(cat $VER_FILE)
IMAGE_INFO="/usr/share/ublue-os/image-info.json"
diff --git a/system_files/desktop/shared/usr/bin/bazzite-hardware-setup b/system_files/desktop/shared/usr/bin/bazzite-hardware-setup
index 5b2a796dd3..94f0576459 100755
--- a/system_files/desktop/shared/usr/bin/bazzite-hardware-setup
+++ b/system_files/desktop/shared/usr/bin/bazzite-hardware-setup
@@ -7,7 +7,7 @@ IMAGE_FLAVOR=$(jq -r '."image-flavor"' < $IMAGE_INFO)
FEDORA_VERSION=$(jq -r '."fedora-version"' < $IMAGE_INFO)
# SCRIPT VERSION
-HWS_VER=20
+HWS_VER=21
HWS_VER_FILE="/etc/bazzite/hws_version"
HWS_VER_RAN=$(cat $HWS_VER_FILE)
diff --git a/system_files/desktop/shared/usr/bin/bazzite-user-setup b/system_files/desktop/shared/usr/bin/bazzite-user-setup
index ee66457cc9..2b440e2761 100755
--- a/system_files/desktop/shared/usr/bin/bazzite-user-setup
+++ b/system_files/desktop/shared/usr/bin/bazzite-user-setup
@@ -11,7 +11,7 @@ BAZZITE_CONFIG_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/bazzite"
mkdir -p "$BAZZITE_CONFIG_DIR"
# SCRIPT VERSION
-USER_SETUP_VER=21
+USER_SETUP_VER=22
USER_SETUP_VER_FILE="$BAZZITE_CONFIG_DIR/version"
USER_SETUP_FEDORA_VER_FILE="$BAZZITE_CONFIG_DIR/fedora_version"
@@ -126,15 +126,21 @@ if [[ $IMAGE_NAME =~ "deck" || $IMAGE_NAME =~ "ally" || $IMAGE_NAME =~ "framegam
# Legion Rotation Fix
AUTOSTART_FOLDER=${XDG_CONFIG_HOME:-$HOME/.config}
- if [[ ":83E1:" =~ ":$SYS_ID" ]] && [[ $BASE_IMAGE_NAME =~ "kinoite" ]]; then
- if [[ ! -f "$AUTOSTART_FOLDER/autostart/bazzite-handle-legion-go-rotation.desktop" ]]; then
- echo 'Adding legion rotation fix'
+
+ # Remove old legion-only file
+ if [[ -f "$AUTOSTART_FOLDER/autostart/bazzite-handle-legion-go-rotation.desktop" ]]; then
+ rm -f "$AUTOSTART_FOLDER/autostart/bazzite-handle-legion-go-rotation.desktop"
+ fi
+
+ if [[ ":ROG Ally RC71L_RC71L:83E1:" =~ ":$SYS_ID" ]] && [[ $BASE_IMAGE_NAME =~ "kinoite" ]]; then
+ if [[ ! -f "$AUTOSTART_FOLDER/autostart/bazzite-rotation-fix.desktop" ]]; then
+ echo 'Adding rotation fix'
mkdir -p "$AUTOSTART_FOLDER/autostart"
- printf "[Desktop Entry]\nExec=/usr/libexec/bazzite-handle-legion-go-rotation\nIcon=dialog-scripts\nName=bazzite-handle-legion-go-rotation\nType=Application\nX-KDE-AutostartScript=true\n" > "$AUTOSTART_FOLDER/autostart/bazzite-handle-legion-go-rotation.desktop"
+ printf "[Desktop Entry]\nExec=/usr/libexec/bazzite-rotation-fix\nIcon=dialog-scripts\nName=bazzite-rotation-fix\nType=Application\nX-KDE-AutostartScript=true\n" > "$AUTOSTART_FOLDER/autostart/bazzite-rotation-fix.desktop"
fi
- elif [[ -f "$AUTOSTART_FOLDER/autostart/bazzite-handle-legion-go-rotation.desktop" ]]; then
- echo 'Non-legion or GNOME detected, removing legionfix'
- rm -f "$AUTOSTART_FOLDER/autostart/bazzite-handle-legion-go-rotation.desktop"
+ elif [[ -f "$AUTOSTART_FOLDER/autostart/bazzite-rotation-fix.desktop" ]]; then
+ echo 'Non-supported or GNOME detected, removing rotaion fix'
+ rm -f "$AUTOSTART_FOLDER/autostart/bazzite-rotation-fix.desktop"
fi
fi
diff --git a/system_files/desktop/shared/usr/etc/skel/.var/app/com.github.marhkb.Pods/config/pods/connections.json b/system_files/desktop/shared/usr/etc/skel/.var/app/com.github.marhkb.Pods/config/pods/connections.json
new file mode 100644
index 0000000000..642aa82962
--- /dev/null
+++ b/system_files/desktop/shared/usr/etc/skel/.var/app/com.github.marhkb.Pods/config/pods/connections.json
@@ -0,0 +1,8 @@
+{
+ "32218213-d8cf-444e-84c7-7f67b9765acd": {
+ "uuid": "32218213-d8cf-444e-84c7-7f67b9765acd",
+ "name": "System",
+ "url": "unix:///run/user/1000/podman/podman.sock",
+ "rgb": null
+ }
+}
\ No newline at end of file
diff --git a/system_files/desktop/shared/usr/share/ublue-os/just/80-bazzite.just b/system_files/desktop/shared/usr/share/ublue-os/just/80-bazzite.just
index 93e26bfcd6..97690c89e0 100644
--- a/system_files/desktop/shared/usr/share/ublue-os/just/80-bazzite.just
+++ b/system_files/desktop/shared/usr/share/ublue-os/just/80-bazzite.just
@@ -50,15 +50,22 @@ configure-waydroid:
# Install Sunshine
install-sunshine:
#!/usr/bin/bash
- flatpak install --system --noninteractive flathub dev.lizardbyte.app.Sunshine
- flatpak run --command=additional-install.sh app/dev.lizardbyte.app.Sunshine/x86_64/stable || true
+ sudo sed -i '0,/enabled=0/s//enabled=1/' /etc/yum.repos.d/rpmfusion-nonfree.repo
+ sudo sed -i '0,/enabled=0/s//enabled=1/' /etc/yum.repos.d/rpmfusion-nonfree-updates.repo
+ systemctl enable sunshine-workaround.service
+ ublue-update --wait
+ rpm-ostree install -y sunshine
echo "Sunshine is installed!"
# Remove Sunshine
remove-sunshine:
#!/usr/bin/bash
- flatpak run --command=remove-additional-install.sh app/dev.lizardbyte.app.Sunshine/x86_64/stable || true
- flatpak uninstall --delete-data --noninteractive dev.lizardbyte.sunshine
+ sudo sed -i '0,/enabled=1/s//enabled=0/' /etc/yum.repos.d/rpmfusion-nonfree.repo
+ sudo sed -i '0,/enabled=1/s//enabled=0/' /etc/yum.repos.d/rpmfusion-nonfree-updates.repo
+ systemctl disable sunshine-workaround.service
+ ublue-update --wait
+ rpm-ostree remove -y sunshine
+ echo "Sunshine has been uninstalled."
# Autostart Sunshine
autostart-sunshine:
diff --git a/system_files/desktop/silverblue/usr/etc/dconf/db/local.d/04-bazzite-folders b/system_files/desktop/silverblue/usr/etc/dconf/db/local.d/04-bazzite-folders
index 0e9f27bf28..7ef2da1fa4 100644
--- a/system_files/desktop/silverblue/usr/etc/dconf/db/local.d/04-bazzite-folders
+++ b/system_files/desktop/silverblue/usr/etc/dconf/db/local.d/04-bazzite-folders
@@ -12,7 +12,7 @@ name='X-Pardus-Apps.directory'
translate=true
[org/gnome/desktop/app-folders/folders/Utilities]
-apps=['yafti.desktop', 'webapp-manager.desktop', 'fish.desktop', 'tuned-gui.desktop', 'nvtop.desktop', 'yelp.desktop', 'btop.desktop', 'com.github.tchx84.Flatseal.desktop', 'io.github.flattool.Warehouse.desktop', 'it.mijorus.gearlever.desktop', 'com.mattjakeman.ExtensionManager.desktop', 'org.gnome.tweaks.desktop', 'com.github.GradienceTeam.Gradience', 'io.github.fastrizwaan.WineZGUI.desktop']
+apps=['yafti.desktop', 'webapp-manager.desktop', 'tuned-gui.desktop', 'fish.desktop', 'tuned-gui.desktop', 'nvtop.desktop', 'yelp.desktop', 'btop.desktop', 'com.github.tchx84.Flatseal.desktop', 'io.github.flattool.Warehouse.desktop', 'it.mijorus.gearlever.desktop', 'com.mattjakeman.ExtensionManager.desktop', 'org.gnome.tweaks.desktop', 'com.github.GradienceTeam.Gradience', 'io.github.fastrizwaan.WineZGUI.desktop']
categories=['X-GNOME-Utilities']
name='X-GNOME-Utilities.directory'
translate=true