Script meetings/bin/meeting-start
./bin/meeting-start
Usage:
-
German:
meeting-start --de -
English:
meeting-start --en -
Auto:
meeting-start --auto
#!/usr/bin/env bash
set -euo pipefail
HERE="$(cd "$(dirname "$0")" && pwd)"
source "$HERE/../lib/paths.sh"
source "$HERE/../lib/whisper.sh"
LANG_MODE="auto"
while [[ $# -gt 0 ]]; do
case "$1" in
--de) LANG_MODE="de"; shift ;;
--en) LANG_MODE="en"; shift ;;
--auto) LANG_MODE="auto"; shift ;;
*) echo "Usage: meeting-start [--de|--en|--auto]"; exit 2 ;;
esac
done
# WhisperSelect model + language
flag nur setzen, wenn nicht auto
LANG_OPT=()
if [[case "$LANG_MODE" !=in
en)
MODEL="auto"$MODEL_EN"
]]LANG_OPTS=(-l en)
;;
thende)
LANG_OPT=MODEL="$MODEL_MULTI"
LANG_OPTS=(--languagel de)
;;
auto)
MODEL="$MODEL_MULTI"
LANG_OPTS=()
;;
esac
"$LANG_MODE")WHISPER" fi\
-m "$MODEL" \
"${LANG_OPTS[@]}" \
"${STREAM_OPTS[@]}" \
"${THREAD_OPTS[@]}" \
-f "$AUDIO" | tee -a "$TRANSCRIPT" &
# ------------------------------------------------------------------
# Audio setup: create persistent sink + remapped source (virtual mic)
# ------------------------------------------------------------------
DISCORD_SINK="discord_sink"
DISCORD_MONITOR="${DISCORD_SINK}.monitor"
VIRTUAL_MIC="whisper_mic"
echo "📁 Session: $SESSION"
echo "🗣️ Language: $LANG_MODE"
echo "🔧 Ensuring audio routing:"
echo " - sink: $DISCORD_SINK"
echo " - source: $VIRTUAL_MIC (master: $DISCORD_MONITOR)"
echo "----"
# 1) Ensure discord_sink exists
if ! pactl list short sinks | awk '{print $2}' | grep -qx "$DISCORD_SINK"; then
pactl load-module module-null-sink \
sink_name="$DISCORD_SINK" \
sink_properties=device.description=DiscordSink >/dev/null
fi
# 2) Move Discord sink-input to discord_sink (best-effort, poll)
# Needed because the sink-input may appear only briefly in silent channels.
moved="no"
for _ in {1..40}; do
SID="$(pactl list short sink-inputs 2>/dev/null | awk 'NF{print $1}' | head -n1 || true)"
if [[ -n "${SID:-}" ]]; then
if pactl move-sink-input "$SID" "$DISCORD_SINK" 2>/dev/null; then
moved="yes"
break
fi
fi
sleep 0.25
done
if [[ "$moved" != "yes" ]]; then
echo "⚠️ Could not move a sink-input to $DISCORD_SINK."
echo " Make sure Legcord is in a voice channel, then re-run meeting-start."
fi
# 3) Remove existing whisper_mic remaps (idempotent)
for mid in $(pactl list short modules | awk '$0 ~ /module-remap-source/ && $0 ~ /source_name=whisper_mic/ {print $1}'); do
pactl unload-module "$mid" >/dev/null 2>&1 || true
done
# 4) Create whisper_mic (mono; attempt 16 kHz)
REMAPPED_MID="$(pactl load-module module-remap-source \
master="$DISCORD_MONITOR" \
source_name="$VIRTUAL_MIC" \
channels=1 \
rate=16000 \
master_channel_map=front-left \
channel_map=mono \
source_properties=device.description=WhisperMic16k)"
echo "✅ Audio ready. remap module id: $REMAPPED_MID"
echo "----"
echo "Live transcription has started."
echo "➡️ Follow the transcript with: meeting-follow"
echo "----"
# ------------------------------------------------------------------
# Recording (ffmpeg) from the virtual mic + transcription (whisper)
# ------------------------------------------------------------------
# Audio recording (virtual mic)
ffmpeg -hide_banner -loglevel error \
-f pulse -i "$VIRTUAL_MIC" \
-ac 1 -ar 16000 \
"$AUDIO" &
FFMPEG_PID=$!
# Transcription: reads the growing WAV file
"$WHISPER" -m "$MODEL" -f "$AUDIO" $COMMON_OPTS "${LANG_OPT[@]}" | \
tee -a "$TRANSCRIPT" &
WHISPER_PID=$!
cat > "$META" <<EOF
SESSION=$SESSION
AUDIO=$AUDIO
TRANSCRIPT=$TRANSCRIPT
LANG_MODE=$LANG_MODE
DISCORD_SINK=$DISCORD_SINK
DISCORD_MONITOR=$DISCORD_MONITOR
VIRTUAL_MIC=$VIRTUAL_MIC
REMAPPED_MID=$REMAPPED_MID
FFMPEG_PID=$FFMPEG_PID
WHISPER_PID=$WHISPER_PID
EOF
echo "$FFMPEG_PID" > "$SESSION/ffmpeg.pid"
echo "$WHISPER_PID" > "$SESSION/whisper.pid"
echo "✅ Started. Transcript: $TRANSCRIPT"
echo "➡️ Follow anytime with: meeting-follow"