vg-x07df 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/.azure-pipelines/publish-public.yml +37 -0
  2. package/.azure-pipelines/publish.yml +39 -0
  3. package/.changeset/README.md +8 -0
  4. package/.changeset/config.json +11 -0
  5. package/AUTO_JOIN_GUIDE.md +411 -0
  6. package/README.md +215 -0
  7. package/Screenshot 2025-09-24 at 14.34.48.png +0 -0
  8. package/Screenshot 2025-10-04 at 12.58.54.png +0 -0
  9. package/biome.json +48 -0
  10. package/examples/demo/.env.example +19 -0
  11. package/examples/demo/CHANGELOG.md +22 -0
  12. package/examples/demo/README.md +72 -0
  13. package/examples/demo/eslint.config.js +23 -0
  14. package/examples/demo/index.html +13 -0
  15. package/examples/demo/package.json +34 -0
  16. package/examples/demo/pnpm-lock.yaml +2098 -0
  17. package/examples/demo/pnpm-workspace.yaml +1 -0
  18. package/examples/demo/public/vite.svg +1 -0
  19. package/examples/demo/src/App.css +52 -0
  20. package/examples/demo/src/App.tsx +176 -0
  21. package/examples/demo/src/assets/react.svg +1 -0
  22. package/examples/demo/src/components/auth/LoginForm.css +144 -0
  23. package/examples/demo/src/components/auth/LoginForm.tsx +80 -0
  24. package/examples/demo/src/components/calling/AutoJoinSettings.tsx +213 -0
  25. package/examples/demo/src/components/calling/AutoJoinStatus.tsx +72 -0
  26. package/examples/demo/src/components/calling/CallInitiator.css +258 -0
  27. package/examples/demo/src/components/calling/CallInitiator.tsx +142 -0
  28. package/examples/demo/src/components/calling/CallNotifications.css +119 -0
  29. package/examples/demo/src/components/calling/CallNotifications.tsx +108 -0
  30. package/examples/demo/src/components/calling/IncomingCallModal.css +192 -0
  31. package/examples/demo/src/components/calling/IncomingCallModal.tsx +78 -0
  32. package/examples/demo/src/components/calling/MinimizedCall.css +156 -0
  33. package/examples/demo/src/components/calling/MinimizedCall.tsx +78 -0
  34. package/examples/demo/src/components/conference/ConferenceHeader.css +265 -0
  35. package/examples/demo/src/components/conference/ConferenceHeader.tsx +78 -0
  36. package/examples/demo/src/components/conference/EnhancedControlBar.css +356 -0
  37. package/examples/demo/src/components/conference/EnhancedControlBar.tsx +262 -0
  38. package/examples/demo/src/components/conference/PaginationControls.css +67 -0
  39. package/examples/demo/src/components/conference/PaginationControls.tsx +64 -0
  40. package/examples/demo/src/components/conference/ParticipantGrid.css +153 -0
  41. package/examples/demo/src/components/conference/ParticipantGrid.tsx +87 -0
  42. package/examples/demo/src/components/conference/ParticipantTile.css +210 -0
  43. package/examples/demo/src/components/conference/ParticipantTile.tsx +114 -0
  44. package/examples/demo/src/components/conference/VideoConference.css +214 -0
  45. package/examples/demo/src/components/conference/VideoConference.tsx +93 -0
  46. package/examples/demo/src/contexts/AuthContext.tsx +105 -0
  47. package/examples/demo/src/hooks/useAuth.ts +5 -0
  48. package/examples/demo/src/hooks/useCallTimer.ts +42 -0
  49. package/examples/demo/src/index.css +68 -0
  50. package/examples/demo/src/main.tsx +10 -0
  51. package/examples/demo/src/services/auth.service.ts +153 -0
  52. package/examples/demo/src/types/auth.types.ts +31 -0
  53. package/examples/demo/tsconfig.app.json +28 -0
  54. package/examples/demo/tsconfig.json +7 -0
  55. package/examples/demo/tsconfig.node.json +26 -0
  56. package/examples/demo/vite.config.ts +15 -0
  57. package/images/callpad-without-ai.png +0 -0
  58. package/package.json +28 -0
  59. package/packages/sdk/CHANGELOG.md +33 -0
  60. package/packages/sdk/LICENSE +21 -0
  61. package/packages/sdk/README.md +97 -0
  62. package/packages/sdk/documentation.md +1132 -0
  63. package/packages/sdk/openapi-ts.config.ts +7 -0
  64. package/packages/sdk/package.json +88 -0
  65. package/packages/sdk/src/core/auth.manager.ts +52 -0
  66. package/packages/sdk/src/core/events/event-bus.ts +301 -0
  67. package/packages/sdk/src/core/events/index.ts +8 -0
  68. package/packages/sdk/src/core/events/types.ts +165 -0
  69. package/packages/sdk/src/core/index.ts +3 -0
  70. package/packages/sdk/src/core/signal/api.config.ts +49 -0
  71. package/packages/sdk/src/core/signal/index.ts +16 -0
  72. package/packages/sdk/src/core/signal/signal.client.ts +101 -0
  73. package/packages/sdk/src/core/signal/types.ts +110 -0
  74. package/packages/sdk/src/core/socketio/handlers/base.handler.ts +212 -0
  75. package/packages/sdk/src/core/socketio/handlers/call-accepted.handler.ts +34 -0
  76. package/packages/sdk/src/core/socketio/handlers/call-canceled.handler.ts +34 -0
  77. package/packages/sdk/src/core/socketio/handlers/call-declined.handler.ts +29 -0
  78. package/packages/sdk/src/core/socketio/handlers/call-ended.handler.ts +40 -0
  79. package/packages/sdk/src/core/socketio/handlers/call-incoming.handler.ts +72 -0
  80. package/packages/sdk/src/core/socketio/handlers/call-join-info.handler.ts +181 -0
  81. package/packages/sdk/src/core/socketio/handlers/call-participant-joined.handler.ts +42 -0
  82. package/packages/sdk/src/core/socketio/handlers/call-participant-joining.handler.ts +42 -0
  83. package/packages/sdk/src/core/socketio/handlers/call-timeout.handler.ts +31 -0
  84. package/packages/sdk/src/core/socketio/handlers/handler.registry.ts +62 -0
  85. package/packages/sdk/src/core/socketio/handlers/index.ts +21 -0
  86. package/packages/sdk/src/core/socketio/handlers/participant-left.handler.ts +37 -0
  87. package/packages/sdk/src/core/socketio/handlers/schema.ts +130 -0
  88. package/packages/sdk/src/core/socketio/index.ts +5 -0
  89. package/packages/sdk/src/core/socketio/socket.manager.ts +187 -0
  90. package/packages/sdk/src/core/socketio/types.ts +14 -0
  91. package/packages/sdk/src/core/types.ts +23 -0
  92. package/packages/sdk/src/generated/api/core/ApiError.ts +21 -0
  93. package/packages/sdk/src/generated/api/core/ApiRequestOptions.ts +13 -0
  94. package/packages/sdk/src/generated/api/core/ApiResult.ts +7 -0
  95. package/packages/sdk/src/generated/api/core/CancelablePromise.ts +126 -0
  96. package/packages/sdk/src/generated/api/core/OpenAPI.ts +55 -0
  97. package/packages/sdk/src/generated/api/core/request.ts +339 -0
  98. package/packages/sdk/src/generated/api/index.ts +5 -0
  99. package/packages/sdk/src/generated/api/models.ts +219 -0
  100. package/packages/sdk/src/generated/api/services.ts +225 -0
  101. package/packages/sdk/src/hooks/index.ts +21 -0
  102. package/packages/sdk/src/hooks/useAutoJoin.ts +66 -0
  103. package/packages/sdk/src/hooks/useCallActions.ts +28 -0
  104. package/packages/sdk/src/hooks/useCallQuality.ts +416 -0
  105. package/packages/sdk/src/hooks/useCallState.ts +23 -0
  106. package/packages/sdk/src/hooks/useConnection.ts +15 -0
  107. package/packages/sdk/src/hooks/useDevices.ts +296 -0
  108. package/packages/sdk/src/hooks/useErrorRecovery.ts +299 -0
  109. package/packages/sdk/src/hooks/useErrors.ts +84 -0
  110. package/packages/sdk/src/hooks/useEvent.ts +188 -0
  111. package/packages/sdk/src/hooks/useMediaControls.ts +215 -0
  112. package/packages/sdk/src/hooks/useParticipantStatus.ts +318 -0
  113. package/packages/sdk/src/hooks/useParticipants.ts +111 -0
  114. package/packages/sdk/src/index.ts +66 -0
  115. package/packages/sdk/src/livekit/constants.ts +76 -0
  116. package/packages/sdk/src/livekit/device.manager.ts +172 -0
  117. package/packages/sdk/src/livekit/error-classifier.ts +155 -0
  118. package/packages/sdk/src/livekit/events/eventBridge.ts +371 -0
  119. package/packages/sdk/src/livekit/events/trackRegistry.ts +114 -0
  120. package/packages/sdk/src/livekit/index.ts +49 -0
  121. package/packages/sdk/src/livekit/livekit.service.ts +110 -0
  122. package/packages/sdk/src/livekit/media.controls.ts +315 -0
  123. package/packages/sdk/src/livekit/room.manager.ts +79 -0
  124. package/packages/sdk/src/livekit/track.utils.ts +230 -0
  125. package/packages/sdk/src/livekit/types.ts +135 -0
  126. package/packages/sdk/src/provider/RtcProvider.tsx +78 -0
  127. package/packages/sdk/src/services/call-actions.ts +260 -0
  128. package/packages/sdk/src/services/error-recovery.ts +461 -0
  129. package/packages/sdk/src/services/index.ts +2 -0
  130. package/packages/sdk/src/services/sdk-builder.ts +104 -0
  131. package/packages/sdk/src/state/errors.ts +163 -0
  132. package/packages/sdk/src/state/selectors.ts +28 -0
  133. package/packages/sdk/src/state/store.ts +36 -0
  134. package/packages/sdk/src/state/types.ts +151 -0
  135. package/packages/sdk/src/utils/logger.ts +183 -0
  136. package/packages/sdk/tsconfig.json +49 -0
  137. package/packages/sdk/tsup.config.ts +51 -0
  138. package/pnpm-workspace.yaml +4 -0
  139. package/tsconfig.base.json +19 -0
  140. package/turbo.json +34 -0
