Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,20 @@ reinstall_dotfiles
- ✅ **WSL** (Windows Subsystem for Linux)
- ✅ **macOS** (shell and tool configs, package installation not automated)

## Corsair headset auto-switch

`bin/corsair-headset-switch` is a systemd user service that switches the default
PipeWire sink to the Corsair VOID Elite when the headset powers on and restores
the previous sink when it powers off. It depends on `headsetcontrol` (installed
by `setup.sh`). After symlinking, enable it once:

```bash
systemctl --user daemon-reload
systemctl --user enable --now corsair-headset.service
```

Logs: `journalctl --user -u corsair-headset -f`.

## 📝 License

Personal dotfiles - use at your own discretion.
77 changes: 77 additions & 0 deletions bin/corsair-headset-switch
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#!/usr/bin/env bash
set -uo pipefail

readonly VOID_SINK_PATTERN='VOID_ELITE'
readonly POLL_INTERVAL=2

parse_headset_state() {
local json status
json="$(cat)"
[[ -n "${json}" ]] || { echo unknown; return; }
status="$(jq -r '.devices[0].battery.status // empty' <<<"${json}" 2>/dev/null)"
case "${status}" in
BATTERY_AVAILABLE | BATTERY_CHARGING) echo on ;;
BATTERY_UNAVAILABLE | BATTERY_TIMEOUT) echo off ;;
*) echo unknown ;;
esac
}

headset_state() {
local json
json="$(headsetcontrol -o json 2>/dev/null)" || { echo unknown; return; }
parse_headset_state <<<"${json}"
}

void_sink() {
pactl list short sinks | awk -v p="${VOID_SINK_PATTERN}" '$0 ~ p { print $2; exit }'
}

log() { printf '%s %s\n' "$(date '+%H:%M:%S')" "$*"; }

main() {
command -v headsetcontrol >/dev/null || { echo 'headsetcontrol not found' >&2; exit 1; }
command -v jq >/dev/null || { echo 'jq not found' >&2; exit 1; }
command -v pactl >/dev/null || { echo 'pactl not found' >&2; exit 1; }

local prev current sink saved_default=''
prev="$(headset_state)"
[[ "${prev}" == unknown ]] && prev=off
log "baseline headset state: ${prev}"

while true; do
current="$(headset_state)"
case "${current}" in
on)
if [[ "${prev}" == off ]]; then
sink="$(void_sink)"
if [[ -n "${sink}" ]]; then
saved_default="$(pactl get-default-sink)"
pactl set-default-sink "${sink}"
log "headset on -> default sink = ${sink} (was ${saved_default})"
else
log 'headset on but VOID sink not found; skipping'
fi
fi
prev=on
;;
off)
if [[ "${prev}" == on ]]; then
if [[ -n "${saved_default}" ]] \
&& pactl list short sinks | awk '{print $2}' | grep -qxF "${saved_default}"; then
pactl set-default-sink "${saved_default}"
log "headset off -> restored default sink = ${saved_default}"
else
log 'headset off but no valid previous sink to restore'
fi
fi
prev=off
;;
*) : ;;
esac
sleep "${POLL_INTERVAL}"
done
}

if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
main
fi
3 changes: 2 additions & 1 deletion setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ init_links() {
move_link .config/spotifyd/spotifyd.conf media/spotifyd.conf
move_link .config/fontconfig fontconfig
move_link .config/ngrok/ngrok.yml web/ngrok.yml
move_link .config/systemd/user/corsair-headset.service systemd/corsair-headset.service

echo "Symlinking complete. Backups stored in ${SCRIPT_PATH}/backups."
return
Expand All @@ -67,7 +68,7 @@ install_packages() {
return
fi

if grep --quiet 'ID=manjaro' /etc/os-release; then
if is_arch; then
# shellcheck disable=2119
install_arch_packages
post_install_packages
Expand Down
57 changes: 49 additions & 8 deletions shell/functions
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,58 @@ section_start() {
echo "${1}"
}

detect_aur_helper() {
local h
for h in paru pamac yay; do
if command -v "${h}" &>/dev/null; then
AUR_HELPER="${h}"
return 0
fi
done
echo 'No supported AUR helper (paru/pamac/yay) found' >&2
return 1
}

arch_install() {
[[ -n "${AUR_HELPER:-}" ]] || detect_aur_helper || return 1
local cmd
case "${AUR_HELPER}" in
paru | yay) cmd=("${AUR_HELPER}" -S --noconfirm --needed "$@") ;;
pamac) cmd=(sudo pamac install --no-confirm --no-upgrade "$@") ;;
*)
echo "Unknown AUR helper: ${AUR_HELPER}" >&2
return 1
;;
esac
if [[ -n "${DRY:-}" ]]; then
echo "${cmd[*]}"
return 0
fi
"${cmd[@]}"
}

enable_aur() {
[[ -n "${AUR_HELPER:-}" ]] || detect_aur_helper || return 1
[[ "${AUR_HELPER}" == pamac ]] || return 0
[[ -n "${DRY:-}" ]] && return 0
sudo sed -Ei '/EnableAUR/s/^#//' /etc/pamac.conf
}

is_arch() {
local id id_like
id="$(. /etc/os-release 2>/dev/null && echo "${ID:-}")"
id_like="$(. /etc/os-release 2>/dev/null && echo "${ID_LIKE:-}")"
[[ "${id}" == arch ]] || [[ " ${id_like} " == *' arch '* ]]
}

reinstall_dotfiles() {
rm -rf ~/.{local/bin,npm,nvm,zinit,go/bin,config/composer/vendor,nvim,config/nvim}
cd ~/.dotfiles && ./setup.sh
}

install_arch_packages() {
echo 'Enabling the AUR...'
sudo sed -Ei '/EnableAUR/s/^#//' /etc/pamac.conf
enable_aur

PACKAGES=(
# General
Expand Down Expand Up @@ -90,6 +134,7 @@ install_arch_packages() {
tldr
git
jq
headsetcontrol
ripgrep
exa
fd
Expand All @@ -101,11 +146,7 @@ install_arch_packages() {
bat
)

# shellcheck disable=2046
sudo pamac install --no-confirm --no-upgrade $(
IFS=' '
echo "${PACKAGES[*]}"
) "$@"
arch_install "${PACKAGES[@]}" "$@"
}

install_wsl_packages() {
Expand Down Expand Up @@ -393,7 +434,7 @@ post_install_packages() {
echo 'Installing `spotify-tui'
mkdir "${HOME}/.rustup"
rustup default stable
pamac install --no-confirm --no-upgrade spotify-tui
arch_install spotify-tui
}

post_setup_arch_services() {
Expand All @@ -403,7 +444,7 @@ post_setup_arch_services() {
}

setup_arch_system_emoji_support() {
sudo pamac install noto-fonts-emoji
arch_install noto-fonts-emoji
sudo cp ~/.dotfiles/templates/fonts-local.conf /etc/fonts/local.conf
}

Expand Down
12 changes: 12 additions & 0 deletions systemd/corsair-headset.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[Unit]
Description=Corsair VOID Elite auto-switch
After=pipewire.service

[Service]
Type=simple
ExecStart=%h/.dotfiles/bin/corsair-headset-switch
Restart=on-failure
RestartSec=5

[Install]
WantedBy=default.target
Loading