Skip to content

Release v1.2

Latest

Choose a tag to compare

@github-actions github-actions released this 21 Aug 14:47
· 4 commits to master since this release
Immutable release. Only release title and notes can be modified.

WiFi Audio Streaming Desktop v1.2 🎉

Last time I said v1.1 was the one where the app finally settled down.

Then someone asked whether it could play to their soundbar, someone else asked
about multiroom, and I found myself reading the UPnP AVTransport specification at
an hour of the night that no specification deserves.

So: two new protocols, pairing by QR code, streaming over a USB cable, and an
audio path that no longer falls apart the moment your Wi-Fi does.


🛡️ Security

This release includes fixes to the authentication and local control paths,
identified during a deeper security review of the code.

If you're running v1.1, please update to v1.2.


⚠️ Before You Update

Good news for once: this is not a repeat of last time.

The existing v2 wire protocol remains compatible. A v1.1 device and a v1.2 device
can still communicate using the existing protocol and existing setups.

New features such as QR pairing and USB transport require v1.2 support on the
relevant side, so update both ends anyway.

👉 https://github.com/marcomorosi06/WiFiAudioStreaming-Android/releases


📺 DLNA / UPnP

Your TV can already play audio. Your AV receiver can already play audio. Your
soundbar has had a network port on the back for years and has never once been
asked to do anything with it.

Now the app can just send audio to all of them. Nothing to install on their side:
the app finds the renderers on the network, you tick the ones you want, and they
start playing when the stream starts. They're remembered and reconnected next
time.

Four formats — LPCM, WAV, MP3, AAC/ADTS — negotiated per device
by default, or forced if you own a piece of firmware with opinions. Which, if it
was made before roughly 2016, you probably do.

🔊 Snapcast Multiroom

The one I'm most quietly pleased about.

Turn this machine into a Snapcast server and every snapclient on your
network joins in and plays in sync: Raspberry Pis, ESP32 boards, Home
Assistant, the Snapcast mobile apps. Kitchen, living room, office, one stream, no
echo between rooms.

Codecs are PCM (no encoding delay), FLAC (lossless, about half the
bandwidth) and Opus (lowest bandwidth, needs 48 kHz stereo). Chunk size and
client buffer are adjustable, and the app runs its own mDNS responder, so clients
find the stream without you typing an address anywhere.

If Opus can't work with your current audio settings, the app says so and falls
back to PCM. I have opinions about software that silently produces nothing.

📷 Pair by Scanning a QR Code

Typing a shared password on two devices is fine. Reading one out loud across a
room twice, because someone heard "b" instead of "d", is where I lost patience.

The server can now show a QR code carrying the address, the port and a freshly
generated 256-bit key. Scan it and you're connected, encrypted, done. The key is
never typed and is never sent as part of the streaming handshake; the invite
carries it out-of-band.

The nice part is what it isn't: not a fourth security mode, just Key mode with
a better key — 256 random bits instead of whatever passphrase a human was willing
to type twice. The streaming handshake itself is unchanged, so older versions
don't get confused and nobody's setup breaks.

  • Invites expire after 120 seconds, so a code left on screen stops being
    useful quickly.
  • The pairing key exists only in memory, in the process that issued it: it is
    never written to the configuration or credential store, and is never restored
    at the next start. Close the server and it's gone. A passphrase you typed by
    hand is a separate thing, and is kept.
  • It renders in the terminal too, as ASCII art, for headless boxes —
    wfas pair invite --watch even redraws it before it expires.

There's also a wifiaudio:// deep link registered on all three platforms, and an
HTTPS link form that keeps the key in the URL fragment, so it isn't included in
the HTTP request sent to the web server.

🔌 Streaming Over USB

Wi-Fi is great until it isn't. Congested band, crowded flat, a hotel access point
doing its best impression of a wet paper bag.

Plug the phone in, turn on USB tethering, and the audio takes the cable instead.
The app finds the link on its own, marks those devices as USB in the list,
and buffers them separately from the Wi-Fi path.

Two things I'd rather say up front. Some devices deliver USB packets in bursts
and want more buffer here, not less — the setting is there for exactly that.
And on macOS there's no built-in RNDIS driver, so Android tethering generally
doesn't come up at all; the app now tells you that instead of showing you an
empty list.

You can also set whether WFAS stays available always, never, or not while the
cable is connected
, so the phone isn't offered two routes to the same audio.

🎧 Audio That Survives a Bad Network

