Skip to content

Commit 2e49edf

Browse files
authored
AMR codecs, proxy interop, and the 0.3.7 catch-up for 0.3.8 (#181)
Brings feat/amr-codecs up to the released 0.3.7 base and takes the two commits ahead of it, so 0.3.8 can be cut from main. Includes 023c064 (RFC 3261 12.1.1 secure fallback Contact, refs #176) and 34b7310 (observation-only coordinator on the profiled egress registration, for Bridgefu security evidence), plus two defects that existed only in the merged tree: the opus passthrough bypass defeated by per-leg payload numbering, and a barge-in flush that missed the AMR re-framer. PR Gate is green across 35 checks. CodeQL is red and was reviewed rather than waved through: by stable alert identity main carries 697 open alerts and this branch 703. Of the 11 in the delta, four are main's own unchanged lines that were renumbered when the Kamailio and OpenSIPS provider blocks were inserted above them, one is in a workflow file byte-identical to main, four are false positives (an IP literal, two SRTP boolean flags, and a println of tone and SNR figures), and two are the accept-all proxy lab's default password, which the registrar never challenges for. No new security defect. Verified before merge: workspace check --all-targets --locked, the full --all-features test run, the perf target under --release, and the Kamailio proxy matrix at 32/32 -- registration, basic call, and AMR NB/WB in both octet-aligned and bandwidth-efficient modes over UDP and TLS, through a record-routing proxy with rtpengine. Bridgefu 53ef1c7 compiles against this tree with the workspace patched over its =0.3.7 pins.
2 parents dba121e + 078db3d commit 2e49edf

418 files changed

Lines changed: 100769 additions & 823 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/main-ci.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ jobs:
4848
--job-mode combined
4949
--deferred-sip-mode separate
5050
--github-output "$GITHUB_OUTPUT"
51+
--specialty-gate codec-features-codec-core
52+
--specialty-gate codec-features-media-core
53+
--specialty-gate codec-features-sip
54+
--specialty-gate codec-features-core
5155
--specialty-gate release-tooling
5256
--specialty-gate rtp-interop
5357
--specialty-gate vcon-postgres

.gitignore

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,3 +168,22 @@ config.stamp
168168

169169
## CCD session state — never publish.
170170
.claude/
171+
172+
## PBX interop labs
173+
# Local env: machine-specific addresses and credentials. The committed
174+
# *.env.example files are the templates; a real env/<provider>.env is sourced
175+
# after the lab-generated ~/Developer/<provider>/*-local.env and therefore
176+
# OVERRIDES it, so committing one silently redirects the release runners at a
177+
# developer's own lab addresses.
178+
crates/sip/rvoip-sip/examples/pbx/env/*.env
179+
!crates/sip/rvoip-sip/examples/pbx/env/*.env.example
180+
# Run artifacts: logs, WAVs, pcaps, matrix.tsv and per-role metadata, all
181+
# regenerated by every ./run.sh. Nothing reads the committed copy — the
182+
# release gates write their evidence to PBX_OUT_ROOT (the artifact dir)
183+
# instead — and the files embed absolute paths from whichever machine
184+
# produced them, so committing them adds churn and leaks local layout.
185+
crates/sip/rvoip-sip/examples/pbx/output/
186+
# Proxy lab configs rendered by up.sh from the .in templates, with the run's
187+
# public host, ports and a freshly generated TLS key beside them. Regenerated
188+
# every bring-up and machine-specific; the templates are what is tracked.
189+
infra/release-runners/pbx/*/.rendered/

CONTRIBUTING.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ qualification instead of holding every SIP PR open. Changes to shared or
2828
unmapped build inputs deliberately select the full workspace, while CI-policy-
2929
only changes run the planner and policy tests.
3030

31+
Shards build each crate with its *default* features, so a test that lives
32+
behind an optional feature is compiled out rather than run. Where a crate keeps
33+
substantial test code behind such a feature — the codecs do, since G.729, Opus
34+
and AMR are all optional — a specialty gate repeats the run with
35+
`--all-features`. If you add an optional feature that carries tests, put it
36+
behind a gate; otherwise the tests exist and nothing executes them.
37+
3138
## Pull request expectations
3239

3340
Complete the pull request template, including:

README.md

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -55,25 +55,29 @@ them.
5555

5656
- **Beta-qualified** — covered by the SIP release gate and its bounded
5757
interoperability, security, standards, performance, and soak evidence.
58-
- **Available — developer preview** — implemented and included in `0.3.2`,
59-
but API-unstable or outside the SIP beta attestation.
58+
- **Available — developer preview** — implemented and available in the
59+
workspace, but API-unstable or outside the SIP beta attestation.
6060
- **Planned** — not implemented; listed only in the [roadmap](#roadmap).
6161

6262
## SIP interoperability
6363

6464
The 0.3.2 full release run passed all 16 selected PBX and interoperability
65-
gates. The table distinguishes peers that were actually exercised from proxy
66-
targets that were only audited and deliberately excluded from the release
67-
claim.
65+
gates. The table distinguishes peers that were exercised by that release run
66+
from proxy targets that it audited and deliberately excluded.
6867

69-
| Peer/tool | 0.3.2 status | Executed scope |
68+
Both proxies have since been exercised in the AMR interop lab. That is lab
69+
evidence, labelled as such: it does not join the 0.3.2 release claim, and it
70+
does not meet the four-peer attestation boundary described
71+
[below](#sip-interoperability-attestation).
72+
73+
| Peer/tool | Status | Executed scope |
7074
| --- | --- | --- |
71-
| **Asterisk** | **Interop matrix passed** | `Endpoint`, `StreamPeer`, and `CallbackPeer`; registration, basic call, G.729A/G.729AB, hold/resume, ring-cancel, RFC 4733 DTMF, rejection, and blind transfer over UDP and TLS |
72-
| **FreeSWITCH** | **Interop matrix passed** | The same API, scenario, codec, and UDP/TLS matrix as Asterisk |
73-
| **SIPp** | **Standalone matrix passed** | 30, 100, 300, 1,000, and 2,000 CPS; every configured call completed |
74-
| **baresip** | **Strict-UA check passed** | External user-agent call against the rvoip SIP listener |
75-
| **Kamailio** | **Not release-tested** | Named proxy/RTPengine investigation track; the 0.3.2 gate records a de-scope audit, not a Kamailio interoperability claim |
76-
| **OpenSIPS** | **Not release-tested** | Named proxy/RTPengine investigation track; the 0.3.2 gate records a de-scope audit, not an OpenSIPS interoperability claim |
75+
| **Asterisk** | **0.3.2 interop matrix passed** | `Endpoint`, `StreamPeer`, and `CallbackPeer`; registration, basic call, G.729A/G.729AB, hold/resume, ring-cancel, RFC 4733 DTMF, rejection, and blind transfer over UDP and TLS |
76+
| **FreeSWITCH** | **0.3.2 interop matrix passed** | The same API, scenario, codec, and UDP/TLS matrix as Asterisk |
77+
| **SIPp** | **0.3.2 standalone matrix passed** | 30, 100, 300, 1,000, and 2,000 CPS; every configured call completed |
78+
| **baresip** | **0.3.2 strict-UA check passed** | External user-agent call against the rvoip SIP listener |
79+
| **Kamailio** | **Lab-tested; not release-gated** | Registrar-proxy with an rtpengine media relay: registration, calls, AMR in all four framings relayed verbatim, DTMF, and SDES-SRTP, over UDP and TLS. No TCP, no second adjacency order, and not bound into the release attestation |
80+
| **OpenSIPS** | **Lab-tested; not release-gated** | The same lab scope over UDP only — no TLS image yet |
7781

7882
See the [0.3.2 complete gate
7983
record](crates/sip/rvoip-sip/docs/BETA_GATE_EXCEPTION.md) and
@@ -198,6 +202,7 @@ voice AI, and cross-transport integrations:
198202
| RTP/RTCP and G.711 | **Beta-qualified** | PCMU/PCMA media delivery, RTCP receiver reports, telephone-event DTMF, hold/resume, and bridging | [`rvoip-media-core`](crates/media/media-core) |
199203
| SDES-SRTP | **Beta-qualified** | Tested AES-CM/HMAC profiles with negotiated encrypted media | [`07-secure-call-srtp`](examples/07-secure-call-srtp) |
200204
| G.729A/G.729AB | **Available — developer preview** | Fully integrated optional path: PT 18 SDP/Annex B negotiation, RTP encode/decode, G.711 transcoding, and Asterisk/FreeSWITCH matrix coverage; excluded only from the general SIP full-media performance claim | [0.3.2 gate record](crates/sip/rvoip-sip/docs/BETA_GATE_EXCEPTION.md) |
205+
| AMR-NB and AMR-WB | **Available — developer preview** | Both variants behind `amr-nb`/`amr-wb`: encoders and decoders bit-exact against the 3GPP reference implementations over the committed fixtures and the normative sequences, RFC 4867 octet-aligned and bandwidth-efficient framing checked against Wireshark's dissector, DTX, CMR and mode negotiation, every mode exercised in a live call, SDES-SRTP, and live calls through Asterisk, FreeSWITCH, Kamailio and OpenSIPS; outside the SIP beta attestation | [AMR status](crates/media/codec-core/docs/AMR_IMPLEMENTATION_STATUS.md) |
201206
| Opus and G.722 paths | **Available — developer preview** | Feature-gated codec/media support; not part of the bounded SIP beta media claim | [`rvoip-media-core`](crates/media/media-core) |
202207
| OS audio devices | **Available — developer preview** | Microphone/speaker bridge, drift-free pacing, resampling, jitter buffering, mute-as-silence, and VU metering | [`02-softphone-audio`](examples/02-softphone-audio) |
203208
| Conference mixing | **Available — developer preview** | Lower-level N-way/N-1 mixing and conference monitoring primitives; not an integrated SIP beta conference product | [Media README](crates/media/media-core/README.md) |

ROADMAP.md

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# rvoip Roadmap
2+
3+
**Updated:** 2026-08-11
4+
**Purpose:** portfolio-level rollup of active and future work across the rvoip
5+
workspace. Detailed component plans remain authoritative for acceptance criteria
6+
and implementation history.
7+
8+
## Status model
9+
10+
- **Active** — accepted work with an existing detailed tracker.
11+
- **Future** — desired direction; not scheduled and not a support claim.
12+
- **Research** — requires standards, interoperability, dependency, or product
13+
validation before implementation is committed.
14+
15+
## Active engineering tracks
16+
17+
| Track | Status | Detailed tracker |
18+
|---|---|---|
19+
| Open-internet media hardening | Active | [`docs/PRODUCTION_HARDENING_ROADMAP.md`](docs/PRODUCTION_HARDENING_ROADMAP.md) — DTLS fragmentation, crypto review, CI/hygiene follow-through |
20+
| Cross-product architecture gaps | Active | [`docs/GAP_PLAN.md`](docs/GAP_PLAN.md) — deferred v1.x/v2 work and protocol adapters |
21+
| UCTP completion | Active | [`crates/uctp/rvoip-uctp/UCTP_GAP_PLAN.md`](crates/uctp/rvoip-uctp/UCTP_GAP_PLAN.md) — browser bidi-stream interoperability and per-session SIP codec override |
22+
| SIP standards promotion | Active | [`docs/sip/SIP_RFC_COMPLIANCE.md`](docs/sip/SIP_RFC_COMPLIANCE.md#roadmap-rollup) — partial/type-only behaviors to promote with executable evidence |
23+
| SIP transport reliability | Active | [`crates/sip/sip-transport/TODO.md`](crates/sip/sip-transport/TODO.md) — failover, recovery, backpressure, load/stress, and interoperability |
24+
25+
## Future protocols and products
26+
27+
| Initiative | Status | Intended integration |
28+
|---|---|---|
29+
| SIP-over-QUIC | Future | Add a QUIC transport to `rvoip-sip-transport`; keep the SIP transaction/dialog layers transport-neutral. |
30+
| RTP-over-QUIC (RoQ) | Future | Add a codec-agnostic `rvoip-roq` adapter for RTP/RTCP over QUIC DATAGRAMs and, where useful, QUIC streams. Preserve UCTP's distinct datagram framing and bridge at the media-adapter boundary. |
31+
| **Lyra V2 over UCTP, RTP, SIP, and RoQ** | Research | Add an optional Lyra V2 codec backend, an experimental RTP payload mapping, UCTP capability negotiation, SIP SDP integration, and a Lyra-over-RoQ end-to-end proof. See the workstream below. |
32+
| Media over QUIC (MoQ) | Future | Extend the existing MoQ crates toward broadcast-scale fan-out and UCTP/WebRTC bridging. |
33+
| Multi-party SFU/MCU products | Future | Build integrated products on the shipped media and subscription-routing primitives. |
34+
| AAuth production graduation | Future | Graduate the experimental standards work after security and deployment evidence mature. |
35+
| Deeper AI participants | Future | Add multi-agent orchestration beyond the current pluggable provider harness. |
36+
| QUIC multipath/NAT traversal | Research | Re-evaluate `noq` or equivalent when direct peer-to-peer and mobile multipath requirements justify a `quinn`-compatible change. |
37+
38+
## Lyra V2 + RTP-over-QUIC workstream
39+
40+
### Goal
41+
42+
Demonstrate a bidirectional voice session that encodes 20 ms PCM frames with
43+
Lyra V2, packetizes them as RTP, and carries the same RTP stream over either
44+
ordinary UDP or RoQ. The proof must work through both a UCTP Session and a SIP
45+
call controlled by `rvoip-sip`.
46+
47+
This is initially an **experimental, controlled-endpoint profile**. Lyra does
48+
not currently have an IETF-standard RTP payload format or a broadly deployed
49+
IANA/SDP registration, and RoQ is not yet a broadly deployed production
50+
transport. The roadmap must not imply third-party interoperability until a
51+
stable specification and independent test evidence exist.
52+
53+
### Component ownership
54+
55+
1. **`rvoip-codec-core` — Lyra V2 codec backend**
56+
- Add an opt-in feature and isolate the Google Lyra/TFLite native dependency
57+
from default builds.
58+
- Support mono 20 ms frames, 3.2/6/9.2 kbps, and the Lyra V2-supported
59+
external sample rates.
60+
- Expose encode/decode, bitrate selection, packet-loss concealment behavior,
61+
and capability metadata through the existing codec abstractions.
62+
63+
2. **`rvoip-rtp-core` — experimental Lyra RTP profile**
64+
- Add packetizer/depacketizer support using a dynamic payload type.
65+
- Define the controlled-profile SDP shape, initially following the proven
66+
experimental convention `lyra/<clock-rate>/1` with a `bitrate` `fmtp`
67+
parameter.
68+
- Specify timestamp increments, frame aggregation rules, marker behavior,
69+
loss handling, and maximum packet size. Keep the profile explicitly
70+
namespaced/experimental until standardized.
71+
72+
3. **`rvoip-uctp` — Lyra capability and bridge support**
73+
- Advertise Lyra V2 clock rates, bitrates, frame duration, and experimental
74+
RTP profile in `CapabilityDescriptor` negotiation.
75+
- Carry Lyra RTP packets through the existing UCTP media datagram framing;
76+
do not create a second codec-specific UCTP wire format.
77+
- Add codec selection, mismatch refusal, and optional transcoding fallback
78+
for UCTP-to-SIP bridges.
79+
80+
4. **`rvoip-roq` — RTP/RTCP over QUIC**
81+
- Implement RoQ flow-ID mapping over QUIC DATAGRAMs first; evaluate stream
82+
modes separately so reliable delivery cannot accidentally add
83+
head-of-line latency to conversational audio.
84+
- Remain codec-agnostic, with Lyra V2 as the first low-bitrate audio proof
85+
and Opus/G.711 as interoperability controls.
86+
- Define RTCP/congestion-control ownership and whether QUIC transport
87+
feedback can safely replace any RTCP feedback in each deployment mode.
88+
89+
5. **`rvoip-sip` — negotiation and end-to-end product integration**
90+
- Offer/answer the experimental Lyra RTP profile in SDP only when enabled.
91+
- Complete the existing per-session codec-override gap so re-INVITEs and
92+
UCTP/SIP bridges can select Lyra without changing global codec policy.
93+
- Support SIP signaling with a media leg using Lyra RTP over UDP and a
94+
bridged media leg using the same RTP packets over RoQ.
95+
- Treat RoQ as a media transport selected by the media adapter, not as a new
96+
SIP message encoding. SIP-over-QUIC remains a separate roadmap item.
97+
98+
### Proof and qualification gates
99+
100+
- Codec golden vectors and encode/decode round trips for every supported
101+
bitrate and enabled clock rate.
102+
- RTP sequence/timestamp, loss, reordering, aggregation, and SDP negotiation
103+
tests.
104+
- UCTP Lyra-to-Lyra loopback and UCTP-to-SIP bridge tests.
105+
- `rvoip-sip` calls using Lyra/RTP over UDP, then the same RTP flow tunneled over
106+
QUIC DATAGRAMs through `rvoip-roq`.
107+
- Comparison runs against Opus and G.711 under clean, lossy, reordered, and
108+
mobile-path-migration conditions.
109+
- Measure mouth-to-ear latency, CPU, memory, packet-loss behavior, and actual
110+
wire bitrate at 20, 40, and 100 ms packetization intervals. Report codec,
111+
RTP/RTCP, QUIC, and IP/UDP overhead separately.
112+
- Security review of QUIC-only transport encryption versus retaining SRTP for
113+
end-to-end protection across a terminating RoQ gateway.
114+
- Independent endpoint interoperability before removing the experimental
115+
label or making a compatibility claim.
116+
117+
## Maintenance
118+
119+
- Keep this file as the root portfolio rollup; do not copy detailed phase
120+
histories into it.
121+
- Add new work here when it crosses crate/product boundaries. Keep crate-local
122+
TODOs and acceptance details in the linked component tracker.
123+
- A published crate, feature flag, or experimental demo is not by itself a
124+
production-readiness or interoperability claim.

crates/extensions/rvoip-vapi/src/types.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,17 +46,22 @@ impl VapiAudioFormat {
4646

4747
pub fn codec(self) -> CodecInfo {
4848
match self {
49+
// Both advertise what this transport can carry rather than
50+
// reporting a negotiation, so neither names a payload type.
51+
// Both are static names that `codec_to_pt` already resolves.
4952
Self::MuLaw8Khz => CodecInfo {
5053
name: "PCMU".into(),
5154
clock_rate_hz: 8_000,
5255
channels: 1,
5356
fmtp: None,
57+
payload_type: None,
5458
},
5559
Self::PcmS16Le16Khz => CodecInfo {
5660
name: "pcm_s16le".into(),
5761
clock_rate_hz: 16_000,
5862
channels: 1,
5963
fmtp: None,
64+
payload_type: None,
6065
},
6166
}
6267
}

0 commit comments

Comments
 (0)