Files
qortal-go-2.0/docs/group-call-architecture-diagram.svg

220 lines
12 KiB
XML

<svg xmlns="http://www.w3.org/2000/svg" width="2400" height="1600" viewBox="0 0 2400 1600" role="img" aria-labelledby="title desc">
<title id="title">Qortal group call architecture</title>
<desc id="desc">Diagram showing root forwarder selection, room key distribution, audio processing, Electron IPC, Reticulum audio link transport, forwarding, receive jitter buffer, decode, playout, and diagnostics.</desc>
<defs>
<style>
.bg { fill: #f7f9fb; }
.title { font: 700 48px Inter, Arial, sans-serif; fill: #172033; }
.subtitle { font: 400 24px Inter, Arial, sans-serif; fill: #526070; }
.section { fill: #ffffff; stroke: #c9d3df; stroke-width: 2; rx: 22; }
.section-title { font: 700 25px Inter, Arial, sans-serif; fill: #172033; }
.box { fill: #ffffff; stroke: #9eacbb; stroke-width: 2; rx: 16; }
.box-blue { fill: #e9f2ff; stroke: #5f8ed8; }
.box-green { fill: #e8f7ef; stroke: #56a06e; }
.box-orange { fill: #fff0df; stroke: #cf8842; }
.box-red { fill: #fdeced; stroke: #c95c64; }
.box-purple { fill: #f1ecff; stroke: #8b73d8; }
.box-gray { fill: #f1f4f7; stroke: #8b99a8; }
.label { font: 600 22px Inter, Arial, sans-serif; fill: #1f2937; }
.small { font: 400 18px Inter, Arial, sans-serif; fill: #455260; }
.tiny { font: 400 16px Inter, Arial, sans-serif; fill: #596675; }
.peer-name { font: 700 24px Inter, Arial, sans-serif; fill: #172033; }
.peer-role { font: 500 17px Inter, Arial, sans-serif; fill: #596675; }
.flow { fill: none; stroke: #34495e; stroke-width: 4; marker-end: url(#arrow); }
.flow-soft { fill: none; stroke: #6f7d8a; stroke-width: 3; marker-end: url(#arrow-soft); }
.flow-key { fill: none; stroke: #9a6a00; stroke-width: 4; stroke-dasharray: 10 8; marker-end: url(#arrow-key); }
.flow-enc { fill: none; stroke: #0f766e; stroke-width: 5; marker-end: url(#arrow-enc); }
.flow-ret { fill: none; stroke: #7c3aed; stroke-width: 4; marker-end: url(#arrow-ret); }
.note { fill: #fffdf6; stroke: #d7bf70; stroke-width: 2; rx: 14; }
.pill { fill: #172033; rx: 16; }
.pill-text { font: 700 15px Inter, Arial, sans-serif; fill: #ffffff; letter-spacing: 0; }
</style>
<marker id="arrow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#34495e"/>
</marker>
<marker id="arrow-soft" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#6f7d8a"/>
</marker>
<marker id="arrow-key" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#9a6a00"/>
</marker>
<marker id="arrow-enc" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#0f766e"/>
</marker>
<marker id="arrow-ret" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#7c3aed"/>
</marker>
</defs>
<rect class="bg" x="0" y="0" width="2400" height="1600"/>
<text class="title" x="80" y="86">Qortal Desktop Group Audio Call Architecture</text>
<text class="subtitle" x="80" y="126">Example with Alice as root-forwarder, Bob speaking, and Carol receiving via encrypted fanout</text>
<rect class="section" x="70" y="170" width="2260" height="260"/>
<text class="section-title" x="105" y="215">1. Root selection, topology, and media key</text>
<rect class="box box-blue" x="115" y="250" width="355" height="105"/>
<text class="label" x="145" y="292">Members join room</text>
<text class="small" x="145" y="322">Alice, Bob, Carol</text>
<rect class="box box-blue" x="545" y="250" width="390" height="105"/>
<text class="label" x="575" y="292">Each peer computes rank</text>
<text class="small" x="575" y="322">sha256(address + ":" + roomId)</text>
<rect class="box box-green" x="1010" y="250" width="350" height="105"/>
<text class="label" x="1040" y="292">Lowest rank wins</text>
<text class="small" x="1040" y="322">Alice becomes root-forwarder</text>
<rect class="box box-orange" x="1435" y="250" width="350" height="105"/>
<text class="label" x="1465" y="292">Root creates room key</text>
<text class="small" x="1465" y="322">Shared media encryption key</text>
<rect class="box box-orange" x="1860" y="250" width="390" height="105"/>
<text class="label" x="1890" y="292">Key sent to recipients</text>
<text class="small" x="1890" y="322">Per-peer secure key delivery</text>
<path class="flow" d="M 470 302 L 545 302"/>
<path class="flow" d="M 935 302 L 1010 302"/>
<path class="flow" d="M 1360 302 L 1435 302"/>
<path class="flow-key" d="M 1785 302 L 1860 302"/>
<rect class="section" x="70" y="475" width="690" height="930"/>
<text class="section-title" x="105" y="520">2. Bob send path</text>
<text class="tiny" x="105" y="550">Runs in the renderer until IPC enters Electron main</text>
<rect class="box box-green" x="125" y="590" width="580" height="80"/>
<text class="label" x="160" y="624">Bob microphone</text>
<text class="small" x="160" y="650">AudioContext input</text>
<rect class="box box-green" x="125" y="710" width="580" height="90"/>
<text class="label" x="160" y="745">Capture AudioWorklet</text>
<text class="small" x="160" y="773">20 ms frames, 960 samples, VAD</text>
<rect class="box box-green" x="125" y="840" width="580" height="90"/>
<text class="label" x="160" y="875">WebCodecs Opus encode</text>
<text class="small" x="160" y="903">48 kHz mono, voice profile, FEC requested</text>
<rect class="box box-orange" x="125" y="970" width="580" height="110"/>
<text class="label" x="160" y="1006">Qortal audio payload</text>
<text class="small" x="160" y="1034">sourceAddr, VAD, seq, timestampMs, Opus frame</text>
<text class="small" x="160" y="1060">v2/v3 codec wrapper</text>
<rect class="box box-orange" x="125" y="1120" width="580" height="90"/>
<text class="label" x="160" y="1155">Encrypt media payload</text>
<text class="small" x="160" y="1183">nonce[24] || secretbox(inner), room media key</text>
<rect class="box box-purple" x="125" y="1250" width="580" height="90"/>
<text class="label" x="160" y="1285">Choose next hop</text>
<text class="small" x="160" y="1313">Bob sends upstream to Alice/root-forwarder</text>
<path class="flow" d="M 415 670 L 415 710"/>
<path class="flow" d="M 415 800 L 415 840"/>
<path class="flow" d="M 415 930 L 415 970"/>
<path class="flow-key" d="M 415 1080 L 415 1120"/>
<path class="flow" d="M 415 1210 L 415 1250"/>
<rect class="section" x="820" y="475" width="720" height="930"/>
<text class="section-title" x="855" y="520">3. Electron and Reticulum transport</text>
<text class="tiny" x="855" y="550">Audio is carried through dedicated Reticulum links</text>
<rect class="box box-purple" x="880" y="590" width="600" height="80"/>
<text class="label" x="915" y="624">window.groupCall.sendAudio</text>
<text class="small" x="915" y="650">Renderer to preload API</text>
<rect class="box box-purple" x="880" y="710" width="600" height="90"/>
<text class="label" x="915" y="745">gcall:sendAudio IPC</text>
<text class="small" x="915" y="773">Payload size checks and Buffer normalization</text>
<rect class="box box-purple" x="880" y="840" width="600" height="110"/>
<text class="label" x="915" y="875">GroupCallManager</text>
<text class="small" x="915" y="903">Per-peer pending queues, stale drops</text>
<text class="small" x="915" y="929">Fair round-robin flush</text>
<rect class="box box-red" x="880" y="990" width="600" height="105"/>
<text class="label" x="915" y="1026">Link readiness policy</text>
<text class="small" x="915" y="1054">Open, track, reopen, and pace per-peer audio links</text>
<rect class="box box-blue" x="930" y="1140" width="500" height="115"/>
<text class="label" x="965" y="1176">Reticulum audio link</text>
<text class="small" x="965" y="1204">Dedicated RNS.Link per peer</text>
<text class="small" x="965" y="1230">Carries encrypted Qortal media payloads</text>
<rect class="box box-blue" x="985" y="1300" width="390" height="80"/>
<text class="label" x="1020" y="1334">Python presence_bridge.py</text>
<text class="small" x="1020" y="1360">QAUD fd3/fd4 binary IPC to Reticulum</text>
<path class="flow" d="M 705 1295 C 765 1295 800 630 880 630"/>
<path class="flow" d="M 1180 670 L 1180 710"/>
<path class="flow" d="M 1180 800 L 1180 840"/>
<path class="flow" d="M 1180 950 L 1180 990"/>
<path class="flow-ret" d="M 1180 1095 L 1180 1140"/>
<path class="flow-ret" d="M 1180 1255 L 1180 1300"/>
<rect class="section" x="1600" y="475" width="730" height="930"/>
<text class="section-title" x="1635" y="520">4. Alice forwards; Carol receives and plays</text>
<text class="tiny" x="1635" y="550">Forwarding is opaque; local playback decrypts only for the participant</text>
<rect class="box box-green" x="1655" y="590" width="280" height="110"/>
<text class="peer-name" x="1690" y="630">Alice</text>
<text class="peer-role" x="1690" y="658">root-forwarder</text>
<text class="small" x="1690" y="684">Also a listener</text>
<rect class="box box-green" x="1990" y="590" width="280" height="110"/>
<text class="peer-name" x="2025" y="630">Carol</text>
<text class="peer-role" x="2025" y="658">participant</text>
<text class="small" x="2025" y="684">Receives Bob audio</text>
<rect class="box box-gray" x="1655" y="755" width="615" height="95"/>
<text class="label" x="1690" y="792">Alice receives encrypted Bob payload</text>
<text class="small" x="1690" y="820">For forwarding: does not decrypt or re-encode</text>
<rect class="box box-gray" x="1655" y="895" width="615" height="95"/>
<text class="label" x="1690" y="932">Fan out same encrypted payload</text>
<text class="small" x="1690" y="960">Separate Reticulum audio link send to Carol</text>
<rect class="box box-orange" x="1655" y="1035" width="615" height="90"/>
<text class="label" x="1690" y="1070">Carol decrypts with room key</text>
<text class="small" x="1690" y="1098">Reads sourceAddr=Bob, seq, timestamp, VAD</text>
<rect class="box box-orange" x="1655" y="1165" width="615" height="95"/>
<text class="label" x="1690" y="1202">Per-source jitter buffer</text>
<text class="small" x="1690" y="1230">Reorder, deadline playback, stale/duplicate rejection</text>
<rect class="box box-orange" x="1655" y="1300" width="295" height="80"/>
<text class="label" x="1690" y="1334">Opus decode</text>
<text class="small" x="1690" y="1360">WASM FEC/PLC preferred</text>
<rect class="box box-orange" x="1975" y="1300" width="295" height="80"/>
<text class="label" x="2010" y="1334">Adaptive playout</text>
<text class="small" x="2010" y="1360">PCM ring, output mixer</text>
<path class="flow-ret" d="M 1375 1340 C 1515 1340 1510 810 1655 810"/>
<path class="flow-enc" d="M 1935 645 L 1990 645"/>
<path class="flow-enc" d="M 1962 850 L 1962 895"/>
<path class="flow-enc" d="M 1962 990 L 1962 1035"/>
<path class="flow" d="M 1962 1125 L 1962 1165"/>
<path class="flow" d="M 1962 1260 L 1803 1300"/>
<path class="flow" d="M 1950 1340 L 1975 1340"/>
<rect class="note" x="115" y="1435" width="685" height="90"/>
<text class="label" x="145" y="1470">Important: media encryption is above Reticulum</text>
<text class="small" x="145" y="1498">Forwarders route opaque Qortal audio payloads. They only decrypt for their own local playback.</text>
<rect class="note" x="860" y="1435" width="690" height="90"/>
<text class="label" x="890" y="1470">Transport is link-only</text>
<text class="small" x="890" y="1498">Media is sent through dedicated Reticulum audio links for each peer.</text>
<rect class="note" x="1610" y="1435" width="660" height="90"/>
<text class="label" x="1640" y="1470">Diagnostics drive tuning</text>
<text class="small" x="1640" y="1498">Queue pressure, stale drops, send failures, jitter starvation, FEC/PLC, and profile state are exported.</text>
<rect class="pill" x="125" y="380" width="130" height="32"/>
<text class="pill-text" x="145" y="402">CONTROL</text>
<rect class="pill" x="125" y="1360" width="165" height="32"/>
<text class="pill-text" x="145" y="1382">ENCRYPTED MEDIA</text>
<rect class="pill" x="885" y="1360" width="150" height="32"/>
<text class="pill-text" x="905" y="1382">RETICULUM</text>
<rect class="pill" x="1655" y="1388" width="125" height="32"/>
<text class="pill-text" x="1675" y="1410">PLAYOUT</text>
</svg>