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 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 notes
139
+ ## Architecture and Lifecycle
135
140
 
136
- - Module map: `docs/MODULES.md`
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 session = client.getSession(sessionId);
410
- if (!session)
411
- return () => {
412
- };
413
- session.on(event, handler);
414
- return () => session.off(event, handler);
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 sessions = current.sessionIds.map(
963
- (id) => id === sessionId ? nextSession : current.sessionsById[id]
964
- );
965
- if (!existing) {
966
- sessions.push(nextSession);
967
- }
968
- const { sessionsById, sessionIds } = toSessionMaps(sessions);
969
- state.setState({ sessions, sessionsById, sessionIds });
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
- const sessions = current.sessionIds.filter((id) => id !== sessionId).map((id) => current.sessionsById[id]);
974
- const { sessionsById, sessionIds } = toSessionMaps(sessions);
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
- session.terminate?.({
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 = (opts = {}) => {
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", (e) => stopRetry());
1364
- session.on?.("failed", (e) => stopRetry());
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.forEach((id) => this.hangupSession(id, options));
1641
- return ids.length > 0;
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 true;
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 true;
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
- this.detachSessionHandlers(sessionId, targetSession);
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.getState(),
1890
- onChange: (listener) => this.stateStore.onChange(listener),
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.getState();
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?.id ?? "");
2031
+ const sessionId = String(session.id ?? "");
1945
2032
  if (sessionId) {
1946
- this.sessionModule.setSessionMedia(sessionId, callOptions.mediaStream);
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.onChange(fn);
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.sessionsById[sessionId] ?? null;
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 { sessionIds, sessionsById } = useSipSelector(
2184
- (state) => ({
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 activeId = sessionIds.find(
2198
- (id) => sessionsById[id]?.status === CallStatus.Active
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 sessionsById[resolvedSessionId] ?? null;
2210
- }, [sessionsById, resolvedSessionId]);
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
- if (!audioRef.current)
2385
+ const audioEl = audioRef.current;
2386
+ if (!audioEl)
2265
2387
  return;
2266
- audioRef.current.srcObject = remoteStream;
2267
- audioRef.current.play?.().catch(() => {
2388
+ audioEl.srcObject = remoteStream;
2389
+ audioEl.play?.().catch(() => {
2268
2390
  });
2269
2391
  return () => {
2270
- if (audioRef.current) {
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;