@vapi-ai/web 1.1.7 → 1.3.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.
- package/README.md +6 -0
- package/api.ts +2281 -780
- package/dist/api.d.ts +1916 -757
- package/dist/api.js +177 -45
- package/dist/vapi.d.ts +5 -3
- package/dist/vapi.js +50 -6
- package/package.json +1 -1
- package/update.sh +1 -1
- package/vapi.ts +60 -8
- package/dist/AtomicMediaSource.d.ts +0 -17
- package/dist/AtomicMediaSource.js +0 -78
- package/dist/player.d.ts +0 -10
- package/dist/player.js +0 -38
package/dist/api.js
CHANGED
|
@@ -10,30 +10,7 @@
|
|
|
10
10
|
* ---------------------------------------------------------------
|
|
11
11
|
*/
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
-
exports.Api = exports.HttpClient = exports.ContentType =
|
|
14
|
-
class CreateWebCallDTO {
|
|
15
|
-
/**
|
|
16
|
-
* This is the assistant that will be used for the call. To use a transient assistant, use `assistant` instead.
|
|
17
|
-
*/
|
|
18
|
-
assistantId;
|
|
19
|
-
/**
|
|
20
|
-
* Overrides for the assistant's settings and template variables.
|
|
21
|
-
*/
|
|
22
|
-
assistantOverrides;
|
|
23
|
-
/**
|
|
24
|
-
* This is the assistant that will be used for the call. To use an existing assistant, use `assistantId` instead.
|
|
25
|
-
*/
|
|
26
|
-
assistant;
|
|
27
|
-
/**
|
|
28
|
-
* This will expose SIP URI you can use to connect to the call. Disabled by default.
|
|
29
|
-
*/
|
|
30
|
-
sipEnabled;
|
|
31
|
-
/**
|
|
32
|
-
* This is the metadata associated with the call.
|
|
33
|
-
*/
|
|
34
|
-
metadata;
|
|
35
|
-
}
|
|
36
|
-
exports.CreateWebCallDTO = CreateWebCallDTO;
|
|
13
|
+
exports.Api = exports.HttpClient = exports.ContentType = void 0;
|
|
37
14
|
var ContentType;
|
|
38
15
|
(function (ContentType) {
|
|
39
16
|
ContentType["Json"] = "application/json";
|
|
@@ -325,6 +302,40 @@ class Api extends HttpClient {
|
|
|
325
302
|
format: 'json',
|
|
326
303
|
...params,
|
|
327
304
|
}),
|
|
305
|
+
/**
|
|
306
|
+
* No description
|
|
307
|
+
*
|
|
308
|
+
* @tags Calls
|
|
309
|
+
* @name CallControllerDeleteCallData
|
|
310
|
+
* @summary Delete Call Data
|
|
311
|
+
* @request DELETE:/call/{id}
|
|
312
|
+
* @secure
|
|
313
|
+
*/
|
|
314
|
+
callControllerDeleteCallData: (id, params = {}) => this.request({
|
|
315
|
+
path: `/call/${id}`,
|
|
316
|
+
method: 'DELETE',
|
|
317
|
+
secure: true,
|
|
318
|
+
format: 'json',
|
|
319
|
+
...params,
|
|
320
|
+
}),
|
|
321
|
+
/**
|
|
322
|
+
* No description
|
|
323
|
+
*
|
|
324
|
+
* @tags Calls
|
|
325
|
+
* @name CallControllerUpdate
|
|
326
|
+
* @summary Update Call
|
|
327
|
+
* @request PATCH:/call/{id}
|
|
328
|
+
* @secure
|
|
329
|
+
*/
|
|
330
|
+
callControllerUpdate: (id, data, params = {}) => this.request({
|
|
331
|
+
path: `/call/${id}`,
|
|
332
|
+
method: 'PATCH',
|
|
333
|
+
body: data,
|
|
334
|
+
secure: true,
|
|
335
|
+
type: ContentType.Json,
|
|
336
|
+
format: 'json',
|
|
337
|
+
...params,
|
|
338
|
+
}),
|
|
328
339
|
/**
|
|
329
340
|
* No description
|
|
330
341
|
*
|
|
@@ -591,58 +602,179 @@ class Api extends HttpClient {
|
|
|
591
602
|
...params,
|
|
592
603
|
}),
|
|
593
604
|
};
|
|
594
|
-
|
|
605
|
+
log = {
|
|
595
606
|
/**
|
|
596
607
|
* No description
|
|
597
608
|
*
|
|
598
|
-
* @tags
|
|
599
|
-
* @name
|
|
600
|
-
* @summary Get
|
|
601
|
-
* @request GET:/
|
|
609
|
+
* @tags Logs
|
|
610
|
+
* @name LoggingControllerGetLogs
|
|
611
|
+
* @summary Get Call Logs
|
|
612
|
+
* @request GET:/log
|
|
602
613
|
* @secure
|
|
603
614
|
*/
|
|
604
|
-
|
|
605
|
-
path: `/
|
|
615
|
+
loggingControllerGetLogs: (query, params = {}) => this.request({
|
|
616
|
+
path: `/log`,
|
|
606
617
|
method: 'GET',
|
|
618
|
+
query: query,
|
|
607
619
|
secure: true,
|
|
608
620
|
format: 'json',
|
|
609
621
|
...params,
|
|
610
622
|
}),
|
|
623
|
+
};
|
|
624
|
+
tool = {
|
|
611
625
|
/**
|
|
612
626
|
* No description
|
|
613
627
|
*
|
|
614
|
-
* @tags
|
|
615
|
-
* @name
|
|
616
|
-
* @summary
|
|
617
|
-
* @request POST:/
|
|
628
|
+
* @tags Tools
|
|
629
|
+
* @name ToolControllerCreate
|
|
630
|
+
* @summary Create Tool
|
|
631
|
+
* @request POST:/tool
|
|
618
632
|
* @secure
|
|
619
633
|
*/
|
|
620
|
-
|
|
621
|
-
path: `/
|
|
634
|
+
toolControllerCreate: (data, params = {}) => this.request({
|
|
635
|
+
path: `/tool`,
|
|
622
636
|
method: 'POST',
|
|
637
|
+
body: data,
|
|
623
638
|
secure: true,
|
|
639
|
+
type: ContentType.Json,
|
|
624
640
|
format: 'json',
|
|
625
641
|
...params,
|
|
626
642
|
}),
|
|
627
|
-
};
|
|
628
|
-
logging = {
|
|
629
643
|
/**
|
|
630
644
|
* No description
|
|
631
645
|
*
|
|
632
|
-
* @tags
|
|
633
|
-
* @name
|
|
634
|
-
* @summary
|
|
635
|
-
* @request GET:/
|
|
646
|
+
* @tags Tools
|
|
647
|
+
* @name ToolControllerFindAll
|
|
648
|
+
* @summary List Tools
|
|
649
|
+
* @request GET:/tool
|
|
636
650
|
* @secure
|
|
637
651
|
*/
|
|
638
|
-
|
|
639
|
-
path: `/
|
|
652
|
+
toolControllerFindAll: (query, params = {}) => this.request({
|
|
653
|
+
path: `/tool`,
|
|
640
654
|
method: 'GET',
|
|
641
655
|
query: query,
|
|
642
656
|
secure: true,
|
|
643
657
|
format: 'json',
|
|
644
658
|
...params,
|
|
645
659
|
}),
|
|
660
|
+
/**
|
|
661
|
+
* No description
|
|
662
|
+
*
|
|
663
|
+
* @tags Tools
|
|
664
|
+
* @name ToolControllerFindOne
|
|
665
|
+
* @summary Get Tool
|
|
666
|
+
* @request GET:/tool/{id}
|
|
667
|
+
* @secure
|
|
668
|
+
*/
|
|
669
|
+
toolControllerFindOne: (id, params = {}) => this.request({
|
|
670
|
+
path: `/tool/${id}`,
|
|
671
|
+
method: 'GET',
|
|
672
|
+
secure: true,
|
|
673
|
+
format: 'json',
|
|
674
|
+
...params,
|
|
675
|
+
}),
|
|
676
|
+
/**
|
|
677
|
+
* No description
|
|
678
|
+
*
|
|
679
|
+
* @tags Tools
|
|
680
|
+
* @name ToolControllerUpdate
|
|
681
|
+
* @summary Update Tool
|
|
682
|
+
* @request PATCH:/tool/{id}
|
|
683
|
+
* @secure
|
|
684
|
+
*/
|
|
685
|
+
toolControllerUpdate: (id, data, params = {}) => this.request({
|
|
686
|
+
path: `/tool/${id}`,
|
|
687
|
+
method: 'PATCH',
|
|
688
|
+
body: data,
|
|
689
|
+
secure: true,
|
|
690
|
+
type: ContentType.Json,
|
|
691
|
+
format: 'json',
|
|
692
|
+
...params,
|
|
693
|
+
}),
|
|
694
|
+
/**
|
|
695
|
+
* No description
|
|
696
|
+
*
|
|
697
|
+
* @tags Tools
|
|
698
|
+
* @name ToolControllerRemove
|
|
699
|
+
* @summary Delete Tool
|
|
700
|
+
* @request DELETE:/tool/{id}
|
|
701
|
+
* @secure
|
|
702
|
+
*/
|
|
703
|
+
toolControllerRemove: (id, params = {}) => this.request({
|
|
704
|
+
path: `/tool/${id}`,
|
|
705
|
+
method: 'DELETE',
|
|
706
|
+
secure: true,
|
|
707
|
+
format: 'json',
|
|
708
|
+
...params,
|
|
709
|
+
}),
|
|
710
|
+
};
|
|
711
|
+
file = {
|
|
712
|
+
/**
|
|
713
|
+
* No description
|
|
714
|
+
*
|
|
715
|
+
* @tags Files
|
|
716
|
+
* @name FileControllerCreate
|
|
717
|
+
* @summary Upload File
|
|
718
|
+
* @request POST:/file/upload
|
|
719
|
+
* @secure
|
|
720
|
+
*/
|
|
721
|
+
fileControllerCreate: (data, params = {}) => this.request({
|
|
722
|
+
path: `/file/upload`,
|
|
723
|
+
method: 'POST',
|
|
724
|
+
body: data,
|
|
725
|
+
secure: true,
|
|
726
|
+
type: ContentType.FormData,
|
|
727
|
+
format: 'json',
|
|
728
|
+
...params,
|
|
729
|
+
}),
|
|
730
|
+
/**
|
|
731
|
+
* No description
|
|
732
|
+
*
|
|
733
|
+
* @tags Files
|
|
734
|
+
* @name FileControllerFindAll
|
|
735
|
+
* @summary List Files
|
|
736
|
+
* @request GET:/file
|
|
737
|
+
* @secure
|
|
738
|
+
*/
|
|
739
|
+
fileControllerFindAll: (params = {}) => this.request({
|
|
740
|
+
path: `/file`,
|
|
741
|
+
method: 'GET',
|
|
742
|
+
secure: true,
|
|
743
|
+
format: 'json',
|
|
744
|
+
...params,
|
|
745
|
+
}),
|
|
746
|
+
/**
|
|
747
|
+
* No description
|
|
748
|
+
*
|
|
749
|
+
* @tags Files
|
|
750
|
+
* @name FileControllerFindOne
|
|
751
|
+
* @summary Get File
|
|
752
|
+
* @request GET:/file/{id}
|
|
753
|
+
* @secure
|
|
754
|
+
*/
|
|
755
|
+
fileControllerFindOne: (id, params = {}) => this.request({
|
|
756
|
+
path: `/file/${id}`,
|
|
757
|
+
method: 'GET',
|
|
758
|
+
secure: true,
|
|
759
|
+
format: 'json',
|
|
760
|
+
...params,
|
|
761
|
+
}),
|
|
762
|
+
/**
|
|
763
|
+
* No description
|
|
764
|
+
*
|
|
765
|
+
* @tags Files
|
|
766
|
+
* @name FileControllerRemove
|
|
767
|
+
* @summary Delete File
|
|
768
|
+
* @request DELETE:/file/{id}
|
|
769
|
+
* @secure
|
|
770
|
+
*/
|
|
771
|
+
fileControllerRemove: (id, params = {}) => this.request({
|
|
772
|
+
path: `/file/${id}`,
|
|
773
|
+
method: 'DELETE',
|
|
774
|
+
secure: true,
|
|
775
|
+
format: 'json',
|
|
776
|
+
...params,
|
|
777
|
+
}),
|
|
646
778
|
};
|
|
647
779
|
}
|
|
648
780
|
exports.Api = Api;
|
package/dist/vapi.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
import { Call, CreateAssistantDTO, OverrideAssistantDTO } from './api';
|
|
2
|
+
import { Call, CreateAssistantDTO, CreateSquadDTO, OverrideAssistantDTO } from './api';
|
|
3
|
+
import { DailyCall } from '@daily-co/daily-js';
|
|
3
4
|
import type { ChatCompletionMessageParam } from 'openai/resources';
|
|
4
5
|
import EventEmitter from 'events';
|
|
5
6
|
export interface AddMessageMessage {
|
|
@@ -37,10 +38,9 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
37
38
|
private started;
|
|
38
39
|
private call;
|
|
39
40
|
private speakingTimeout;
|
|
40
|
-
private averageSpeechLevel;
|
|
41
41
|
constructor(apiToken: string, apiBaseUrl?: string);
|
|
42
42
|
private cleanup;
|
|
43
|
-
start(assistant
|
|
43
|
+
start(assistant?: CreateAssistantDTO | string, assistantOverrides?: OverrideAssistantDTO, squad?: CreateSquadDTO | string): Promise<Call | null>;
|
|
44
44
|
private onAppMessage;
|
|
45
45
|
private handleRemoteParticipantsAudioLevel;
|
|
46
46
|
stop(): void;
|
|
@@ -48,5 +48,7 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
48
48
|
setMuted(mute: boolean): void;
|
|
49
49
|
isMuted(): boolean;
|
|
50
50
|
say(message: string, endCallAfterSpoken?: boolean): void;
|
|
51
|
+
setInputDevicesAsync(options: Parameters<DailyCall['setInputDevicesAsync']>[0]): void;
|
|
52
|
+
setOutputDeviceAsync(options: Parameters<DailyCall['setOutputDeviceAsync']>[0]): void;
|
|
51
53
|
}
|
|
52
54
|
export {};
|
package/dist/vapi.js
CHANGED
|
@@ -25,13 +25,13 @@ async function buildAudioPlayer(track, participantId) {
|
|
|
25
25
|
await startPlayer(player, track);
|
|
26
26
|
return player;
|
|
27
27
|
}
|
|
28
|
-
function subscribeToTracks(e, call) {
|
|
28
|
+
function subscribeToTracks(e, call, isVideoRecordingEnabled) {
|
|
29
29
|
if (e.participant.local)
|
|
30
30
|
return;
|
|
31
31
|
call.updateParticipant(e.participant.session_id, {
|
|
32
32
|
setSubscribedTracks: {
|
|
33
33
|
audio: true,
|
|
34
|
-
video:
|
|
34
|
+
video: isVideoRecordingEnabled,
|
|
35
35
|
},
|
|
36
36
|
});
|
|
37
37
|
}
|
|
@@ -60,7 +60,6 @@ class Vapi extends VapiEventEmitter {
|
|
|
60
60
|
started = false;
|
|
61
61
|
call = null;
|
|
62
62
|
speakingTimeout = null;
|
|
63
|
-
averageSpeechLevel = 0;
|
|
64
63
|
constructor(apiToken, apiBaseUrl) {
|
|
65
64
|
super();
|
|
66
65
|
client_1.client.baseUrl = apiBaseUrl ?? 'https://api.vapi.ai';
|
|
@@ -72,7 +71,10 @@ class Vapi extends VapiEventEmitter {
|
|
|
72
71
|
this.call = null;
|
|
73
72
|
this.speakingTimeout = null;
|
|
74
73
|
}
|
|
75
|
-
async start(assistant, assistantOverrides) {
|
|
74
|
+
async start(assistant, assistantOverrides, squad) {
|
|
75
|
+
if (!assistant && !squad) {
|
|
76
|
+
throw new Error('Assistant or Squad must be provided.');
|
|
77
|
+
}
|
|
76
78
|
if (this.started) {
|
|
77
79
|
return null;
|
|
78
80
|
}
|
|
@@ -82,17 +84,24 @@ class Vapi extends VapiEventEmitter {
|
|
|
82
84
|
assistant: typeof assistant === 'string' ? undefined : assistant,
|
|
83
85
|
assistantId: typeof assistant === 'string' ? assistant : undefined,
|
|
84
86
|
assistantOverrides,
|
|
87
|
+
squad: typeof squad === 'string' ? undefined : squad,
|
|
88
|
+
squadId: typeof squad === 'string' ? squad : undefined,
|
|
85
89
|
})).data;
|
|
86
90
|
if (this.call) {
|
|
87
91
|
this.cleanup();
|
|
88
92
|
}
|
|
93
|
+
const isVideoRecordingEnabled = webCall?.artifactPlan?.videoRecordingEnabled ??
|
|
94
|
+
false;
|
|
89
95
|
this.call = daily_js_1.default.createCallObject({
|
|
90
96
|
audioSource: true,
|
|
91
|
-
videoSource:
|
|
97
|
+
videoSource: isVideoRecordingEnabled,
|
|
92
98
|
});
|
|
93
99
|
this.call.iframe()?.style.setProperty('display', 'none');
|
|
94
100
|
this.call.on('left-meeting', () => {
|
|
95
101
|
this.emit('call-end');
|
|
102
|
+
if (isVideoRecordingEnabled) {
|
|
103
|
+
this.call?.stopRecording();
|
|
104
|
+
}
|
|
96
105
|
this.cleanup();
|
|
97
106
|
});
|
|
98
107
|
this.call.on('participant-left', (e) => {
|
|
@@ -102,6 +111,9 @@ class Vapi extends VapiEventEmitter {
|
|
|
102
111
|
});
|
|
103
112
|
this.call.on('error', (error) => {
|
|
104
113
|
this.emit('error', error);
|
|
114
|
+
if (isVideoRecordingEnabled) {
|
|
115
|
+
this.call?.stopRecording();
|
|
116
|
+
}
|
|
105
117
|
});
|
|
106
118
|
this.call.on('camera-error', (error) => {
|
|
107
119
|
this.emit('error', error);
|
|
@@ -121,18 +133,44 @@ class Vapi extends VapiEventEmitter {
|
|
|
121
133
|
this.call.on('participant-joined', (e) => {
|
|
122
134
|
if (!e || !this.call)
|
|
123
135
|
return;
|
|
124
|
-
subscribeToTracks(e, this.call);
|
|
136
|
+
subscribeToTracks(e, this.call, isVideoRecordingEnabled);
|
|
125
137
|
});
|
|
126
138
|
await this.call.join({
|
|
127
139
|
url: webCall.webCallUrl,
|
|
128
140
|
subscribeToTracksAutomatically: false,
|
|
129
141
|
});
|
|
142
|
+
if (isVideoRecordingEnabled) {
|
|
143
|
+
await this.call.startRecording({
|
|
144
|
+
width: 1280,
|
|
145
|
+
height: 720,
|
|
146
|
+
backgroundColor: '#FF1F2D3D',
|
|
147
|
+
layout: {
|
|
148
|
+
preset: 'default',
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
}
|
|
130
152
|
this.call.startRemoteParticipantsAudioLevelObserver(100);
|
|
131
153
|
this.call.on('remote-participants-audio-level', (e) => {
|
|
132
154
|
if (e)
|
|
133
155
|
this.handleRemoteParticipantsAudioLevel(e);
|
|
134
156
|
});
|
|
135
157
|
this.call.on('app-message', (e) => this.onAppMessage(e));
|
|
158
|
+
this.call.on('nonfatal-error', (e) => {
|
|
159
|
+
// https://docs.daily.co/reference/daily-js/events/meeting-events#type-audio-processor-error
|
|
160
|
+
if (e?.type === 'audio-processor-error') {
|
|
161
|
+
this.call
|
|
162
|
+
?.updateInputSettings({
|
|
163
|
+
audio: {
|
|
164
|
+
processor: {
|
|
165
|
+
type: 'none',
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
})
|
|
169
|
+
.then(() => {
|
|
170
|
+
this.call?.setLocalAudio(true);
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
});
|
|
136
174
|
this.call.updateInputSettings({
|
|
137
175
|
audio: {
|
|
138
176
|
processor: {
|
|
@@ -225,5 +263,11 @@ class Vapi extends VapiEventEmitter {
|
|
|
225
263
|
endCallAfterSpoken
|
|
226
264
|
});
|
|
227
265
|
}
|
|
266
|
+
setInputDevicesAsync(options) {
|
|
267
|
+
this.call?.setInputDevicesAsync(options);
|
|
268
|
+
}
|
|
269
|
+
setOutputDeviceAsync(options) {
|
|
270
|
+
this.call?.setOutputDeviceAsync(options);
|
|
271
|
+
}
|
|
228
272
|
}
|
|
229
273
|
exports.default = Vapi;
|
package/package.json
CHANGED
package/update.sh
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
npm version
|
|
1
|
+
npm version minor && npm run build && npm publish && cd ../landing && npm install @vapi-ai/web@latest && cd -
|
package/vapi.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Call, CreateAssistantDTO, OverrideAssistantDTO } from './api';
|
|
1
|
+
import { Call, CreateAssistantDTO, CreateSquadDTO, OverrideAssistantDTO } from './api';
|
|
2
2
|
import DailyIframe, {
|
|
3
3
|
DailyCall,
|
|
4
4
|
DailyEventObjectAppMessage,
|
|
@@ -29,13 +29,13 @@ async function buildAudioPlayer(track: any, participantId: string) {
|
|
|
29
29
|
await startPlayer(player, track);
|
|
30
30
|
return player;
|
|
31
31
|
}
|
|
32
|
-
function subscribeToTracks(e: DailyEventObjectParticipant, call: DailyCall) {
|
|
32
|
+
function subscribeToTracks(e: DailyEventObjectParticipant, call: DailyCall, isVideoRecordingEnabled?: boolean) {
|
|
33
33
|
if (e.participant.local) return;
|
|
34
34
|
|
|
35
35
|
call.updateParticipant(e.participant.session_id, {
|
|
36
36
|
setSubscribedTracks: {
|
|
37
37
|
audio: true,
|
|
38
|
-
video:
|
|
38
|
+
video: isVideoRecordingEnabled,
|
|
39
39
|
},
|
|
40
40
|
});
|
|
41
41
|
}
|
|
@@ -103,7 +103,6 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
103
103
|
private started: boolean = false;
|
|
104
104
|
private call: DailyCall | null = null;
|
|
105
105
|
private speakingTimeout: NodeJS.Timeout | null = null;
|
|
106
|
-
private averageSpeechLevel: number = 0;
|
|
107
106
|
|
|
108
107
|
constructor(apiToken: string, apiBaseUrl?: string) {
|
|
109
108
|
super();
|
|
@@ -119,13 +118,17 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
119
118
|
}
|
|
120
119
|
|
|
121
120
|
async start(
|
|
122
|
-
assistant
|
|
121
|
+
assistant?: CreateAssistantDTO | string,
|
|
123
122
|
assistantOverrides?: OverrideAssistantDTO,
|
|
123
|
+
squad?: CreateSquadDTO | string,
|
|
124
124
|
): Promise<Call | null> {
|
|
125
|
+
if (!assistant && !squad) {
|
|
126
|
+
throw new Error('Assistant or Squad must be provided.');
|
|
127
|
+
}
|
|
128
|
+
|
|
125
129
|
if (this.started) {
|
|
126
130
|
return null;
|
|
127
131
|
}
|
|
128
|
-
|
|
129
132
|
this.started = true;
|
|
130
133
|
|
|
131
134
|
try {
|
|
@@ -134,20 +137,29 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
134
137
|
assistant: typeof assistant === 'string' ? undefined : assistant,
|
|
135
138
|
assistantId: typeof assistant === 'string' ? assistant : undefined,
|
|
136
139
|
assistantOverrides,
|
|
140
|
+
squad: typeof squad === 'string' ? undefined : squad,
|
|
141
|
+
squadId: typeof squad === 'string' ? squad : undefined,
|
|
137
142
|
})
|
|
138
143
|
).data;
|
|
139
144
|
|
|
140
145
|
if (this.call) {
|
|
141
146
|
this.cleanup();
|
|
142
147
|
}
|
|
148
|
+
const isVideoRecordingEnabled =
|
|
149
|
+
webCall?.artifactPlan?.videoRecordingEnabled ??
|
|
150
|
+
false;
|
|
151
|
+
|
|
143
152
|
this.call = DailyIframe.createCallObject({
|
|
144
153
|
audioSource: true,
|
|
145
|
-
videoSource:
|
|
154
|
+
videoSource: isVideoRecordingEnabled,
|
|
146
155
|
});
|
|
147
156
|
this.call.iframe()?.style.setProperty('display', 'none');
|
|
148
157
|
|
|
149
158
|
this.call.on('left-meeting', () => {
|
|
150
159
|
this.emit('call-end');
|
|
160
|
+
if (isVideoRecordingEnabled) {
|
|
161
|
+
this.call?.stopRecording();
|
|
162
|
+
}
|
|
151
163
|
this.cleanup();
|
|
152
164
|
});
|
|
153
165
|
|
|
@@ -158,6 +170,9 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
158
170
|
|
|
159
171
|
this.call.on('error', (error: any) => {
|
|
160
172
|
this.emit('error', error);
|
|
173
|
+
if (isVideoRecordingEnabled) {
|
|
174
|
+
this.call?.stopRecording();
|
|
175
|
+
}
|
|
161
176
|
});
|
|
162
177
|
|
|
163
178
|
this.call.on('camera-error', (error: any) => {
|
|
@@ -177,7 +192,7 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
177
192
|
|
|
178
193
|
this.call.on('participant-joined', (e) => {
|
|
179
194
|
if (!e || !this.call) return;
|
|
180
|
-
subscribeToTracks(e, this.call);
|
|
195
|
+
subscribeToTracks(e, this.call, isVideoRecordingEnabled);
|
|
181
196
|
});
|
|
182
197
|
|
|
183
198
|
await this.call.join({
|
|
@@ -185,6 +200,17 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
185
200
|
subscribeToTracksAutomatically: false,
|
|
186
201
|
});
|
|
187
202
|
|
|
203
|
+
if (isVideoRecordingEnabled) {
|
|
204
|
+
await this.call.startRecording({
|
|
205
|
+
width: 1280,
|
|
206
|
+
height: 720,
|
|
207
|
+
backgroundColor: '#FF1F2D3D',
|
|
208
|
+
layout: {
|
|
209
|
+
preset: 'default',
|
|
210
|
+
},
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
188
214
|
this.call.startRemoteParticipantsAudioLevelObserver(100);
|
|
189
215
|
|
|
190
216
|
this.call.on('remote-participants-audio-level', (e) => {
|
|
@@ -193,6 +219,23 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
193
219
|
|
|
194
220
|
this.call.on('app-message', (e) => this.onAppMessage(e));
|
|
195
221
|
|
|
222
|
+
this.call.on('nonfatal-error', (e) => {
|
|
223
|
+
// https://docs.daily.co/reference/daily-js/events/meeting-events#type-audio-processor-error
|
|
224
|
+
if (e?.type === 'audio-processor-error') {
|
|
225
|
+
this.call
|
|
226
|
+
?.updateInputSettings({
|
|
227
|
+
audio: {
|
|
228
|
+
processor: {
|
|
229
|
+
type: 'none',
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
})
|
|
233
|
+
.then(() => {
|
|
234
|
+
this.call?.setLocalAudio(true);
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
|
|
196
239
|
this.call.updateInputSettings({
|
|
197
240
|
audio: {
|
|
198
241
|
processor: {
|
|
@@ -289,4 +332,13 @@ export default class Vapi extends VapiEventEmitter {
|
|
|
289
332
|
endCallAfterSpoken
|
|
290
333
|
})
|
|
291
334
|
}
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
public setInputDevicesAsync(options: Parameters<DailyCall['setInputDevicesAsync']>[0]) {
|
|
338
|
+
this.call?.setInputDevicesAsync(options)
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
public setOutputDeviceAsync(options: Parameters<DailyCall['setOutputDeviceAsync']>[0]) {
|
|
342
|
+
this.call?.setOutputDeviceAsync(options)
|
|
343
|
+
}
|
|
292
344
|
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
|
-
import EventEmitter from "events";
|
|
3
|
-
declare global {
|
|
4
|
-
interface Window {
|
|
5
|
-
ManagedMediaSource: any;
|
|
6
|
-
}
|
|
7
|
-
}
|
|
8
|
-
declare class AtomicMediaSource extends EventEmitter {
|
|
9
|
-
mediaSource: any;
|
|
10
|
-
sourceBuffer: SourceBuffer | null;
|
|
11
|
-
private operationsQueue;
|
|
12
|
-
constructor();
|
|
13
|
-
appendBuffer(buffer: ArrayBuffer): void;
|
|
14
|
-
clearBuffer(): void;
|
|
15
|
-
private createOperationQueue;
|
|
16
|
-
}
|
|
17
|
-
export default AtomicMediaSource;
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const async_1 = __importDefault(require("async"));
|
|
7
|
-
const events_1 = __importDefault(require("events"));
|
|
8
|
-
// ManagedMediaSource needed for iOS Safari
|
|
9
|
-
function getMediaSource() {
|
|
10
|
-
if (window.ManagedMediaSource) {
|
|
11
|
-
return new window.ManagedMediaSource();
|
|
12
|
-
}
|
|
13
|
-
if (window.MediaSource) {
|
|
14
|
-
return new window.MediaSource();
|
|
15
|
-
}
|
|
16
|
-
return null;
|
|
17
|
-
}
|
|
18
|
-
class AtomicMediaSource extends events_1.default {
|
|
19
|
-
constructor() {
|
|
20
|
-
super();
|
|
21
|
-
this.sourceBuffer = null;
|
|
22
|
-
this.mediaSource = getMediaSource();
|
|
23
|
-
this.operationsQueue = this.createOperationQueue();
|
|
24
|
-
if (!this.mediaSource) {
|
|
25
|
-
console.error("MediaSource is not supported in your browser.");
|
|
26
|
-
// Display a message to the user, or handle this situation in another way
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
this.mediaSource.addEventListener("sourceopen", () => {
|
|
30
|
-
this.mediaSource.duration = Number.POSITIVE_INFINITY;
|
|
31
|
-
this.sourceBuffer = this.mediaSource.addSourceBuffer('audio/webm; codecs="opus"');
|
|
32
|
-
if (this.sourceBuffer) {
|
|
33
|
-
this.sourceBuffer.mode = "sequence";
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
appendBuffer(buffer) {
|
|
38
|
-
this.operationsQueue.push(() => {
|
|
39
|
-
return new Promise((resolve, reject) => {
|
|
40
|
-
if (this.sourceBuffer) {
|
|
41
|
-
this.sourceBuffer.addEventListener("updateend", () => {
|
|
42
|
-
resolve();
|
|
43
|
-
}, { once: true });
|
|
44
|
-
this.sourceBuffer.appendBuffer(buffer);
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
reject();
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
clearBuffer() {
|
|
53
|
-
// this.operationsQueue.push(() => {
|
|
54
|
-
// return new Promise((resolve, reject) => {
|
|
55
|
-
// if (this.sourceBuffer) {
|
|
56
|
-
// this.sourceBuffer.addEventListener(
|
|
57
|
-
// "updateend",
|
|
58
|
-
// () => {
|
|
59
|
-
// resolve();
|
|
60
|
-
// },
|
|
61
|
-
// { once: true }
|
|
62
|
-
// );
|
|
63
|
-
// if (this.sourceBuffer.buffered.length > 0) {
|
|
64
|
-
// this.sourceBuffer.remove(0, this.sourceBuffer.buffered.end(0));
|
|
65
|
-
// }
|
|
66
|
-
// } else {
|
|
67
|
-
// reject();
|
|
68
|
-
// }
|
|
69
|
-
// });
|
|
70
|
-
// });
|
|
71
|
-
}
|
|
72
|
-
createOperationQueue() {
|
|
73
|
-
return async_1.default.queue((task, callback) => {
|
|
74
|
-
task().then(() => callback());
|
|
75
|
-
}, 1);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
exports.default = AtomicMediaSource;
|