Windows tray app that bridges phone audio to the PC over the built-in Bluetooth radio — no Phone Link, no dongle.
- Music / notifications — the phone streams to the PC over A2DP; the PC renders it to any output you pick.
- Calls — cellular calls route to the PC's headset (speakers + mic) via the HFP hands-free role.
Both halves and unattended reconnect work, validated on hardware with the packaged build.
- Music (Stage 0, 2026-08-04) — connects the A2DP sink, correlates the transport to the phone by Bluetooth address, routes to a chosen output.
- Calls (Stage 0, 2026-08-04) — claims the HFP hands-free role; a real call routes to the PC with audio in both directions.
- Reconnect (Stage 1, 2026-08-07) — a
ConnectionManagerstate machine recovers unattended from a call ending, a range exit and return, sleep/resume, reboot, and a phone-initiated disconnect. It also restarts the route when the A2DP capture endpoint appears late — a case the connect path alone silently missed. This was the predecessor app's defining bug; it is fixed. FINDINGS §13, §14.
Not yet done: the full Stage 2 reconnect matrix (hand-verified scenarios) and tray selection of the call audio device.
Requires the packaged build. dotnet run is not a dev loop for the music half —
AudioPlaybackConnection.TryCreateFromId kills an unpackaged process with an uncatchable access
violation (FINDINGS §8).
| Need | Existing option | Why it isn't enough |
|---|---|---|
| Music | AudioPlaybackConnector | Abandoned 2020, reconnect bug, music only |
| Calls | Thy Phone (Store, $3.69) | Works, but is not a tray app — must stay open |
| Both | Phone Link | Ruled out |
- Windows 10 build 19041+ (developed on 19045 / 22H2)
- .NET 8 SDK
- Windows SDK 10.0.19041.0 (for
makeappx/signtool) - A Bluetooth radio the Windows stack owns (no Zadig / WinUSB rebinding)
Prebuilt, signed packages are on the
Releases page — each carries the .msix and the
public .cer it was signed with. The certificate is self-signed, so Windows refuses the package until
that cert is trusted; unlike a downloaded .exe, an MSIX has no "install anyway" prompt, so this step
is required (once per machine):
# elevated: trust the signing certificate
Import-Certificate -FilePath .\Klangbruecke.cer -CertStoreLocation Cert:\LocalMachine\TrustedPeople
# then from Windows PowerShell (not pwsh — the Appx module does not load there):
Add-AppxPackage -Path .\Klangbruecke-<version>.msixKlangbruecke starts on sign-in and lives in the tray.
MSIX packaging is load-bearing: package identity keeps TryCreateFromId from killing the process
(§8) and carries the phoneLineTransportManagement capability the calls half needs. Sideloading
needs no Microsoft approval.
dotnet build src/Klangbruecke/Klangbruecke.csproj -c Release
./packaging/New-DevCert.ps1 # once: create + trust a self-signed dev cert
./packaging/Build-Msix.ps1 # build, package, signInstall the produced .msix with sideloading enabled
(Settings → Update & Security → For developers → Sideload apps).
Cut a GitHub release (build, sign, push the commit, upload the .msix + .cer + install notes) with
./packaging/Publish-Release.ps1. The tray/app icons are generated from the brand mark by
./packaging/Generate-Icons.ps1.
- See what's happening. Right-click the tray icon → Diagnostics → Open Logs, or open
%LOCALAPPDATA%\Klangbruecke\logsdirectly. Copy Diagnostics puts a paste-ready snapshot (version, OS, state, recent log lines) on the clipboard — review it before sharing. - It won't connect. Check the pairing before suspecting the app. Klangbruecke shows "connected"
for its own view of the connection; verify the real endpoint with PowerShell:
Get-PnpDevice -Class AudioEndpoint | Where-Object FriendlyName -like '*A2DP*'. A stale pairing (the IRK trap) presents exactly like an app failure — look atBTHUSBevents 35 / 16 / 24 in the System log first. Seedocs/FINDINGS.md§3. - Music cuts out when a game goes fullscreen, or on screenshot overlays (ShareX, Snipping Tool),
and the phone briefly switches to its own speaker. This comes from Windows, not Klangbruecke. The
automatic Focus Assist rules disconnect the phone's hands-free link each time they turn on or off,
and music skips while it reconnects. Fix: Settings → System → Focus assist → Automatic rules, turn
off When I'm playing a game and When I'm using an app in full screen mode. See
docs/FINDINGS.md§26. - Force a reconnect. Diagnostics won't help if the app is deliberately dormant — use Connect Now to override a Disconnect or a switched-off auto-reconnect for one attempt.
- Reset configuration. Delete
%LOCALAPPDATA%\Klangbruecke\settings.jsonand restart; the app starts from defaults (no phone selected). - Check for a newer build. Diagnostics → Check for Updates, or see the Releases page.
Bluetooth (built-in radio, Windows stack)
|
+-------------------+--------------------+
A2DP sink HFP hands-free
AudioPlaybackConnection PhoneLineTransportDevice
| |
"Line (<phone> A2DP SNK)" call audio in/out (Windows owns the path)
capture endpoint
|
WASAPI capture -> BufferedWaveProvider -> WASAPI render -> selected output
ConnectionManager owns the lifecycle: a DeviceWatcher, an endpoint monitor,
and a 30s reconcile loop drive connect / route / retry / reconnect.
src/Klangbruecke/
Program.cs entry point, single-instance guard
TrayContext.cs tray icon + menu (view only)
Connection/ConnectionManager.cs reconnect state machine
Connection/ LinkMachine, SuppressionLatch, MusicHalf,
CallsHalf, ConnectionState, BackoffSchedule
Bluetooth/AudioSinkService.cs A2DP sink lifecycle
Bluetooth/CallTransportService.cs HFP call transport
Bluetooth/LinkMonitor.cs DeviceWatcher + ConnectionStatus
Audio/AudioRouter.cs WASAPI capture -> render bridge
Audio/EndpointMonitor.cs IMMNotificationClient: A2DP endpoint arrival
Platform/ scheduler, power notifier, package identity
tests/Klangbruecke.Tests/ 4,200+ unit tests
packaging/ AppxManifest, dev cert, MSIX build scripts
docs/FINDINGS.md research record; read before changing approach
Personal project, unlicensed.