58 lines
2.2 KiB
Bash
58 lines
2.2 KiB
Bash
# shellcheck shell=bash
|
|
# Part of JoeyLib, Copyright (c) 2026 Scott Duensing, under the MIT License.
|
|
# See LICENSE.md for license information.
|
|
# SPDX-License-Identifier: MIT
|
|
#
|
|
# pulseRecordLib.sh - shared PulseAudio capture helpers. SOURCE, do not run.
|
|
#
|
|
# Used by verify-amiga-audio.sh and verify-dos-audio.sh, the two gates that
|
|
# grade recorded sound because Paula and the Sound Blaster cannot be tapped
|
|
# register-by-register under fs-uae and DOSBox.
|
|
#
|
|
# The recording scheme in both: create a null sink for THIS run, point only
|
|
# the emulator at it with PULSE_SINK, and record that sink's monitor with
|
|
# parec. The host's default sink is never touched, so the gates are safe to
|
|
# run on a desktop that is playing something else, and two gates can never
|
|
# collide because the sink name carries the pid.
|
|
|
|
# pulseEnsureServer -- locate the audio server, or fail with a real reason.
|
|
#
|
|
# A sanitised environment (cron, CI, `env -i`, a systemd unit without the
|
|
# user session) has no XDG_RUNTIME_DIR, and pactl then reports "no server"
|
|
# even though one is running -- measured: `env -i make verify-audio` skipped
|
|
# both recording gates for exactly this. The socket lives at a predictable
|
|
# path, so derive it before giving up.
|
|
pulseEnsureServer() {
|
|
if pactl info >/dev/null 2>&1; then
|
|
return 0
|
|
fi
|
|
if [ -z "${XDG_RUNTIME_DIR:-}" ] && [ -S "/run/user/$(id -u)/pulse/native" ]; then
|
|
export XDG_RUNTIME_DIR="/run/user/$(id -u)"
|
|
if pactl info >/dev/null 2>&1; then
|
|
return 0
|
|
fi
|
|
fi
|
|
if [ -z "${PULSE_SERVER:-}" ] && [ -S "/run/user/$(id -u)/pulse/native" ]; then
|
|
export PULSE_SERVER="unix:/run/user/$(id -u)/pulse/native"
|
|
if pactl info >/dev/null 2>&1; then
|
|
return 0
|
|
fi
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
|
|
# pulseCreateSink <name> -- echo the module id of a new null sink.
|
|
pulseCreateSink() {
|
|
pactl load-module module-null-sink \
|
|
sink_name="$1" \
|
|
sink_properties=device.description="$1" 2>/dev/null
|
|
}
|
|
|
|
|
|
# pulseUnloadSink <moduleId> -- always call this; a leaked null sink on the
|
|
# user's audio server is the one lasting side effect these gates can have.
|
|
pulseUnloadSink() {
|
|
[ -n "${1:-}" ] && pactl unload-module "$1" 2>/dev/null
|
|
return 0
|
|
}
|