Skip to main content

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"

# ------------------------------------------------------------
# Argument parsing
# ------------------------------------------------------------

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

# ------------------------------------------------------------
# Select model + language options for whisper-stream
# ------------------------------------------------------------

case "$LANG_MODE" in
  en)
    MODEL="$MODEL_EN"
    LANG_OPTS=(-l en)
    ;;
  de)
    MODEL="$MODEL_MULTI"
    LANG_OPTS=(-l de)
    ;;
  auto)
    MODEL="$MODEL_MULTI"
    LANG_OPTS=()
    ;;
esac

"$WHISPER" \
  -m "$MODEL" \
  "${LANG_OPTS[@]}" \
  "${STREAM_OPTS[@]}" \
  "${THREAD_OPTS[@]}" \
  -f "$AUDIO" | tee -a "$TRANSCRIPT" &
  
# ------------------------------------------------------------------
# Audio setup: create persistent sink + remapped source (virtual mic)microphone
# ------------------------------------------------------------------

DISCORD_SINK="discord_sink"
DISCORD_MONITOR="${DISCORD_SINK}.monitor"
VIRTUAL_MIC="whisper_mic"

echo "📁 Session: $SESSION"
echo "🗣️  Language:Language mode: $LANG_MODE"
echo "🔧 EnsuringSetting up audio routing:routing…"
echo "   - sink:Sink:   $DISCORD_SINK"
echo "   - source: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) MoveTry Discordto move an active sink-input (Discord) to discord_sink
(best-effort, poll)
#    Needed because the sink-inputThis may appearbe only brieflytransient in silent channels.channels → poll briefly.
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 inconnected to a voice channel, then re-run meeting-start."
fi

# 3) Remove existing whisper_mic remapsremap-sources (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_micvirtual microphone (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.ready (remap module id: $REMAPPED_MID"
echo REMAPPED_MID)"----"
echo "Live transcription has started."
echo "➡️  Follow the transcript with: meeting-follow"
echo "----"

# ------------------------------------------------------------------
# RecordingStart recording (ffmpeg) from the virtual mic +and transcription (whisper)whisper-stream)
# ------------------------------------------------------------

echo "🎙️  Recording from virtual microphone: $VIRTUAL_MIC"
echo "📝 Live transcription started."
echo "➡️  Follow the transcript with: meeting-follow"
echo "⏹  Stop with: meeting-stop"
echo "------"

# AudioRecord recordingaudio (from virtual mic)mic
ffmpeg -hide_banner -loglevel error \
  -f pulse -i "$VIRTUAL_MIC" \
  -ac 1 -ar 16000 \
  "$AUDIO" &
FFMPEG_PID=$!

# Transcription:Live readstranscription thefrom growing WAV file
"$WHISPER" \
  -m "$MODEL" \
  "${LANG_OPTS[@]}" \
  "${STREAM_OPTS[@]}" \
  "${THREAD_OPTS[@]}" \
  -f "$AUDIO" $COMMON_OPTS "${LANG_OPT[@]}" | \ tee -a "$TRANSCRIPT" &
WHISPER_PID=$!

# ------------------------------------------------------------
# Metadata
# ------------------------------------------------------------

cat > "$META" <<EOF
SESSION=$SESSION
AUDIO=$AUDIO
TRANSCRIPT=$TRANSCRIPT
LANG_MODE=$LANG_MODE
MODEL=$MODEL
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.meeting-start Transcript:finished $TRANSCRIPT"setup echo successfully."➡️  Follow anytime with: meeting-follow"