Skip to content

Commit 97980fa

Browse files
SSD DDDclaude
authored andcommitted
test(rig): two-endpoint call on one Mac — honest cross-process end-to-end measurement
Single-process loopback confounded every metric and repeatedly produced broken-ruler results: sent and recv were the SAME node's counters (delivery ratios >100% from timing offsets, waves #26/#33/#37), jitter==0 meant "no stream" not "clean link" (#24), and a cross-thread crash-race hid until it fired (#33). There was no way to verify the UI or a real MITM either. Fix: run TWO independent TriNetMonitor instances that dial each other over real UDP. Three dev-only env hooks (no-ops in a shipping run): TRINET_LOG=<path> per-instance log (LogBus) so each process's counters read apart TRINET_LISTEN=<port> this instance's UDP listen port TRINET_AUTOCALL=host:port auto-dial a 1-1 call on launch (INVITE bypassed) CallManager.startCall now honors a distinct listen port so two locals don't collide. smoke/two_endpoint_rig.sh orchestrates A(:8000) <-> B(:8100) and reports the CROSS-process delivery A->B = (B received)/(A sent) — the honest number a single process cannot give. Verified live: two real windowed processes establish a bidirectional call (macOS shares the camera, so both send AND receive). Clean link: A->B 98.7%, B->A 93.4%. With 25% induced packet loss on B: A->B still 96.7% -- i.e. the layered loss-recovery stack (grouped FEC + whole-NAL NACK + per-fragment NACK from #31-33) recovers 25% loss to ~97% frame delivery, now proven over two genuine processes instead of a self-loopback. Mac-only (the rig runs two Mac instances); the env hooks are inert dev tooling. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent e5a8581 commit 97980fa

3 files changed

Lines changed: 72 additions & 1 deletion

File tree

phone/desktop/TriNetVideo/CallManager.swift

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,26 @@ class CallManager: ObservableObject {
200200
selectedCameraID = AVCaptureDevice.default(for: .video)?.uniqueID ?? cameras.first?.uniqueID ?? ""
201201
discovery.start() // advertise + browse from launch
202202
startIdleListener() // listen on :7000 for incoming calls while idle
203+
autoCallIfConfigured() // two-endpoint test rig hook (no-op in a real run)
204+
}
205+
206+
// TEST RIG ONLY: TRINET_AUTOCALL=<host>:<peerPort> + TRINET_LISTEN=<myPort> auto-dials a
207+
// 1-1 call on launch with distinct local ports, so two instances on one machine can talk
208+
// over real UDP (INVITE bypassed). Never set in a shipping run.
209+
private var autoListenPort: UInt16?
210+
private func autoCallIfConfigured() {
211+
let env = ProcessInfo.processInfo.environment
212+
guard let peer = env["TRINET_AUTOCALL"], !peer.isEmpty else { return }
213+
let parts = peer.split(separator: ":")
214+
guard parts.count == 2, let peerPort = UInt16(parts[1]) else { NSLog("TRINET: bad TRINET_AUTOCALL"); return }
215+
remoteIP = String(parts[0])
216+
port = String(peerPort)
217+
autoListenPort = env["TRINET_LISTEN"].flatMap { UInt16($0) }
218+
NSLog("TRINET: RIG autocall -> \(remoteIP):\(peerPort) listen \(autoListenPort.map(String.init) ?? "same")")
219+
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { [weak self] in
220+
guard let self = self, !self.isInCall else { return }
221+
self.startCall()
222+
}
203223
}
204224

205225
// MARK: - Incoming call ("take the call")
@@ -979,7 +999,8 @@ class CallManager: ObservableObject {
979999
NSLog("TRINET: group call — \(hosts.count) peers")
9801000
} else {
9811001
isGroup = false
982-
transport.connect(peerHost: remoteIP, peerPort: p, listenPort: p)
1002+
let listenP = autoListenPort ?? p // rig: two local instances need distinct listen ports
1003+
transport.connect(peerHost: remoteIP, peerPort: p, listenPort: listenP)
9831004
}
9841005
let hostStrs = hosts.map { String($0) }
9851006
sendInvite(to: hostStrs, participants: [localIP] + hostStrs) // ring the callee(s); carry the full roster

phone/desktop/TriNetVideo/LinkStatus.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ final class LogBus: ObservableObject {
2929
// Persistent log FILE, so the detailed log survives quitting (the in-memory `lines` does not).
3030
// Standard macOS location -> visible in Console.app and Finder.
3131
let logURL: URL = {
32+
// TRINET_LOG lets a second instance write its own log — needed by the two-endpoint
33+
// test rig so each process's counters can be read independently (never set in a real run).
34+
if let p = ProcessInfo.processInfo.environment["TRINET_LOG"], !p.isEmpty {
35+
return URL(fileURLWithPath: (p as NSString).expandingTildeInPath)
36+
}
3237
let dir = FileManager.default.homeDirectoryForCurrentUser
3338
.appendingPathComponent("Library/Logs/TriNetMonitor", isDirectory: true)
3439
try? FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)

smoke/two_endpoint_rig.sh

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#!/usr/bin/env bash
2+
# two_endpoint_rig.sh — a REAL two-process video call on one Mac, for HONEST end-to-end
3+
# measurement. Single-process loopback confounds every metric (sent and recv are the same
4+
# node's counters; jitter==0 can mean "no stream", not "clean link" — the broken-ruler traps
5+
# that bit waves #24, #26, #33, #37). Here two independent TriNetMonitor instances dial each
6+
# other over real UDP (INVITE bypassed via TRINET_AUTOCALL), each writes its own log, and we
7+
# read the CROSS-process delivery: A->B = (B received) / (A sent).
8+
#
9+
# Enabled by three env hooks (all no-ops in a shipping run):
10+
# TRINET_LOG=<path> per-instance log file (LogBus)
11+
# TRINET_LISTEN=<port> this instance's UDP listen port
12+
# TRINET_AUTOCALL=host:port auto-dial a 1-1 call to the peer on launch
13+
#
14+
# Usage: smoke/two_endpoint_rig.sh [seconds] [dropPercentOnB]
15+
set -u
16+
SECS="${1:-30}"
17+
DROP="${2:-0}"
18+
APP=/Applications/TriNetMonitor.app
19+
A=/tmp/rigA.log; B=/tmp/rigB.log
20+
pkill -9 -f "TriNetMonitor.app/Contents/MacOS" 2>/dev/null; sleep 2
21+
defaults delete com.trinet.monitor trinetRoom 2>/dev/null # open lobby: both instances share the empty room
22+
rm -f "$A" "$B"
23+
24+
echo "launching A (:8000) <-> B (:8100)${DROP:+, ${DROP}% induced loss on B}"
25+
open -n --env TRINET_LOG="$A" --env TRINET_LISTEN=8000 --env TRINET_AUTOCALL=127.0.0.1:8100 "$APP"
26+
sleep 1
27+
open -n --env TRINET_LOG="$B" --env TRINET_LISTEN=8100 --env TRINET_AUTOCALL=127.0.0.1:8000 ${DROP:+--env TRINET_DROP=$DROP} "$APP"
28+
29+
END=$(( $(date +%s) + SECS )); while [ "$(date +%s)" -lt "$END" ]; do sleep 5; done
30+
31+
# Last STATS line from each: "video sent=<framesSent> recv=<framesReceived>"
32+
read AS AR < <(grep -aoE "video sent=[0-9]+ recv=[0-9]+" "$A" 2>/dev/null | tail -1 | grep -oE "[0-9]+" | tr '\n' ' ')
33+
read BS BR < <(grep -aoE "video sent=[0-9]+ recv=[0-9]+" "$B" 2>/dev/null | tail -1 | grep -oE "[0-9]+" | tr '\n' ' ')
34+
pkill -9 -f "TriNetMonitor.app/Contents/MacOS" 2>/dev/null
35+
36+
echo
37+
if [ -z "${AS:-}" ] || [ -z "${BR:-}" ]; then
38+
echo "RIG FAILED — no STATS in one log (call did not establish). Tail of A/B:"
39+
tail -3 "$A" 2>/dev/null; echo "---"; tail -3 "$B" 2>/dev/null
40+
exit 1
41+
fi
42+
echo "A sent $AS video, recv $AR | B sent $BS video, recv $BR"
43+
python3 -c "print(f'A->B video delivery = {100*$BR/max(1,$AS):.1f}% (B received / A sent)')"
44+
python3 -c "print(f'B->A video delivery = {100*$AR/max(1,$BS):.1f}% (A received / B sent)')"
45+
echo "(cross-process ratios — the honest end-to-end numbers a single loopback process cannot give)"

0 commit comments

Comments
 (0)