Schlanke, lokale Android-App: internes Smartphone-Mikrofon live auf eine verbundene Bluetooth-Box übertragen. Keine Aufnahme, kein Konto, keine Internetberechtigung.
  • Kotlin 89.7%
  • Python 10.3%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-22 12:18:22 +02:00
app init 2026-09-22 12:18:22 +02:00
gradle init 2026-09-22 12:18:22 +02:00
scripts init 2026-09-22 12:18:22 +02:00
.gitignore init 2026-09-22 12:18:22 +02:00
build.gradle.kts init 2026-09-22 12:18:22 +02:00
gradle.properties init 2026-09-22 12:18:22 +02:00
gradlew init 2026-09-22 12:18:22 +02:00
gradlew.bat init 2026-09-22 12:18:22 +02:00
README.md init 2026-09-22 12:18:22 +02:00
settings.gradle.kts init 2026-09-22 12:18:22 +02:00

Mic to Bluetooth

Schlanke, lokale Android-App: internes Smartphone-Mikrofon live auf eine verbundene Bluetooth-Box übertragen. Keine Aufnahme, kein Konto, keine Internetberechtigung.

Installieren und verwenden

Die gebaute Debug-APK liegt unter app/build/outputs/apk/debug/app-debug.apk. Auf das Smartphone kopieren, öffnen und bei Bedarf der verwendeten Datei-App die Installation erlauben. Android 8 oder neuer ist erforderlich.

  1. Die Box in den Android-Bluetooth-Einstellungen koppeln und als Medienausgabe verbinden.
  2. App öffnen und Mikrofon, Bluetooth-Gerätezugriff sowie Benachrichtigungen freigeben. Unter älteren Android-Versionen werden nur die jeweils nötigen Berechtigungen angefragt.
  3. Box auswählen und Start drücken. Die App prüft zunächst mit stummer Ausgabe, ob Android tatsächlich die Box und das interne Mikrofon verwendet.
  4. Mikrofonverstärkung, Bass, Mitten und Höhen einstellen. Die Werte werden lokal gespeichert; Klang zurücksetzen stellt alle vier Werte auf 0 dB.
  5. Mit Stop in der App oder in der laufenden Benachrichtigung beenden. Die Übertragung funktioniert auch bei ausgeschaltetem Bildschirm. Nach einer Unterbrechung ist ein erneuter manueller Start erforderlich.

Start bleibt gesperrt, solange Berechtigungen, sichtbare Benachrichtigungen oder eine Bluetooth-Ausgabe fehlen. Falls Android keine erneute Berechtigungsabfrage anbietet, die App-Einstellungen verwenden. Auch der Benachrichtigungskanal „Mikrofon-Übertragung“ muss aktiviert sein.

Bluetooth verursacht geräte- und codecabhängige Verzögerung. Die App reduziert ihre eigenen Puffer, kann die Funkverbindung aber nicht verzögerungsfrei machen. Zur Vermeidung von Rückkopplung mit geringer Box-Lautstärke beginnen und Abstand zwischen Box und Smartphone halten.

Bauen / Android Studio

Voraussetzungen: JDK 21, Android SDK Platform 36 und Android SDK Build Tools. Das Projekt in Android Studio öffnen oder ANDROID_HOME auf das installierte SDK setzen. Alternativ lokal sdk.dir in einer nicht eingecheckten local.properties angeben.

./gradlew :app:testDebugUnitTest :app:lintDebug :app:assembleDebug

Beim ersten Build lädt Gradle fehlende Abhängigkeiten von Google Maven / Maven Central. Der Wrapper verwendet Gradle 8.14.5, Android Gradle Plugin 8.13.2 und Kotlin 2.2.10. Mindest-API 26, Compile-/Target-API 36; Java-/Kotlin-Bytecode ist auf Java 17 ausgerichtet.

Gradle-JVM-Fehler mit Java 25

gradle/gradle-daemon-jvm.properties legt Java 21 für den Gradle-Daemon fest. Ein lokal installiertes JDK 21 wird automatisch gesucht; ein bestimmter Hersteller oder absoluter Rechnerpfad ist nicht vorgegeben. Es erfolgt kein automatischer JDK-Download. Die Bytecode-Zielversion 17 ist unabhängig von der Gradle-JVM.

Falls Android Studio weiterhin seine Java-25-Laufzeit für Gradle auswählt:

  1. Settings → Build, Execution, Deployment → Build Tools → Gradle öffnen.
  2. Unter Gradle JDK / Gradle JVM ein installiertes JDK 21 auswählen; bei Bedarf über Download JDK installieren. Auf diesem Entwicklungsrechner liegt es unter /usr/lib/jvm/java-21-openjdk-amd64.
  3. Das Projekt erneut mit Gradle synchronisieren. Für Terminal-Aufrufe bei Bedarf ebenfalls JAVA_HOME auf JDK 21 setzen.

Mit ./gradlew --version lässt sich die Einstellung kontrollieren: Daemon JVM: Compatible with Java 21 ... (from gradle/gradle-daemon-jvm.properties).

Hintergrund: Gradle-Daemon-JVM-Kriterien und JDK-Auswahl in Android Studio.

