@absolutejs/voice 0.0.22-beta.81 → 0.0.22-beta.83
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/index.d.ts +6 -4
- package/dist/index.js +412 -2
- package/dist/openaiTTS.d.ts +18 -0
- package/dist/telephony/plivo.d.ts +101 -1
- package/dist/telephony/telnyx.d.ts +109 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export { applyVoiceTelephonyOutcome, createMemoryVoiceTelephonyWebhookIdempotenc
|
|
|
15
15
|
export { createStoredVoiceCallReviewArtifact, createStoredVoiceExternalObjectMap, createStoredVoiceIntegrationEvent, createStoredVoiceOpsTask, createVoiceFileExternalObjectMapStore, createVoiceFileAssistantMemoryStore, createVoiceFileIntegrationEventStore, createVoiceFileReviewStore, createVoiceFileRuntimeStorage, createVoiceFileSessionStore, createVoiceFileTaskStore, createVoiceFileTraceSinkDeliveryStore, createVoiceFileTraceEventStore } from './fileStore';
|
|
16
16
|
export { createVoiceAssistantMemoryHandle, createVoiceAssistantMemoryRecord, createVoiceMemoryAssistantMemoryStore, resolveVoiceAssistantMemoryNamespace } from './assistantMemory';
|
|
17
17
|
export { createAnthropicVoiceAssistantModel, createGeminiVoiceAssistantModel, createJSONVoiceAssistantModel, createOpenAIVoiceAssistantModel, resolveVoiceProviderRoutingPolicyPreset, createVoiceProviderRouter } from './modelAdapters';
|
|
18
|
+
export { createOpenAIVoiceTTS } from './openaiTTS';
|
|
18
19
|
export { createVoiceProviderHealthHTMLHandler, createVoiceProviderHealthJSONHandler, createVoiceProviderHealthRoutes, renderVoiceProviderHealthHTML, summarizeVoiceProviderHealth } from './providerHealth';
|
|
19
20
|
export { createVoiceProviderCapabilityHTMLHandler, createVoiceProviderCapabilityJSONHandler, createVoiceProviderCapabilityRoutes, renderVoiceProviderCapabilityHTML, summarizeVoiceProviderCapabilities } from './providerCapabilities';
|
|
20
21
|
export { buildVoiceOpsConsoleReport, createVoiceOpsConsoleRoutes, renderVoiceOpsConsoleHTML } from './opsConsoleRoutes';
|
|
@@ -53,6 +54,7 @@ export type { VoiceEvalBaselineComparison, VoiceEvalBaselineComparisonOptions, V
|
|
|
53
54
|
export type { VoiceWorkflowContract, VoiceWorkflowContractDefinition, VoiceWorkflowContractField, VoiceWorkflowContractFieldMatch, VoiceWorkflowContractPresetName, VoiceWorkflowContractPresetOptions, VoiceWorkflowContractTracePayload, VoiceWorkflowContractValidation, VoiceWorkflowContractValidationIssue, VoiceWorkflowOutcome } from './workflowContract';
|
|
54
55
|
export type { VoiceSessionListHTMLHandlerOptions, VoiceSessionListItem, VoiceSessionListOptions, VoiceSessionListRoutesOptions, VoiceSessionListStatus, VoiceSessionReplay, VoiceSessionReplayHTMLHandlerOptions, VoiceSessionReplayOptions, VoiceSessionReplayRoutesOptions, VoiceSessionReplayTurn } from './sessionReplay';
|
|
55
56
|
export type { AnthropicVoiceAssistantModelOptions, GeminiVoiceAssistantModelOptions, OpenAIVoiceAssistantModelOptions, VoiceProviderRouterEvent, VoiceProviderRouterFallbackMode, VoiceProviderRouterHealthOptions, VoiceProviderRouterOptions, VoiceProviderRouterPolicy, VoiceProviderRouterPolicyPreset, VoiceProviderRouterPolicyWeights, VoiceProviderRouterProviderHealth, VoiceProviderRouterProviderProfile, VoiceProviderRouterStrategy, VoiceJSONAssistantModelHandler, VoiceJSONAssistantModelOptions } from './modelAdapters';
|
|
57
|
+
export type { OpenAIVoiceTTSOptions, OpenAIVoiceTTSVoice } from './openaiTTS';
|
|
56
58
|
export type { VoiceProviderHealthStatus, VoiceProviderHealthSummary, VoiceProviderHealthSummaryOptions } from './providerHealth';
|
|
57
59
|
export type { VoiceProviderCapabilityDefinition, VoiceProviderCapabilityHandlerOptions, VoiceProviderCapabilityHTMLHandlerOptions, VoiceProviderCapabilityKind, VoiceProviderCapabilityOptions, VoiceProviderCapabilityReport, VoiceProviderCapabilityRoutesOptions, VoiceProviderCapabilitySummary } from './providerCapabilities';
|
|
58
60
|
export type { VoiceTurnQualityHTMLHandlerOptions, VoiceTurnQualityItem, VoiceTurnQualityOptions, VoiceTurnQualityReport, VoiceTurnQualityRoutesOptions, VoiceTurnQualityStatus } from './turnQuality';
|
|
@@ -82,13 +84,13 @@ export type { VoiceSQLiteRuntimeStorage, VoiceSQLiteStoreOptions } from './sqlit
|
|
|
82
84
|
export type { StoredVoiceIntegrationEvent, StoredVoiceExternalObjectMap, StoredVoiceOpsTask, VoiceExternalObjectMap, VoiceExternalObjectMapStore, VoiceOpsTaskAgeBucket, VoiceOpsTaskAnalyticsOptions, VoiceOpsTaskAnalyticsSummary, VoiceOpsTaskAssignmentRule, VoiceOpsTaskAssignmentRuleCondition, VoiceOpsTaskAssignmentRules, VoiceOpsTaskAssigneeAnalytics, VoiceOpsDispositionTaskPolicies, VoiceOpsSLABreachPolicy, VoiceIntegrationDeliveryStatus, VoiceIntegrationEvent, VoiceIntegrationEventStore, VoiceIntegrationSinkDelivery, VoiceIntegrationEventType, VoiceIntegrationWebhookConfig, VoiceOpsTask, VoiceOpsTaskHistoryEntry, VoiceOpsTaskKind, VoiceOpsTaskPolicy, VoiceOpsTaskPriority, VoiceOpsTaskStatus, VoiceOpsTaskStore, VoiceOpsTaskSummary, VoiceOpsTaskWorkerAnalytics } from './ops';
|
|
83
85
|
export { createTwilioMediaStreamBridge, createTwilioVoiceRoutes, createTwilioVoiceResponse, decodeTwilioMulawBase64, encodeTwilioMulawBase64, transcodePCMToTwilioOutboundPayload, transcodeTwilioInboundPayloadToPCM16 } from './telephony/twilio';
|
|
84
86
|
export { evaluateVoiceTelephonyContract } from './telephony/contract';
|
|
85
|
-
export { createTelnyxVoiceResponse, createTelnyxVoiceRoutes, verifyVoiceTelnyxWebhookSignature } from './telephony/telnyx';
|
|
86
|
-
export { createPlivoVoiceResponse, createPlivoVoiceRoutes, signVoicePlivoWebhook, verifyVoicePlivoWebhookSignature } from './telephony/plivo';
|
|
87
|
+
export { createTelnyxMediaStreamBridge, createTelnyxVoiceResponse, createTelnyxVoiceRoutes, verifyVoiceTelnyxWebhookSignature } from './telephony/telnyx';
|
|
88
|
+
export { createPlivoMediaStreamBridge, createPlivoVoiceResponse, createPlivoVoiceRoutes, signVoicePlivoWebhook, verifyVoicePlivoWebhookSignature } from './telephony/plivo';
|
|
87
89
|
export { createVoiceTelephonyCarrierMatrix, createVoiceTelephonyCarrierMatrixRoutes, renderVoiceTelephonyCarrierMatrixHTML } from './telephony/matrix';
|
|
88
90
|
export type { TwilioInboundMessage, TwilioMediaStreamBridge, TwilioMediaStreamBridgeOptions, TwilioMediaStreamSocket, TwilioOutboundClearMessage, TwilioOutboundMarkMessage, TwilioOutboundMediaMessage, TwilioOutboundMessage, TwilioVoiceRouteParameters, TwilioVoiceResponseOptions, TwilioVoiceSmokeCheck, TwilioVoiceSmokeOptions, TwilioVoiceSmokeReport, TwilioVoiceSetupOptions, TwilioVoiceSetupStatus, TwilioVoiceRoutesOptions } from './telephony/twilio';
|
|
89
91
|
export type { VoiceTelephonyContractIssue, VoiceTelephonyContractOptions, VoiceTelephonyContractReport, VoiceTelephonyContractRequirement, VoiceTelephonyProvider, VoiceTelephonySetupStatus, VoiceTelephonySmokeCheck, VoiceTelephonySmokeReport } from './telephony/contract';
|
|
90
|
-
export type { TelnyxVoiceResponseOptions, TelnyxVoiceRoutesOptions, TelnyxVoiceSetupOptions, TelnyxVoiceSetupStatus, TelnyxVoiceSmokeCheck, TelnyxVoiceSmokeOptions, TelnyxVoiceSmokeReport } from './telephony/telnyx';
|
|
91
|
-
export type { PlivoVoiceResponseOptions, PlivoVoiceRoutesOptions, PlivoVoiceSetupOptions, PlivoVoiceSetupStatus, PlivoVoiceSmokeCheck, PlivoVoiceSmokeOptions, PlivoVoiceSmokeReport } from './telephony/plivo';
|
|
92
|
+
export type { TelnyxInboundMessage, TelnyxMediaPayload, TelnyxMediaStreamBridge, TelnyxMediaStreamBridgeOptions, TelnyxMediaStreamSocket, TelnyxOutboundClearMessage, TelnyxOutboundMarkMessage, TelnyxOutboundMediaMessage, TelnyxOutboundMessage, TelnyxVoiceResponseOptions, TelnyxVoiceRoutesOptions, TelnyxVoiceSetupOptions, TelnyxVoiceSetupStatus, TelnyxVoiceSmokeCheck, TelnyxVoiceSmokeOptions, TelnyxVoiceSmokeReport } from './telephony/telnyx';
|
|
93
|
+
export type { PlivoInboundMessage, PlivoMediaStreamBridge, PlivoMediaStreamBridgeOptions, PlivoMediaStreamSocket, PlivoOutboundCheckpointMessage, PlivoOutboundClearAudioMessage, PlivoOutboundMessage, PlivoOutboundPlayAudioMessage, PlivoVoiceResponseOptions, PlivoVoiceRoutesOptions, PlivoVoiceSetupOptions, PlivoVoiceSetupStatus, PlivoVoiceSmokeCheck, PlivoVoiceSmokeOptions, PlivoVoiceSmokeReport } from './telephony/plivo';
|
|
92
94
|
export type { VoiceTelephonyCarrierMatrix, VoiceTelephonyCarrierMatrixEntry, VoiceTelephonyCarrierMatrixInput, VoiceTelephonyCarrierMatrixOptions, VoiceTelephonyCarrierMatrixRoutesOptions, VoiceTelephonyCarrierMatrixStatus } from './telephony/matrix';
|
|
93
95
|
export { shapeTelephonyAssistantText } from './telephony/response';
|
|
94
96
|
export type { TelephonyResponseShapeMode, TelephonyResponseShapeOptions } from './telephony/response';
|
package/dist/index.js
CHANGED
|
@@ -12424,6 +12424,136 @@ var createGeminiVoiceAssistantModel = (options) => {
|
|
|
12424
12424
|
}
|
|
12425
12425
|
};
|
|
12426
12426
|
};
|
|
12427
|
+
// src/openaiTTS.ts
|
|
12428
|
+
var OPENAI_PCM24_FORMAT = {
|
|
12429
|
+
channels: 1,
|
|
12430
|
+
container: "raw",
|
|
12431
|
+
encoding: "pcm_s16le",
|
|
12432
|
+
sampleRateHz: 24000
|
|
12433
|
+
};
|
|
12434
|
+
var resolveInstructions = async (instructions, input) => {
|
|
12435
|
+
if (typeof instructions === "function") {
|
|
12436
|
+
return instructions(input);
|
|
12437
|
+
}
|
|
12438
|
+
return instructions;
|
|
12439
|
+
};
|
|
12440
|
+
var createTTSHTTPError = (response) => new Error(`OpenAI voice TTS failed: HTTP ${response.status}`);
|
|
12441
|
+
var emit = async (listeners, event, payload) => {
|
|
12442
|
+
for (const handler of listeners[event]) {
|
|
12443
|
+
await Promise.resolve(handler(payload));
|
|
12444
|
+
}
|
|
12445
|
+
};
|
|
12446
|
+
var createOpenAIVoiceTTS = (options) => {
|
|
12447
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
12448
|
+
const baseUrl = options.baseUrl ?? "https://api.openai.com/v1";
|
|
12449
|
+
const model = options.model ?? "gpt-4o-mini-tts";
|
|
12450
|
+
const voice2 = options.voice ?? "coral";
|
|
12451
|
+
return {
|
|
12452
|
+
kind: "tts",
|
|
12453
|
+
open: (openOptions) => {
|
|
12454
|
+
const listeners = {
|
|
12455
|
+
audio: new Set,
|
|
12456
|
+
close: new Set,
|
|
12457
|
+
error: new Set
|
|
12458
|
+
};
|
|
12459
|
+
const abortController = new AbortController;
|
|
12460
|
+
const signalAbort = () => abortController.abort();
|
|
12461
|
+
openOptions.signal?.addEventListener("abort", signalAbort, { once: true });
|
|
12462
|
+
let closed = false;
|
|
12463
|
+
return {
|
|
12464
|
+
close: async (reason) => {
|
|
12465
|
+
if (closed) {
|
|
12466
|
+
return;
|
|
12467
|
+
}
|
|
12468
|
+
closed = true;
|
|
12469
|
+
abortController.abort();
|
|
12470
|
+
openOptions.signal?.removeEventListener("abort", signalAbort);
|
|
12471
|
+
await emit(listeners, "close", {
|
|
12472
|
+
reason,
|
|
12473
|
+
type: "close"
|
|
12474
|
+
});
|
|
12475
|
+
},
|
|
12476
|
+
on: (event, handler) => {
|
|
12477
|
+
listeners[event].add(handler);
|
|
12478
|
+
return () => {
|
|
12479
|
+
listeners[event].delete(handler);
|
|
12480
|
+
};
|
|
12481
|
+
},
|
|
12482
|
+
send: async (text) => {
|
|
12483
|
+
if (closed || !text.trim()) {
|
|
12484
|
+
return;
|
|
12485
|
+
}
|
|
12486
|
+
try {
|
|
12487
|
+
const instructions = await resolveInstructions(options.instructions, {
|
|
12488
|
+
lexicon: openOptions.lexicon,
|
|
12489
|
+
sessionId: openOptions.sessionId,
|
|
12490
|
+
text
|
|
12491
|
+
});
|
|
12492
|
+
const response = await fetchImpl(`${baseUrl.replace(/\/$/, "")}/audio/speech`, {
|
|
12493
|
+
body: JSON.stringify({
|
|
12494
|
+
input: text,
|
|
12495
|
+
instructions,
|
|
12496
|
+
model,
|
|
12497
|
+
response_format: "pcm",
|
|
12498
|
+
speed: options.speed,
|
|
12499
|
+
voice: voice2
|
|
12500
|
+
}),
|
|
12501
|
+
headers: {
|
|
12502
|
+
authorization: `Bearer ${options.apiKey}`,
|
|
12503
|
+
"content-type": "application/json"
|
|
12504
|
+
},
|
|
12505
|
+
method: "POST",
|
|
12506
|
+
signal: abortController.signal
|
|
12507
|
+
});
|
|
12508
|
+
if (!response.ok) {
|
|
12509
|
+
throw createTTSHTTPError(response);
|
|
12510
|
+
}
|
|
12511
|
+
if (!response.body) {
|
|
12512
|
+
const chunk = new Uint8Array(await response.arrayBuffer());
|
|
12513
|
+
if (!closed && chunk.byteLength > 0) {
|
|
12514
|
+
await emit(listeners, "audio", {
|
|
12515
|
+
chunk,
|
|
12516
|
+
format: OPENAI_PCM24_FORMAT,
|
|
12517
|
+
receivedAt: Date.now(),
|
|
12518
|
+
type: "audio"
|
|
12519
|
+
});
|
|
12520
|
+
}
|
|
12521
|
+
return;
|
|
12522
|
+
}
|
|
12523
|
+
const reader = response.body.getReader();
|
|
12524
|
+
try {
|
|
12525
|
+
while (!closed) {
|
|
12526
|
+
const { done, value } = await reader.read();
|
|
12527
|
+
if (done) {
|
|
12528
|
+
break;
|
|
12529
|
+
}
|
|
12530
|
+
if (value.byteLength > 0) {
|
|
12531
|
+
await emit(listeners, "audio", {
|
|
12532
|
+
chunk: new Uint8Array(value),
|
|
12533
|
+
format: OPENAI_PCM24_FORMAT,
|
|
12534
|
+
receivedAt: Date.now(),
|
|
12535
|
+
type: "audio"
|
|
12536
|
+
});
|
|
12537
|
+
}
|
|
12538
|
+
}
|
|
12539
|
+
} finally {
|
|
12540
|
+
reader.releaseLock();
|
|
12541
|
+
}
|
|
12542
|
+
} catch (error) {
|
|
12543
|
+
if (closed || abortController.signal.aborted) {
|
|
12544
|
+
return;
|
|
12545
|
+
}
|
|
12546
|
+
await emit(listeners, "error", {
|
|
12547
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
12548
|
+
recoverable: true,
|
|
12549
|
+
type: "error"
|
|
12550
|
+
});
|
|
12551
|
+
}
|
|
12552
|
+
}
|
|
12553
|
+
};
|
|
12554
|
+
}
|
|
12555
|
+
};
|
|
12556
|
+
};
|
|
12427
12557
|
// src/providerAdapters.ts
|
|
12428
12558
|
class VoiceIOProviderTimeoutError extends Error {
|
|
12429
12559
|
provider;
|
|
@@ -12611,11 +12741,11 @@ var createResolver = (options) => {
|
|
|
12611
12741
|
selectedProvider: preferred
|
|
12612
12742
|
};
|
|
12613
12743
|
};
|
|
12614
|
-
const
|
|
12744
|
+
const emit2 = async (event, input) => {
|
|
12615
12745
|
await options.onProviderEvent?.(event, input);
|
|
12616
12746
|
};
|
|
12617
12747
|
return {
|
|
12618
|
-
emit,
|
|
12748
|
+
emit: emit2,
|
|
12619
12749
|
getSuppressionRemainingMs,
|
|
12620
12750
|
providerIds,
|
|
12621
12751
|
recordError,
|
|
@@ -16028,6 +16158,114 @@ var createTelnyxVoiceResponse = (options) => {
|
|
|
16028
16158
|
].filter((value) => Boolean(value)).join(" ");
|
|
16029
16159
|
return `<?xml version="1.0" encoding="UTF-8"?><Response><Start><Stream ${attributes} /></Start></Response>`;
|
|
16030
16160
|
};
|
|
16161
|
+
var parseTelnyxMessage = (raw) => {
|
|
16162
|
+
if (typeof raw !== "string") {
|
|
16163
|
+
return raw;
|
|
16164
|
+
}
|
|
16165
|
+
return JSON.parse(raw);
|
|
16166
|
+
};
|
|
16167
|
+
var normalizeTelnyxTrack = (track) => track === "outbound" || track === "outbound_track" ? "outbound" : "inbound";
|
|
16168
|
+
var telnyxToTwilioMessage = (message) => {
|
|
16169
|
+
switch (message.event) {
|
|
16170
|
+
case "connected":
|
|
16171
|
+
return {
|
|
16172
|
+
event: "connected",
|
|
16173
|
+
version: message.version
|
|
16174
|
+
};
|
|
16175
|
+
case "start": {
|
|
16176
|
+
const streamSid = message.stream_id ?? "telnyx-stream";
|
|
16177
|
+
return {
|
|
16178
|
+
event: "start",
|
|
16179
|
+
start: {
|
|
16180
|
+
callSid: message.start?.call_control_id ?? message.start?.call_session_id ?? message.start?.call_leg_id,
|
|
16181
|
+
customParameters: {
|
|
16182
|
+
...message.start?.custom_parameters ?? {},
|
|
16183
|
+
...message.start?.call_session_id ? { sessionId: message.start.call_session_id } : {}
|
|
16184
|
+
},
|
|
16185
|
+
mediaFormat: {
|
|
16186
|
+
channels: message.start?.media_format?.channels,
|
|
16187
|
+
encoding: message.start?.media_format?.encoding,
|
|
16188
|
+
sampleRate: message.start?.media_format?.sample_rate
|
|
16189
|
+
},
|
|
16190
|
+
streamSid
|
|
16191
|
+
},
|
|
16192
|
+
streamSid
|
|
16193
|
+
};
|
|
16194
|
+
}
|
|
16195
|
+
case "media": {
|
|
16196
|
+
const streamSid = message.stream_id ?? "telnyx-stream";
|
|
16197
|
+
return {
|
|
16198
|
+
event: "media",
|
|
16199
|
+
media: {
|
|
16200
|
+
chunk: message.media.chunk,
|
|
16201
|
+
payload: message.media.payload,
|
|
16202
|
+
timestamp: message.media.timestamp,
|
|
16203
|
+
track: normalizeTelnyxTrack(message.media.track)
|
|
16204
|
+
},
|
|
16205
|
+
streamSid
|
|
16206
|
+
};
|
|
16207
|
+
}
|
|
16208
|
+
case "mark":
|
|
16209
|
+
return {
|
|
16210
|
+
event: "mark",
|
|
16211
|
+
mark: message.mark,
|
|
16212
|
+
streamSid: message.stream_id ?? "telnyx-stream"
|
|
16213
|
+
};
|
|
16214
|
+
case "stop":
|
|
16215
|
+
return {
|
|
16216
|
+
event: "stop",
|
|
16217
|
+
stop: {
|
|
16218
|
+
callSid: message.stop?.call_control_id
|
|
16219
|
+
},
|
|
16220
|
+
streamSid: message.stream_id ?? "telnyx-stream"
|
|
16221
|
+
};
|
|
16222
|
+
case "dtmf":
|
|
16223
|
+
case "error":
|
|
16224
|
+
return null;
|
|
16225
|
+
}
|
|
16226
|
+
};
|
|
16227
|
+
var createTelnyxTwilioSocketAdapter = (socket) => ({
|
|
16228
|
+
close: (code, reason) => socket.close(code, reason),
|
|
16229
|
+
send: async (data) => {
|
|
16230
|
+
const message = JSON.parse(data);
|
|
16231
|
+
const telnyxMessage = message.event === "media" ? {
|
|
16232
|
+
event: "media",
|
|
16233
|
+
media: {
|
|
16234
|
+
payload: message.media.payload
|
|
16235
|
+
}
|
|
16236
|
+
} : message.event === "clear" ? {
|
|
16237
|
+
event: "clear"
|
|
16238
|
+
} : message.event === "mark" ? {
|
|
16239
|
+
event: "mark",
|
|
16240
|
+
mark: message.mark
|
|
16241
|
+
} : null;
|
|
16242
|
+
if (telnyxMessage) {
|
|
16243
|
+
await Promise.resolve(socket.send(JSON.stringify(telnyxMessage)));
|
|
16244
|
+
}
|
|
16245
|
+
}
|
|
16246
|
+
});
|
|
16247
|
+
var createTelnyxMediaStreamBridge = (socket, options) => {
|
|
16248
|
+
const bridge = createTwilioMediaStreamBridge(createTelnyxTwilioSocketAdapter(socket), {
|
|
16249
|
+
...options,
|
|
16250
|
+
onVoiceMessage: options.onVoiceMessage ? (input) => options.onVoiceMessage?.({
|
|
16251
|
+
callControlId: input.callSid,
|
|
16252
|
+
message: input.message,
|
|
16253
|
+
sessionId: input.sessionId,
|
|
16254
|
+
streamId: input.streamSid
|
|
16255
|
+
}) : undefined
|
|
16256
|
+
});
|
|
16257
|
+
return {
|
|
16258
|
+
close: bridge.close,
|
|
16259
|
+
getSessionId: bridge.getSessionId,
|
|
16260
|
+
getStreamId: bridge.getStreamSid,
|
|
16261
|
+
handleMessage: async (raw) => {
|
|
16262
|
+
const message = telnyxToTwilioMessage(parseTelnyxMessage(raw));
|
|
16263
|
+
if (message) {
|
|
16264
|
+
await bridge.handleMessage(message);
|
|
16265
|
+
}
|
|
16266
|
+
}
|
|
16267
|
+
};
|
|
16268
|
+
};
|
|
16031
16269
|
var decodeBase64 = (value) => Uint8Array.from(Buffer4.from(value, "base64"));
|
|
16032
16270
|
var verifyVoiceTelnyxWebhookSignature = async (input) => {
|
|
16033
16271
|
if (!input.publicKey) {
|
|
@@ -16182,6 +16420,7 @@ var createTelnyxVoiceRoutes = (options = {}) => {
|
|
|
16182
16420
|
const webhookPath = options.webhook?.path ?? "/api/voice/telnyx/webhook";
|
|
16183
16421
|
const setupPath = options.setup?.path === false ? false : options.setup?.path ?? "/api/voice/telnyx/setup";
|
|
16184
16422
|
const smokePath = options.smoke?.path === false ? false : options.smoke?.path ?? "/api/voice/telnyx/smoke";
|
|
16423
|
+
const bridges = new WeakMap;
|
|
16185
16424
|
const webhookPolicy = options.webhook?.policy ?? options.outcomePolicy ?? createVoiceTelephonyOutcomePolicy();
|
|
16186
16425
|
const verify = options.webhook?.verify ?? (options.webhook?.publicKey ? (input) => verifyVoiceTelnyxWebhookSignature({
|
|
16187
16426
|
body: input.rawBody,
|
|
@@ -16219,6 +16458,31 @@ var createTelnyxVoiceRoutes = (options = {}) => {
|
|
|
16219
16458
|
"content-type": "text/xml; charset=utf-8"
|
|
16220
16459
|
}
|
|
16221
16460
|
});
|
|
16461
|
+
}).ws(streamPath, {
|
|
16462
|
+
close: async (ws, _code, reason) => {
|
|
16463
|
+
const bridge = bridges.get(ws);
|
|
16464
|
+
bridges.delete(ws);
|
|
16465
|
+
await bridge?.close(reason);
|
|
16466
|
+
},
|
|
16467
|
+
message: async (ws, raw) => {
|
|
16468
|
+
if (!options.bridge) {
|
|
16469
|
+
ws.close(1011, "Telnyx media bridge is not configured.");
|
|
16470
|
+
return;
|
|
16471
|
+
}
|
|
16472
|
+
let bridge = bridges.get(ws);
|
|
16473
|
+
if (!bridge) {
|
|
16474
|
+
bridge = createTelnyxMediaStreamBridge({
|
|
16475
|
+
close: (code, reason) => {
|
|
16476
|
+
ws.close(code, reason);
|
|
16477
|
+
},
|
|
16478
|
+
send: (data) => {
|
|
16479
|
+
ws.send(data);
|
|
16480
|
+
}
|
|
16481
|
+
}, options.bridge);
|
|
16482
|
+
bridges.set(ws, bridge);
|
|
16483
|
+
}
|
|
16484
|
+
await bridge.handleMessage(raw);
|
|
16485
|
+
}
|
|
16222
16486
|
}).use(createVoiceTelephonyWebhookRoutes({
|
|
16223
16487
|
...options.webhook ?? {},
|
|
16224
16488
|
context: options.context,
|
|
@@ -16327,6 +16591,123 @@ var createPlivoVoiceResponse = (options) => {
|
|
|
16327
16591
|
const openTag = attributes ? `<Stream ${attributes}>` : "<Stream>";
|
|
16328
16592
|
return `<?xml version="1.0" encoding="UTF-8"?><Response>${openTag}${escapeXml4(options.streamUrl)}</Stream></Response>`;
|
|
16329
16593
|
};
|
|
16594
|
+
var parsePlivoMessage = (raw) => {
|
|
16595
|
+
if (typeof raw !== "string") {
|
|
16596
|
+
return raw;
|
|
16597
|
+
}
|
|
16598
|
+
return JSON.parse(raw);
|
|
16599
|
+
};
|
|
16600
|
+
var parsePlivoExtraHeaders = (headers) => {
|
|
16601
|
+
if (!headers) {
|
|
16602
|
+
return {};
|
|
16603
|
+
}
|
|
16604
|
+
return Object.fromEntries(headers.split(/[;,]/).map((header) => header.trim()).filter(Boolean).map((header) => {
|
|
16605
|
+
const separator = header.indexOf("=");
|
|
16606
|
+
if (separator === -1) {
|
|
16607
|
+
return [header, ""];
|
|
16608
|
+
}
|
|
16609
|
+
return [
|
|
16610
|
+
header.slice(0, separator).trim(),
|
|
16611
|
+
header.slice(separator + 1).trim()
|
|
16612
|
+
];
|
|
16613
|
+
}).filter((entry) => (entry[0] ?? "").length > 0));
|
|
16614
|
+
};
|
|
16615
|
+
var plivoToTwilioMessage = (message) => {
|
|
16616
|
+
switch (message.event) {
|
|
16617
|
+
case "start": {
|
|
16618
|
+
const streamSid = message.streamId ?? message.start?.streamId ?? "plivo-stream";
|
|
16619
|
+
const callSid = message.start?.callId ?? message.start?.callUuid;
|
|
16620
|
+
const customParameters = parsePlivoExtraHeaders(message.start?.extra_headers);
|
|
16621
|
+
return {
|
|
16622
|
+
event: "start",
|
|
16623
|
+
start: {
|
|
16624
|
+
callSid,
|
|
16625
|
+
customParameters,
|
|
16626
|
+
mediaFormat: message.start?.mediaFormat,
|
|
16627
|
+
streamSid
|
|
16628
|
+
},
|
|
16629
|
+
streamSid
|
|
16630
|
+
};
|
|
16631
|
+
}
|
|
16632
|
+
case "media": {
|
|
16633
|
+
const streamSid = message.streamId ?? "plivo-stream";
|
|
16634
|
+
return {
|
|
16635
|
+
event: "media",
|
|
16636
|
+
media: {
|
|
16637
|
+
payload: message.media.payload,
|
|
16638
|
+
timestamp: message.media.timestamp,
|
|
16639
|
+
track: message.media.track ?? "inbound"
|
|
16640
|
+
},
|
|
16641
|
+
streamSid
|
|
16642
|
+
};
|
|
16643
|
+
}
|
|
16644
|
+
case "playedStream":
|
|
16645
|
+
return {
|
|
16646
|
+
event: "mark",
|
|
16647
|
+
mark: {
|
|
16648
|
+
name: message.name
|
|
16649
|
+
},
|
|
16650
|
+
streamSid: message.streamId ?? "plivo-stream"
|
|
16651
|
+
};
|
|
16652
|
+
case "stop":
|
|
16653
|
+
return {
|
|
16654
|
+
event: "stop",
|
|
16655
|
+
stop: {
|
|
16656
|
+
callSid: message.stop?.callId ?? message.stop?.callUuid
|
|
16657
|
+
},
|
|
16658
|
+
streamSid: message.streamId ?? "plivo-stream"
|
|
16659
|
+
};
|
|
16660
|
+
case "clearedAudio":
|
|
16661
|
+
case "dtmf":
|
|
16662
|
+
return null;
|
|
16663
|
+
}
|
|
16664
|
+
};
|
|
16665
|
+
var createPlivoTwilioSocketAdapter = (socket) => ({
|
|
16666
|
+
close: (code, reason) => socket.close(code, reason),
|
|
16667
|
+
send: async (data) => {
|
|
16668
|
+
const message = JSON.parse(data);
|
|
16669
|
+
const plivoMessage = message.event === "media" ? {
|
|
16670
|
+
event: "playAudio",
|
|
16671
|
+
media: {
|
|
16672
|
+
contentType: "audio/x-mulaw",
|
|
16673
|
+
payload: message.media.payload,
|
|
16674
|
+
sampleRate: 8000
|
|
16675
|
+
}
|
|
16676
|
+
} : message.event === "clear" ? {
|
|
16677
|
+
event: "clearAudio",
|
|
16678
|
+
streamId: message.streamSid
|
|
16679
|
+
} : message.event === "mark" ? {
|
|
16680
|
+
event: "checkpoint",
|
|
16681
|
+
name: message.mark.name,
|
|
16682
|
+
streamId: message.streamSid
|
|
16683
|
+
} : null;
|
|
16684
|
+
if (plivoMessage) {
|
|
16685
|
+
await Promise.resolve(socket.send(JSON.stringify(plivoMessage)));
|
|
16686
|
+
}
|
|
16687
|
+
}
|
|
16688
|
+
});
|
|
16689
|
+
var createPlivoMediaStreamBridge = (socket, options) => {
|
|
16690
|
+
const bridge = createTwilioMediaStreamBridge(createPlivoTwilioSocketAdapter(socket), {
|
|
16691
|
+
...options,
|
|
16692
|
+
onVoiceMessage: options.onVoiceMessage ? (input) => options.onVoiceMessage?.({
|
|
16693
|
+
callId: input.callSid,
|
|
16694
|
+
message: input.message,
|
|
16695
|
+
sessionId: input.sessionId,
|
|
16696
|
+
streamId: input.streamSid
|
|
16697
|
+
}) : undefined
|
|
16698
|
+
});
|
|
16699
|
+
return {
|
|
16700
|
+
close: bridge.close,
|
|
16701
|
+
getSessionId: bridge.getSessionId,
|
|
16702
|
+
getStreamId: bridge.getStreamSid,
|
|
16703
|
+
handleMessage: async (raw) => {
|
|
16704
|
+
const message = plivoToTwilioMessage(parsePlivoMessage(raw));
|
|
16705
|
+
if (message) {
|
|
16706
|
+
await bridge.handleMessage(message);
|
|
16707
|
+
}
|
|
16708
|
+
}
|
|
16709
|
+
};
|
|
16710
|
+
};
|
|
16330
16711
|
var toBase642 = (bytes) => Buffer5.from(new Uint8Array(bytes)).toString("base64");
|
|
16331
16712
|
var timingSafeEqual3 = (left, right) => {
|
|
16332
16713
|
const encoder = new TextEncoder;
|
|
@@ -16507,6 +16888,7 @@ var createPlivoVoiceRoutes = (options = {}) => {
|
|
|
16507
16888
|
const webhookPath = options.webhook?.path ?? "/api/voice/plivo/webhook";
|
|
16508
16889
|
const setupPath = options.setup?.path === false ? false : options.setup?.path ?? "/api/voice/plivo/setup";
|
|
16509
16890
|
const smokePath = options.smoke?.path === false ? false : options.smoke?.path ?? "/api/voice/plivo/smoke";
|
|
16891
|
+
const bridges = new WeakMap;
|
|
16510
16892
|
const webhookPolicy = options.webhook?.policy ?? options.outcomePolicy ?? createVoiceTelephonyOutcomePolicy();
|
|
16511
16893
|
const verificationUrl = options.webhook?.verificationUrl;
|
|
16512
16894
|
const verify = options.webhook?.verify ?? (options.webhook?.authToken ? (input) => verifyVoicePlivoWebhookSignature({
|
|
@@ -16548,6 +16930,31 @@ var createPlivoVoiceRoutes = (options = {}) => {
|
|
|
16548
16930
|
"content-type": "text/xml; charset=utf-8"
|
|
16549
16931
|
}
|
|
16550
16932
|
});
|
|
16933
|
+
}).ws(streamPath, {
|
|
16934
|
+
close: async (ws, _code, reason) => {
|
|
16935
|
+
const bridge = bridges.get(ws);
|
|
16936
|
+
bridges.delete(ws);
|
|
16937
|
+
await bridge?.close(reason);
|
|
16938
|
+
},
|
|
16939
|
+
message: async (ws, raw) => {
|
|
16940
|
+
if (!options.bridge) {
|
|
16941
|
+
ws.close(1011, "Plivo media bridge is not configured.");
|
|
16942
|
+
return;
|
|
16943
|
+
}
|
|
16944
|
+
let bridge = bridges.get(ws);
|
|
16945
|
+
if (!bridge) {
|
|
16946
|
+
bridge = createPlivoMediaStreamBridge({
|
|
16947
|
+
close: (code, reason) => {
|
|
16948
|
+
ws.close(code, reason);
|
|
16949
|
+
},
|
|
16950
|
+
send: (data) => {
|
|
16951
|
+
ws.send(data);
|
|
16952
|
+
}
|
|
16953
|
+
}, options.bridge);
|
|
16954
|
+
bridges.set(ws, bridge);
|
|
16955
|
+
}
|
|
16956
|
+
await bridge.handleMessage(raw);
|
|
16957
|
+
}
|
|
16551
16958
|
}).use(createVoiceTelephonyWebhookRoutes({
|
|
16552
16959
|
...options.webhook ?? {},
|
|
16553
16960
|
context: options.context,
|
|
@@ -17013,6 +17420,7 @@ export {
|
|
|
17013
17420
|
createTwilioMediaStreamBridge,
|
|
17014
17421
|
createTelnyxVoiceRoutes,
|
|
17015
17422
|
createTelnyxVoiceResponse,
|
|
17423
|
+
createTelnyxMediaStreamBridge,
|
|
17016
17424
|
createStoredVoiceOpsTask,
|
|
17017
17425
|
createStoredVoiceIntegrationEvent,
|
|
17018
17426
|
createStoredVoiceExternalObjectMap,
|
|
@@ -17020,7 +17428,9 @@ export {
|
|
|
17020
17428
|
createRiskyTurnCorrectionHandler,
|
|
17021
17429
|
createPlivoVoiceRoutes,
|
|
17022
17430
|
createPlivoVoiceResponse,
|
|
17431
|
+
createPlivoMediaStreamBridge,
|
|
17023
17432
|
createPhraseHintCorrectionHandler,
|
|
17433
|
+
createOpenAIVoiceTTS,
|
|
17024
17434
|
createOpenAIVoiceAssistantModel,
|
|
17025
17435
|
createMemoryVoiceTelephonyWebhookIdempotencyStore,
|
|
17026
17436
|
createJSONVoiceAssistantModel,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { TTSAdapter, TTSAdapterOpenOptions, VoiceLexiconEntry } from './types';
|
|
2
|
+
export type OpenAIVoiceTTSVoice = 'alloy' | 'ash' | 'ballad' | 'cedar' | 'coral' | 'echo' | 'fable' | 'marin' | 'nova' | 'onyx' | 'sage' | 'shimmer' | 'verse' | (string & {});
|
|
3
|
+
export type OpenAIVoiceTTSOptions = {
|
|
4
|
+
apiKey: string;
|
|
5
|
+
baseUrl?: string;
|
|
6
|
+
fetch?: typeof fetch;
|
|
7
|
+
instructions?: string | ((input: {
|
|
8
|
+
lexicon?: VoiceLexiconEntry[];
|
|
9
|
+
sessionId: string;
|
|
10
|
+
text: string;
|
|
11
|
+
}) => Promise<string | undefined> | string | undefined);
|
|
12
|
+
model?: 'gpt-4o-mini-tts' | 'tts-1' | 'tts-1-hd' | (string & {});
|
|
13
|
+
speed?: number;
|
|
14
|
+
voice?: OpenAIVoiceTTSVoice | {
|
|
15
|
+
id: string;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
export declare const createOpenAIVoiceTTS: (options: OpenAIVoiceTTSOptions) => TTSAdapter<TTSAdapterOpenOptions>;
|
|
@@ -1,7 +1,95 @@
|
|
|
1
1
|
import { Elysia } from 'elysia';
|
|
2
2
|
import { type VoiceTelephonyContractReport, type VoiceTelephonySetupStatus, type VoiceTelephonySmokeCheck, type VoiceTelephonySmokeReport } from './contract';
|
|
3
3
|
import { type VoiceTelephonyOutcomePolicy, type VoiceTelephonyWebhookRoutesOptions, type VoiceTelephonyWebhookVerificationResult } from '../telephonyOutcome';
|
|
4
|
-
import type { VoiceSessionRecord } from '../types';
|
|
4
|
+
import type { VoiceServerMessage, VoiceSessionRecord } from '../types';
|
|
5
|
+
import { type TwilioMediaStreamBridgeOptions } from './twilio';
|
|
6
|
+
export type PlivoInboundMessage = {
|
|
7
|
+
event: 'start';
|
|
8
|
+
sequenceNumber?: number;
|
|
9
|
+
start?: {
|
|
10
|
+
callId?: string;
|
|
11
|
+
callUuid?: string;
|
|
12
|
+
extra_headers?: string;
|
|
13
|
+
mediaFormat?: {
|
|
14
|
+
channels?: number;
|
|
15
|
+
encoding?: string;
|
|
16
|
+
sampleRate?: number;
|
|
17
|
+
};
|
|
18
|
+
streamId?: string;
|
|
19
|
+
};
|
|
20
|
+
streamId?: string;
|
|
21
|
+
} | {
|
|
22
|
+
event: 'media';
|
|
23
|
+
media: {
|
|
24
|
+
payload: string;
|
|
25
|
+
timestamp?: string;
|
|
26
|
+
track?: 'inbound' | 'outbound';
|
|
27
|
+
};
|
|
28
|
+
sequenceNumber?: number;
|
|
29
|
+
streamId?: string;
|
|
30
|
+
} | {
|
|
31
|
+
event: 'dtmf';
|
|
32
|
+
dtmf?: {
|
|
33
|
+
digit?: string;
|
|
34
|
+
timestamp?: string;
|
|
35
|
+
track?: string;
|
|
36
|
+
};
|
|
37
|
+
sequenceNumber?: number;
|
|
38
|
+
streamId?: string;
|
|
39
|
+
} | {
|
|
40
|
+
event: 'playedStream';
|
|
41
|
+
name?: string;
|
|
42
|
+
sequenceNumber?: number;
|
|
43
|
+
streamId?: string;
|
|
44
|
+
} | {
|
|
45
|
+
event: 'clearedAudio';
|
|
46
|
+
sequenceNumber?: number;
|
|
47
|
+
streamId?: string;
|
|
48
|
+
} | {
|
|
49
|
+
event: 'stop';
|
|
50
|
+
sequenceNumber?: number;
|
|
51
|
+
stop?: {
|
|
52
|
+
callId?: string;
|
|
53
|
+
callUuid?: string;
|
|
54
|
+
};
|
|
55
|
+
streamId?: string;
|
|
56
|
+
};
|
|
57
|
+
export type PlivoOutboundPlayAudioMessage = {
|
|
58
|
+
event: 'playAudio';
|
|
59
|
+
media: {
|
|
60
|
+
contentType: 'audio/x-mulaw';
|
|
61
|
+
payload: string;
|
|
62
|
+
sampleRate: 8000;
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
export type PlivoOutboundClearAudioMessage = {
|
|
66
|
+
event: 'clearAudio';
|
|
67
|
+
streamId?: string;
|
|
68
|
+
};
|
|
69
|
+
export type PlivoOutboundCheckpointMessage = {
|
|
70
|
+
event: 'checkpoint';
|
|
71
|
+
name: string;
|
|
72
|
+
streamId?: string;
|
|
73
|
+
};
|
|
74
|
+
export type PlivoOutboundMessage = PlivoOutboundPlayAudioMessage | PlivoOutboundClearAudioMessage | PlivoOutboundCheckpointMessage;
|
|
75
|
+
export type PlivoMediaStreamSocket = {
|
|
76
|
+
close: (code?: number, reason?: string) => void | Promise<void>;
|
|
77
|
+
send: (data: string) => void | Promise<void>;
|
|
78
|
+
};
|
|
79
|
+
export type PlivoMediaStreamBridgeOptions<TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown> = Omit<TwilioMediaStreamBridgeOptions<TContext, TSession, TResult>, 'onVoiceMessage'> & {
|
|
80
|
+
onVoiceMessage?: (input: {
|
|
81
|
+
callId?: string;
|
|
82
|
+
message: VoiceServerMessage<TResult>;
|
|
83
|
+
sessionId: string;
|
|
84
|
+
streamId?: string;
|
|
85
|
+
}) => Promise<void> | void;
|
|
86
|
+
};
|
|
87
|
+
export type PlivoMediaStreamBridge = {
|
|
88
|
+
close: (reason?: string) => Promise<void>;
|
|
89
|
+
getSessionId: () => string | null;
|
|
90
|
+
getStreamId: () => string | null;
|
|
91
|
+
handleMessage: (raw: string | PlivoInboundMessage) => Promise<void>;
|
|
92
|
+
};
|
|
5
93
|
export type PlivoVoiceResponseOptions = {
|
|
6
94
|
audioTrack?: 'both' | 'inbound' | 'outbound';
|
|
7
95
|
bidirectional?: boolean;
|
|
@@ -53,6 +141,7 @@ export type PlivoVoiceRoutesOptions<TContext = unknown, TSession extends VoiceSe
|
|
|
53
141
|
streamPath: string;
|
|
54
142
|
}) => Promise<string> | string);
|
|
55
143
|
};
|
|
144
|
+
bridge?: PlivoMediaStreamBridgeOptions<TContext, TSession, TResult>;
|
|
56
145
|
context?: TContext;
|
|
57
146
|
name?: string;
|
|
58
147
|
outcomePolicy?: VoiceTelephonyOutcomePolicy;
|
|
@@ -70,6 +159,7 @@ export type PlivoVoiceRoutesOptions<TContext = unknown, TSession extends VoiceSe
|
|
|
70
159
|
};
|
|
71
160
|
};
|
|
72
161
|
export declare const createPlivoVoiceResponse: (options: PlivoVoiceResponseOptions) => string;
|
|
162
|
+
export declare const createPlivoMediaStreamBridge: <TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown>(socket: PlivoMediaStreamSocket, options: PlivoMediaStreamBridgeOptions<TContext, TSession, TResult>) => PlivoMediaStreamBridge;
|
|
73
163
|
export declare const signVoicePlivoWebhook: (input: {
|
|
74
164
|
authToken: string;
|
|
75
165
|
body?: unknown;
|
|
@@ -121,6 +211,16 @@ export declare const createPlivoVoiceRoutes: <TContext = unknown, TSession exten
|
|
|
121
211
|
};
|
|
122
212
|
};
|
|
123
213
|
};
|
|
214
|
+
} & {
|
|
215
|
+
[x: string]: {
|
|
216
|
+
subscribe: {
|
|
217
|
+
body: unknown;
|
|
218
|
+
params: {};
|
|
219
|
+
query: unknown;
|
|
220
|
+
headers: unknown;
|
|
221
|
+
response: {};
|
|
222
|
+
};
|
|
223
|
+
};
|
|
124
224
|
} & {
|
|
125
225
|
[x: string]: {
|
|
126
226
|
post: {
|
|
@@ -1,7 +1,103 @@
|
|
|
1
1
|
import { Elysia } from 'elysia';
|
|
2
2
|
import { type VoiceTelephonyContractReport, type VoiceTelephonySetupStatus, type VoiceTelephonySmokeCheck, type VoiceTelephonySmokeReport } from './contract';
|
|
3
3
|
import { type VoiceTelephonyOutcomePolicy, type VoiceTelephonyWebhookRoutesOptions, type VoiceTelephonyWebhookVerificationResult } from '../telephonyOutcome';
|
|
4
|
-
import type { VoiceSessionRecord } from '../types';
|
|
4
|
+
import type { VoiceServerMessage, VoiceSessionRecord } from '../types';
|
|
5
|
+
import { type TwilioMediaStreamBridgeOptions } from './twilio';
|
|
6
|
+
export type TelnyxMediaPayload = {
|
|
7
|
+
chunk?: string;
|
|
8
|
+
payload: string;
|
|
9
|
+
timestamp?: string;
|
|
10
|
+
track?: 'inbound' | 'outbound' | 'inbound_track' | 'outbound_track';
|
|
11
|
+
};
|
|
12
|
+
export type TelnyxInboundMessage = {
|
|
13
|
+
event: 'connected';
|
|
14
|
+
version?: string;
|
|
15
|
+
} | {
|
|
16
|
+
event: 'start';
|
|
17
|
+
sequence_number?: string;
|
|
18
|
+
start?: {
|
|
19
|
+
call_control_id?: string;
|
|
20
|
+
call_leg_id?: string;
|
|
21
|
+
call_session_id?: string;
|
|
22
|
+
custom_parameters?: Record<string, string>;
|
|
23
|
+
media_format?: {
|
|
24
|
+
channels?: number;
|
|
25
|
+
encoding?: string;
|
|
26
|
+
sample_rate?: number;
|
|
27
|
+
};
|
|
28
|
+
user_id?: string;
|
|
29
|
+
};
|
|
30
|
+
stream_id?: string;
|
|
31
|
+
} | {
|
|
32
|
+
event: 'media';
|
|
33
|
+
media: TelnyxMediaPayload;
|
|
34
|
+
sequence_number?: string;
|
|
35
|
+
stream_id?: string;
|
|
36
|
+
} | {
|
|
37
|
+
event: 'mark';
|
|
38
|
+
mark?: {
|
|
39
|
+
name?: string;
|
|
40
|
+
};
|
|
41
|
+
sequence_number?: string;
|
|
42
|
+
stream_id?: string;
|
|
43
|
+
} | {
|
|
44
|
+
event: 'dtmf';
|
|
45
|
+
dtmf?: {
|
|
46
|
+
digit?: string;
|
|
47
|
+
};
|
|
48
|
+
sequence_number?: string;
|
|
49
|
+
stream_id?: string;
|
|
50
|
+
} | {
|
|
51
|
+
event: 'error';
|
|
52
|
+
payload?: {
|
|
53
|
+
code?: number;
|
|
54
|
+
detail?: string;
|
|
55
|
+
title?: string;
|
|
56
|
+
};
|
|
57
|
+
stream_id?: string;
|
|
58
|
+
} | {
|
|
59
|
+
event: 'stop';
|
|
60
|
+
sequence_number?: string;
|
|
61
|
+
stop?: {
|
|
62
|
+
call_control_id?: string;
|
|
63
|
+
user_id?: string;
|
|
64
|
+
};
|
|
65
|
+
stream_id?: string;
|
|
66
|
+
};
|
|
67
|
+
export type TelnyxOutboundMediaMessage = {
|
|
68
|
+
event: 'media';
|
|
69
|
+
media: {
|
|
70
|
+
payload: string;
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
export type TelnyxOutboundClearMessage = {
|
|
74
|
+
event: 'clear';
|
|
75
|
+
};
|
|
76
|
+
export type TelnyxOutboundMarkMessage = {
|
|
77
|
+
event: 'mark';
|
|
78
|
+
mark: {
|
|
79
|
+
name: string;
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
export type TelnyxOutboundMessage = TelnyxOutboundMediaMessage | TelnyxOutboundClearMessage | TelnyxOutboundMarkMessage;
|
|
83
|
+
export type TelnyxMediaStreamSocket = {
|
|
84
|
+
close: (code?: number, reason?: string) => void | Promise<void>;
|
|
85
|
+
send: (data: string) => void | Promise<void>;
|
|
86
|
+
};
|
|
87
|
+
export type TelnyxMediaStreamBridgeOptions<TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown> = Omit<TwilioMediaStreamBridgeOptions<TContext, TSession, TResult>, 'onVoiceMessage'> & {
|
|
88
|
+
onVoiceMessage?: (input: {
|
|
89
|
+
callControlId?: string;
|
|
90
|
+
message: VoiceServerMessage<TResult>;
|
|
91
|
+
sessionId: string;
|
|
92
|
+
streamId?: string;
|
|
93
|
+
}) => Promise<void> | void;
|
|
94
|
+
};
|
|
95
|
+
export type TelnyxMediaStreamBridge = {
|
|
96
|
+
close: (reason?: string) => Promise<void>;
|
|
97
|
+
getSessionId: () => string | null;
|
|
98
|
+
getStreamId: () => string | null;
|
|
99
|
+
handleMessage: (raw: string | TelnyxInboundMessage) => Promise<void>;
|
|
100
|
+
};
|
|
5
101
|
export type TelnyxVoiceResponseOptions = {
|
|
6
102
|
bidirectionalCodec?: 'AMR-WB' | 'G722' | 'OPUS' | 'PCMA' | 'PCMU';
|
|
7
103
|
bidirectionalMode?: 'mp3' | 'rtp';
|
|
@@ -38,6 +134,7 @@ export type TelnyxVoiceSmokeOptions = {
|
|
|
38
134
|
title?: string;
|
|
39
135
|
};
|
|
40
136
|
export type TelnyxVoiceRoutesOptions<TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown> = {
|
|
137
|
+
bridge?: TelnyxMediaStreamBridgeOptions<TContext, TSession, TResult>;
|
|
41
138
|
context?: TContext;
|
|
42
139
|
name?: string;
|
|
43
140
|
outcomePolicy?: VoiceTelephonyOutcomePolicy;
|
|
@@ -61,6 +158,7 @@ export type TelnyxVoiceRoutesOptions<TContext = unknown, TSession extends VoiceS
|
|
|
61
158
|
};
|
|
62
159
|
};
|
|
63
160
|
export declare const createTelnyxVoiceResponse: (options: TelnyxVoiceResponseOptions) => string;
|
|
161
|
+
export declare const createTelnyxMediaStreamBridge: <TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown>(socket: TelnyxMediaStreamSocket, options: TelnyxMediaStreamBridgeOptions<TContext, TSession, TResult>) => TelnyxMediaStreamBridge;
|
|
64
162
|
export declare const verifyVoiceTelnyxWebhookSignature: (input: {
|
|
65
163
|
body: string;
|
|
66
164
|
headers: Headers;
|
|
@@ -106,6 +204,16 @@ export declare const createTelnyxVoiceRoutes: <TContext = unknown, TSession exte
|
|
|
106
204
|
};
|
|
107
205
|
};
|
|
108
206
|
};
|
|
207
|
+
} & {
|
|
208
|
+
[x: string]: {
|
|
209
|
+
subscribe: {
|
|
210
|
+
body: unknown;
|
|
211
|
+
params: {};
|
|
212
|
+
query: unknown;
|
|
213
|
+
headers: unknown;
|
|
214
|
+
response: {};
|
|
215
|
+
};
|
|
216
|
+
};
|
|
109
217
|
} & {
|
|
110
218
|
[x: string]: {
|
|
111
219
|
post: {
|