@capgo/capacitor-stream-call 0.0.3 → 0.0.4

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
@@ -337,6 +337,7 @@ isCameraEnabled() => Promise<CameraEnabledResponse>
337
337
  | **`callId`** | <code>string</code> | ID of the call |
338
338
  | **`state`** | <code>string</code> | Current state of the call |
339
339
  | **`userId`** | <code>string</code> | User ID of the participant in the call who triggered the event |
340
+ | **`reason`** | <code>string</code> | Reason for the call state change |
340
341
 
341
342
 
342
343
  #### CameraEnabledResponse
@@ -34,7 +34,7 @@ class CustomNotificationHandler(
34
34
  shouldHaveContentIntent: Boolean,
35
35
  ): Notification {
36
36
 
37
- customCreateIncomingCallChannel(channelId, showAsHighPriority)
37
+ customCreateIncomingCallChannel()
38
38
 
39
39
  return buildNotification(
40
40
  fullScreenPendingIntent,
@@ -136,8 +136,13 @@ fun IncomingCallView(
136
136
  isCameraEnabled = isCameraEnabled,
137
137
  onCallAction = { action ->
138
138
  when (action) {
139
- DeclineCall -> onDeclineCall?.invoke(call)
140
- AcceptCall -> onAcceptCall?.invoke(call)
139
+ DeclineCall -> {
140
+ onDeclineCall?.invoke(call)
141
+ }
142
+ AcceptCall -> {
143
+ call.camera.setEnabled(isCameraEnabled)
144
+ onAcceptCall?.invoke(call)
145
+ }
141
146
  is ToggleCamera -> {
142
147
  call.camera.setEnabled(action.isEnabled)
143
148
  }
@@ -202,7 +202,7 @@ public class StreamCallPlugin : Plugin() {
202
202
  private fun declineCall(call: Call) {
203
203
  kotlinx.coroutines.GlobalScope.launch {
204
204
  try {
205
- call.leave()
205
+ call.reject()
206
206
 
207
207
  // Stop ringtone
208
208
  ringtonePlayer?.stopRinging()
@@ -733,7 +733,7 @@ public class StreamCallPlugin : Plugin() {
733
733
  }
734
734
 
735
735
  // Join the call without affecting others
736
- call.join()
736
+ call.accept()
737
737
 
738
738
  // Notify that call has started
739
739
  val data = JSObject().apply {
package/dist/docs.json CHANGED
@@ -506,6 +506,13 @@
506
506
  "docs": "User ID of the participant in the call who triggered the event",
507
507
  "complexTypes": [],
508
508
  "type": "string | undefined"
509
+ },
510
+ {
511
+ "name": "reason",
512
+ "tags": [],
513
+ "docs": "Reason for the call state change",
514
+ "complexTypes": [],
515
+ "type": "string | undefined"
509
516
  }
510
517
  ]
511
518
  },
@@ -59,6 +59,8 @@ export interface CallEvent {
59
59
  state: string;
60
60
  /** User ID of the participant in the call who triggered the event */
61
61
  userId?: string;
62
+ /** Reason for the call state change */
63
+ reason?: string;
62
64
  }
63
65
  export interface CameraEnabledResponse {
64
66
  enabled: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * @interface LoginOptions\n * @description Configuration options for logging into the Stream Video service\n * @property {string} token - Stream Video API token for authentication\n * @property {string} userId - Unique identifier for the current user\n * @property {string} name - Display name for the current user\n * @property {string} [imageURL] - Avatar URL for the current user\n * @property {string} apiKey - Stream Video API key for your application\n * @property {string} [magicDivId] - DOM element ID where video will be rendered\n */\nexport interface LoginOptions {\n /** Stream Video API token */\n token: string;\n /** User ID for the current user */\n userId: string;\n /** Display name for the current user */\n name: string;\n /** Optional avatar URL for the current user */\n imageURL?: string;\n /** Stream Video API key */\n apiKey: string;\n /** ID of the HTML element where the video will be rendered */\n magicDivId?: string;\n}\n\n/**\n * @interface CallOptions\n * @description Options for initiating a video call\n * @property {string} userId - ID of the user to call\n * @property {string} [type=default] - Type of call\n * @property {boolean} [ring=true] - Whether to send ring notification\n */\nexport interface CallOptions {\n /** User ID of the person to call */\n userIds: string[];\n /** Type of call, defaults to 'default' */\n type?: string;\n /** Whether to ring the other user, defaults to true */\n ring?: boolean;\n}\n\n/**\n * @interface SuccessResponse\n * @description Standard response indicating operation success/failure\n * @property {boolean} success - Whether the operation succeeded\n */\nexport interface SuccessResponse {\n /** Whether the operation was successful */\n success: boolean;\n}\n\n/**\n * @interface CallEvent\n * @description Event emitted when call state changes\n * @property {string} callId - Unique identifier of the call\n * @property {string} state - Current state of the call (joined, left, ringing, etc)\n */\nexport interface CallEvent {\n /** ID of the call */\n callId: string;\n /** Current state of the call */\n state: string;\n /** User ID of the participant in the call who triggered the event */\n userId?: string\n}\n\nexport interface CameraEnabledResponse {\n enabled: boolean;\n}\n\n/**\n * @interface StreamCallPlugin\n * @description Capacitor plugin for Stream Video calling functionality\n */\nexport interface StreamCallPlugin {\n /**\n * Login to Stream Video service\n * @param {LoginOptions} options - Login configuration\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.login({\n * token: 'your-token',\n * userId: 'user-123',\n * name: 'John Doe',\n * apiKey: 'your-api-key'\n * });\n */\n login(options: LoginOptions): Promise<SuccessResponse>;\n\n /**\n * Logout from Stream Video service\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.logout();\n */\n logout(): Promise<SuccessResponse>;\n\n /**\n * Initiate a call to another user\n * @param {CallOptions} options - Call configuration\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.call({\n * userId: 'user-456',\n * type: 'video',\n * ring: true\n * });\n */\n call(options: CallOptions): Promise<SuccessResponse>;\n\n /**\n * End the current call\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.endCall();\n */\n endCall(): Promise<SuccessResponse>;\n\n /**\n * Enable or disable microphone\n * @param {{ enabled: boolean }} options - Microphone state\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.setMicrophoneEnabled({ enabled: false });\n */\n setMicrophoneEnabled(options: { enabled: boolean }): Promise<SuccessResponse>;\n\n /**\n * Enable or disable camera\n * @param {{ enabled: boolean }} options - Camera state\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.setCameraEnabled({ enabled: false });\n */\n setCameraEnabled(options: { enabled: boolean }): Promise<SuccessResponse>;\n\n /**\n * Add listener for call events\n * @param {'callEvent'} eventName - Name of the event to listen for\n * @param {(event: CallEvent) => void} listenerFunc - Callback function\n * @returns {Promise<{ remove: () => Promise<void> }>} Function to remove listener\n * @example\n * const listener = await StreamCall.addListener('callEvent', (event) => {\n * console.log(`Call ${event.callId} is now ${event.state}`);\n * });\n */\n addListener(\n eventName: 'callEvent',\n listenerFunc: (event: CallEvent) => void,\n ): Promise<{ remove: () => Promise<void> }>;\n\n /**\n * Remove all event listeners\n * @returns {Promise<void>}\n * @example\n * await StreamCall.removeAllListeners();\n */\n removeAllListeners(): Promise<void>;\n\n /**\n * Accept an incoming call\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.acceptCall();\n */\n acceptCall(): Promise<SuccessResponse>;\n\n /**\n * Reject an incoming call\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.rejectCall();\n */\n rejectCall(): Promise<SuccessResponse>;\n isCameraEnabled(): Promise<CameraEnabledResponse>;\n}\n"]}
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * @interface LoginOptions\n * @description Configuration options for logging into the Stream Video service\n * @property {string} token - Stream Video API token for authentication\n * @property {string} userId - Unique identifier for the current user\n * @property {string} name - Display name for the current user\n * @property {string} [imageURL] - Avatar URL for the current user\n * @property {string} apiKey - Stream Video API key for your application\n * @property {string} [magicDivId] - DOM element ID where video will be rendered\n */\nexport interface LoginOptions {\n /** Stream Video API token */\n token: string;\n /** User ID for the current user */\n userId: string;\n /** Display name for the current user */\n name: string;\n /** Optional avatar URL for the current user */\n imageURL?: string;\n /** Stream Video API key */\n apiKey: string;\n /** ID of the HTML element where the video will be rendered */\n magicDivId?: string;\n}\n\n/**\n * @interface CallOptions\n * @description Options for initiating a video call\n * @property {string} userId - ID of the user to call\n * @property {string} [type=default] - Type of call\n * @property {boolean} [ring=true] - Whether to send ring notification\n */\nexport interface CallOptions {\n /** User ID of the person to call */\n userIds: string[];\n /** Type of call, defaults to 'default' */\n type?: string;\n /** Whether to ring the other user, defaults to true */\n ring?: boolean;\n}\n\n/**\n * @interface SuccessResponse\n * @description Standard response indicating operation success/failure\n * @property {boolean} success - Whether the operation succeeded\n */\nexport interface SuccessResponse {\n /** Whether the operation was successful */\n success: boolean;\n}\n\n/**\n * @interface CallEvent\n * @description Event emitted when call state changes\n * @property {string} callId - Unique identifier of the call\n * @property {string} state - Current state of the call (joined, left, ringing, etc)\n */\nexport interface CallEvent {\n /** ID of the call */\n callId: string;\n /** Current state of the call */\n state: string;\n /** User ID of the participant in the call who triggered the event */\n userId?: string\n /** Reason for the call state change */\n reason?: string;\n}\n\nexport interface CameraEnabledResponse {\n enabled: boolean;\n}\n\n/**\n * @interface StreamCallPlugin\n * @description Capacitor plugin for Stream Video calling functionality\n */\nexport interface StreamCallPlugin {\n /**\n * Login to Stream Video service\n * @param {LoginOptions} options - Login configuration\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.login({\n * token: 'your-token',\n * userId: 'user-123',\n * name: 'John Doe',\n * apiKey: 'your-api-key'\n * });\n */\n login(options: LoginOptions): Promise<SuccessResponse>;\n\n /**\n * Logout from Stream Video service\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.logout();\n */\n logout(): Promise<SuccessResponse>;\n\n /**\n * Initiate a call to another user\n * @param {CallOptions} options - Call configuration\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.call({\n * userId: 'user-456',\n * type: 'video',\n * ring: true\n * });\n */\n call(options: CallOptions): Promise<SuccessResponse>;\n\n /**\n * End the current call\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.endCall();\n */\n endCall(): Promise<SuccessResponse>;\n\n /**\n * Enable or disable microphone\n * @param {{ enabled: boolean }} options - Microphone state\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.setMicrophoneEnabled({ enabled: false });\n */\n setMicrophoneEnabled(options: { enabled: boolean }): Promise<SuccessResponse>;\n\n /**\n * Enable or disable camera\n * @param {{ enabled: boolean }} options - Camera state\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.setCameraEnabled({ enabled: false });\n */\n setCameraEnabled(options: { enabled: boolean }): Promise<SuccessResponse>;\n\n /**\n * Add listener for call events\n * @param {'callEvent'} eventName - Name of the event to listen for\n * @param {(event: CallEvent) => void} listenerFunc - Callback function\n * @returns {Promise<{ remove: () => Promise<void> }>} Function to remove listener\n * @example\n * const listener = await StreamCall.addListener('callEvent', (event) => {\n * console.log(`Call ${event.callId} is now ${event.state}`);\n * });\n */\n addListener(\n eventName: 'callEvent',\n listenerFunc: (event: CallEvent) => void,\n ): Promise<{ remove: () => Promise<void> }>;\n\n /**\n * Remove all event listeners\n * @returns {Promise<void>}\n * @example\n * await StreamCall.removeAllListeners();\n */\n removeAllListeners(): Promise<void>;\n\n /**\n * Accept an incoming call\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.acceptCall();\n */\n acceptCall(): Promise<SuccessResponse>;\n\n /**\n * Reject an incoming call\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.rejectCall();\n */\n rejectCall(): Promise<SuccessResponse>;\n isCameraEnabled(): Promise<CameraEnabledResponse>;\n}\n"]}
package/dist/esm/web.d.ts CHANGED
@@ -11,11 +11,21 @@ export declare class StreamCallWeb extends WebPlugin implements StreamCallPlugin
11
11
  private audioBindings;
12
12
  private participantJoinedListener?;
13
13
  private participantLeftListener?;
14
+ private participantResponses;
15
+ private callMembersExpected;
14
16
  private setupCallRingListener;
17
+ private setupCallEventListeners;
15
18
  private ringCallback;
16
19
  private setupParticipantListener;
17
20
  private setupParticipantVideo;
18
21
  private setupParticipantAudio;
22
+ private callSessionStartedCallback;
23
+ private callRejectedCallback;
24
+ private callAcceptedCallback;
25
+ private callMissedCallback;
26
+ private callStates;
27
+ private checkCallTimeout;
28
+ private checkAllParticipantsResponded;
19
29
  private cleanupCall;
20
30
  login(options: LoginOptions): Promise<SuccessResponse>;
21
31
  logout(): Promise<SuccessResponse>;
package/dist/esm/web.js CHANGED
@@ -5,6 +5,8 @@ export class StreamCallWeb extends WebPlugin {
5
5
  super(...arguments);
6
6
  this.videoBindings = new Map();
7
7
  this.audioBindings = new Map();
8
+ this.participantResponses = new Map();
9
+ this.callMembersExpected = new Map();
8
10
  this.ringCallback = (event) => {
9
11
  var _a, _b;
10
12
  console.log('Call ringing', event, this.currentCall);
@@ -12,7 +14,10 @@ export class StreamCallWeb extends WebPlugin {
12
14
  if (!this.currentCall) {
13
15
  console.log('Creating new call', event.call.id);
14
16
  this.currentCall = (_a = this.client) === null || _a === void 0 ? void 0 : _a.call(event.call.type, event.call.id);
17
+ // this.currentActiveCallId = this.currentCall?.cid;
15
18
  this.notifyListeners('callEvent', { callId: event.call.id, state: CallingState.RINGING });
19
+ // Clear previous responses when a new call starts
20
+ this.participantResponses.clear();
16
21
  }
17
22
  if (this.currentCall) {
18
23
  console.log('Call found', this.currentCall.id);
@@ -21,6 +26,7 @@ export class StreamCallWeb extends WebPlugin {
21
26
  console.log('Call state', s);
22
27
  if (s === CallingState.JOINED) {
23
28
  this.setupParticipantListener();
29
+ this.setupCallEventListeners();
24
30
  }
25
31
  else if (s === CallingState.LEFT || s === CallingState.RECONNECTING_FAILED) {
26
32
  this.cleanupCall();
@@ -34,11 +40,110 @@ export class StreamCallWeb extends WebPlugin {
34
40
  });
35
41
  }
36
42
  };
43
+ this.callSessionStartedCallback = (event) => {
44
+ console.log('Call created (session started)', event);
45
+ if (event.call && event.call.session && event.call.session.participants) {
46
+ // Store the number of expected participants for this call
47
+ const callCid = event.call.cid;
48
+ const memberCount = event.call.session.participants.length;
49
+ console.log(`Call ${callCid} created with ${memberCount} members`);
50
+ this.callMembersExpected.set(callCid, memberCount);
51
+ // Store call members in callStates
52
+ this.callStates.set(callCid, {
53
+ members: event.call.session.participants.map(p => { var _a; return ({ user_id: ((_a = p.user) === null || _a === void 0 ? void 0 : _a.id) || '' }); }),
54
+ participantResponses: new Map(),
55
+ expectedMemberCount: memberCount,
56
+ createdAt: new Date(),
57
+ });
58
+ // Start a timeout task that runs every second
59
+ const timeoutTask = setInterval(() => this.checkCallTimeout(callCid), 1000);
60
+ // Update the callState with the timeout task
61
+ const callState = this.callStates.get(callCid);
62
+ if (callState) {
63
+ callState.timer = timeoutTask;
64
+ this.callStates.set(callCid, callState);
65
+ }
66
+ }
67
+ };
68
+ this.callRejectedCallback = (event) => {
69
+ console.log('Call rejected', event);
70
+ if (event.user && event.user.id) {
71
+ this.participantResponses.set(event.user.id, 'rejected');
72
+ // Update the combined callStates map
73
+ const callState = this.callStates.get(event.call_cid);
74
+ if (callState) {
75
+ callState.participantResponses.set(event.user.id, 'rejected');
76
+ this.callStates.set(event.call_cid, callState);
77
+ }
78
+ this.notifyListeners('callEvent', {
79
+ callId: event.call_cid,
80
+ state: 'rejected',
81
+ userId: event.user.id
82
+ });
83
+ this.checkAllParticipantsResponded();
84
+ }
85
+ };
86
+ this.callAcceptedCallback = (event) => {
87
+ console.log('Call accepted', event);
88
+ if (event.user && event.user.id) {
89
+ this.participantResponses.set(event.user.id, 'accepted');
90
+ // Update the combined callStates map
91
+ const callState = this.callStates.get(event.call_cid);
92
+ if (callState) {
93
+ callState.participantResponses.set(event.user.id, 'accepted');
94
+ // If someone accepted, clear the timer as we don't need to check anymore
95
+ if (callState.timer) {
96
+ clearInterval(callState.timer);
97
+ callState.timer = undefined;
98
+ }
99
+ this.callStates.set(event.call_cid, callState);
100
+ }
101
+ this.notifyListeners('callEvent', {
102
+ callId: event.call_cid,
103
+ state: 'accepted',
104
+ userId: event.user.id
105
+ });
106
+ }
107
+ };
108
+ this.callMissedCallback = (event) => {
109
+ console.log('Call missed', event);
110
+ if (event.user && event.user.id) {
111
+ this.participantResponses.set(event.user.id, 'missed');
112
+ // Update the combined callStates map
113
+ const callState = this.callStates.get(event.call_cid);
114
+ if (callState) {
115
+ callState.participantResponses.set(event.user.id, 'missed');
116
+ this.callStates.set(event.call_cid, callState);
117
+ }
118
+ this.notifyListeners('callEvent', {
119
+ callId: event.call_cid,
120
+ state: 'missed',
121
+ userId: event.user.id
122
+ });
123
+ this.checkAllParticipantsResponded();
124
+ }
125
+ };
126
+ // Add a combined map for call states, mirroring the iOS implementation
127
+ this.callStates = new Map();
37
128
  }
129
+ // private currentActiveCallId?: string;
38
130
  setupCallRingListener() {
39
- var _a, _b;
131
+ var _a, _b, _c, _d;
40
132
  (_a = this.client) === null || _a === void 0 ? void 0 : _a.off('call.ring', this.ringCallback);
41
- (_b = this.client) === null || _b === void 0 ? void 0 : _b.on('call.ring', this.ringCallback);
133
+ (_b = this.client) === null || _b === void 0 ? void 0 : _b.off('call.session_started', this.callSessionStartedCallback);
134
+ (_c = this.client) === null || _c === void 0 ? void 0 : _c.on('call.ring', this.ringCallback);
135
+ (_d = this.client) === null || _d === void 0 ? void 0 : _d.on('call.session_started', this.callSessionStartedCallback);
136
+ }
137
+ setupCallEventListeners() {
138
+ var _a, _b, _c, _d, _e, _f;
139
+ // Clear previous listeners if any
140
+ (_a = this.client) === null || _a === void 0 ? void 0 : _a.off('call.rejected', this.callRejectedCallback);
141
+ (_b = this.client) === null || _b === void 0 ? void 0 : _b.off('call.accepted', this.callAcceptedCallback);
142
+ (_c = this.client) === null || _c === void 0 ? void 0 : _c.off('call.missed', this.callMissedCallback);
143
+ // Register event listeners
144
+ (_d = this.client) === null || _d === void 0 ? void 0 : _d.on('call.rejected', this.callRejectedCallback);
145
+ (_e = this.client) === null || _e === void 0 ? void 0 : _e.on('call.accepted', this.callAcceptedCallback);
146
+ (_f = this.client) === null || _f === void 0 ? void 0 : _f.on('call.missed', this.callMissedCallback);
42
147
  }
43
148
  setupParticipantListener() {
44
149
  // Subscribe to participant changes
@@ -55,6 +160,7 @@ export class StreamCallWeb extends WebPlugin {
55
160
  }
56
161
  };
57
162
  this.participantLeftListener = (event) => {
163
+ var _a, _b;
58
164
  if (this.magicDivId && event.participant) {
59
165
  const videoId = `video-${event.participant.sessionId}`;
60
166
  const audioId = `audio-${event.participant.sessionId}`;
@@ -70,10 +176,9 @@ export class StreamCallWeb extends WebPlugin {
70
176
  if (tracks) {
71
177
  tracks.getTracks().forEach((track) => {
72
178
  track.stop();
73
- track.enabled = false;
74
179
  });
75
- videoEl.srcObject = null;
76
180
  }
181
+ videoEl.srcObject = null;
77
182
  videoEl.remove();
78
183
  }
79
184
  // Remove audio element
@@ -88,13 +193,44 @@ export class StreamCallWeb extends WebPlugin {
88
193
  if (tracks) {
89
194
  tracks.getTracks().forEach((track) => {
90
195
  track.stop();
91
- track.enabled = false;
92
196
  });
93
- audioEl.srcObject = null;
94
197
  }
198
+ audioEl.srcObject = null;
95
199
  audioEl.remove();
96
200
  }
97
201
  }
202
+ // Check if we're the only participant left in the call
203
+ if (this.currentCall && this.currentCall.state.session) {
204
+ // Get the remaining participants count (we need to subtract 1 as we haven't been removed from the list yet)
205
+ const remainingParticipants = this.currentCall.state.session.participants.length - 1;
206
+ // If we're the only one left, end the call
207
+ if (remainingParticipants <= 1) {
208
+ console.log(`We are left solo in a call. Ending. cID: ${this.currentCall.cid}`);
209
+ // End the call
210
+ this.currentCall.leave();
211
+ // Clean up resources
212
+ const callCid = this.currentCall.cid;
213
+ // Invalidate and remove timer
214
+ const callState = (_a = this.callStates) === null || _a === void 0 ? void 0 : _a.get(callCid);
215
+ if (callState === null || callState === void 0 ? void 0 : callState.timer) {
216
+ clearInterval(callState.timer);
217
+ }
218
+ // Remove from callStates
219
+ (_b = this.callStates) === null || _b === void 0 ? void 0 : _b.delete(callCid);
220
+ // Reset the current call
221
+ this.currentCall = undefined;
222
+ // this.currentActiveCallId = undefined;
223
+ // Clean up
224
+ this.cleanupCall();
225
+ console.log(`Cleaned up resources for ended call: ${callCid}`);
226
+ // Notify that the call has ended
227
+ this.notifyListeners('callEvent', {
228
+ callId: callCid,
229
+ state: 'left',
230
+ reason: 'participant_left'
231
+ });
232
+ }
233
+ }
98
234
  };
99
235
  this.currentCall.on('participantJoined', this.participantJoinedListener);
100
236
  this.currentCall.on('participantLeft', this.participantLeftListener);
@@ -139,6 +275,101 @@ export class StreamCallWeb extends WebPlugin {
139
275
  this.audioBindings.set(id, unbind);
140
276
  }
141
277
  }
278
+ checkCallTimeout(callCid) {
279
+ const callState = this.callStates.get(callCid);
280
+ if (!callState)
281
+ return;
282
+ // Calculate time elapsed since call creation
283
+ const now = new Date();
284
+ const elapsedSeconds = (now.getTime() - callState.createdAt.getTime()) / 1000;
285
+ // Check if 30 seconds have passed
286
+ if (elapsedSeconds >= 30) {
287
+ console.log(`Call ${callCid} has timed out after ${elapsedSeconds} seconds`);
288
+ // Check if anyone has accepted
289
+ const hasAccepted = Array.from(callState.participantResponses.values())
290
+ .some(response => response === 'accepted');
291
+ if (!hasAccepted) {
292
+ console.log(`No one accepted call ${callCid}, marking all non-responders as missed`);
293
+ // Mark all members who haven't responded as "missed"
294
+ callState.members.forEach(member => {
295
+ if (!callState.participantResponses.has(member.user_id)) {
296
+ callState.participantResponses.set(member.user_id, 'missed');
297
+ this.participantResponses.set(member.user_id, 'missed');
298
+ this.notifyListeners('callEvent', {
299
+ callId: callCid,
300
+ state: 'missed',
301
+ userId: member.user_id
302
+ });
303
+ }
304
+ });
305
+ // End the call
306
+ if (this.currentCall && this.currentCall.cid === callCid) {
307
+ this.currentCall.leave();
308
+ }
309
+ // Clear the timeout task
310
+ if (callState.timer) {
311
+ clearInterval(callState.timer);
312
+ callState.timer = undefined;
313
+ }
314
+ // Remove from callStates
315
+ this.callStates.delete(callCid);
316
+ // Clean up
317
+ this.cleanupCall();
318
+ // Notify that the call has ended
319
+ this.notifyListeners('callEvent', {
320
+ callId: callCid,
321
+ state: 'ended',
322
+ reason: 'timeout'
323
+ });
324
+ }
325
+ }
326
+ }
327
+ checkAllParticipantsResponded() {
328
+ if (!this.currentCall)
329
+ return;
330
+ const callCid = this.currentCall.cid;
331
+ const totalParticipants = this.callMembersExpected.get(callCid);
332
+ if (!totalParticipants) {
333
+ console.log(`No expected participant count found for call: ${callCid}`);
334
+ return;
335
+ }
336
+ console.log(`Total expected participants: ${totalParticipants}`);
337
+ // Count rejections and misses
338
+ let rejectedOrMissedCount = 0;
339
+ this.participantResponses.forEach(response => {
340
+ if (response === 'rejected' || response === 'missed') {
341
+ rejectedOrMissedCount++;
342
+ }
343
+ });
344
+ console.log(`Participants responded: ${this.participantResponses.size}/${totalParticipants}`);
345
+ console.log(`Rejected or missed: ${rejectedOrMissedCount}`);
346
+ const allResponded = this.participantResponses.size >= totalParticipants;
347
+ const allRejectedOrMissed = allResponded &&
348
+ Array.from(this.participantResponses.values()).every(response => response === 'rejected' || response === 'missed');
349
+ // If all participants have rejected or missed the call
350
+ if (allResponded && allRejectedOrMissed) {
351
+ console.log('All participants have rejected or missed the call');
352
+ // End the call
353
+ this.currentCall.leave();
354
+ // Clean up the timer if exists in callStates
355
+ const callState = this.callStates.get(callCid);
356
+ if (callState === null || callState === void 0 ? void 0 : callState.timer) {
357
+ clearInterval(callState.timer);
358
+ }
359
+ // Remove from callStates
360
+ this.callStates.delete(callCid);
361
+ // Clear the responses
362
+ this.participantResponses.clear();
363
+ // Clean up
364
+ this.cleanupCall();
365
+ // Notify that the call has ended
366
+ this.notifyListeners('callEvent', {
367
+ callId: callCid,
368
+ state: 'ended',
369
+ reason: 'all_rejected_or_missed'
370
+ });
371
+ }
372
+ }
142
373
  cleanupCall() {
143
374
  var _a;
144
375
  // First cleanup the call listeners
@@ -240,10 +471,14 @@ export class StreamCallWeb extends WebPlugin {
240
471
  }
241
472
  const call = this.client.call(options.type || 'default', crypto.randomUUID());
242
473
  const members = options.userIds.map((userId) => ({ user_id: userId }));
243
- if (this.client.streamClient.userID && options.userIds.includes(this.client.streamClient.userID)) {
474
+ if (this.client.streamClient.userID && !options.userIds.includes(this.client.streamClient.userID)) {
244
475
  members.push({ user_id: this.client.streamClient.userID });
245
476
  }
246
477
  await call.getOrCreate({ data: { members } });
478
+ // Store the expected member count for this call
479
+ // -1, because we don't count the caller themselves
480
+ this.callMembersExpected.set(call.cid, members.length);
481
+ console.log(`Setting expected members for call ${call.cid}: ${members.length}`);
247
482
  this.currentCall = call;
248
483
  if (options.ring) {
249
484
  this.outgoingCall = call.cid;
@@ -312,7 +547,7 @@ export class StreamCallWeb extends WebPlugin {
312
547
  console.log('Rejecting call', this.incomingCall);
313
548
  const call = this.client.call(this.incomingCall.type, this.incomingCall.id);
314
549
  console.log('Leaving call', call);
315
- await call.leave();
550
+ await call.reject();
316
551
  this.incomingCall = undefined;
317
552
  console.log('Rejected call', call);
318
553
  this.notifyListeners('callEvent', { callId: call.id, state: CallingState.LEFT });
@@ -1 +1 @@
1
- {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"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","sourcesContent":["import { WebPlugin } from '@capacitor/core';\nimport type { AllClientEvents, Call, CallResponse, StreamVideoParticipant } from '@stream-io/video-client';\nimport { CallingState, StreamVideoClient } from '@stream-io/video-client';\n\nimport type {\n CallOptions,\n StreamCallPlugin,\n SuccessResponse,\n LoginOptions,\n CameraEnabledResponse,\n} from './definitions';\n\nexport class StreamCallWeb extends WebPlugin implements StreamCallPlugin {\n private client?: StreamVideoClient;\n private currentCall?: Call;\n private callStateSubscription?: { unsubscribe: () => void };\n private incomingCall?: CallResponse;\n private outgoingCall?: string;\n private magicDivId?: string;\n private videoBindings: Map<string, () => void> = new Map();\n private audioBindings: Map<string, () => void> = new Map();\n private participantJoinedListener?: (event: { participant?: { sessionId: string } }) => void;\n private participantLeftListener?: (event: { participant?: { sessionId: string } }) => void;\n\n private setupCallRingListener() {\n this.client?.off('call.ring', this.ringCallback);\n this.client?.on('call.ring', this.ringCallback);\n }\n\n private ringCallback = (event: AllClientEvents['call.ring']) => {\n console.log('Call ringing', event, this.currentCall);\n this.incomingCall = event.call;\n if (!this.currentCall) {\n console.log('Creating new call', event.call.id);\n this.currentCall = this.client?.call(event.call.type, event.call.id);\n this.notifyListeners('callEvent', { callId: event.call.id, state: CallingState.RINGING });\n }\n if (this.currentCall) {\n console.log('Call found', this.currentCall.id);\n this.callStateSubscription = this.currentCall?.state.callingState$.subscribe((s) => {\n console.log('Call state', s);\n if (s === CallingState.JOINED) {\n this.setupParticipantListener();\n } else if (s === CallingState.LEFT || s === CallingState.RECONNECTING_FAILED) {\n this.cleanupCall();\n }\n if (this.outgoingCall && s === CallingState.RINGING) {\n this.outgoingCall = undefined;\n } else {\n this.notifyListeners('callEvent', { callId: this.currentCall?.id, state: s });\n }\n });\n }\n };\n\n private setupParticipantListener() {\n // Subscribe to participant changes\n this.incomingCall = undefined;\n if (!this.currentCall) return;\n\n this.participantJoinedListener = (event) => {\n if (this.magicDivId && event.participant) {\n const magicDiv = document.getElementById(this.magicDivId);\n if (magicDiv && this.currentCall) {\n this.setupParticipantVideo(this.currentCall, event.participant as StreamVideoParticipant, magicDiv);\n this.setupParticipantAudio(this.currentCall, event.participant as StreamVideoParticipant, magicDiv);\n }\n }\n };\n\n this.participantLeftListener = (event) => {\n if (this.magicDivId && event.participant) {\n const videoId = `video-${event.participant.sessionId}`;\n const audioId = `audio-${event.participant.sessionId}`;\n\n // Remove video element\n const videoEl = document.getElementById(videoId) as HTMLVideoElement;\n if (videoEl) {\n const unbindVideo = this.videoBindings.get(videoId);\n if (unbindVideo) {\n unbindVideo();\n this.videoBindings.delete(videoId);\n }\n const tracks = videoEl.srcObject as MediaStream;\n if (tracks) {\n tracks.getTracks().forEach((track) => {\n track.stop();\n track.enabled = false;\n });\n videoEl.srcObject = null;\n }\n videoEl.remove();\n }\n\n // Remove audio element\n const audioEl = document.getElementById(audioId) as HTMLAudioElement;\n if (audioEl) {\n const unbindAudio = this.audioBindings.get(audioId);\n if (unbindAudio) {\n unbindAudio();\n this.audioBindings.delete(audioId);\n }\n const tracks = audioEl.srcObject as MediaStream;\n if (tracks) {\n tracks.getTracks().forEach((track) => {\n track.stop();\n track.enabled = false;\n });\n audioEl.srcObject = null;\n }\n audioEl.remove();\n }\n }\n };\n\n this.currentCall.on('participantJoined', this.participantJoinedListener);\n this.currentCall.on('participantLeft', this.participantLeftListener);\n\n // Setup initial participants\n const participants = this.currentCall.state.participants;\n if (this.magicDivId) {\n const magicDiv = document.getElementById(this.magicDivId);\n if (magicDiv) {\n participants.forEach((participant: StreamVideoParticipant) => {\n if (this.currentCall) {\n this.setupParticipantVideo(this.currentCall, participant, magicDiv);\n this.setupParticipantAudio(this.currentCall, participant, magicDiv);\n }\n });\n }\n }\n }\n\n private setupParticipantVideo(call: Call, participant: StreamVideoParticipant, container: HTMLElement) {\n const id = `video-${participant.sessionId}`;\n if (!document.getElementById(id)) {\n const videoEl = document.createElement('video');\n videoEl.id = id;\n videoEl.style.width = '100%';\n videoEl.style.maxWidth = '300px';\n videoEl.style.aspectRatio = '16/9';\n container.appendChild(videoEl);\n\n const unbind = call.bindVideoElement(videoEl, participant.sessionId, 'videoTrack');\n if (unbind) this.videoBindings.set(id, unbind);\n }\n }\n\n private setupParticipantAudio(call: Call, participant: StreamVideoParticipant, container: HTMLElement) {\n if (participant.isLocalParticipant) return;\n\n const id = `audio-${participant.sessionId}`;\n if (!document.getElementById(id)) {\n const audioEl = document.createElement('audio');\n audioEl.id = id;\n container.appendChild(audioEl);\n\n const unbind = call.bindAudioElement(audioEl, participant.sessionId);\n if (unbind) this.audioBindings.set(id, unbind);\n }\n }\n\n private cleanupCall() {\n // First cleanup the call listeners\n if (this.currentCall) {\n if (this.participantJoinedListener) {\n this.currentCall.off('participantJoined', this.participantJoinedListener);\n this.participantJoinedListener = undefined;\n }\n if (this.participantLeftListener) {\n this.currentCall.off('participantLeft', this.participantLeftListener);\n this.participantLeftListener = undefined;\n }\n this.callStateSubscription?.unsubscribe();\n }\n\n if (this.magicDivId) {\n const magicDiv = document.getElementById(this.magicDivId);\n if (magicDiv) {\n // Remove all video elements\n const videoElements = magicDiv.querySelectorAll('video');\n videoElements.forEach((video) => {\n const id = video.id;\n const unbind = this.videoBindings.get(id);\n if (unbind) {\n unbind();\n this.videoBindings.delete(id);\n }\n // Stop all tracks\n const tracks = (video as HTMLVideoElement).srcObject as MediaStream;\n if (tracks) {\n tracks.getTracks().forEach((track) => {\n track.stop();\n track.enabled = false;\n });\n video.srcObject = null;\n }\n video.remove();\n });\n\n // Remove all audio elements\n const audioElements = magicDiv.querySelectorAll('audio');\n audioElements.forEach((audio) => {\n const id = audio.id;\n const unbind = this.audioBindings.get(id);\n if (unbind) {\n unbind();\n this.audioBindings.delete(id);\n }\n // Stop all tracks\n const tracks = (audio as HTMLAudioElement).srcObject as MediaStream;\n if (tracks) {\n tracks.getTracks().forEach((track) => {\n track.stop();\n track.enabled = false;\n });\n audio.srcObject = null;\n }\n audio.remove();\n });\n\n // Clear the container\n while (magicDiv.firstChild) {\n magicDiv.removeChild(magicDiv.firstChild);\n }\n }\n }\n\n // Clear all bindings\n this.videoBindings.clear();\n this.audioBindings.clear();\n\n // Clear call references\n this.currentCall = undefined;\n this.incomingCall = undefined;\n }\n\n async login(options: LoginOptions): Promise<SuccessResponse> {\n this.client = StreamVideoClient.getOrCreateInstance({\n apiKey: options.apiKey,\n user: { id: options.userId, name: options.name, image: options.imageURL },\n token: options.token,\n });\n\n this.magicDivId = options.magicDivId;\n this.setupCallRingListener();\n\n return { success: true };\n }\n\n async logout(): Promise<SuccessResponse> {\n if (!this.client) {\n console.log('No client', this.client);\n throw new Error('Client not initialized');\n }\n\n // Cleanup subscription\n this.callStateSubscription?.unsubscribe();\n this.callStateSubscription = undefined;\n\n await this.client.disconnectUser();\n this.client = undefined;\n this.currentCall = undefined;\n return { success: true };\n }\n\n async call(options: CallOptions): Promise<SuccessResponse> {\n if (!this.client) {\n console.log('No client', this.client);\n throw new Error('Client not initialized - Please login first');\n }\n\n const call = this.client.call(options.type || 'default', crypto.randomUUID());\n const members = options.userIds.map((userId) => ({ user_id: userId }));\n if (this.client.streamClient.userID && options.userIds.includes(this.client.streamClient.userID)) {\n members.push({ user_id: this.client.streamClient.userID });\n }\n await call.getOrCreate({ data: { members } });\n this.currentCall = call;\n if (options.ring) {\n this.outgoingCall = call.cid;\n await call.ring();\n }\n\n await call.join();\n return { success: true };\n }\n\n async endCall(): Promise<SuccessResponse> {\n if (!this.currentCall) {\n console.log('No active call', this.currentCall);\n throw new Error('No active call');\n }\n\n await this.currentCall.leave();\n this.currentCall = undefined;\n this.cleanupCall();\n\n return { success: true };\n }\n\n async setMicrophoneEnabled(options: { enabled: boolean }): Promise<SuccessResponse> {\n if (!this.currentCall) {\n console.log('No active call', this.currentCall);\n throw new Error('No active call');\n }\n\n if (options.enabled) {\n await this.currentCall.microphone.enable();\n } else {\n await this.currentCall.microphone.disable();\n }\n\n return { success: true };\n }\n\n async setCameraEnabled(options: { enabled: boolean }): Promise<SuccessResponse> {\n if (!this.currentCall) {\n console.log('No active call', this.currentCall);\n throw new Error('No active call');\n }\n\n if (options.enabled) {\n await this.currentCall.camera.enable();\n } else {\n await this.currentCall.camera.disable();\n }\n\n return { success: true };\n }\n\n async acceptCall(): Promise<SuccessResponse> {\n if (!this.incomingCall || !this.client) {\n console.log('No incoming call to accept', this.incomingCall, this.client);\n throw new Error('No incoming call to accept');\n }\n console.log('Accepting call', this.incomingCall);\n const call = this.client.call(this.incomingCall.type, this.incomingCall.id);\n this.currentCall = call;\n console.log('Joining call', call);\n await call.accept();\n await call.join();\n console.log('Joined call', call);\n this.notifyListeners('callEvent', { callId: call.id, state: CallingState.JOINED });\n this.setupParticipantListener();\n return { success: true };\n }\n\n async rejectCall(): Promise<SuccessResponse> {\n if (!this.incomingCall || !this.client) {\n console.log('No incoming call to reject', this.incomingCall, this.client);\n throw new Error('No incoming call to reject');\n }\n console.log('Rejecting call', this.incomingCall);\n const call: Call = this.client.call(this.incomingCall.type, this.incomingCall.id);\n console.log('Leaving call', call);\n await call.leave();\n this.incomingCall = undefined;\n console.log('Rejected call', call);\n this.notifyListeners('callEvent', { callId: call.id, state: CallingState.LEFT });\n this.cleanupCall();\n return { success: true };\n }\n\n async isCameraEnabled(): Promise<CameraEnabledResponse> {\n if (!this.currentCall) {\n console.log('No active call', this.currentCall);\n throw new Error('No active call');\n }\n const enabled = await this.currentCall.camera.enabled;\n return { enabled };\n }\n}\n"]}
1
+ {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"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","sourcesContent":["import { WebPlugin } from '@capacitor/core';\nimport type { AllClientEvents, Call, CallResponse, StreamVideoParticipant } from '@stream-io/video-client';\nimport { CallingState, StreamVideoClient } from '@stream-io/video-client';\n\nimport type {\n CallOptions,\n StreamCallPlugin,\n SuccessResponse,\n LoginOptions,\n CameraEnabledResponse,\n} from './definitions';\n\nexport class StreamCallWeb extends WebPlugin implements StreamCallPlugin {\n private client?: StreamVideoClient;\n private currentCall?: Call;\n private callStateSubscription?: { unsubscribe: () => void };\n private incomingCall?: CallResponse;\n private outgoingCall?: string;\n private magicDivId?: string;\n private videoBindings: Map<string, () => void> = new Map();\n private audioBindings: Map<string, () => void> = new Map();\n private participantJoinedListener?: (event: { participant?: { sessionId: string } }) => void;\n private participantLeftListener?: (event: { participant?: { sessionId: string } }) => void;\n private participantResponses: Map<string, string> = new Map();\n private callMembersExpected: Map<string, number> = new Map();\n// private currentActiveCallId?: string;\n\n private setupCallRingListener() {\n this.client?.off('call.ring', this.ringCallback);\n this.client?.off('call.session_started', this.callSessionStartedCallback);\n\n this.client?.on('call.ring', this.ringCallback);\n this.client?.on('call.session_started', this.callSessionStartedCallback);\n }\n\n private setupCallEventListeners() {\n // Clear previous listeners if any\n this.client?.off('call.rejected', this.callRejectedCallback);\n this.client?.off('call.accepted', this.callAcceptedCallback);\n this.client?.off('call.missed', this.callMissedCallback); \n // Register event listeners\n this.client?.on('call.rejected', this.callRejectedCallback);\n this.client?.on('call.accepted', this.callAcceptedCallback);\n this.client?.on('call.missed', this.callMissedCallback);\n }\n\n private ringCallback = (event: AllClientEvents['call.ring']) => {\n console.log('Call ringing', event, this.currentCall);\n this.incomingCall = event.call;\n if (!this.currentCall) {\n console.log('Creating new call', event.call.id);\n this.currentCall = this.client?.call(event.call.type, event.call.id);\n // this.currentActiveCallId = this.currentCall?.cid;\n this.notifyListeners('callEvent', { callId: event.call.id, state: CallingState.RINGING });\n // Clear previous responses when a new call starts\n this.participantResponses.clear();\n }\n if (this.currentCall) {\n console.log('Call found', this.currentCall.id);\n this.callStateSubscription = this.currentCall?.state.callingState$.subscribe((s) => {\n console.log('Call state', s);\n if (s === CallingState.JOINED) {\n this.setupParticipantListener();\n this.setupCallEventListeners();\n } else if (s === CallingState.LEFT || s === CallingState.RECONNECTING_FAILED) {\n this.cleanupCall();\n }\n if (this.outgoingCall && s === CallingState.RINGING) {\n this.outgoingCall = undefined;\n } else {\n this.notifyListeners('callEvent', { callId: this.currentCall?.id, state: s });\n }\n });\n }\n };\n\n private setupParticipantListener() {\n // Subscribe to participant changes\n this.incomingCall = undefined;\n if (!this.currentCall) return;\n\n this.participantJoinedListener = (event) => {\n if (this.magicDivId && event.participant) {\n const magicDiv = document.getElementById(this.magicDivId);\n if (magicDiv && this.currentCall) {\n this.setupParticipantVideo(this.currentCall, event.participant as StreamVideoParticipant, magicDiv);\n this.setupParticipantAudio(this.currentCall, event.participant as StreamVideoParticipant, magicDiv);\n }\n }\n };\n\n this.participantLeftListener = (event) => {\n if (this.magicDivId && event.participant) {\n const videoId = `video-${event.participant.sessionId}`;\n const audioId = `audio-${event.participant.sessionId}`;\n\n // Remove video element\n const videoEl = document.getElementById(videoId) as HTMLVideoElement;\n if (videoEl) {\n const unbindVideo = this.videoBindings.get(videoId);\n if (unbindVideo) {\n unbindVideo();\n this.videoBindings.delete(videoId);\n }\n const tracks = videoEl.srcObject as MediaStream;\n if (tracks) {\n tracks.getTracks().forEach((track) => {\n track.stop();\n });\n }\n videoEl.srcObject = null;\n videoEl.remove();\n }\n\n // Remove audio element\n const audioEl = document.getElementById(audioId) as HTMLAudioElement;\n if (audioEl) {\n const unbindAudio = this.audioBindings.get(audioId);\n if (unbindAudio) {\n unbindAudio();\n this.audioBindings.delete(audioId);\n }\n const tracks = audioEl.srcObject as MediaStream;\n if (tracks) {\n tracks.getTracks().forEach((track) => {\n track.stop();\n });\n }\n audioEl.srcObject = null;\n audioEl.remove();\n }\n }\n \n // Check if we're the only participant left in the call\n if (this.currentCall && this.currentCall.state.session) {\n // Get the remaining participants count (we need to subtract 1 as we haven't been removed from the list yet)\n const remainingParticipants = this.currentCall.state.session.participants.length - 1;\n \n // If we're the only one left, end the call\n if (remainingParticipants <= 1) {\n console.log(`We are left solo in a call. Ending. cID: ${this.currentCall.cid}`);\n \n // End the call\n this.currentCall.leave();\n \n // Clean up resources\n const callCid = this.currentCall.cid;\n \n // Invalidate and remove timer\n const callState = this.callStates?.get(callCid);\n if (callState?.timer) {\n clearInterval(callState.timer);\n }\n \n // Remove from callStates\n this.callStates?.delete(callCid);\n \n // Reset the current call\n this.currentCall = undefined;\n // this.currentActiveCallId = undefined;\n \n // Clean up\n this.cleanupCall();\n \n console.log(`Cleaned up resources for ended call: ${callCid}`);\n \n // Notify that the call has ended\n this.notifyListeners('callEvent', { \n callId: callCid, \n state: 'left',\n reason: 'participant_left'\n });\n }\n }\n };\n\n this.currentCall.on('participantJoined', this.participantJoinedListener);\n this.currentCall.on('participantLeft', this.participantLeftListener);\n\n // Setup initial participants\n const participants = this.currentCall.state.participants;\n if (this.magicDivId) {\n const magicDiv = document.getElementById(this.magicDivId);\n if (magicDiv) {\n participants.forEach((participant: StreamVideoParticipant) => {\n if (this.currentCall) {\n this.setupParticipantVideo(this.currentCall, participant, magicDiv);\n this.setupParticipantAudio(this.currentCall, participant, magicDiv);\n }\n });\n }\n }\n }\n\n private setupParticipantVideo(call: Call, participant: StreamVideoParticipant, container: HTMLElement) {\n const id = `video-${participant.sessionId}`;\n if (!document.getElementById(id)) {\n const videoEl = document.createElement('video');\n videoEl.id = id;\n videoEl.style.width = '100%';\n videoEl.style.maxWidth = '300px';\n videoEl.style.aspectRatio = '16/9';\n container.appendChild(videoEl);\n\n const unbind = call.bindVideoElement(videoEl, participant.sessionId, 'videoTrack');\n if (unbind) this.videoBindings.set(id, unbind);\n }\n }\n\n private setupParticipantAudio(call: Call, participant: StreamVideoParticipant, container: HTMLElement) {\n if (participant.isLocalParticipant) return;\n\n const id = `audio-${participant.sessionId}`;\n if (!document.getElementById(id)) {\n const audioEl = document.createElement('audio');\n audioEl.id = id;\n container.appendChild(audioEl);\n\n const unbind = call.bindAudioElement(audioEl, participant.sessionId);\n if (unbind) this.audioBindings.set(id, unbind);\n }\n }\n\n private callSessionStartedCallback = (event: AllClientEvents['call.session_started']) => {\n console.log('Call created (session started)', event);\n if (event.call && event.call.session && event.call.session.participants) {\n // Store the number of expected participants for this call\n const callCid = event.call.cid;\n const memberCount = event.call.session.participants.length;\n console.log(`Call ${callCid} created with ${memberCount} members`);\n this.callMembersExpected.set(callCid, memberCount);\n \n // Store call members in callStates\n this.callStates.set(callCid, {\n members: event.call.session.participants.map(p => ({ user_id: p.user?.id || '' })),\n participantResponses: new Map(),\n expectedMemberCount: memberCount,\n createdAt: new Date(),\n });\n \n // Start a timeout task that runs every second\n const timeoutTask = setInterval(() => this.checkCallTimeout(callCid), 1000);\n \n // Update the callState with the timeout task\n const callState = this.callStates.get(callCid);\n if (callState) {\n callState.timer = timeoutTask;\n this.callStates.set(callCid, callState);\n }\n }\n };\n\n private callRejectedCallback = (event: AllClientEvents['call.rejected']) => {\n console.log('Call rejected', event);\n if (event.user && event.user.id) {\n this.participantResponses.set(event.user.id, 'rejected');\n \n // Update the combined callStates map\n const callState = this.callStates.get(event.call_cid);\n if (callState) {\n callState.participantResponses.set(event.user.id, 'rejected');\n this.callStates.set(event.call_cid, callState);\n }\n \n this.notifyListeners('callEvent', { \n callId: event.call_cid, \n state: 'rejected',\n userId: event.user.id\n });\n \n this.checkAllParticipantsResponded();\n }\n };\n\n private callAcceptedCallback = (event: AllClientEvents['call.accepted']) => {\n console.log('Call accepted', event);\n if (event.user && event.user.id) {\n this.participantResponses.set(event.user.id, 'accepted');\n \n // Update the combined callStates map\n const callState = this.callStates.get(event.call_cid);\n if (callState) {\n callState.participantResponses.set(event.user.id, 'accepted');\n \n // If someone accepted, clear the timer as we don't need to check anymore\n if (callState.timer) {\n clearInterval(callState.timer);\n callState.timer = undefined;\n }\n \n this.callStates.set(event.call_cid, callState);\n }\n \n this.notifyListeners('callEvent', { \n callId: event.call_cid, \n state: 'accepted',\n userId: event.user.id\n });\n }\n };\n\n private callMissedCallback = (event: AllClientEvents['call.missed']) => {\n console.log('Call missed', event);\n if (event.user && event.user.id) {\n this.participantResponses.set(event.user.id, 'missed');\n \n // Update the combined callStates map\n const callState = this.callStates.get(event.call_cid);\n if (callState) {\n callState.participantResponses.set(event.user.id, 'missed');\n this.callStates.set(event.call_cid, callState);\n }\n \n this.notifyListeners('callEvent', { \n callId: event.call_cid, \n state: 'missed',\n userId: event.user.id\n });\n \n this.checkAllParticipantsResponded();\n }\n };\n \n // Add a combined map for call states, mirroring the iOS implementation\n private callStates: Map<string, {\n members: { user_id: string }[],\n participantResponses: Map<string, string>,\n expectedMemberCount: number,\n createdAt: Date,\n timer?: ReturnType<typeof setInterval>\n }> = new Map();\n \n private checkCallTimeout(callCid: string) {\n const callState = this.callStates.get(callCid);\n if (!callState) return;\n \n // Calculate time elapsed since call creation\n const now = new Date();\n const elapsedSeconds = (now.getTime() - callState.createdAt.getTime()) / 1000;\n \n // Check if 30 seconds have passed\n if (elapsedSeconds >= 30) {\n console.log(`Call ${callCid} has timed out after ${elapsedSeconds} seconds`);\n \n // Check if anyone has accepted\n const hasAccepted = Array.from(callState.participantResponses.values())\n .some(response => response === 'accepted');\n \n if (!hasAccepted) {\n console.log(`No one accepted call ${callCid}, marking all non-responders as missed`);\n \n // Mark all members who haven't responded as \"missed\"\n callState.members.forEach(member => {\n if (!callState.participantResponses.has(member.user_id)) {\n callState.participantResponses.set(member.user_id, 'missed');\n this.participantResponses.set(member.user_id, 'missed');\n \n this.notifyListeners('callEvent', { \n callId: callCid, \n state: 'missed',\n userId: member.user_id\n });\n }\n });\n \n // End the call\n if (this.currentCall && this.currentCall.cid === callCid) {\n this.currentCall.leave();\n }\n \n // Clear the timeout task\n if (callState.timer) {\n clearInterval(callState.timer);\n callState.timer = undefined;\n }\n \n // Remove from callStates\n this.callStates.delete(callCid);\n \n // Clean up\n this.cleanupCall();\n \n // Notify that the call has ended\n this.notifyListeners('callEvent', { \n callId: callCid, \n state: 'ended',\n reason: 'timeout'\n });\n }\n }\n }\n\n private checkAllParticipantsResponded() {\n if (!this.currentCall) return;\n \n const callCid = this.currentCall.cid;\n const totalParticipants = this.callMembersExpected.get(callCid);\n \n if (!totalParticipants) {\n console.log(`No expected participant count found for call: ${callCid}`);\n return;\n }\n \n console.log(`Total expected participants: ${totalParticipants}`);\n \n // Count rejections and misses\n let rejectedOrMissedCount = 0;\n this.participantResponses.forEach(response => {\n if (response === 'rejected' || response === 'missed') {\n rejectedOrMissedCount++;\n }\n });\n \n console.log(`Participants responded: ${this.participantResponses.size}/${totalParticipants}`);\n console.log(`Rejected or missed: ${rejectedOrMissedCount}`);\n \n const allResponded = this.participantResponses.size >= totalParticipants;\n const allRejectedOrMissed = allResponded && \n Array.from(this.participantResponses.values()).every(response => \n response === 'rejected' || response === 'missed'\n );\n \n // If all participants have rejected or missed the call\n if (allResponded && allRejectedOrMissed) {\n console.log('All participants have rejected or missed the call');\n \n // End the call\n this.currentCall.leave();\n \n // Clean up the timer if exists in callStates\n const callState = this.callStates.get(callCid);\n if (callState?.timer) {\n clearInterval(callState.timer);\n }\n \n // Remove from callStates\n this.callStates.delete(callCid);\n \n // Clear the responses\n this.participantResponses.clear();\n \n // Clean up\n this.cleanupCall();\n \n // Notify that the call has ended\n this.notifyListeners('callEvent', { \n callId: callCid, \n state: 'ended',\n reason: 'all_rejected_or_missed'\n });\n }\n }\n\n private cleanupCall() {\n // First cleanup the call listeners\n if (this.currentCall) {\n if (this.participantJoinedListener) {\n this.currentCall.off('participantJoined', this.participantJoinedListener);\n this.participantJoinedListener = undefined;\n }\n if (this.participantLeftListener) {\n this.currentCall.off('participantLeft', this.participantLeftListener);\n this.participantLeftListener = undefined;\n }\n this.callStateSubscription?.unsubscribe();\n }\n\n if (this.magicDivId) {\n const magicDiv = document.getElementById(this.magicDivId);\n if (magicDiv) {\n // Remove all video elements\n const videoElements = magicDiv.querySelectorAll('video');\n videoElements.forEach((video) => {\n const id = video.id;\n const unbind = this.videoBindings.get(id);\n if (unbind) {\n unbind();\n this.videoBindings.delete(id);\n }\n // Stop all tracks\n const tracks = (video as HTMLVideoElement).srcObject as MediaStream;\n if (tracks) {\n tracks.getTracks().forEach((track) => {\n track.stop();\n track.enabled = false;\n });\n video.srcObject = null;\n }\n video.remove();\n });\n\n // Remove all audio elements\n const audioElements = magicDiv.querySelectorAll('audio');\n audioElements.forEach((audio) => {\n const id = audio.id;\n const unbind = this.audioBindings.get(id);\n if (unbind) {\n unbind();\n this.audioBindings.delete(id);\n }\n // Stop all tracks\n const tracks = (audio as HTMLAudioElement).srcObject as MediaStream;\n if (tracks) {\n tracks.getTracks().forEach((track) => {\n track.stop();\n track.enabled = false;\n });\n audio.srcObject = null;\n }\n audio.remove();\n });\n\n // Clear the container\n while (magicDiv.firstChild) {\n magicDiv.removeChild(magicDiv.firstChild);\n }\n }\n }\n\n // Clear all bindings\n this.videoBindings.clear();\n this.audioBindings.clear();\n\n // Clear call references\n this.currentCall = undefined;\n this.incomingCall = undefined;\n }\n\n async login(options: LoginOptions): Promise<SuccessResponse> {\n this.client = StreamVideoClient.getOrCreateInstance({\n apiKey: options.apiKey,\n user: { id: options.userId, name: options.name, image: options.imageURL },\n token: options.token,\n });\n\n this.magicDivId = options.magicDivId;\n this.setupCallRingListener();\n\n return { success: true };\n }\n\n async logout(): Promise<SuccessResponse> {\n if (!this.client) {\n console.log('No client', this.client);\n throw new Error('Client not initialized');\n }\n\n // Cleanup subscription\n this.callStateSubscription?.unsubscribe();\n this.callStateSubscription = undefined;\n\n await this.client.disconnectUser();\n this.client = undefined;\n this.currentCall = undefined;\n return { success: true };\n }\n\n async call(options: CallOptions): Promise<SuccessResponse> {\n if (!this.client) {\n console.log('No client', this.client);\n throw new Error('Client not initialized - Please login first');\n }\n\n const call = this.client.call(options.type || 'default', crypto.randomUUID());\n const members = options.userIds.map((userId) => ({ user_id: userId }));\n if (this.client.streamClient.userID && !options.userIds.includes(this.client.streamClient.userID)) {\n members.push({ user_id: this.client.streamClient.userID });\n }\n await call.getOrCreate({ data: { members } });\n \n // Store the expected member count for this call\n // -1, because we don't count the caller themselves\n this.callMembersExpected.set(call.cid, members.length);\n console.log(`Setting expected members for call ${call.cid}: ${members.length}`);\n \n this.currentCall = call;\n if (options.ring) {\n this.outgoingCall = call.cid;\n await call.ring();\n }\n\n await call.join();\n return { success: true };\n }\n\n async endCall(): Promise<SuccessResponse> {\n if (!this.currentCall) {\n console.log('No active call', this.currentCall);\n throw new Error('No active call');\n }\n\n await this.currentCall.leave();\n this.currentCall = undefined;\n this.cleanupCall();\n\n return { success: true };\n }\n\n async setMicrophoneEnabled(options: { enabled: boolean }): Promise<SuccessResponse> {\n if (!this.currentCall) {\n console.log('No active call', this.currentCall);\n throw new Error('No active call');\n }\n\n if (options.enabled) {\n await this.currentCall.microphone.enable();\n } else {\n await this.currentCall.microphone.disable();\n }\n\n return { success: true };\n }\n\n async setCameraEnabled(options: { enabled: boolean }): Promise<SuccessResponse> {\n if (!this.currentCall) {\n console.log('No active call', this.currentCall);\n throw new Error('No active call');\n }\n\n if (options.enabled) {\n await this.currentCall.camera.enable();\n } else {\n await this.currentCall.camera.disable();\n }\n\n return { success: true };\n }\n\n async acceptCall(): Promise<SuccessResponse> {\n if (!this.incomingCall || !this.client) {\n console.log('No incoming call to accept', this.incomingCall, this.client);\n throw new Error('No incoming call to accept');\n }\n console.log('Accepting call', this.incomingCall);\n const call = this.client.call(this.incomingCall.type, this.incomingCall.id);\n this.currentCall = call;\n console.log('Joining call', call);\n await call.accept();\n await call.join();\n console.log('Joined call', call);\n this.notifyListeners('callEvent', { callId: call.id, state: CallingState.JOINED });\n this.setupParticipantListener();\n return { success: true };\n }\n\n async rejectCall(): Promise<SuccessResponse> {\n if (!this.incomingCall || !this.client) {\n console.log('No incoming call to reject', this.incomingCall, this.client);\n throw new Error('No incoming call to reject');\n }\n console.log('Rejecting call', this.incomingCall);\n const call: Call = this.client.call(this.incomingCall.type, this.incomingCall.id);\n console.log('Leaving call', call);\n await call.reject();\n this.incomingCall = undefined;\n console.log('Rejected call', call);\n this.notifyListeners('callEvent', { callId: call.id, state: CallingState.LEFT });\n this.cleanupCall();\n return { success: true };\n }\n\n async isCameraEnabled(): Promise<CameraEnabledResponse> {\n if (!this.currentCall) {\n console.log('No active call', this.currentCall);\n throw new Error('No active call');\n }\n const enabled = await this.currentCall.camera.enabled;\n return { enabled };\n }\n}\n"]}