@@ -0,0 +1,1132 @@
1
+ # CallPad SDK Documentation
2
+
3
+ A production-ready headless SDK for CallPad audio/video calls built on React, LiveKit, and Socket.IO.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Installation](#installation)
8
+ - [Quick Start](#quick-start)
9
+ - [RTC Provider Configuration](#rtc-provider-configuration)
10
+ - [Core Concepts](#core-concepts)
11
+ - [Call Management](#call-management)
12
+ - [Intercepting Incoming Calls](#intercepting-incoming-calls)
13
+ - [Initiating Calls](#initiating-calls)
14
+ - [Accepting and Declining Calls](#accepting-and-declining-calls)
15
+ - [Managing Call State](#managing-call-state)
16
+ - [Hooks Reference](#hooks-reference)
17
+ - [Event System](#event-system)
18
+ - [Media Controls](#media-controls)
19
+ - [Participant Management](#participant-management)
20
+ - [Auto-Join Configuration](#auto-join-configuration)
21
+ - [Error Handling](#error-handling)
22
+ - [TypeScript Support](#typescript-support)
23
+ - [Advanced Usage](#advanced-usage)
24
+ - [Examples](#examples)
25
+
26
+ ## Installation
27
+
28
+ Install the SDK using pnpm (recommended):
29
+
30
+ ```bash
31
+ pnpm add vg-x07df
32
+ ```
33
+
34
+ Or using npm:
35
+
36
+ ```bash
37
+ npm install vg-x07df
38
+ ```
39
+
40
+ ### Peer Dependencies
41
+
42
+ The SDK requires the following peer dependencies:
43
+
44
+ ```bash
45
+ pnpm add react@>=18 react-dom@>=18 livekit-client@^2.8.0 socket.io-client@^4.7.0
46
+ ```
47
+
48
+ ## Quick Start
49
+
50
+ ### 1. Setup the RTC Provider
51
+
52
+ Wrap your application with the `RtcProvider` to enable CallPad functionality:
53
+
54
+ ```tsx
55
+ import React from 'react';
56
+ import { RtcProvider } from 'vg-x07df';
57
+
58
+ const rtcOptions = {
59
+ appId: 'your-app-id',
60
+ signalHost: 'https://your-signal-server.com',
61
+ authProvider: () => {
62
+ // Return your authentication token
63
+ return localStorage.getItem('auth-token');
64
+ },
65
+ logLevel: 'info',
66
+ enableDebug: false,
67
+ };
68
+
69
+ function App() {
70
+ return (
71
+ <RtcProvider options={rtcOptions}>
72
+ <YourAppComponents />
73
+ </RtcProvider>
74
+ );
75
+ }
76
+ ```
77
+
78
+ ### 2. Use Basic Hooks
79
+
80
+ ```tsx
81
+ import { useCallState, useCallActions } from 'vg-x07df';
82
+
83
+ function CallComponent() {
84
+ const callState = useCallState();
85
+ const { initiate, accept, decline } = useCallActions();
86
+
87
+ const handleInitiateCall = () => {
88
+ initiate(['user-id-1', 'user-id-2'], 'VIDEO');
89
+ };
90
+
91
+ return (
92
+ <div>
93
+ <p>Call Status: {callState.status}</p>
94
+ <button onClick={handleInitiateCall}>Start Video Call</button>
95
+ </div>
96
+ );
97
+ }
98
+ ```
99
+
100
+ ## RTC Provider Configuration
101
+
102
+ The `RtcProvider` accepts an `options` prop with the following configuration:
103
+
104
+ ### Required Options
105
+
106
+ ```tsx
107
+ interface RtcOptions {
108
+ appId: string; // Your application identifier
109
+ signalHost: string; // Signal server URL
110
+ authProvider: () => string | null; // Token provider function
111
+ }
112
+ ```
113
+
114
+ ### Optional Configuration
115
+
116
+ ```tsx
117
+ interface RtcOptions {
118
+ // Logging configuration
119
+ logLevel?: 'debug' | 'info' | 'warn' | 'error';
120
+ enableDebug?: boolean;
121
+ log?: (level: string, message: string, meta?: any) => void;
122
+
123
+ // Auto-join configuration
124
+ autoJoin?: Partial<AutoJoinConfig>;
125
+ }
126
+ ```
127
+
128
+ ### Auto-Join Configuration
129
+
130
+ ```tsx
131
+ interface AutoJoinConfig {
132
+ enabled: boolean; // Enable auto-join (default: true)
133
+ retryOnFailure: boolean; // Retry on connection failure (default: true)
134
+ maxRetries: number; // Maximum retry attempts (default: 2)
135
+ }
136
+ ```
137
+
138
+ ### Complete Configuration Example
139
+
140
+ ```tsx
141
+ const rtcOptions = {
142
+ appId: 'callpad-app',
143
+ signalHost: 'https://signal.example.com',
144
+ authProvider: () => authService.getToken(),
145
+
146
+ // Logging
147
+ logLevel: 'debug',
148
+ enableDebug: true,
149
+ log: (level, message, meta) => {
150
+ console.log(`[${level.toUpperCase()}] ${message}`, meta);
151
+ },
152
+
153
+ // Auto-join
154
+ autoJoin: {
155
+ enabled: true,
156
+ retryOnFailure: true,
157
+ maxRetries: 3,
158
+ },
159
+ };
160
+ ```
161
+
162
+ ## Core Concepts
163
+
164
+ ### Session Status
165
+
166
+ The SDK tracks call sessions through various states:
167
+
168
+ - `IDLE` - No active call
169
+ - `CALLING` - Outgoing call initiated, waiting for response
170
+ - `RINGING` - Incoming call received
171
+ - `ACCEPTED` - Call accepted but not yet connected to media
172
+ - `AWAITING_JOIN_INFO` - Waiting for LiveKit connection details
173
+ - `READY_TO_JOIN` - Ready to connect to media session
174
+ - `CONNECTING` - Joining LiveKit room
175
+ - `ACTIVE` - Successfully connected to media session
176
+ - `ENDED` - Call completed
177
+
178
+ ### Participants
179
+
180
+ Participants represent users in a call with the following properties:
181
+
182
+ ```tsx
183
+ interface Participant {
184
+ id: string;
185
+ firstName?: string;
186
+ lastName?: string;
187
+ avatarUrl?: string;
188
+ role: "CALLER" | "CALLEE" | "HOST" | "MEMBER";
189
+ callState: "INVITED" | "RINGING" | "JOINED" | "LEFT";
190
+ audioEnabled: boolean;
191
+ videoEnabled: boolean;
192
+ isSpeaking: boolean;
193
+ connectionQuality?: "excellent" | "good" | "poor" | "lost" | "unknown";
194
+ invitedAt?: number;
195
+ joinedAt?: number;
196
+ leftAt?: number;
197
+ }
198
+ ```
199
+
200
+ ## Call Management
201
+
202
+ ### Intercepting Incoming Calls
203
+
204
+ Use the `useCallState` hook to detect incoming calls:
205
+
206
+ ```tsx
207
+ import { useCallState, useCallActions } from 'vg-x07df';
208
+
209
+ function IncomingCallHandler() {
210
+ const { incomingCall, status } = useCallState();
211
+ const { accept, decline } = useCallActions();
212
+
213
+ if (status === 'RINGING' && incomingCall) {
214
+ return (
215
+ <div className="incoming-call-modal">
216
+ <h3>Incoming {incomingCall.type} call</h3>
217
+ <p>From: {incomingCall.caller.name}</p>
218
+
219
+ <button onClick={() => accept(incomingCall.callId)}>
220
+ Accept
221
+ </button>
222
+ <button onClick={() => decline(incomingCall.callId)}>
223
+ Decline
224
+ </button>
225
+ </div>
226
+ );
227
+ }
228
+
229
+ return null;
230
+ }
231
+ ```
232
+
233
+ ### Advanced Incoming Call Handling
234
+
235
+ Use event hooks for more sophisticated incoming call management:
236
+
237
+ ```tsx
238
+ import { useEvent, SdkEventType } from 'vg-x07df';
239
+
240
+ function AdvancedIncomingCallHandler() {
241
+ useEvent(SdkEventType.CALL_INCOMING, (event) => {
242
+ const { callId, caller, type } = event.payload;
243
+
244
+ // Show custom notification
245
+ showNotification({
246
+ title: `Incoming ${type} call`,
247
+ body: `${caller.firstName} ${caller.lastName} is calling`,
248
+ actions: [
249
+ { action: 'accept', title: 'Accept' },
250
+ { action: 'decline', title: 'Decline' }
251
+ ]
252
+ });
253
+ });
254
+
255
+ return <div>Listening for incoming calls...</div>;
256
+ }
257
+ ```
258
+
259
+ ### Initiating Calls
260
+
261
+ Use the `useCallActions` hook to start calls:
262
+
263
+ ```tsx
264
+ function CallInitiator() {
265
+ const { initiate } = useCallActions();
266
+ const [participants, setParticipants] = useState(['']);
267
+
268
+ const handleVideoCall = async () => {
269
+ try {
270
+ const response = await initiate(participants, 'VIDEO');
271
+ console.log('Call initiated:', response);
272
+ } catch (error) {
273
+ console.error('Failed to initiate call:', error);
274
+ }
275
+ };
276
+
277
+ const handleAudioCall = async () => {
278
+ try {
279
+ const response = await initiate(participants, 'AUDIO');
280
+ console.log('Call initiated:', response);
281
+ } catch (error) {
282
+ console.error('Failed to initiate call:', error);
283
+ }
284
+ };
285
+
286
+ return (
287
+ <div>
288
+ <input
289
+ value={participants[0]}
290
+ onChange={(e) => setParticipants([e.target.value])}
291
+ placeholder="User ID to call"
292
+ />
293
+ <button onClick={handleVideoCall}>Video Call</button>
294
+ <button onClick={handleAudioCall}>Audio Call</button>
295
+ </div>
296
+ );
297
+ }
298
+ ```
299
+
300
+ ### Accepting and Declining Calls
301
+
302
+ ```tsx
303
+ function CallResponseHandler() {
304
+ const { accept, decline } = useCallActions();
305
+ const { incomingCall } = useCallState();
306
+
307
+ const handleAccept = async () => {
308
+ if (incomingCall) {
309
+ try {
310
+ await accept(incomingCall.callId);
311
+ } catch (error) {
312
+ console.error('Failed to accept call:', error);
313
+ }
314
+ }
315
+ };
316
+
317
+ const handleDecline = async () => {
318
+ if (incomingCall) {
319
+ try {
320
+ await decline(incomingCall.callId);
321
+ } catch (error) {
322
+ console.error('Failed to decline call:', error);
323
+ }
324
+ }
325
+ };
326
+
327
+ return (
328
+ <div>
329
+ <button onClick={handleAccept}>Accept Call</button>
330
+ <button onClick={handleDecline}>Decline Call</button>
331
+ </div>
332
+ );
333
+ }
334
+ ```
335
+
336
+ ### Managing Call State
337
+
338
+ Monitor and respond to call state changes:
339
+
340
+ ```tsx
341
+ function CallStateManager() {
342
+ const callState = useCallState();
343
+
344
+ useEffect(() => {
345
+ switch (callState.status) {
346
+ case 'CALLING':
347
+ console.log('Outgoing call initiated');
348
+ break;
349
+ case 'RINGING':
350
+ console.log('Incoming call received');
351
+ break;
352
+ case 'ACTIVE':
353
+ console.log('Call is now active');
354
+ break;
355
+ case 'ENDED':
356
+ console.log('Call has ended');
357
+ break;
358
+ }
359
+ }, [callState.status]);
360
+
361
+ return (
362
+ <div>
363
+ <h3>Call Information</h3>
364
+ <p>Status: {callState.status}</p>
365
+ <p>Mode: {callState.mode || 'None'}</p>
366
+ <p>Room: {callState.roomName || 'None'}</p>
367
+ {callState.id && <p>Call ID: {callState.id}</p>}
368
+ </div>
369
+ );
370
+ }
371
+ ```
372
+
373
+ ## Hooks Reference
374
+
375
+ ### Call Management Hooks
376
+
377
+ #### `useCallState()`
378
+
379
+ Returns current call state information:
380
+
381
+ ```tsx
382
+ interface CallState {
383
+ id: string | undefined;
384
+ status: SessionStatus;
385
+ mode: "AUDIO" | "VIDEO" | undefined;
386
+ roomName: string | undefined;
387
+ incomingCall: IncomingCallInfo | undefined;
388
+ }
389
+
390
+ const callState = useCallState();
391
+ ```
392
+
393
+ #### `useCallActions()`
394
+
395
+ Provides call action functions:
396
+
397
+ ```tsx
398
+ interface CallActions {
399
+ initiate: (participants: string[], type: "AUDIO" | "VIDEO") => Promise<CallResponse>;
400
+ accept: (callId: string) => Promise<CallActionResponse>;
401
+ decline: (callId: string) => Promise<CallActionResponse>;
402
+ end: (callId: string) => Promise<CallActionResponse>;
403
+ cancel: (callId: string) => Promise<CallActionResponse>;
404
+ join: () => Promise<void>;
405
+ }
406
+
407
+ const actions = useCallActions();
408
+ ```
409
+
410
+ #### `useCallQuality()`
411
+
412
+ Monitor call quality metrics:
413
+
414
+ ```tsx
415
+ const quality = useCallQuality();
416
+ // Returns quality information and metrics
417
+ ```
418
+
419
+ ### Media Control Hooks
420
+
421
+ #### `useMediaControls()`
422
+
423
+ Comprehensive media control interface:
424
+
425
+ ```tsx
426
+ const {
427
+ // State
428
+ isVideoEnabled,
429
+ isAudioEnabled,
430
+ isCameraAvailable,
431
+ isMicrophoneAvailable,
432
+ isConnected,
433
+ isLoading,
434
+ errors,
435
+ devices,
436
+
437
+ // Actions
438
+ enableCamera,
439
+ disableCamera,
440
+ enableMicrophone,
441
+ disableMicrophone,
442
+ toggleCamera,
443
+ toggleMicrophone,
444
+ toggleAudio,
445
+ toggleVideo,
446
+ switchCamera,
447
+ switchMicrophone
448
+ } = useMediaControls();
449
+ ```
450
+
451
+ #### `useDevices()`
452
+
453
+ Access and manage media devices:
454
+
455
+ ```tsx
456
+ const devices = useDevices();
457
+ // Returns cameras, microphones, speakers, and permissions
458
+ ```
459
+
460
+ ### Event System Hooks
461
+
462
+ #### `useEvent(eventType, callback?, filter?)`
463
+
464
+ Subscribe to specific SDK events:
465
+
466
+ ```tsx
467
+ // Listen for specific event
468
+ const callEvent = useEvent(SdkEventType.CALL_ACCEPTED);
469
+
470
+ // Listen with callback
471
+ useEvent(SdkEventType.MEDIA_ENABLED, (event) => {
472
+ console.log('Media enabled:', event.payload);
473
+ });
474
+
475
+ // Listen with filter
476
+ useEvent('call:*', null, (event) =>
477
+ event.payload.callId === 'specific-call'
478
+ );
479
+ ```
480
+
481
+ #### `useCallEvents(callId?)`
482
+
483
+ Subscribe to call-specific events:
484
+
485
+ ```tsx
486
+ const {
487
+ callAccepted,
488
+ callDeclined,
489
+ callEnded,
490
+ participantJoined,
491
+ participantLeft
492
+ } = useCallEvents(callId);
493
+ ```
494
+
495
+ #### `useMediaEvents(participantId?)`
496
+
497
+ Subscribe to media events for a specific participant:
498
+
499
+ ```tsx
500
+ const { mediaEnabled, mediaDisabled } = useMediaEvents(participantId);
501
+ ```
502
+
503
+ ### Participant Hooks
504
+
505
+ #### `useParticipants()`
506
+
507
+ Get all call participants:
508
+
509
+ ```tsx
510
+ const participants = useParticipants();
511
+ // Returns array of Participant objects
512
+ ```
513
+
514
+ #### `useParticipantStatus(participantId)`
515
+
516
+ Get status for a specific participant:
517
+
518
+ ```tsx
519
+ const status = useParticipantStatus('user-123');
520
+ ```
521
+
522
+ ### Auto-Join Hooks
523
+
524
+ #### `useAutoJoin()`
525
+
526
+ Access auto-join configuration:
527
+
528
+ ```tsx
529
+ const {
530
+ config,
531
+ isEnabled,
532
+ retryOnFailure,
533
+ maxRetries
534
+ } = useAutoJoin();
535
+ ```
536
+
537
+ ### Error Handling Hooks
538
+
539
+ #### `useErrorRecovery()`
540
+
541
+ Access error recovery functionality:
542
+
543
+ ```tsx
544
+ const recovery = useErrorRecovery();
545
+ ```
546
+
547
+ #### `useErrors()`
548
+
549
+ Get current error state:
550
+
551
+ ```tsx
552
+ const errors = useErrors();
553
+ const connectionErrors = useErrorsByCode('CONNECTION_');
554
+ const errorCount = useErrorCount();
555
+ ```
556
+
557
+ ## Event System
558
+
559
+ The SDK provides a comprehensive event system for real-time communication updates.
560
+
561
+ ### Event Types
562
+
563
+ ```tsx
564
+ enum SdkEventType {
565
+ // Call lifecycle
566
+ CALL_INITIATED = "call:initiated",
567
+ CALL_INCOMING = "call:incoming",
568
+ CALL_ACCEPTED = "call:accepted",
569
+ CALL_DECLINED = "call:declined",
570
+ CALL_ENDED = "call:ended",
571
+ CALL_CANCELED = "call:canceled",
572
+ CALL_TIMEOUT = "call:timeout",
573
+
574
+ // Participants
575
+ PARTICIPANT_JOINED = "participant:joined",
576
+ PARTICIPANT_LEFT = "participant:left",
577
+
578
+ // Media
579
+ MEDIA_ENABLED = "media:enabled",
580
+ MEDIA_DISABLED = "media:disabled",
581
+
582
+ // Connection
583
+ CONNECTION_ESTABLISHED = "connection:established",
584
+ CONNECTION_LOST = "connection:lost",
585
+ CONNECTION_QUALITY_CHANGED = "connection:quality-changed",
586
+
587
+ // Errors
588
+ ERROR_OCCURRED = "error:occurred",
589
+ }
590
+ ```
591
+
592
+ ### Event Usage Examples
593
+
594
+ ```tsx
595
+ // Single event listener
596
+ useEvent(SdkEventType.CALL_ACCEPTED, (event) => {
597
+ console.log('Call accepted:', event.payload);
598
+ });
599
+
600
+ // Pattern matching
601
+ useEvent('call:*', (event) => {
602
+ console.log('Any call event:', event.type, event.payload);
603
+ });
604
+
605
+ // Event with filter
606
+ useEvent(
607
+ SdkEventType.PARTICIPANT_JOINED,
608
+ (event) => {
609
+ console.log('New participant:', event.payload.participant);
610
+ },
611
+ (event) => event.payload.callId === currentCallId
612
+ );
613
+
614
+ // One-time event listener
615
+ useEventOnce(SdkEventType.CALL_ENDED, (event) => {
616
+ console.log('Call ended, cleaning up...');
617
+ });
618
+ ```
619
+
620
+ ### Direct Event Bus Access
621
+
622
+ ```tsx
623
+ const eventBus = useEventBus();
624
+
625
+ // Emit custom event
626
+ eventBus.emit('custom:event', { data: 'test' });
627
+
628
+ // Get event history
629
+ const history = eventBus.getEventHistory();
630
+
631
+ // Get filtered events
632
+ const callEvents = eventBus.getEventsWhere(
633
+ (event) => event.type.startsWith('call:')
634
+ );
635
+ ```
636
+
637
+ ## Media Controls
638
+
639
+ ### Basic Media Controls
640
+
641
+ ```tsx
642
+ function MediaControlPanel() {
643
+ const {
644
+ isVideoEnabled,
645
+ isAudioEnabled,
646
+ toggleVideo,
647
+ toggleAudio,
648
+ devices
649
+ } = useMediaControls();
650
+
651
+ return (
652
+ <div>
653
+ <button
654
+ onClick={toggleVideo}
655
+ className={isVideoEnabled ? 'enabled' : 'disabled'}
656
+ >
657
+ {isVideoEnabled ? 'Disable Video' : 'Enable Video'}
658
+ </button>
659
+
660
+ <button
661
+ onClick={toggleAudio}
662
+ className={isAudioEnabled ? 'enabled' : 'disabled'}
663
+ >
664
+ {isAudioEnabled ? 'Disable Audio' : 'Enable Audio'}
665
+ </button>
666
+ </div>
667
+ );
668
+ }
669
+ ```
670
+
671
+ ### Device Management
672
+
673
+ ```tsx
674
+ function DeviceSelector() {
675
+ const { devices, switchCamera, switchMicrophone } = useMediaControls();
676
+
677
+ return (
678
+ <div>
679
+ <select onChange={(e) => switchCamera(e.target.value)}>
680
+ <option value="">Select Camera</option>
681
+ {devices.cameras.map(camera => (
682
+ <option key={camera.deviceId} value={camera.deviceId}>
683
+ {camera.label}
684
+ </option>
685
+ ))}
686
+ </select>
687
+
688
+ <select onChange={(e) => switchMicrophone(e.target.value)}>
689
+ <option value="">Select Microphone</option>
690
+ {devices.microphones.map(mic => (
691
+ <option key={mic.deviceId} value={mic.deviceId}>
692
+ {mic.label}
693
+ </option>
694
+ ))}
695
+ </select>
696
+ </div>
697
+ );
698
+ }
699
+ ```
700
+
701
+ ### Advanced Media Controls
702
+
703
+ ```tsx
704
+ function AdvancedMediaControls() {
705
+ const {
706
+ enableCamera,
707
+ disableCamera,
708
+ enableMicrophone,
709
+ disableMicrophone,
710
+ isLoading,
711
+ errors
712
+ } = useMediaControls();
713
+
714
+ const handleCameraToggle = async () => {
715
+ try {
716
+ if (isVideoEnabled) {
717
+ await disableCamera();
718
+ } else {
719
+ await enableCamera();
720
+ }
721
+ } catch (error) {
722
+ console.error('Camera control failed:', error);
723
+ }
724
+ };
725
+
726
+ if (errors.length > 0) {
727
+ return (
728
+ <div className="media-errors">
729
+ {errors.map(error => (
730
+ <p key={error.code}>{error.message}</p>
731
+ ))}
732
+ </div>
733
+ );
734
+ }
735
+
736
+ return (
737
+ <div>
738
+ <button onClick={handleCameraToggle} disabled={isLoading}>
739
+ {isLoading ? 'Loading...' : 'Toggle Camera'}
740
+ </button>
741
+ </div>
742
+ );
743
+ }
744
+ ```
745
+
746
+ ## Participant Management
747
+
748
+ ### Displaying Participants
749
+
750
+ ```tsx
751
+ function ParticipantList() {
752
+ const participants = useParticipants();
753
+
754
+ return (
755
+ <div className="participants">
756
+ {participants.map(participant => (
757
+ <div key={participant.id} className="participant">
758
+ <img src={participant.avatarUrl} alt={participant.firstName} />
759
+ <span>{participant.firstName} {participant.lastName}</span>
760
+ <span className={`status ${participant.callState.toLowerCase()}`}>
761
+ {participant.callState}
762
+ </span>
763
+ <div className="media-status">
764
+ {participant.audioEnabled && <span>🎤</span>}
765
+ {participant.videoEnabled && <span>📹</span>}
766
+ {participant.isSpeaking && <span>🔊</span>}
767
+ </div>
768
+ </div>
769
+ ))}
770
+ </div>
771
+ );
772
+ }
773
+ ```
774
+
775
+ ### Participant Status Monitoring
776
+
777
+ ```tsx
778
+ function ParticipantMonitor({ participantId }) {
779
+ const status = useParticipantStatus(participantId);
780
+ const { mediaEnabled, mediaDisabled } = useMediaEvents(participantId);
781
+
782
+ useEffect(() => {
783
+ if (mediaEnabled) {
784
+ console.log(`${participantId} enabled ${mediaEnabled.payload.mediaType}`);
785
+ }
786
+ }, [mediaEnabled, participantId]);
787
+
788
+ useEffect(() => {
789
+ if (mediaDisabled) {
790
+ console.log(`${participantId} disabled ${mediaDisabled.payload.mediaType}`);
791
+ }
792
+ }, [mediaDisabled, participantId]);
793
+
794
+ return (
795
+ <div>
796
+ <h4>Participant: {participantId}</h4>
797
+ <p>Connection: {status?.connectionQuality}</p>
798
+ <p>Speaking: {status?.isSpeaking ? 'Yes' : 'No'}</p>
799
+ </div>
800
+ );
801
+ }
802
+ ```
803
+
804
+ ## Auto-Join Configuration
805
+
806
+ ### Using Auto-Join
807
+
808
+ ```tsx
809
+ function AutoJoinExample() {
810
+ const autoJoin = useAutoJoin();
811
+ const { shouldAutoJoin, reason } = useAutoJoinForCurrentUser();
812
+
813
+ return (
814
+ <div>
815
+ <h3>Auto-Join Status</h3>
816
+ <p>Enabled: {autoJoin.isEnabled ? 'Yes' : 'No'}</p>
817
+ <p>Max Retries: {autoJoin.maxRetries}</p>
818
+ <p>Should Auto-Join: {shouldAutoJoin ? 'Yes' : 'No'}</p>
819
+ <p>Reason: {reason}</p>
820
+ </div>
821
+ );
822
+ }
823
+ ```
824
+
825
+ ## Error Handling
826
+
827
+ ### Error Recovery
828
+
829
+ ```tsx
830
+ function ErrorRecoveryExample() {
831
+ const recovery = useErrorRecovery();
832
+ const errors = useErrors();
833
+
834
+ const handleRecovery = async () => {
835
+ try {
836
+ await recovery.attemptRecovery();
837
+ } catch (error) {
838
+ console.error('Recovery failed:', error);
839
+ }
840
+ };
841
+
842
+ if (errors.length > 0) {
843
+ return (
844
+ <div className="error-panel">
845
+ <h3>Errors Detected</h3>
846
+ {errors.map(error => (
847
+ <div key={error.code} className="error">
848
+ <strong>{error.code}</strong>: {error.message}
849
+ </div>
850
+ ))}
851
+ <button onClick={handleRecovery}>Attempt Recovery</button>
852
+ </div>
853
+ );
854
+ }
855
+
856
+ return null;
857
+ }
858
+ ```
859
+
860
+ ### Custom Error Handling
861
+
862
+ ```tsx
863
+ function CustomErrorHandler() {
864
+ useEvent(SdkEventType.ERROR_OCCURRED, (event) => {
865
+ const { code, message, source } = event.payload;
866
+
867
+ // Custom error handling logic
868
+ switch (code) {
869
+ case 'CONNECTION_LOST':
870
+ showReconnectingNotification();
871
+ break;
872
+ case 'MEDIA_PERMISSION_DENIED':
873
+ showPermissionRequestDialog();
874
+ break;
875
+ default:
876
+ showGenericErrorToast(message);
877
+ }
878
+ });
879
+
880
+ return <div>Error handler active</div>;
881
+ }
882
+ ```
883
+
884
+ ## TypeScript Support
885
+
886
+ The SDK is built with full TypeScript support. All hooks, components, and utilities are fully typed.
887
+
888
+ ### Type Definitions
889
+
890
+ ```tsx
891
+ import type {
892
+ // Core types
893
+ SessionStatus,
894
+ Participant,
895
+ IncomingCallInfo,
896
+ RtcError,
897
+
898
+ // Config types
899
+ RtcOptions,
900
+ AutoJoinConfig,
901
+
902
+ // Event types
903
+ SdkEvent,
904
+ SdkEventType,
905
+ CallAcceptedEvent,
906
+
907
+ // API types
908
+ InitiateCallParams,
909
+ CallResponse,
910
+ CallActionResponse,
911
+ } from 'vg-x07df';
912
+ ```
913
+
914
+ ### Custom Hook Example
915
+
916
+ ```tsx
917
+ import { useCallState, useCallActions } from 'vg-x07df';
918
+ import type { SessionStatus } from 'vg-x07df';
919
+
920
+ function useCallManager() {
921
+ const callState = useCallState();
922
+ const actions = useCallActions();
923
+
924
+ const isCallActive = (): boolean => {
925
+ return callState.status === 'ACTIVE';
926
+ };
927
+
928
+ const canInitiateCall = (): boolean => {
929
+ return callState.status === 'IDLE';
930
+ };
931
+
932
+ return {
933
+ ...callState,
934
+ ...actions,
935
+ isCallActive,
936
+ canInitiateCall,
937
+ };
938
+ }
939
+ ```
940
+
941
+ ## Advanced Usage
942
+
943
+ ### Direct SDK Access
944
+
945
+ Access the SDK instance directly for advanced operations:
946
+
947
+ ```tsx
948
+ import { useSdk } from 'vg-x07df';
949
+
950
+ function AdvancedComponent() {
951
+ const sdk = useSdk();
952
+
953
+ const performAdvancedOperation = async () => {
954
+ // Direct access to SDK components
955
+ const authToken = sdk.auth.getCurrentToken();
956
+ await sdk.signal.customApiCall();
957
+ sdk.livekit.performAdvancedMediaOperation();
958
+ };
959
+
960
+ return <button onClick={performAdvancedOperation}>Advanced Op</button>;
961
+ }
962
+ ```
963
+
964
+ ### Custom Logging
965
+
966
+ ```tsx
967
+ const rtcOptions = {
968
+ appId: 'my-app',
969
+ signalHost: 'https://signal.example.com',
970
+ authProvider: () => getToken(),
971
+
972
+ // Custom logging
973
+ log: (level, message, meta) => {
974
+ // Send to your logging service
975
+ analyticsService.log({
976
+ level,
977
+ message,
978
+ meta,
979
+ timestamp: Date.now(),
980
+ userId: getCurrentUserId(),
981
+ });
982
+ },
983
+ };
984
+ ```
985
+
986
+ ### State Management Integration
987
+
988
+ ```tsx
989
+ // Redux integration example
990
+ function useCallStateSync() {
991
+ const callState = useCallState();
992
+ const dispatch = useDispatch();
993
+
994
+ useEffect(() => {
995
+ dispatch(updateCallState(callState));
996
+ }, [callState, dispatch]);
997
+ }
998
+ ```
999
+
1000
+ ## Examples
1001
+
1002
+ ### Complete Call Application
1003
+
1004
+ ```tsx
1005
+ import React from 'react';
1006
+ import {
1007
+ RtcProvider,
1008
+ useCallState,
1009
+ useCallActions,
1010
+ useMediaControls,
1011
+ useParticipants,
1012
+ useEvent,
1013
+ SdkEventType
1014
+ } from 'vg-x07df';
1015
+
1016
+ // Main app with provider
1017
+ function App() {
1018
+ const rtcOptions = {
1019
+ appId: 'demo-app',
1020
+ signalHost: 'https://your-signal-server.com',
1021
+ authProvider: () => localStorage.getItem('token'),
1022
+ logLevel: 'info',
1023
+ autoJoin: { enabled: true, maxRetries: 2 }
1024
+ };
1025
+
1026
+ return (
1027
+ <RtcProvider options={rtcOptions}>
1028
+ <CallApp />
1029
+ </RtcProvider>
1030
+ );
1031
+ }
1032
+
1033
+ // Call application component
1034
+ function CallApp() {
1035
+ const callState = useCallState();
1036
+ const { initiate, accept, decline, end } = useCallActions();
1037
+ const { toggleVideo, toggleAudio, isVideoEnabled, isAudioEnabled } = useMediaControls();
1038
+ const participants = useParticipants();
1039
+
1040
+ // Handle incoming calls
1041
+ useEvent(SdkEventType.CALL_INCOMING, (event) => {
1042
+ const { caller, type } = event.payload;
1043
+ const response = confirm(`Accept ${type} call from ${caller.firstName}?`);
1044
+ if (response) {
1045
+ accept(event.payload.callId);
1046
+ } else {
1047
+ decline(event.payload.callId);
1048
+ }
1049
+ });
1050
+
1051
+ const startVideoCall = () => {
1052
+ initiate(['user-123'], 'VIDEO');
1053
+ };
1054
+
1055
+ const endCall = () => {
1056
+ if (callState.id) {
1057
+ end(callState.id);
1058
+ }
1059
+ };
1060
+
1061
+ return (
1062
+ <div>
1063
+ <h1>CallPad Demo</h1>
1064
+
1065
+ <div>Status: {callState.status}</div>
1066
+
1067
+ {callState.status === 'IDLE' && (
1068
+ <button onClick={startVideoCall}>Start Video Call</button>
1069
+ )}
1070
+
1071
+ {callState.status === 'ACTIVE' && (
1072
+ <div>
1073
+ <button onClick={toggleVideo}>
1074
+ {isVideoEnabled ? 'Disable Video' : 'Enable Video'}
1075
+ </button>
1076
+ <button onClick={toggleAudio}>
1077
+ {isAudioEnabled ? 'Mute' : 'Unmute'}
1078
+ </button>
1079
+ <button onClick={endCall}>End Call</button>
1080
+
1081
+ <div>
1082
+ <h3>Participants ({participants.length})</h3>
1083
+ {participants.map(p => (
1084
+ <div key={p.id}>
1085
+ {p.firstName} {p.lastName} - {p.callState}
1086
+ </div>
1087
+ ))}
1088
+ </div>
1089
+ </div>
1090
+ )}
1091
+ </div>
1092
+ );
1093
+ }
1094
+
1095
+ export default App;
1096
+ ```
1097
+
1098
+ ### Notification Service Integration
1099
+
1100
+ ```tsx
1101
+ function NotificationService() {
1102
+ useEvent(SdkEventType.CALL_INCOMING, (event) => {
1103
+ const { callId, caller, type } = event.payload;
1104
+
1105
+ if ('Notification' in window && Notification.permission === 'granted') {
1106
+ const notification = new Notification(
1107
+ `Incoming ${type} Call`,
1108
+ {
1109
+ body: `${caller.firstName} ${caller.lastName} is calling`,
1110
+ icon: caller.avatarUrl,
1111
+ actions: [
1112
+ { action: 'accept', title: 'Accept' },
1113
+ { action: 'decline', title: 'Decline' }
1114
+ ]
1115
+ }
1116
+ );
1117
+
1118
+ notification.onclick = (event) => {
1119
+ if (event.action === 'accept') {
1120
+ acceptCall(callId);
1121
+ } else if (event.action === 'decline') {
1122
+ declineCall(callId);
1123
+ }
1124
+ };
1125
+ }
1126
+ });
1127
+
1128
+ return null;
1129
+ }
1130
+ ```
1131
+
1132
+ This comprehensive documentation covers all major aspects of the CallPad SDK, providing developers with the information needed to integrate audio/video calling functionality into their React applications.