react-jssip-kit 0.1.1 → 0.2.0
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 +3 -4
- package/dist/index.cjs +81 -129
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +33 -39
- package/dist/index.d.ts +33 -39
- package/dist/index.js +81 -129
- package/dist/index.js.map +1 -1
- package/package.json +28 -16
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ React provider and hooks that wrap [JsSIP](https://jssip.net/) so you can manage
|
|
|
8
8
|
npm install react-jssip-kit jssip
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
Peer deps: `react
|
|
11
|
+
Peer deps: `react >=18 <20` and `react-dom >=18 <20`.
|
|
12
12
|
|
|
13
13
|
## Quick start
|
|
14
14
|
|
|
@@ -32,7 +32,7 @@ client.connect("sip:alice@example.com", "supersecret", {
|
|
|
32
32
|
|
|
33
33
|
function CallControls() {
|
|
34
34
|
const { sessions, sipStatus } = useSipState();
|
|
35
|
-
const { call, hangup,
|
|
35
|
+
const { call, hangup, toggleMute } = useSipActions();
|
|
36
36
|
const active = sessions[0];
|
|
37
37
|
|
|
38
38
|
return (
|
|
@@ -40,8 +40,7 @@ function CallControls() {
|
|
|
40
40
|
<div>Status: {sipStatus}</div>
|
|
41
41
|
<button onClick={() => call("sip:bob@example.com")}>Call Bob</button>
|
|
42
42
|
<button onClick={() => hangup(active?.id)}>Hang up</button>
|
|
43
|
-
<button onClick={() =>
|
|
44
|
-
<button onClick={() => unmute(active?.id)}>Unmute</button>
|
|
43
|
+
<button onClick={() => toggleMute(active?.id)}>Toggle mute</button>
|
|
45
44
|
</div>
|
|
46
45
|
);
|
|
47
46
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -324,6 +324,44 @@ function createUAHandlers(deps) {
|
|
|
324
324
|
};
|
|
325
325
|
}
|
|
326
326
|
|
|
327
|
+
// src/jssip-lib/sip/sessionState.ts
|
|
328
|
+
function holdOtherSessions(state, sessionId, holdFn) {
|
|
329
|
+
const current = state.getState();
|
|
330
|
+
current.sessions.forEach((s) => {
|
|
331
|
+
if (s.id === sessionId)
|
|
332
|
+
return;
|
|
333
|
+
if (s.status === CallStatus.Active) {
|
|
334
|
+
holdFn(s.id);
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
function upsertSessionState(state, sessionId, partial) {
|
|
339
|
+
const current = state.getState();
|
|
340
|
+
const existing = current.sessions.find((s) => s.id === sessionId);
|
|
341
|
+
const base = existing ?? {
|
|
342
|
+
id: sessionId,
|
|
343
|
+
status: CallStatus.Idle,
|
|
344
|
+
direction: CallDirection.None,
|
|
345
|
+
from: null,
|
|
346
|
+
to: null,
|
|
347
|
+
muted: false,
|
|
348
|
+
acceptedAt: null,
|
|
349
|
+
mediaKind: "audio",
|
|
350
|
+
remoteVideoEnabled: false
|
|
351
|
+
};
|
|
352
|
+
const nextSession = { ...base, ...partial };
|
|
353
|
+
const sessions = existing ? current.sessions.map((s) => s.id === sessionId ? nextSession : s) : [...current.sessions, nextSession];
|
|
354
|
+
state.setState({ sessions });
|
|
355
|
+
}
|
|
356
|
+
function removeSessionState(state, sessionId) {
|
|
357
|
+
const current = state.getState();
|
|
358
|
+
const sessions = current.sessions.filter((s) => s.id !== sessionId);
|
|
359
|
+
state.setState({
|
|
360
|
+
sessions,
|
|
361
|
+
error: null
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
|
|
327
365
|
// src/jssip-lib/sip/handlers/sessionHandlers.ts
|
|
328
366
|
function createSessionHandlers(deps) {
|
|
329
367
|
const {
|
|
@@ -378,35 +416,19 @@ function createSessionHandlers(deps) {
|
|
|
378
416
|
},
|
|
379
417
|
muted: () => {
|
|
380
418
|
emitter.emit("muted", { sessionId, data: void 0 });
|
|
381
|
-
state
|
|
382
|
-
sessions: state.getState().sessions.map(
|
|
383
|
-
(s) => s.id === sessionId ? { ...s, muted: true } : s
|
|
384
|
-
)
|
|
385
|
-
});
|
|
419
|
+
upsertSessionState(state, sessionId, { muted: true });
|
|
386
420
|
},
|
|
387
421
|
unmuted: () => {
|
|
388
422
|
emitter.emit("unmuted", { sessionId, data: void 0 });
|
|
389
|
-
state
|
|
390
|
-
sessions: state.getState().sessions.map(
|
|
391
|
-
(s) => s.id === sessionId ? { ...s, muted: false } : s
|
|
392
|
-
)
|
|
393
|
-
});
|
|
423
|
+
upsertSessionState(state, sessionId, { muted: false });
|
|
394
424
|
},
|
|
395
425
|
hold: () => {
|
|
396
426
|
emitter.emit("hold", { sessionId, data: void 0 });
|
|
397
|
-
state.
|
|
398
|
-
sessions: state.getState().sessions.map(
|
|
399
|
-
(s) => s.id === sessionId ? { ...s, status: CallStatus.Hold } : s
|
|
400
|
-
)
|
|
401
|
-
});
|
|
427
|
+
upsertSessionState(state, sessionId, { status: CallStatus.Hold });
|
|
402
428
|
},
|
|
403
429
|
unhold: () => {
|
|
404
430
|
emitter.emit("unhold", { sessionId, data: void 0 });
|
|
405
|
-
state.
|
|
406
|
-
sessions: state.getState().sessions.map(
|
|
407
|
-
(s) => s.id === sessionId ? { ...s, status: CallStatus.Active } : s
|
|
408
|
-
)
|
|
409
|
-
});
|
|
431
|
+
upsertSessionState(state, sessionId, { status: CallStatus.Active });
|
|
410
432
|
},
|
|
411
433
|
reinvite: (e) => emitter.emit("reinvite", { sessionId, data: e }),
|
|
412
434
|
update: (e) => emitter.emit("update", { sessionId, data: e }),
|
|
@@ -554,11 +576,6 @@ var WebRTCSessionController = class {
|
|
|
554
576
|
old.stop();
|
|
555
577
|
return true;
|
|
556
578
|
}
|
|
557
|
-
async startScreenShare(getDisplayMedia) {
|
|
558
|
-
const display = await getDisplayMedia();
|
|
559
|
-
const screen = display.getVideoTracks()[0];
|
|
560
|
-
return screen ? this.switchCamera(screen) : false;
|
|
561
|
-
}
|
|
562
579
|
};
|
|
563
580
|
|
|
564
581
|
// src/jssip-lib/sip/sessionManager.ts
|
|
@@ -706,45 +723,6 @@ var SessionManager = class {
|
|
|
706
723
|
}
|
|
707
724
|
};
|
|
708
725
|
|
|
709
|
-
// src/jssip-lib/sip/sessionState.ts
|
|
710
|
-
function holdOtherSessions(state, sessionId, holdFn, updateSession) {
|
|
711
|
-
const current = state.getState();
|
|
712
|
-
current.sessions.forEach((s) => {
|
|
713
|
-
if (s.id === sessionId)
|
|
714
|
-
return;
|
|
715
|
-
if (s.status === CallStatus.Active) {
|
|
716
|
-
holdFn(s.id);
|
|
717
|
-
updateSession(s.id, { status: CallStatus.Hold });
|
|
718
|
-
}
|
|
719
|
-
});
|
|
720
|
-
}
|
|
721
|
-
function upsertSessionState(state, sessionId, partial) {
|
|
722
|
-
const current = state.getState();
|
|
723
|
-
const existing = current.sessions.find((s) => s.id === sessionId);
|
|
724
|
-
const base = existing ?? {
|
|
725
|
-
id: sessionId,
|
|
726
|
-
status: CallStatus.Idle,
|
|
727
|
-
direction: CallDirection.None,
|
|
728
|
-
from: null,
|
|
729
|
-
to: null,
|
|
730
|
-
muted: false,
|
|
731
|
-
acceptedAt: null,
|
|
732
|
-
mediaKind: "audio",
|
|
733
|
-
remoteVideoEnabled: false
|
|
734
|
-
};
|
|
735
|
-
const nextSession = { ...base, ...partial };
|
|
736
|
-
const sessions = existing ? current.sessions.map((s) => s.id === sessionId ? nextSession : s) : [...current.sessions, nextSession];
|
|
737
|
-
state.setState({ sessions });
|
|
738
|
-
}
|
|
739
|
-
function removeSessionState(state, sessionId) {
|
|
740
|
-
const current = state.getState();
|
|
741
|
-
const sessions = current.sessions.filter((s) => s.id !== sessionId);
|
|
742
|
-
state.setState({
|
|
743
|
-
sessions,
|
|
744
|
-
error: null
|
|
745
|
-
});
|
|
746
|
-
}
|
|
747
|
-
|
|
748
726
|
// src/jssip-lib/sip/sessionLifecycle.ts
|
|
749
727
|
var SessionLifecycle = class {
|
|
750
728
|
constructor(deps) {
|
|
@@ -784,8 +762,7 @@ var SessionLifecycle = class {
|
|
|
784
762
|
(id) => {
|
|
785
763
|
const otherRtc = this.sessionManager.getRtc(id);
|
|
786
764
|
otherRtc?.hold();
|
|
787
|
-
}
|
|
788
|
-
(id, partial) => upsertSessionState(this.state, id, partial)
|
|
765
|
+
}
|
|
789
766
|
);
|
|
790
767
|
const sdpHasVideo = e.request?.body && e.request.body.toString().includes("m=video") || session?.connection?.getReceivers?.()?.some((r) => r.track?.kind === "video");
|
|
791
768
|
upsertSessionState(this.state, sessionId, {
|
|
@@ -855,10 +832,11 @@ var SipClient = class extends EventTargetEmitter {
|
|
|
855
832
|
}
|
|
856
833
|
call(target, callOptions = {}) {
|
|
857
834
|
try {
|
|
858
|
-
|
|
859
|
-
|
|
835
|
+
const opts = this.ensureMediaConstraints(callOptions);
|
|
836
|
+
if (opts.mediaStream)
|
|
837
|
+
this.sessionManager.enqueueOutgoingMedia(opts.mediaStream);
|
|
860
838
|
const ua = this.userAgent.getUA();
|
|
861
|
-
ua?.call(target,
|
|
839
|
+
ua?.call(target, opts);
|
|
862
840
|
} catch (e) {
|
|
863
841
|
const err = this.emitError(e, "CALL_FAILED", "call failed");
|
|
864
842
|
this.cleanupAllSessions();
|
|
@@ -868,22 +846,22 @@ var SipClient = class extends EventTargetEmitter {
|
|
|
868
846
|
}
|
|
869
847
|
}
|
|
870
848
|
answer(options = {}) {
|
|
871
|
-
|
|
849
|
+
const sessionId = this.resolveSessionId();
|
|
850
|
+
if (!sessionId)
|
|
851
|
+
return false;
|
|
852
|
+
return this.answerSession(sessionId, options);
|
|
872
853
|
}
|
|
873
854
|
hangup(options) {
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
return this.
|
|
878
|
-
}
|
|
879
|
-
unmute() {
|
|
880
|
-
return this.unmuteSession();
|
|
855
|
+
const sessionId = this.resolveSessionId();
|
|
856
|
+
if (!sessionId)
|
|
857
|
+
return false;
|
|
858
|
+
return this.hangupSession(sessionId, options);
|
|
881
859
|
}
|
|
882
|
-
|
|
883
|
-
return this.
|
|
860
|
+
toggleMute() {
|
|
861
|
+
return this.toggleMuteSession();
|
|
884
862
|
}
|
|
885
|
-
|
|
886
|
-
return this.
|
|
863
|
+
toggleHold() {
|
|
864
|
+
return this.toggleHoldSession();
|
|
887
865
|
}
|
|
888
866
|
sendDTMF(tones, options) {
|
|
889
867
|
const sessionId = this.resolveSessionId();
|
|
@@ -1001,72 +979,48 @@ var SipClient = class extends EventTargetEmitter {
|
|
|
1001
979
|
const active = sessions.find((s) => s.status === CallStatus.Active);
|
|
1002
980
|
return active?.id ?? sessions[0]?.id ?? null;
|
|
1003
981
|
}
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
982
|
+
ensureMediaConstraints(opts) {
|
|
983
|
+
if (opts.mediaStream || opts.mediaConstraints)
|
|
984
|
+
return opts;
|
|
985
|
+
return { ...opts, mediaConstraints: { audio: true, video: false } };
|
|
986
|
+
}
|
|
987
|
+
answerSession(sessionId, options = {}) {
|
|
1007
988
|
if (!sessionId)
|
|
1008
989
|
return false;
|
|
1009
|
-
|
|
1010
|
-
this.stateStore,
|
|
1011
|
-
sessionId,
|
|
1012
|
-
(id) => {
|
|
1013
|
-
const rtc = this.sessionManager.getRtc(id);
|
|
1014
|
-
rtc?.hold();
|
|
1015
|
-
},
|
|
1016
|
-
(id, partial) => upsertSessionState(this.stateStore, id, partial)
|
|
1017
|
-
);
|
|
990
|
+
const opts = this.ensureMediaConstraints(options);
|
|
1018
991
|
return this.sessionManager.answer(sessionId, opts);
|
|
1019
992
|
}
|
|
1020
|
-
hangupSession(
|
|
1021
|
-
const sessionId = typeof sessionIdOrOptions === "string" ? sessionIdOrOptions : this.resolveSessionId();
|
|
1022
|
-
const opts = typeof sessionIdOrOptions === "string" ? options : sessionIdOrOptions;
|
|
993
|
+
hangupSession(sessionId, options) {
|
|
1023
994
|
if (!sessionId)
|
|
1024
995
|
return false;
|
|
1025
|
-
return this.sessionManager.hangup(sessionId,
|
|
996
|
+
return this.sessionManager.hangup(sessionId, options);
|
|
1026
997
|
}
|
|
1027
|
-
|
|
998
|
+
toggleMuteSession(sessionId) {
|
|
1028
999
|
const resolved = this.resolveSessionId(sessionId);
|
|
1029
1000
|
if (!resolved)
|
|
1030
1001
|
return false;
|
|
1031
1002
|
const sessionState = this.stateStore.getState().sessions.find((s) => s.id === resolved);
|
|
1032
|
-
|
|
1003
|
+
const muted = sessionState?.muted ?? false;
|
|
1004
|
+
if (muted) {
|
|
1005
|
+
this.sessionManager.unmute(resolved);
|
|
1033
1006
|
return true;
|
|
1007
|
+
}
|
|
1034
1008
|
this.sessionManager.mute(resolved);
|
|
1035
|
-
upsertSessionState(this.stateStore, resolved, { muted: true });
|
|
1036
1009
|
return true;
|
|
1037
1010
|
}
|
|
1038
|
-
|
|
1011
|
+
toggleHoldSession(sessionId) {
|
|
1039
1012
|
const resolved = this.resolveSessionId(sessionId);
|
|
1040
1013
|
if (!resolved)
|
|
1041
1014
|
return false;
|
|
1042
1015
|
const sessionState = this.stateStore.getState().sessions.find((s) => s.id === resolved);
|
|
1043
|
-
|
|
1016
|
+
const isOnHold = sessionState?.status === CallStatus.Hold;
|
|
1017
|
+
if (isOnHold) {
|
|
1018
|
+
this.sessionManager.unhold(resolved);
|
|
1044
1019
|
return true;
|
|
1045
|
-
|
|
1046
|
-
upsertSessionState(this.stateStore, resolved, { muted: false });
|
|
1047
|
-
return true;
|
|
1048
|
-
}
|
|
1049
|
-
holdSession(sessionId) {
|
|
1050
|
-
const resolved = this.resolveSessionId(sessionId);
|
|
1051
|
-
if (!resolved)
|
|
1052
|
-
return false;
|
|
1053
|
-
const sessionState = this.stateStore.getState().sessions.find((s) => s.id === resolved);
|
|
1020
|
+
}
|
|
1054
1021
|
if (sessionState?.status === CallStatus.Active) {
|
|
1055
1022
|
this.sessionManager.hold(resolved);
|
|
1056
|
-
|
|
1057
|
-
}
|
|
1058
|
-
return true;
|
|
1059
|
-
}
|
|
1060
|
-
unholdSession(sessionId) {
|
|
1061
|
-
const resolved = this.resolveSessionId(sessionId);
|
|
1062
|
-
if (!resolved)
|
|
1063
|
-
return false;
|
|
1064
|
-
const sessionState = this.stateStore.getState().sessions.find((s) => s.id === resolved);
|
|
1065
|
-
if (sessionState?.status === CallStatus.Hold) {
|
|
1066
|
-
this.sessionManager.unhold(resolved);
|
|
1067
|
-
upsertSessionState(this.stateStore, resolved, {
|
|
1068
|
-
status: CallStatus.Active
|
|
1069
|
-
});
|
|
1023
|
+
return true;
|
|
1070
1024
|
}
|
|
1071
1025
|
return true;
|
|
1072
1026
|
}
|
|
@@ -1195,10 +1149,8 @@ function useSipActions() {
|
|
|
1195
1149
|
call: (...args) => client.call(...args),
|
|
1196
1150
|
answer: (...args) => client.answerSession(...args),
|
|
1197
1151
|
hangup: (...args) => client.hangupSession(...args),
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
hold: (...args) => client.holdSession(...args),
|
|
1201
|
-
unhold: (...args) => client.unholdSession(...args),
|
|
1152
|
+
toggleMute: (...args) => client.toggleMuteSession(...args),
|
|
1153
|
+
toggleHold: (...args) => client.toggleHoldSession(...args),
|
|
1202
1154
|
sendDTMF: (...args) => client.sendDTMFSession(...args),
|
|
1203
1155
|
transfer: (...args) => client.transferSession(...args),
|
|
1204
1156
|
attendedTransfer: (...args) => client.attendedTransferSession(...args),
|