Vier Beweise, die das Projekt tragen, als eigenständig lauffähige Skripte:
S1 Plasma Mobile in proot über genestetes kwin_wayland im X11-Backend.
Fällt selbsttätig auf startplasmamobile und dann auf XFCE zurück, damit
ein Fehlschlag eindeutig Plasma zuzuordnen ist und nicht der Umgebung.
S2 Mikrofon über PulseAudio mit OpenSL-Quelle. Misst den Pegel statt nur die
Dateigröße — der typische Fehlschlag ist eine formal korrekte WAV-Datei
voller Stille.
S3 Virtuelle PipeWire-Kamera per GStreamer-pipewiresink, ohne Kernel-Modul.
Setzt die Firefox-Einstellung vorab, damit der Test nicht an einem
vergessenen Häkchen scheitert.
S4 Intent-Handoff mit lauffähiger Mini-Bridge: xdg-open-Handler für geo:,
tel: und sms:, Token-Authentifizierung, feste Liste erlaubter Schemata.
provision/provision.sh setzt die Hintergrundbeschränkungen per ADB und benennt,
was ADB nicht kann und von Hand erledigt werden muss.
Dokumentiert sind auch die sieben verworfenen Wege — Waydroid, AVF, QEMU, SIP,
APK-Daten-Redirect, Fenster-Durchreichung und der Android-Server — mit Belegen,
damit sie nicht erneut durchdacht werden müssen.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
155 lines
6.6 KiB
Bash
Executable File
155 lines
6.6 KiB
Bash
Executable File
#!/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."
|