vocallabsai-sdk 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +328 -0
- package/lib/VocalLabsSDK.d.ts +33 -0
- package/lib/VocalLabsSDK.d.ts.map +1 -0
- package/lib/VocalLabsSDK.js +192 -0
- package/lib/audio/AudioManager.d.ts +37 -0
- package/lib/audio/AudioManager.d.ts.map +1 -0
- package/lib/audio/AudioManager.js +127 -0
- package/lib/audio/AudioQueueService.d.ts +105 -0
- package/lib/audio/AudioQueueService.d.ts.map +1 -0
- package/lib/audio/AudioQueueService.js +544 -0
- package/lib/audio/index.d.ts +2 -0
- package/lib/audio/index.d.ts.map +1 -0
- package/lib/audio/index.js +5 -0
- package/lib/call/CallManager.d.ts +12 -0
- package/lib/call/CallManager.d.ts.map +1 -0
- package/lib/call/CallManager.js +24 -0
- package/lib/call/index.d.ts +2 -0
- package/lib/call/index.d.ts.map +1 -0
- package/lib/call/index.js +5 -0
- package/lib/config/constants.d.ts +5 -0
- package/lib/config/constants.d.ts.map +1 -0
- package/lib/config/constants.js +7 -0
- package/lib/config/index.d.ts +2 -0
- package/lib/config/index.d.ts.map +1 -0
- package/lib/config/index.js +5 -0
- package/lib/index.d.ts +8 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +30 -0
- package/lib/types/index.d.ts +68 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/index.js +20 -0
- package/lib/utils/index.d.ts +2 -0
- package/lib/utils/index.d.ts.map +1 -0
- package/lib/utils/index.js +6 -0
- package/lib/utils/logger.d.ts +16 -0
- package/lib/utils/logger.d.ts.map +1 -0
- package/lib/utils/logger.js +53 -0
- package/package.json +73 -0
- package/src/VocalLabsSDK.ts +343 -0
- package/src/audio/AudioManager.ts +213 -0
- package/src/audio/AudioQueueService.ts +733 -0
- package/src/audio/index.ts +1 -0
- package/src/call/CallManager.ts +46 -0
- package/src/call/index.ts +1 -0
- package/src/config/constants.ts +8 -0
- package/src/config/index.ts +1 -0
- package/src/index.ts +18 -0
- package/src/types/index.ts +101 -0
- package/src/types/react-native.d.ts +100 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/logger.ts +71 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Subspace
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
# VocalLabs SDK
|
|
2
|
+
|
|
3
|
+
A lightweight React Native SDK for VocalLabs audio calls with built-in audio streaming. Connect directly to calls using call ID and WebSocket URL - no API polling, no authentication, just simple direct connections.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🎤 **Direct Connection** - Connect directly with call ID and WebSocket URL
|
|
8
|
+
- 🎧 **Audio Streaming** - Real-time audio with WebSocket support
|
|
9
|
+
- 🔇 **Mute Control** - Built-in mute/unmute functionality
|
|
10
|
+
- 📈 **Statistics** - Real-time audio and sending stats
|
|
11
|
+
- 🎯 **Event-Driven** - Comprehensive event system for all actions
|
|
12
|
+
- 📝 **TypeScript** - Full TypeScript support with type definitions
|
|
13
|
+
- ⚡ **Lightweight** - No authentication, no polling, minimal overhead
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install vocal-native-sdk
|
|
19
|
+
# or
|
|
20
|
+
yarn add vocal-native-sdk
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import VocalLabsSDK from 'vocal-native-sdk';
|
|
27
|
+
|
|
28
|
+
// 1. Initialize SDK (optional config)
|
|
29
|
+
const sdk = new VocalLabsSDK({
|
|
30
|
+
sampleRate: 8000,
|
|
31
|
+
enableLogs: true,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// 2. Setup event listeners
|
|
35
|
+
sdk.on('onAudioConnected', () => {
|
|
36
|
+
console.log('Audio connected!');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
sdk.on('onUserConnected', (connected) => {
|
|
40
|
+
console.log('User connected:', connected);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
sdk.on('onMuteChanged', (isMuted) => {
|
|
44
|
+
console.log('Mute status:', isMuted);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// 3. Connect with either callId, websocketUrl, or both
|
|
48
|
+
// If both provided, websocketUrl is used (prioritized)
|
|
49
|
+
|
|
50
|
+
// Option 1: Just websocket URL (callId extracted from query params)
|
|
51
|
+
await sdk.connect({ websocketUrl: 'wss://rupture2.vocallabs.ai/ws?callId=test-call-123&sampleRate=8000' });
|
|
52
|
+
|
|
53
|
+
// Option 2: Just call ID
|
|
54
|
+
await sdk.connect({ callId: 'test-call-123' });
|
|
55
|
+
|
|
56
|
+
// Option 3: Both (websocketUrl takes priority)
|
|
57
|
+
await sdk.connect({
|
|
58
|
+
callId: 'test-call-123',
|
|
59
|
+
websocketUrl: 'wss://rupture2.vocallabs.ai/ws?callId=test-call-123&sampleRate=8000'
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// 4. Control the call
|
|
63
|
+
sdk.toggleMute(); // Toggle mute
|
|
64
|
+
sdk.setVolume(0.8); // Set volume
|
|
65
|
+
const stats = sdk.getStats(); // Get statistics
|
|
66
|
+
|
|
67
|
+
// 5. Disconnect when done
|
|
68
|
+
sdk.disconnect();
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Configuration
|
|
72
|
+
|
|
73
|
+
### SDK Configuration Options
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
interface SDKConfig {
|
|
77
|
+
sampleRate?: number; // Optional: Audio sample rate (default: 8000)
|
|
78
|
+
enableLogs?: boolean; // Optional: Enable console logs (default: true)
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Example with Custom Configuration
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
const sdk = new VocalLabsSDK({
|
|
86
|
+
sampleRate: 16000,
|
|
87
|
+
enableLogs: false,
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## API Reference
|
|
92
|
+
|
|
93
|
+
### Main Methods
|
|
94
|
+
|
|
95
|
+
#### `initializeAudioService(audioService)`
|
|
96
|
+
Initialize the SDK with your AudioAPIService instance. **Must be called before connecting audio.**
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
const audioService = new AudioAPIService();
|
|
100
|
+
sdk.initializeAudioService(audioService);
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
#### `connect({ callId?, websocketUrl? })`
|
|
104
|
+
Connect directly to a call. Provide either callId, websocketUrl, or both. If both are provided, websocketUrl takes priority.
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
// With just websocket URL (callId extracted from query params)
|
|
108
|
+
await sdk.connect({ websocketUrl: 'wss://rupture2.vocallabs.ai/ws?callId=test-123&sampleRate=8000' });
|
|
109
|
+
|
|
110
|
+
// With just call ID
|
|
111
|
+
await sdk.connect({ callId: 'test-123' });
|
|
112
|
+
|
|
113
|
+
// With both (websocket URL is prioritized)
|
|
114
|
+
await sdk.connect({
|
|
115
|
+
callId: 'test-123',
|
|
116
|
+
websocketUrl: 'wss://rupture2.vocallabs.ai/ws?callId=test-123&sampleRate=8000'
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
#### `disconnect()`
|
|
121
|
+
Disconnect from the current call and clean up.
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
sdk.disconnect();
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
#### `toggleMute()`
|
|
128
|
+
Toggle microphone mute state.
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
const isMuted = sdk.toggleMute();
|
|
132
|
+
console.log('Muted:', isMuted);
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
#### `setVolume(volume)`
|
|
136
|
+
Set audio volume (0.0 to 1.0).
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
sdk.setVolume(0.8);
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
#### `getState()`
|
|
143
|
+
Get current SDK state.
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
const state = sdk.getState();
|
|
147
|
+
console.log(state.isConnected, state.isMuted, state.currentCallId);
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
#### `getStats()`
|
|
151
|
+
Get audio and sending statistics.
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
const stats = sdk.getStats();
|
|
155
|
+
console.log('Sent chunks:', stats.sending.sentChunks);
|
|
156
|
+
console.log('Received chunks:', stats.audio.receivedChunks);
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
#### `dispose()`
|
|
160
|
+
Clean up all resources.
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
await sdk.dispose();
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Events
|
|
167
|
+
|
|
168
|
+
The SDK provides a comprehensive event system:
|
|
169
|
+
|
|
170
|
+
### Audio Events
|
|
171
|
+
- `onAudioConnected` - Audio stream connected
|
|
172
|
+
- `onAudioDisconnected` - Audio stream disconnected
|
|
173
|
+
- `onUserConnected` - Other user connected to the call
|
|
174
|
+
- `onUserDisconnected` - Other user disconnected
|
|
175
|
+
- `onMuteChanged` - Mute state changed
|
|
176
|
+
- `onStatsUpdate` - Statistics updated
|
|
177
|
+
|
|
178
|
+
### General Events
|
|
179
|
+
- `onError` - General error occurred
|
|
180
|
+
- `onLog` - Log message (if logging enabled)
|
|
181
|
+
|
|
182
|
+
### Event Usage Example
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
sdk.on('onAudioConnected', () => {
|
|
186
|
+
console.log('Audio connected successfully');
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
sdk.on('onUserConnected', (connected) => {
|
|
190
|
+
if (connected) {
|
|
191
|
+
console.log('Other user joined the call');
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
sdk.on('onStatsUpdate', ({ audio, sending }) => {
|
|
197
|
+
console.log(`Queue size: ${audio.queueSize}`);
|
|
198
|
+
console.log(`Sent chunks: ${sending.sentChunks}`);
|
|
199
|
+
});
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Complete Example with React Native Component
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
206
|
+
import { View, Button, Text } from 'react-native';
|
|
207
|
+
import SubspaceCallSDK from 'subspace-call-sdk';
|
|
208
|
+
import AudioAPIService from './services/AudioService';
|
|
209
|
+
|
|
210
|
+
const CallScreen = ({ userId, friendId }) => {
|
|
211
|
+
const sdkRef = useRef<VocalLabsSDK | null>(null);
|
|
212
|
+
const [isConnected, setIsConnected] = useState(false);
|
|
213
|
+
const [isMuted, setIsMuted] = useState(false);
|
|
214
|
+
|
|
215
|
+
useEffect(() => {
|
|
216
|
+
// Initialize SDK
|
|
217
|
+
const sdk = new VocalLabsSDK({
|
|
218
|
+
sampleRate: 8000,
|
|
219
|
+
enableLogs: true,
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
// Setup listeners
|
|
223
|
+
sdk.on('onAudioConnected', () => {
|
|
224
|
+
setIsConnected(true);
|
|
225
|
+
console.log('Audio connected');
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
sdk.on('onAudioDisconnected', () => {
|
|
229
|
+
setIsConnected(false);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
sdk.on('onMuteChanged', (muted) => {
|
|
233
|
+
setIsMuted(muted);
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
sdkRef.current = sdk;
|
|
237
|
+
|
|
238
|
+
return () => {
|
|
239
|
+
sdk.dispose();
|
|
240
|
+
};websocketUrl: string) => {
|
|
241
|
+
if (!sdkRef.current) return;
|
|
242
|
+
|
|
243
|
+
try {
|
|
244
|
+
// Just provide the websocket URL
|
|
245
|
+
await sdkRef.current.connect({ websocketUrl }
|
|
246
|
+
try {
|
|
247
|
+
// Provide either callId, websocketUrl, or both
|
|
248
|
+
await sdkRef.current.connect(callId, websocketUrl);
|
|
249
|
+
} catch (error) {
|
|
250
|
+
console.error('Failed to connect:', error);
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
const endCall = () => {
|
|
255
|
+
sdkRef.current?.disconnect();
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
const toggleMute = () => {
|
|
259
|
+
sdkRef.current?.toggleMute();
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
return (
|
|
263
|
+
<View>
|
|
264
|
+
<Text>Connected: {isConnected ? 'Yes' : 'No'}</Text>
|
|
265
|
+
<Text>Muted: {isMuted ? 'Yes' : 'No'}</Text>
|
|
266
|
+
|
|
267
|
+
<Button
|
|
268
|
+
title="Start Call"
|
|
269
|
+
onPress={() => startCall('wss://rupture2.vocallabs.ai/ws?callId=test-123&sampleRate=8000')}
|
|
270
|
+
/>
|
|
271
|
+
<Button title="Toggle Mute" onPress={toggleMute} />
|
|
272
|
+
<Button title="End Call" onPress={endCall} />
|
|
273
|
+
</View>
|
|
274
|
+
);
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
export default CallScreen;
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
## Error Handling
|
|
281
|
+
|
|
282
|
+
The SDK provides detailed error information:
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
import { SDKError, ErrorCode } from 'vocal-native-sdk';
|
|
286
|
+
|
|
287
|
+
try {
|
|
288
|
+
await sdk.connect({ websocketUrl: 'wss://rupture2.vocallabs.ai/ws?callId=test-123&sampleRate=8000' });
|
|
289
|
+
} catch (error) {
|
|
290
|
+
if (error instanceof SDKError) {
|
|
291
|
+
switch (error.code) {
|
|
292
|
+
case ErrorCode.INVALID_CONFIG:
|
|
293
|
+
console.log('Invalid configuration or URL');
|
|
294
|
+
break;
|
|
295
|
+
case ErrorCode.AUDIO_CONNECTION_FAILED:
|
|
296
|
+
console.log('Audio connection failed');
|
|
297
|
+
break;
|
|
298
|
+
// ... handle other error codes
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## TypeScript Support
|
|
305
|
+
|
|
306
|
+
The SDK is written in TypeScript and provides full type definitions:
|
|
307
|
+
|
|
308
|
+
```typescript
|
|
309
|
+
import VocalLabsSDK, {
|
|
310
|
+
CallData,
|
|
311
|
+
SDKState,
|
|
312
|
+
AudioStats,
|
|
313
|
+
SendingStats
|
|
314
|
+
} from 'vocal-native-sdk';
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
## Requirements
|
|
318
|
+
|
|
319
|
+
- React Native >= 0.60.0
|
|
320
|
+
- React >= 16.8.0
|
|
321
|
+
|
|
322
|
+
## License
|
|
323
|
+
|
|
324
|
+
MIT
|
|
325
|
+
|
|
326
|
+
## Support
|
|
327
|
+
|
|
328
|
+
For issues and questions, please open an issue on GitHub.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { SDKConfig, SDKState, EventType, EventCallback, CallData, AudioStats, SendingStats } from './types';
|
|
2
|
+
export declare class VocalLabsSDK {
|
|
3
|
+
private callManager;
|
|
4
|
+
private audioManager;
|
|
5
|
+
private logger;
|
|
6
|
+
private config;
|
|
7
|
+
private state;
|
|
8
|
+
private listeners;
|
|
9
|
+
constructor(config?: SDKConfig);
|
|
10
|
+
private setupAudioCallbacks;
|
|
11
|
+
connect(options: {
|
|
12
|
+
callId?: string;
|
|
13
|
+
websocketUrl?: string;
|
|
14
|
+
}): Promise<void>;
|
|
15
|
+
disconnect(): void;
|
|
16
|
+
toggleMute(): boolean;
|
|
17
|
+
setVolume(volume: number): void;
|
|
18
|
+
clearAudioQueue(): void;
|
|
19
|
+
getState(): SDKState;
|
|
20
|
+
getCurrentCall(): CallData | null;
|
|
21
|
+
getStats(): {
|
|
22
|
+
audio: AudioStats | null;
|
|
23
|
+
sending: SendingStats | null;
|
|
24
|
+
};
|
|
25
|
+
isMuted(): boolean;
|
|
26
|
+
isConnected(): boolean;
|
|
27
|
+
on<T = any>(event: EventType, callback: EventCallback<T>): void;
|
|
28
|
+
off<T = any>(event: EventType, callback: EventCallback<T>): void;
|
|
29
|
+
private _emit;
|
|
30
|
+
dispose(): Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
export default VocalLabsSDK;
|
|
33
|
+
//# sourceMappingURL=VocalLabsSDK.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VocalLabsSDK.d.ts","sourceRoot":"","sources":["../src/VocalLabsSDK.ts"],"names":[],"mappings":"AAuBA,OAAO,EACL,SAAS,EACT,QAAQ,EAER,SAAS,EACT,aAAa,EACb,QAAQ,EAGR,UAAU,EACV,YAAY,EACb,MAAM,SAAS,CAAC;AAMjB,qBAAa,YAAY;IAEvB,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,MAAM,CAAS;IAGvB,OAAO,CAAC,MAAM,CAAsB;IAGpC,OAAO,CAAC,KAAK,CAKX;IAGF,OAAO,CAAC,SAAS,CASf;gBAEU,MAAM,CAAC,EAAE,SAAS;IA8B9B,OAAO,CAAC,mBAAmB;IAqCrB,OAAO,CAAC,OAAO,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAyDjF,UAAU,IAAI,IAAI;IAoBlB,UAAU,IAAI,OAAO;IAcrB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAO/B,eAAe,IAAI,IAAI;IAOvB,QAAQ,IAAI,QAAQ;IAOpB,cAAc,IAAI,QAAQ,GAAG,IAAI;IAOjC,QAAQ,IAAI;QAAE,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;QAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAAA;KAAE;IAOtE,OAAO,IAAI,OAAO;IAOlB,WAAW,IAAI,OAAO;IAOtB,EAAE,CAAC,CAAC,GAAG,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,IAAI;IAW/D,GAAG,CAAC,CAAC,GAAG,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,IAAI;IAWhE,OAAO,CAAC,KAAK;IAeP,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CA2B/B;AAED,eAAe,YAAY,CAAC"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.VocalLabsSDK = void 0;
|
|
4
|
+
const types_1 = require("./types");
|
|
5
|
+
const constants_1 = require("./config/constants");
|
|
6
|
+
const logger_1 = require("./utils/logger");
|
|
7
|
+
const CallManager_1 = require("./call/CallManager");
|
|
8
|
+
const AudioManager_1 = require("./audio/AudioManager");
|
|
9
|
+
class VocalLabsSDK {
|
|
10
|
+
constructor(config) {
|
|
11
|
+
this.state = {
|
|
12
|
+
isInitialized: false,
|
|
13
|
+
isConnected: false,
|
|
14
|
+
currentCallId: null,
|
|
15
|
+
isMuted: false,
|
|
16
|
+
};
|
|
17
|
+
this.listeners = {
|
|
18
|
+
onAudioConnected: [],
|
|
19
|
+
onAudioDisconnected: [],
|
|
20
|
+
onUserConnected: [],
|
|
21
|
+
onUserDisconnected: [],
|
|
22
|
+
onMuteChanged: [],
|
|
23
|
+
onStatsUpdate: [],
|
|
24
|
+
onError: [],
|
|
25
|
+
onLog: [],
|
|
26
|
+
};
|
|
27
|
+
this.config = {
|
|
28
|
+
sampleRate: config?.sampleRate || constants_1.DEFAULT_CONFIG.SAMPLE_RATE,
|
|
29
|
+
enableLogs: config?.enableLogs !== false,
|
|
30
|
+
};
|
|
31
|
+
this.logger = new logger_1.Logger(this.config.enableLogs);
|
|
32
|
+
this.logger.setLogCallback((message, type) => {
|
|
33
|
+
this._emit('onLog', { message, type });
|
|
34
|
+
});
|
|
35
|
+
this.callManager = new CallManager_1.CallManager(this.logger);
|
|
36
|
+
this.audioManager = new AudioManager_1.AudioManager(this.logger, this.config.sampleRate);
|
|
37
|
+
this.setupAudioCallbacks();
|
|
38
|
+
this.logger.info('🚀 VocalLabs SDK initialized with built-in audio support');
|
|
39
|
+
this.state.isInitialized = true;
|
|
40
|
+
}
|
|
41
|
+
setupAudioCallbacks() {
|
|
42
|
+
this.audioManager.onConnected(() => {
|
|
43
|
+
this.state.isConnected = true;
|
|
44
|
+
this._emit('onAudioConnected');
|
|
45
|
+
});
|
|
46
|
+
this.audioManager.onDisconnected(() => {
|
|
47
|
+
this.state.isConnected = false;
|
|
48
|
+
this._emit('onAudioDisconnected');
|
|
49
|
+
});
|
|
50
|
+
this.audioManager.onMuteChanged((isMuted) => {
|
|
51
|
+
this.state.isMuted = isMuted;
|
|
52
|
+
this._emit('onMuteChanged', isMuted);
|
|
53
|
+
});
|
|
54
|
+
this.audioManager.onUserConnected((connected) => {
|
|
55
|
+
if (connected) {
|
|
56
|
+
this._emit('onUserConnected', true);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
this._emit('onUserDisconnected', false);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
this.audioManager.onStatsUpdate((stats) => {
|
|
63
|
+
this._emit('onStatsUpdate', stats);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
async connect(options) {
|
|
67
|
+
try {
|
|
68
|
+
if (!this.state.isInitialized) {
|
|
69
|
+
throw new types_1.SDKError('SDK not initialized', types_1.ErrorCode.NOT_INITIALIZED);
|
|
70
|
+
}
|
|
71
|
+
let { callId, websocketUrl } = options;
|
|
72
|
+
if (!callId && !websocketUrl) {
|
|
73
|
+
throw new types_1.SDKError('Either callId or websocketUrl must be provided', types_1.ErrorCode.INVALID_CONFIG);
|
|
74
|
+
}
|
|
75
|
+
if (!callId && websocketUrl) {
|
|
76
|
+
try {
|
|
77
|
+
const url = new URL(websocketUrl);
|
|
78
|
+
const callIdParam = url.searchParams.get('callId');
|
|
79
|
+
callId = callIdParam || `call-${Date.now()}`;
|
|
80
|
+
this.logger.info(`Extracted callId from URL: ${callId}`);
|
|
81
|
+
}
|
|
82
|
+
catch (e) {
|
|
83
|
+
callId = `call-${Date.now()}`;
|
|
84
|
+
this.logger.warning('Could not parse URL, using generated callId');
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
this.logger.info(`Connecting to call: ${callId}`);
|
|
88
|
+
const callData = {
|
|
89
|
+
call_id: callId,
|
|
90
|
+
websocket: websocketUrl || '',
|
|
91
|
+
};
|
|
92
|
+
this.callManager.setCurrentCall(callData);
|
|
93
|
+
this.state.currentCallId = callId;
|
|
94
|
+
await this.audioManager.connect({
|
|
95
|
+
callId: callId,
|
|
96
|
+
sampleRate: this.config.sampleRate,
|
|
97
|
+
wsUrl: websocketUrl,
|
|
98
|
+
});
|
|
99
|
+
this.logger.info('✅ Connected successfully');
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
this._emit('onError', error);
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
disconnect() {
|
|
107
|
+
this.logger.info('Disconnecting...');
|
|
108
|
+
this.audioManager.disconnect();
|
|
109
|
+
this.callManager.clearCurrentCall();
|
|
110
|
+
this.state.isConnected = false;
|
|
111
|
+
this.state.currentCallId = null;
|
|
112
|
+
this.state.isMuted = false;
|
|
113
|
+
this.logger.info('✅ Disconnected');
|
|
114
|
+
}
|
|
115
|
+
toggleMute() {
|
|
116
|
+
try {
|
|
117
|
+
const isMuted = this.audioManager.toggleMute();
|
|
118
|
+
this.state.isMuted = isMuted;
|
|
119
|
+
return isMuted;
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
this._emit('onError', error);
|
|
123
|
+
throw error;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
setVolume(volume) {
|
|
127
|
+
this.audioManager.setVolume(volume);
|
|
128
|
+
}
|
|
129
|
+
clearAudioQueue() {
|
|
130
|
+
this.audioManager.clearQueue();
|
|
131
|
+
}
|
|
132
|
+
getState() {
|
|
133
|
+
return { ...this.state };
|
|
134
|
+
}
|
|
135
|
+
getCurrentCall() {
|
|
136
|
+
return this.callManager.getCurrentCall();
|
|
137
|
+
}
|
|
138
|
+
getStats() {
|
|
139
|
+
return this.audioManager.getStats();
|
|
140
|
+
}
|
|
141
|
+
isMuted() {
|
|
142
|
+
return this.state.isMuted;
|
|
143
|
+
}
|
|
144
|
+
isConnected() {
|
|
145
|
+
return this.state.isConnected;
|
|
146
|
+
}
|
|
147
|
+
on(event, callback) {
|
|
148
|
+
if (this.listeners[event]) {
|
|
149
|
+
this.listeners[event].push(callback);
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
this.logger.warning(`Unknown event: ${event}`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
off(event, callback) {
|
|
156
|
+
if (this.listeners[event]) {
|
|
157
|
+
this.listeners[event] = this.listeners[event].filter((cb) => cb !== callback);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
_emit(event, data) {
|
|
161
|
+
if (this.listeners[event]) {
|
|
162
|
+
this.listeners[event].forEach((callback) => {
|
|
163
|
+
try {
|
|
164
|
+
callback(data);
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
this.logger.error(`Error in ${event} listener:`, error);
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
async dispose() {
|
|
173
|
+
this.logger.info('Disposing SDK...');
|
|
174
|
+
if (this.state.isConnected) {
|
|
175
|
+
this.disconnect();
|
|
176
|
+
}
|
|
177
|
+
this.callManager.dispose();
|
|
178
|
+
await this.audioManager.dispose();
|
|
179
|
+
Object.keys(this.listeners).forEach((key) => {
|
|
180
|
+
this.listeners[key] = [];
|
|
181
|
+
});
|
|
182
|
+
this.state = {
|
|
183
|
+
isInitialized: false,
|
|
184
|
+
isConnected: false,
|
|
185
|
+
currentCallId: null,
|
|
186
|
+
isMuted: false,
|
|
187
|
+
};
|
|
188
|
+
this.logger.info('✅ SDK disposed');
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
exports.VocalLabsSDK = VocalLabsSDK;
|
|
192
|
+
exports.default = VocalLabsSDK;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { AudioStats, SendingStats, AudioConnectionOptions } from '../types';
|
|
2
|
+
import { Logger } from '../utils/logger';
|
|
3
|
+
export declare class AudioManager {
|
|
4
|
+
private audioService;
|
|
5
|
+
private logger;
|
|
6
|
+
private sampleRate;
|
|
7
|
+
private isInitialized;
|
|
8
|
+
private onConnectedCallback?;
|
|
9
|
+
private onDisconnectedCallback?;
|
|
10
|
+
private onMuteChangedCallback?;
|
|
11
|
+
private onUserConnectedCallback?;
|
|
12
|
+
private onStatsUpdateCallback?;
|
|
13
|
+
constructor(logger: Logger, sampleRate?: number);
|
|
14
|
+
isServiceInitialized(): boolean;
|
|
15
|
+
private setupCallbacks;
|
|
16
|
+
connect(options: AudioConnectionOptions): Promise<void>;
|
|
17
|
+
disconnect(): void;
|
|
18
|
+
toggleMute(): boolean;
|
|
19
|
+
isMuted(): boolean;
|
|
20
|
+
isConnected(): boolean;
|
|
21
|
+
setVolume(volume: number): void;
|
|
22
|
+
clearQueue(): void;
|
|
23
|
+
getStats(): {
|
|
24
|
+
audio: AudioStats;
|
|
25
|
+
sending: SendingStats;
|
|
26
|
+
};
|
|
27
|
+
onConnected(callback: () => void): void;
|
|
28
|
+
onDisconnected(callback: () => void): void;
|
|
29
|
+
onMuteChanged(callback: (isMuted: boolean) => void): void;
|
|
30
|
+
onUserConnected(callback: (connected: boolean) => void): void;
|
|
31
|
+
onStatsUpdate(callback: (stats: {
|
|
32
|
+
audio: AudioStats;
|
|
33
|
+
sending: SendingStats;
|
|
34
|
+
}) => void): void;
|
|
35
|
+
dispose(): Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=AudioManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AudioManager.d.ts","sourceRoot":"","sources":["../../src/audio/AudioManager.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,sBAAsB,EAAuB,MAAM,UAAU,CAAC;AACjG,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAIzC,qBAAa,YAAY;IACvB,OAAO,CAAC,YAAY,CAAoB;IACxC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,aAAa,CAAkB;IAGvC,OAAO,CAAC,mBAAmB,CAAC,CAAa;IACzC,OAAO,CAAC,sBAAsB,CAAC,CAAa;IAC5C,OAAO,CAAC,qBAAqB,CAAC,CAA6B;IAC3D,OAAO,CAAC,uBAAuB,CAAC,CAA+B;IAC/D,OAAO,CAAC,qBAAqB,CAAC,CAAgE;gBAElF,MAAM,EAAE,MAAM,EAAE,UAAU,GAAE,MAAmC;IAc3E,oBAAoB,IAAI,OAAO;IAO/B,OAAO,CAAC,cAAc;IA+ChB,OAAO,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAsC7D,UAAU,IAAI,IAAI;IAQlB,UAAU,IAAI,OAAO;IAQrB,OAAO,IAAI,OAAO;IAOlB,WAAW,IAAI,OAAO;IAOtB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAO/B,UAAU,IAAI,IAAI;IAOlB,QAAQ,IAAI;QAAE,KAAK,EAAE,UAAU,CAAC;QAAC,OAAO,EAAE,YAAY,CAAA;KAAE;IAUxD,WAAW,CAAC,QAAQ,EAAE,MAAM,IAAI;IAIhC,cAAc,CAAC,QAAQ,EAAE,MAAM,IAAI;IAInC,aAAa,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI;IAIlD,eAAe,CAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI;IAItD,aAAa,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE;QAAE,KAAK,EAAE,UAAU,CAAC;QAAC,OAAO,EAAE,YAAY,CAAA;KAAE,KAAK,IAAI;IAO/E,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAK/B"}
|