#!/usr/bin/env bash # Phase 0 · Beweis S2 — Erreicht das Mikrofon die Linux-Seite? # # Der stillste K.-o.-Punkt des Projekts. Ohne Mikrofon im Linux gibt es keine # Videocalls in Element oder im Browser, keine Sprachaufnahme, keine Spracheingabe. # Die Wette: Termux' PulseAudio kann über OpenSL ES eine Aufnahmequelle anbieten, # die per TCP in den proot durchgereicht wird. # # Ausführen IN TERMUX: bash spike/02-s2-mikrofon.sh set -uo pipefail source "$(dirname "$0")/lib.sh" require_termux DISTRO=debian DAUER="${HPOS_DAUER:-6}" WAV="$OUT_DIR/s2-aufnahme.wav" log "HPOS Phase 0 · S2 — Mikrofon im Linux" log "Protokoll: $LOG" # ── Berechtigung ───────────────────────────────────────────────────────────── # Ohne erteilte Mikrofonberechtigung liefert die OpenSL-Quelle Stille statt eines # Fehlers — der verwirrendste denkbare Fehlschlag. Deshalb vorher erzwingen. section "Mikrofonberechtigung" if have termux-microphone-record; then log " Kurzer Test über Termux:API, um den Berechtigungsdialog auszulösen …" try termux-microphone-record -d -l 2 -f "$OUT_DIR/s2-vortest.m4a" sleep 3 try termux-microphone-record -q if [ -s "$OUT_DIR/s2-vortest.m4a" ]; then ok "Termux:API kann aufnehmen — Berechtigung liegt vor" else fail "Termux:API konnte nicht aufnehmen" hint "Einstellungen → Apps → Termux:API → Berechtigungen → Mikrofon erlauben." hint "Ohne das ist S2 nicht aussagekräftig." fi else warn "termux-microphone-record fehlt (Paket termux-api). Weiter ohne Vortest." fi # ── PulseAudio mit Aufnahmequelle ──────────────────────────────────────────── section "PulseAudio mit OpenSL-Quelle" pulseaudio --kill 2>/dev/null || true sleep 1 # module-sles-source ist der Teil, der wackelt: er existiert nicht in jedem # Termux-Build. Deshalb erst mit, dann ohne — und der Unterschied wird protokolliert. MIT_QUELLE=0 if pulseaudio --start --exit-idle-time=-1 \ --load="module-sles-source" \ --load="module-native-protocol-tcp auth-ip-acl=127.0.0.1 auth-anonymous=1" \ >>"$LOG" 2>&1; then MIT_QUELLE=1 ok "PulseAudio mit module-sles-source gestartet" else warn "module-sles-source ließ sich nicht laden — starte ohne" try pulseaudio --start --exit-idle-time=-1 \ --load="module-native-protocol-tcp auth-ip-acl=127.0.0.1 auth-anonymous=1" fi sleep 2 section "Verfügbare Quellen" if have pactl; then pactl list sources short 2>&1 | tee -a "$LOG" | sed 's/^/ /' QUELLEN=$(pactl list sources short 2>/dev/null | wc -l) if [ "$QUELLEN" -gt 0 ]; then ok "$QUELLEN Aufnahmequelle(n) gemeldet" else fail "Keine einzige Aufnahmequelle — S2 wird so nicht gelingen" hint "Falls module-sles-source fehlt, ist dieser Termux-Build ohne OpenSL-Aufnahme gebaut." fi else warn "pactl fehlt, kann Quellen nicht auflisten" fi # ── Aufnahme im Debian ─────────────────────────────────────────────────────── section "Aufnahme aus dem Debian heraus" log " ${DAUER} Sekunden werden aufgenommen — bitte jetzt laut und deutlich sprechen." log "" sleep 1 proot-distro login "$DISTRO" --shared-tmp --bind "$REPO_ROOT:/hpos" -- bash -lc " set -uo pipefail export PULSE_SERVER=127.0.0.1 echo ' Quellen aus Sicht des Debian:' pactl list sources short 2>&1 | sed 's/^/ /' || echo ' (pactl lieferte nichts)' echo ' Nehme auf …' timeout $((DAUER + 4)) parecord --channels=1 --rate=16000 --file-format=wav \ /hpos/spike/out/$(basename "$WAV") & REC=\$! sleep $DAUER kill \$REC 2>/dev/null wait \$REC 2>/dev/null echo ' Aufnahme beendet.' " 2>&1 | tee -a "$LOG" # ── Auswertung ─────────────────────────────────────────────────────────────── # Eine Datei zu erzeugen beweist nichts: die häufigste Fehlerform ist eine # formal korrekte WAV-Datei voller Stille. Deshalb Größe UND Inhalt prüfen. section "Auswertung" if [ ! -s "$WAV" ]; then fail "Keine Aufnahmedatei entstanden → S2 gescheitert" else GROESSE=$(stat -c%s "$WAV" 2>/dev/null || echo 0) ok "Datei vorhanden: $WAV ($GROESSE Bytes)" ERWARTET=$((DAUER * 16000 * 2 * 8 / 10)) if [ "$GROESSE" -lt "$ERWARTET" ]; then warn "Deutlich kleiner als erwartet (~$ERWARTET Bytes) — vermutlich abgebrochen" fi # Stilletest. Der typische Fehlschlag ist eine formal korrekte WAV-Datei voller # Nullen — sie sieht in jeder Dateiliste richtig aus und enthält doch nichts. # Deshalb wird der Pegel gemessen, nicht nur die Größe. if have python; then python - "$WAV" <<'PY' 2>&1 | tee -a "$LOG" import array, math, sys, wave # Bewusst ohne audioop: das Modul ist in Python 3.13 entfernt worden, und Termux # liegt regelmäßig auf der aktuellen Version. try: with wave.open(sys.argv[1]) as w: breite = w.getsampwidth() roh = w.readframes(w.getnframes()) if breite == 1: werte = array.array("b", bytes(b - 128 for b in roh)) elif breite == 2: werte = array.array("h", roh[: len(roh) // 2 * 2]) else: raise ValueError(f"{breite} Byte je Abtastwert werden hier nicht ausgewertet") if not werte: raise ValueError("keine Abtastwerte enthalten") pegel = int(math.sqrt(sum(v * v for v in werte) / len(werte))) spitze = max(abs(v) for v in werte) print(f" Effektivpegel: {pegel} Spitze: {spitze}") if spitze < 40: print(" ✗ Praktisch Stille — die Quelle liefert keine echten Daten.") print(" Das ist der typische Fehlschlag: Datei ja, Ton nein.") print(" Prüfen: Mikrofonberechtigung für Termux:API, und ob") print(" module-sles-source in diesem Termux-Build überhaupt existiert.") else: print(" ✓ Echtes Signal aufgenommen.") except Exception as e: print(f" ! Datei nicht auswertbar: {e}") PY fi log "" log " Zum Gegenhören: pactl upload-sample nicht nötig — einfach abspielen:" log " proot-distro login $DISTRO -- env PULSE_SERVER=127.0.0.1 paplay /hpos/spike/out/$(basename "$WAV")" fi log "" log " module-sles-source geladen: $([ "$MIT_QUELLE" = 1 ] && echo ja || echo NEIN)" verdict "S2" "Ist auf der Aufnahme deine Stimme hörbar? Abspielen mit dem Befehl oben. Eine Datei ohne Ton zählt als gescheitert."