mirror of
git://f0xx.org/android_cast
synced 2026-07-29 08:19:00 +03:00
snap next steps egress review
This commit is contained in:
165
20260521_next_gen_steps_egress_review.pdf
Normal file
165
20260521_next_gen_steps_egress_review.pdf
Normal file
File diff suppressed because one or more lines are too long
5
app/src/main/res/drawable/settings_app_info_divider.xml
Normal file
5
app/src/main/res/drawable/settings_app_info_divider.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="@color/settings_app_info_divider" />
|
||||||
|
</shape>
|
||||||
@@ -285,6 +285,13 @@
|
|||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="2dp"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:layout_marginEnd="12dp"
|
||||||
|
android:background="@drawable/settings_app_info_divider" />
|
||||||
|
|
||||||
<include
|
<include
|
||||||
layout="@layout/include_app_info_section"
|
layout="@layout/include_app_info_section"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|||||||
@@ -5,4 +5,5 @@
|
|||||||
<color name="settings_header_gradient_end">#FF000000</color>
|
<color name="settings_header_gradient_end">#FF000000</color>
|
||||||
<color name="settings_header_text">#FFFFFFFF</color>
|
<color name="settings_header_text">#FFFFFFFF</color>
|
||||||
<color name="settings_header_shadow">#99000000</color>
|
<color name="settings_header_shadow">#99000000</color>
|
||||||
|
<color name="settings_app_info_divider">#66FFFFFF</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -11,4 +11,5 @@
|
|||||||
<color name="inverted_primary">#FF212121</color>
|
<color name="inverted_primary">#FF212121</color>
|
||||||
<color name="settings_spinner_text_shadow">#AA000000</color>
|
<color name="settings_spinner_text_shadow">#AA000000</color>
|
||||||
<color name="settings_spinner_selected_underline">#FFFFFFFF</color>
|
<color name="settings_spinner_selected_underline">#FFFFFFFF</color>
|
||||||
|
<color name="settings_app_info_divider">#66000000</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
383
docs/_pdf_build/build_egress_review_pdf.py
Normal file
383
docs/_pdf_build/build_egress_review_pdf.py
Normal file
@@ -0,0 +1,383 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Build 20260521_next_gen_steps_egress_review.pdf from summary text and diagram PNGs."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from reportlab.lib import colors
|
||||||
|
from reportlab.lib.enums import TA_LEFT
|
||||||
|
from reportlab.lib.pagesizes import A4
|
||||||
|
from reportlab.lib.styles import ParagraphStyle, getSampleStyleSheet
|
||||||
|
from reportlab.lib.units import cm
|
||||||
|
from reportlab.platypus import (
|
||||||
|
Image,
|
||||||
|
PageBreak,
|
||||||
|
Paragraph,
|
||||||
|
SimpleDocTemplate,
|
||||||
|
Spacer,
|
||||||
|
Table,
|
||||||
|
TableStyle,
|
||||||
|
)
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
BUILD = Path(__file__).resolve().parent
|
||||||
|
OUT_PDF = ROOT / "20260521_next_gen_steps_egress_review.pdf"
|
||||||
|
|
||||||
|
MM = [
|
||||||
|
("diagram_current_arch.mmd", "diagram_current_arch.png", "Current sender path (1 encode, N unicast sends)"),
|
||||||
|
("diagram_multicast_proposal.mmd", "diagram_multicast_proposal.png", "Proposed multicast setup (handshake then one media flow)"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def render_mermaid() -> None:
|
||||||
|
for mmd, png, _ in MM:
|
||||||
|
src = BUILD / mmd
|
||||||
|
dst = BUILD / png
|
||||||
|
subprocess.run(
|
||||||
|
[
|
||||||
|
"npx",
|
||||||
|
"--yes",
|
||||||
|
"@mermaid-js/mermaid-cli@11.4.0",
|
||||||
|
"-i",
|
||||||
|
str(src),
|
||||||
|
"-o",
|
||||||
|
str(dst),
|
||||||
|
"-b",
|
||||||
|
"white",
|
||||||
|
"-w",
|
||||||
|
"1400",
|
||||||
|
"-H",
|
||||||
|
"900",
|
||||||
|
],
|
||||||
|
cwd=str(ROOT),
|
||||||
|
check=True,
|
||||||
|
timeout=180,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def p(text: str, style) -> Paragraph:
|
||||||
|
return Paragraph(text.replace("\n", "<br/>"), style)
|
||||||
|
|
||||||
|
|
||||||
|
def build_pdf() -> None:
|
||||||
|
styles = getSampleStyleSheet()
|
||||||
|
title = ParagraphStyle(
|
||||||
|
"DocTitle",
|
||||||
|
parent=styles["Title"],
|
||||||
|
fontSize=18,
|
||||||
|
spaceAfter=12,
|
||||||
|
textColor=colors.HexColor("#1565C0"),
|
||||||
|
)
|
||||||
|
h1 = ParagraphStyle("H1", parent=styles["Heading1"], fontSize=14, spaceBefore=14, spaceAfter=8)
|
||||||
|
h2 = ParagraphStyle("H2", parent=styles["Heading2"], fontSize=12, spaceBefore=10, spaceAfter=6)
|
||||||
|
body = ParagraphStyle("Body", parent=styles["Normal"], fontSize=10, leading=14, alignment=TA_LEFT)
|
||||||
|
small = ParagraphStyle("Small", parent=body, fontSize=9, textColor=colors.grey)
|
||||||
|
|
||||||
|
story = []
|
||||||
|
story.append(p("Android Cast — Next-gen egress review", title))
|
||||||
|
story.append(
|
||||||
|
p(
|
||||||
|
"Summary of sender 1:N behavior, bandwidth model, limitations, and feasibility "
|
||||||
|
"of single-stream multicast plus multi-tier (full / 720p / 480p) renditions. "
|
||||||
|
"Generated 2026-05-21.",
|
||||||
|
small,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
story.append(Spacer(1, 0.4 * cm))
|
||||||
|
|
||||||
|
# --- Current state ---
|
||||||
|
story.append(p("1. Current sender behavior", h1))
|
||||||
|
story.append(
|
||||||
|
p(
|
||||||
|
"<b>How many receivers?</b> Up to 5 when MULTI_RECEIVER_ENABLED "
|
||||||
|
"(CastConfig.MAX_RECEIVERS). Sender opens one CastSession per selected device; "
|
||||||
|
"failed handshakes are skipped if at least one peer connects.",
|
||||||
|
body,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
story.append(Spacer(1, 0.2 * cm))
|
||||||
|
story.append(
|
||||||
|
p(
|
||||||
|
"<b>CPU / GPU / memory:</b> Capture and encode run once per cast. "
|
||||||
|
"CastFanoutPump duplicates each encoded frame to every session. "
|
||||||
|
"Network send and per-peer UDP/FEC state scale with N; encode cost does not.",
|
||||||
|
body,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
story.append(Spacer(1, 0.2 * cm))
|
||||||
|
story.append(
|
||||||
|
p(
|
||||||
|
"<b>Bandwidth:</b> Per-receiver unicast duplicate of the same bitstream — not IP multicast. "
|
||||||
|
"Rough LAN egress ≈ (video + ~96 kbps audio) × N, plus per-peer protocol overhead.",
|
||||||
|
body,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
story.append(Spacer(1, 0.5 * cm))
|
||||||
|
|
||||||
|
img1 = BUILD / MM[0][1]
|
||||||
|
if img1.exists():
|
||||||
|
story.append(p(MM[0][2], h2))
|
||||||
|
iw = 16 * cm
|
||||||
|
story.append(Image(str(img1), width=iw, height=iw * 0.45))
|
||||||
|
story.append(Spacer(1, 0.4 * cm))
|
||||||
|
|
||||||
|
# Table current limits
|
||||||
|
story.append(p("1.1 Current limitations (sender-focused)", h2))
|
||||||
|
limits = [
|
||||||
|
["Area", "Limitation"],
|
||||||
|
["Primary peer", "First connected peer sets negotiated MIME, adaptive tuning, and network feedback."],
|
||||||
|
["Codec", "Single encoder; all peers must tolerate the same bitstream."],
|
||||||
|
["Send path", "One CastFanoutPump thread; serial fan-out to N sessions."],
|
||||||
|
["Wi‑Fi", "Uplink often saturates before CPU on 3–5 receivers."],
|
||||||
|
["Topology", "Sender dials out; no shared LAN broadcast stream today."],
|
||||||
|
]
|
||||||
|
t = Table(limits, colWidths=[3.2 * cm, 13.3 * cm])
|
||||||
|
t.setStyle(
|
||||||
|
TableStyle(
|
||||||
|
[
|
||||||
|
("BACKGROUND", (0, 0), (-1, 0), colors.HexColor("#1565C0")),
|
||||||
|
("TEXTCOLOR", (0, 0), (-1, 0), colors.white),
|
||||||
|
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
|
||||||
|
("FONTSIZE", (0, 0), (-1, -1), 9),
|
||||||
|
("VALIGN", (0, 0), (-1, -1), "TOP"),
|
||||||
|
("GRID", (0, 0), (-1, -1), 0.5, colors.lightgrey),
|
||||||
|
("ROWBACKGROUNDS", (0, 1), (-1, -1), [colors.white, colors.HexColor("#F5F5F5")]),
|
||||||
|
("LEFTPADDING", (0, 0), (-1, -1), 6),
|
||||||
|
("RIGHTPADDING", (0, 0), (-1, -1), 6),
|
||||||
|
("TOPPADDING", (0, 0), (-1, -1), 4),
|
||||||
|
("BOTTOMPADDING", (0, 0), (-1, -1), 4),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
story.append(t)
|
||||||
|
story.append(PageBreak())
|
||||||
|
|
||||||
|
# --- Proposal 1 ---
|
||||||
|
story.append(p("2. Proposal: single outgoing stream (multicast)", h1))
|
||||||
|
story.append(
|
||||||
|
p(
|
||||||
|
"<b>Goal:</b> One encoded stream on the air; only handshake-authorized receivers consume it; "
|
||||||
|
"save ~(N−1) × bitrate vs today’s unicast fan-out.",
|
||||||
|
body,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
story.append(Spacer(1, 0.2 * cm))
|
||||||
|
story.append(
|
||||||
|
p(
|
||||||
|
"<b>Feasible</b> with UDP IP multicast + unicast handshake (group address, port, sessionId, PIN). "
|
||||||
|
"Handshake-only targeting without multicast does <b>not</b> reduce bandwidth. "
|
||||||
|
"TCP/QUIC cannot deliver true 1× Wi‑Fi airtime.",
|
||||||
|
body,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
story.append(Spacer(1, 0.3 * cm))
|
||||||
|
|
||||||
|
img2 = BUILD / MM[1][1]
|
||||||
|
if img2.exists():
|
||||||
|
story.append(p(MM[1][2], h2))
|
||||||
|
iw = 16 * cm
|
||||||
|
story.append(Image(str(img2), width=iw, height=iw * 0.55))
|
||||||
|
story.append(Spacer(1, 0.4 * cm))
|
||||||
|
|
||||||
|
story.append(p("2.1 Approach comparison", h2))
|
||||||
|
approaches = [
|
||||||
|
["Approach", "1× sender airtime?", "Notes"],
|
||||||
|
["Unicast fan-out (today)", "No", "Same encode; N × send()."],
|
||||||
|
["UDP multicast", "Yes on good LAN", "MulticastLock; AP client isolation risk."],
|
||||||
|
["Sender server, N TCP clients", "No", "Flip connect direction; still N wire copies."],
|
||||||
|
["LAN relay receiver", "Sender 1×", "Relay pays duplicate bandwidth."],
|
||||||
|
]
|
||||||
|
t2 = Table(approaches, colWidths=[4.5 * cm, 3.2 * cm, 8.8 * cm])
|
||||||
|
t2.setStyle(
|
||||||
|
TableStyle(
|
||||||
|
[
|
||||||
|
("BACKGROUND", (0, 0), (-1, 0), colors.HexColor("#1565C0")),
|
||||||
|
("TEXTCOLOR", (0, 0), (-1, 0), colors.white),
|
||||||
|
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
|
||||||
|
("FONTSIZE", (0, 0), (-1, -1), 9),
|
||||||
|
("VALIGN", (0, 0), (-1, -1), "TOP"),
|
||||||
|
("GRID", (0, 0), (-1, -1), 0.5, colors.lightgrey),
|
||||||
|
("ROWBACKGROUNDS", (0, 1), (-1, -1), [colors.white, colors.HexColor("#F5F5F5")]),
|
||||||
|
("LEFTPADDING", (0, 0), (-1, -1), 6),
|
||||||
|
("RIGHTPADDING", (0, 0), (-1, -1), 6),
|
||||||
|
("TOPPADDING", (0, 0), (-1, -1), 4),
|
||||||
|
("BOTTOMPADDING", (0, 0), (-1, -1), 4),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
story.append(t2)
|
||||||
|
story.append(Spacer(1, 0.3 * cm))
|
||||||
|
story.append(
|
||||||
|
p(
|
||||||
|
"<b>Protocol notes:</b> CastFramingContext.sessionId and CastSessionGate already support "
|
||||||
|
"session binding. FEC/NACK must become group-scoped (one retransmit cache, resend to multicast). "
|
||||||
|
"Existing code paths: MultiCastCoordinator, CastFanoutPump, UdpCastTransport.",
|
||||||
|
body,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
story.append(PageBreak())
|
||||||
|
|
||||||
|
# --- Proposal 2 ---
|
||||||
|
story.append(p("3. Proposal: multi-tier streams (e.g. full + 720p + 480p)", h1))
|
||||||
|
story.append(
|
||||||
|
p(
|
||||||
|
"<b>Goal:</b> Several encoded renditions from one capture; each receiver picks a tier at handshake "
|
||||||
|
"(e.g. full quality vs 480p for bandwidth-limited devices).",
|
||||||
|
body,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
story.append(Spacer(1, 0.2 * cm))
|
||||||
|
story.append(
|
||||||
|
p(
|
||||||
|
"<b>Feasible</b> via multiple encoders fed from one capture (EGL / scaled Surfaces into separate "
|
||||||
|
"MediaCodec instances). Cost scales with <b>active</b> tiers (~2–3 HW encoders typical phone limit; "
|
||||||
|
"3× software VP9 is heavy). Audio usually stays one AAC stream.",
|
||||||
|
body,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
story.append(Spacer(1, 0.2 * cm))
|
||||||
|
story.append(
|
||||||
|
p(
|
||||||
|
"<b>Bandwidth:</b> Unicast per tier → egress ≈ sum of each peer’s tier bitrate. "
|
||||||
|
"Multicast per tier → one group per tier; airtime ≈ sum of tiers with ≥1 subscriber.",
|
||||||
|
body,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
story.append(Spacer(1, 0.3 * cm))
|
||||||
|
story.append(p("3.1 Tier architecture options", h2))
|
||||||
|
tiers = [
|
||||||
|
["Option", "Verdict"],
|
||||||
|
["Multiple HW encoders from one capture", "Recommended v1."],
|
||||||
|
["One encode + CPU re-encode", "Too expensive for live cast."],
|
||||||
|
["SVC / simulcast in one bitstream", "Poor Android HW support; defer."],
|
||||||
|
["Receiver-only downscale", "Saves sender encode, not downlink bandwidth."],
|
||||||
|
]
|
||||||
|
t3 = Table(tiers, colWidths=[6 * cm, 10.5 * cm])
|
||||||
|
t3.setStyle(
|
||||||
|
TableStyle(
|
||||||
|
[
|
||||||
|
("BACKGROUND", (0, 0), (-1, 0), colors.HexColor("#1565C0")),
|
||||||
|
("TEXTCOLOR", (0, 0), (-1, 0), colors.white),
|
||||||
|
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
|
||||||
|
("FONTSIZE", (0, 0), (-1, -1), 9),
|
||||||
|
("GRID", (0, 0), (-1, -1), 0.5, colors.lightgrey),
|
||||||
|
("VALIGN", (0, 0), (-1, -1), "TOP"),
|
||||||
|
("ROWBACKGROUNDS", (0, 1), (-1, -1), [colors.white, colors.HexColor("#F5F5F5")]),
|
||||||
|
("LEFTPADDING", (0, 0), (-1, -1), 6),
|
||||||
|
("RIGHTPADDING", (0, 0), (-1, -1), 6),
|
||||||
|
("TOPPADDING", (0, 0), (-1, -1), 4),
|
||||||
|
("BOTTOMPADDING", (0, 0), (-1, -1), 4),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
story.append(t3)
|
||||||
|
story.append(PageBreak())
|
||||||
|
|
||||||
|
# --- Rollout ---
|
||||||
|
story.append(p("4. Recommended rollout", h1))
|
||||||
|
rollout = [
|
||||||
|
["Phase", "Deliverable", "Benefit"],
|
||||||
|
[
|
||||||
|
"A — Tier selection (unicast)",
|
||||||
|
"Handshake tier; 720p + 480p encoders; send chosen tier per peer",
|
||||||
|
"Per-device quality without multicast; no AP surprises",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"B — Multicast one tier",
|
||||||
|
"UDP multicast publish after unicast handshake",
|
||||||
|
"~(N−1) egress for same-quality 1:N",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"C — Multicast per tier",
|
||||||
|
"Separate multicast group per tier; lazy encoder start",
|
||||||
|
"Combines (1) and (2) on good LANs",
|
||||||
|
],
|
||||||
|
]
|
||||||
|
t4 = Table(rollout, colWidths=[3.5 * cm, 7.5 * cm, 5.5 * cm])
|
||||||
|
t4.setStyle(
|
||||||
|
TableStyle(
|
||||||
|
[
|
||||||
|
("BACKGROUND", (0, 0), (-1, 0), colors.HexColor("#1565C0")),
|
||||||
|
("TEXTCOLOR", (0, 0), (-1, 0), colors.white),
|
||||||
|
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
|
||||||
|
("FONTSIZE", (0, 0), (-1, -1), 9),
|
||||||
|
("GRID", (0, 0), (-1, -1), 0.5, colors.lightgrey),
|
||||||
|
("VALIGN", (0, 0), (-1, -1), "TOP"),
|
||||||
|
("ROWBACKGROUNDS", (0, 1), (-1, -1), [colors.white, colors.HexColor("#F5F5F5")]),
|
||||||
|
("LEFTPADDING", (0, 0), (-1, -1), 6),
|
||||||
|
("RIGHTPADDING", (0, 0), (-1, -1), 6),
|
||||||
|
("TOPPADDING", (0, 0), (-1, -1), 4),
|
||||||
|
("BOTTOMPADDING", (0, 0), (-1, -1), 4),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
story.append(t4)
|
||||||
|
story.append(Spacer(1, 0.4 * cm))
|
||||||
|
|
||||||
|
story.append(p("4.1 Summary judgment", h2))
|
||||||
|
summary = [
|
||||||
|
["Idea", "Feasible?", "Main win", "Main cost"],
|
||||||
|
[
|
||||||
|
"(1) Multicast + handshake gate",
|
||||||
|
"Yes (UDP)",
|
||||||
|
"~(N−1) uplink on good LAN",
|
||||||
|
"Transport refactor; FEC/NACK; AP testing",
|
||||||
|
],
|
||||||
|
["(1) Unicast only", "Trivial", "Auth only", "No bandwidth win"],
|
||||||
|
["(2) Multi-tier encode", "Yes", "Per-receiver quality", "2–3× encode resources"],
|
||||||
|
["(1) + (2) combined", "Yes", "Multicast per tier", "Highest complexity"],
|
||||||
|
]
|
||||||
|
t5 = Table(summary, colWidths=[4.2 * cm, 2.2 * cm, 4.5 * cm, 4.6 * cm])
|
||||||
|
t5.setStyle(
|
||||||
|
TableStyle(
|
||||||
|
[
|
||||||
|
("BACKGROUND", (0, 0), (-1, 0), colors.HexColor("#1565C0")),
|
||||||
|
("TEXTCOLOR", (0, 0), (-1, 0), colors.white),
|
||||||
|
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
|
||||||
|
("FONTSIZE", (0, 0), (-1, -1), 8),
|
||||||
|
("GRID", (0, 0), (-1, -1), 0.5, colors.lightgrey),
|
||||||
|
("VALIGN", (0, 0), (-1, -1), "TOP"),
|
||||||
|
("ROWBACKGROUNDS", (0, 1), (-1, -1), [colors.white, colors.HexColor("#F5F5F5")]),
|
||||||
|
("LEFTPADDING", (0, 0), (-1, -1), 4),
|
||||||
|
("RIGHTPADDING", (0, 0), (-1, -1), 4),
|
||||||
|
("TOPPADDING", (0, 0), (-1, -1), 4),
|
||||||
|
("BOTTOMPADDING", (0, 0), (-1, -1), 4),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
story.append(t5)
|
||||||
|
story.append(Spacer(1, 0.5 * cm))
|
||||||
|
story.append(
|
||||||
|
p(
|
||||||
|
"<b>Key code paths today:</b> CastConfig.MAX_RECEIVERS, MultiCastCoordinator, "
|
||||||
|
"CastFanoutPump, ScreenCastService (primary peer), UdpCastTransport, CastFramingContext, "
|
||||||
|
"CastSessionGate.",
|
||||||
|
small,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
doc = SimpleDocTemplate(
|
||||||
|
str(OUT_PDF),
|
||||||
|
pagesize=A4,
|
||||||
|
leftMargin=1.8 * cm,
|
||||||
|
rightMargin=1.8 * cm,
|
||||||
|
topMargin=1.5 * cm,
|
||||||
|
bottomMargin=1.5 * cm,
|
||||||
|
title="Android Cast — Next-gen egress review",
|
||||||
|
author="Android Cast project",
|
||||||
|
)
|
||||||
|
doc.build(story)
|
||||||
|
print(f"Wrote {OUT_PDF}")
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
render_mermaid()
|
||||||
|
build_pdf()
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
15
docs/_pdf_build/diagram_current_arch.mmd
Normal file
15
docs/_pdf_build/diagram_current_arch.mmd
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
flowchart LR
|
||||||
|
subgraph once [Once per cast]
|
||||||
|
Cap[MediaProjection capture]
|
||||||
|
Enc[Video and audio encoders]
|
||||||
|
Q[CastFanoutPump queues]
|
||||||
|
end
|
||||||
|
subgraph perPeer [Per receiver today]
|
||||||
|
S1[CastSession 1 UDP or TCP]
|
||||||
|
S2[CastSession 2]
|
||||||
|
SN[CastSession N]
|
||||||
|
end
|
||||||
|
Cap --> Enc --> Q
|
||||||
|
Q -->|same encoded payload| S1
|
||||||
|
Q --> S2
|
||||||
|
Q --> SN
|
||||||
BIN
docs/_pdf_build/diagram_current_arch.png
Normal file
BIN
docs/_pdf_build/diagram_current_arch.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
9
docs/_pdf_build/diagram_multicast_proposal.mmd
Normal file
9
docs/_pdf_build/diagram_multicast_proposal.mmd
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
sequenceDiagram
|
||||||
|
participant S as Sender
|
||||||
|
participant R1 as Receiver 1
|
||||||
|
participant R2 as Receiver N
|
||||||
|
S->>R1: Unicast handshake PIN codec tier
|
||||||
|
S->>R2: Unicast handshake
|
||||||
|
Note over S: One encoder one sessionId
|
||||||
|
S-->>R1: Multicast media packets
|
||||||
|
S-->>R2: Same packets
|
||||||
BIN
docs/_pdf_build/diagram_multicast_proposal.png
Normal file
BIN
docs/_pdf_build/diagram_multicast_proposal.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
Reference in New Issue
Block a user