Two changes, and together they're why a long stream now sounds different.

Lost packets no longer automatically become holes of silence. The app uses
the audio around a gap to conceal short losses, and crossfades back to the real
stream when packets return. A long outage still sounds like a long outage, but
the brief dropouts that used to click and stutter now mostly just pass by.

Clock drift is corrected continuously. Two machines never agree on how long a
second is, and that disagreement used to go into the buffer, which quietly
settled at its maximum and left you with latency you never asked for. Now the
buffer is resampled by a fraction of a percent to hold it at the target. Latency
stays where you set it, for hours.

🎨 The Window, Rebuilt

Redrawn around what you actually do: start a stream, see who's listening, switch
protocol. Settings are in sections now, which became non-negotiable once there
were two more protocols to fit in there.

  • A live audio spectrum, with the same groove control the terminal
    visualizer has. It used to be a CLI-only party trick.
  • A "how to connect" panel listing the endpoint for every protocol you have
    enabled, each copyable in one click, so you stop hunting for your own IP.
  • A capture indicator. While the app is capturing your microphone or system
    audio it says so — in the window and in the tray — and logs every capture with
    start, stop, duration and source. An app that can hear the room should be
    visibly honest about when it's doing it.

Discovery is stricter too: entries expire, a BYE removes a server immediately,
and the list is emptied when you switch modes. No more phantom servers from ten
minutes ago sitting there looking connectable.

On Linux the tray is finally managed properly — skipped on Wayland, gives up
after two crashes instead of taking the app with it, and if the icon never
appears the window refuses to hide. Because the old behaviour was an app still
running, still streaming, and completely unreachable. Ask me how I know.

⌨️ The CLI Grew Up

wfas was already a full daemon in v1.1. This release is about it being
pleasant.

The help is browsable — nine topics, interactive in a terminal, --json when
a script wants it. The man page is generated from the same source, and the build
fails if the help and the argument parser ever disagree about which flags
exist. Documentation that can't drift, because it isn't allowed to.

wfas devices lists your audio devices and, when one won't open, explains
why — usually "held by PulseAudio, PipeWire or JACK", which beats a device that
simply isn't in the list.

Commands that can't do what you asked now say so, instead of quietly doing
something else: --watch outside discovery, --connect alongside --server,
--encrypt with no key.

Ask mode works from a terminal now. One prompt per client instead of one per
retried packet, and no answer — timeout, no terminal, --json — means no.

New flags: --persist, --no-mute-render, --latency, --auth-key-file,
--auth-key - for a key that stays out of your shell history, --ip4 / --ip6,
the whole wfas pair family, and all the DLNA and Snapcast options.

🔧 Other Changes

  • Credentials are handled through the system credential store — DPAPI on
    Windows, Keychain on macOS, and the system keyring on Linux. Existing
    credentials are migrated automatically where possible, with WFAS_AUTH_KEY
    available for headless setups.
  • The key field has a strength meter, and wfas config output masks secrets
    unless you ask for them with --reveal.
  • Windows capture no longer drops frames under load.
  • Mono capture actually produces mono. Setting one channel used to be
    politely ignored.
  • IPv6 works, on discovery and streaming, and on machines with several
    interfaces the app picks the one that actually reaches the other device.
  • Volume goes to 200 % as digital gain, with magnetic stops and a warning
    that loud passages will clip.
  • Auto-start is properly unattended: waits for the network to exist, its own
    start volume, and its own security settings — a server that starts by itself
    and runs for hours deserves different defaults from one you're sitting in front
    of.
  • Auto-connect entries are real entries now — address, port, name, saved key
    — so they can reach a protected server without a dialog nobody is there to
    answer.
  • The startup update check no longer fires while the welcome screen is still
    explaining that the update check exists
    . Bad look, glad someone said.
  • Turning off "launch at startup" now also removes the entry written under the
    app's older name.
  • Better failure messages: a server that never answers is called out as probably
    running an older version, and on a version mismatch the app names which
    side
    needs updating.
  • Fixed a memory leak in the native engine on stop.

📱 Update the Android App Too

WiFi Audio Streaming for Android v1.2 is out as well, and the two halves are
meant to be used together — QR pairing needs a camera on one end, USB streaming
needs a phone at the other end of the cable.

👉 https://github.com/marcomorosi06/WiFiAudioStreaming-Android/releases


If you'd like to support the project, Ko-fi is there. ☕

Support on Ko-fi