Lightning 0.9.8
The release that actually delivers what 0.9.7 promised, and says plainly where
0.9.7 did not.
What 0.9.7 promised and could not keep
0.9.7's notes said Lightning "now measures what it is actually sending" and
listed three things. Two of them could not happen in any 0.9.7 package, and
this is the release that makes them true:
- the microphone's level in the log every few seconds — the line comes from
a GStreamer element calledlevel, and no 0.9.7 package contained it. On
Windows the plugin was not in the builder image; in the AppImage it was added
to the required list one commit after the release was cut. - a warning in the call header when your microphone produces nothing — that
badge is raised from the level readings, so with no element it could never
appear, whether your microphone was live or dead.
The third promise — "if the capture never starts, the log says so" — did work
in 0.9.7 and still does. It sits on a different counter, at the last point
Lightning owns before the network, and has nothing to do with level.
Both packages carry the level meter now, and a Windows package was run in a
real call to check it: it logged microphone level peak= every five seconds
and raised the "your microphone is capturing nothing" warning when the capture
went quiet. That is the 0.9.7 promise no shipped package could keep.
The reading it prints for a completely silent microphone is -350 dBFS, which
is not a mistake: that is the floor the underlying GStreamer element reports
for digital silence.
The microphone could pick the wrong device, or none at all
Choosing a microphone in Settings could stop capture completely on the
AppImage. Lightning preferred PipeWire's own capture element, and the version
bundled in the AppImage mishandles the way a device is named there, so the
chain came up with nothing on it: a call that looked perfectly healthy and
carried silence. Lightning now prefers PulseAudio's element, which every
PipeWire desktop also provides.
And a chosen device could fail to bind at all. PipeWire's monitor publishes
a node name and a serial, and no device.name — the property Lightning matched
on — so a device picked from the list could never be resolved. Both halves are
fixed, and the fix was confirmed against a built package, not a source tree.
The camera takes the compressed path on Linux for the first time
The AppImage was also missing the JPEG plugin, which is what lets a camera
send its own compressed frames. Without it a USB 2.0 webcam has to send raw
frames over a link that cannot carry 720p30 of them, and the rate falls. It
ships now, so an AppImage camera takes the compressed path for the first time,
and the 0.9.8 AppImage was run on that chain to confirm it still renders.
No frame rate was measured, so this section does not claim one. What the
plugin removes is the bandwidth ceiling that forced the fallback; whether a
given camera then reaches 30 fps depends on the camera.
Windows already had that plugin and is unchanged by this.
Interoperability, and exactly how much of it was measured
Twelve legs were exercised against three other participants. The six AUDIO
legs were measured: a 440+880 Hz tone was played into one client's microphone
and detected at the far end's speaker, with pw-link proving the routing, so
those are numbers rather than impressions. The six SCREEN-SHARE legs were
WATCHED — the picture appeared at the far end — and a tone cannot measure a
screen share, so they are exactly as strong as a human looking at a screen.
- Sable — audio both ways (measured), screen share both ways (observed).
- Element Web, through Element Call — audio both ways (measured), screen
share both ways (observed). - Lightning to Lightning across platforms, Windows to Linux — audio both
ways (measured), screen share both ways (observed).
Those twelve legs were run on 0.9.7 packages, because they are the
packages that existed when the matrix was run. 0.9.8 changes the Linux audio
capture element and moves the whole Windows Qt stack, so the matrix does not
transfer to it unchanged and is not presented as if it does.
A 0.9.8 Windows package has since been run in a real call against a Linux
Lightning, with the tone measured in both directions — and its session was
migrated from a 0.9.7 install, so the upgrade path was exercised too. The
other ten legs have not been repeated on 0.9.8 binaries.
Calls: what reviewing this release found, rather than using it
A single undecryptable frame said somebody could not be heard. The call
header's "this person's media cannot be decrypted" badge was raised by the
FIRST frame that failed to decrypt. A live four-party call measured one such
frame in 3101 — and put a warning on screen for it. The badge is now decided
by a failure RATE over a sliding window of recent frames, raised high and
cleared low so it cannot flap, and the cryptor now names WHICH of six faults a
frame hit instead of the log guessing.
Ten of the eleven queues in the call paths were unbounded. 0.9.7 bounded
one of them, after a report of roughly one second of extra delay in one
direction. A GStreamer queue defaults to holding one second and never
dropping any of it, so one moment of anything downstream falling behind
becomes permanent latency for the rest of the call — and every other one was
left at that default: the queue feeding the video encoder, both queues on the
RECEIVE side (which is where a listener experiences the delay), the
screen-share audio path, and the whole one-to-one call lane, capture and
receive. All eleven are bounded now, and all but one drop old data rather than
hoarding it; the exception carries network packets into the video decoder,
where dropping one would corrupt the picture instead of shortening a delay.
jpegenc was never checked in the Windows package. It is not decoration
beside jpegdec: the app decides whether a camera takes the compressed path
by building a chain through it, so had it failed to register, every Windows
camera would have silently dropped to the raw path with nothing in any log to
say why. And no Linux package asked either — they checked that the plugin FILE
was present, which is not the same question. --call-media-status now reports
whether that chain actually works, on every platform.
A warning could outlive the person it was about. If someone's media could
not be decrypted and they then left the call, the warning stayed on the call
header for the rest of it, with nobody left for it to point at.
Voice delay, and a way to check it that does not need a room
0.9.7 fixed one queue after a report of about a second of extra delay in one
direction, and the only evidence for the fix was that it sounded better. This
release adds --call-queue-selftest, which measures the property itself:
it starves each queue's consumer and reports what the queue was still holding
once the consumer had caught up, with a plain unbounded queue running beside
it as a control.
It needs no call, no account, no second machine and no sound card, so it runs
from an installed package on any platform — which is the point, because the
acoustic rig that used to be the only way to ask needed all four. Measured on
every Linux package, on the development build and on a Windows 11 machine:
the shipped queues gave everything back above their limit, and the plain
queue held a full second and was still holding it. Every package's own
validation job now runs it and prints the result.
Under the hood
The Windows build toolchain moved to Qt 6.11.2, because Fedora withdrew every
6.11.1 package it pinned. Nothing in Lightning asked for a newer Qt.
Known limitations
- What is left of the GStreamer licence gap. Every Lightning package that
bundles GStreamer — the Windows builds, the AppImage and the snap — carried
plugins fromgst-plugins-goodwithout that project's LGPL licence text.
The text ships with them now. What is deliberately still open is whether
Lightning should also publish a written offer for those plugins' source, and
where; that is a decision about the project rather than about packaging. - The camera on Windows has failed once and then would not fail again. A
session on 2026-09-16 published camera frames and drew no picture at either
end. Every attempt to reproduce it the next day, on the same package and the
same machine, drew a picture — on the compressed path and on the raw one,
and the far end received and decrypted a thousand frames of it. Nothing in
the code changed in between, so this is not a fix and is not claimed as one:
it is an intermittent fault with no identified trigger, and until there is
one, nobody should say the camera is reliable on Windows or that it never
works. - macOS cameras have been sending uncompressed video. The macOS bundle
never shipped the JPEG plugin, so a camera there falls back to the raw path
— the same fallback that limits a Windows camera to 5 frames per second at
1080p instead of 30. It ships in this release, but as an optional piece:
nothing yet proves it is present on the machine that builds the bundle, so
the next macOS build will report whether it took. - macOS remains untested for calls.
This is a read-only mirror. It is not a release authority.
The canonical Lightning 0.9.8 release lives on GitLab:
https://gitlab.smetonis.net/Mizerd/lightning/-/releases/v0.9.8
The files attached here are byte-identical copies of the artifacts published
there. They exist so downloads do not all have to come from one small server.
Nothing about this page decides anything: it does not determine what version
exists, what is installable, or what Lightning will accept.
Verify any download against the SHA256SUMS asset, which is itself a copy of
the published one.
Lightning's in-app updater fetches its update manifest only from GitLab and
verifies an Ed25519 signature made with a key that exists nowhere near GitHub.
Every downloaded file is checked against the SHA-256 recorded in that signed
manifest before it is installed, so replacing a file here cannot cause Lightning
to install it.
Issues, source, and history: https://gitlab.smetonis.net/Mizerd/lightning