@origonai/web-sdk 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/dist/index.d.ts +5 -0
- package/dist/origon-web-sdk.js +603 -565
- package/dist/origon-web-sdk.js.map +1 -1
- package/docs/backend-integration.md +17 -30
- package/docs/contract.md +21 -0
- package/docs/voice.md +12 -1
- package/package.json +1 -1
|
@@ -82,7 +82,7 @@ Document a min-supported-browser policy with the product team.
|
|
|
82
82
|
|---|---|---|
|
|
83
83
|
| Bidi QUIC stream | `wt.createBidirectionalStream()` (client-opened) | ControlMessages — Connect, NegotiateMedia, Hold, Mute, SendDtmf, Resume + their `*Ok` + server-push |
|
|
84
84
|
| QUIC datagrams | `wt.datagrams` (readable + writable streams) | Audio frames (one frame per datagram), uplink + downlink |
|
|
85
|
-
| QUIC uni stream (server→client) | `wt.incomingUnidirectionalStreams` |
|
|
85
|
+
| QUIC uni stream (server→client) | `wt.incomingUnidirectionalStreams` | Drained as unsupported protocol input; no public receive lane |
|
|
86
86
|
| QUIC graceful close | `wt.close({ closeCode, reason })` | Hangup |
|
|
87
87
|
|
|
88
88
|
Everything in [`client-integration.md`](client-integration.md) §4–§12 applies
|
|
@@ -154,8 +154,8 @@ After `ConnectOk` the bidi multiplexes:
|
|
|
154
154
|
- Your verbs out (`Hold`, `Mute`, `SendDtmf`, `Resume`, `NegotiateMedia`).
|
|
155
155
|
- Server `*Ok` responses (correlate by `request_id`).
|
|
156
156
|
- Server-push events (`PeerAttached`, `PeerDetached`, `EndpointHeld`,
|
|
157
|
-
`EndpointMuted`, `PeerStateChanged`, `
|
|
158
|
-
|
|
157
|
+
`EndpointMuted`, `PeerStateChanged`, `EndpointHangup`, `MoqError`) — these
|
|
158
|
+
carry `request_id = 0`.
|
|
159
159
|
|
|
160
160
|
A single read loop on `ctrl.readable.getReader()` is sufficient. Dispatch
|
|
161
161
|
by `msg_type`.
|
|
@@ -232,30 +232,18 @@ manual PLC). Server never retransmits.
|
|
|
232
232
|
|
|
233
233
|
---
|
|
234
234
|
|
|
235
|
-
## 6. DTMF
|
|
235
|
+
## 6. DTMF flow input
|
|
236
236
|
|
|
237
|
-
|
|
238
|
-
|
|
237
|
+
`SessionManager.sendDtmf(sessionId, digit)` sends exactly one symbol from
|
|
238
|
+
`0-9*#A-D` as `SendDtmf` on the bidi control stream. It resolves only after
|
|
239
|
+
the matching `SendDtmfOk`, which acknowledges Media publication to the active
|
|
240
|
+
CX flow. Request-scoped Media errors reject only the matching call.
|
|
239
241
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
// stream is a ReadableStream<Uint8Array>
|
|
246
|
-
handleDtmfUniStream(stream) // decodes SubgroupHeader + DtmfEvent + EndOfGroup
|
|
247
|
-
}
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
The framing on this stream is documented in
|
|
251
|
-
[`docs/wire-protocol.md`](wire-protocol.md) §"Stream paths (non-audio)".
|
|
252
|
-
The payload is a single `DtmfEvent { digit, duration_ms }` protobuf
|
|
253
|
-
message.
|
|
254
|
-
|
|
255
|
-
DTMF *to the server* (you pressing a digit) is the `SendDtmf` verb on
|
|
256
|
-
the bidi control stream — not a uni stream. The browser cannot open
|
|
257
|
-
WT uni sub-streams at all in some specs/browsers, so we never required
|
|
258
|
-
it for the outbound direction.
|
|
242
|
+
The request belongs to the WebTransport on which it was sent. A close rejects
|
|
243
|
+
it; reconnect/Resume never queues or replays it, and a stale ACK is ignored.
|
|
244
|
+
The SDK does not receive peer-generated DTMF, expose a DTMF callback, synthesize
|
|
245
|
+
a tone, or imply PSTN/carrier delivery. Incoming uni streams are drained only
|
|
246
|
+
to keep the transport healthy.
|
|
259
247
|
|
|
260
248
|
---
|
|
261
249
|
|
|
@@ -268,13 +256,12 @@ Same shape as native. See [`client-integration.md`](client-integration.md)
|
|
|
268
256
|
|---|---|---|
|
|
269
257
|
| `Hold { held: bool }` | Client → Server | `session.hold` |
|
|
270
258
|
| `Mute { scope: Uplink \| Downlink \| Both \| None }` | Client → Server | `session.mute_self` |
|
|
271
|
-
| `SendDtmf {
|
|
259
|
+
| `SendDtmf { request_id, digit }` | Client → Server | `dtmf_send` |
|
|
272
260
|
| `Resume { call_token, last_event_seq }` | Client → Server | (token only) |
|
|
273
261
|
| `NegotiateMedia { offers, frame_size_ms }` | Client → Server | (token only; additive) |
|
|
274
262
|
|
|
275
|
-
The corresponding `*Ok` responses carry the echoed `request_id`.
|
|
276
|
-
|
|
277
|
-
`PeerStateChanged`, `DtmfReceived`) for other peers' UI consistency.
|
|
263
|
+
The corresponding `*Ok` responses carry the echoed `request_id`. DTMF has no
|
|
264
|
+
peer receive event; `SendDtmfOk` acknowledges Media publication only.
|
|
278
265
|
|
|
279
266
|
---
|
|
280
267
|
|
|
@@ -446,7 +433,7 @@ async function startCall({ url, jwt, certHash /* optional */ }) {
|
|
|
446
433
|
startBidiReadLoop(reader, dispatchEvent) // server-push + verb Oks
|
|
447
434
|
startDatagramSender(wt, audioAlias, serverEpochUnix) // mic → Opus → datagram
|
|
448
435
|
startDatagramReceiver(wt) // datagrams → decoders
|
|
449
|
-
|
|
436
|
+
startUniStreamDrain(wt) // unsupported server uni input
|
|
450
437
|
|
|
451
438
|
// 5. Wait for session end
|
|
452
439
|
wt.closed.then(info => onClosed(info), err => onError(err))
|
package/docs/contract.md
CHANGED
|
@@ -39,6 +39,27 @@ Run typecheck, unit tests, and the production build, then rebuild both linked
|
|
|
39
39
|
declarations and artifact bytes before publication. Publishing to npm remains
|
|
40
40
|
an owner action and is never part of an implementation spin.
|
|
41
41
|
|
|
42
|
+
## Internal voice DTMF wire codec
|
|
43
|
+
|
|
44
|
+
- The browser codec encodes `SEND_DTMF=0x58` as
|
|
45
|
+
`requestId (QUIC varint) | digit (exactly one ASCII byte)` and decodes
|
|
46
|
+
`SEND_DTMF_OK=0x59` as the echoed request id only. The accepted alphabet is
|
|
47
|
+
exactly `0-9*#A-D`; empty, multi-byte, lowercase, non-ASCII, and trailing
|
|
48
|
+
bytes fail closed.
|
|
49
|
+
- Request-scoped Media refusals remain the existing `MoqError` path:
|
|
50
|
+
`CapabilityMissing`, `IllegalState`, or `ResourceExhausted`. An ACK means
|
|
51
|
+
input acceptance for the owning CX flow, not peer delivery, tone playback,
|
|
52
|
+
or carrier forwarding.
|
|
53
|
+
- `src/voice/wire/testdata/send_dtmf_golden.txt` is a byte-identical copy of
|
|
54
|
+
Media's producer-owned canonical fixture at
|
|
55
|
+
`core/media/modules/moq-endpoint/testdata/send_dtmf_golden.txt`.
|
|
56
|
+
- `VoiceSession.sendDtmf(digit)` and
|
|
57
|
+
`SessionManager.sendDtmf(sessionId, digit)` expose the send-only API. Calls
|
|
58
|
+
reject during Resume, pending requests reject on transport close, and no
|
|
59
|
+
request is replayed on a replacement transport. There is no peer-receive
|
|
60
|
+
callback or tone playback. Media error-code changes and canonical fixture
|
|
61
|
+
changes therefore require a web-sdk consumer review.
|
|
62
|
+
|
|
42
63
|
## Live-chat monitoring and optional message metadata
|
|
43
64
|
|
|
44
65
|
- Version 0.1.2 exposes optional `Message.metadata` and optional
|
package/docs/voice.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
| Layer | Tech |
|
|
6
6
|
|--------------|----------------------------------------------------------------------|
|
|
7
7
|
| Transport | WebTransport (`https://<media-server>/web`), one bidi control sub-stream + datagrams |
|
|
8
|
-
| Control | B2BUA verbs (Connect/ConnectOk/Mute/Resume/PeerAttached/…), `msg_type (vi) \| payload_len (vi) \| payload` |
|
|
8
|
+
| Control | B2BUA verbs (Connect/ConnectOk/Mute/Resume/SendDtmf/PeerAttached/…), `msg_type (vi) \| payload_len (vi) \| payload` |
|
|
9
9
|
| Audio | Opus 48 kHz mono, 20 ms frames (50 per wall-second), `ObjectDatagram` per frame |
|
|
10
10
|
| Group / object IDs | `group_id = floor(Date.now()/1000) - server_epoch_unix`, `object_id ∈ [0..49]`, `end_of_group` on object 49 |
|
|
11
11
|
| Reconnect | Tier-3 `Resume { call_token, last_event_seq }` only — browsers expose no QUIC migration / 0-RTT |
|
|
@@ -13,6 +13,10 @@
|
|
|
13
13
|
|
|
14
14
|
See [`backend-integration.md`](backend-integration.md) (canonical spec) for the full wire definitions.
|
|
15
15
|
|
|
16
|
+
The internal `SendDtmf` codec carries one `0-9*#A-D` symbol and awaits its
|
|
17
|
+
request-correlated ACK. It does not yet expose a public send method, receive
|
|
18
|
+
callback, tone generator, duration control, or carrier-forwarding behavior.
|
|
19
|
+
|
|
16
20
|
## Required browser features (the SDK-wide floor)
|
|
17
21
|
|
|
18
22
|
| Feature | Needed by |
|
|
@@ -128,6 +132,7 @@ const { sessionId } = await client.joinSession({
|
|
|
128
132
|
})
|
|
129
133
|
|
|
130
134
|
await client.setMute(sessionId, 'uplink') // 'uplink' | 'downlink' | 'both' | 'none'
|
|
135
|
+
await client.sendDtmf(sessionId, '#') // exactly one of 0-9, *, #, A-D
|
|
131
136
|
|
|
132
137
|
// For a provisioned receive-only join, enter and leave microphone capture
|
|
133
138
|
// without exposing an unmuted permission/acquisition window.
|
|
@@ -147,6 +152,12 @@ await client.endSession(sessionId)
|
|
|
147
152
|
|
|
148
153
|
## Reconnect behaviour
|
|
149
154
|
|
|
155
|
+
DTMF requests are transport-bound. Calls made during reconnect reject locally;
|
|
156
|
+
an unacknowledged digit is rejected when its transport closes and is never
|
|
157
|
+
replayed on the replacement transport. `SendDtmfOk` means CX-flow publication
|
|
158
|
+
was accepted, not carrier delivery. There is no inbound DTMF callback or SDK
|
|
159
|
+
tone playback.
|
|
160
|
+
|
|
150
161
|
When `wt.closed` fires unexpectedly (no `EndpointHangup` or terminal `MoqError` arrived first), the SDK runs:
|
|
151
162
|
|
|
152
163
|
```
|