@vapi-ai/web 2.5.2 → 2.6.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/dist/vapi.d.ts +40 -2
- package/dist/vapi.js +106 -0
- package/package.json +5 -5
- package/vapi.ts +131 -1
package/dist/vapi.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ChatCompletionMessageParam } from 'openai/resources';
|
|
2
|
-
import { DailyCall, DailyAdvancedConfig, DailyFactoryOptions, DailyParticipant, DailyVideoSendSettings } from '@daily-co/daily-js';
|
|
2
|
+
import { DailyCall, DailyAdvancedConfig, DailyFactoryOptions, DailyEventObjectNoPayload, DailyEventObjectRecordingError, DailyEventObjectRecordingStarted, DailyEventObjectRecordingStopped, DailyParticipant, DailyVideoSendSettings } from '@daily-co/daily-js';
|
|
3
3
|
import EventEmitter from 'events';
|
|
4
4
|
import { Call, CreateSquadDTO, CreateAssistantDTO, AssistantOverrides, CreateWorkflowDTO, WorkflowOverrides } from './api';
|
|
5
5
|
export interface EndCallMessage {
|
|
@@ -23,7 +23,7 @@ export interface SayMessage {
|
|
|
23
23
|
interruptAssistantEnabled?: boolean;
|
|
24
24
|
}
|
|
25
25
|
type VapiClientToServerMessage = AddMessageMessage | ControlMessages | SayMessage | EndCallMessage;
|
|
26
|
-
type VapiEventNames = 'call-end' | 'call-start' | 'volume-level' | 'speech-start' | 'speech-end' | 'message' | 'video' | 'error' | 'camera-error' | 'network-quality-change' | 'network-connection' | 'daily-participant-updated' | 'call-start-progress' | 'call-start-success' | 'call-start-failed';
|
|
26
|
+
type VapiEventNames = 'call-end' | 'call-start' | 'volume-level' | 'local-volume-level' | 'local-audio-level-observer-error' | 'speech-start' | 'speech-end' | 'message' | 'video' | 'error' | 'camera-error' | 'network-quality-change' | 'network-connection' | 'daily-participant-updated' | 'call-start-progress' | 'call-start-success' | 'call-start-failed' | 'recording-started' | 'recording-stopped' | 'recording-stats' | 'recording-error' | 'recording-upload-completed';
|
|
27
27
|
interface CallStartProgressEvent {
|
|
28
28
|
stage: string;
|
|
29
29
|
status: 'started' | 'completed' | 'failed';
|
|
@@ -48,6 +48,8 @@ type VapiEventListeners = {
|
|
|
48
48
|
'call-end': () => void;
|
|
49
49
|
'call-start': () => void;
|
|
50
50
|
'volume-level': (volume: number) => void;
|
|
51
|
+
'local-volume-level': (volume: number) => void;
|
|
52
|
+
'local-audio-level-observer-error': (error: any) => void;
|
|
51
53
|
'speech-start': () => void;
|
|
52
54
|
'speech-end': () => void;
|
|
53
55
|
video: (track: MediaStreamTrack) => void;
|
|
@@ -60,6 +62,11 @@ type VapiEventListeners = {
|
|
|
60
62
|
'call-start-progress': (event: CallStartProgressEvent) => void;
|
|
61
63
|
'call-start-success': (event: CallStartSuccessEvent) => void;
|
|
62
64
|
'call-start-failed': (event: CallStartFailedEvent) => void;
|
|
65
|
+
'recording-started': (event: DailyEventObjectRecordingStarted) => void;
|
|
66
|
+
'recording-stopped': (event: DailyEventObjectRecordingStopped) => void;
|
|
67
|
+
'recording-stats': (event: DailyEventObjectNoPayload) => void;
|
|
68
|
+
'recording-error': (event: DailyEventObjectRecordingError) => void;
|
|
69
|
+
'recording-upload-completed': (event: DailyEventObjectNoPayload) => void;
|
|
63
70
|
};
|
|
64
71
|
type StartCallOptions = {
|
|
65
72
|
/**
|
|
@@ -123,6 +130,7 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
123
130
|
start(assistant?: CreateAssistantDTO | string, assistantOverrides?: AssistantOverrides, squad?: CreateSquadDTO | string, workflow?: CreateWorkflowDTO | string, workflowOverrides?: WorkflowOverrides, options?: StartCallOptions): Promise<Call | null>;
|
|
124
131
|
private onAppMessage;
|
|
125
132
|
private handleRemoteParticipantsAudioLevel;
|
|
133
|
+
private handleLocalAudioLevel;
|
|
126
134
|
/**
|
|
127
135
|
* Stops the call by destroying the Daily call object.
|
|
128
136
|
*
|
|
@@ -149,6 +157,36 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
149
157
|
increaseMicLevel(gain: number): Promise<void>;
|
|
150
158
|
setOutputDeviceAsync(options: Parameters<DailyCall['setOutputDeviceAsync']>[0]): void;
|
|
151
159
|
getDailyCallObject(): DailyCall | null;
|
|
160
|
+
/**
|
|
161
|
+
* Returns the most recent local (microphone) audio level, a number between 0 and 1.
|
|
162
|
+
*
|
|
163
|
+
* Useful for detecting when the local participant's microphone is not picking up any
|
|
164
|
+
* audio (e.g. wrong input device selected, OS-level input volume at 0, or muted
|
|
165
|
+
* hardware) so you can surface a "we can't hear you" style warning in your UI.
|
|
166
|
+
*
|
|
167
|
+
* Returns 0 when there is no active call.
|
|
168
|
+
*/
|
|
169
|
+
getLocalAudioLevel(): number;
|
|
170
|
+
/**
|
|
171
|
+
* Starts (or restarts) the local audio level observer. The observer is started
|
|
172
|
+
* automatically when a call begins, but this can be used to change the sampling
|
|
173
|
+
* interval or restart it if it was stopped.
|
|
174
|
+
*
|
|
175
|
+
* While running, the Vapi instance emits 'local-volume-level' events with the local
|
|
176
|
+
* microphone audio level (0 to 1).
|
|
177
|
+
*
|
|
178
|
+
* @param interval How often, in milliseconds, to emit audio level events. Defaults to Daily's default.
|
|
179
|
+
*/
|
|
180
|
+
startLocalAudioLevelObserver(interval?: number): Promise<void>;
|
|
181
|
+
/**
|
|
182
|
+
* Stops the local audio level observer. After calling this, 'local-volume-level'
|
|
183
|
+
* events will no longer be emitted until the observer is started again.
|
|
184
|
+
*/
|
|
185
|
+
stopLocalAudioLevelObserver(): void;
|
|
186
|
+
/**
|
|
187
|
+
* Returns whether the local audio level observer is currently running.
|
|
188
|
+
*/
|
|
189
|
+
isLocalAudioLevelObserverRunning(): boolean;
|
|
152
190
|
startScreenSharing(displayMediaOptions?: DisplayMediaStreamOptions, screenVideoSendSettings?: DailyVideoSendSettings): void;
|
|
153
191
|
stopScreenSharing(): void;
|
|
154
192
|
/**
|
package/dist/vapi.js
CHANGED
|
@@ -300,6 +300,26 @@ class Vapi extends VapiEventEmitter {
|
|
|
300
300
|
this.call.on('network-connection', (event) => {
|
|
301
301
|
this.emit('network-connection', event);
|
|
302
302
|
});
|
|
303
|
+
this.call.on('recording-started', (event) => {
|
|
304
|
+
if (event)
|
|
305
|
+
this.emit('recording-started', event);
|
|
306
|
+
});
|
|
307
|
+
this.call.on('recording-stopped', (event) => {
|
|
308
|
+
if (event)
|
|
309
|
+
this.emit('recording-stopped', event);
|
|
310
|
+
});
|
|
311
|
+
this.call.on('recording-stats', (event) => {
|
|
312
|
+
if (event)
|
|
313
|
+
this.emit('recording-stats', event);
|
|
314
|
+
});
|
|
315
|
+
this.call.on('recording-error', (event) => {
|
|
316
|
+
if (event)
|
|
317
|
+
this.emit('recording-error', event);
|
|
318
|
+
});
|
|
319
|
+
this.call.on('recording-upload-completed', (event) => {
|
|
320
|
+
if (event)
|
|
321
|
+
this.emit('recording-upload-completed', event);
|
|
322
|
+
});
|
|
303
323
|
this.call.on('track-started', async (e) => {
|
|
304
324
|
if (!e || !e.participant) {
|
|
305
325
|
return;
|
|
@@ -479,6 +499,7 @@ class Vapi extends VapiEventEmitter {
|
|
|
479
499
|
const audioObserverStartTime = Date.now();
|
|
480
500
|
try {
|
|
481
501
|
this.call.startRemoteParticipantsAudioLevelObserver(100);
|
|
502
|
+
this.call.startLocalAudioLevelObserver(100);
|
|
482
503
|
const audioObserverDuration = Date.now() - audioObserverStartTime;
|
|
483
504
|
this.emit('call-start-progress', {
|
|
484
505
|
stage: 'audio-observer-setup',
|
|
@@ -509,9 +530,16 @@ class Vapi extends VapiEventEmitter {
|
|
|
509
530
|
if (e)
|
|
510
531
|
this.handleRemoteParticipantsAudioLevel(e);
|
|
511
532
|
});
|
|
533
|
+
this.call.on('local-audio-level', (e) => {
|
|
534
|
+
if (e)
|
|
535
|
+
this.handleLocalAudioLevel(e);
|
|
536
|
+
});
|
|
512
537
|
this.call.on('app-message', (e) => this.onAppMessage(e));
|
|
513
538
|
this.call.on('nonfatal-error', (e) => {
|
|
514
539
|
// https://docs.daily.co/reference/daily-js/events/meeting-events#type-audio-processor-error
|
|
540
|
+
if (e?.type === 'local-audio-level-observer-error') {
|
|
541
|
+
this.emit('local-audio-level-observer-error', serializeError(e));
|
|
542
|
+
}
|
|
515
543
|
if (e?.type === 'audio-processor-error') {
|
|
516
544
|
this.call
|
|
517
545
|
?.updateInputSettings({
|
|
@@ -653,6 +681,9 @@ class Vapi extends VapiEventEmitter {
|
|
|
653
681
|
this.speakingTimeout = null;
|
|
654
682
|
}, 1000);
|
|
655
683
|
}
|
|
684
|
+
handleLocalAudioLevel(e) {
|
|
685
|
+
this.emit('local-volume-level', e.audioLevel);
|
|
686
|
+
}
|
|
656
687
|
/**
|
|
657
688
|
* Stops the call by destroying the Daily call object.
|
|
658
689
|
*
|
|
@@ -733,6 +764,53 @@ class Vapi extends VapiEventEmitter {
|
|
|
733
764
|
getDailyCallObject() {
|
|
734
765
|
return this.call;
|
|
735
766
|
}
|
|
767
|
+
/**
|
|
768
|
+
* Returns the most recent local (microphone) audio level, a number between 0 and 1.
|
|
769
|
+
*
|
|
770
|
+
* Useful for detecting when the local participant's microphone is not picking up any
|
|
771
|
+
* audio (e.g. wrong input device selected, OS-level input volume at 0, or muted
|
|
772
|
+
* hardware) so you can surface a "we can't hear you" style warning in your UI.
|
|
773
|
+
*
|
|
774
|
+
* Returns 0 when there is no active call.
|
|
775
|
+
*/
|
|
776
|
+
getLocalAudioLevel() {
|
|
777
|
+
if (!this.call) {
|
|
778
|
+
return 0;
|
|
779
|
+
}
|
|
780
|
+
return this.call.getLocalAudioLevel();
|
|
781
|
+
}
|
|
782
|
+
/**
|
|
783
|
+
* Starts (or restarts) the local audio level observer. The observer is started
|
|
784
|
+
* automatically when a call begins, but this can be used to change the sampling
|
|
785
|
+
* interval or restart it if it was stopped.
|
|
786
|
+
*
|
|
787
|
+
* While running, the Vapi instance emits 'local-volume-level' events with the local
|
|
788
|
+
* microphone audio level (0 to 1).
|
|
789
|
+
*
|
|
790
|
+
* @param interval How often, in milliseconds, to emit audio level events. Defaults to Daily's default.
|
|
791
|
+
*/
|
|
792
|
+
async startLocalAudioLevelObserver(interval) {
|
|
793
|
+
if (!this.call) {
|
|
794
|
+
throw new Error('Call object is not available.');
|
|
795
|
+
}
|
|
796
|
+
await this.call.startLocalAudioLevelObserver(interval);
|
|
797
|
+
}
|
|
798
|
+
/**
|
|
799
|
+
* Stops the local audio level observer. After calling this, 'local-volume-level'
|
|
800
|
+
* events will no longer be emitted until the observer is started again.
|
|
801
|
+
*/
|
|
802
|
+
stopLocalAudioLevelObserver() {
|
|
803
|
+
this.call?.stopLocalAudioLevelObserver();
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
806
|
+
* Returns whether the local audio level observer is currently running.
|
|
807
|
+
*/
|
|
808
|
+
isLocalAudioLevelObserverRunning() {
|
|
809
|
+
if (!this.call) {
|
|
810
|
+
return false;
|
|
811
|
+
}
|
|
812
|
+
return this.call.isLocalAudioLevelObserverRunning();
|
|
813
|
+
}
|
|
736
814
|
startScreenSharing(displayMediaOptions, screenVideoSendSettings) {
|
|
737
815
|
this.call?.startScreenShare({
|
|
738
816
|
displayMediaOptions,
|
|
@@ -849,6 +927,26 @@ class Vapi extends VapiEventEmitter {
|
|
|
849
927
|
this.call.on('network-connection', (event) => {
|
|
850
928
|
this.emit('network-connection', event);
|
|
851
929
|
});
|
|
930
|
+
this.call.on('recording-started', (event) => {
|
|
931
|
+
if (event)
|
|
932
|
+
this.emit('recording-started', event);
|
|
933
|
+
});
|
|
934
|
+
this.call.on('recording-stopped', (event) => {
|
|
935
|
+
if (event)
|
|
936
|
+
this.emit('recording-stopped', event);
|
|
937
|
+
});
|
|
938
|
+
this.call.on('recording-stats', (event) => {
|
|
939
|
+
if (event)
|
|
940
|
+
this.emit('recording-stats', event);
|
|
941
|
+
});
|
|
942
|
+
this.call.on('recording-error', (event) => {
|
|
943
|
+
if (event)
|
|
944
|
+
this.emit('recording-error', event);
|
|
945
|
+
});
|
|
946
|
+
this.call.on('recording-upload-completed', (event) => {
|
|
947
|
+
if (event)
|
|
948
|
+
this.emit('recording-upload-completed', event);
|
|
949
|
+
});
|
|
852
950
|
this.call.on('track-started', async (e) => {
|
|
853
951
|
if (!e || !e.participant) {
|
|
854
952
|
return;
|
|
@@ -888,9 +986,16 @@ class Vapi extends VapiEventEmitter {
|
|
|
888
986
|
if (e)
|
|
889
987
|
this.handleRemoteParticipantsAudioLevel(e);
|
|
890
988
|
});
|
|
989
|
+
this.call.on('local-audio-level', (e) => {
|
|
990
|
+
if (e)
|
|
991
|
+
this.handleLocalAudioLevel(e);
|
|
992
|
+
});
|
|
891
993
|
this.call.on('app-message', (e) => this.onAppMessage(e));
|
|
892
994
|
this.call.on('nonfatal-error', (e) => {
|
|
893
995
|
// https://docs.daily.co/reference/daily-js/events/meeting-events#type-audio-processor-error
|
|
996
|
+
if (e?.type === 'local-audio-level-observer-error') {
|
|
997
|
+
this.emit('local-audio-level-observer-error', serializeError(e));
|
|
998
|
+
}
|
|
894
999
|
if (e?.type === 'audio-processor-error') {
|
|
895
1000
|
this.call
|
|
896
1001
|
?.updateInputSettings({
|
|
@@ -1021,6 +1126,7 @@ class Vapi extends VapiEventEmitter {
|
|
|
1021
1126
|
const audioObserverStartTime = Date.now();
|
|
1022
1127
|
try {
|
|
1023
1128
|
this.call.startRemoteParticipantsAudioLevelObserver(100);
|
|
1129
|
+
this.call.startLocalAudioLevelObserver(100);
|
|
1024
1130
|
const audioObserverDuration = Date.now() - audioObserverStartTime;
|
|
1025
1131
|
this.emit('call-start-progress', {
|
|
1026
1132
|
stage: 'audio-observer-setup',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vapi-ai/web",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/vapi.js",
|
|
6
6
|
"types": "dist/vapi.d.ts",
|
|
@@ -19,19 +19,19 @@
|
|
|
19
19
|
},
|
|
20
20
|
"repository": {
|
|
21
21
|
"type": "git",
|
|
22
|
-
"url": "git+https://github.com/VapiAI/web.git"
|
|
22
|
+
"url": "git+https://github.com/VapiAI/client-sdk-web.git"
|
|
23
23
|
},
|
|
24
24
|
"author": "vapi",
|
|
25
25
|
"license": "MIT",
|
|
26
26
|
"bugs": {
|
|
27
|
-
"url": "https://github.com/VapiAI/web/issues"
|
|
27
|
+
"url": "https://github.com/VapiAI/client-sdk-web/issues"
|
|
28
28
|
},
|
|
29
|
-
"homepage": "https://github.com/VapiAI/web#readme",
|
|
29
|
+
"homepage": "https://github.com/VapiAI/client-sdk-web#readme",
|
|
30
30
|
"engines": {
|
|
31
31
|
"node": ">=18.0.0"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@daily-co/daily-js": "^0.
|
|
34
|
+
"@daily-co/daily-js": "^0.87.0",
|
|
35
35
|
"events": "^3.3.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
package/vapi.ts
CHANGED
|
@@ -5,7 +5,12 @@ import DailyIframe, {
|
|
|
5
5
|
DailyAdvancedConfig,
|
|
6
6
|
DailyFactoryOptions,
|
|
7
7
|
DailyEventObjectAppMessage,
|
|
8
|
+
DailyEventObjectLocalAudioLevel,
|
|
9
|
+
DailyEventObjectNoPayload,
|
|
8
10
|
DailyEventObjectParticipant,
|
|
11
|
+
DailyEventObjectRecordingError,
|
|
12
|
+
DailyEventObjectRecordingStarted,
|
|
13
|
+
DailyEventObjectRecordingStopped,
|
|
9
14
|
DailyEventObjectRemoteParticipantsAudioLevel,
|
|
10
15
|
DailyParticipant,
|
|
11
16
|
DailyVideoSendSettings,
|
|
@@ -62,6 +67,8 @@ type VapiEventNames =
|
|
|
62
67
|
| 'call-end'
|
|
63
68
|
| 'call-start'
|
|
64
69
|
| 'volume-level'
|
|
70
|
+
| 'local-volume-level'
|
|
71
|
+
| 'local-audio-level-observer-error'
|
|
65
72
|
| 'speech-start'
|
|
66
73
|
| 'speech-end'
|
|
67
74
|
| 'message'
|
|
@@ -73,7 +80,12 @@ type VapiEventNames =
|
|
|
73
80
|
| 'daily-participant-updated'
|
|
74
81
|
| 'call-start-progress'
|
|
75
82
|
| 'call-start-success'
|
|
76
|
-
| 'call-start-failed'
|
|
83
|
+
| 'call-start-failed'
|
|
84
|
+
| 'recording-started'
|
|
85
|
+
| 'recording-stopped'
|
|
86
|
+
| 'recording-stats'
|
|
87
|
+
| 'recording-error'
|
|
88
|
+
| 'recording-upload-completed';
|
|
77
89
|
|
|
78
90
|
interface CallStartProgressEvent {
|
|
79
91
|
stage: string;
|
|
@@ -169,6 +181,8 @@ type VapiEventListeners = {
|
|
|
169
181
|
'call-end': () => void;
|
|
170
182
|
'call-start': () => void;
|
|
171
183
|
'volume-level': (volume: number) => void;
|
|
184
|
+
'local-volume-level': (volume: number) => void;
|
|
185
|
+
'local-audio-level-observer-error': (error: any) => void;
|
|
172
186
|
'speech-start': () => void;
|
|
173
187
|
'speech-end': () => void;
|
|
174
188
|
video: (track: MediaStreamTrack) => void;
|
|
@@ -181,6 +195,11 @@ type VapiEventListeners = {
|
|
|
181
195
|
'call-start-progress': (event: CallStartProgressEvent) => void;
|
|
182
196
|
'call-start-success': (event: CallStartSuccessEvent) => void;
|
|
183
197
|
'call-start-failed': (event: CallStartFailedEvent) => void;
|
|
198
|
+
'recording-started': (event: DailyEventObjectRecordingStarted) => void;
|
|
199
|
+
'recording-stopped': (event: DailyEventObjectRecordingStopped) => void;
|
|
200
|
+
'recording-stats': (event: DailyEventObjectNoPayload) => void;
|
|
201
|
+
'recording-error': (event: DailyEventObjectRecordingError) => void;
|
|
202
|
+
'recording-upload-completed': (event: DailyEventObjectNoPayload) => void;
|
|
184
203
|
};
|
|
185
204
|
|
|
186
205
|
type StartCallOptions = {
|
|
@@ -539,6 +558,26 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
539
558
|
this.emit('network-connection', event);
|
|
540
559
|
});
|
|
541
560
|
|
|
561
|
+
this.call.on('recording-started', (event) => {
|
|
562
|
+
if (event) this.emit('recording-started', event);
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
this.call.on('recording-stopped', (event) => {
|
|
566
|
+
if (event) this.emit('recording-stopped', event);
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
this.call.on('recording-stats', (event) => {
|
|
570
|
+
if (event) this.emit('recording-stats', event);
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
this.call.on('recording-error', (event) => {
|
|
574
|
+
if (event) this.emit('recording-error', event);
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
this.call.on('recording-upload-completed', (event) => {
|
|
578
|
+
if (event) this.emit('recording-upload-completed', event);
|
|
579
|
+
});
|
|
580
|
+
|
|
542
581
|
this.call.on('track-started', async (e) => {
|
|
543
582
|
if (!e || !e.participant) {
|
|
544
583
|
return;
|
|
@@ -736,6 +775,7 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
736
775
|
|
|
737
776
|
try {
|
|
738
777
|
this.call.startRemoteParticipantsAudioLevelObserver(100);
|
|
778
|
+
this.call.startLocalAudioLevelObserver(100);
|
|
739
779
|
const audioObserverDuration = Date.now() - audioObserverStartTime;
|
|
740
780
|
this.emit('call-start-progress', {
|
|
741
781
|
stage: 'audio-observer-setup',
|
|
@@ -766,10 +806,17 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
766
806
|
if (e) this.handleRemoteParticipantsAudioLevel(e);
|
|
767
807
|
});
|
|
768
808
|
|
|
809
|
+
this.call.on('local-audio-level', (e) => {
|
|
810
|
+
if (e) this.handleLocalAudioLevel(e);
|
|
811
|
+
});
|
|
812
|
+
|
|
769
813
|
this.call.on('app-message', (e) => this.onAppMessage(e));
|
|
770
814
|
|
|
771
815
|
this.call.on('nonfatal-error', (e) => {
|
|
772
816
|
// https://docs.daily.co/reference/daily-js/events/meeting-events#type-audio-processor-error
|
|
817
|
+
if (e?.type === 'local-audio-level-observer-error') {
|
|
818
|
+
this.emit('local-audio-level-observer-error', serializeError(e));
|
|
819
|
+
}
|
|
773
820
|
if (e?.type === 'audio-processor-error') {
|
|
774
821
|
this.call
|
|
775
822
|
?.updateInputSettings({
|
|
@@ -927,6 +974,10 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
927
974
|
}, 1000);
|
|
928
975
|
}
|
|
929
976
|
|
|
977
|
+
private handleLocalAudioLevel(e: DailyEventObjectLocalAudioLevel) {
|
|
978
|
+
this.emit('local-volume-level', e.audioLevel);
|
|
979
|
+
}
|
|
980
|
+
|
|
930
981
|
/**
|
|
931
982
|
* Stops the call by destroying the Daily call object.
|
|
932
983
|
*
|
|
@@ -1027,6 +1078,57 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
1027
1078
|
return this.call;
|
|
1028
1079
|
}
|
|
1029
1080
|
|
|
1081
|
+
/**
|
|
1082
|
+
* Returns the most recent local (microphone) audio level, a number between 0 and 1.
|
|
1083
|
+
*
|
|
1084
|
+
* Useful for detecting when the local participant's microphone is not picking up any
|
|
1085
|
+
* audio (e.g. wrong input device selected, OS-level input volume at 0, or muted
|
|
1086
|
+
* hardware) so you can surface a "we can't hear you" style warning in your UI.
|
|
1087
|
+
*
|
|
1088
|
+
* Returns 0 when there is no active call.
|
|
1089
|
+
*/
|
|
1090
|
+
public getLocalAudioLevel(): number {
|
|
1091
|
+
if (!this.call) {
|
|
1092
|
+
return 0;
|
|
1093
|
+
}
|
|
1094
|
+
return this.call.getLocalAudioLevel();
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
/**
|
|
1098
|
+
* Starts (or restarts) the local audio level observer. The observer is started
|
|
1099
|
+
* automatically when a call begins, but this can be used to change the sampling
|
|
1100
|
+
* interval or restart it if it was stopped.
|
|
1101
|
+
*
|
|
1102
|
+
* While running, the Vapi instance emits 'local-volume-level' events with the local
|
|
1103
|
+
* microphone audio level (0 to 1).
|
|
1104
|
+
*
|
|
1105
|
+
* @param interval How often, in milliseconds, to emit audio level events. Defaults to Daily's default.
|
|
1106
|
+
*/
|
|
1107
|
+
public async startLocalAudioLevelObserver(interval?: number): Promise<void> {
|
|
1108
|
+
if (!this.call) {
|
|
1109
|
+
throw new Error('Call object is not available.');
|
|
1110
|
+
}
|
|
1111
|
+
await this.call.startLocalAudioLevelObserver(interval);
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
/**
|
|
1115
|
+
* Stops the local audio level observer. After calling this, 'local-volume-level'
|
|
1116
|
+
* events will no longer be emitted until the observer is started again.
|
|
1117
|
+
*/
|
|
1118
|
+
public stopLocalAudioLevelObserver(): void {
|
|
1119
|
+
this.call?.stopLocalAudioLevelObserver();
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
/**
|
|
1123
|
+
* Returns whether the local audio level observer is currently running.
|
|
1124
|
+
*/
|
|
1125
|
+
public isLocalAudioLevelObserverRunning(): boolean {
|
|
1126
|
+
if (!this.call) {
|
|
1127
|
+
return false;
|
|
1128
|
+
}
|
|
1129
|
+
return this.call.isLocalAudioLevelObserverRunning();
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1030
1132
|
public startScreenSharing(displayMediaOptions?: DisplayMediaStreamOptions, screenVideoSendSettings?: DailyVideoSendSettings) {
|
|
1031
1133
|
this.call?.startScreenShare({
|
|
1032
1134
|
displayMediaOptions,
|
|
@@ -1161,6 +1263,26 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
1161
1263
|
this.emit('network-connection', event);
|
|
1162
1264
|
});
|
|
1163
1265
|
|
|
1266
|
+
this.call.on('recording-started', (event) => {
|
|
1267
|
+
if (event) this.emit('recording-started', event);
|
|
1268
|
+
});
|
|
1269
|
+
|
|
1270
|
+
this.call.on('recording-stopped', (event) => {
|
|
1271
|
+
if (event) this.emit('recording-stopped', event);
|
|
1272
|
+
});
|
|
1273
|
+
|
|
1274
|
+
this.call.on('recording-stats', (event) => {
|
|
1275
|
+
if (event) this.emit('recording-stats', event);
|
|
1276
|
+
});
|
|
1277
|
+
|
|
1278
|
+
this.call.on('recording-error', (event) => {
|
|
1279
|
+
if (event) this.emit('recording-error', event);
|
|
1280
|
+
});
|
|
1281
|
+
|
|
1282
|
+
this.call.on('recording-upload-completed', (event) => {
|
|
1283
|
+
if (event) this.emit('recording-upload-completed', event);
|
|
1284
|
+
});
|
|
1285
|
+
|
|
1164
1286
|
this.call.on('track-started', async (e) => {
|
|
1165
1287
|
if (!e || !e.participant) {
|
|
1166
1288
|
return;
|
|
@@ -1208,10 +1330,17 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
1208
1330
|
if (e) this.handleRemoteParticipantsAudioLevel(e);
|
|
1209
1331
|
});
|
|
1210
1332
|
|
|
1333
|
+
this.call.on('local-audio-level', (e) => {
|
|
1334
|
+
if (e) this.handleLocalAudioLevel(e);
|
|
1335
|
+
});
|
|
1336
|
+
|
|
1211
1337
|
this.call.on('app-message', (e) => this.onAppMessage(e));
|
|
1212
1338
|
|
|
1213
1339
|
this.call.on('nonfatal-error', (e) => {
|
|
1214
1340
|
// https://docs.daily.co/reference/daily-js/events/meeting-events#type-audio-processor-error
|
|
1341
|
+
if (e?.type === 'local-audio-level-observer-error') {
|
|
1342
|
+
this.emit('local-audio-level-observer-error', serializeError(e));
|
|
1343
|
+
}
|
|
1215
1344
|
if (e?.type === 'audio-processor-error') {
|
|
1216
1345
|
this.call
|
|
1217
1346
|
?.updateInputSettings({
|
|
@@ -1353,6 +1482,7 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
1353
1482
|
|
|
1354
1483
|
try {
|
|
1355
1484
|
this.call.startRemoteParticipantsAudioLevelObserver(100);
|
|
1485
|
+
this.call.startLocalAudioLevelObserver(100);
|
|
1356
1486
|
const audioObserverDuration = Date.now() - audioObserverStartTime;
|
|
1357
1487
|
this.emit('call-start-progress', {
|
|
1358
1488
|
stage: 'audio-observer-setup',
|