@fonoster/apiserver 0.6.2 → 0.7.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/dist/applications/buildService.d.ts +3 -3
- package/dist/applications/createApplication.d.ts +2 -2
- package/dist/applications/createGetFnUtil.d.ts +2 -2
- package/dist/applications/deleteApplication.d.ts +3 -3
- package/dist/applications/getApplication.d.ts +2 -2
- package/dist/applications/getApplication.js +1 -3
- package/dist/applications/types.d.ts +1 -1
- package/dist/applications/utils/applicationWithEncodedStruct.js +20 -1
- package/dist/applications/utils/convertToApplicationData.js +1 -1
- package/dist/applications/utils/getApplicationValidationSchema.d.ts +3 -3
- package/dist/applications/utils/getApplicationValidationSchema.js +6 -3
- package/dist/applications/utils/prepareForValidation.js +1 -1
- package/dist/calls/ListCallsRequestSchema.d.ts +1 -4
- package/dist/calls/ListCallsRequestSchema.js +0 -4
- package/dist/calls/buildService.d.ts +2 -2
- package/dist/calls/buildService.js +6 -5
- package/dist/calls/createCall.d.ts +6 -4
- package/dist/calls/createCall.js +18 -8
- package/dist/calls/createFetchCalls.js +3 -7
- package/dist/calls/createFetchSingleCall.js +9 -2
- package/dist/calls/{trackCall.d.ts → makeTrackCall.d.ts} +3 -3
- package/dist/calls/makeTrackCall.js +67 -0
- package/dist/calls/runCallManager.js +12 -13
- package/dist/calls/types.d.ts +8 -42
- package/dist/calls/types.js +5 -38
- package/dist/core/seed.js +20 -0
- package/dist/core/services.d.ts +24 -25
- package/dist/envs.d.ts +0 -2
- package/dist/envs.js +1 -3
- package/dist/events/createInfluxDbPub.js +2 -1
- package/dist/events/mapCallDirectionToEnum.d.ts +3 -0
- package/dist/events/mapCallDirectionToEnum.js +37 -0
- package/dist/events/nats.js +5 -6
- package/dist/events/transformEvent.d.ts +2 -0
- package/dist/events/transformEvent.js +72 -0
- package/dist/index.js +4 -5
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/makeHandleDialEventsWithNats.d.ts +5 -0
- package/dist/{voice/handlers/StasisEnd.js → utils/makeHandleDialEventsWithNats.js} +10 -15
- package/dist/utils/makeHandleDialEventsWithVoiceClient.d.ts +5 -0
- package/dist/{voice/handlers/dial/handleDialEvents.js → utils/makeHandleDialEventsWithVoiceClient.js} +6 -17
- package/dist/utils/mapDialStatus.d.ts +3 -0
- package/dist/utils/mapDialStatus.js +38 -0
- package/dist/voice/VoiceClientImpl.d.ts +10 -1
- package/dist/voice/VoiceClientImpl.js +47 -7
- package/dist/voice/VoiceDispatcher.d.ts +6 -2
- package/dist/voice/VoiceDispatcher.js +50 -37
- package/dist/voice/connectToAri.js +3 -1
- package/dist/voice/createExternalMediaConfig.d.ts +3 -0
- package/dist/voice/createExternalMediaConfig.js +4 -1
- package/dist/voice/handlers/Answer.js +1 -1
- package/dist/voice/handlers/Hangup.js +1 -1
- package/dist/voice/handlers/Mute.js +1 -1
- package/dist/voice/handlers/Play.js +2 -2
- package/dist/voice/handlers/PlayDtmf.js +1 -1
- package/dist/voice/handlers/PlaybackControl.js +1 -1
- package/dist/voice/handlers/Record.js +2 -2
- package/dist/voice/handlers/Say.js +2 -2
- package/dist/voice/handlers/StreamGather.d.ts +3 -0
- package/dist/voice/handlers/StreamGather.js +66 -0
- package/dist/voice/handlers/Unmute.js +1 -1
- package/dist/voice/handlers/dial/Dial.js +10 -6
- package/dist/voice/handlers/gather/Gather.js +5 -4
- package/dist/voice/handlers/index.d.ts +12 -0
- package/dist/voice/handlers/index.js +46 -0
- package/dist/voice/handlers/{awaitForPlaybackFinished.js → utils/awaitForPlaybackFinished.js} +1 -1
- package/dist/voice/handlers/{awaitForRecordingFinished.js → utils/awaitForRecordingFinished.js} +1 -1
- package/dist/voice/handlers/utils/index.d.ts +3 -0
- package/dist/voice/handlers/utils/index.js +37 -0
- package/dist/voice/handlers/utils/isDtmf.d.ts +2 -0
- package/dist/voice/handlers/utils/isDtmf.js +24 -0
- package/dist/voice/integrations/findIntegrationsCredentials.d.ts +1 -1
- package/dist/voice/integrations/findIntegrationsCredentials.js +2 -1
- package/dist/voice/integrations/getSttConfig.d.ts +4 -2
- package/dist/voice/integrations/getSttConfig.js +4 -1
- package/dist/voice/integrations/getTtsConfig.d.ts +2 -1
- package/dist/voice/integrations/getTtsConfig.js +5 -1
- package/dist/voice/integrations/makeCreateContainer.js +1 -1
- package/dist/voice/integrations/types.d.ts +1 -1
- package/dist/voice/makeCreateVoiceClient.js +4 -10
- package/dist/voice/makeGetChannelVar.d.ts +2 -1
- package/dist/voice/makeGetChannelVar.js +13 -0
- package/dist/voice/stt/AbstractSpeechToText.d.ts +4 -3
- package/dist/voice/stt/Deepgram.d.ts +18 -0
- package/dist/voice/stt/Deepgram.js +156 -0
- package/dist/voice/stt/Google.d.ts +5 -6
- package/dist/voice/stt/Google.js +13 -13
- package/dist/voice/stt/SpeechToTextFactory.js +2 -0
- package/dist/voice/stt/types.d.ts +22 -10
- package/dist/voice/stt/types.js +7 -0
- package/dist/voice/tts/Deepgram.d.ts +25 -0
- package/dist/voice/tts/Deepgram.js +122 -0
- package/dist/voice/tts/Google.d.ts +2 -1
- package/dist/voice/tts/Google.js +7 -8
- package/dist/voice/tts/TextToSpeechFactory.js +2 -0
- package/dist/voice/types/ari.d.ts +2 -1
- package/dist/voice/types/ari.js +1 -0
- package/dist/voice/types/voice.d.ts +9 -1
- package/package.json +10 -9
- package/dist/calls/createTrackCallSubscriber.d.ts +0 -5
- package/dist/calls/createTrackCallSubscriber.js +0 -52
- package/dist/calls/trackCall.js +0 -63
- package/dist/voice/handlers/StasisEnd.d.ts +0 -4
- package/dist/voice/handlers/dial/handleDialEvents.d.ts +0 -5
- /package/dist/voice/handlers/{awaitForPlaybackFinished.d.ts → utils/awaitForPlaybackFinished.d.ts} +0 -0
- /package/dist/voice/handlers/{awaitForRecordingFinished.d.ts → utils/awaitForRecordingFinished.d.ts} +0 -0
- /package/dist/voice/handlers/{withErrorHandling.d.ts → utils/withErrorHandling.d.ts} +0 -0
- /package/dist/voice/handlers/{withErrorHandling.js → utils/withErrorHandling.js} +0 -0
|
@@ -67,26 +67,27 @@ class VoiceClientImpl {
|
|
|
67
67
|
constructor(params) {
|
|
68
68
|
const { config, tts, stt, ari } = params;
|
|
69
69
|
this.config = config;
|
|
70
|
-
this.
|
|
70
|
+
this.verbsStream = new stream_1.Stream();
|
|
71
|
+
this.transcriptionsStream = new stream_1.Stream();
|
|
71
72
|
this.tts = tts;
|
|
72
73
|
this.stt = stt;
|
|
73
74
|
this.ari = ari;
|
|
74
75
|
}
|
|
75
76
|
connect() {
|
|
76
77
|
return __awaiter(this, void 0, void 0, function* () {
|
|
77
|
-
this.grpcClient = new VoiceServiceClientConst_1.VoiceServiceClient(this.config.
|
|
78
|
+
this.grpcClient = new VoiceServiceClientConst_1.VoiceServiceClient(this.config.endpoint, grpc.credentials.createInsecure());
|
|
78
79
|
const metadata = new grpc.Metadata();
|
|
79
80
|
metadata.add("accessKeyId", this.config.accessKeyId);
|
|
80
81
|
metadata.add("token", this.config.sessionToken);
|
|
81
82
|
this.voice = this.grpcClient.createSession(metadata);
|
|
82
83
|
this.voice.on(common_1.StreamEvent.DATA, (data) => {
|
|
83
|
-
this.
|
|
84
|
+
this.verbsStream.emit(data.content, data);
|
|
84
85
|
});
|
|
85
86
|
this.voice.write({ request: this.config });
|
|
86
87
|
this.voice.on(common_1.StreamEvent.ERROR, (error) => {
|
|
87
88
|
if (error.code === grpc.status.UNAVAILABLE) {
|
|
88
89
|
// FIXME: This error should be sent back to the user
|
|
89
|
-
logger.error(`voice server not available at "${this.config.
|
|
90
|
+
logger.error(`voice server not available at "${this.config.endpoint}"`);
|
|
90
91
|
return;
|
|
91
92
|
}
|
|
92
93
|
logger.error(error.message);
|
|
@@ -98,7 +99,7 @@ class VoiceClientImpl {
|
|
|
98
99
|
}
|
|
99
100
|
setupAudioSocket(port) {
|
|
100
101
|
this.audioSocket = new streams_1.AudioSocket();
|
|
101
|
-
this.audioSocket.onConnection((0, transcribeOnConnection_1.transcribeOnConnection)(this.
|
|
102
|
+
this.audioSocket.onConnection((0, transcribeOnConnection_1.transcribeOnConnection)(this.transcriptionsStream));
|
|
102
103
|
this.audioSocket.listen(port, () => {
|
|
103
104
|
logger.verbose("starting audio socket for voice client", {
|
|
104
105
|
port,
|
|
@@ -118,10 +119,22 @@ class VoiceClientImpl {
|
|
|
118
119
|
});
|
|
119
120
|
yield channel.answer();
|
|
120
121
|
}));
|
|
122
|
+
channel.once("ChannelLeftBridge", () => __awaiter(this, void 0, void 0, function* () {
|
|
123
|
+
// TODO: Evaluate a better way to handle this
|
|
124
|
+
// We should keep track of the channels and bridges and destroy them
|
|
125
|
+
// even if the apiserver crashes. Otherwise we risk having a lot of
|
|
126
|
+
// unused channels and bridges.
|
|
127
|
+
try {
|
|
128
|
+
yield bridge.destroy();
|
|
129
|
+
}
|
|
130
|
+
catch (e) {
|
|
131
|
+
// We can only try
|
|
132
|
+
}
|
|
133
|
+
}));
|
|
121
134
|
});
|
|
122
135
|
}
|
|
123
136
|
on(type, callback) {
|
|
124
|
-
this.
|
|
137
|
+
this.verbsStream.on(type.toString(), (data) => {
|
|
125
138
|
callback(data[type]);
|
|
126
139
|
});
|
|
127
140
|
}
|
|
@@ -136,7 +149,7 @@ class VoiceClientImpl {
|
|
|
136
149
|
transcribe() {
|
|
137
150
|
return __awaiter(this, void 0, void 0, function* () {
|
|
138
151
|
try {
|
|
139
|
-
return yield this.stt.transcribe(this.
|
|
152
|
+
return yield this.stt.transcribe(this.transcriptionsStream);
|
|
140
153
|
}
|
|
141
154
|
catch (e) {
|
|
142
155
|
logger.warn("transcription error", e);
|
|
@@ -144,6 +157,32 @@ class VoiceClientImpl {
|
|
|
144
157
|
}
|
|
145
158
|
});
|
|
146
159
|
}
|
|
160
|
+
startSpeechGather(callback) {
|
|
161
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
162
|
+
try {
|
|
163
|
+
const out = this.stt.streamTranscribe(this.transcriptionsStream);
|
|
164
|
+
out.on("data", callback);
|
|
165
|
+
}
|
|
166
|
+
catch (e) {
|
|
167
|
+
logger.error(e);
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
startDtmfGather(sessionRef, callback) {
|
|
172
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
173
|
+
const channel = yield this.ari.channels.get({ channelId: sessionRef });
|
|
174
|
+
channel.on(types_1.AriEvent.CHANNEL_DTMF_RECEIVED, (event) => {
|
|
175
|
+
const { digit } = event;
|
|
176
|
+
callback({ digit });
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
// Stops both speech and dtmf gather
|
|
181
|
+
stopStreamGather() {
|
|
182
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
183
|
+
throw new Error("Method 'stopStreamGather' not implemented.");
|
|
184
|
+
});
|
|
185
|
+
}
|
|
147
186
|
waitForDtmf(params) {
|
|
148
187
|
return __awaiter(this, void 0, void 0, function* () {
|
|
149
188
|
const { onDigitReceived, sessionRef, finishOnKey, maxDigits, timeout } = params;
|
|
@@ -181,6 +220,7 @@ class VoiceClientImpl {
|
|
|
181
220
|
}
|
|
182
221
|
close() {
|
|
183
222
|
try {
|
|
223
|
+
this.voice.end();
|
|
184
224
|
this.grpcClient.close();
|
|
185
225
|
this.audioSocket.close();
|
|
186
226
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Channel, Client, StasisStart } from "ari-client";
|
|
1
|
+
import { Channel, Client, Dial, StasisStart } from "ari-client";
|
|
2
|
+
import { NatsConnection } from "nats";
|
|
2
3
|
import { VoiceClient } from "./types";
|
|
3
4
|
type CreateVoiceClient = (params: {
|
|
4
5
|
ari: Client;
|
|
@@ -8,10 +9,13 @@ type CreateVoiceClient = (params: {
|
|
|
8
9
|
declare class VoiceDispatcher {
|
|
9
10
|
voiceClients: Map<string, VoiceClient>;
|
|
10
11
|
ari: Client;
|
|
12
|
+
nc: NatsConnection;
|
|
11
13
|
createVoiceClient: CreateVoiceClient;
|
|
12
|
-
constructor(ari: Client, createVoiceClient: CreateVoiceClient);
|
|
14
|
+
constructor(ari: Client, nc: NatsConnection, createVoiceClient: CreateVoiceClient);
|
|
13
15
|
start(): void;
|
|
14
16
|
handleStasisStart(event: StasisStart, channel: Channel): Promise<void>;
|
|
15
17
|
handleStasisEnd(_: undefined, channel: Channel): void;
|
|
18
|
+
handleDial(event: Dial, channel: Channel): Promise<void>;
|
|
19
|
+
isHandledElsewhere(channel: Channel): Promise<boolean>;
|
|
16
20
|
}
|
|
17
21
|
export { VoiceDispatcher };
|
|
@@ -30,58 +30,59 @@ exports.VoiceDispatcher = void 0;
|
|
|
30
30
|
*/
|
|
31
31
|
const common_1 = require("@fonoster/common");
|
|
32
32
|
const logger_1 = require("@fonoster/logger");
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
const Gather_1 = require("./handlers/gather/Gather");
|
|
36
|
-
const Hangup_1 = require("./handlers/Hangup");
|
|
37
|
-
const Mute_1 = require("./handlers/Mute");
|
|
38
|
-
const Play_1 = require("./handlers/Play");
|
|
39
|
-
const PlaybackControl_1 = require("./handlers/PlaybackControl");
|
|
40
|
-
const PlayDtmf_1 = require("./handlers/PlayDtmf");
|
|
41
|
-
const Say_1 = require("./handlers/Say");
|
|
42
|
-
const Unmute_1 = require("./handlers/Unmute");
|
|
33
|
+
const handlers_1 = require("./handlers");
|
|
34
|
+
const makeGetChannelVar_1 = require("./makeGetChannelVar");
|
|
43
35
|
const types_1 = require("./types");
|
|
36
|
+
const utils_1 = require("../utils");
|
|
44
37
|
const logger = (0, logger_1.getLogger)({ service: "apiserver", filePath: __filename });
|
|
45
38
|
class VoiceDispatcher {
|
|
46
|
-
constructor(ari, createVoiceClient) {
|
|
39
|
+
constructor(ari, nc, createVoiceClient) {
|
|
47
40
|
this.ari = ari;
|
|
41
|
+
this.nc = nc;
|
|
48
42
|
this.voiceClients = new Map();
|
|
49
43
|
this.createVoiceClient = createVoiceClient;
|
|
50
44
|
}
|
|
51
45
|
start() {
|
|
52
46
|
// Initialize the ARI client
|
|
53
|
-
this
|
|
54
|
-
|
|
55
|
-
|
|
47
|
+
const { ari, handleStasisStart, handleStasisEnd, handleDial } = this;
|
|
48
|
+
ari.start(common_1.STASIS_APP_NAME);
|
|
49
|
+
ari.on(types_1.AriEvent.STASIS_START, handleStasisStart.bind(this));
|
|
50
|
+
ari.on(types_1.AriEvent.STASIS_END, handleStasisEnd.bind(this));
|
|
51
|
+
ari.on(types_1.AriEvent.DIAL, handleDial.bind(this));
|
|
56
52
|
}
|
|
57
53
|
handleStasisStart(event, channel) {
|
|
58
54
|
return __awaiter(this, void 0, void 0, function* () {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
55
|
+
var _a;
|
|
56
|
+
const { ari, voiceClients, createVoiceClient, isHandledElsewhere } = this;
|
|
57
|
+
const getChannelVar = (0, makeGetChannelVar_1.makeGetChannelVarWithoutThrow)(channel);
|
|
58
|
+
const appRef = (_a = (yield getChannelVar(types_1.ChannelVar.APP_REF))) === null || _a === void 0 ? void 0 : _a.value;
|
|
59
|
+
// This check feels strange but is necessary as ARI calls this event twice
|
|
60
|
+
if (!appRef) {
|
|
61
|
+
logger.silly("no appRef found, ignoring handleStasisStart event");
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (yield isHandledElsewhere(channel)) {
|
|
64
65
|
return;
|
|
65
66
|
}
|
|
66
67
|
try {
|
|
67
|
-
const vc = yield
|
|
68
|
-
ari: this.ari,
|
|
69
|
-
event,
|
|
70
|
-
channel
|
|
71
|
-
});
|
|
68
|
+
const vc = yield createVoiceClient({ ari, event, channel });
|
|
72
69
|
// Connect to voice server
|
|
73
70
|
vc.connect();
|
|
74
|
-
|
|
75
|
-
vc.on(common_1.StreamContent.ANSWER_REQUEST, (0,
|
|
76
|
-
vc.on(common_1.StreamContent.HANGUP_REQUEST, (0,
|
|
77
|
-
vc.on(common_1.StreamContent.MUTE_REQUEST, (0,
|
|
78
|
-
vc.on(common_1.StreamContent.UNMUTE_REQUEST, (0,
|
|
79
|
-
vc.on(common_1.StreamContent.PLAY_REQUEST, (0,
|
|
80
|
-
vc.on(common_1.StreamContent.PLAY_DTMF_REQUEST, (0,
|
|
81
|
-
vc.on(common_1.StreamContent.
|
|
82
|
-
vc.on(common_1.StreamContent.
|
|
83
|
-
vc.on(common_1.StreamContent.
|
|
84
|
-
vc.on(common_1.StreamContent.
|
|
71
|
+
voiceClients.set(channel.id, vc);
|
|
72
|
+
vc.on(common_1.StreamContent.ANSWER_REQUEST, (0, handlers_1.answerHandler)(ari, vc).bind(this));
|
|
73
|
+
vc.on(common_1.StreamContent.HANGUP_REQUEST, (0, handlers_1.hangupHandler)(ari, vc).bind(this));
|
|
74
|
+
vc.on(common_1.StreamContent.MUTE_REQUEST, (0, handlers_1.muteHandler)(ari, vc).bind(this));
|
|
75
|
+
vc.on(common_1.StreamContent.UNMUTE_REQUEST, (0, handlers_1.unmuteHandler)(ari, vc).bind(this));
|
|
76
|
+
vc.on(common_1.StreamContent.PLAY_REQUEST, (0, handlers_1.playHandler)(ari, vc).bind(this));
|
|
77
|
+
vc.on(common_1.StreamContent.PLAY_DTMF_REQUEST, (0, handlers_1.playDtmfHandler)(ari, vc).bind(this));
|
|
78
|
+
vc.on(common_1.StreamContent.SAY_REQUEST, (0, handlers_1.sayHandler)(ari, vc).bind(this));
|
|
79
|
+
vc.on(common_1.StreamContent.GATHER_REQUEST, (0, handlers_1.gatherHandler)(vc).bind(this));
|
|
80
|
+
vc.on(common_1.StreamContent.DIAL_REQUEST, (0, handlers_1.dialHandler)(ari, vc).bind(this));
|
|
81
|
+
vc.on(common_1.StreamContent.PLAYBACK_CONTROL_REQUEST, (0, handlers_1.playbackControlHandler)(ari, vc).bind(this));
|
|
82
|
+
vc.on(common_1.StreamContent.START_STREAM_GATHER_REQUEST, (0, handlers_1.streamGatherHandler)(vc).bind(this));
|
|
83
|
+
vc.on(common_1.StreamContent.STOP_STREAM_GATHER_REQUEST, () => {
|
|
84
|
+
vc.stopStreamGather();
|
|
85
|
+
});
|
|
85
86
|
}
|
|
86
87
|
catch (err) {
|
|
87
88
|
logger.error("error handling stasis start", { error: err.message });
|
|
@@ -89,11 +90,23 @@ class VoiceDispatcher {
|
|
|
89
90
|
});
|
|
90
91
|
}
|
|
91
92
|
handleStasisEnd(_, channel) {
|
|
92
|
-
const
|
|
93
|
+
const { voiceClients } = this;
|
|
94
|
+
const voiceClient = voiceClients.get(channel.id);
|
|
93
95
|
if (voiceClient) {
|
|
94
96
|
voiceClient.close();
|
|
95
|
-
|
|
97
|
+
voiceClients.delete(channel.id);
|
|
96
98
|
}
|
|
97
99
|
}
|
|
100
|
+
handleDial(event, channel) {
|
|
101
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
102
|
+
(0, utils_1.makeHandleDialEventsWithNats)(this.nc)(channel.id, event);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
isHandledElsewhere(channel) {
|
|
106
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
107
|
+
var _a;
|
|
108
|
+
return (((_a = (yield (0, makeGetChannelVar_1.makeGetChannelVarWithoutThrow)(channel)(types_1.ChannelVar.FROM_EXTERNAL_MEDIA))) === null || _a === void 0 ? void 0 : _a.value) === "true");
|
|
109
|
+
});
|
|
110
|
+
}
|
|
98
111
|
}
|
|
99
112
|
exports.VoiceDispatcher = VoiceDispatcher;
|
|
@@ -33,6 +33,7 @@ exports.connectToAri = connectToAri;
|
|
|
33
33
|
*/
|
|
34
34
|
const logger_1 = require("@fonoster/logger");
|
|
35
35
|
const ari_client_1 = __importDefault(require("ari-client"));
|
|
36
|
+
const nats_1 = require("nats");
|
|
36
37
|
const wait_port_1 = __importDefault(require("wait-port"));
|
|
37
38
|
const integrations_1 = require("./integrations");
|
|
38
39
|
const makeCreateVoiceClient_1 = require("./makeCreateVoiceClient");
|
|
@@ -62,7 +63,8 @@ function connectToAri() {
|
|
|
62
63
|
});
|
|
63
64
|
logger.info("asterisk is ready");
|
|
64
65
|
const createContainer = (0, integrations_1.makeCreateContainer)(db_1.prisma, envs_1.INTEGRATIONS_FILE);
|
|
65
|
-
const
|
|
66
|
+
const nats = yield (0, nats_1.connect)({ servers: envs_1.NATS_URL });
|
|
67
|
+
const dispatcher = new VoiceDispatcher_1.VoiceDispatcher(ari, nats, (0, makeCreateVoiceClient_1.makeCreateVoiceClient)(createContainer));
|
|
66
68
|
dispatcher.start();
|
|
67
69
|
}
|
|
68
70
|
else {
|
|
@@ -10,7 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.answerHandler = answerHandler;
|
|
13
|
-
const withErrorHandling_1 = require("./withErrorHandling");
|
|
13
|
+
const withErrorHandling_1 = require("./utils/withErrorHandling");
|
|
14
14
|
function answerHandler(ari, voiceClient) {
|
|
15
15
|
return (0, withErrorHandling_1.withErrorHandling)((request) => __awaiter(this, void 0, void 0, function* () {
|
|
16
16
|
const { sessionRef } = request;
|
|
@@ -10,7 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.hangupHandler = hangupHandler;
|
|
13
|
-
const withErrorHandling_1 = require("./withErrorHandling");
|
|
13
|
+
const withErrorHandling_1 = require("./utils/withErrorHandling");
|
|
14
14
|
function hangupHandler(ari, voiceClient) {
|
|
15
15
|
return (0, withErrorHandling_1.withErrorHandling)((request) => __awaiter(this, void 0, void 0, function* () {
|
|
16
16
|
const { sessionRef } = request;
|
|
@@ -10,7 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.muteHandler = muteHandler;
|
|
13
|
-
const withErrorHandling_1 = require("./withErrorHandling");
|
|
13
|
+
const withErrorHandling_1 = require("./utils/withErrorHandling");
|
|
14
14
|
function muteHandler(ari, voiceClient) {
|
|
15
15
|
return (0, withErrorHandling_1.withErrorHandling)((request) => __awaiter(this, void 0, void 0, function* () {
|
|
16
16
|
const { sessionRef, direction } = request;
|
|
@@ -11,8 +11,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.playHandler = playHandler;
|
|
13
13
|
const nanoid_1 = require("nanoid");
|
|
14
|
-
const awaitForPlaybackFinished_1 = require("./awaitForPlaybackFinished");
|
|
15
|
-
const withErrorHandling_1 = require("./withErrorHandling");
|
|
14
|
+
const awaitForPlaybackFinished_1 = require("./utils/awaitForPlaybackFinished");
|
|
15
|
+
const withErrorHandling_1 = require("./utils/withErrorHandling");
|
|
16
16
|
function playHandler(ari, voiceClient) {
|
|
17
17
|
return (0, withErrorHandling_1.withErrorHandling)((request) => __awaiter(this, void 0, void 0, function* () {
|
|
18
18
|
const { sessionRef } = request;
|
|
@@ -10,7 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.playDtmfHandler = playDtmfHandler;
|
|
13
|
-
const withErrorHandling_1 = require("./withErrorHandling");
|
|
13
|
+
const withErrorHandling_1 = require("./utils/withErrorHandling");
|
|
14
14
|
function playDtmfHandler(ari, voiceClient) {
|
|
15
15
|
return (0, withErrorHandling_1.withErrorHandling)((request) => __awaiter(this, void 0, void 0, function* () {
|
|
16
16
|
const { sessionRef, digits } = request;
|
|
@@ -10,7 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.playbackControlHandler = playbackControlHandler;
|
|
13
|
-
const withErrorHandling_1 = require("./withErrorHandling");
|
|
13
|
+
const withErrorHandling_1 = require("./utils/withErrorHandling");
|
|
14
14
|
function playbackControlHandler(ari, voiceClient) {
|
|
15
15
|
return (0, withErrorHandling_1.withErrorHandling)((playbackControlReq) => __awaiter(this, void 0, void 0, function* () {
|
|
16
16
|
const { sessionRef, playbackRef, action } = playbackControlReq;
|
|
@@ -30,8 +30,8 @@ exports.recordHandler = recordHandler;
|
|
|
30
30
|
*/
|
|
31
31
|
const common_1 = require("@fonoster/common");
|
|
32
32
|
const nanoid_1 = require("nanoid");
|
|
33
|
-
const awaitForRecordingFinished_1 = require("./awaitForRecordingFinished");
|
|
34
|
-
const withErrorHandling_1 = require("./withErrorHandling");
|
|
33
|
+
const awaitForRecordingFinished_1 = require("./utils/awaitForRecordingFinished");
|
|
34
|
+
const withErrorHandling_1 = require("./utils/withErrorHandling");
|
|
35
35
|
function recordHandler(ari, voiceClient) {
|
|
36
36
|
return (0, withErrorHandling_1.withErrorHandling)((request) => __awaiter(this, void 0, void 0, function* () {
|
|
37
37
|
const { sessionRef, maxDuration, maxSilence, beep, finishOnKey } = request;
|
|
@@ -13,8 +13,8 @@ exports.sayHandler = sayHandler;
|
|
|
13
13
|
const nanoid_1 = require("nanoid");
|
|
14
14
|
const pb_util_1 = require("pb-util");
|
|
15
15
|
const zod_1 = require("zod");
|
|
16
|
-
const awaitForPlaybackFinished_1 = require("./awaitForPlaybackFinished");
|
|
17
|
-
const withErrorHandling_1 = require("./withErrorHandling");
|
|
16
|
+
const awaitForPlaybackFinished_1 = require("./utils/awaitForPlaybackFinished");
|
|
17
|
+
const withErrorHandling_1 = require("./utils/withErrorHandling");
|
|
18
18
|
const envs_1 = require("../../envs");
|
|
19
19
|
const sayRequestSchema = zod_1.z.object({
|
|
20
20
|
text: zod_1.z.string(),
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.streamGatherHandler = streamGatherHandler;
|
|
13
|
+
/*
|
|
14
|
+
* Copyright (C) 2024 by Fonoster Inc (https://fonoster.com)
|
|
15
|
+
* http://github.com/fonoster/fonoster
|
|
16
|
+
*
|
|
17
|
+
* This file is part of Fonoster
|
|
18
|
+
*
|
|
19
|
+
* Licensed under the MIT License (the "License");
|
|
20
|
+
* you may not use this file except in compliance with
|
|
21
|
+
* the License. You may obtain a copy of the License at
|
|
22
|
+
*
|
|
23
|
+
* https://opensource.org/licenses/MIT
|
|
24
|
+
*
|
|
25
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
26
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
27
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
28
|
+
* See the License for the specific language governing permissions and
|
|
29
|
+
* limitations under the License.
|
|
30
|
+
*/
|
|
31
|
+
const common_1 = require("@fonoster/common");
|
|
32
|
+
const zod_1 = require("zod");
|
|
33
|
+
const withErrorHandling_1 = require("./utils/withErrorHandling");
|
|
34
|
+
const gatherRequestSchema = zod_1.z.object({
|
|
35
|
+
source: zod_1.z.optional(zod_1.z.nativeEnum(common_1.StreamGatherSource))
|
|
36
|
+
});
|
|
37
|
+
function streamGatherHandler(voiceClient) {
|
|
38
|
+
return (0, withErrorHandling_1.withErrorHandling)((request) => __awaiter(this, void 0, void 0, function* () {
|
|
39
|
+
const { sessionRef, source } = request;
|
|
40
|
+
// Error handled by withErrorHandling
|
|
41
|
+
gatherRequestSchema.parse(request);
|
|
42
|
+
const effectiveSource = source || common_1.StreamGatherSource.SPEECH_AND_DTMF;
|
|
43
|
+
if (effectiveSource.includes(common_1.StreamGatherSource.DTMF)) {
|
|
44
|
+
voiceClient.startDtmfGather(sessionRef, (event) => {
|
|
45
|
+
const { digit } = event;
|
|
46
|
+
voiceClient.sendResponse({
|
|
47
|
+
streamGatherPayload: {
|
|
48
|
+
sessionRef,
|
|
49
|
+
digit
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
if (effectiveSource.includes(common_1.StreamGatherSource.SPEECH)) {
|
|
55
|
+
voiceClient.startSpeechGather((event) => {
|
|
56
|
+
const { speech } = event;
|
|
57
|
+
voiceClient.sendResponse({
|
|
58
|
+
streamGatherPayload: {
|
|
59
|
+
sessionRef,
|
|
60
|
+
speech
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}));
|
|
66
|
+
}
|
|
@@ -10,7 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.unmuteHandler = unmuteHandler;
|
|
13
|
-
const withErrorHandling_1 = require("./withErrorHandling");
|
|
13
|
+
const withErrorHandling_1 = require("./utils/withErrorHandling");
|
|
14
14
|
function unmuteHandler(ari, voiceClient) {
|
|
15
15
|
return (0, withErrorHandling_1.withErrorHandling)((request) => __awaiter(this, void 0, void 0, function* () {
|
|
16
16
|
const { sessionRef, direction } = request;
|
|
@@ -29,11 +29,12 @@ exports.dialHandler = dialHandler;
|
|
|
29
29
|
* limitations under the License.
|
|
30
30
|
*/
|
|
31
31
|
const common_1 = require("@fonoster/common");
|
|
32
|
+
const uuid_1 = require("uuid");
|
|
32
33
|
const handleChannelLeftBridge_1 = require("./handleChannelLeftBridge");
|
|
33
|
-
const handleDialEvents_1 = require("./handleDialEvents");
|
|
34
34
|
const handleStasisEnd_1 = require("./handleStasisEnd");
|
|
35
35
|
const handleStasisStart_1 = require("./handleStasisStart");
|
|
36
36
|
const envs_1 = require("../../../envs");
|
|
37
|
+
const utils_1 = require("../../../utils");
|
|
37
38
|
const makeGetChannelVar_1 = require("../../makeGetChannelVar");
|
|
38
39
|
const types_1 = require("../../types");
|
|
39
40
|
// TODO: Needs request validation
|
|
@@ -50,18 +51,21 @@ function dialHandler(ari, voiceClient) {
|
|
|
50
51
|
const getChannelVar = (0, makeGetChannelVar_1.makeGetChannelVar)(callerChannel);
|
|
51
52
|
const ingressNumber = (yield getChannelVar(types_1.ChannelVar.INGRESS_NUMBER))
|
|
52
53
|
.value;
|
|
54
|
+
const ref = (0, uuid_1.v4)();
|
|
53
55
|
yield dialed.originate({
|
|
54
56
|
app: common_1.STASIS_APP_NAME,
|
|
55
57
|
endpoint: `PJSIP/${envs_1.ASTERISK_TRUNK}/sip:${destination}@${envs_1.ASTERISK_SYSTEM_DOMAIN}`,
|
|
56
58
|
timeout,
|
|
57
59
|
variables: {
|
|
58
|
-
"PJSIP_HEADER(add,X-
|
|
60
|
+
"PJSIP_HEADER(add,X-Call-Ref)": ref,
|
|
61
|
+
"PJSIP_HEADER(add,X-Dod-Number)": ingressNumber,
|
|
62
|
+
"PJSIP_HEADER(add,X-Is-Api-Originated-Type)": "true"
|
|
59
63
|
}
|
|
60
64
|
});
|
|
61
|
-
dialed.
|
|
62
|
-
dialed.
|
|
63
|
-
dialed.
|
|
64
|
-
dialed.on(types_1.AriEvent.DIAL, (0,
|
|
65
|
+
dialed.once(types_1.AriEvent.STASIS_START, (0, handleStasisStart_1.handleStasisStart)({ ari, request, bridge, dialed }));
|
|
66
|
+
dialed.once(types_1.AriEvent.CHANNEL_LEFT_BRIDGE, (0, handleChannelLeftBridge_1.handleChannelLeftBridge)({ bridge, dialed }));
|
|
67
|
+
dialed.once(types_1.AriEvent.STASIS_END, (0, handleStasisEnd_1.handleStasisEnd)(request));
|
|
68
|
+
dialed.on(types_1.AriEvent.DIAL, (0, utils_1.makeHandleDialEventsWithVoiceClient)(voiceClient));
|
|
65
69
|
voiceClient.sendResponse({
|
|
66
70
|
dialResponse: {
|
|
67
71
|
status: common_1.DialStatus.TRYING
|
|
@@ -31,9 +31,10 @@ exports.gatherHandler = gatherHandler;
|
|
|
31
31
|
const common_1 = require("@fonoster/common");
|
|
32
32
|
const zod_1 = require("zod");
|
|
33
33
|
const getTimeoutPromise_1 = require("./getTimeoutPromise");
|
|
34
|
-
const
|
|
35
|
-
const
|
|
34
|
+
const utils_1 = require("../utils");
|
|
35
|
+
const withErrorHandling_1 = require("../utils/withErrorHandling");
|
|
36
36
|
const gatherRequestSchema = zod_1.z.object({
|
|
37
|
+
source: zod_1.z.optional(zod_1.z.nativeEnum(common_1.GatherSource)),
|
|
37
38
|
maxDigits: zod_1.z.number().optional().nullable(),
|
|
38
39
|
// TODO: Ensure it is a dtmf character
|
|
39
40
|
finishOnKey: zod_1.z.string().max(1).optional().nullable()
|
|
@@ -64,8 +65,8 @@ function gatherHandler(voiceClient) {
|
|
|
64
65
|
voiceClient.sendResponse({
|
|
65
66
|
gatherResponse: {
|
|
66
67
|
sessionRef,
|
|
67
|
-
speech: isDtmf(result) ? null : result,
|
|
68
|
-
digits: isDtmf(result) ? result : null
|
|
68
|
+
speech: (0, utils_1.isDtmf)(result) ? null : result,
|
|
69
|
+
digits: (0, utils_1.isDtmf)(result) ? result : null
|
|
69
70
|
}
|
|
70
71
|
});
|
|
71
72
|
}));
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from "./Answer";
|
|
2
|
+
export * from "./Hangup";
|
|
3
|
+
export * from "./Mute";
|
|
4
|
+
export * from "./Unmute";
|
|
5
|
+
export * from "./dial/Dial";
|
|
6
|
+
export * from "./gather/Gather";
|
|
7
|
+
export * from "./StreamGather";
|
|
8
|
+
export * from "./Play";
|
|
9
|
+
export * from "./PlaybackControl";
|
|
10
|
+
export * from "./PlayDtmf";
|
|
11
|
+
export * from "./Record";
|
|
12
|
+
export * from "./Say";
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
/*
|
|
18
|
+
* Copyright (C) 2024 by Fonoster Inc (https://fonoster.com)
|
|
19
|
+
* http://github.com/fonoster/fonoster
|
|
20
|
+
*
|
|
21
|
+
* This file is part of Fonoster
|
|
22
|
+
*
|
|
23
|
+
* Licensed under the MIT License (the "License");
|
|
24
|
+
* you may not use this file except in compliance with
|
|
25
|
+
* the License. You may obtain a copy of the License at
|
|
26
|
+
*
|
|
27
|
+
* https://opensource.org/licenses/MIT
|
|
28
|
+
*
|
|
29
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
30
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
31
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
32
|
+
* See the License for the specific language governing permissions and
|
|
33
|
+
* limitations under the License.
|
|
34
|
+
*/
|
|
35
|
+
__exportStar(require("./Answer"), exports);
|
|
36
|
+
__exportStar(require("./Hangup"), exports);
|
|
37
|
+
__exportStar(require("./Mute"), exports);
|
|
38
|
+
__exportStar(require("./Unmute"), exports);
|
|
39
|
+
__exportStar(require("./dial/Dial"), exports);
|
|
40
|
+
__exportStar(require("./gather/Gather"), exports);
|
|
41
|
+
__exportStar(require("./StreamGather"), exports);
|
|
42
|
+
__exportStar(require("./Play"), exports);
|
|
43
|
+
__exportStar(require("./PlaybackControl"), exports);
|
|
44
|
+
__exportStar(require("./PlayDtmf"), exports);
|
|
45
|
+
__exportStar(require("./Record"), exports);
|
|
46
|
+
__exportStar(require("./Say"), exports);
|
package/dist/voice/handlers/{awaitForPlaybackFinished.js → utils/awaitForPlaybackFinished.js}
RENAMED
|
@@ -10,7 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.awaitForPlaybackFinished = void 0;
|
|
13
|
-
const types_1 = require("
|
|
13
|
+
const types_1 = require("../../types");
|
|
14
14
|
const awaitForPlaybackFinished = (ari, playbackRef) => __awaiter(void 0, void 0, void 0, function* () {
|
|
15
15
|
return new Promise((resolve) => {
|
|
16
16
|
const listener = (_, playback) => {
|
package/dist/voice/handlers/{awaitForRecordingFinished.js → utils/awaitForRecordingFinished.js}
RENAMED
|
@@ -30,7 +30,7 @@ exports.awaitForRecordingFinished = awaitForRecordingFinished;
|
|
|
30
30
|
*/
|
|
31
31
|
const common_1 = require("@fonoster/common");
|
|
32
32
|
const grpc_js_1 = require("@grpc/grpc-js");
|
|
33
|
-
const types_1 = require("
|
|
33
|
+
const types_1 = require("../../types");
|
|
34
34
|
function awaitForRecordingFinished(ari, name) {
|
|
35
35
|
return __awaiter(this, void 0, void 0, function* () {
|
|
36
36
|
return new Promise((resolve, reject) => {
|