Aufbau und Grenzen

  • Die Activity bindet sich an den TransmissionService. Dieser besitzt Audiofokus, Benachrichtigung, partiellen Wake-Lock und eine einzelne Sitzung. Ein weiterer Start ist erst nach vollständiger Freigabe der vorherigen Audioinstanzen möglich. Kein Boot-Start, kein automatischer Neustart.
  • Der Audiothread liest PCM16/Mono mit bevorzugt 48 kHz, bei nicht initialisierbaren Streams mit 44,1 kHz. Bearbeitet wird in etwa 5-ms-Blöcken; interne Puffer berücksichtigen die Android-Mindestgrößen. UNPROCESSED wird verwendet, sofern unterstützt, sonst VOICE_RECOGNITION.
  • Verstärkung und RBJ-Biquad-Filter: Low-Shelf 150 Hz, Peak 1 kHz (Q ≈ 0,707), High-Shelf 4 kHz. Alle Regler reichen von −12 bis +12 dB. Geglättete Änderungen und eine weiche Spitzenbegrenzung oberhalb 0,9 FS benötigen keinen Lookahead-Puffer.
  • Unterstützt werden eine klassische A2DP-Ausgabe und, sofern Android sie anbietet, ein BLE-Speaker. Kein Bluetooth-SCO/Telefonieprofil und kein Bluetooth-Mikrofon. Es findet weder Gerätesuche noch Koppeln in der App statt.
  • Routing-Listener, Gerätemeldungen und Kontrollen vor Schreibzugriffen stoppen bei Routenwechsel. Beim Stop werden lokale Wiedergabepuffer verworfen. Bereits an die Box übertragene Daten lassen sich nicht zurückrufen; auch Androids Routenwechsel und das Stoppen sind nicht atomar. Ein kurzer Restton oder ein sehr kurzer systembedingter Wechsel kann daher nicht garantiert ausgeschlossen werden.
  • Bei Fokusverlust (auch Ducking), belegtem/stummgeschaltetem Mikrofon, Verbindungsverlust oder Audiofehler wird gestoppt. Bei fehlender Routing-Bestätigung bricht der Start nach etwa 2,5 Sekunden ab, sofern die System-Audioaufrufe normal zurückkehren.
  • Keine automatische Rückkopplungsunterdrückung, kein Recording, keine Hintergrund-Telemetrie. Veröffentlichung und Release-Signierung sind nicht eingerichtet.

Prüfungen

Stand 22.09.2026: Debug-APK gebaut (ca. 2,6 MB), alle acht Unit-Tests bestanden und Lint ohne Fehler abgeschlossen. Lint meldet vier Hinweise zu den bewusst festgelegten SDK-/Bibliotheksversionen und zur Backup-Konfiguration. Der vollständige UI-Smoke-Test ist auf einem Pixel-9-Emulator mit Android 16.1 bestanden. Der Build wurde auch mit der projektweiten Java-21-Daemonvorgabe erfolgreich ausgeführt.

Die Unit-Tests prüfen neutralen Frequenzgang bei beiden Abtastraten, Wirkung der einzelnen EQ-Bänder, Pegelbegrenzung ohne Integer-Überlauf, geglättete Pegeländerungen, Filterzustand über Puffergrenzen und die Sitzungszustände bei wiederholtem Start/Stop sowie verspäteten Worker-Rückmeldungen.

Der UI-Smoke-Test benötigt Python 3, ADB und einen laufenden Emulator ohne Bluetooth-Ausgabe. Er setzt ausschließlich die Daten dieser App auf dem angegebenen Emulator zurück und lehnt physische Geräteseriennummern ab:

python3 scripts/emulator_smoke.py --serial emulator-5554

Geprüft werden Berechtigungsablehnung, deaktivierter Start ohne Box, gespeicherte Reglerwerte nach Prozessneustart, Zurücksetzen und fehlende Benachrichtigungsberechtigung. Screenshot und UI-Dump landen in app/build/reports/emulator/.

Noch auf echter Hardware zu prüfen

Hier war das registrierte Smartphone offline. Emulator- und Unit-Tests ersetzen keine Audioabnahme. Folgende Prüfungen bleiben ausdrücklich offen:

  • Internes Mikrofon trotz verbundener Bluetooth-Box; keine Aufnahme über ein eventuell vorhandenes Box-Mikrofon.
  • Hörbare Wirkung aller vier Regler, störungsfreie Ausgabe und Start/Stop über mindestens 20 Zyklen.
  • Mindestens 15 Minuten Übertragung bei ausgeschaltetem Bildschirm; Stop aus der Benachrichtigung.
  • Box ausschalten / trennen, Medienroute ändern, Anruf oder andere Audio-App starten, Mikrofonzugriff entziehen; Ausgabe muss enden und darf nicht automatisch wieder starten.
  • Praktischer Test auf Android 8 sowie einem aktuellen Android-Gerät; 44,1-kHz-Fallback auf passender Hardware.
  • Ende-zu-Ende-Latenz: Smartphone und Box nahe einem externen Aufnahmegerät platzieren, mehrere kurze Klack-/Klatschimpulse erzeugen und in der Aufnahme den Abstand zwischen Originalimpuls und Box-Wiedergabe messen. Median und Spannweite zusammen mit Smartphone, Android-Version, Box und Codec dokumentieren. Bisher liegt kein gemessener Latenzwert vor.