react-jssip-kit 1.0.0 → 1.0.1
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 +16 -2
- package/dist/index.cjs +198 -79
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +44 -19
- package/dist/index.d.ts +44 -19
- package/dist/index.js +199 -79
- package/dist/index.js.map +1 -1
- package/package.json +15 -6
package/README.md
CHANGED
|
@@ -110,6 +110,9 @@ const { remoteStream, audioTracks } = useSessionMedia(sessionId);
|
|
|
110
110
|
- Hooks: `useSipKernel`, `useSipState`, `useSipSelector`, `useSipActions`, `useSipEvent`, `useSipSessionEvent`, `useSipSessions`, `useSipSession`, `useActiveSipSession`, `useSessionMedia`.
|
|
111
111
|
- Components: `CallPlayer` (basic remote audio element).
|
|
112
112
|
- Kernel utilities: `createSipKernel`, `createSipClientInstance`, `createSipEventManager`.
|
|
113
|
+
- Kernel commands include:
|
|
114
|
+
- Call/session: `call`, `answer`, `hangup`, `hangupAll`, `toggleMute`, `toggleHold`, `sendDTMF`, `transfer`, `sendInfo`, `update`, `reinvite`.
|
|
115
|
+
- UA-level: `sendMessage`, `sendOptions`.
|
|
113
116
|
- JsSIP utility: `WebSocketInterface`.
|
|
114
117
|
|
|
115
118
|
## Public API Contract (1.0.0)
|
|
@@ -125,15 +128,26 @@ Public and supported:
|
|
|
125
128
|
- `createSipEventManager()`
|
|
126
129
|
- `SipStatus`, `CallStatus`, `CallDirection`
|
|
127
130
|
- Public types exported from root (`SipKernel`, `SipState`, event/call option types)
|
|
131
|
+
- Public state shape: `SipState = { sipStatus, error, sessions }`
|
|
128
132
|
|
|
129
133
|
Internal (not part of public contract):
|
|
130
134
|
- Direct imports from `src/core/*`
|
|
131
135
|
- `SipContext` object
|
|
136
|
+
- Internal normalized fields (`sessionsById`, `sessionIds`)
|
|
132
137
|
- Any file not re-exported from package root
|
|
133
138
|
|
|
134
|
-
## Architecture
|
|
139
|
+
## Architecture and Lifecycle
|
|
135
140
|
|
|
136
|
-
|
|
141
|
+
Runtime flow (short):
|
|
142
|
+
1. App creates kernel with `createSipKernel()`.
|
|
143
|
+
2. `SipProvider` injects kernel into React tree.
|
|
144
|
+
3. `commands.connect(...)` starts UA and state transitions.
|
|
145
|
+
4. Session events are projected into public `SipState.sessions`.
|
|
146
|
+
5. Media hooks (`useSessionMedia`) observe peer connection/remote tracks.
|
|
147
|
+
6. `commands.disconnect()` stops UA and performs full cleanup.
|
|
148
|
+
|
|
149
|
+
Detailed module map and full lifecycle:
|
|
150
|
+
- `docs/MODULES.md`
|
|
137
151
|
|
|
138
152
|
## Build
|
|
139
153
|
|
package/dist/index.cjs
CHANGED
|
@@ -295,19 +295,35 @@ var SipStateStore = class {
|
|
|
295
295
|
constructor() {
|
|
296
296
|
this.state = getInitialSipState();
|
|
297
297
|
this.lastState = getInitialSipState();
|
|
298
|
+
this.publicState = {
|
|
299
|
+
sipStatus: this.state.sipStatus,
|
|
300
|
+
error: this.state.error,
|
|
301
|
+
sessions: this.state.sessions
|
|
302
|
+
};
|
|
298
303
|
this.listeners = /* @__PURE__ */ new Set();
|
|
304
|
+
this.publicListeners = /* @__PURE__ */ new Set();
|
|
299
305
|
this.pendingState = null;
|
|
300
306
|
this.updateScheduled = false;
|
|
301
307
|
}
|
|
302
308
|
getState() {
|
|
303
309
|
return this.state;
|
|
304
310
|
}
|
|
311
|
+
getPublicState() {
|
|
312
|
+
return this.publicState;
|
|
313
|
+
}
|
|
305
314
|
onChange(fn) {
|
|
306
315
|
this.listeners.add(fn);
|
|
307
316
|
fn(this.state);
|
|
308
317
|
return () => this.listeners.delete(fn);
|
|
309
318
|
}
|
|
319
|
+
onPublicChange(fn) {
|
|
320
|
+
this.publicListeners.add(fn);
|
|
321
|
+
return () => this.publicListeners.delete(fn);
|
|
322
|
+
}
|
|
310
323
|
subscribe(fn) {
|
|
324
|
+
return this.onPublicChange(fn);
|
|
325
|
+
}
|
|
326
|
+
subscribeInternal(fn) {
|
|
311
327
|
return this.onChange(fn);
|
|
312
328
|
}
|
|
313
329
|
setState(partial) {
|
|
@@ -319,6 +335,11 @@ var SipStateStore = class {
|
|
|
319
335
|
}
|
|
320
336
|
this.state = next;
|
|
321
337
|
this.lastState = next;
|
|
338
|
+
this.publicState = {
|
|
339
|
+
sipStatus: next.sipStatus,
|
|
340
|
+
error: next.error,
|
|
341
|
+
sessions: next.sessions
|
|
342
|
+
};
|
|
322
343
|
this.emit();
|
|
323
344
|
}
|
|
324
345
|
batchSet(partial) {
|
|
@@ -339,6 +360,8 @@ var SipStateStore = class {
|
|
|
339
360
|
emit() {
|
|
340
361
|
for (const fn of this.listeners)
|
|
341
362
|
fn(this.state);
|
|
363
|
+
for (const fn of this.publicListeners)
|
|
364
|
+
fn(this.publicState);
|
|
342
365
|
}
|
|
343
366
|
};
|
|
344
367
|
|
|
@@ -400,18 +423,52 @@ var SipDebugRuntime = class {
|
|
|
400
423
|
};
|
|
401
424
|
|
|
402
425
|
// src/core/modules/event/sip-event-manager.adapter.ts
|
|
426
|
+
function getSessionFromPayload(payload) {
|
|
427
|
+
return payload?.session ?? null;
|
|
428
|
+
}
|
|
429
|
+
function getSessionId(session) {
|
|
430
|
+
return String(session.id ?? "");
|
|
431
|
+
}
|
|
403
432
|
function createSipEventManager(client) {
|
|
404
433
|
return {
|
|
405
434
|
onUA(event, handler) {
|
|
406
435
|
return client.on(event, handler);
|
|
407
436
|
},
|
|
408
437
|
onSession(sessionId, event, handler) {
|
|
409
|
-
const
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
438
|
+
const wrapped = (payload) => {
|
|
439
|
+
handler(payload);
|
|
440
|
+
};
|
|
441
|
+
let attachedSession = null;
|
|
442
|
+
const detach = () => {
|
|
443
|
+
if (!attachedSession)
|
|
444
|
+
return;
|
|
445
|
+
attachedSession.off(event, wrapped);
|
|
446
|
+
attachedSession = null;
|
|
447
|
+
};
|
|
448
|
+
const attach = (session) => {
|
|
449
|
+
if (!session)
|
|
450
|
+
return;
|
|
451
|
+
const id = getSessionId(session);
|
|
452
|
+
if (!id || id !== sessionId)
|
|
453
|
+
return;
|
|
454
|
+
if (attachedSession === session)
|
|
455
|
+
return;
|
|
456
|
+
detach();
|
|
457
|
+
attachedSession = session;
|
|
458
|
+
attachedSession.on(event, wrapped);
|
|
459
|
+
};
|
|
460
|
+
const offNewSession = client.on("newRTCSession", (payload) => {
|
|
461
|
+
attach(getSessionFromPayload(payload));
|
|
462
|
+
});
|
|
463
|
+
attach(client.getSession(sessionId) ?? null);
|
|
464
|
+
const offDisconnected = client.on("disconnected", () => {
|
|
465
|
+
detach();
|
|
466
|
+
});
|
|
467
|
+
return () => {
|
|
468
|
+
offNewSession();
|
|
469
|
+
offDisconnected();
|
|
470
|
+
detach();
|
|
471
|
+
};
|
|
415
472
|
}
|
|
416
473
|
};
|
|
417
474
|
}
|
|
@@ -926,15 +983,6 @@ var SessionManager = class {
|
|
|
926
983
|
};
|
|
927
984
|
|
|
928
985
|
// src/core/modules/session/session.state.projector.ts
|
|
929
|
-
function toSessionMaps(sessions) {
|
|
930
|
-
const sessionsById = {};
|
|
931
|
-
const sessionIds = [];
|
|
932
|
-
for (const session of sessions) {
|
|
933
|
-
sessionsById[session.id] = session;
|
|
934
|
-
sessionIds.push(session.id);
|
|
935
|
-
}
|
|
936
|
-
return { sessionsById, sessionIds };
|
|
937
|
-
}
|
|
938
986
|
function holdOtherSessions(state, sessionId, holdFn) {
|
|
939
987
|
const current = state.getState();
|
|
940
988
|
current.sessionIds.forEach((id) => {
|
|
@@ -959,19 +1007,26 @@ function upsertSessionState(state, sessionId, partial) {
|
|
|
959
1007
|
acceptedAt: null
|
|
960
1008
|
};
|
|
961
1009
|
const nextSession = { ...base, ...partial };
|
|
962
|
-
const
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
1010
|
+
const sessionsById = {
|
|
1011
|
+
...current.sessionsById,
|
|
1012
|
+
[sessionId]: nextSession
|
|
1013
|
+
};
|
|
1014
|
+
const sessionIds = existing ? current.sessionIds : [...current.sessionIds, sessionId];
|
|
1015
|
+
const sessions = existing ? current.sessions.map(
|
|
1016
|
+
(session) => session.id === sessionId ? nextSession : session
|
|
1017
|
+
) : [...current.sessions, nextSession];
|
|
1018
|
+
state.setState({ sessionsById, sessionIds, sessions });
|
|
970
1019
|
}
|
|
971
1020
|
function removeSessionState(state, sessionId) {
|
|
972
1021
|
const current = state.getState();
|
|
973
|
-
|
|
974
|
-
|
|
1022
|
+
if (!current.sessionsById[sessionId])
|
|
1023
|
+
return;
|
|
1024
|
+
const sessionsById = { ...current.sessionsById };
|
|
1025
|
+
delete sessionsById[sessionId];
|
|
1026
|
+
const sessionIds = current.sessionIds.filter((id) => id !== sessionId);
|
|
1027
|
+
const sessions = current.sessions.filter(
|
|
1028
|
+
(session) => session.id !== sessionId
|
|
1029
|
+
);
|
|
975
1030
|
state.setState({
|
|
976
1031
|
sessions,
|
|
977
1032
|
sessionsById,
|
|
@@ -1149,18 +1204,18 @@ var SessionLifecycle = class {
|
|
|
1149
1204
|
}
|
|
1150
1205
|
handleNewRTCSession(e) {
|
|
1151
1206
|
const session = e.session;
|
|
1152
|
-
const sessionId = String(
|
|
1153
|
-
session?.id ?? crypto.randomUUID?.() ?? Date.now()
|
|
1154
|
-
);
|
|
1207
|
+
const sessionId = String(session.id ?? crypto.randomUUID?.() ?? Date.now());
|
|
1155
1208
|
const currentSessions = this.state.getState().sessions;
|
|
1156
1209
|
if (currentSessions.length >= this.getMaxSessionCount()) {
|
|
1157
1210
|
try {
|
|
1158
|
-
|
|
1211
|
+
const terminateOptions = {
|
|
1159
1212
|
status_code: 486,
|
|
1160
1213
|
reason_phrase: "Busy Here"
|
|
1161
|
-
}
|
|
1214
|
+
};
|
|
1215
|
+
session.terminate(terminateOptions);
|
|
1162
1216
|
} catch {
|
|
1163
1217
|
}
|
|
1218
|
+
return;
|
|
1164
1219
|
}
|
|
1165
1220
|
const rtc = this.sessionManager.getOrCreateRtc(sessionId, session);
|
|
1166
1221
|
this.sessionManager.setSession(sessionId, session);
|
|
@@ -1259,7 +1314,7 @@ var SessionLifecycle = class {
|
|
|
1259
1314
|
clearTimeout(retryTimer);
|
|
1260
1315
|
retryTimer = null;
|
|
1261
1316
|
};
|
|
1262
|
-
const stopRetry = (
|
|
1317
|
+
const stopRetry = () => {
|
|
1263
1318
|
if (stopped)
|
|
1264
1319
|
return;
|
|
1265
1320
|
stopped = true;
|
|
@@ -1360,8 +1415,8 @@ var SessionLifecycle = class {
|
|
|
1360
1415
|
session.on?.("peerconnection", onPeer);
|
|
1361
1416
|
}
|
|
1362
1417
|
session.on?.("confirmed", onConfirmed);
|
|
1363
|
-
session.on?.("ended", (
|
|
1364
|
-
session.on?.("failed", (
|
|
1418
|
+
session.on?.("ended", () => stopRetry());
|
|
1419
|
+
session.on?.("failed", () => stopRetry());
|
|
1365
1420
|
}
|
|
1366
1421
|
bindRemoteIncomingAudio(sessionId, session) {
|
|
1367
1422
|
const maxAttempts = 50;
|
|
@@ -1637,8 +1692,9 @@ var SessionModule = class {
|
|
|
1637
1692
|
}
|
|
1638
1693
|
hangupAll(options) {
|
|
1639
1694
|
const ids = this.getSessionIds();
|
|
1640
|
-
ids.
|
|
1641
|
-
|
|
1695
|
+
if (ids.length === 0)
|
|
1696
|
+
return false;
|
|
1697
|
+
return ids.every((id) => this.hangupSession(id, options));
|
|
1642
1698
|
}
|
|
1643
1699
|
toggleMuteSession(sessionId) {
|
|
1644
1700
|
const resolved = this.resolveExistingSessionId(sessionId);
|
|
@@ -1667,7 +1723,7 @@ var SessionModule = class {
|
|
|
1667
1723
|
this.deps.sessionManager.hold(resolved);
|
|
1668
1724
|
return true;
|
|
1669
1725
|
}
|
|
1670
|
-
return
|
|
1726
|
+
return false;
|
|
1671
1727
|
}
|
|
1672
1728
|
sendDTMFSession(sessionId, tones, options) {
|
|
1673
1729
|
const resolved = this.resolveExistingSessionId(sessionId);
|
|
@@ -1676,8 +1732,9 @@ var SessionModule = class {
|
|
|
1676
1732
|
const sessionState = this.deps.state.getState().sessionsById[resolved];
|
|
1677
1733
|
if (sessionState?.status === CallStatus.Active) {
|
|
1678
1734
|
this.deps.sessionManager.sendDTMF(resolved, tones, options);
|
|
1735
|
+
return true;
|
|
1679
1736
|
}
|
|
1680
|
-
return
|
|
1737
|
+
return false;
|
|
1681
1738
|
}
|
|
1682
1739
|
transferSession(sessionId, target, options) {
|
|
1683
1740
|
const resolved = this.resolveExistingSessionId(sessionId);
|
|
@@ -1686,9 +1743,37 @@ var SessionModule = class {
|
|
|
1686
1743
|
const sessionState = this.deps.state.getState().sessionsById[resolved];
|
|
1687
1744
|
if (sessionState?.status === CallStatus.Active) {
|
|
1688
1745
|
this.deps.sessionManager.transfer(resolved, target, options);
|
|
1746
|
+
return true;
|
|
1689
1747
|
}
|
|
1748
|
+
return false;
|
|
1749
|
+
}
|
|
1750
|
+
sendInfoSession(sessionId, contentType, body, options) {
|
|
1751
|
+
const resolved = this.resolveExistingSessionId(sessionId);
|
|
1752
|
+
if (!resolved)
|
|
1753
|
+
return false;
|
|
1754
|
+
const sessionState = this.deps.state.getState().sessionsById[resolved];
|
|
1755
|
+
if (sessionState?.status !== CallStatus.Active && sessionState?.status !== CallStatus.Hold) {
|
|
1756
|
+
return false;
|
|
1757
|
+
}
|
|
1758
|
+
const session = this.deps.sessionManager.getSession(resolved);
|
|
1759
|
+
if (!session)
|
|
1760
|
+
return false;
|
|
1761
|
+
session.sendInfo(contentType, body, options);
|
|
1690
1762
|
return true;
|
|
1691
1763
|
}
|
|
1764
|
+
updateSession(sessionId, options) {
|
|
1765
|
+
const resolved = this.resolveExistingSessionId(sessionId);
|
|
1766
|
+
if (!resolved)
|
|
1767
|
+
return false;
|
|
1768
|
+
const sessionState = this.deps.state.getState().sessionsById[resolved];
|
|
1769
|
+
if (sessionState?.status !== CallStatus.Active && sessionState?.status !== CallStatus.Hold) {
|
|
1770
|
+
return false;
|
|
1771
|
+
}
|
|
1772
|
+
const session = this.deps.sessionManager.getSession(resolved);
|
|
1773
|
+
if (!session)
|
|
1774
|
+
return false;
|
|
1775
|
+
return session.renegotiate(options);
|
|
1776
|
+
}
|
|
1692
1777
|
getSession(sessionId) {
|
|
1693
1778
|
return this.deps.sessionManager.getSession(sessionId);
|
|
1694
1779
|
}
|
|
@@ -1731,7 +1816,9 @@ var SessionModule = class {
|
|
|
1731
1816
|
}
|
|
1732
1817
|
cleanupSession(sessionId, session) {
|
|
1733
1818
|
const targetSession = session ?? this.deps.sessionManager.getSession(sessionId) ?? this.deps.sessionManager.getRtc(sessionId)?.currentSession;
|
|
1734
|
-
|
|
1819
|
+
if (targetSession) {
|
|
1820
|
+
this.detachSessionHandlers(sessionId, targetSession);
|
|
1821
|
+
}
|
|
1735
1822
|
this.deps.micRecovery.disable(sessionId);
|
|
1736
1823
|
this.deps.sessionManager.cleanupSession(sessionId);
|
|
1737
1824
|
removeSessionState(this.deps.state, sessionId);
|
|
@@ -1886,8 +1973,8 @@ var SipClient = class extends EventTargetEmitter {
|
|
|
1886
1973
|
getIceCandidateReadyDelayMs: () => this.iceCandidateReadyDelayMs
|
|
1887
1974
|
});
|
|
1888
1975
|
this.debugRuntime = new SipDebugRuntime({
|
|
1889
|
-
getState: () => this.stateStore.
|
|
1890
|
-
onChange: (listener) => this.stateStore.
|
|
1976
|
+
getState: () => this.stateStore.getPublicState(),
|
|
1977
|
+
onChange: (listener) => this.stateStore.onPublicChange(listener),
|
|
1891
1978
|
getSessions: () => this.getSessions(),
|
|
1892
1979
|
setDebugEnabled: (enabled) => this.sessionModule.setDebugEnabled(enabled)
|
|
1893
1980
|
});
|
|
@@ -1896,7 +1983,7 @@ var SipClient = class extends EventTargetEmitter {
|
|
|
1896
1983
|
);
|
|
1897
1984
|
}
|
|
1898
1985
|
get state() {
|
|
1899
|
-
return this.stateStore.
|
|
1986
|
+
return this.stateStore.getPublicState();
|
|
1900
1987
|
}
|
|
1901
1988
|
connect(uri, password, config) {
|
|
1902
1989
|
this.disconnect();
|
|
@@ -1941,9 +2028,12 @@ var SipClient = class extends EventTargetEmitter {
|
|
|
1941
2028
|
const ua = this.userAgent.getUA();
|
|
1942
2029
|
const session = ua?.call(target, callOptions);
|
|
1943
2030
|
if (session && callOptions.mediaStream) {
|
|
1944
|
-
const sessionId = String(session
|
|
2031
|
+
const sessionId = String(session.id ?? "");
|
|
1945
2032
|
if (sessionId) {
|
|
1946
|
-
this.sessionModule.setSessionMedia(
|
|
2033
|
+
this.sessionModule.setSessionMedia(
|
|
2034
|
+
sessionId,
|
|
2035
|
+
callOptions.mediaStream
|
|
2036
|
+
);
|
|
1947
2037
|
this.sessionModule.setSession(sessionId, session);
|
|
1948
2038
|
}
|
|
1949
2039
|
}
|
|
@@ -1952,13 +2042,40 @@ var SipClient = class extends EventTargetEmitter {
|
|
|
1952
2042
|
this.cleanupAllSessions();
|
|
1953
2043
|
}
|
|
1954
2044
|
}
|
|
2045
|
+
sendMessage(target, body, options) {
|
|
2046
|
+
try {
|
|
2047
|
+
const ua = this.userAgent.getUA();
|
|
2048
|
+
if (!ua)
|
|
2049
|
+
return false;
|
|
2050
|
+
ua.sendMessage(target, body, options);
|
|
2051
|
+
return true;
|
|
2052
|
+
} catch (e) {
|
|
2053
|
+
console.error(e);
|
|
2054
|
+
return false;
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
sendOptions(target, body, options) {
|
|
2058
|
+
try {
|
|
2059
|
+
const ua = this.userAgent.getUA();
|
|
2060
|
+
if (!ua)
|
|
2061
|
+
return false;
|
|
2062
|
+
const optionsUa = ua;
|
|
2063
|
+
if (typeof optionsUa.sendOptions !== "function")
|
|
2064
|
+
return false;
|
|
2065
|
+
optionsUa.sendOptions(target, body, options);
|
|
2066
|
+
return true;
|
|
2067
|
+
} catch (e) {
|
|
2068
|
+
console.error(e);
|
|
2069
|
+
return false;
|
|
2070
|
+
}
|
|
2071
|
+
}
|
|
1955
2072
|
hangupAll(options) {
|
|
1956
2073
|
const ids = this.getSessionIds();
|
|
1957
2074
|
ids.forEach((id) => this.hangupSession(id, options));
|
|
1958
2075
|
return ids.length > 0;
|
|
1959
2076
|
}
|
|
1960
2077
|
onChange(fn) {
|
|
1961
|
-
return this.stateStore.
|
|
2078
|
+
return this.stateStore.onPublicChange(fn);
|
|
1962
2079
|
}
|
|
1963
2080
|
setDebug(debug) {
|
|
1964
2081
|
this.debugPattern = debug;
|
|
@@ -1994,6 +2111,20 @@ var SipClient = class extends EventTargetEmitter {
|
|
|
1994
2111
|
transferSession(sessionId, target, options) {
|
|
1995
2112
|
return this.sessionModule.transferSession(sessionId, target, options);
|
|
1996
2113
|
}
|
|
2114
|
+
sendInfoSession(sessionId, contentType, body, options) {
|
|
2115
|
+
return this.sessionModule.sendInfoSession(
|
|
2116
|
+
sessionId,
|
|
2117
|
+
contentType,
|
|
2118
|
+
body,
|
|
2119
|
+
options
|
|
2120
|
+
);
|
|
2121
|
+
}
|
|
2122
|
+
updateSession(sessionId, options) {
|
|
2123
|
+
return this.sessionModule.updateSession(sessionId, options);
|
|
2124
|
+
}
|
|
2125
|
+
reinviteSession(sessionId, options) {
|
|
2126
|
+
return this.sessionModule.updateSession(sessionId, options);
|
|
2127
|
+
}
|
|
1997
2128
|
setSessionMedia(sessionId, stream) {
|
|
1998
2129
|
this.sessionModule.setSessionMedia(sessionId, stream);
|
|
1999
2130
|
}
|
|
@@ -2061,6 +2192,8 @@ function createSipKernel() {
|
|
|
2061
2192
|
register: () => client.registerUA(),
|
|
2062
2193
|
setDebug: (debug) => client.setDebug(debug),
|
|
2063
2194
|
call: (target, options) => client.call(target, options),
|
|
2195
|
+
sendMessage: (target, body, options) => client.sendMessage(target, body, options),
|
|
2196
|
+
sendOptions: (target, body, options) => client.sendOptions(target, body, options),
|
|
2064
2197
|
answer: (sessionId, options) => client.answerSession(sessionId, options),
|
|
2065
2198
|
hangup: (sessionId, options) => client.hangupSession(sessionId, options),
|
|
2066
2199
|
hangupAll: (options) => client.hangupAll(options),
|
|
@@ -2068,6 +2201,9 @@ function createSipKernel() {
|
|
|
2068
2201
|
toggleHold: (sessionId) => client.toggleHoldSession(sessionId),
|
|
2069
2202
|
sendDTMF: (sessionId, tones, options) => client.sendDTMFSession(sessionId, tones, options),
|
|
2070
2203
|
transfer: (sessionId, target, options) => client.transferSession(sessionId, target, options),
|
|
2204
|
+
sendInfo: (sessionId, contentType, body, options) => client.sendInfoSession(sessionId, contentType, body, options),
|
|
2205
|
+
update: (sessionId, options) => client.updateSession(sessionId, options),
|
|
2206
|
+
reinvite: (sessionId, options) => client.reinviteSession(sessionId, options),
|
|
2071
2207
|
getSession: (sessionId) => client.getSession(sessionId),
|
|
2072
2208
|
getSessionIds: () => client.getSessionIds(),
|
|
2073
2209
|
getSessions: () => client.getSessions(),
|
|
@@ -2105,6 +2241,8 @@ function useSipActions() {
|
|
|
2105
2241
|
register: commands.register,
|
|
2106
2242
|
setDebug: commands.setDebug,
|
|
2107
2243
|
call: commands.call,
|
|
2244
|
+
sendMessage: commands.sendMessage,
|
|
2245
|
+
sendOptions: commands.sendOptions,
|
|
2108
2246
|
answer: commands.answer,
|
|
2109
2247
|
hangup: commands.hangup,
|
|
2110
2248
|
hangupAll: commands.hangupAll,
|
|
@@ -2112,6 +2250,9 @@ function useSipActions() {
|
|
|
2112
2250
|
toggleHold: commands.toggleHold,
|
|
2113
2251
|
sendDTMF: commands.sendDTMF,
|
|
2114
2252
|
transfer: commands.transfer,
|
|
2253
|
+
sendInfo: commands.sendInfo,
|
|
2254
|
+
update: commands.update,
|
|
2255
|
+
reinvite: commands.reinvite,
|
|
2115
2256
|
getSession: commands.getSession,
|
|
2116
2257
|
getSessionIds: commands.getSessionIds,
|
|
2117
2258
|
getSessions: commands.getSessions,
|
|
@@ -2140,22 +2281,12 @@ function useSipSelector(selector, equalityFn = Object.is) {
|
|
|
2140
2281
|
return react.useSyncExternalStore(store.subscribe, getSelection, getSelection);
|
|
2141
2282
|
}
|
|
2142
2283
|
|
|
2143
|
-
// src/hooks/useActiveSipSession.ts
|
|
2144
|
-
function useActiveSipSession() {
|
|
2145
|
-
return useSipSelector((state) => {
|
|
2146
|
-
const activeId = state.sessionIds.find(
|
|
2147
|
-
(id) => state.sessionsById[id]?.status === CallStatus.Active
|
|
2148
|
-
);
|
|
2149
|
-
return activeId ? state.sessionsById[activeId] : null;
|
|
2150
|
-
});
|
|
2151
|
-
}
|
|
2152
|
-
|
|
2153
2284
|
// src/hooks/useSipSession.ts
|
|
2154
2285
|
function useSipSession(sessionId) {
|
|
2155
2286
|
return useSipSelector((state) => {
|
|
2156
2287
|
if (!sessionId)
|
|
2157
2288
|
return null;
|
|
2158
|
-
return state.
|
|
2289
|
+
return state.sessions.find((session) => session.id === sessionId) ?? null;
|
|
2159
2290
|
});
|
|
2160
2291
|
}
|
|
2161
2292
|
function useSipSessions() {
|
|
@@ -2180,25 +2311,15 @@ function useSipSessionEvent(sessionId, event, handler) {
|
|
|
2180
2311
|
}
|
|
2181
2312
|
function useSessionMedia(sessionId) {
|
|
2182
2313
|
const { media } = useSipKernel();
|
|
2183
|
-
const
|
|
2184
|
-
|
|
2185
|
-
sessionIds: state.sessionIds,
|
|
2186
|
-
sessionsById: state.sessionsById
|
|
2187
|
-
}),
|
|
2188
|
-
(prev, next) => prev.sessionIds === next.sessionIds && prev.sessionsById === next.sessionsById
|
|
2189
|
-
);
|
|
2190
|
-
const [peerConnection, setPeerConnection] = react.useState(
|
|
2191
|
-
null
|
|
2192
|
-
);
|
|
2314
|
+
const sessions = useSipSelector((state) => state.sessions);
|
|
2315
|
+
const [peerConnection, setPeerConnection] = react.useState(null);
|
|
2193
2316
|
const [remoteStream, setRemoteStream] = react.useState(null);
|
|
2194
2317
|
const resolvedSessionId = react.useMemo(() => {
|
|
2195
2318
|
if (sessionId)
|
|
2196
2319
|
return sessionId;
|
|
2197
|
-
const
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
return activeId ?? sessionIds[0];
|
|
2201
|
-
}, [sessionId, sessionIds, sessionsById]);
|
|
2320
|
+
const active = sessions.find((s) => s.status === CallStatus.Active);
|
|
2321
|
+
return active?.id ?? sessions[0]?.id;
|
|
2322
|
+
}, [sessionId, sessions]);
|
|
2202
2323
|
const session = react.useMemo(
|
|
2203
2324
|
() => resolvedSessionId ? media.getSession(resolvedSessionId) : null,
|
|
2204
2325
|
[media, resolvedSessionId]
|
|
@@ -2206,8 +2327,8 @@ function useSessionMedia(sessionId) {
|
|
|
2206
2327
|
const sessionState = react.useMemo(() => {
|
|
2207
2328
|
if (!resolvedSessionId)
|
|
2208
2329
|
return null;
|
|
2209
|
-
return
|
|
2210
|
-
}, [
|
|
2330
|
+
return sessions.find((s) => s.id === resolvedSessionId) ?? null;
|
|
2331
|
+
}, [sessions, resolvedSessionId]);
|
|
2211
2332
|
react.useEffect(() => {
|
|
2212
2333
|
if (!resolvedSessionId) {
|
|
2213
2334
|
setPeerConnection(null);
|
|
@@ -2261,15 +2382,14 @@ function CallPlayer({ sessionId }) {
|
|
|
2261
2382
|
const { remoteStream } = useSessionMedia(sessionId);
|
|
2262
2383
|
const audioRef = react.useRef(null);
|
|
2263
2384
|
react.useEffect(() => {
|
|
2264
|
-
|
|
2385
|
+
const audioEl = audioRef.current;
|
|
2386
|
+
if (!audioEl)
|
|
2265
2387
|
return;
|
|
2266
|
-
|
|
2267
|
-
|
|
2388
|
+
audioEl.srcObject = remoteStream;
|
|
2389
|
+
audioEl.play?.().catch(() => {
|
|
2268
2390
|
});
|
|
2269
2391
|
return () => {
|
|
2270
|
-
|
|
2271
|
-
audioRef.current.srcObject = null;
|
|
2272
|
-
}
|
|
2392
|
+
audioEl.srcObject = null;
|
|
2273
2393
|
};
|
|
2274
2394
|
}, [remoteStream]);
|
|
2275
2395
|
return /* @__PURE__ */ jsxRuntime.jsx("audio", { ref: audioRef, autoPlay: true, playsInline: true });
|
|
@@ -2290,7 +2410,6 @@ exports.SipStatus = SipStatus;
|
|
|
2290
2410
|
exports.createSipClientInstance = createSipClientInstance;
|
|
2291
2411
|
exports.createSipEventManager = createSipEventManager;
|
|
2292
2412
|
exports.createSipKernel = createSipKernel;
|
|
2293
|
-
exports.useActiveSipSession = useActiveSipSession;
|
|
2294
2413
|
exports.useSessionMedia = useSessionMedia;
|
|
2295
2414
|
exports.useSipActions = useSipActions;
|
|
2296
2415
|
exports.useSipEvent = useSipEvent;
|