# PSTN simulator

Test your system the way the outside world uses it: call your DIDs from the
"public telephone network", decide how PSTN numbers answer the calls your
system places through the vendors, and register simulated desk phones to your
PBX. Course staff test your system with the same simulator.

Base URL: `https://pstn.cse356.compas.cs.stonybrook.edu`. Every request needs
`Authorization: Bearer <your PSTN simulator token>` (Course Services tab).
Bodies are JSON. Times in call reports are milliseconds since the call started.

## Calls

A call is one leg the simulator is part of. `kind` is `pstn_to_did` (the PSTN
calling one of your DIDs), `vendor_to_pstn` (your system calling a PSTN number
through a vendor), `phone_out` (a simulated phone dialing), or `phone_in` (your
PBX ringing a simulated phone). `state` goes `calling` → `ringing` →
`answered` → `ended`.

- `POST /v1/calls` `{ "to": "+16317198221", "from": "+12125550123", "script": [...], "ring_timeout_ms": 60000 }`
  calls one of your DIDs through the DID provider. `from` is the caller ID.
- `GET /v1/calls?kind=&phone_id=&number=&after=<call id>&wait_ms=&limit=` lists
  calls, newest first. With `wait_ms`, waits until a call matching the filters
  (created after `after`) exists, e.g. to catch the call your system places.
- `GET /v1/calls/{id}?wait=answered&timeout_ms=10000` returns the call, first
  waiting until it reaches that state (or later) or the timeout passes.
- `POST /v1/calls/{id}/actions` `{ "actions": [...] }` adds actions to the call's queue.
- `DELETE /v1/calls/{id}` hangs up (or cancels, or rejects a ringing incoming call).
- `GET /v1/calls/{id}/recording.wav?from_ms=&to_ms=` is what the simulator heard (8 kHz, 16-bit mono).
- `GET /v1/calls/{id}/analysis?freqs=440,1000&from_ms=&to_ms=` finds tones and
  DTMF in what it heard: `tones` (segments per frequency), `dtmf_inband`,
  `dtmf_rfc4733`, `level_dbfs`.

The call report includes the SIP responses and events (`timeline`), the
negotiated codec and whether media was encrypted (`media`), DTMF received,
and the result of each action (`results`).

### Actions

Actions run one after another once the call is answered.

| Action | |
|---|---|
| `{ "type": "wait", "ms": 1000 }` | |
| `{ "type": "play", "tone": { "freqs": [1000], "ms": 2000 } }` | also `"wav": "<sound id>"` or `"silence_ms"`; `"wait": false` plays in the background |
| `{ "type": "echo", "ms": 10000 }` | sends back what it hears |
| `{ "type": "dtmf", "digits": "1#", "duration_ms": 120, "gap_ms": 120 }` | RFC 4733 events when negotiated, otherwise inband tones (`"mode"` forces one) |
| `{ "type": "wait_for_tone", "freq": 1000, "timeout_ms": 10000, "min_ms": 200 }` | fails if not heard in time |
| `{ "type": "wait_for_dtmf", "digits": "5", "timeout_ms": 10000 }` | RFC 4733, inband or SIP INFO |
| `{ "type": "hold" }`, `{ "type": "unhold" }` | re-INVITE with `sendonly` / `sendrecv` |
| `{ "type": "transfer", "mode": "blind", "target": "102" }` | REFER (phones) |
| `{ "type": "transfer", "mode": "attended", "consult_call": "<call id>" }` | REFER with Replaces to another answered call of the same phone |
| `{ "type": "answer" }`, `{ "type": "reject", "code": 486 }` | for ringing incoming calls |
| `{ "type": "hangup" }` | |

Sounds: `PUT /v1/sounds/{id}` with a WAV body (`Content-Type: audio/wav`,
16-bit PCM, any rate) stores audio for `play`.

## PSTN numbers

Calls your system places through the vendors end at the simulator. By default
a number rings for 1 s, answers, and echoes what it hears. A call to a number
that is an active DID goes back into the DID provider, as on the real PSTN.

- `PUT /v1/numbers/{e164}` `{ "ring_ms": 3000, "answer": true, "reject_code": null, "script": [...] }`
  sets how that number answers your group's calls: `reject_code` (486 busy,
  603 decline, ...) rejects after `ring_ms`; `answer: false` rings until your
  system gives up.
- `GET /v1/numbers`, `DELETE /v1/numbers/{e164}`.

## Desk phones

- `POST /v1/phones` `{ "username": "...", "password": "...", "transport": "udp", "answer": "auto", "ring_ms": 1000, "script": [...] }`
  registers a phone with an extension's SIP credentials at
  `<group>.cse356.compas.cs.stonybrook.edu` (or `"domain"`), finding your PBX
  through your `_sip._udp` / `_sips._tcp` SRV records (or the A record on
  5060/5061). `transport: "tls"` uses SRTP (`"srtp": "required"`, SDES) unless
  `"srtp": "off"`. Phones offer PCMU and PCMA with telephone-event. The reply
  shows the registration result (`state`, `last_code`, `last_error`); phones
  re-register before their registration expires.
- `answer`: `auto` (answer after `ring_ms`, then run `script`; default echo),
  `manual` (ring until you send `answer` / `reject`), `never`; `reject_code`
  rejects instead. `PATCH /v1/phones/{id}` changes these.
- `POST /v1/phones/{id}/calls` `{ "to": "102", "script": [...] }` dials through
  your PBX (an extension, `*98`, or an E.164 number).
- `GET /v1/phones`, `GET /v1/phones/{id}`, `POST /v1/phones/{id}/register`, `DELETE /v1/phones/{id}` (unregisters).

A phone that receives a REFER follows it (calling the target, with Replaces
if given) and reports progress with NOTIFY.

Limits per group: 30 simultaneous calls, 200 phones. State is kept in memory
for two hours.
