sceyt-call 1.1.4 → 1.1.6
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 +185 -213
- package/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,24 +1,20 @@
|
|
|
1
1
|
# Sceyt Call SDK
|
|
2
2
|
|
|
3
|
-
JavaScript SDK for real-time voice and video calls with WebRTC.
|
|
3
|
+
JavaScript SDK for real-time voice and video calls with WebRTC. This SDK works alongside the [SceytChat SDK](https://www.npmjs.com/package/sceyt-chat) to provide calling functionality.
|
|
4
4
|
|
|
5
5
|
## Table of Contents
|
|
6
6
|
|
|
7
7
|
* [Installation](#installation)
|
|
8
|
+
* [Prerequisites](#prerequisites)
|
|
8
9
|
* [Quick Start](#quick-start)
|
|
9
|
-
* [Core Flow](#core-flow)
|
|
10
10
|
* [Media Flow Types](#media-flow-types)
|
|
11
|
-
* [Creating a Call](#creating-a-call)
|
|
12
|
-
* [Joining a Call](#joining-a-call)
|
|
13
|
-
* [Answering & Rejecting](#answering--rejecting)
|
|
14
|
-
* [Invite Keys](#invite-keys)
|
|
15
11
|
* [Call Methods](#call-methods)
|
|
16
|
-
* [
|
|
12
|
+
* [Error Handling](#error-handling)
|
|
17
13
|
* [Call Events](#call-events)
|
|
18
14
|
* [Client Events](#client-events)
|
|
19
15
|
* [Call Management](#call-management)
|
|
20
16
|
* [Call History (CDR)](#call-history-cdr)
|
|
21
|
-
* [
|
|
17
|
+
* [Participant States](#participant-states)
|
|
22
18
|
* [Logging](#logging)
|
|
23
19
|
* [TypeScript Support](#typescript-support)
|
|
24
20
|
* [License](#license)
|
|
@@ -33,7 +29,7 @@ yarn add sceyt-call
|
|
|
33
29
|
|
|
34
30
|
## Prerequisites
|
|
35
31
|
|
|
36
|
-
The Sceyt Call SDK requires the [SceytChat SDK](https://www.npmjs.com/package/sceyt-chat) to be installed and connected before initializing the call client.
|
|
32
|
+
The Sceyt Call SDK requires the [SceytChat SDK](https://www.npmjs.com/package/sceyt-chat) to be installed and connected before initializing the call client. The chat client handles authentication and signaling for calls.
|
|
37
33
|
|
|
38
34
|
```bash
|
|
39
35
|
npm install sceyt-chat
|
|
@@ -46,52 +42,39 @@ const chatClient = new SceytChat('{apiUrl}', '{appId}', '{clientId}');
|
|
|
46
42
|
await chatClient.connect('{accessToken}');
|
|
47
43
|
```
|
|
48
44
|
|
|
49
|
-
For detailed setup, see the [sceyt-chat documentation](https://www.npmjs.com/package/sceyt-chat).
|
|
45
|
+
For detailed chat client setup, see the [sceyt-chat documentation](https://www.npmjs.com/package/sceyt-chat).
|
|
50
46
|
|
|
51
47
|
## Quick Start
|
|
52
48
|
|
|
53
49
|
```typescript
|
|
54
50
|
import SceytCallClient, { MediaFlow } from 'sceyt-call';
|
|
55
51
|
|
|
52
|
+
// Initialize call client with connected chat client
|
|
56
53
|
const callClient = new SceytCallClient(chatClient);
|
|
57
54
|
|
|
58
55
|
// Listen for incoming calls
|
|
59
56
|
callClient.on('invitedToCall', ({ call }) => {
|
|
57
|
+
console.log(`Incoming call from ${call.createdBy}`);
|
|
60
58
|
call.sendRinging();
|
|
61
|
-
//
|
|
59
|
+
// Show incoming call UI...
|
|
62
60
|
});
|
|
63
61
|
|
|
64
|
-
// Start a call
|
|
65
|
-
const result = callClient.prepareCall('
|
|
62
|
+
// Start a call — prepare first, then join
|
|
63
|
+
const result = callClient.prepareCall('call-123', {
|
|
66
64
|
mediaFlow: MediaFlow.P2P,
|
|
67
65
|
participantIds: ['user1', 'user2'],
|
|
68
66
|
});
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
audioSettings: { publishAudio: true },
|
|
72
|
-
videoSettings: { publishVideo: true },
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
## Core Flow
|
|
67
|
+
const call = result.data;
|
|
68
|
+
call?.join({ audioSettings: { publishAudio: true } });
|
|
78
69
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
2. **`call.join(options)`** or **`call.create(errorCallback?)`** — Start signaling and media. On success the call moves to `activeCalls`.
|
|
83
|
-
|
|
84
|
-
```typescript
|
|
85
|
-
// Prepare with full options
|
|
86
|
-
const result = callClient.prepareCall('call-123', {
|
|
87
|
-
mediaFlow: MediaFlow.SFU,
|
|
88
|
-
participantIds: ['user1', 'user2'],
|
|
89
|
-
videoCall: true,
|
|
90
|
-
settings: { startsAt: Date.now(), expiresAt: Date.now() + 3600000 },
|
|
70
|
+
// Handle call events
|
|
71
|
+
call.on('callStateChanged', ({ state }) => {
|
|
72
|
+
console.log(`Call state: ${state}`);
|
|
91
73
|
});
|
|
92
74
|
|
|
93
|
-
|
|
94
|
-
|
|
75
|
+
call.on('participantStateChanged', ({ participant, state }) => {
|
|
76
|
+
console.log(`${participant.id} is now ${state}`);
|
|
77
|
+
});
|
|
95
78
|
```
|
|
96
79
|
|
|
97
80
|
## Media Flow Types
|
|
@@ -102,189 +85,187 @@ const result = callClient.prepareCall(inviteKey);
|
|
|
102
85
|
| `MediaFlow.SFU` | Server-routed media (Selective Forwarding Unit) | Group calls |
|
|
103
86
|
| `MediaFlow.S2W` | SIP-to-WebRTC media processing | 1:1 calls |
|
|
104
87
|
|
|
105
|
-
##
|
|
106
|
-
|
|
107
|
-
Use `call.create()` to send invitations without joining yourself. All call options (`participantIds`, `metadata`, `settings`, etc.) are set via `prepareCall`.
|
|
88
|
+
## Call Methods
|
|
108
89
|
|
|
109
90
|
```typescript
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
metadata: { topic: 'standup' },
|
|
115
|
-
settings: {
|
|
116
|
-
expiresAt: Date.now() + 3600000,
|
|
117
|
-
persistent: true,
|
|
118
|
-
},
|
|
119
|
-
});
|
|
91
|
+
// Audio controls
|
|
92
|
+
call.mute(true); // Mute microphone
|
|
93
|
+
call.mute(false); // Unmute
|
|
94
|
+
call.hold(true); // Put on hold
|
|
120
95
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
```
|
|
96
|
+
// Video controls
|
|
97
|
+
await call.enableVideo(true);
|
|
98
|
+
await call.startScreenShare();
|
|
99
|
+
await call.stopScreenShare();
|
|
126
100
|
|
|
127
|
-
|
|
101
|
+
// Device selection
|
|
102
|
+
const cameras = await call.getAvailableVideoDevices();
|
|
103
|
+
await call.selectVideoDevice(cameras[0].deviceId);
|
|
128
104
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
call.join({
|
|
132
|
-
audioSettings: { publishAudio: true },
|
|
133
|
-
videoSettings: { publishVideo: false }
|
|
134
|
-
});
|
|
105
|
+
const mics = await call.getAvailableAudioDevices();
|
|
106
|
+
await call.selectAudioDevice(mics[0].deviceId);
|
|
135
107
|
|
|
136
|
-
//
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
participantIds: ['user1'],
|
|
140
|
-
videoCall: true,
|
|
141
|
-
});
|
|
142
|
-
result.data?.join({
|
|
143
|
-
audioSettings: { publishAudio: true },
|
|
144
|
-
videoSettings: { publishVideo: true },
|
|
145
|
-
});
|
|
108
|
+
// Participants
|
|
109
|
+
await call.addParticipants(['user3', 'user4']);
|
|
110
|
+
await call.switchToSFU(); // Upgrade P2P to SFU
|
|
146
111
|
```
|
|
147
112
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
| Field | Type | Description |
|
|
151
|
-
|-------|------|-------------|
|
|
152
|
-
| `audioSettings` | `AudioSettings` | Audio publish settings |
|
|
153
|
-
| `videoSettings` | `VideoSettings` | Video publish settings |
|
|
154
|
-
| `useMediaProxy` | `boolean` | Route media through proxy |
|
|
155
|
-
| `localAudioTracks` | `MediaStreamTrack[]` | Custom audio tracks |
|
|
156
|
-
| `localVideoTracks` | `MediaStreamTrack[]` | Custom video tracks |
|
|
157
|
-
|
|
158
|
-
### `AudioSettings`
|
|
113
|
+
## Error Handling
|
|
159
114
|
|
|
160
|
-
|
|
161
|
-
|-------|------|-------------|
|
|
162
|
-
| `publishAudio` | `boolean` | Publish audio on join. Default: `true` |
|
|
163
|
-
| `preferredAudioRoute` | `string \| null` | Preferred microphone device ID |
|
|
115
|
+
All methods return `CallClientResult<T>` with structured error information instead of throwing exceptions:
|
|
164
116
|
|
|
165
|
-
###
|
|
117
|
+
### Pattern 1: Check Result Success
|
|
166
118
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
119
|
+
```typescript
|
|
120
|
+
const result = await call.enableVideo(true);
|
|
121
|
+
if (!result.success) {
|
|
122
|
+
console.error('Error:', result.error?.message);
|
|
123
|
+
console.error('Code:', result.error?.code);
|
|
124
|
+
}
|
|
125
|
+
```
|
|
170
126
|
|
|
171
|
-
###
|
|
127
|
+
### Pattern 2: Use Error Callback
|
|
172
128
|
|
|
173
|
-
|
|
174
|
-
|-------|------|-------------|
|
|
175
|
-
| `mediaFlow` | `MediaFlow` | Media routing mode (required) |
|
|
176
|
-
| `participantIds` | `string[]` | User IDs to invite |
|
|
177
|
-
| `videoCall` | `boolean` | Whether this is a video call |
|
|
178
|
-
| `metadata` | `Record<string, string \| number>` | Custom metadata |
|
|
179
|
-
| `settings` | `CallSettings` | Scheduling and broadcast settings |
|
|
129
|
+
Some methods support optional error callbacks for real-time error feedback:
|
|
180
130
|
|
|
181
|
-
|
|
131
|
+
```typescript
|
|
132
|
+
const handleError = (result) => {
|
|
133
|
+
if (result.error) {
|
|
134
|
+
console.error(result.error.message, result.error.code);
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
// Synchronous methods — check return value
|
|
139
|
+
const prepareResult = callClient.prepareCall('call-123', { mediaFlow: MediaFlow.P2P });
|
|
140
|
+
if (!prepareResult.success) console.error(prepareResult.error?.message);
|
|
141
|
+
|
|
142
|
+
// Join — sync result + optional async signal error callback
|
|
143
|
+
const joinResult = call.join({ audioSettings: { publishAudio: true } }, handleError);
|
|
144
|
+
if (!joinResult.success) console.error(joinResult.error?.message);
|
|
145
|
+
|
|
146
|
+
// Create without joining — optional async signal error callback
|
|
147
|
+
call.create(handleError);
|
|
148
|
+
|
|
149
|
+
// Ringing notification — optional async signal error callback
|
|
150
|
+
call.sendRinging(handleError);
|
|
151
|
+
|
|
152
|
+
// Reject — optional async signal error callback
|
|
153
|
+
call.reject('busy', handleError);
|
|
154
|
+
|
|
155
|
+
// Async methods — await result + optional async signal error callback
|
|
156
|
+
const videoResult = await call.enableVideo(true, handleError);
|
|
157
|
+
await call.startScreenShare(handleError);
|
|
158
|
+
await call.stopScreenShare(handleError);
|
|
159
|
+
call.mute(true, handleError);
|
|
160
|
+
await call.switchToSFU(handleError);
|
|
161
|
+
```
|
|
182
162
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
163
|
+
**Methods Supporting Error Callbacks:**
|
|
164
|
+
- `callClient.prepareCall(callId, options?)` — check return value
|
|
165
|
+
- `call.join(options, errorCallback?)` — signal rejection delivered via callback
|
|
166
|
+
- `call.create(errorCallback?)` — server CREATE rejection delivered via callback
|
|
167
|
+
- `call.sendRinging(errorCallback?)` — signal error delivered via callback
|
|
168
|
+
- `call.reject(reason?, errorCallback?)` — signal error delivered via callback
|
|
169
|
+
- `call.enableVideo(enabled, errorCallback?)` — camera/signal errors via callback
|
|
170
|
+
- `call.startScreenShare(errorCallback?)` — screen share errors via callback
|
|
171
|
+
- `call.stopScreenShare(errorCallback?)` — signal errors via callback
|
|
172
|
+
- `call.mute(mute, errorCallback?)` — signal errors via callback
|
|
173
|
+
- `call.switchToSFU(errorCallback?)` — signal errors via callback
|
|
174
|
+
- `call.leave()` — no callback, check return value
|
|
175
|
+
|
|
176
|
+
**All Error Codes:**
|
|
177
|
+
|
|
178
|
+
| Code | Error Type | Cause | Solution |
|
|
179
|
+
|------|-----------|-------|----------|
|
|
180
|
+
| 4000 | `BadSignal` | Invalid signal format | Check signal parameters |
|
|
181
|
+
| 4001 | `CallNotFound` | Call not found in system | Verify call ID exists |
|
|
182
|
+
| 4002 | `ParticipantNotFound` | Participant not in call | Check participant exists |
|
|
183
|
+
| 4003 | `NotAllowed` | Operation not allowed in state | Verify call state |
|
|
184
|
+
| 4004 | `ParticipantAlreadyExists` | Participant already in call | Don't add duplicates |
|
|
185
|
+
| 4005 | `NotAllowed` | Permission denied by user | Enable in browser settings |
|
|
186
|
+
| 4006 | `BadRequest` | Invalid request parameters | Fix parameters |
|
|
187
|
+
| 5001 | `InternalError` | Server-side error | Retry (resendable) |
|
|
188
|
+
| 9901 | `NetworkError` | Network connectivity lost | Check connection (resendable) |
|
|
189
|
+
| 9902 | `Timeout` | Operation timed out | Retry (resendable) |
|
|
190
|
+
| 9903 | `NetworkError` | Network error occurred | Check connection (resendable) |
|
|
191
|
+
| 9904 | `NetworkError` | Network error occurred | Check connection (resendable) |
|
|
189
192
|
|
|
190
|
-
##
|
|
193
|
+
## Call Events
|
|
191
194
|
|
|
192
195
|
```typescript
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
196
|
+
call.on('audioTrackAdded', ({ participant, track }) => {
|
|
197
|
+
// Play participant's audio
|
|
198
|
+
const audio = new Audio();
|
|
199
|
+
audio.srcObject = new MediaStream([track]);
|
|
200
|
+
audio.play();
|
|
201
|
+
});
|
|
198
202
|
|
|
199
|
-
|
|
200
|
-
|
|
203
|
+
call.on('videoTrackAdded', ({ participant, track }) => {
|
|
204
|
+
// Display participant's video
|
|
205
|
+
videoElement.srcObject = new MediaStream([track]);
|
|
201
206
|
});
|
|
202
|
-
```
|
|
203
207
|
|
|
204
|
-
|
|
208
|
+
call.on('participantEvent', ({ participant, event }) => {
|
|
209
|
+
// event: 'Mute' | 'Unmute' | 'Hold' | 'VideoEnabled' | etc.
|
|
210
|
+
});
|
|
205
211
|
|
|
206
|
-
|
|
207
|
-
//
|
|
208
|
-
|
|
212
|
+
call.on('activeSpeakersChanged', ({ activeSpeakers }) => {
|
|
213
|
+
// Handle active speaker detection
|
|
214
|
+
});
|
|
209
215
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
216
|
+
call.on('sessionRenewed', ({ call, sessionId }) => {
|
|
217
|
+
// Fired when the server assigns a new sessionId to an existing call
|
|
218
|
+
});
|
|
213
219
|
```
|
|
214
220
|
|
|
215
|
-
##
|
|
221
|
+
## Client Events
|
|
216
222
|
|
|
217
223
|
```typescript
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
await call.startScreenShare();
|
|
222
|
-
await call.stopScreenShare();
|
|
223
|
-
call.addParticipants(['user3']);
|
|
224
|
-
await call.switchToSFU();
|
|
225
|
-
await call.selectVideoDevice(deviceId);
|
|
226
|
-
await call.selectAudioDevice(deviceId);
|
|
227
|
-
call.leave();
|
|
228
|
-
call.reject('busy');
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
## Call Properties
|
|
224
|
+
callClient.on('invitedToCall', ({ call }) => {
|
|
225
|
+
// Handle incoming call
|
|
226
|
+
});
|
|
232
227
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
call.mediaFlow; // Current media flow type
|
|
237
|
-
call.state; // Current CallState
|
|
238
|
-
call.participants; // All Participant objects
|
|
239
|
-
call.localParticipant; // The local user's Participant
|
|
240
|
-
call.activeSpeakers; // ActiveSpeakerInfo[] — currently speaking participants
|
|
241
|
-
call.settings; // CallSettings (startsAt, expiresAt, persistent, broadcastSettings)
|
|
228
|
+
callClient.on('ongoingCallsUpdated', ({ calls }) => {
|
|
229
|
+
// Handle call list updates
|
|
230
|
+
});
|
|
242
231
|
```
|
|
243
232
|
|
|
244
|
-
## Call
|
|
233
|
+
## Call Management
|
|
245
234
|
|
|
246
235
|
```typescript
|
|
247
|
-
call
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
// event: 'Mute' | 'Unmute' | 'Hold' | 'Unhold' | 'VideoEnabled' | 'VideoDisabled'
|
|
252
|
-
// | 'ScreenSharingStarted' | 'ScreenSharingStopped'
|
|
253
|
-
call.on('participantsAdded', ({ call, participants }) => {});
|
|
254
|
-
call.on('participantsRemoved', ({ call, participants }) => {});
|
|
255
|
-
call.on('audioTrackAdded', ({ call, participant, track }) => {});
|
|
256
|
-
call.on('audioTrackRemoved', ({ call, participant }) => {});
|
|
257
|
-
call.on('videoTrackAdded', ({ call, participant, track }) => {});
|
|
258
|
-
call.on('videoTrackRemoved', ({ call, participant }) => {});
|
|
259
|
-
call.on('activeSpeakersChanged', ({ call, activeSpeakers }) => {});
|
|
260
|
-
call.on('dominantSpeakerChanged', ({ call, dominantSpeaker }) => {});
|
|
261
|
-
call.on('mediaFlowChanged', ({ call, mediaFlow }) => {});
|
|
262
|
-
call.on('sessionRenewed', ({ call, sessionId }) => {
|
|
263
|
-
// Fired when the server assigns a new sessionId to the call
|
|
236
|
+
// Prepare a call (placed in prepareCalls, no media yet)
|
|
237
|
+
const result = callClient.prepareCall('call-123', {
|
|
238
|
+
mediaFlow: MediaFlow.SFU,
|
|
239
|
+
participantIds: ['user1'],
|
|
264
240
|
});
|
|
265
|
-
|
|
241
|
+
const call = result.data;
|
|
266
242
|
|
|
267
|
-
|
|
243
|
+
// Join — moves call from prepareCalls to activeCalls
|
|
244
|
+
call?.join({ audioSettings: { publishAudio: true } });
|
|
268
245
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
callClient.on('ongoingCallsUpdated', ({ calls }) => {});
|
|
272
|
-
```
|
|
246
|
+
// Create without joining (sends invites, stays in prepareCalls until server confirms)
|
|
247
|
+
call?.create((error) => console.error(error.error?.message));
|
|
273
248
|
|
|
274
|
-
|
|
249
|
+
// Accept an incoming call
|
|
250
|
+
callClient.on('invitedToCall', ({ call }) => {
|
|
251
|
+
call.join({ audioSettings: { publishAudio: true } });
|
|
252
|
+
});
|
|
275
253
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
254
|
+
// Reject / leave
|
|
255
|
+
call?.reject('busy');
|
|
256
|
+
call?.leave();
|
|
279
257
|
|
|
280
|
-
// Calls
|
|
281
|
-
callClient.
|
|
258
|
+
// Calls prepared but not yet joined
|
|
259
|
+
const pendingCalls = callClient.prepareCalls;
|
|
282
260
|
|
|
283
|
-
//
|
|
284
|
-
const
|
|
261
|
+
// Calls actively joined
|
|
262
|
+
const activeCalls = callClient.activeCalls;
|
|
285
263
|
|
|
286
|
-
//
|
|
287
|
-
|
|
264
|
+
// Active speakers on a call (updated via 'activeSpeakersChanged' event)
|
|
265
|
+
const speakers = call?.activeSpeakers;
|
|
266
|
+
|
|
267
|
+
// Fetch a call by ID (local first, then server)
|
|
268
|
+
const { data } = await callClient.getCall('call-id');
|
|
288
269
|
```
|
|
289
270
|
|
|
290
271
|
## Call History (CDR)
|
|
@@ -297,59 +278,50 @@ const query = new callClient.RecentCallQueryBuilder()
|
|
|
297
278
|
.limit(20)
|
|
298
279
|
.build();
|
|
299
280
|
|
|
300
|
-
const { records } = await query.loadNextPage();
|
|
301
|
-
```
|
|
302
|
-
|
|
303
|
-
## Error Handling
|
|
304
|
-
|
|
305
|
-
All methods return `CallClientResult<T>`:
|
|
281
|
+
const { records, hasNext } = await query.loadNextPage();
|
|
306
282
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
console.
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
// Optional error callback for async signal errors (create/join)
|
|
314
|
-
result.data?.create((result) => {
|
|
315
|
-
console.error(result.error?.message);
|
|
283
|
+
records.forEach(record => {
|
|
284
|
+
console.log(`Call: ${record.callId}`);
|
|
285
|
+
console.log(`Duration: ${record.endedAt - record.startedAt}ms`);
|
|
286
|
+
console.log(`Participants: ${record.participants.length}`);
|
|
316
287
|
});
|
|
317
288
|
```
|
|
318
289
|
|
|
290
|
+
## Participant States
|
|
291
|
+
|
|
292
|
+
| State | Description |
|
|
293
|
+
|-------|-------------|
|
|
294
|
+
| `Idle` | Not actively participating |
|
|
295
|
+
| `Ringing` | Device is ringing |
|
|
296
|
+
| `Joined` | In the call |
|
|
297
|
+
| `Left` | Left the call |
|
|
298
|
+
| `Declined` | Declined invitation |
|
|
299
|
+
| `Kicked` | Removed by another user |
|
|
300
|
+
| `NoAnswer` | Did not answer |
|
|
301
|
+
|
|
319
302
|
## Logging
|
|
320
303
|
|
|
321
304
|
```typescript
|
|
322
|
-
|
|
305
|
+
callClient.onLog((entry) => {
|
|
323
306
|
console.log(`[${entry.level}] ${entry.prefix}: ${entry.message}`);
|
|
324
307
|
});
|
|
325
|
-
unsubscribe();
|
|
326
308
|
```
|
|
327
309
|
|
|
328
310
|
## TypeScript Support
|
|
329
311
|
|
|
312
|
+
Full TypeScript support with exported types:
|
|
313
|
+
|
|
330
314
|
```typescript
|
|
331
315
|
import type {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
VideoSettings,
|
|
336
|
-
CallSettings,
|
|
337
|
-
BroadcastSettings,
|
|
338
|
-
CallClientResult,
|
|
316
|
+
Call,
|
|
317
|
+
Participant,
|
|
318
|
+
IJoinCallOptions,
|
|
339
319
|
CallEventMap,
|
|
340
320
|
CallClientEventMap,
|
|
341
321
|
ICallDetailRecord,
|
|
342
|
-
ICDRParticipant,
|
|
343
|
-
Unsubscribe,
|
|
344
|
-
} from 'sceyt-call';
|
|
345
|
-
|
|
346
|
-
import {
|
|
347
|
-
MediaFlow,
|
|
348
|
-
CallState,
|
|
349
322
|
ParticipantState,
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
CDRRequestOrder,
|
|
323
|
+
CallState,
|
|
324
|
+
MediaFlow
|
|
353
325
|
} from 'sceyt-call';
|
|
354
326
|
```
|
|
355
327
|
|