162 lines
7.0 KiB
Markdown
162 lines
7.0 KiB
Markdown
# W09 isolated Asterisk/ARI runtime PoC (2026-09-18)
|
|
|
|
## Scope and boundary
|
|
|
|
This is an owner-authorized, mock-only compatibility probe on the existing
|
|
Debian 13 ECS test host. It does not use a SIP provider, a real phone number,
|
|
SaaS, RabbitMQ, OSS, AI credentials, or the production Agent binary. It is not
|
|
W09, W13, W14, or P1 acceptance.
|
|
|
|
The probe was deliberately kept outside the project module at `/tmp/ari-poc`.
|
|
It uses the already reviewed temporary module:
|
|
|
|
- `github.com/CyCoreSystems/ari/v5` `v5.3.1`
|
|
- module checksum:
|
|
`h1:S+NHG1+uMwoAIl0hMBnRUGNZsQKQQQFq7XCRSE2c2mg=`
|
|
- Asterisk runtime: `22.10.1`
|
|
- source image reference: `andrius/asterisk@sha256:1fde2a38e17c42c4f8999bb80d2ac52a01543bc696a98e02faee1cf6f14d4d64`
|
|
- transferred image ID on the host:
|
|
`sha256:08c732ed191c02ad54c019c4e6b46b641bb3ebbe42fcd5b525eb41c6373f6128`
|
|
|
|
The image was transferred as an archive because Docker Hub was unreachable from
|
|
the host. The host-local tag is only a transport/runtime tag; it is not a new
|
|
upstream digest claim. The container is on the isolated Docker network
|
|
`agent-call-asterisk-poc`, with ARI published only on host loopback
|
|
`127.0.0.1:18088`.
|
|
|
|
## Runtime procedure
|
|
|
|
The temporary Go probe:
|
|
|
|
1. listened on host UDP `0.0.0.0:19000` as the external-media sink;
|
|
2. connected to ARI with the mock `sipmock` application and mock credentials;
|
|
3. originated an internal `Local/900001@ari-gate` channel, with no provider leg;
|
|
4. waited for `StasisStart`;
|
|
5. created a `mixing` bridge and added the internal channel;
|
|
6. created an `ExternalMedia` channel using RTP/UDP, PCMA (`alaw`), direction
|
|
`both`, and external host `172.18.0.1:19000`;
|
|
7. waited for the ExternalMedia `StasisStart`, added it to the bridge, read
|
|
`UNICASTRTP_LOCAL_ADDRESS` and `UNICASTRTP_LOCAL_PORT`, and then hung it up;
|
|
8. observed `StasisEnd` for the ExternalMedia channel.
|
|
|
|
The build and execution used the host-installed Go toolchain with
|
|
`GOTOOLCHAIN=local`; the resulting probe binary was copied to the ECS host and
|
|
run as `rogee`.
|
|
|
|
## Observed output
|
|
|
|
```text
|
|
local_channel=ari-poc-local
|
|
stasis_start channel=ari-poc-local args=[]
|
|
bridge=ari-poc-bridge data=&{Key:ari-poc-bridge ID:ari-poc-bridge Class:stasis Type:mixing ChannelIDs:[01m2syek1a93x6jkz567r1m3j8-ch ari-poc-local] Creator:Stasis Name:ari-poc-bridge Technology:simple_bridge}
|
|
external_channel=01m2syek1a93x6jkz567r1m3j8-ch state=Up name=UnicastRTP/172.18.0.1:19000-0x7f51780063b0
|
|
local_rtp=172.18.0.2:10748
|
|
probe_packets=0 peer=<nil> read_error=read udp4 0.0.0.0:19000: i/o timeout
|
|
stasis_end channel=01m2syek1a93x6jkz567r1m3j8-ch
|
|
```
|
|
|
|
The first run exposed a real ordering requirement: adding ExternalMedia to the
|
|
bridge before its `StasisStart` was observable returned HTTP `422`. Waiting for
|
|
that event made the bridge add succeed. This is useful compatibility evidence,
|
|
not a production implementation.
|
|
|
|
## Controlled RTP forwarding follow-up
|
|
|
|
A second temporary probe used two independent ExternalMedia channels in the
|
|
same mixing bridge. Both were configured as RTP/UDP, PCMA (`alaw`), direction
|
|
`both`. The host listened on `172.18.0.1:19000` and `172.18.0.1:19001`, sent 20
|
|
synthetic RTP packets to the first channel's Asterisk-local port, and captured
|
|
the bridge output at the second host port.
|
|
|
|
The successful run, after restarting only the isolated PoC container to clear
|
|
connections left by a timed-out disposable probe, returned:
|
|
|
|
```text
|
|
connected
|
|
bridge_created
|
|
first_created=01m2szdw9r2s4erk251qpm4pme-ch
|
|
first_stasis
|
|
first_added
|
|
second_created=01m2szdwa1p6a16jtqsyphcefj-ch
|
|
second_stasis
|
|
second_added
|
|
bridge=ari-poc-media first=172.18.0.2:10724 second=172.18.0.2:10256
|
|
forwarded_rtp_bytes=172 peer=172.18.0.2:10256 version=2 payload_type=8 sequence=63988 timestamp=800 ssrc=1b5ec593
|
|
stasis_end channel=01m2szdwa1p6a16jtqsyphcefj-ch
|
|
stasis_end channel=01m2szdw9r2s4erk251qpm4pme-ch
|
|
remote_rc=0
|
|
channels: []
|
|
bridges: []
|
|
```
|
|
|
|
This proves a controlled host-to-Asterisk-to-host RTP path through an Asterisk
|
|
mixing bridge and confirms RTP version 2, PCMA payload type 8, and lifecycle
|
|
cleanup. Asterisk rewrote the forwarded sequence/timestamp/SSRC; payload
|
|
identity and production jitter/clock behavior were not assessed.
|
|
|
|
## Recording close follow-up
|
|
|
|
A third temporary probe created the same two-channel synthetic bridge, started
|
|
an ARI bridge recording with format `wav`, injected 40 PCMA packets, stopped
|
|
the recording explicitly, and read the stored-recording metadata. The isolated
|
|
container first received the missing `/var/spool/asterisk/recording` directory
|
|
with `asterisk:asterisk` ownership; this was a disposable mock-container setup
|
|
change, not a production artifact.
|
|
|
|
The run returned:
|
|
|
|
```text
|
|
connected
|
|
recording_started name=ari-poc-record-20260918 format=wav state=recording
|
|
forwarded_rtp_bytes=172 peer=172.18.0.2:10250 payload_type=8
|
|
recording_stopped name=ari-poc-record-20260918 format=wav
|
|
stasis_end channel=01m2szqryme5sm3w89866j2key-ch
|
|
stasis_end channel=01m2szqryxqpz6xgakr28bgdj0-ch
|
|
recording_name=ari-poc-record-20260918
|
|
```
|
|
|
|
The closed file was inspected before cleanup:
|
|
|
|
```text
|
|
size=13804 mode=644 owner=asterisk:asterisk path=/var/spool/asterisk/recording/ari-poc-record-20260918.wav
|
|
sha256=c62bede7c200c99a9fb9d73eee11ebefe71397b71aeff4dbfe0a05dc7d112e82
|
|
header=RIFF/WAVE, PCM mono, 8000 Hz, 16-bit
|
|
channels: []
|
|
bridges: []
|
|
recording_cleanup=ok
|
|
```
|
|
|
|
The synthetic recording file was then removed from the disposable container.
|
|
This proves ARI recording start/stop, a closed WAV header, and cleanup in the
|
|
isolated environment; it does not prove business recording retention or OSS
|
|
upload semantics.
|
|
|
|
## Result
|
|
|
|
**Passed in isolation:** Asterisk 22.10.1 accepted the selected ARI client at
|
|
runtime; internal Stasis channels and mixing bridges were created; RTP/UDP
|
|
PCMA ExternalMedia channels reached `Up`; Asterisk-local RTP addresses and
|
|
ports were retrievable; bridge insertion required and honored `StasisStart`;
|
|
a controlled RTP packet stream traversed the bridge; an ARI bridge recording
|
|
started and stopped with a valid closed WAV file; the artifact was cleaned; and
|
|
both channels produced clean `StasisEnd` lifecycle events.
|
|
|
|
**Not proven:** this remains synthetic ExternalMedia-to-ExternalMedia traffic,
|
|
not a SIP/RTP provider leg or an Agent media session. The separate isolated
|
|
SIPp-to-PJSIP/ARI signaling result is recorded in
|
|
`docs/evidence/20260918-w09-sip-ari.md`. Full same-channel bidirectional
|
|
semantics, exact PCMA sample preservation, reconnect/fencing behavior, provider
|
|
lines, static artifact loading, Agent integration, retention/OSS upload, and
|
|
capacity were not tested. The result
|
|
therefore only advances the compatibility PoC and does not unlock W09's full
|
|
M/G gate or any P1/production claim.
|
|
|
|
## Follow-up gate
|
|
|
|
Before selecting ARI in the production module, retain this runtime result and
|
|
complete the separate library/license/security review, full media-session and
|
|
reconnect/fencing tests, approved static Asterisk/Cell artifact loading,
|
|
retention/OSS handoff, and the remaining SIP/provider validation. Real provider
|
|
and telephone tests remain under W14 authorization and are not implied by this
|
|
document.
|