Files

136 lines
3.4 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
RECORDINGS_DIR="$SCRIPT_DIR/recordings"
mkdir -p "$RECORDINGS_DIR"
OUTPUT="$RECORDINGS_DIR/call_$(date +%Y%m%d_%H%M%S).mp3"
# Argument parsing
SHOW_INPUTS=false
for arg in "$@"; do
[[ "$arg" == "--show-inputs" ]] && SHOW_INPUTS=true
done
# Detect the default audio sink via PipeWire metadata
DEFAULT_SINK=$(pw-metadata 0 2>/dev/null \
| awk -F"'" '/default\.audio\.sink/ { print $4 }' \
| grep -o '"name":"[^"]*"' \
| cut -d'"' -f4)
if [[ -z "$DEFAULT_SINK" ]]; then
echo "ERROR: Could not detect default audio sink." >&2
echo "Run ./list-sources.sh to see available devices." >&2
exit 1
fi
MONITOR_SOURCE="${DEFAULT_SINK}.monitor"
# --- show-inputs mode ---
if $SHOW_INPUTS; then
BAR_WIDTH=30
DB_MIN=-60
DB_MAX=0
render_bar() {
local label="$1"
local db="$2"
local bar=""
local filled=0
if [[ -n "$db" ]]; then
# Clamp to range
local clamped
clamped=$(awk -v v="$db" -v lo="$DB_MIN" -v hi="$DB_MAX" \
'BEGIN { if (v < lo) v=lo; if (v > hi) v=hi; print v }')
filled=$(awk -v v="$clamped" -v lo="$DB_MIN" -v hi="$DB_MAX" -v w="$BAR_WIDTH" \
'BEGIN { printf "%d", (v - lo) / (hi - lo) * w }')
fi
local empty=$(( BAR_WIDTH - filled ))
# Color based on level
local color="\033[32m" # green
if [[ -n "$db" ]]; then
color=$(awk -v v="$db" 'BEGIN {
if (v >= -3) { print "\033[31m" }
else if (v >= -12) { print "\033[33m" }
else { print "\033[32m" }
}')
fi
bar="${color}"
local i
for (( i=0; i<filled; i++ )); do bar+="█"; done
for (( i=0; i<empty; i++ )); do bar+="░"; done
bar+="\033[0m"
local db_str="${db:- ---}"
printf " %-13s: [%b] %6s dB\n" "$label" "$bar" "$db_str"
}
echo "=========================================="
echo " Input Monitor (Ctrl+C to exit)"
echo "=========================================="
echo ""
TMP_MIC=$(mktemp)
TMP_SYS=$(mktemp)
ffmpeg -loglevel info -f pulse -i default \
-af ebur128 -f null - 2>"$TMP_MIC" &
PID_MIC=$!
ffmpeg -loglevel info -f pulse -i "$MONITOR_SOURCE" \
-af ebur128 -f null - 2>"$TMP_SYS" &
PID_SYS=$!
cleanup() {
kill "$PID_MIC" "$PID_SYS" 2>/dev/null || true
rm -f "$TMP_MIC" "$TMP_SYS"
tput cnorm
echo ""
exit 0
}
trap cleanup INT TERM
tput civis # hide cursor
# Reserve two lines
printf "\n\n"
while true; do
MIC_DB=$(grep -oP 'M:\s*\K[-0-9.]+' "$TMP_MIC" 2>/dev/null | tail -1 || true)
SYS_DB=$(grep -oP 'M:\s*\K[-0-9.]+' "$TMP_SYS" 2>/dev/null | tail -1 || true)
printf "\033[2A" # move up 2 lines
render_bar "Mikrofon" "$MIC_DB"
render_bar "System Audio" "$SYS_DB"
sleep 0.1
done
fi
# --- Recording mode ---
echo "=========================================="
echo " Call Recorder"
echo "=========================================="
echo " Microphone : default"
echo " System audio: $MONITOR_SOURCE"
echo " Output file : $OUTPUT"
echo "------------------------------------------"
echo " Press Ctrl+C to stop recording."
echo "=========================================="
echo ""
ffmpeg -loglevel warning \
-f pulse -i default \
-f pulse -i "$MONITOR_SOURCE" \
-filter_complex "amix=inputs=2:duration=longest:normalize=0" \
-c:a libmp3lame -b:a 128k \
"$OUTPUT"
echo ""
echo "Recording saved to: $OUTPUT"