1
0
mirror of git://f0xx.org/android_cast synced 2026-07-29 04:57:40 +03:00

all sync, docs mostly

This commit is contained in:
Anton Afanasyeu
2026-06-18 16:39:49 +02:00
parent 017b6ddf25
commit 55cdcb49bf
40 changed files with 2329 additions and 127 deletions

View File

@@ -483,7 +483,7 @@ endobj
endobj
81 0 obj
<<
/Author (Android Cast project) /CreationDate (D:20260616121121+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260616121121+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Author (Android Cast project) /CreationDate (D:20260617220445+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260617220445+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (Android Cast \204 On-Demand Remote Access \(Reverse Tunnel\) Proposals) /Trapped /False
>>
endobj
@@ -1052,7 +1052,7 @@ xref
trailer
<<
/ID
[<ab8688a2e86c2f05c59259be39690dd5><ab8688a2e86c2f05c59259be39690dd5>]
[<3f94d39cd85223d5686ff0349cc56520><3f94d39cd85223d5686ff0349cc56520>]
% ReportLab generated PDF document -- digest (opensource)
/Info 81 0 R

View File

@@ -265,7 +265,7 @@ endobj
endobj
42 0 obj
<<
/Author (Android Cast project) /CreationDate (D:20260616121121+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260616121121+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Author (Android Cast project) /CreationDate (D:20260617220445+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260617220445+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (Android Cast \204 Email agent config & 2FA / mobile auth flow) /Trapped /False
>>
endobj
@@ -537,7 +537,7 @@ xref
trailer
<<
/ID
[<9b9be03de41f665ab211a19780765fb6><9b9be03de41f665ab211a19780765fb6>]
[<8e9582b9d629fb33039bda9127c34432><8e9582b9d629fb33039bda9127c34432>]
% ReportLab generated PDF document -- digest (opensource)
/Info 42 0 R

View File

@@ -208,7 +208,7 @@ endobj
endobj
33 0 obj
<<
/Author (Android Cast project) /CreationDate (D:20260616121122+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260616121122+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Author (Android Cast project) /CreationDate (D:20260617220445+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260617220445+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (Android Cast \204 alpha priorities \(2026-06-08 renumber\)) /Trapped /False
>>
endobj
@@ -418,7 +418,7 @@ xref
trailer
<<
/ID
[<373c648a4decb94fdad2e447f53ba30b><373c648a4decb94fdad2e447f53ba30b>]
[<cbeebf3abfc4c12ed8adf1ecbcb8d5a4><cbeebf3abfc4c12ed8adf1ecbcb8d5a4>]
% ReportLab generated PDF document -- digest (opensource)
/Info 33 0 R

View File

@@ -203,7 +203,7 @@ endobj
endobj
31 0 obj
<<
/Author (Android Cast project) /CreationDate (D:20260616121122+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260616121122+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Author (Android Cast project) /CreationDate (D:20260617220446+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260617220446+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (BE services & infrastructure \204 validation map) /Trapped /False
>>
endobj
@@ -385,7 +385,7 @@ xref
trailer
<<
/ID
[<4df0697a410fb791a9ad2c4da6bce9bb><4df0697a410fb791a9ad2c4da6bce9bb>]
[<33842309a5332be4e933481fb5cc3564><33842309a5332be4e933481fb5cc3564>]
% ReportLab generated PDF document -- digest (opensource)
/Info 31 0 R

View File

@@ -137,7 +137,7 @@ endobj
endobj
22 0 obj
<<
/Author (Android Cast project) /CreationDate (D:20260616121122+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260616121122+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Author (Android Cast project) /CreationDate (D:20260617220446+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260617220446+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (Stream dump \204 developer debug recording \(FR 0.1\)) /Trapped /False
>>
endobj
@@ -277,7 +277,7 @@ xref
trailer
<<
/ID
[<d5199be1b9289b743a4b5a7e9d5e6fce><d5199be1b9289b743a4b5a7e9d5e6fce>]
[<9df46fa4be55aef5251ba708945ef660><9df46fa4be55aef5251ba708945ef660>]
% ReportLab generated PDF document -- digest (opensource)
/Info 22 0 R

View File

@@ -275,7 +275,7 @@ endobj
endobj
47 0 obj
<<
/Author (Android Cast project) /CreationDate (D:20260616121122+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260616121122+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Author (Android Cast project) /CreationDate (D:20260617220446+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260617220446+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (Android Cast \204 exposed services catalog) /Trapped /False
>>
endobj
@@ -589,7 +589,7 @@ xref
trailer
<<
/ID
[<31f0eae15bf1213465266b8d555540ce><31f0eae15bf1213465266b8d555540ce>]
[<3bea3360dfff53d8101b105e2ed9c80c><3bea3360dfff53d8101b105e2ed9c80c>]
% ReportLab generated PDF document -- digest (opensource)
/Info 47 0 R

View File

@@ -183,7 +183,7 @@ endobj
endobj
30 0 obj
<<
/Author (Android Cast project) /CreationDate (D:20260616121122+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260616121122+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Author (Android Cast project) /CreationDate (D:20260617220446+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260617220446+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (Android Cast \204 alpha release & QA) /Trapped /False
>>
endobj
@@ -377,7 +377,7 @@ xref
trailer
<<
/ID
[<0fe2b532305c2f37dd6c62ca6bdde964><0fe2b532305c2f37dd6c62ca6bdde964>]
[<ef2f91cbe4ea30aef08962c29d279824><ef2f91cbe4ea30aef08962c29d279824>]
% ReportLab generated PDF document -- digest (opensource)
/Info 30 0 R

View File

@@ -122,7 +122,7 @@ endobj
endobj
20 0 obj
<<
/Author (Android Cast project) /CreationDate (D:20260616121122+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260616121122+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Author (Android Cast project) /CreationDate (D:20260617220446+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260617220446+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (Alpha soak checklist \(LAN demo\)) /Trapped /False
>>
endobj
@@ -240,7 +240,7 @@ xref
trailer
<<
/ID
[<53b93f56e4ba8440cb5af34509f955e7><53b93f56e4ba8440cb5af34509f955e7>]
[<933980664bcbdbdfe6a12d9cb1786fa3><933980664bcbdbdfe6a12d9cb1786fa3>]
% ReportLab generated PDF document -- digest (opensource)
/Info 20 0 R

View File

@@ -244,7 +244,7 @@ endobj
endobj
40 0 obj
<<
/Author (Android Cast project) /CreationDate (D:20260616121122+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260616121122+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Author (Android Cast project) /CreationDate (D:20260617220446+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260617220446+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (AV quality enhancement \204 Q&A session notes) /Trapped /False
>>
endobj
@@ -512,7 +512,7 @@ xref
trailer
<<
/ID
[<bede30ec80558c24da73d8816f8031d9><bede30ec80558c24da73d8816f8031d9>]
[<ad9c835cc704152d28b5b3f7ebff6df3><ad9c835cc704152d28b5b3f7ebff6df3>]
% ReportLab generated PDF document -- digest (opensource)
/Info 40 0 R

View File

@@ -137,7 +137,7 @@ endobj
endobj
22 0 obj
<<
/Author (Android Cast project) /CreationDate (D:20260616121122+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260616121122+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Author (Android Cast project) /CreationDate (D:20260617220446+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260617220446+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (Android Cast build ecosystem) /Trapped /False
>>
endobj
@@ -278,7 +278,7 @@ xref
trailer
<<
/ID
[<cd81a7e6527e122406b62353aa6bcb61><cd81a7e6527e122406b62353aa6bcb61>]
[<6cfcadb37be859dd22566ebb5a6a8025><6cfcadb37be859dd22566ebb5a6a8025>]
% ReportLab generated PDF document -- digest (opensource)
/Info 22 0 R

View File

@@ -97,7 +97,7 @@ endobj
endobj
15 0 obj
<<
/Author (Android Cast project) /CreationDate (D:20260616121122+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260616121122+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Author (Android Cast project) /CreationDate (D:20260617220446+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260617220446+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (Commercial features \(developer-gated\)) /Trapped /False
>>
endobj
@@ -192,7 +192,7 @@ xref
trailer
<<
/ID
[<75a8219b0a798c01075a0cec99453c43><75a8219b0a798c01075a0cec99453c43>]
[<c8d6b37b537060a0dc93294feeb6bfd7><c8d6b37b537060a0dc93294feeb6bfd7>]
% ReportLab generated PDF document -- digest (opensource)
/Info 15 0 R

View File

@@ -102,7 +102,7 @@ endobj
endobj
16 0 obj
<<
/Author (Android Cast project) /CreationDate (D:20260616121122+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260616121122+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Author (Android Cast project) /CreationDate (D:20260617220446+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260617220446+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (Anonymous crash reporter) /Trapped /False
>>
endobj
@@ -198,7 +198,7 @@ xref
trailer
<<
/ID
[<bd4acbd898c52ce55620c92c6ac9a846><bd4acbd898c52ce55620c92c6ac9a846>]
[<50b171b4584914c2210e49fce78dc2be><50b171b4584914c2210e49fce78dc2be>]
% ReportLab generated PDF document -- digest (opensource)
/Info 16 0 R

View File

@@ -279,7 +279,7 @@ endobj
endobj
46 0 obj
<<
/Author (Android Cast project) /CreationDate (D:20260616121122+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260616121122+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Author (Android Cast project) /CreationDate (D:20260617220446+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260617220446+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (URL shortener service \204 design review \(DR\)) /Trapped /False
>>
endobj
@@ -553,7 +553,7 @@ xref
trailer
<<
/ID
[<df66ecc393a2b137e06a511c1fbe529e><df66ecc393a2b137e06a511c1fbe529e>]
[<3a7c0ee4bbf3482849eeadc12de9b9c8><3a7c0ee4bbf3482849eeadc12de9b9c8>]
% ReportLab generated PDF document -- digest (opensource)
/Info 46 0 R

View File

@@ -498,7 +498,7 @@ endobj
endobj
79 0 obj
<<
/Author (Android Cast project) /CreationDate (D:20260616121123+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260616121123+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Author (Android Cast project) /CreationDate (D:20260617220446+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260617220446+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (Platform scaling and multi-environment architecture \204 design review \(DR\)) /Trapped /False
>>
endobj
@@ -933,7 +933,7 @@ xref
trailer
<<
/ID
[<6faf855138e92333540e6bef33a787f8><6faf855138e92333540e6bef33a787f8>]
[<cc552ef08a2fe35d84129cecaf25d843><cc552ef08a2fe35d84129cecaf25d843>]
% ReportLab generated PDF document -- digest (opensource)
/Info 79 0 R

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,375 @@
# Codec2 / ultra-low-bandwidth voice — design review (DR)
<!-- doc-meta:start -->
| Field | Value |
|---|---|
| Author | Anton Afanasyeu |
| Revision | R0 |
| Creation date | 2026-06-17 |
| Last modification date | 2026-06-17 |
| Co-authored | Cursor Agent (project assistant) |
| Severity | low |
| State | approved for planning (implementation post-alpha) |
| Document type | DR |
| Pre-requisite to | [ROADMAP.md](../ROADMAP.md) §6.1 Opus/Speex JNI encode/decode; F1 SFU SPEC (post-alpha) |
<!-- doc-meta:end -->
\newpage
\newpage
---
**Document type:** DR (Design Review)
**Source draft:** [docs/drafts/20260617_codec2_ulbw_voice_integration.txt](../drafts/20260617_codec2_ulbw_voice_integration.txt)
**PDF:** [20260617_codec2_ulbw_voice.pdf](20260617_codec2_ulbw_voice.pdf) · Regenerate: `bash scripts/build-all-docs-pdf.sh`
**Status:** PO-reviewed (inline draft comments incorporated) — **no native implementation** until Opus/Speex JNI sinks land
**Scope:** Voice-only / ULBW audio cast on P2P (LAN, BT, mesh); future MCU/SFU relay hooks
**Related:** [OPUS_SPEEX_VALIDATION.md](../OPUS_SPEEX_VALIDATION.md) · [ndk/README.md](../../ndk/README.md) · [20260608_BE_SERVICES_and_infra.md](../20260608_BE_SERVICES_and_infra.md) § SFU · [specs/20100612_1_scaling.md](../specs/20100612_1_scaling.md) F1
**Documentation index:** [README.md](../README.md)
---
---
---
## Table of contents
<!-- toc -->
- [1. Executive summary](#1-executive-summary)
- [2. Problem statement](#2-problem-statement)
- [3. Vocabulary](#3-vocabulary)
- [4. Current state (mobile + BE)](#4-current-state-mobile--be)
- [5. Codec landscape and PO decisions](#5-codec-landscape-and-po-decisions)
- [6. Goals and non-goals](#6-goals-and-non-goals)
- [7. Mobile peer negotiation (today)](#7-mobile-peer-negotiation-today)
- [8. Proposed mobile integration](#8-proposed-mobile-integration)
- [9. Future backend: MCU / SFU](#9-future-backend-mcu--sfu)
- [10. Protocol extensions](#10-protocol-extensions)
- [11. Third-party and licenses](#11-third-party-and-licenses)
- [12. Testing and validation](#12-testing-and-validation)
- [13. Task dependency graph](#13-task-dependency-graph)
- [14. Risks](#14-risks)
- [15. Open questions (remaining)](#15-open-questions-remaining)
- [16. Changelog](#16-changelog)
<!-- /toc -->
---
## 1. Executive summary
**Question:** Should androidcast integrate **Codec2** for ultra-low-bandwidth (ULBW) **voice-only** casts when normal AAC/Opus paths are too heavy for the link?
**Short answer:** **Yes, as a post-alpha product slice** — not a lab experiment. End users on marginal links (BT P2P, slow mesh, very poor LTE) should get **intelligible audio** (“something rather than nothing”). **Codec2 @ 3200 bit/s** (and lower modes where needed) fits that goal better than Opus narrowband @ ~6 kbps + FEC in POs practical experience (lower sustained bandwidth, less audible noise on those links).
**DR decision (R0):**
| Item | Decision |
|------|----------|
| **Primary use case** | **Voice-only** ULBW cast; not the audio leg of full screen cast (8 kHz telephony; no lip-sync with HD video) |
| **Codec2 modes** | **3200 bit/s** default target; **700C** for extreme BT/mesh; user/dev sub-mode selection |
| **MELP / TWELP** | **Out of scope** (patent / slim OSS path) |
| **AAC** | Keep as platform MediaCodec path; no license conflict for screen cast |
| **Opus / Speex** | Finish **JNI encode/decode** first ([ROADMAP.md](../ROADMAP.md) — cross-compile done, sinks **TODO**); negotiation/scaffolding exists today but wire path is **stub → AAC** without `libopus.a` / encode JNI |
| **Codec2 timing** | After **6.1** JNI baseline; behind dev flag until E2E validated |
| **SFU / MCU** | Plan **transcode at ingress** (Codec2 → Opus) for mixed WebRTC rooms; separate F1 SPEC — signaling reuses extended audio caps |
| **MSG_AUDIO_SELECTED** | Add in handshake when Codec2 implementation starts (SETTINGS_VERSION bump) — aligns P2P multicast and SFU data channel |
---
## 2. Problem statement
Screen cast defaults to **AAC** (32128 kbps class). Negotiation already advertises **Opus** and **Speex**, but without native encode/decode the sender often still ships **AAC** while labeling Opus in diagnostics.
For **ULBW** links:
- Opus @ 6 kbps + FEC/NACK can exceed the sustained budget PO has seen on BT/mesh and adds noise versus Codec2-class vocoders.
- Users still want **audio cast** (commentary, coordination, voice relay) when video is impossible — a deliberate **voice-only** mode.
Future **multipoint** (F1 SFU/MCU) cannot rely on pairwise discovery bitmasks alone; room-level **negotiated_audio** must be defined before Codec2 legs join a relay.
---
## 3. Vocabulary
| Term | Meaning |
|------|---------|
| **ULBW** | Ultra-low bandwidth; sustained **&lt; 34 kbps** audio payload target on worst links |
| **Voice-only cast** | No video track; discovery may send `videoCodecs = 0` |
| **Radio mode** | Dev/user profile preferring Codec2 in AUTO when both peers advertise `AUDIO_CODEC2` |
| **P2P negotiation** | `CastProtoHeader.audioCodecs` bitmask + `AudioNegotiator` (today) |
| **Room negotiation** | Signaling API + server-published codec (SFU future) |
| **SFU** | Selective forwarding unit — relay without per-subscriber transcode |
| **MCU** | Mix decode → PCM → encode; needed for heterogeneous legs |
---
## 4. Current state (mobile + BE)
### 4.1 Audio codecs in app
| Layer | Opus / Speex today | Notes |
|-------|-------------------|-------|
| `CastCodecFlags` | `AUDIO_OPUS=4`, `AUDIO_SPEEX=8` | Masks advertised in discovery |
| `AudioNegotiator` | Works | AUTO scoring via `CodecPriorityCatalog` |
| `NativeCodecBridge` | **Probe only** (`nativeIsOpusAvailable`) | No encode/decode JNI in `opus_bridge.c` / `speex_bridge.c` |
| Wire path | **OPUS_STUB / SPEEX_STUB → AAC** | `PassthroughCodecPolicy`, `AudioCodecFactory` |
| Build | `scripts/build-native-codecs.sh` can link `.a` | [ROADMAP.md](../ROADMAP.md): JNI sinks **TODO** |
**Clarification for PO:** Prior agent work completed **negotiation, settings UI, priority catalog, and native autolink scaffolding** — not full Opus/Speex on-the-wire encoding. Task **6.1** remains open for JNI sinks + E2E per [OPUS_SPEEX_VALIDATION.md](../OPUS_SPEEX_VALIDATION.md).
### 4.2 Video vs audio negotiation asymmetry
```mermaid
sequenceDiagram
participant S as Sender
participant R as Receiver
Note over S,R: Discovery: audioCodecs bitmask in header
S->>R: MSG_HELLO, CAST_SETTINGS
S->>R: MSG_CODEC_CAPS (video MIME list)
R->>S: MSG_RECEIVER_CAST_SETTINGS
R->>S: MSG_CODEC_CAPS
R->>S: MSG_CODEC_SELECTED (video MIME only)
Note over S: AudioNegotiator.resolveForSender(peerMask)
Note over R: No MSG_AUDIO_SELECTED today
```
### 4.3 Backend (gray)
- `SfuRelayGate.PREVIEW_ENABLED = false`; `api/sfu_health.php` returns disabled.
- Janus on **:8089** is **other stack** — androidcast signaling stays on `apps.f0xx.org` PHP ([INFRA.md](../INFRA.md)).
---
## 5. Codec landscape and PO decisions
| Codec | Bitrate | Role in androidcast | DR decision |
|-------|---------|---------------------|-------------|
| **Codec2** | 7003200 bps | ULBW voice-only | **Integrate** (post-6.1) |
| **Opus SILK NB** | ~612 kbps | General narrowband when link allows | Finish JNI; keep in AUTO above Codec2 only when bandwidth sufficient |
| **Speex NB** | ~215 kbps | Legacy / fallback | Finish JNI |
| **AAC-LC** | 32+ kbps | Screen cast default | Unchanged |
| **MELP/TWELP** | ~2.4 kbps | — | **Rejected** |
**PO rationale (2026-06-17):** Opus @ 6k + FEC is **heavier and noisier** than Codec2 on target links; Codec2 **3200 bps** meets product goals; intent is **end-user value**, not codec shootout lab work.
**Maintainer risk:** Codec2 upstream is in active re-development; pin submodule tag (e.g. 1.2.0) and mirror on Gitea like `third-party/opus`.
---
## 6. Goals and non-goals
### Goals
- Voice-only cast mode with **Codec2 encode/decode** on Android (NDK).
- Extend **peer negotiation** (`AUDIO_CODEC2 = 16`, optional `MSG_AUDIO_SELECTED`).
- Document **SFU ingress transcode** and room caps for F1 SPEC.
- LGPL compliance + license files.
### Non-goals (R0)
- MELP/TWELP integration.
- Codec2 as default for **screen cast with video**.
- SFU passthrough-only design (closed Android mesh edge case only).
- Alpha ship — hidden until E2E + PO QA.
---
## 7. Mobile peer negotiation (today)
| Step | Mechanism | Codec2 impact |
|------|-----------|---------------|
| Advertise | `CastCodecFlags.localAudioMask()` in discovery | Add bit 16 when native probe passes |
| Resolve | `AudioNegotiator.negotiate(senderMask, receiverMask, pref, settings)` | Add `CODEC2` to enum + `CodecPriorityId` |
| Score | `codecs.json` + `CodecPriorityCatalog` | ULBW profile: CODEC2 lowest `bitrate_score` |
| Wire | Audio frames (today AAC ADTS) | New codec tag or `MSG_AUDIO_FRAME` subtype |
**Gap:** Receiver does not receive explicit audio selection — sender-resolved only. **Must fix** before multicast + SFU (§10).
---
## 8. Proposed mobile integration
### 8.1 Settings and enum
```text
CastSettings.AudioCodec.CODEC2
CastSettings.codec2Mode: 3200 | 1300 | 700C (default 3200 per PO)
CastSettings.VoiceOnlyMode: boolean
```
### 8.2 Native stack
1. `third-party/codec2` submodule + `scripts/init-third-party-submodules.sh`
2. `scripts/build-native-codecs.sh``libcodec2.a`, `ANDROIDCAST_HAVE_CODEC2`
3. JNI: `isCodec2Available()`, encode/decode **8 kHz mono** frames
4. Link via existing `libandroidcast_codecs.so`
### 8.3 Priority (ULBW profile)
Suggested AUTO order when `NetworkAdoption.ESTIMATED` or **radio mode** on:
**CODEC2 → OPUS → SPEEX → AAC → PCM**
### 8.4 Milestones
| # | Deliverable | Depends on |
|---|-------------|------------|
| M1 | Opus/Speex JNI encode/decode + E2E | 6.1 |
| M2 | Codec2 probe + round-trip unit test | M1 |
| M3 | Voice-only UI slice (dev gate) | M2 |
| M4 | `MSG_AUDIO_SELECTED` + SETTINGS_VERSION | M2 |
| M5 | SFU signaling fields in F1 SPEC | Owner SFU spec |
---
## 9. Future backend: MCU / SFU
```mermaid
flowchart TB
subgraph clients [Android clients]
A[Sender A Codec2]
B[Sender B Opus]
C[Receiver WebRTC]
end
subgraph be [BE post-alpha]
SIG[Signaling API PHP]
SFU[Janus / media worker]
end
A --> SIG
B --> SIG
SIG --> SFU
SFU -->|transcode| C
SFU -->|fan-out Opus| B
```
### 9.1 Negotiation shift (P2P → room)
| Layer | P2P today | SFU future |
|-------|-----------|------------|
| Caps | Header bitmask | `join` JSON: `audio_caps.bitmask`, `codec2_modes[]` |
| Pick | `AudioNegotiator` local | Server `negotiated_audio` |
| Auth | PIN / LAN | Session RBAC + room token |
### 9.2 Codec2 on media plane (DR preference)
| Mode | When | CPU on be-media-N |
|------|------|-------------------|
| **Transcode ingress** | Mixed room (Android + browser) | **Recommended** — decode Codec2 → Opus egress |
| Passthrough | All Codec2 clients | Low CPU; no WebRTC viewers |
| MCU mix | Conference voice | High CPU; radio bridge legs only |
**Signaling sketch** (F1 SPEC — not implemented):
- `POST /api/sfu/room``ingress_caps: [opus, codec2]`, `egress_caps: [opus]`
- `POST /api/sfu/room/{id}/join` — returns transport params + `negotiated_audio`
Mobile: `SfuSignalingClient` fills `CastSettings.resolvedAudioCodec` from server; **LAN fallback** if signaling down.
---
## 10. Protocol extensions
### 10.1 `CastCodecFlags`
```text
AUDIO_CODEC2 = 16 // next free bit after SPEEX=8
```
### 10.2 `MSG_AUDIO_SELECTED` (recommended at M4)
```text
payload: uint32 audio_flag (little-endian) + uint8 codec2_mode_id
```
Symmetric with `MSG_CODEC_SELECTED`; reusable on WebRTC data channel.
### 10.3 `CastSettings.SETTINGS_VERSION`
Bump when adding `sfu_room_id`, `relay_mode`, `server_negotiated_audio` (SFU phase).
---
## 11. Third-party and licenses
| Component | License | Action |
|-----------|---------|--------|
| codec2 (libcodec2) | LGPL-2.1 | Submodule + Gitea mirror; dynamic link in `.so` |
| Opus / Speex | BSD | Existing |
| ffmpeg (SFU transcode) | LGPL/GPL | BE media worker SPEC only |
Update mobile `LICENSES` / notices when submodule added ([bottomline_reminder.txt](../../bottomline_reminder.txt)).
---
## 12. Testing and validation
| Phase | Tests |
|-------|-------|
| Unit | `AudioNegotiatorTest` CODEC2 mask; `CastProtoHeader` round-trip |
| Native | JNI c2enc/c2dec parity arm64-v8a |
| E2E | Extend [OPUS_SPEEX_VALIDATION.md](../OPUS_SPEEX_VALIDATION.md) — voice-only, UDP/TCP, diagnostics kbps |
| SFU | Post-alpha: 2× Codec2 Android + 1× WebRTC viewer via transcode |
---
## 13. Task dependency graph
```mermaid
flowchart TB
A61["6.1 Opus/Speex JNI sinks<br/>Developer · P5"]
C2["Codec2 NDK + voice-only<br/>Agent · post-alpha"]
AUDIO_HS["MSG_AUDIO_SELECTED<br/>Agent"]
SFU["F1 SFU SPEC + signaling<br/>PO · post-alpha"]
TRANS["SFU Codec2 transcode worker<br/>BE media"]
A61 --> C2
C2 --> AUDIO_HS
AUDIO_HS --> SFU
SFU --> TRANS
style A61 fill:#b45309,color:#fff
style C2 fill:#7c3aed,color:#fff
style SFU fill:#e5e7eb,color:#374151
```
**Numbered priority (PO overrides AI):**
1. **6.1** — Opus/Speex JNI (alpha LAN quality path; unblocks honest ULBW comparison)
2. **Codec2 ULBW** — this DR (parallel after M1 green)
3. **F1 SFU SPEC** — room negotiation + transcode
4. Alpha blockers **5.1 / 5.2 / 4.rssh** remain above on [OPEN_TASKS_GRAPH.md](../OPEN_TASKS_GRAPH.md)
---
## 14. Risks
| Risk | Mitigation |
|------|------------|
| Codec2 upstream churn | Pin tag; Gitea mirror |
| 8 kHz-only confuses users expecting music | Voice-only mode UX; no video leg |
| SFU CPU cost | Ingress transcode budget in scaling SPEC |
| Opus/Speex “done” confusion | ROADMAP + this DR state JNI sinks explicitly |
| BT latency 150300 ms | Document; jitter buffer 80120 ms |
---
## 15. Open questions (remaining)
| # | Question | Owner |
|---|----------|-------|
| 1 | SFU commercial story: always transcode vs optional passthrough mesh? | PO |
| 2 | Ship Codec2 in AUTO on ULBW profile or explicit “radio mode” only? | PO + UX |
| 3 | `700C` exposed to end users or dev-only? | PO |
**Resolved by PO (2026-06-17):** voice-only ULBW product intent; Codec2 3200 OK; skip MELP/TWELP; Opus @ 6k insufficient for target links; AAC platform use OK.
---
## 16. Changelog
| Rev | Date | Change |
|-----|------|--------|
| R0 | 2026-06-17 | Initial DR from draft; PO inline comments; Opus/Speex JNI status clarified |

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -42,7 +42,7 @@ endobj
endobj
7 0 obj
<<
/Author (Android Cast project) /CreationDate (D:20260616121134+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260616121134+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Author (Android Cast project) /CreationDate (D:20260617220511+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260617220511+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (Grafana vs Others GraphVis Pivot) /Trapped /False
>>
endobj
@@ -81,7 +81,7 @@ xref
trailer
<<
/ID
[<72a4394cac60eeec138c965dc18fed12><72a4394cac60eeec138c965dc18fed12>]
[<10a588f5438fd4e86531a2b28eee10c1><10a588f5438fd4e86531a2b28eee10c1>]
% ReportLab generated PDF document -- digest (opensource)
/Info 7 0 R

View File

@@ -183,7 +183,7 @@ endobj
endobj
30 0 obj
<<
/Author (Android Cast project) /CreationDate (D:20260616121123+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260616121123+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Author (Android Cast project) /CreationDate (D:20260617220500+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260617220500+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (Android Cast \204 production infrastructure) /Trapped /False
>>
endobj
@@ -376,7 +376,7 @@ xref
trailer
<<
/ID
[<73a81a3ce178ce7964b1217079da8449><73a81a3ce178ce7964b1217079da8449>]
[<535797484fc3ea7f6c0c9067cdb5b8d8><535797484fc3ea7f6c0c9067cdb5b8d8>]
% ReportLab generated PDF document -- digest (opensource)
/Info 30 0 R

View File

@@ -142,7 +142,7 @@ endobj
endobj
23 0 obj
<<
/Author (Android Cast project) /CreationDate (D:20260616121123+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260616121123+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Author (Android Cast project) /CreationDate (D:20260617220500+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260617220500+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (Crash console \204 open ingest API \(design\)) /Trapped /False
>>
endobj
@@ -289,7 +289,7 @@ xref
trailer
<<
/ID
[<f557a648e1f9e4567e03c8107a24e6bf><f557a648e1f9e4567e03c8107a24e6bf>]
[<f785af38a27e85b78bc868cfd8895ae6><f785af38a27e85b78bc868cfd8895ae6>]
% ReportLab generated PDF document -- digest (opensource)
/Info 23 0 R

View File

@@ -93,7 +93,7 @@ _Last synced: 2026-06-04 (RSSH full stack on `feature/rssh-alpha`, RA control HT
| **P4b** | **4.rssh** deploy soak | **Yes** (alpha essential) |
| **P5** | **6.16.6** app LAN | LAN alpha |
| **P9** | **9.x** landing (excl. globe FR) | No |
| **Post-alpha** | **SFU** relay | No |
| **Post-alpha** | **SFU** relay, **ULBW Codec2** voice | No |
---
@@ -127,6 +127,7 @@ flowchart TB
subgraph POST["Post-alpha"]
SFU["SFU / Janus relay"]
ULBW["Codec2 ULBW voice<br/>DR R0 · after 6.1"]
end
FULL["FULL_ALPHA<br/>no DNS/mail"]
@@ -142,12 +143,15 @@ flowchart TB
A65 --> A66
SFU -.-> FULL
A61 --> ULBW
ULBW -.-> SFU
style FULL fill:#1e3a5f,color:#fff
style OTA fill:#991b1b,color:#fff
style URL fill:#b45309,color:#fff
style RSSH fill:#7c3aed,color:#fff
style SFU fill:#e5e7eb,color:#374151
style ULBW fill:#e5e7eb,color:#374151
```
---
@@ -164,6 +168,7 @@ flowchart TB
| **9.x** | Agent (low) | — | Open |
| **cluster0** | Agent | NFS/DNS | cast0103 lab |
| **SFU** | Agent | owner spec | Hidden |
| **ULBW** | Agent | 6.1 JNI | DR R0 — [20260617_codec2_ulbw_voice.md](DRs/20260617_codec2_ulbw_voice.md) |
---
@@ -176,7 +181,7 @@ ALPHA: 4.rssh deploy (FE stream + BE sshd + app) ───┤
OPTIONAL: 5.5 RBAC UI click-through ────────────────────┤
DEV: 6.2 LAN soak ────────────────────────────────┘
Parallel: cluster0 lab (c1c3.acl0.f0xx.org), 6.1/6.36.6, 9.x, SFU
Parallel: cluster0 lab (c1c3.acl0.f0xx.org), 6.1/6.36.6, 9.x, SFU, ULBW Codec2 (post-6.1)
Off graph: 2.x DNS/mail (postponed)
```

File diff suppressed because one or more lines are too long

View File

@@ -163,7 +163,7 @@ endobj
endobj
27 0 obj
<<
/Author (Android Cast project) /CreationDate (D:20260616121124+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260616121124+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Author (Android Cast project) /CreationDate (D:20260617220502+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260617220502+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (Opus / Speex / stream protection \204 validation checklist \(task 3\)) /Trapped /False
>>
endobj
@@ -333,7 +333,7 @@ xref
trailer
<<
/ID
[<f9cf19f3d5280412cbf1fab060da5943><f9cf19f3d5280412cbf1fab060da5943>]
[<09eae2d38beac43ddd775c1a746bf63e><09eae2d38beac43ddd775c1a746bf63e>]
% ReportLab generated PDF document -- digest (opensource)
/Info 27 0 R

View File

@@ -142,7 +142,7 @@ endobj
endobj
23 0 obj
<<
/Author (Android Cast project) /CreationDate (D:20260616121124+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260616121124+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Author (Android Cast project) /CreationDate (D:20260617220502+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260617220502+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (Over-the-air \(OTA\) updates \204 deployment schema **v0**) /Trapped /False
>>
endobj
@@ -290,7 +290,7 @@ xref
trailer
<<
/ID
[<827a83dc9690f5d03b0df195af7de6de><827a83dc9690f5d03b0df195af7de6de>]
[<82cd7398c6c125d2dd7bfdcdc3eec6fa><82cd7398c6c125d2dd7bfdcdc3eec6fa>]
% ReportLab generated PDF document -- digest (opensource)
/Info 23 0 R

View File

@@ -127,7 +127,7 @@ endobj
endobj
20 0 obj
<<
/Author (Android Cast project) /CreationDate (D:20260616121124+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260616121124+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Author (Android Cast project) /CreationDate (D:20260617220502+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260617220502+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (Pro / OSS split \(cast-core + cast-pro AAR\)) /Trapped /False
>>
endobj
@@ -259,7 +259,7 @@ xref
trailer
<<
/ID
[<663b5886a1b00b1f8a1f420abfd25fa3><663b5886a1b00b1f8a1f420abfd25fa3>]
[<25f000128476a42bea3f6be0b0c8670f><25f000128476a42bea3f6be0b0c8670f>]
% ReportLab generated PDF document -- digest (opensource)
/Info 20 0 R

View File

@@ -87,6 +87,8 @@ Click a link to open a guide. Section links jump within the document (GitHub, Cu
|----------|---------|
| [20100611_3_url_shortener.md](DRs/20100611_3_url_shortener.md) | URL shortener — design review (auth, slug algo, task graph). |
| [20100612_1_scaling.md](DRs/20100612_1_scaling.md) | |
| [20260616_rssh_routed_egress.md](DRs/20260616_rssh_routed_egress.md) | RSSH routed egress (postponed). |
| [20260617_codec2_ulbw_voice.md](DRs/20260617_codec2_ulbw_voice.md) | Codec2 ULBW voice-only cast + SFU negotiation hooks. |
---
@@ -124,6 +126,8 @@ Click a link to open a guide. Section links jump within the document (GitHub, Cu
- [PRO_AAR.md](PRO_AAR.md) — Pro AAR split
- [USB_HDMI_CAST.md](USB_HDMI_CAST.md) — HDMI / USB-tether
- [AV_QUALITY_QA_SESSION.md](AV_QUALITY_QA_SESSION.md) — AV enhancement Q&A
- [DRs/20260617_codec2_ulbw_voice.md](DRs/20260617_codec2_ulbw_voice.md) — Codec2 ULBW voice DR
- [OPUS_SPEEX_VALIDATION.md](OPUS_SPEEX_VALIDATION.md) — Opus/Speex E2E checklist
---

View File

@@ -153,7 +153,7 @@ endobj
endobj
25 0 obj
<<
/Author (Android Cast project) /CreationDate (D:20260616121124+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260616121124+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Author (Android Cast project) /CreationDate (D:20260617220502+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260617220502+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (Android Cast \204 documentation index) /Trapped /False
>>
endobj
@@ -253,17 +253,17 @@ GarnQ4`>s,'\rL!2j,Y2Gf7VIg8H)\3`Pd>,m?5I#W;ibrdKEq;-TkXak$(>48Fnu%%uk//)XH<EDN5A
endobj
43 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 3277
/Filter [ /ASCII85Decode /FlateDecode ] /Length 3437
>>
stream
Gb"/)>Ap9-(4P^ZELp4q=dr7,eal6CP4iu;41:@0OWks#b;Rfd(bSRh^OAsE^rC(uTQddom3nECQOg6?X8:+CV][,A+3FNNC]H*ME.1N3:m`neaFXil>;564rqo1@T9L'VeJ1pc:"'5B)T_\8']T]q3>WhmhZ0MNa62&2)_X"H#gj")%*sPpi1q=S-h1i:rrM^u\<_L>gM'Q.S=_2P;nAkt&9THO&dZoN'f@!79q_ZWi4P\0r0a@"'*eRb</!Mu+C_SQ"m=rr`A<\VUM#6r65^7tMdK?CoZS/^p+t16i8i*]=1c\X8Z-3%`@`sig?G"O\]`4hF9\_s-%f`I3eKihP!Ph6c6,uqA<=m11J";o)'n9b#)UtYK7hVZe@O^:4e4d59D5.cgTOQDl;O$X/Hm_Y>5A85-'2Xla1MI6X!gV$aHeUjp]P52n#1OH<2i7h<E)%S5"dgR4*iuUHiNiQG1?:S[0A,&^.Kk!4K0O4VWOX6SXJ&Fp;IB6+:M`6MletJ8D#I338@j;f^CKG`qC49\kS8?YT8M<0g)"T]/`AScBk]S^mGP&5!s%KE7>T/J]JiVT_7QWd77\OYJ1C8;/b>ePBDB>"Y\-UDm.mUg0bdd06X^Ar>#5Nj03Ra,dJ(BnB]K+%#+)&CE#0GSFkG,Q9BZ!%=gu1#!fYVgW:8LRS8Lsl#8gCB?f3a'RnOf.-QLgALA]a:0</UFb@b0hB;H,5>tN"G(smm!dUM>*=/hc'L1D9Z`",FMpJ--#C0!04'C0jKBddGE*V=50W0uL964_('"(to);1!YdR!2Q#r.@HY/=XWLHX;DT"E'E!Q9hcV!.F:q>k*G[OupCn>mi2m=aqsdb4BJHtjQElfqn8Z*)</LRVn)\(>jf"\^cL(bp@>Mf]V!*&=GC09p_PMhkq2S%7!O;-t#*,"aP=_9Mq9E5`S]>%;O<`:ecti2YAdKg!>kYfF!X;sU6A=3:8:Ao_6XqaB5_ZH-\X;+Tb6gQ5s8]ic159V-+I-,YG[CN@AG5?SNb%>`i*h[c$r*\>sl:;*G=c)IL^Em'o2NN^TSCTh0T%\a)DNB;puq`?cQk'Zn7ZT4&@=.<SNO1!81WO6f.f):5@4.Q=gh4p1rCc39j2=n.NFqgdp+\E]7_#1V-4,ibO\BgD0r@S%'I`6Hs0+c+30uC97gau$<2e8NGZhgJ\-G68aNXs%^/&\.'mJ-Efm^C_u`9o^uE/AoS!I)M`nT\sDi&PpCm\^`nEI_S1_*Tf"X)j@2>4\E1nRuH.08IPa,PO64\7/\)"X/g#.m$$rZ556c_pFc9'!,,?IEIB&RbD"A%4%*8F#'?4c"Su;g1rG@^jk)A.=u>Ga(n4#2thiEVD(Cnok\,5rC).&,[,!'F>KFkf=0dYc.p`B&YoqAmioVc[q;-8^[iZFSJQ,ul?#R_cJd\9T=lQV%m>@/iC<L-*?u3#K4O5\+pb*TpJ/D;6_q*O1H/7mg:/r?D/9Bt)EF:@KI'lAh:N(jD3-R^?$j8O8<\Z8ABJ?k:,e<K[!`nfXlIF6Zu47H>%csJ,\D:F4`+4m4%qhpJjns8X<>=m&2K'N?f;243=+Qs/2FEqs5]"dC,PtcpOIB(i>F8l*e[Y7OEpVWFLVnAGeL26!3%j?)GeR=$i*N'^pKa61>D@*e-q6glG40UHI7?jEpXSD6ud<fc-cluZg6,Q7p9u(be:PAq`;'&Ytr(jF0gLjOC@;=pj:5#%kkN.o9M%K`.nq_n.9jPil'D!B0:I,=gNs!rkj%M`c5S6Ro54ub/,u!T7r6;,%s2G9o@s2*r-J807B%Q4/u<Dl_$,9_D:#iYtd*MdC/L"%m9_@8/'X54ZqZumLg<fY0PGnI#`P.I7C]sOS'N,I+)<+R`TYf)+Lt/gO=;NX&7a\OQ)m"p2<VATK53PH#<\rY;8JZiPP8L(9Zq-;d2&HWAtmC:!:&bj4qisN[E#\;gUsjgkad^G-lcO!I#3'\4BE%5c$?+WB/OLf<n\(lh]ir>i#r6:>LSs;gI+*6CW11l?ne"1T'Eh\/H6K7]s+jI>CJ::+?"t3C44C2,Wos&Y:gbhrU$feB+Ejq<prfIBRQ/[5DDW]_lNiB3#sQ4(rVrdO&sR*9k9Kk0?FtPJhXqfmOqP<rBo0B?JX9['$P)LY7CSj_?WZ/rePs+ba^F<:]Cle[bK+E+NFlfFc#"-$k:MoFo4N-!#<GO#`,t9k.DpO-;XfBTC*`NA6i(msQF[@;Y2MEm\h#h]JHnSSGGsi:(f6o1;d:V7]U[m&i)<d">IJ'))Q=j_Jl)_7`@!9Z6C0pI.%m79$7BE*.u'Xb^puM"l\hSqmnMOfh_Q3%RLe<"\)n'WDi-q61RT>"++^;C'@!&IqGGXb;rM99E>5"s4U)IY#$WiknZi=/*NdV+@^VK+CV;;MbT"Q6NjP%6c=3;C*6/=GfWq)LPYE`(Dl]YRh6n_&2NJTiFFQm386)!ho&ATN&e$m%PV&JfsH_M!BTEMa0-"L&[AIndWQj:_&BUI"/C!b1@qM1(Z:%BY."6i;lpq8B9hT/f4)EY?N,lFkihZAEE"Hq\G>gG)B&.DXfr;FkWd7FhB_O5PNK1S@5V!<$WYg#%C/))L5B-S&/:&U/j^fGt7(,H4-R0ntmhI8\d^Iji9hf/1ecl=!<B##CR_DnjfRK;54g!7ic)+/Rl\ZSMC-D@,3pL2t^0l:gZ'ZmAMn@#;&Na#M&`_H/o!+cm;gXrdZD`&%%"lX/oY0q3BrRfV0kKe+=GorVtkXMZZ<M[kbU"m&rJ,W_\h$%q71tiH]8ToWhe)hV\/;TDmU?6ua7O!U;*2:dl*UM&lmU9',VpQM>Rl`]N%[F#6<I-),WXM2iH>/OV8!%/:Y9C52Z"N];kn-bHMC?)tWOF':6E21\AB(V.%mBl3rYN-_pr7K*I/dh>H.ipIrH*7s?KKj"-FbP$>7XN/$FKVon#d_#;=Erue-FY>M@/3LFjbmiL@/hLs3F7W!i,O8>%BB,>&Df_[u^ND%BXk)8KN^3CVN=;!7Sj=qEdeb&#G$Q.Y!Ip<8JOZ[>Gj4WY0,uShYZ$sD@.--3O$ilBU#+kY:bQ.mi\@6*gdj>\+jkctWOj3Tma/uH=I]LX.lMrud+N2Df0JJ1'h,]FDKCLO)t&^7Wq6^[lM/0:&/=Trj8m>/TulpCYL$5m&N`;"RKPnipOgiKZJlUggq<2pR,"PlFr7s,^R]T&,[()&]NjN!r.#\MDDjeE#m)4hIdX.7jrW*jGAagd>`giDiEaJ2-RcL#1IKG%gbrn9%t+3iFWtWQ~>endstream
Gb!l!D0)I3')nJ0d@[RRG&;iLX7mQ)8B*S[lkjBt[OP8k_6V;q#*p&Q\R0h<#hUD4%-7+sX0,@4*k>kTS(.DD=p.7k,PhAq%D^X::+lnb$M,PT=cd'@%HdTLcP,k1;cX$$=%!o_9bTp/,ie?TN'AT<>(j\="-i?uT3frn]Zd?!`%1Unpc^5q2qtPZ9g6Jm&"*C6\_Q0$Ng$L'qEt@PdQL'OW)H9M5`eI8W9GF<$6@4kf0'H0B9L,#*!qj+'o#,.R)/>0>a,2QF!U]sF+ep,);]h.^S8m@Q-jR,=/Mb?d?U]6p/tO^Nj#OAI9)ZAj"!cCT9\Y\%oTZn#Kc2>#Dq<XK1%lj6)+#A+H__3O@Xd^8B>c]'![K&8&lXKp$nZ#gjMd:mn#*k?SC:o].T/P'XU!PdW^7C!_F/cQrcc&HBb6gaAsgMp]@'??DHf%TLpL[W1r!]E@]d[SG;3jgAAYJ\YDG4WjQ5+p/t9*_ilQJHY.^_B9m79ee^E*_^J1u5I$D=,%7fkTl>5DP@1n.)^ea\lS`1o^i<YG,k1<fqpd,fEk:mj#0(c_n/3^LKS-"l$q0Mt!Gt@\N?JYhq85r%LjXtQQEH!95C@4DIWs?ik6B*`IWFG%(TcOr[):$Zdb%.)0K;LXckMK^XW?&)8NL*<>P@Qsd/YBTB`QsIY,>V8HTE*AB&i^>[+_Kb147D\<5K<NN_XJ^,\8\ke-fb>I=]I`Jt,[afI'X&'Z^BQl:?.hUBK94Oi7D.T)ocU""7su3U+-.*)tO:S)XnfK/rfe4uY&4\#AZtbLgN?P9*uT9Lr9uoiq\?-Q9eOn\%B*$Qr$31ddh9bBpT6gNr2mc*N:uQQs(W8oNOfq91[5m#1b1WI83Hh-[S=]0"'V)5*a%a-\k+=Cdm,P)-Z.HE"9D?::k7g.n3aN/"&L&lF8V'-?RS$s.7B\hsN?8KC$#!Ua\3T%G:CNs@eUTkiI8p1ljAa@./-lB$gK?5E@Z5;S-Yl=uL[YdZDUO2^_N\R`3iGtsA;q_oJ0SH4SV$ARM[3Ih9;3glTu7WU&Y^!s?iM=J!EDV[<TlS))mg:2h^FFJbPB'p0O@lBD.W7<6Mo4+P9<9gR?2uE%"\/rtG\*m-be$?uWgNIn/bRR*Vnhs)ZhgblG-ZBsD4)gNBq=Ka-_tX]8Fg/Y0^.g:D]?K%#M!d^UpB&q4<71seeUuo\q"b'Pd.DYTHTQA^o0?^X"'%>$1Pl-V`O#)FD@GGXo6d^=)[8li?t@(t5C@0COGl6\T_$:MNB''B)qV4AlbVP3D4)J8/0:sa'Vght8Dk3%`Y?j?[ITem7eG!Qk'Ub`OIV`fa_Yk?g1f*.M\1WYb9kFe\Ah:LL(&Lj/3%7!+p:i*%f/"a1oEp>F[f&+j10S`4o*r0/aXB?H?]#,@Q\gL`c:Ju/s9R]d3aWDDo'jN]U9P>kOd#pLX-&bW'588N5Y$9?$ag6KJUYuL#.e9;EEj+X-msAg`#lEZ,:[CR*A+9'!8WL@Ro959\Yu<45Y+4al*GEAdJuC=0])R!XI&RlQn[$DG].YA`_2[ApeqcCR7\@/3]'27HWa2+N4Zn&]Dk2E.oGq%,oVc4g45PjFJdqh>P=eJ9`$M1Rsj8LbO`1nd$qtiC6A$os-R\8=`&uA89uTLi:ubVYg5Qq2r]_bqSr;+*95m(B[3<cWN!<.#nY;=VbLjp=s9Q88!mFX#Du=YEk0;IJTe2RQ^F6$pF&)58'Q7Gg[&VQXYSWI(3T>(6QX(SCe_@9W%QMD,!ar?hQEH*#HW-/_'"%/BX,S.q7i_KD,8_Zn)HdjA/p`ohB2hTN78ZUX#eFdsN[bHEE,m4$gZ0n=>n"949=\YeUXZ-#QoASMtca3M+4V&_1&PIb2r>S),%59P5$n0\YXGm]3seNJ;>,&H<I8J"sm]fjP3MHR\H2SLNh5B:b0gE7LbQg)8;^baZ`0[#K,Xk:Ct-1Mqo<\hj3N`U#'qiWX-)Galdp9mRc_.\4CL?(m:VXuj720?BaDr-AcCk+rKO.^$H-Eqlb1PAYDR`&*r#(H9@@Pq(Tk+/;d*.]"PbA&Non,t`/MKU&DNGaspuSLfd5s#u/,O62@qY!U@Qk?lKEATq"Z#8[moD46^Na8iBiG7LXAVN/:6qgCG+nVZ_[N+GLe?!$IgesZKuib!#!)qMYJK^69N$LbgMWVIKPB&Gd30uL"(2+%D!.H>pkZb-qs*5sbGYq,Qedp"@[D^P1C0t$B"HR#M$DWf4NdQd9:5>D?PC9g1amH<j$6r;g@lDJNCD%&W#_9,@/5!c8u/ac?gRrVm[hN-J?iNOM'V+/=173]*._I6$q%FmTS+''XmXc[R)OYj%,_I5l2CVo[O7?Y%s$&96eP%u<_<[:j).j%e;Z"=G//4mL*\OYYsMPSk*_1rasX]^8e/!<f:"s6kk\Rl:7X@Q76)LPYL8Bi'#=HUOj2>FC$NG?HMm;/KH9VLi)U"0XGmd-Urbb4=(+OuDnmHo`+L=igth#O;NP`CV'`Jm\'b5H_^k4hs&-"JbD1lZ1\6hkPN.ZC1@F@hflHH51a#[L_Sl+)*93W@l%P0&a3Z0)mPe(/66bgj%@g3r@L2GUks.4PrB1BXm.4,\MKiKqEKUZ,$?Z2K[/rTkFP*`]*dmj);'G5hK8-kVd)o<T"JX#Kc<]^eRgSjT7trM,rBTf0.hf?"X)?^Nb_Kq%5+3GM<Xs7N<JC(=F1KG2n1Z90g,'m*#J%o3buC-otFFckRJ5g`Il*k!arm;Y0"\,P9VP-h7(HH*kjCO\/^Ft^Zq'G%g^X2i+?%PII!1N*;)l$<>dT<5=->_Rh.%^!6"48*:EIh_\7A!)5..'HKI4&1sH*J[e?(,fC9=>0VQ'q/]^JV"IJN6p?BX$gC3Na,$HD;B!9)_RLNmEC'-ZF;!S^NL?8k?I&<%GY<_I>=?;0F[lGr-Aa"c/2n3C_`gRERh9'_]M+V=DjbP%O1;[6rqS0Gp<,)!;9J+%]2E>8V2Q)mpKb&OsjuV4e*J58?X@^9RUP,]U@ci#<1"iM'a<RU8&6]$dhU",Q>YGRk]CJPb`<]jprX1KkPIIfRg;!"=c:B&\uI^$OQSDf(39%nh54mLhI]kD5e^C?CId)B%95J3^7m3#g_rA(=m/p=7X8l((r+VSn34>pnk<'#eJWE0:VEaGSQp;FL([=q\>*A67@;J^D4prr'DHrKShEd$&%CfmCSKeg\:M:N$o23,KU]@7JcVX]@4Dl\?`o1AT!+5:3U-%k'j\oVB;q,0Dr<h.?r*F2DuOPDSi7RIFP7.le+UuNT[Vn`Pbat!oqP%E>uG",4EY(dC09H*ZOO+j/eJ-*.>m2jjUEM!6+9*S:C>qX(I4,%3sHD#dXA:kL<gV(#i4(XU:K13)T>=qXF*I8:i0%U8dYUEsHu3SsZ0W1%1]MMPLPHa$PM1JjP9bMtor\]r]f[^r_'+^['pJ~>endstream
endobj
44 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1270
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1402
>>
stream
GatUsDf;C1&B<W%;iJ)p;tdXGR"R]k4#`jMZq3W9p9[^D7);U--CD33kjn+b9G=kh9i\c%PQ6?@IuL"Fljtl@6gEQF$#gqQpOWCM+FXIA2u4)H_2jYk+-CE`^25j$D>(g=4N$TXp@1/UD:Z28lj.sj28rlQ_hND=pZ^46RQ<-Wc96/Q(ka`W8jYb0L9Vg=b8fq%bCrWcEXo-b_:/<<`;`.$O(Po<cTVij1X*`rVLa5fcsY?7']k9F"W2jgcFqbPDeg11\Gt=ca`.hc9fs>Ap#@G,VfXnl5sqN,m"m.t?f84d/8`44]8*9H18G`YRO2g<E&D8p-8Ucbo5u4?W`X>m^suj"Fg)$Phg(?\]g+Z>#&M>p-*p:g0ce_0%Gghgj<kQ)W=ll'10qshY*R71C`5LRQ<Z.8Z]%JdS_9+,%HtW&c.i'kq*80/EmHa&Za+&.lrk_j9o"h+Q`S+LO`N,h/"((\Do4:d;2>:'Y_2\F\@!_:qbU-"_[jWp_^<]m0@hZZ?Ek-WYHY_J?HQ=0-J:$d'>1GB]P!L3E2j!nFV4tOY;-8qR7"u8bkLu:3o7]=171f`IQ/1lEKcbHQdCEu%9`bA#9-2F:(p6LRO[G#n/<U^-s@=_iuDkS\']JA24TVg!KH)n6Urg>Gk4<Xm3XDem"::LhBb+iF?GGq,r[Z;r$WIXY8\g7#HXGnA]C%;<3O!.%:IM$c+^4ZpG]<Ie)6LC$.8[:[1fdYIYgj5)X2fo,o,-L$Q.>MXCeP^1M=EbEV*+:dAC"pV.0HTFA0g+0ck<(.n\_DBB&9+#5cnql[@Z_0Ohi]qBD_"f0&]s"eTYY8P0KckhQWR"oVQdbVQr]D/@s,#9LG&"YY+_B;njI9ZHdr5>Rb[^uZt>0#l@i)sRZZJsq<o/Q`D(Z!I5q`]cA0c[\!?:FCHK.3=E6%*ic]j'a_8KCSRQ&fpGo:E6iN4cb/nb\6MZNrA-$$sCP8T[&*pqU]__'3Xk"`6Ae'"D]m-Ab9rHGd@hGT%Psq?l;^;,f)/%$mD2Pg<:tM%<)8Sn(0hC1;,feU*uWZX<c9L]rT[NGH_^CM\E'J$\ipuEt+q!`e?6W>J>A'`>T;h9UGVR<RH3joX\MC^Gktjc#u('I]t<V\,\S;/d$S,JmhY3;l*S;U`t4S*b6W/1pZ;@]O';ReOIf/f`RY!U/J9Ye%:N;Z'1\jnjN#lW&DC%mH)/?e*?Do@CU_P>R+RWT:),a5;etu^RuC=G0`%%kB`eF<J5TSFiV<\3ko(<d17^l2?j~>endstream
GatUsCJWtM'SaBKY;jsD=.NVfj4rTtBN(k,d#b'INeCqs`3`\$3+G&+iSUgZg<a8c#ZMOlqNCI2of6q##^#l.c0oHPE0`b=KE)mOg]Oi=$^(f!aep5Qct9+cCQ<&n(:YF6FS!G6qrG->Lt[3$RLR@GOJd9r7g>K^Jbs%c#<%@o=dhL815E6:p_QL#L#am%k$!6-KlUGCDF8:0Z5Z^D)c&a7^=U`tC1%+V>NE@LM#@#L7mT+oOs&1R3SYO-$Q2V5!pXMle%>d<mI!+-LH)/>E/"70g_(=_S8\LL#]>!uL?6]!(c?:0V#unB*%FZ<*deE[(e7MSGj0u8R4.,6#nDI&Gp,`4J]2^@Q01:#8,ed7f,R_o+H5>@9<6%Ci4(8f<4$Vh0Sa8E".<TdW3d@SbL(o)-Yl(]k_>io\fl.Y-A^X]a"j8:7OuX1--*Z)X]"lFnhIGEJj>c9K_*I17V&WP$.fW)n'@nihs$AfIAjHa+rThg3mr-U+`-/,/MUU/-:g^1b<:b1d#LF4#(nLT&1=$4;R[-1b$jp[fO<:pbis.BEhF-riC>KcX.Ud-6LK*pr^?![C*B?tSI%i`Z"5bYH?TYY*,I'Vl/cIf%EACC'dh0coO7*A*<>GY%4$n0f_;"4<U'ST]1fbHd@iN?lX8J7`FnsTGWEbG5>GAl2'QUnPK/8'2sJ+e*c)Pi%DJG0PB$.6?i)emicmT!C74u=+QXe!1U84$Gj,AP!0)W%i2O)JRirS,H"u8`H1rCedip"gl(FGqg#VK=1c'/^#<m6Kktf3"N2?+Ks54iqj3USF"e8UNn&H.d59V]^a;-%J=;JPBSfsn$B6"a@h?C?7dOocAr!4`Z_q<PSqS%=Ir`l#V*Mn>qq.=pl`cc1CBOgGY8Uk"ms'A729;TapK)?>RA]'?aOr)e1'I?SA'6`)\_7!ZshR@PHBe[7>7K.A?+CBgq3e*A@>Z,70pIFd[TXOMg4l&3QN,<I_K6tb*=#*t?=is/LJ$prpj0BO@S<"=GRS:K(e9=U;iW<5q,TY[o2U*8]hAP2"+A)CHZ$I'"pI064B=%,=Lke8UR=:Jj7seFEU[F,^&J1(=*?N'O5H\E_.LJl33V_dR<>$f*.pA1C:Qu&V3ec0Ce()jHAS??q]AT5kGaV/:q'2AD8>_"L-Yg2hk3W]QFq)A8;k4(CMt2Edc&(_M0C$1KTOs_"@kJgh7-]rt$:lH]AR'j^q<#r#X8tf5FJ\tc;)Fn0^T<h%mn8+6ZO+[K+4Oj,(U0\KD&)gjA40J[.M[Qr@ER#"dK=@86b;P](Y!Oq^$8HGBP@Oo=A]C]T<#s_($%?P)*\lne#LGqM"^D,RS7p@Rie)7+lk]Ro(p;S559usD#RMl+gk$G6_<UplMhIe)X<n=F``)KJ5?1I2CFqW~>endstream
endobj
xref
0 45
@@ -311,11 +311,11 @@ xref
0000007001 00000 n
0000007229 00000 n
0000007642 00000 n
0000011011 00000 n
0000011171 00000 n
trailer
<<
/ID
[<74d094b45c0ab837dfac111b102db2cd><74d094b45c0ab837dfac111b102db2cd>]
[<941c3b462cefa7769fe8013038040d71><941c3b462cefa7769fe8013038040d71>]
% ReportLab generated PDF document -- digest (opensource)
/Info 25 0 R
@@ -323,5 +323,5 @@ trailer
/Size 45
>>
startxref
12373
12665
%%EOF

View File

@@ -183,7 +183,7 @@ endobj
endobj
30 0 obj
<<
/Author (Android Cast project) /CreationDate (D:20260616121124+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260616121124+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Author (Android Cast project) /CreationDate (D:20260617220502+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260617220502+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (Remote access \204 implementation notes \(v1 WireGuard\)) /Trapped /False
>>
endobj
@@ -383,7 +383,7 @@ xref
trailer
<<
/ID
[<deae7b6f7dbb648f92f4e1c4452bcf17><deae7b6f7dbb648f92f4e1c4452bcf17>]
[<853c39306aecb77ed422e218a356e197><853c39306aecb77ed422e218a356e197>]
% ReportLab generated PDF document -- digest (opensource)
/Info 30 0 R

View File

@@ -137,7 +137,7 @@ endobj
endobj
22 0 obj
<<
/Author (Android Cast project) /CreationDate (D:20260616121124+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260616121124+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Author (Android Cast project) /CreationDate (D:20260617220502+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260617220502+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (Remote access \204 validation \(Linux CLI + mobile parity\)) /Trapped /False
>>
endobj
@@ -277,7 +277,7 @@ xref
trailer
<<
/ID
[<7421df7523b2a5fb9743c37af90d9b8b><7421df7523b2a5fb9743c37af90d9b8b>]
[<5d07b3d520dc1b2274d0b97bcaaecff2><5d07b3d520dc1b2274d0b97bcaaecff2>]
% ReportLab generated PDF document -- digest (opensource)
/Info 22 0 R

View File

@@ -198,7 +198,7 @@ endobj
endobj
32 0 obj
<<
/Author (Android Cast project) /CreationDate (D:20260616121124+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260616121124+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Author (Android Cast project) /CreationDate (D:20260617220502+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260617220502+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (Android Cast \204 implementation roadmap) /Trapped /False
>>
endobj
@@ -407,7 +407,7 @@ xref
trailer
<<
/ID
[<613132d6179351c563a5f385a1c086cc><613132d6179351c563a5f385a1c086cc>]
[<0da68f69d69dfa4b1bad783189324a7b><0da68f69d69dfa4b1bad783189324a7b>]
% ReportLab generated PDF document -- digest (opensource)
/Info 32 0 R

View File

@@ -132,7 +132,7 @@ endobj
endobj
21 0 obj
<<
/Author (Android Cast project) /CreationDate (D:20260616121124+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260616121124+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Author (Android Cast project) /CreationDate (D:20260617220502+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260617220502+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (Tickets, Gitea, and alpha smoke delegation) /Trapped /False
>>
endobj
@@ -266,7 +266,7 @@ xref
trailer
<<
/ID
[<d274bb4400f3f8257f3cbf0154e5f352><d274bb4400f3f8257f3cbf0154e5f352>]
[<7488f6bb6c67f7874dbd93366608ef58><7488f6bb6c67f7874dbd93366608ef58>]
% ReportLab generated PDF document -- digest (opensource)
/Info 21 0 R

View File

@@ -112,7 +112,7 @@ endobj
endobj
18 0 obj
<<
/Author (Android Cast project) /CreationDate (D:20260616121124+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260616121124+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Author (Android Cast project) /CreationDate (D:20260617220502+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260617220502+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (USB-C / HDMI and USB-tether cast \(roadmap D & E\)) /Trapped /False
>>
endobj
@@ -216,7 +216,7 @@ xref
trailer
<<
/ID
[<2da9107c99ca25f08b416afdb8f65144><2da9107c99ca25f08b416afdb8f65144>]
[<fce2b2bd44cc97dec62511ff4c212ee7><fce2b2bd44cc97dec62511ff4c212ee7>]
% ReportLab generated PDF document -- digest (opensource)
/Info 18 0 R

View File

@@ -102,7 +102,7 @@ endobj
endobj
16 0 obj
<<
/Author (Android Cast project) /CreationDate (D:20260616121124+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260616121124+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Author (Android Cast project) /CreationDate (D:20260617220502+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260617220502+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (VPN / Remote Access demo \204 gap report \(2026-06-13\)) /Trapped /False
>>
endobj
@@ -204,7 +204,7 @@ xref
trailer
<<
/ID
[<6d1e4602f418374dc8e08d255d1c650c><6d1e4602f418374dc8e08d255d1c650c>]
[<fc38ff8f318a67e77a875d191d72edee><fc38ff8f318a67e77a875d191d72edee>]
% ReportLab generated PDF document -- digest (opensource)
/Info 16 0 R

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

After

Width:  |  Height:  |  Size: 114 KiB

View File

@@ -0,0 +1,278 @@
Codec2 / ultra-low-bandwidth (ULBW) voice — research draft
R0-pre
severity: low
state: research (post-alpha candidate; blocked on Opus/Speex JNI baseline)
author: PO + agent
date: 2026-06-17
Problem:
- PO asked whether Codec2 (or MELP/TWELP-class codecs) should be integrated for voice-only or
audio-primary paths on very slow links: mesh/BT P2P, marginal LTE, future multipoint relay.
- Today screen cast defaults to AAC; Opus/Speex are advertised in discovery masks but native
encode/decode JNI is still TODO (stub → AAC on wire). See ndk/README.md, OPUS_SPEEX_VALIDATION.md.
- Future F1 multipoint cast (MCU/SFU on BE) will need a single negotiated audio format per room
or per leg — P2P bitmask negotiation alone will not scale.
[foxx comment]: it's surprise to me to hear that Opus/Speex is still TODO - reported to be finished by AI
[AI note]: Negotiation/UI/autolink scaffolding is done; ROADMAP.md lists "Opus/Speex JNI encode/decode sinks" as TODO.
opus_bridge.c only exposes nativeIsOpusAvailable — wire path is OPUS_STUB→AAC without libopus.a + encode JNI.
See DR docs/DRs/20260617_codec2_ulbw_voice.md §4.1.
Scope of this draft:
- Research + integration sketch only. No Codec2 until Opus/Speex JNI encode/decode lands (ROADMAP 6.1).
- Covers mobile peer negotiation (today + extensions) and backend MCU/SFU hooks (gray / post-alpha).
──────────────────────────────────────────────────────────────────────────────
1. Codec landscape (skeptical first)
──────────────────────────────────────────────────────────────────────────────
| Codec | Bitrate | Sample rate | Quality / role | License | Android fit |
|--------------|-------------|-------------|-----------------------------|-----------|--------------------|
| Opus SILK NB | ~612 kbps | 8 kHz | Good comms; FEC; wide use | BSD | Submodule exists |
| Speex NB | ~215 kbps | 8 kHz | Legacy narrowband | BSD | Submodule exists |
| Codec2 | 7003200 bps| 8 kHz | HF radio; intelligible only | LGPL-2.1 | New submodule |
| MELP / TWELP | ~2400 bps | 8 kHz | Govt vocoder; patent encumbrance | varies | Poor OSS story |
| AAC-LC | 32128 kbps | 44.1/48 kHz | Screen cast default | patent | MediaCodec HW |
Skeptical PO questions (answer before building Codec2):
- Is Codec2 needed if Opus @ 6 kbps + existing FEC/NACK already fits the slow-link budget?
- Is the use case **voice-only cast** (no video) or **audio leg of screen cast**? Codec2 is 8 kHz
telephony — downmixing stereo app audio loses music/UI cues; fine for push-to-talk, poor for
“share my meeting audio”.
- Codec2 maintainer note (2023+): major re-dev; many modes “not actively maintained”; only 3200 for
M17 called out as exception. Fork/maintenance risk vs stable Opus.
- LGPL-2.1: dynamic link via libandroidcast_codecs.so is OK; document in mobile + BE licenses;
Gitea mirror like opus/speex.
[foxx comment]: from my past practical experience, Opus@6k+FEC gives a lot more hearable noise and network bandwidth rather than Codec2, so everything just fits its hole and goals; we use AAC legally as a part of Android platform, no conflict there; Codec2 3200bps looks also OK for the goals we want to achieve; MELP/TWELP - skipping that, out of scope because of many slim points using it
When Codec2 still wins:
- Sub-3 kbps **sustained** (not burst): BT Classic SPP mesh, APRS-style relay, satellite backhaul.
- Symmetric **voice-only** sessions where both peers opt into “radio mode” (dev/PO setting).
- Lab demos comparing Speex vs Codec2 700C on identical packet loss (after Opus baseline exists).
[foxx comment]: the intent of using Codec2 is not the lab comparison but the desire from end-users to have audio casts on ultra-low bandwidth (better to have something than have nothing, let's say)
──────────────────────────────────────────────────────────────────────────────
2. Current mobile negotiation (P2P LAN / TCP / UDP)
──────────────────────────────────────────────────────────────────────────────
Two parallel paths today — video and audio are **not** negotiated the same way.
A) Discovery + wire header (both peers, pre-session):
- CastProtoHeader.audioCodecs / videoCodecs bitmasks (48-byte header, every packet).
- CastCodecFlags: AUDIO_PCM=1, AAC=2, OPUS=4, SPEEX=8 (room for 16, 32, …).
- DiscoveryManager advertises localAudioMask() from CastCodecFlags.localAudioMask().
- Receiver list in UI carries peer audioCodecs → sender picks target.
B) TCP handshake (video only, CastSession):
- MSG_CODEC_CAPS → MIME lists (H.264, VP8, …).
- MSG_CODEC_SELECTED → single negotiated video MIME.
- Receiver runs CodecNegotiator; sender logs CodecPriorityCatalog decision.
- **No MSG_AUDIO_SELECTED** — audio is not on this wire sequence.
C) Audio resolution (sender side, after target known):
- AudioNegotiator.resolveForSender(settings, peerAudioMask):
negotiate(localMask, peerMask, user preference, settings).
- AUTO → CodecPriorityCatalog.decideBestAudioCodec (scores from codecs.json).
- Explicit pref → mask intersection; fallback to AUTO → AAC.
- Result stored in CastSettings.resolvedAudioCodec (transient).
- Wired from ScreenCastService / MultiCastCoordinator.
D) Stream protection (UDP):
- Separate post-handshake negotiation (FEC/NACK); independent of codec choice.
Implications for Codec2:
- Adding Codec2 requires a new flag bit (e.g. AUDIO_CODEC2 = 16) in CastCodecFlags + proto docs.
- Must update: localAudioMask(), flagForAudioPreference(), isLocallyAvailable(), CodecPriorityId,
CastSettings.AudioCodec enum, codecs.json, manualAudioPreferences() order.
- **Do not** advertise CODEC2 in mask until NativeCodecBridge probe passes (same rule as Opus).
- Unit tests: AudioNegotiatorTest, CastProtoHeaderTest round-trip, mask intersection cases.
Gap (intentional for alpha, painful for SFU):
- Audio choice is **sender-resolved** from discovery masks; receiver is not sent MSG_AUDIO_SELECTED.
- Receiver must infer from CastSettings in session or mirror sender logic on first audio frame
(today: implicit via shared settings blob / same negotiation inputs). Document before SFU.
──────────────────────────────────────────────────────────────────────────────
3. Proposed Codec2 mobile integration (minimal diff)
──────────────────────────────────────────────────────────────────────────────
Enum / settings:
- CastSettings.AudioCodec.CODEC2 (or CODEC2_1300 / CODEC2_700C sub-modes in dev settings).
- Optional CastSettings.VoiceOnlyMode flag (no video track; skips video handshake).
Native:
- third-party/codec2 submodule → scripts/init-third-party-submodules.sh + Gitea mirror.
- Extend scripts/build-native-codecs.sh + ndk CMake: ANDROIDCAST_HAVE_CODEC2.
- JNI in NativeCodecBridge: isCodec2Available(), encode/decode 20 ms frames @ 8 kHz mono.
- Frame format on wire: length-prefixed Codec2 blobs (mode id in session meta or first frame);
**not** AAC ADTS — new CastProtocol MSG_AUDIO_FRAME subtype or codec tag in existing payload.
Priority catalog (codecs.json):
- Default order suggestion if ULBW profile enabled: CODEC2 < OPUS < SPEEX < AAC < PCM.
- bitrate_score: CODEC2 lowest; internal_score: higher delay penalty (see §5).
- Profile hook: CastSettings.NetworkAdoption.ESTIMATED or new ULBW_PRESET gates AUTO toward CODEC2
only when both masks include it AND user/dev “radio mode” on.
Voice-only cast (optional product slice):
- Capture: AudioRecord 8 kHz mono (or resample from 48 kHz graph).
- Skip video encoder; discovery still sends videoCodecs=0 or VIDEO_UNKNOWN.
- BT / mesh: same negotiation masks over RFCOMM or UDP wrapper — framing spec TBD (§6).
Milestone order:
1. Opus + Speex JNI encode/decode (ROADMAP 6.1) — validates pipeline end-to-end.
2. Codec2 probe + encode/decode behind dev flag.
3. Voice-only mode + E2E on two devices.
4. SFU signaling extensions (§4) — only when F1 spec approved.
──────────────────────────────────────────────────────────────────────────────
4. Future backend: MCU / SFU integration
──────────────────────────────────────────────────────────────────────────────
References:
- docs/20260608_BE_SERVICES_and_infra.md § Planned SFU relay (Janus-class)
- docs/specs/20100612_1_scaling.md F1 Multipoint cast, be-media-N tier
- docs/INFRA.md: port 8089 = Janus/other — **not** androidcast PHP vhost; do not mix nginx paths
- App: SfuRelayGate.PREVIEW_ENABLED = false; CastConfig.ALPHA_FEATURE_FREEZE
Architecture (target, gray):
[Sender A]──┐ ┌──[Receiver B]
├──► Signaling (PHP) ──►├── Janus/mediasoup SFU (:8089 or dedicated)
[Sender C]──┘ │ └── transcode / fan-out
RBAC/session
room lifecycle
Negotiation shifts from pairwise bitmask to **room capability contract**:
| Layer | P2P today | SFU future |
|--------------------|------------------------------|-------------------------------------------------|
| Capability advert | Discovery header masks | Join-room: client caps JSON + bitmask |
| Audio pick | AudioNegotiator local | Server publishes room_audio_codec or per-leg |
| Video pick | MSG_CODEC_SELECTED | WebRTC SDP / simulcast layers |
| Auth | PIN / LAN | Existing session/RBAC + room token |
| Transport | UDP/TCP cast | WebRTC (+ optional TURN); LAN cast unchanged |
Codec2 on SFU — three realistic modes:
1) **Passthrough (hardest):** SFU relays Codec2 packets without decode. All clients must speak
Codec2; no WebRTC browser viewers. Fits closed Android mesh only.
2) **Transcode at SFU (likely):** Android sends Codec2 or Opus; media worker (ffmpeg/Janus plugin)
decodes → Opus/VP8 for WebRTC subscribers. PO must budget CPU on be-media-N (scaling SPEC).
Negotiation: room advertises sfu_audio_ingress: [opus, codec2], egress: opus.
3) **MCU mix (voice conference):** Decode all legs → PCM mix → encode Opus (or Codec2 for radio
leg). Codec2 only on “radio bridge” participants, not main room.
Signaling API sketch (owner spec TBD — not implemented):
- POST /api/sfu/room — create; body includes max_participants, ingress_caps, egress_caps.
- POST /api/sfu/room/{id}/join — returns Janus session/handle or mediasoup transport params.
- Client payload extension (parallel to CastSettings):
audio_caps: { bitmask, codec2_modes: ["700C","1300"], max_bitrate_bps }
video_caps: { bitmask, mime_list }
preference: { audio: "AUTO", network_profile: "ULBW" }
- Server response:
negotiated_audio: "opus" | "codec2_1300" | ...
negotiated_video: mime or null for voice-only
relay_mode: "p2p" | "sfu" | "mcu"
Mobile changes when SFU lands:
- New transport enum value TRANSPORT_WEBRTC (frozen in alpha UI).
- Before cast: if SfuRelayGate.isAvailable() && room URL → skip LAN discovery masks;
run SfuSignalingClient.negotiate(roomCaps) → populate CastSettings.resolvedAudioCodec from server.
- Fallback: LAN P2P unchanged if signaling unreachable (local-first).
- AudioNegotiator.negotiate() reused for **pre-signaling** pairwise preview; server may override.
Janus / 8089 caution:
- FE nginx location /janus/ exists for other stack — androidcast signaling stays on apps.f0xx.org
PHP API; media UDP ports on dedicated media subnet per scaling DR. No coupling in alpha.
MCU vs SFU choice (for PO):
- SFU: lower server CPU if passthrough/simulcast; N subscribers see one encoded stream.
- MCU: needed for true multiparty voice mix or heterogeneous codecs (Codec2 leg + Opus leg).
- F1 backlog item — separate SFU SPEC before any Codec2-on-BE work.
──────────────────────────────────────────────────────────────────────────────
5. Peer negotiation — extensions (mobile + protocol)
──────────────────────────────────────────────────────────────────────────────
Short term (Codec2 on P2P, no proto version bump if possible):
- Reserve CastCodecFlags.AUDIO_CODEC2 = 16.
- Add optional CastSettings.codec2Mode (1300, 700C, 3200) — must match on both sides; if mismatch,
AudioNegotiator falls back to next scored codec (same as explicit OPUS unavailable).
- Consider MSG_AUDIO_SELECTED in TCP handshake (symmetric with video):
payload: uint32 audio_flag + uint8 mode
Benefits: receiver logs definitive choice; multi-receiver multicast gets same codec;
SFU migration reuses message type over WebRTC data channel.
Cost: proto doc + CastSession serverHandshake/clientHandshake change — schedule with SETTINGS_VERSION bump.
Medium term (multipoint / SFU):
- Extend CastSettings SETTINGS_VERSION when adding sfu_room_id, relay_mode, server_negotiated_audio.
- Discovery header insufficient for 3+ peers — room state lives on signaling server.
- Per-peer legs: senderMask/receiverMask become N-vectors or server-issued single codec.
- AudioNegotiator refactor: negotiateRoom(RoomCaps, List<PeerCaps>, preference) → server or elected
“master” receiver (first joiner) picks; align with CodecNegotiator pattern for video.
BT / mesh P2P (no BE):
- Same bitmask in link-local discovery (mDNS or BLE advertisement) — reuse CastProtoHeader layout.
- Frame timing: Codec2 1600-mode ~ 40 ms frames; BT SPP throughput ~13 kbps practical — profile
700C only; add jitter buffer 80120 ms (document in AV_QUALITY_QA_SESSION follow-up).
Delay budget (manage expectations):
- Codec2 encode+decode + BT latency → 150300 ms one-way plausible; unacceptable for lip-sync
with video — reinforce voice-only or audio-only cast for ULBW profile.
──────────────────────────────────────────────────────────────────────────────
6. Testing & validation (when implemented)
──────────────────────────────────────────────────────────────────────────────
Automated:
- AudioNegotiatorTest: CODEC2 in both masks → selected when scores favor; one side missing → fallback.
- CastCodecFlags round-trip AUDIO_CODEC2 bit.
- Native round-trip: c2enc/c2dec parity via JNI on arm64-v8a CI (optional, after submodule).
Manual E2E (extend OPUS_SPEEX_VALIDATION.md matrix):
- Voice-only, CODEC2 explicit, two devices, UDP then TCP.
- AUTO + ESTIMATED network preset on marginal WiFi (throttle via dev settings).
- Record: resolvedAudioCodec in diagnostics, audio kbps, subjective MOS notes.
SFU (post-alpha):
- Room with 2 Android + 1 ingress Codec2 → verify transcode to Opus for third WebRTC viewer.
- sfu_health.php enabled; SfuRelayGate preview on dev builds only.
──────────────────────────────────────────────────────────────────────────────
7. Open questions for PO
──────────────────────────────────────────────────────────────────────────────
1. Primary use case: voice-only P2P, or audio leg of screen cast on ULBW?
2. Accept 8 kHz telephony quality for “radio mode”, or require wideband Opus for anything with video?
3. Codec2 mode default: 1300 (balance) vs 700C (minimum bits) vs user-selectable?
4. Proceed with Codec2 at all after Opus @ 6 kbps measured on target BT/mesh hardware?
5. SFU: passthrough Codec2 vs transcode-only at ingress — which matches commercial story?
6. MSG_AUDIO_SELECTED in handshake: worth SETTINGS_VERSION bump now, or defer until SFU spec?
7. MELP/TWELP: drop — insufficient OSS path unless PO has licensed binaries.
──────────────────────────────────────────────────────────────────────────────
8. Recommendation (agent opinion)
──────────────────────────────────────────────────────────────────────────────
Defer Codec2 implementation until:
- Opus/Speex JNI is real on wire (not stub).
- PO picks voice-only vs AV-leg scope.
- One measured session on slow link proves Opus+FEC insufficient.
If proceeding:
- Treat Codec2 as dev/ULBW profile codec, not AUTO default.
- Design bitmask + optional MSG_AUDIO_SELECTED now so SFU room negotiation reuses the same types.
- Plan BE transcode path (ffmpeg decode Codec2 → Opus) in F1 SFU SPEC — do not assume SFU passthrough.
Next doc steps:
- DR: docs/DRs/20260617_codec2_ulbw_voice.md + PDF (done 2026-06-17)
- SPEC slice in scaling or dedicated docs/specs/…_sfu_audio_negotiation.md when F1 unblocks
- Ticket: “ULBW voice” → implementation epic after 6.1 green
Related files:
- app/.../CastCodecFlags.java, AudioNegotiator.java, CodecPriorityCatalog.java
- app/.../network/CastSession.java, CastProtoHeader.java, CastProtocol.java
- app/.../sfu/SfuRelayGate.java
- ndk/README.md, app/src/main/assets/codecs.json
- third-party/opus, third-party/speex (pattern for codec2 submodule)

View File

@@ -0,0 +1,98 @@
Project repository and structure reorganization draft
milestone: R0-pre
severity: high
state: pre-implementation
author: Anton Afanasyeu
date: 2026-06-18
The problem:
The project looks like monolith. For better and more atomic support we need to reorganize the whole project repo structure
The what:
Current project structure
Project | Placement | Repo | State | Description
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
AndroidCast all in one | repo root | git://f0xx.org/android_cast | monolithic | all-in-one project, needs to be splitted
libvpx | third-party/libvpx | https://chromium.googlesource.com/webm/libvpx | 3rdparty exported submodule | VPx video codecs
opus | third-party/opus | https://github.com/xiph/opus | 3rdparty exported submodule | Opus voice codec
speex | third-party/speex | https://github.com/xiph/speex/ | 3rdparty exported submodule | Speex voice codec
wireguard | third-party/wireguard-android | https://git.zx2c4.com/wireguard-android | 3rdparty exported submodule | wireguard for android
url-shortener | backend/url-shortener | git://f0xx.org/androidcast_project/url-shortener | part of AndroidCast backend | url shortener standalone backend
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
The how:
Next hope project structure
AndroidCast project - all in one | git://f0xx.org/ac
|-- AndroidCast - common | @common
|-- AndroidCast - mobile | @mobile
|-- AndroidCast - BE | @backend
... TBD
AndroidCast project | Placement (@ - submodule) | Description | Repo
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
AndroidCast - common | @common | project all common | git://f0xx.org/ac/ac-common
|-- AndroidCast - docs | @docs | project docs, BE, MS, mobile, web, everything | git://f0xx.org/ac/ac-docs
|-- AndroidCast - scripts | @scripts | common project scripts | git://f0xx.org/ac/ac-scripts
AndroidCast - mobile | @mobile | mobile app sources | git://f0xx.org/ac/ac-mobile
|-- AndroidCast - common | @common | | git://f0xx.org/ac/ac-common
AndroidCast - Session Studio | @session-studio | offline analytic tools | git://f0xx.org/ac/ac-session-studio
|-- AndroidCast - common | @common | | git://f0xx.org/ac/ac-common
AndroidCast - BE - MS | @backend | backend microservices common base (UI) | git://f0xx.org/ac/ac-be-microservice
|-- AndroidCast - common | @common | | git://f0xx.org/ac/ac-common
AndroidCast - MS | @microservices | microservice commons | git://f0xx.org/ac/ac-microservice
|-- AndroidCast - common | @common | | git://f0xx.org/ac/ac-common
... TBD
AndroidCast BE microservices and their derivatives (OpenAPI providers, any REST API services for web and mobile apps)
AndroidCast - MS - template <- AndroidCast - MS (@ means suibmodule) |git://f0xx.org/ac/ac-microservice/ac-ms-template
| -- AndroidCast - common | @common | project all common | git://f0xx.org/ac/ac-common
| -- AndroidCast - MS - common | @ms-common | microservices common | git://f0xx.org/ac/ac-microservice/ac-ms-common
|-- AndroidCast - MS - builder | @ms-builder | builder microservice | git://f0xx.org/ac/ac-microservice/ac-ms-builder
|-- AndroidCast - MS - VPN | @ms-vpn | VPN microservice | git://f0xx.org/ac/ac-microservice/ac-ms-vpn
|-- AndroidCast - MS - VPN - RSSH | @ms-vpn-rssh | VPN RSSH microservice | git://f0xx.org/ac/ac-microservice/ac-ms-vpn-rssh
|-- AndroidCast - MS - VPN - WireGuard | @ms-vpn-wireguard | VPN WG microservice | git://f0xx.org/ac/ac-microservice/ac-ms-vpn-wireguard
|-- AndroidCast - MS - VCS | @ms-vcs | VCS microservice (gitea) | git://f0xx.org/ac/ac-microservice/ac-ms-vcs
|-- AndroidCast - MS - URL shortener | @ms-url-shortener | URL shortener microservice | git://f0xx.org/ac/ac-microservice/ac-ms-url-shortener
|-- AndroidCast - MS - analytics | @ms-analytics | analytics microservice | git://f0xx.org/ac/ac-microservice/ac-ms-analytics
|-- AndroidCast - MS - orchestration | @ms-orchestration | orchestration microservice | git://f0xx.org/ac/ac-microservice/ac-ms-orchestration
|-- AndroidCast - MS - tracker | @ms-tracker | issues & tickets tracker microservice | git://f0xx.org/ac/ac-microservice/ac-ms-tracker
|-- AndroidCast - MS - RBAC | @ms-rbac | RBAC microservice | git://f0xx.org/ac/ac-microservice/ac-ms-rbac
... TBD
Sub-project of AndroidCast BE/MS, mostly Web UI stuff, but also should be OpenAPI-compatible and provide services to the mobile app (@ means suibmodule)
AndroidCast - BE - common <- AndroidCast - BE - MS | git://f0xx.org/ac/ac-backend
|-- AndroidCast - BE - vcs (UI) | @be-vcs | VCS frontend, former gitea, backend UI | git://f0xx.org/ac/ac-backend/ac-be-vcs
|-- AndroidCast - MS - vcs | @ms-vcs | VCS microservice (gitea) | git://f0xx.org/ac/ac-microservice/ac-ms-vcs
|-- AndroidCast - BE - console (UI) | @be-console | git://f0xx.org/ac/ac-backend/ac-be-console | primary console, ./examples/build_console ? check if it is
|-- AndroidCast - MS - common | @ms-common | git://f0xx.org/ac/ac-microservice/ac-ms-common | microservice commons
|-- AndroidCast - BE - landing (UI) | @be-landing | git://f0xx.org/ac/ac-backend/ac-be-landing | landing page(s), now in ./examples/app_hub
|-- AndroidCast - MS - common | @ms-common | git://f0xx.org/ac/ac-microservice/ac-ms-common | microservice commons
|-- AndroidCast - BE - issues (UI) | @be-issues | git://f0xx.org/ac/ac-backend/ac-be-issues | issues tracker UI, now is in ./examples somewhere
|-- AndroidCast - MS - tracker | @ms-tracker | git://f0xx.org/ac/ac-microservice/ac-ms-tracker | issues tracker microservice shared base, now is in ./examples somewhere
|-- AndroidCast - BE - tickets (UI) | @be-tickets | git://f0xx.org/ac/ac-backend/ac-be-tickets | tickets UI, now is in ./examples somewhere
|-- AndroidCast - MS - tracker | @ms-tracker | git://f0xx.org/ac/ac-microservice/ac-ms-tracker | issues tracker microservice shared base, now is in ./examples somewhere
|-- AndroidCast - BE - graphs (UI) | @be-graphs | git://f0xx.org/ac/ac-backend/ac-be-graphs | graphs UI, now somewhere in ./examples
|-- AndroidCast - MS - analytics | @ms-analytics | git://f0xx.org/ac/ac-microservice/ac-ms-analytics | analytics base microservice
|-- AndroidCast - BE - analytics (UI) | @be-analytics | git://f0xx.org/ac/ac-backend/ac-be-analytics | analytics and statistics web UI
|-- AndroidCast - MS - analytics | @ms-analytics | git://f0xx.org/ac/ac-microservice/ac-ms-analytics | analytics base microservice
|-- AndroidCast - BE - remote access (UI) | @be-remote-access | git://f0xx.org/ac/ac-backend/ac-be-remote-access | remote access (now for vpn, somewhere in ./examples now) UI
|-- AndroidCast - MS - common | @ms-commmon | git://f0xx.org/ac/ac-microservice/ac-ms-common | microservice commons
|-- AndroidCast - MS - VPN | @ms-vpn | git://f0xx.org/ac/ac-microservice/ac-ms-vpn | VPN MS as a dependency
|-- AndroidCast - MS - RBAC | @ms-rbac | @ms-rbac | git://f0xx.org/ac/ac-microservice/ac-ms-rbac | RBAC MS as a dependency
|-- AndroidCast - BE - URL shortener (UI) | @be-url-shortener | git://f0xx.org/ac/ac-backend/ac-be-url-shortener | URL shortener UI, now is in separate submodule
|-- AndroidCast - MS - URL shortener | @ms-url-shortener | git://f0xx.org/ac/ac-microservice/ac-ms-url-shortener | URL shortener microservice, now is in separate submodule
|-- AndroidCast - BE - builder (UI) | @be-builder | git://f0xx.org/ac/ac-backend/ac-be-builder | orchestration builder UI, now in ./orchestration
|-- AndroidCast - MS - orchestration | @ms-orchestration | git://f0xx.org/ac/ac-microservice/ac-ms-orchestration | orchestration microservice, now in ./orchestration
|-- AndroidCast - BE - RBAC (UI) | @be-rbac | git://f0xx.org/ac/ac-backend/ac-be-rbac | RBAC backend, now mixed within ./examples somewhere
|-- AndroidCast - MS - common | @ms-common | git://f0xx.org/ac/ac-microservice/ac-ms-common | microservice commons
|-- AndroidCast - MS - RBAC | @ms-rbac | git://f0xx.org/ac/ac-microservice/ac-ms-rbac | RBAC microservice
|-- AndroidCast - BE - OTA | @be-ota | git://f0xx.org/ac/ac-backend/ac-be-ota | OTA BE UI
|-- AndroidCast - MS - OTA | @ms-ota | git://f0xx.org/ac/ac-microservice/ac-ms-ota | OTA microservice, now intermixed in examples/ota and other commons
... TBD
ms-common (microservices common) needs a sharp eye, it may share project sensitive parts, like common stuff such as shared web sessions, DB access (or should be separated to @be-db-service/@ac-db-service sort of)

View File

@@ -0,0 +1,98 @@
Project repository and structure reorganization draft
milestone: R0-pre
severity: high
state: pre-implementation
author: Anton Afanasyeu
date: 2026-06-18
The problem:
The project looks like monolith. For better and more atomic support we need to reorganize the whole project repo structure
The what:
Current project structure
Project | Placement | Repo | State | Description
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
AndroidCast all in one | repo root | git://f0xx.org/android_cast | monolithic | all-in-one project, needs to be splitted
libvpx | third-party/libvpx | https://chromium.googlesource.com/webm/libvpx | 3rdparty exported submodule | VPx video codecs
opus | third-party/opus | https://github.com/xiph/opus | 3rdparty exported submodule | Opus voice codec
speex | third-party/speex | https://github.com/xiph/speex/ | 3rdparty exported submodule | Speex voice codec
wireguard | third-party/wireguard-android | https://git.zx2c4.com/wireguard-android | 3rdparty exported submodule | wireguard for android
url-shortener | backend/url-shortener | git://f0xx.org/androidcast_project/url-shortener | part of AndroidCast backend | url shortener standalone backend
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
The how:
Next hope project structure
AndroidCast project - all in one | git://f0xx.org/ac
|-- AndroidCast - common | @common
|-- AndroidCast - mobile | @mobile
|-- AndroidCast - BE | @backend
... TBD
AndroidCast project | Placement (@ - submodule) | Description | Repo
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
AndroidCast - common | @common | project all common | git://f0xx.org/ac/ac-common
|-- AndroidCast - docs | @docs | project docs, BE, MS, mobile, web, everything | git://f0xx.org/ac/ac-docs
|-- AndroidCast - scripts | @scripts | common project scripts | git://f0xx.org/ac/ac-scripts
AndroidCast - mobile | @mobile | mobile app sources | git://f0xx.org/ac/ac-mobile
|-- AndroidCast - common | @common | | git://f0xx.org/ac/ac-common
AndroidCast - Session Studio | @session-studio | offline analytic tools | git://f0xx.org/ac/ac-session-studio
|-- AndroidCast - common | @common | | git://f0xx.org/ac/ac-common
AndroidCast - BE - MS | @backend | backend microservices common base (UI) | git://f0xx.org/ac/ac-be-microservice
|-- AndroidCast - common | @common | | git://f0xx.org/ac/ac-common
AndroidCast - MS | @microservices | microservice commons | git://f0xx.org/ac/ac-microservice
|-- AndroidCast - common | @common | | git://f0xx.org/ac/ac-common
... TBD
AndroidCast BE microservices and their derivatives (OpenAPI providers, any REST API services for web and mobile apps)
AndroidCast - MS - template <- AndroidCast - MS (@ means suibmodule) |git://f0xx.org/ac/ac-microservice/ac-ms-template
| -- AndroidCast - common | @common | project all common | git://f0xx.org/ac/ac-common
| -- AndroidCast - MS - common | @ms-common | microservices common | git://f0xx.org/ac/ac-microservice/ac-ms-common
|-- AndroidCast - MS - builder | @ms-builder | builder microservice | git://f0xx.org/ac/ac-microservice/ac-ms-builder
|-- AndroidCast - MS - VPN | @ms-vpn | VPN microservice | git://f0xx.org/ac/ac-microservice/ac-ms-vpn
|-- AndroidCast - MS - VPN - RSSH | @ms-vpn-rssh | VPN RSSH microservice | git://f0xx.org/ac/ac-microservice/ac-ms-vpn-rssh
|-- AndroidCast - MS - VPN - WireGuard | @ms-vpn-wireguard | VPN WG microservice | git://f0xx.org/ac/ac-microservice/ac-ms-vpn-wireguard
|-- AndroidCast - MS - VCS | @ms-vcs | VCS microservice (gitea) | git://f0xx.org/ac/ac-microservice/ac-ms-vcs
|-- AndroidCast - MS - URL shortener | @ms-url-shortener | URL shortener microservice | git://f0xx.org/ac/ac-microservice/ac-ms-url-shortener
|-- AndroidCast - MS - analytics | @ms-analytics | analytics microservice | git://f0xx.org/ac/ac-microservice/ac-ms-analytics
|-- AndroidCast - MS - orchestration | @ms-orchestration | orchestration microservice | git://f0xx.org/ac/ac-microservice/ac-ms-orchestration
|-- AndroidCast - MS - tracker | @ms-tracker | issues & tickets tracker microservice | git://f0xx.org/ac/ac-microservice/ac-ms-tracker
|-- AndroidCast - MS - RBAC | @ms-rbac | RBAC microservice | git://f0xx.org/ac/ac-microservice/ac-ms-rbac
... TBD
Sub-project of AndroidCast BE/MS, mostly Web UI stuff, but also should be OpenAPI-compatible and provide services to the mobile app (@ means suibmodule)
AndroidCast - BE - common <- AndroidCast - BE - MS | git://f0xx.org/ac/ac-backend
|-- AndroidCast - BE - vcs (UI) | @be-vcs | VCS frontend, former gitea, backend UI | git://f0xx.org/ac/ac-backend/ac-be-vcs
|-- AndroidCast - MS - vcs | @ms-vcs | VCS microservice (gitea) | git://f0xx.org/ac/ac-microservice/ac-ms-vcs
|-- AndroidCast - BE - console (UI) | @be-console | git://f0xx.org/ac/ac-backend/ac-be-console | primary console, ./examples/build_console ? check if it is
|-- AndroidCast - MS - common | @ms-common | git://f0xx.org/ac/ac-microservice/ac-ms-common | microservice commons
|-- AndroidCast - BE - landing (UI) | @be-landing | git://f0xx.org/ac/ac-backend/ac-be-landing | landing page(s), now in ./examples/app_hub
|-- AndroidCast - MS - common | @ms-common | git://f0xx.org/ac/ac-microservice/ac-ms-common | microservice commons
|-- AndroidCast - BE - issues (UI) | @be-issues | git://f0xx.org/ac/ac-backend/ac-be-issues | issues tracker UI, now is in ./examples somewhere
|-- AndroidCast - MS - tracker | @ms-tracker | git://f0xx.org/ac/ac-microservice/ac-ms-tracker | issues tracker microservice shared base, now is in ./examples somewhere
|-- AndroidCast - BE - tickets (UI) | @be-tickets | git://f0xx.org/ac/ac-backend/ac-be-tickets | tickets UI, now is in ./examples somewhere
|-- AndroidCast - MS - tracker | @ms-tracker | git://f0xx.org/ac/ac-microservice/ac-ms-tracker | issues tracker microservice shared base, now is in ./examples somewhere
|-- AndroidCast - BE - graphs (UI) | @be-graphs | git://f0xx.org/ac/ac-backend/ac-be-graphs | graphs UI, now somewhere in ./examples
|-- AndroidCast - MS - analytics | @ms-analytics | git://f0xx.org/ac/ac-microservice/ac-ms-analytics | analytics base microservice
|-- AndroidCast - BE - analytics (UI) | @be-analytics | git://f0xx.org/ac/ac-backend/ac-be-analytics | analytics and statistics web UI
|-- AndroidCast - MS - analytics | @ms-analytics | git://f0xx.org/ac/ac-microservice/ac-ms-analytics | analytics base microservice
|-- AndroidCast - BE - remote access (UI) | @be-remote-access | git://f0xx.org/ac/ac-backend/ac-be-remote-access | remote access (now for vpn, somewhere in ./examples now) UI
|-- AndroidCast - MS - common | @ms-commmon | git://f0xx.org/ac/ac-microservice/ac-ms-common | microservice commons
|-- AndroidCast - MS - VPN | @ms-vpn | git://f0xx.org/ac/ac-microservice/ac-ms-vpn | VPN MS as a dependency
|-- AndroidCast - MS - RBAC | @ms-rbac | @ms-rbac | git://f0xx.org/ac/ac-microservice/ac-ms-rbac | RBAC MS as a dependency
|-- AndroidCast - BE - URL shortener (UI) | @be-url-shortener | git://f0xx.org/ac/ac-backend/ac-be-url-shortener | URL shortener UI, now is in separate submodule
|-- AndroidCast - MS - URL shortener | @ms-url-shortener | git://f0xx.org/ac/ac-microservice/ac-ms-url-shortener | URL shortener microservice, now is in separate submodule
|-- AndroidCast - BE - builder (UI) | @be-builder | git://f0xx.org/ac/ac-backend/ac-be-builder | orchestration builder UI, now in ./orchestration
|-- AndroidCast - MS - orchestration | @ms-orchestration | git://f0xx.org/ac/ac-microservice/ac-ms-orchestration | orchestration microservice, now in ./orchestration
|-- AndroidCast - BE - RBAC (UI) | @be-rbac | git://f0xx.org/ac/ac-backend/ac-be-rbac | RBAC backend, now mixed within ./examples somewhere
|-- AndroidCast - MS - common | @ms-common | git://f0xx.org/ac/ac-microservice/ac-ms-common | microservice commons
|-- AndroidCast - MS - RBAC | @ms-rbac | git://f0xx.org/ac/ac-microservice/ac-ms-rbac | RBAC microservice
|-- AndroidCast - BE - OTA | @be-ota | git://f0xx.org/ac/ac-backend/ac-be-ota | OTA BE UI
|-- AndroidCast - MS - OTA | @ms-ota | git://f0xx.org/ac/ac-microservice/ac-ms-ota | OTA microservice, now intermixed in examples/ota and other commons
... TBD
ms-common (microservices common) needs a sharp eye, it may share project sensitive parts, like common stuff such as shared web sessions, DB access (or should be separated to @be-db-service/@ac-db-service sort of)

View File

@@ -305,7 +305,7 @@ endobj
endobj
51 0 obj
<<
/Author (Android Cast project) /CreationDate (D:20260616121124+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260616121124+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Author (Android Cast project) /CreationDate (D:20260617220502+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260617220502+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (URL shortener service \204 specification) /Trapped /False
>>
endobj
@@ -647,7 +647,7 @@ xref
trailer
<<
/ID
[<61e6dc8dc43c449d33e78ae8cbec84ac><61e6dc8dc43c449d33e78ae8cbec84ac>]
[<db651936781475f5cdf0f7bf03422a2e><db651936781475f5cdf0f7bf03422a2e>]
% ReportLab generated PDF document -- digest (opensource)
/Info 51 0 R

View File

@@ -425,7 +425,7 @@ endobj
endobj
67 0 obj
<<
/Author (Android Cast project) /CreationDate (D:20260616121124+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260616121124+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Author (Android Cast project) /CreationDate (D:20260617220503+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260617220503+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (Platform scaling and multi-environment architecture \204 specification) /Trapped /False
>>
endobj
@@ -862,7 +862,7 @@ xref
trailer
<<
/ID
[<5e0868313874a2ecbb16da098bb3036c><5e0868313874a2ecbb16da098bb3036c>]
[<f0fbbf50d8dfd95b3b0f2c0df4aae3a2><f0fbbf50d8dfd95b3b0f2c0df4aae3a2>]
% ReportLab generated PDF document -- digest (opensource)
/Info 67 0 R