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 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@^18` and `react-dom@^18`.
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, mute, unmute } = useSipActions();
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={() => mute(active?.id)}>Mute</button>
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.batchSet({
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.batchSet({
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.batchSet({
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.batchSet({
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
- if (callOptions.mediaStream)
859
- this.sessionManager.enqueueOutgoingMedia(callOptions.mediaStream);
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, callOptions);
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
- return this.answerSession(void 0, options);
849
+ const sessionId = this.resolveSessionId();
850
+ if (!sessionId)
851
+ return false;
852
+ return this.answerSession(sessionId, options);
872
853
  }
873
854
  hangup(options) {
874
- return this.hangupSession(void 0, options);
875
- }
876
- mute() {
877
- return this.muteSession();
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
- hold() {
883
- return this.holdSession();
860
+ toggleMute() {
861
+ return this.toggleMuteSession();
884
862
  }
885
- unhold() {
886
- return this.unholdSession();
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
- answerSession(sessionIdOrOptions, options) {
1005
- const sessionId = typeof sessionIdOrOptions === "string" ? sessionIdOrOptions : this.resolveSessionId();
1006
- const opts = typeof sessionIdOrOptions === "string" ? options ?? {} : sessionIdOrOptions ?? {};
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
- holdOtherSessions(
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(sessionIdOrOptions, options) {
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, opts);
996
+ return this.sessionManager.hangup(sessionId, options);
1026
997
  }
1027
- muteSession(sessionId) {
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
- if (sessionState?.muted)
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
- unmuteSession(sessionId) {
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
- if (!sessionState?.muted)
1016
+ const isOnHold = sessionState?.status === CallStatus.Hold;
1017
+ if (isOnHold) {
1018
+ this.sessionManager.unhold(resolved);
1044
1019
  return true;
1045
- this.sessionManager.unmute(resolved);
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
- upsertSessionState(this.stateStore, resolved, { status: CallStatus.Hold });
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
- mute: (...args) => client.muteSession(...args),
1199
- unmute: (...args) => client.unmuteSession(...args),
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),