#!/sbin/openrc-run

description="Nestri pipewire audio sink"

nestri_export_env

: "${NESTRI_UID:=1000}"
: "${NESTRI_USER:=nestri}"

command="/usr/bin/neswire"
command_user="${NESTRI_USER}:${NESTRI_USER}"
command_background="yes"
pidfile="/run/nestri/neswire.pid"
output_log="/nestri/logs/neswire.log"
error_log="/nestri/logs/neswire.log"
respawn="yes"
respawn_delay="2"
respawn_max="2"

export XDG_RUNTIME_DIR="/run/user/${NESTRI_UID}"
export DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/${NESTRI_UID}/bus"

depend() {
    # wireplumber is a hard dependency, not a nicety: start_post below pins
    # the default sink through the `default` metadata object, and
    # WirePlumber is what owns that object. Started concurrently, the pin
    # lands in an object pw-metadata created itself, which is destroyed the
    # moment it exits.
    need xdg-runtime dbus dbus-session pipewire wireplumber
    use neshub
    after pipewire wireplumber neshub
}

start_pre() {
    checkpath -d -m 0755 -o "${NESTRI_USER}:${NESTRI_USER}" /run/nestri
}

# Point the graph at neswire's sink, by name.
#
# `neswire` registers itself as media.class = Audio/Sink, node.name = neswire
# ("Neswire Cloud Gaming Audio Sink"). With the hardware monitors off it is
# the only sink, so WirePlumber's find-best hook should land on it anyway --
# this makes it explicit rather than a consequence of there being nothing
# else, so adding a second sink later cannot silently steal the default.
#
# `default.configured.audio.sink` is the metadata WirePlumber's find-selected
# hook reads, and it takes a name; `wpctl set-default` takes a numeric object
# id that changes every boot, which is why this uses pw-metadata instead.
#
# Not fatal if it fails: find-best still has one candidate. A game playing
# into the wrong sink is silent, and a warning here is the only place that
# would say so.
start_post() {
    local i=0
    while [ $i -lt 50 ]; do
        pw-dump 2>/dev/null | grep -q '"node.name": "neswire"' && break
        sleep 0.1
        i=$((i+1))
    done
    if ! pw-dump 2>/dev/null | grep -q '"node.name": "neswire"'; then
        ewarn "neswire started but its sink never appeared in the graph"
        return 0
    fi

    # Wait for WirePlumber to own the `default` metadata before writing to it.
    #
    # `need wireplumber` only guarantees its script returned, not that it has
    # built its objects. Writing too early is silently useless rather than an
    # error: pw-metadata creates the object, sets the key, exits 0, and the
    # object dies with the client. So wait for the object to exist, and say
    # so if it never does.
    i=0
    while [ $i -lt 50 ]; do
        pw-metadata -n default >/dev/null 2>&1 && break
        sleep 0.1
        i=$((i+1))
    done
    if ! pw-metadata -n default >/dev/null 2>&1; then
        ewarn "no 'default' metadata: WirePlumber is not running, sink not pinned"
        return 0
    fi

    pw-metadata -n default 0 default.configured.audio.sink '{ "name": "neswire" }' \
        >/dev/null 2>&1

    # Read it back. A write that did not stick is the failure this whole
    # sequence exists to catch, and it is invisible unless checked.
    if pw-metadata -n default 2>/dev/null | grep -q "neswire"; then
        einfo "default sink pinned to neswire"
    else
        ewarn "pinned neswire as default sink but it did not stick"
    fi
}
