v3.9.1: plain/WASAPI streams now play on an ASIO-mode receiver (silent-mic fix)
Receiver: a Mixed (plain) session is rendered on an active lane in BothIndependent mode instead of being skipped, so a WASAPI-only sender is no longer silent to a receiver that has an ASIO driver selected. Also port the per-session buffer depth-drain (stops the receive jitter buffer bloating). Sender: add sndAudFr meter (audio frames actually sent) to localise capture vs send. App: startup sound cue (machine-wide, Preferences); stop sending audio when no peer is reachable (issue #8). Version 3.9.1. Server (relay): fix updater version-compare for multi-dot tags, guard the main loop against crashes, reject spoofed BYE from a mismatched endpoint. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
04b17ff1ab
commit
84c4a47411
@@ -188,6 +188,15 @@ public sealed class AudioSender : IDisposable
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
/// <summary>Total audio frames both lanes actually handed to the wire since the last call
|
||||
/// (resets on read). Pairs with <see cref="TakeMaxSenderPreEncodePeak"/> on the diag line:
|
||||
/// capPeak proves real signal reached the encoder; this proves frames left the socket. A
|
||||
/// high capPeak with zero frames sent localises a silence to the encode/encrypt stage — the
|
||||
/// missing measurement behind the "mic only works in ASIO" report. In WasapiOnly mode only
|
||||
/// defaultLane fires, so this number IS the WASAPI mic lane's output.</summary>
|
||||
public long TakeSenderAudioFramesSent() =>
|
||||
defaultLane.TakeAudioFramesSent() + asioLane.TakeAudioFramesSent();
|
||||
|
||||
// Cross-buffer (boundary) and within-buffer (content) split — see AudioStepProbe for the
|
||||
// diagnostic distinction. Used by the per-second diag logger to emit two extra columns so
|
||||
// an offline log inspection can tell a real audio transient apart from a buffer-boundary
|
||||
|
||||
@@ -83,6 +83,17 @@ internal sealed class SenderLane
|
||||
private float preEncodePeak;
|
||||
public float TakeMaxPreEncodePeak() { var p = preEncodePeak; preEncodePeak = 0f; return p; }
|
||||
|
||||
// Count of audio frames this lane actually handed to the wire (encode AND encrypt both
|
||||
// succeeded → SendAudio / SendPcmPart called) since the last drain. Pairs with preEncodePeak:
|
||||
// capPeak proves real signal reached the encoder INPUT, but every post-encode early-return —
|
||||
// the Opus encoder returning len<=0, no password so cryptoGcm is null, or the accumulator
|
||||
// never completing a frame — is INVISIBLE to it. This counts what actually left the machine,
|
||||
// so a log can finally tell "mic captured but nothing sent" (a drop at encode/encrypt) from
|
||||
// "mic captured and sent" (the silence is downstream). Added 2026-06-12 for Andre's
|
||||
// WASAPI-mic-only-works-in-ASIO investigation. Reset on read, like the peak.
|
||||
private long audioFramesSent;
|
||||
public long TakeAudioFramesSent() => Interlocked.Exchange(ref audioFramesSent, 0);
|
||||
|
||||
// Which render route this lane announces in its format packets. The receiver reads the
|
||||
// Lane byte on the wire and tags the matching SessionPlayout, which makes PlayoutEngine
|
||||
// route the lane's audio to the corresponding per-route IWaveProvider surface (lane
|
||||
@@ -297,6 +308,7 @@ internal sealed class SenderLane
|
||||
var maxPart = RemPacket.MaxAudioPayloadBytes;
|
||||
var totalParts = (byte)((ctLen + maxPart - 1) / maxPart);
|
||||
pcmFrameId++;
|
||||
Interlocked.Increment(ref audioFramesSent);
|
||||
for (byte part = 0; part < totalParts; part++)
|
||||
{
|
||||
var offset = part * maxPart;
|
||||
@@ -324,6 +336,7 @@ internal sealed class SenderLane
|
||||
EnsureCrypto();
|
||||
if (cryptoGcm is null) return; // no password yet → never send audio in the clear
|
||||
var ctLen = RemSoundCrypto.EncryptInto(cryptoGcm, opusBytes, cipherScratch);
|
||||
Interlocked.Increment(ref audioFramesSent);
|
||||
SendAudio(cipherScratch.AsSpan(0, ctLen));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user