#!/usr/bin/env bash
set -euo pipefail

profile_root="/usr/share/t2bce-audio-dsp/profiles"
state_root="/var/lib/t2bce-audio-dsp"
current_dir="${state_root}/current"
wp_dir="/etc/wireplumber/wireplumber.conf.d"
wp_conf="${wp_dir}/51-t2bce-audio-dsp.conf"

log() {
    printf 't2bce-audio-dsp: %s\n' "$*"
}

cleanup_generated() {
    rm -f "${wp_conf}"
    rm -rf "${current_dir}"
}

if [[ "${1:-}" == "--remove" ]]; then
    cleanup_generated
    log "removed generated DSP configuration"
    exit 0
fi

product_name=""
if [[ -r /sys/class/dmi/id/product_name ]]; then
    product_name="$(</sys/class/dmi/id/product_name)"
fi

# KAIT2EN currently names profile directories from the numeric part of
# MacBookAirX,Y / MacBookProX,Y, for example MacBookPro15,1 -> 15_1.
if [[ "${product_name}" =~ ^MacBook(Air|Pro)([0-9]+),([0-9]+)$ ]]; then
    profile="${BASH_REMATCH[2]}_${BASH_REMATCH[3]}"
else
    cleanup_generated
    log "unsupported system '${product_name:-unknown}'; no DSP configuration generated"
    exit 0
fi

src_dir="${profile_root}/${profile}"
if [[ ! -f "${src_dir}/graph.json" ]]; then
    cleanup_generated
    log "no DSP profile for ${product_name} (${profile})"
    exit 0
fi

pci_tag=""
for dev in /sys/bus/pci/devices/*; do
    [[ -r "${dev}/vendor" && -r "${dev}/device" ]] || continue
    if [[ "$(<"${dev}/vendor")" == "0x106b" && "$(<"${dev}/device")" == "0x1803" ]]; then
        pci_tag="$(basename "${dev}")"
        pci_tag="${pci_tag//:/_}"
        break
    fi
done

if [[ -z "${pci_tag}" ]]; then
    cleanup_generated
    log "Apple T2 audio PCI device 106b:1803 not found"
    exit 0
fi

speaker_sink="alsa_output.pci-${pci_tag}.HiFi__Speaker__sink"
mic_source="alsa_input.pci-${pci_tag}.HiFi__Mic__source"

install -d -m 0755 "${state_root}" "${wp_dir}"

tmp_current="$(mktemp -d "${state_root}/.current.XXXXXX")"
chmod 0755 "${tmp_current}"
tmp_conf="$(mktemp "${wp_dir}/.51-t2bce-audio-dsp.conf.XXXXXX")"

cleanup_tmp() {
    rm -rf "${tmp_current}"
    rm -f "${tmp_conf}"
}
trap cleanup_tmp EXIT

install -m 0644 "${src_dir}/graph.json" "${tmp_current}/graph.json"

has_mic=0
if [[ -f "${src_dir}/mic.json" ]]; then
    sed "s|@T2_MIC_SOURCE@|${mic_source}|g" \
        "${src_dir}/mic.json" > "${tmp_current}/mic.json"
    chmod 0644 "${tmp_current}/mic.json"
    has_mic=1
fi

{
    printf '# Generated by t2bce-audio-dsp for %s\n\n' "${product_name}"
    printf 'node.software-dsp.rules = [\n'
    printf '    {\n'
    printf '        matches = [\n'
    printf '            { node.name = "%s" }\n' "${speaker_sink}"
    printf '        ]\n'
    printf '        actions = {\n'
    printf '            create-filter = {\n'
    printf '                filter-path = "%s/graph.json"\n' "${current_dir}"
    printf '                hide-parent = false\n'
    printf '            }\n'
    printf '        }\n'
    printf '    }\n'

    if (( has_mic )); then
        printf '    {\n'
        printf '        matches = [\n'
        printf '            { node.name = "%s" }\n' "${mic_source}"
        printf '        ]\n'
        printf '        actions = {\n'
        printf '            create-filter = {\n'
        printf '                filter-path = "%s/mic.json"\n' "${current_dir}"
        printf '                hide-parent = false\n'
        printf '            }\n'
        printf '        }\n'
        printf '    }\n'
    fi

    printf ']\n\n'
    printf 'wireplumber.profiles = {\n'
    printf '    main = {\n'
    printf '        node.software-dsp = required\n'
    printf '    }\n'
    printf '}\n'
} > "${tmp_conf}"

# Replace the generated state atomically enough that WirePlumber never sees a
# partially written graph/config.
rm -rf "${current_dir}"
mv "${tmp_current}" "${current_dir}"
chmod 0755 "${current_dir}"
install -m 0644 "${tmp_conf}" "${wp_conf}"

trap - EXIT
rm -f "${tmp_conf}"

log "configured ${product_name} DSP profile ${profile}"
