Prd/components/dialer-patch/tests/LegInterleaverTest.java
Lucy Doupalů be9f14ce34 Helpdesk - operator console + patched GrapheneOS Dialer for call handling
A small helpdesk system: an office Pixel running a patched GrapheneOS Dialer
answers technician calls, records both call legs as separate channels, and a
Ruby backend transcribes them through Whisper and files an AI summary against
the caller.

Squashed to a single commit for sharing. No credentials are included; secrets
live outside the repo in /etc/helpdesk/env on the server or a gitignored
.claude/env.local locally. See .claude/env.local.example for the shape.

Start at README.md, then docs/architecture.md.
2026-07-27 18:50:32 +02:00

117 lines
5.8 KiB
Java

package com.android.dialer.helpdesk.util;
/**
* Standalone off-device test for {@link LegInterleaver}.
*
* <p>This is the code that decides whether dual-leg recording produces a real conversation or a
* plausible-looking file in which the two speakers drift apart. Its failure mode is quiet: a wrong
* alignment still yields playable stereo and a readable transcript, just with the operator's words
* sliding away from when they were said. So the interesting cases here are the uneven ones - legs
* delivering different amounts, a leg stalling, a leg arriving in odd-sized pieces.
*/
public class LegInterleaverTest {
static int pass = 0, fail = 0;
static void ok(String d) { pass++; System.out.println(" ok " + d); }
static void bad(String d, String got) { fail++; System.out.println(" FAIL " + d + " (got: " + got + ")"); }
static void eq(int got, int want, String d) {
if (got == want) ok(d); else bad(d, got + ", want " + want);
}
static void eqBytes(byte[] got, int len, int[] want, String d) {
if (len != want.length) { bad(d, "length " + len + ", want " + want.length); return; }
for (int i = 0; i < len; i++) {
if ((got[i] & 0xFF) != want[i]) { bad(d, "byte " + i + " = " + (got[i] & 0xFF) + ", want " + want[i]); return; }
}
ok(d);
}
static byte[] bytes(int... v) {
byte[] b = new byte[v.length];
for (int i = 0; i < v.length; i++) b[i] = (byte) v[i];
return b;
}
public static void main(String[] args) {
byte[] out = new byte[4096];
System.out.println("equal legs interleave left-sample-first");
LegInterleaver a = new LegInterleaver(64000);
a.offerUp(bytes(1, 2, 3, 4), 4); // two mono samples: [1,2] [3,4]
a.offerDown(bytes(9, 8, 7, 6), 4); // [9,8] [7,6]
eq(a.available(), 8, "two frames ready");
int n = a.drainInto(out, 0, out.length);
eqBytes(out, n, new int[] {1, 2, 9, 8, 3, 4, 7, 6}, "L,R,L,R with sample bytes kept in pairs");
eq(a.available(), 0, "nothing left over");
System.out.println("uneven legs: only frames present on BOTH sides are emitted");
LegInterleaver b = new LegInterleaver(64000);
b.offerUp(bytes(1, 1, 2, 2, 3, 3), 6); // three samples
b.offerDown(bytes(9, 9), 2); // one sample
eq(b.available(), 4, "one common frame only");
n = b.drainInto(out, 0, out.length);
eqBytes(out, n, new int[] {1, 1, 9, 9}, "the single common frame");
eq(b.available(), 0, "the uplink surplus is NOT emitted against silence");
b.offerDown(bytes(8, 8, 7, 7), 4); // downlink catches up
eq(b.available(), 8, "the retained surplus pairs up when its counterpart arrives");
n = b.drainInto(out, 0, out.length);
eqBytes(out, n, new int[] {2, 2, 8, 8, 3, 3, 7, 7}, "and interleaves in the original order");
System.out.println("a leg arriving in odd-sized pieces still aligns");
LegInterleaver c = new LegInterleaver(64000);
c.offerUp(bytes(1, 1), 2);
c.offerUp(bytes(2, 2), 2);
c.offerDown(bytes(9, 9, 8, 8), 4);
n = c.drainInto(out, 0, out.length);
eqBytes(out, n, new int[] {1, 1, 9, 9, 2, 2, 8, 8}, "two offers on one leg equal one on the other");
System.out.println("capacity is respected and the remainder is kept");
LegInterleaver d = new LegInterleaver(64000);
d.offerUp(bytes(1, 1, 2, 2), 4);
d.offerDown(bytes(9, 9, 8, 8), 4);
n = d.drainInto(out, 0, 4); // room for exactly one frame
eqBytes(out, n, new int[] {1, 1, 9, 9}, "only what fits is written");
eq(d.available(), 4, "the rest waits rather than being dropped");
n = d.drainInto(out, 0, out.length);
eqBytes(out, n, new int[] {2, 2, 8, 8}, "and comes out next time");
eq(d.drainInto(out, 0, 3), 0, "less than a whole frame of room writes nothing");
System.out.println("writing at an offset does not disturb what is already there");
LegInterleaver e = new LegInterleaver(64000);
e.offerUp(bytes(1, 1), 2);
e.offerDown(bytes(9, 9), 2);
out[0] = 77;
n = e.drainInto(out, 1, out.length - 1);
eq(out[0] & 0xFF, 77, "the byte before the offset is untouched");
eq(n, 4, "one frame written at the offset");
System.out.println("a stalled leg drops the OLDEST audio, keeping the channels in the present");
LegInterleaver f = new LegInterleaver(8); // room for 4 mono samples
f.offerUp(bytes(1, 1, 2, 2, 3, 3, 4, 4), 8); // fills it exactly
eq(f.droppedBytes(), 0, "at the cap, nothing dropped yet");
f.offerUp(bytes(5, 5), 2); // one over
eq(f.droppedBytes(), 2, "one sample discarded");
f.offerDown(bytes(9, 9), 2);
n = f.drainInto(out, 0, out.length);
// The oldest uplink sample [1,1] is gone, so the first frame pairs [2,2] with the live downlink.
eqBytes(out, n, new int[] {2, 2, 9, 9}, "the surviving audio is the most RECENT, not the backlog");
System.out.println("dropping never splits a sample in half");
LegInterleaver g = new LegInterleaver(5); // deliberately not a multiple of 2
g.offerUp(bytes(1, 1, 2, 2, 3, 3), 6);
eq(g.droppedBytes() % LegInterleaver.BYTES_PER_SAMPLE, 0,
"only whole samples are discarded (a half would swap every following byte pair)");
System.out.println("degenerate input is harmless");
LegInterleaver h = new LegInterleaver(64000);
eq(h.available(), 0, "nothing offered -> nothing available");
eq(h.drainInto(out, 0, out.length), 0, "draining an empty interleaver writes nothing");
h.offerUp(bytes(1, 1), 0);
eq(h.available(), 0, "a zero-length offer adds nothing");
h.offerUp(bytes(1, 1), 2);
eq(h.available(), 0, "one leg alone is never enough to emit a frame");
eq(h.drainInto(out, 0, -5), 0, "negative capacity writes nothing rather than throwing");
System.out.println();
System.out.println(pass + " passed, " + fail + " failed");
if (fail > 0) System.exit(1);
}
}