@memberjunction/telephony-adapters 0.0.0 → 6.1.0-edge.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +183 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +83 -0
- package/dist/index.js.map +1 -0
- package/dist/resolvers/RingCentralTelephonyResolver.d.ts +20 -0
- package/dist/resolvers/RingCentralTelephonyResolver.d.ts.map +1 -0
- package/dist/resolvers/RingCentralTelephonyResolver.js +83 -0
- package/dist/resolvers/RingCentralTelephonyResolver.js.map +1 -0
- package/dist/resolvers/TeamsMeetingsResolver.d.ts +21 -0
- package/dist/resolvers/TeamsMeetingsResolver.d.ts.map +1 -0
- package/dist/resolvers/TeamsMeetingsResolver.js +87 -0
- package/dist/resolvers/TeamsMeetingsResolver.js.map +1 -0
- package/dist/resolvers/TelephonyResolver.d.ts +20 -0
- package/dist/resolvers/TelephonyResolver.d.ts.map +1 -0
- package/dist/resolvers/TelephonyResolver.js +83 -0
- package/dist/resolvers/TelephonyResolver.js.map +1 -0
- package/dist/resolvers/VonageTelephonyResolver.d.ts +20 -0
- package/dist/resolvers/VonageTelephonyResolver.d.ts.map +1 -0
- package/dist/resolvers/VonageTelephonyResolver.js +83 -0
- package/dist/resolvers/VonageTelephonyResolver.js.map +1 -0
- package/dist/resolvers/index.d.ts +10 -0
- package/dist/resolvers/index.d.ts.map +1 -0
- package/dist/resolvers/index.js +10 -0
- package/dist/resolvers/index.js.map +1 -0
- package/dist/server-extensions/RingCentralTelephonyExtension.d.ts +14 -0
- package/dist/server-extensions/RingCentralTelephonyExtension.d.ts.map +1 -0
- package/dist/server-extensions/RingCentralTelephonyExtension.js +81 -0
- package/dist/server-extensions/RingCentralTelephonyExtension.js.map +1 -0
- package/dist/server-extensions/TeamsMeetingsExtension.d.ts +17 -0
- package/dist/server-extensions/TeamsMeetingsExtension.d.ts.map +1 -0
- package/dist/server-extensions/TeamsMeetingsExtension.js +109 -0
- package/dist/server-extensions/TeamsMeetingsExtension.js.map +1 -0
- package/dist/server-extensions/TwilioTelephonyExtension.d.ts +14 -0
- package/dist/server-extensions/TwilioTelephonyExtension.d.ts.map +1 -0
- package/dist/server-extensions/TwilioTelephonyExtension.js +88 -0
- package/dist/server-extensions/TwilioTelephonyExtension.js.map +1 -0
- package/dist/server-extensions/VonageTelephonyExtension.d.ts +14 -0
- package/dist/server-extensions/VonageTelephonyExtension.d.ts.map +1 -0
- package/dist/server-extensions/VonageTelephonyExtension.js +89 -0
- package/dist/server-extensions/VonageTelephonyExtension.js.map +1 -0
- package/dist/sessionManager.d.ts +26 -0
- package/dist/sessionManager.d.ts.map +1 -0
- package/dist/sessionManager.js +38 -0
- package/dist/sessionManager.js.map +1 -0
- package/dist/telephony/RingCentralTelephonyService.d.ts +79 -0
- package/dist/telephony/RingCentralTelephonyService.d.ts.map +1 -0
- package/dist/telephony/RingCentralTelephonyService.js +225 -0
- package/dist/telephony/RingCentralTelephonyService.js.map +1 -0
- package/dist/telephony/TeamsMeetingsRouter.d.ts +21 -0
- package/dist/telephony/TeamsMeetingsRouter.d.ts.map +1 -0
- package/dist/telephony/TeamsMeetingsRouter.js +84 -0
- package/dist/telephony/TeamsMeetingsRouter.js.map +1 -0
- package/dist/telephony/TeamsMeetingsService.d.ts +76 -0
- package/dist/telephony/TeamsMeetingsService.d.ts.map +1 -0
- package/dist/telephony/TeamsMeetingsService.js +157 -0
- package/dist/telephony/TeamsMeetingsService.js.map +1 -0
- package/dist/telephony/TwilioTelephonyRouter.d.ts +30 -0
- package/dist/telephony/TwilioTelephonyRouter.d.ts.map +1 -0
- package/dist/telephony/TwilioTelephonyRouter.js +137 -0
- package/dist/telephony/TwilioTelephonyRouter.js.map +1 -0
- package/dist/telephony/TwilioTelephonyService.d.ts +91 -0
- package/dist/telephony/TwilioTelephonyService.d.ts.map +1 -0
- package/dist/telephony/TwilioTelephonyService.js +191 -0
- package/dist/telephony/TwilioTelephonyService.js.map +1 -0
- package/dist/telephony/VonageTelephonyRouter.d.ts +24 -0
- package/dist/telephony/VonageTelephonyRouter.d.ts.map +1 -0
- package/dist/telephony/VonageTelephonyRouter.js +175 -0
- package/dist/telephony/VonageTelephonyRouter.js.map +1 -0
- package/dist/telephony/VonageTelephonyService.d.ts +62 -0
- package/dist/telephony/VonageTelephonyService.d.ts.map +1 -0
- package/dist/telephony/VonageTelephonyService.js +162 -0
- package/dist/telephony/VonageTelephonyService.js.map +1 -0
- package/dist/telephony/calendar-scheduler.d.ts +41 -0
- package/dist/telephony/calendar-scheduler.d.ts.map +1 -0
- package/dist/telephony/calendar-scheduler.js +98 -0
- package/dist/telephony/calendar-scheduler.js.map +1 -0
- package/dist/telephony/index.d.ts +21 -0
- package/dist/telephony/index.d.ts.map +1 -0
- package/dist/telephony/index.js +26 -0
- package/dist/telephony/index.js.map +1 -0
- package/dist/telephony/ringcentral-runtime.d.ts +11 -0
- package/dist/telephony/ringcentral-runtime.d.ts.map +1 -0
- package/dist/telephony/ringcentral-runtime.js +20 -0
- package/dist/telephony/ringcentral-runtime.js.map +1 -0
- package/dist/telephony/teams-meetings-runtime.d.ts +11 -0
- package/dist/telephony/teams-meetings-runtime.d.ts.map +1 -0
- package/dist/telephony/teams-meetings-runtime.js +20 -0
- package/dist/telephony/teams-meetings-runtime.js.map +1 -0
- package/dist/telephony/teamsAcsMediaRegistry.d.ts +35 -0
- package/dist/telephony/teamsAcsMediaRegistry.d.ts.map +1 -0
- package/dist/telephony/teamsAcsMediaRegistry.js +86 -0
- package/dist/telephony/teamsAcsMediaRegistry.js.map +1 -0
- package/dist/telephony/telephony-runtime.d.ts +14 -0
- package/dist/telephony/telephony-runtime.d.ts.map +1 -0
- package/dist/telephony/telephony-runtime.js +23 -0
- package/dist/telephony/telephony-runtime.js.map +1 -0
- package/dist/telephony/twilioMediaRegistry.d.ts +60 -0
- package/dist/telephony/twilioMediaRegistry.d.ts.map +1 -0
- package/dist/telephony/twilioMediaRegistry.js +109 -0
- package/dist/telephony/twilioMediaRegistry.js.map +1 -0
- package/dist/telephony/vonage-runtime.d.ts +11 -0
- package/dist/telephony/vonage-runtime.d.ts.map +1 -0
- package/dist/telephony/vonage-runtime.js +20 -0
- package/dist/telephony/vonage-runtime.js.map +1 -0
- package/dist/telephony/vonageMediaRegistry.d.ts +38 -0
- package/dist/telephony/vonageMediaRegistry.d.ts.map +1 -0
- package/dist/telephony/vonageMediaRegistry.js +113 -0
- package/dist/telephony/vonageMediaRegistry.js.map +1 -0
- package/dist/types.d.ts +123 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +27 -0
- package/dist/types.js.map +1 -0
- package/package.json +48 -8
- package/README.md +0 -45
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Telephony and meetings exports for @memberjunction/telephony-adapters.
|
|
3
|
+
*
|
|
4
|
+
* @module @memberjunction/telephony-adapters
|
|
5
|
+
*/
|
|
6
|
+
export { TwilioCallMediaRegistry } from './twilioMediaRegistry.js';
|
|
7
|
+
export { TwilioTelephonyService, type TwilioTelephonyServiceDeps } from './TwilioTelephonyService.js';
|
|
8
|
+
export * from './TwilioTelephonyRouter.js';
|
|
9
|
+
export * from './telephony-runtime.js';
|
|
10
|
+
export { VonageCallMediaRegistry } from './vonageMediaRegistry.js';
|
|
11
|
+
export { VonageTelephonyService, type VonageTelephonyServiceDeps } from './VonageTelephonyService.js';
|
|
12
|
+
export * from './VonageTelephonyRouter.js';
|
|
13
|
+
export * from './vonage-runtime.js';
|
|
14
|
+
export { RingCentralTelephonyService, type RingCentralTelephonyServiceDeps } from './RingCentralTelephonyService.js';
|
|
15
|
+
export * from './ringcentral-runtime.js';
|
|
16
|
+
export * from './teamsAcsMediaRegistry.js';
|
|
17
|
+
export * from './TeamsMeetingsService.js';
|
|
18
|
+
export * from './TeamsMeetingsRouter.js';
|
|
19
|
+
export * from './teams-meetings-runtime.js';
|
|
20
|
+
export * from './calendar-scheduler.js';
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/telephony/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,KAAK,0BAA0B,EAAE,MAAM,6BAA6B,CAAC;AACtG,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wBAAwB,CAAC;AAGvC,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,KAAK,0BAA0B,EAAE,MAAM,6BAA6B,CAAC;AACtG,cAAc,4BAA4B,CAAC;AAC3C,cAAc,qBAAqB,CAAC;AAGpC,OAAO,EAAE,2BAA2B,EAAE,KAAK,+BAA+B,EAAE,MAAM,kCAAkC,CAAC;AACrH,cAAc,0BAA0B,CAAC;AAGzC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAG5C,cAAc,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Telephony and meetings exports for @memberjunction/telephony-adapters.
|
|
3
|
+
*
|
|
4
|
+
* @module @memberjunction/telephony-adapters
|
|
5
|
+
*/
|
|
6
|
+
// ── Twilio Programmable Voice + Media Streams ──────────────────────────────────────────
|
|
7
|
+
export { TwilioCallMediaRegistry } from './twilioMediaRegistry.js';
|
|
8
|
+
export { TwilioTelephonyService } from './TwilioTelephonyService.js';
|
|
9
|
+
export * from './TwilioTelephonyRouter.js';
|
|
10
|
+
export * from './telephony-runtime.js';
|
|
11
|
+
// ── Vonage Voice + WebSocket-media ─────────────────────────────────────────────────────
|
|
12
|
+
export { VonageCallMediaRegistry } from './vonageMediaRegistry.js';
|
|
13
|
+
export { VonageTelephonyService } from './VonageTelephonyService.js';
|
|
14
|
+
export * from './VonageTelephonyRouter.js';
|
|
15
|
+
export * from './vonage-runtime.js';
|
|
16
|
+
// ── RingCentral SIP softphone ──────────────────────────────────────────────────────────
|
|
17
|
+
export { RingCentralTelephonyService } from './RingCentralTelephonyService.js';
|
|
18
|
+
export * from './ringcentral-runtime.js';
|
|
19
|
+
// ── Teams meetings (Microsoft Graph cloud-communications + ACS application-hosted media) ──
|
|
20
|
+
export * from './teamsAcsMediaRegistry.js';
|
|
21
|
+
export * from './TeamsMeetingsService.js';
|
|
22
|
+
export * from './TeamsMeetingsRouter.js';
|
|
23
|
+
export * from './teams-meetings-runtime.js';
|
|
24
|
+
// ── Scheduled / invite-driven meeting join loop ────────────────────────────────────────
|
|
25
|
+
export * from './calendar-scheduler.js';
|
|
26
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/telephony/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,0FAA0F;AAC1F,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAmC,MAAM,6BAA6B,CAAC;AACtG,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wBAAwB,CAAC;AAEvC,0FAA0F;AAC1F,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAmC,MAAM,6BAA6B,CAAC;AACtG,cAAc,4BAA4B,CAAC;AAC3C,cAAc,qBAAqB,CAAC;AAEpC,0FAA0F;AAC1F,OAAO,EAAE,2BAA2B,EAAwC,MAAM,kCAAkC,CAAC;AACrH,cAAc,0BAA0B,CAAC;AAEzC,6FAA6F;AAC7F,cAAc,4BAA4B,CAAC;AAC3C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAE5C,0FAA0F;AAC1F,cAAc,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Process-wide holder for the startup-constructed RingCentral telephony service.
|
|
3
|
+
*
|
|
4
|
+
* @module @memberjunction/telephony-adapters
|
|
5
|
+
*/
|
|
6
|
+
import type { RingCentralTelephonyService } from './RingCentralTelephonyService.js';
|
|
7
|
+
/** Binds the startup-constructed RingCentral telephony service (called from server boot). */
|
|
8
|
+
export declare function SetRingCentralTelephonyService(service: RingCentralTelephonyService | undefined): void;
|
|
9
|
+
/** Returns the bound RingCentral telephony service, or `undefined` when telephony is not configured. */
|
|
10
|
+
export declare function GetRingCentralTelephonyService(): RingCentralTelephonyService | undefined;
|
|
11
|
+
//# sourceMappingURL=ringcentral-runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ringcentral-runtime.d.ts","sourceRoot":"","sources":["../../src/telephony/ringcentral-runtime.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAIpF,6FAA6F;AAC7F,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,2BAA2B,GAAG,SAAS,GAAG,IAAI,CAKrG;AAED,wGAAwG;AACxG,wBAAgB,8BAA8B,IAAI,2BAA2B,GAAG,SAAS,CAGxF"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Process-wide holder for the startup-constructed RingCentral telephony service.
|
|
3
|
+
*
|
|
4
|
+
* @module @memberjunction/telephony-adapters
|
|
5
|
+
*/
|
|
6
|
+
import { MJGlobal } from '@memberjunction/global';
|
|
7
|
+
const RINGCENTRAL_SERVICE_KEY = '__MJ_RINGCENTRAL_TELEPHONY_SERVICE__';
|
|
8
|
+
/** Binds the startup-constructed RingCentral telephony service (called from server boot). */
|
|
9
|
+
export function SetRingCentralTelephonyService(service) {
|
|
10
|
+
const store = MJGlobal.Instance.GetGlobalObjectStore();
|
|
11
|
+
if (store) {
|
|
12
|
+
store[RINGCENTRAL_SERVICE_KEY] = service;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/** Returns the bound RingCentral telephony service, or `undefined` when telephony is not configured. */
|
|
16
|
+
export function GetRingCentralTelephonyService() {
|
|
17
|
+
const store = MJGlobal.Instance.GetGlobalObjectStore();
|
|
18
|
+
return store ? store[RINGCENTRAL_SERVICE_KEY] : undefined;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=ringcentral-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ringcentral-runtime.js","sourceRoot":"","sources":["../../src/telephony/ringcentral-runtime.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAGlD,MAAM,uBAAuB,GAAG,sCAAsC,CAAC;AAEvE,6FAA6F;AAC7F,MAAM,UAAU,8BAA8B,CAAC,OAAgD;IAC3F,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,oBAAoB,EAAE,CAAC;IACvD,IAAI,KAAK,EAAE,CAAC;QACR,KAAK,CAAC,uBAAuB,CAAC,GAAG,OAAO,CAAC;IAC7C,CAAC;AACL,CAAC;AAED,wGAAwG;AACxG,MAAM,UAAU,8BAA8B;IAC1C,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,oBAAoB,EAAE,CAAC;IACvD,OAAO,KAAK,CAAC,CAAC,CAAE,KAAK,CAAC,uBAAuB,CAA6C,CAAC,CAAC,CAAC,SAAS,CAAC;AAC3G,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Process-wide holder for the startup-constructed Teams meetings service.
|
|
3
|
+
*
|
|
4
|
+
* @module @memberjunction/telephony-adapters
|
|
5
|
+
*/
|
|
6
|
+
import type { TeamsMeetingsService } from './TeamsMeetingsService.js';
|
|
7
|
+
/** Binds the startup-constructed Teams meetings service (called from server boot). */
|
|
8
|
+
export declare function SetTeamsMeetingsService(service: TeamsMeetingsService | undefined): void;
|
|
9
|
+
/** Returns the bound Teams meetings service, or `undefined` when Teams meetings are not configured. */
|
|
10
|
+
export declare function GetTeamsMeetingsService(): TeamsMeetingsService | undefined;
|
|
11
|
+
//# sourceMappingURL=teams-meetings-runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"teams-meetings-runtime.d.ts","sourceRoot":"","sources":["../../src/telephony/teams-meetings-runtime.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAItE,sFAAsF;AACtF,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,oBAAoB,GAAG,SAAS,GAAG,IAAI,CAKvF;AAED,uGAAuG;AACvG,wBAAgB,uBAAuB,IAAI,oBAAoB,GAAG,SAAS,CAG1E"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Process-wide holder for the startup-constructed Teams meetings service.
|
|
3
|
+
*
|
|
4
|
+
* @module @memberjunction/telephony-adapters
|
|
5
|
+
*/
|
|
6
|
+
import { MJGlobal } from '@memberjunction/global';
|
|
7
|
+
const TEAMS_SERVICE_KEY = '__MJ_TEAMS_MEETINGS_SERVICE__';
|
|
8
|
+
/** Binds the startup-constructed Teams meetings service (called from server boot). */
|
|
9
|
+
export function SetTeamsMeetingsService(service) {
|
|
10
|
+
const store = MJGlobal.Instance.GetGlobalObjectStore();
|
|
11
|
+
if (store) {
|
|
12
|
+
store[TEAMS_SERVICE_KEY] = service;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/** Returns the bound Teams meetings service, or `undefined` when Teams meetings are not configured. */
|
|
16
|
+
export function GetTeamsMeetingsService() {
|
|
17
|
+
const store = MJGlobal.Instance.GetGlobalObjectStore();
|
|
18
|
+
return store ? store[TEAMS_SERVICE_KEY] : undefined;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=teams-meetings-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"teams-meetings-runtime.js","sourceRoot":"","sources":["../../src/telephony/teams-meetings-runtime.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAGlD,MAAM,iBAAiB,GAAG,+BAA+B,CAAC;AAE1D,sFAAsF;AACtF,MAAM,UAAU,uBAAuB,CAAC,OAAyC;IAC7E,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,oBAAoB,EAAE,CAAC;IACvD,IAAI,KAAK,EAAE,CAAC;QACR,KAAK,CAAC,iBAAiB,CAAC,GAAG,OAAO,CAAC;IACvC,CAAC;AACL,CAAC;AAED,uGAAuG;AACvG,MAAM,UAAU,uBAAuB;IACnC,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,oBAAoB,EAAE,CAAC;IACvD,OAAO,KAAK,CAAC,CAAC,CAAE,KAAK,CAAC,iBAAiB,CAAsC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC9F,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Per-call ACS application-hosted-media pump registry for the Teams meetings ingress.
|
|
3
|
+
*
|
|
4
|
+
* @module @memberjunction/telephony-adapters
|
|
5
|
+
*/
|
|
6
|
+
import type { AcsInboundAudioFrame, IAcsMediaPump } from '@memberjunction/ai-bridge-teams';
|
|
7
|
+
/**
|
|
8
|
+
* The minimal ACS media-transport surface the registry drives.
|
|
9
|
+
*/
|
|
10
|
+
export interface IAcsMediaTransport {
|
|
11
|
+
/** Sends one outbound PCM16 frame on the call's application-hosted-media outbound audio socket. */
|
|
12
|
+
sendAudioFrame(pcm: ArrayBuffer): void;
|
|
13
|
+
/** Closes the call's media transport (best-effort; called on call end). */
|
|
14
|
+
close(): void;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Coordinates ACS application-hosted-media transports with the bridge bindings, keyed by Graph call id.
|
|
18
|
+
*/
|
|
19
|
+
export declare class TeamsAcsMediaRegistry implements IAcsMediaPump {
|
|
20
|
+
readonly SampleRate: number;
|
|
21
|
+
private readonly channels;
|
|
22
|
+
constructor(SampleRate?: number);
|
|
23
|
+
/** Ensures a channel exists for a call (called when a meeting bridge session for the call starts). */
|
|
24
|
+
RegisterCall(callId: string): void;
|
|
25
|
+
Send(callId: string, pcm: ArrayBuffer): void;
|
|
26
|
+
OnFrame(callId: string, handler: (frame: AcsInboundAudioFrame) => void): void;
|
|
27
|
+
OnHandRaise(callId: string, handler: (participantId: string, raised: boolean) => void): void;
|
|
28
|
+
AttachTransport(callId: string, transport: IAcsMediaTransport): void;
|
|
29
|
+
DispatchInbound(callId: string, frame: AcsInboundAudioFrame): void;
|
|
30
|
+
DispatchHandRaise(callId: string, participantId: string, raised: boolean): void;
|
|
31
|
+
EndCall(callId: string): void;
|
|
32
|
+
HasCall(callId: string): boolean;
|
|
33
|
+
private ensureChannel;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=teamsAcsMediaRegistry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"teamsAcsMediaRegistry.d.ts","sourceRoot":"","sources":["../../src/telephony/teamsAcsMediaRegistry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAE3F;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAC/B,mGAAmG;IACnG,cAAc,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI,CAAC;IACvC,2EAA2E;IAC3E,KAAK,IAAI,IAAI,CAAC;CACjB;AAUD;;GAEG;AACH,qBAAa,qBAAsB,YAAW,aAAa;aAG3B,UAAU;IAFtC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAuC;gBAEpC,UAAU,SAAQ;IAE9C,sGAAsG;IAC/F,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAMlC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,IAAI;IAS5C,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,GAAG,IAAI;IAI7E,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI;IAM5F,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,kBAAkB,GAAG,IAAI;IASpE,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,oBAAoB,GAAG,IAAI;IAUlE,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI;IAU/E,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAa7B,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAIvC,OAAO,CAAC,aAAa;CAQxB"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Per-call ACS application-hosted-media pump registry for the Teams meetings ingress.
|
|
3
|
+
*
|
|
4
|
+
* @module @memberjunction/telephony-adapters
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Coordinates ACS application-hosted-media transports with the bridge bindings, keyed by Graph call id.
|
|
8
|
+
*/
|
|
9
|
+
export class TeamsAcsMediaRegistry {
|
|
10
|
+
constructor(SampleRate = 16000) {
|
|
11
|
+
this.SampleRate = SampleRate;
|
|
12
|
+
this.channels = new Map();
|
|
13
|
+
}
|
|
14
|
+
/** Ensures a channel exists for a call (called when a meeting bridge session for the call starts). */
|
|
15
|
+
RegisterCall(callId) {
|
|
16
|
+
this.ensureChannel(callId);
|
|
17
|
+
}
|
|
18
|
+
// ── IAcsMediaPump ─────────────────────────────────────────────────────────────
|
|
19
|
+
Send(callId, pcm) {
|
|
20
|
+
const channel = this.ensureChannel(callId);
|
|
21
|
+
if (channel.transport) {
|
|
22
|
+
channel.transport.sendAudioFrame(pcm);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
channel.outboundBuffer.push(pcm);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
OnFrame(callId, handler) {
|
|
29
|
+
this.ensureChannel(callId).frameHandlers.push(handler);
|
|
30
|
+
}
|
|
31
|
+
OnHandRaise(callId, handler) {
|
|
32
|
+
this.ensureChannel(callId).handRaiseHandlers.push(handler);
|
|
33
|
+
}
|
|
34
|
+
// ── native-adapter side ─────────────────────────────────────────────────────
|
|
35
|
+
AttachTransport(callId, transport) {
|
|
36
|
+
const channel = this.ensureChannel(callId);
|
|
37
|
+
channel.transport = transport;
|
|
38
|
+
const buffered = channel.outboundBuffer.splice(0, channel.outboundBuffer.length);
|
|
39
|
+
for (const pcm of buffered) {
|
|
40
|
+
transport.sendAudioFrame(pcm);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
DispatchInbound(callId, frame) {
|
|
44
|
+
const channel = this.channels.get(callId);
|
|
45
|
+
if (!channel) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
for (const handler of channel.frameHandlers) {
|
|
49
|
+
handler(frame);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
DispatchHandRaise(callId, participantId, raised) {
|
|
53
|
+
const channel = this.channels.get(callId);
|
|
54
|
+
if (!channel) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
for (const handler of channel.handRaiseHandlers) {
|
|
58
|
+
handler(participantId, raised);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
EndCall(callId) {
|
|
62
|
+
const channel = this.channels.get(callId);
|
|
63
|
+
if (!channel) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
channel.transport?.close();
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
/* best-effort */
|
|
71
|
+
}
|
|
72
|
+
this.channels.delete(callId);
|
|
73
|
+
}
|
|
74
|
+
HasCall(callId) {
|
|
75
|
+
return this.channels.has(callId);
|
|
76
|
+
}
|
|
77
|
+
ensureChannel(callId) {
|
|
78
|
+
let channel = this.channels.get(callId);
|
|
79
|
+
if (!channel) {
|
|
80
|
+
channel = { frameHandlers: [], handRaiseHandlers: [], outboundBuffer: [] };
|
|
81
|
+
this.channels.set(callId, channel);
|
|
82
|
+
}
|
|
83
|
+
return channel;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=teamsAcsMediaRegistry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"teamsAcsMediaRegistry.js","sourceRoot":"","sources":["../../src/telephony/teamsAcsMediaRegistry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Process-wide holder for the startup-constructed telephony service, so the
|
|
3
|
+
* outbound `PlaceTwilioCall` GraphQL resolver reaches the SAME {@link TwilioTelephonyService}
|
|
4
|
+
* (and thus the same {@link TwilioCallMediaRegistry} the Media-Streams WSS attaches sockets to)
|
|
5
|
+
* that the inbound webhook router uses.
|
|
6
|
+
*
|
|
7
|
+
* @module @memberjunction/telephony-adapters
|
|
8
|
+
*/
|
|
9
|
+
import type { TwilioTelephonyService } from './TwilioTelephonyService.js';
|
|
10
|
+
/** Binds the startup-constructed Twilio telephony service (called from server boot). */
|
|
11
|
+
export declare function SetTwilioTelephonyService(service: TwilioTelephonyService | undefined): void;
|
|
12
|
+
/** Returns the bound Twilio telephony service, or `undefined` when telephony is not configured. */
|
|
13
|
+
export declare function GetTwilioTelephonyService(): TwilioTelephonyService | undefined;
|
|
14
|
+
//# sourceMappingURL=telephony-runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telephony-runtime.d.ts","sourceRoot":"","sources":["../../src/telephony/telephony-runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAI1E,wFAAwF;AACxF,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,sBAAsB,GAAG,SAAS,GAAG,IAAI,CAK3F;AAED,mGAAmG;AACnG,wBAAgB,yBAAyB,IAAI,sBAAsB,GAAG,SAAS,CAG9E"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Process-wide holder for the startup-constructed telephony service, so the
|
|
3
|
+
* outbound `PlaceTwilioCall` GraphQL resolver reaches the SAME {@link TwilioTelephonyService}
|
|
4
|
+
* (and thus the same {@link TwilioCallMediaRegistry} the Media-Streams WSS attaches sockets to)
|
|
5
|
+
* that the inbound webhook router uses.
|
|
6
|
+
*
|
|
7
|
+
* @module @memberjunction/telephony-adapters
|
|
8
|
+
*/
|
|
9
|
+
import { MJGlobal } from '@memberjunction/global';
|
|
10
|
+
const TWILIO_SERVICE_KEY = '__MJ_TWILIO_TELEPHONY_SERVICE__';
|
|
11
|
+
/** Binds the startup-constructed Twilio telephony service (called from server boot). */
|
|
12
|
+
export function SetTwilioTelephonyService(service) {
|
|
13
|
+
const store = MJGlobal.Instance.GetGlobalObjectStore();
|
|
14
|
+
if (store) {
|
|
15
|
+
store[TWILIO_SERVICE_KEY] = service;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/** Returns the bound Twilio telephony service, or `undefined` when telephony is not configured. */
|
|
19
|
+
export function GetTwilioTelephonyService() {
|
|
20
|
+
const store = MJGlobal.Instance.GetGlobalObjectStore();
|
|
21
|
+
return store ? store[TWILIO_SERVICE_KEY] : undefined;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=telephony-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telephony-runtime.js","sourceRoot":"","sources":["../../src/telephony/telephony-runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAGlD,MAAM,kBAAkB,GAAG,iCAAiC,CAAC;AAE7D,wFAAwF;AACxF,MAAM,UAAU,yBAAyB,CAAC,OAA2C;IACjF,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,oBAAoB,EAAE,CAAC;IACvD,IAAI,KAAK,EAAE,CAAC;QACR,KAAK,CAAC,kBAAkB,CAAC,GAAG,OAAO,CAAC;IACxC,CAAC;AACL,CAAC;AAED,mGAAmG;AACnG,MAAM,UAAU,yBAAyB;IACrC,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,oBAAoB,EAAE,CAAC;IACvD,OAAO,KAAK,CAAC,CAAC,CAAE,KAAK,CAAC,kBAAkB,CAAwC,CAAC,CAAC,CAAC,SAAS,CAAC;AACjG,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Per-call Media-Streams pump registry for the Twilio telephony ingress.
|
|
3
|
+
*
|
|
4
|
+
* This is the server half of the Twilio media plane: it implements the provider package's
|
|
5
|
+
* `ITwilioMediaPump` seam (which `RealTwilioBindings` drives) on top of the live Media-Streams
|
|
6
|
+
* websockets MJAPI accepts at `WSS /telephony/twilio/media`. It exists because of a lifecycle gap:
|
|
7
|
+
* when an INBOUND call's webhook fires, the bridge session starts and `RealTwilioBindings` registers
|
|
8
|
+
* its inbound-audio handler — but Twilio has not yet opened the media websocket (it does so only AFTER
|
|
9
|
+
* the webhook's `<Connect><Stream>` TwiML response). The registry bridges that gap by buffering
|
|
10
|
+
* handler registrations + outbound frames per Call SID and binding them to the socket once it connects
|
|
11
|
+
* (matched on the `start` frame's Call SID).
|
|
12
|
+
*
|
|
13
|
+
* Pure + unit-testable: the websocket is injected as the minimal {@link ITelephonyMediaSocket} surface,
|
|
14
|
+
* so the registry's buffering / dispatch / stream-SID capture logic is exercised with a fake socket and
|
|
15
|
+
* no `ws` install or network.
|
|
16
|
+
*
|
|
17
|
+
* @module @memberjunction/telephony-adapters
|
|
18
|
+
*/
|
|
19
|
+
import type { TwilioMediaFrame } from '@memberjunction/ai-bridge-twilio';
|
|
20
|
+
import type { ITwilioMediaPump } from '@memberjunction/ai-bridge-twilio';
|
|
21
|
+
/**
|
|
22
|
+
* The minimal websocket surface the registry drives — a structural subset of a `ws` socket, so the
|
|
23
|
+
* registry never imports `ws` and is testable with a fake. Outbound frames are sent as JSON strings.
|
|
24
|
+
*/
|
|
25
|
+
export interface ITelephonyMediaSocket {
|
|
26
|
+
/** Sends a serialized outbound Media-Streams frame on the call's socket. */
|
|
27
|
+
send(data: string): void;
|
|
28
|
+
/** Closes the socket (best-effort; called on call end). */
|
|
29
|
+
close(): void;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Coordinates Media-Streams sockets with the bridge bindings, keyed by Call SID. One instance per
|
|
33
|
+
* server, shared between the inbound-webhook service (which binds `RealTwilioBindings` over this as the
|
|
34
|
+
* `ITwilioMediaPump`) and the WSS server (which attaches sockets + dispatches inbound frames).
|
|
35
|
+
*/
|
|
36
|
+
export declare class TwilioCallMediaRegistry implements ITwilioMediaPump {
|
|
37
|
+
private readonly channels;
|
|
38
|
+
/** Ensures a channel exists for a call (called when a bridge session for the call starts). */
|
|
39
|
+
RegisterCall(callSid: string): void;
|
|
40
|
+
/** @inheritdoc — buffers when the socket has not yet connected; sends immediately once it has. Flushes buffer on 'clear'. */
|
|
41
|
+
Send(callSid: string, frame: TwilioMediaFrame): void;
|
|
42
|
+
/** @inheritdoc — stores the handler so frames delivered before AND after socket connect reach it. */
|
|
43
|
+
OnFrame(callSid: string, handler: (frame: TwilioMediaFrame) => void): void;
|
|
44
|
+
/** @inheritdoc — the captured stream SID, or `''` until the `start` frame arrives. */
|
|
45
|
+
GetStreamSid(callSid: string): string;
|
|
46
|
+
/**
|
|
47
|
+
* Binds a connected Media-Streams socket (and its captured stream SID) to a call, flushing any
|
|
48
|
+
* outbound frames produced while the socket was still connecting. Called by the WSS server on the
|
|
49
|
+
* `start` frame.
|
|
50
|
+
*/
|
|
51
|
+
AttachSocket(callSid: string, socket: ITelephonyMediaSocket, streamSid: string): void;
|
|
52
|
+
/** Dispatches one inbound Media-Streams frame to all registered handlers for the call. */
|
|
53
|
+
DispatchInbound(callSid: string, frame: TwilioMediaFrame): void;
|
|
54
|
+
/** Tears down a call's channel and closes its socket (called on socket close / call end). */
|
|
55
|
+
EndCall(callSid: string): void;
|
|
56
|
+
/** Whether a channel is currently tracked for the call (test/observability helper). */
|
|
57
|
+
HasCall(callSid: string): boolean;
|
|
58
|
+
private ensureChannel;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=twilioMediaRegistry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"twilioMediaRegistry.d.ts","sourceRoot":"","sources":["../../src/telephony/twilioMediaRegistry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAEzE;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IAClC,4EAA4E;IAC5E,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,2DAA2D;IAC3D,KAAK,IAAI,IAAI,CAAC;CACjB;AAYD;;;;GAIG;AACH,qBAAa,uBAAwB,YAAW,gBAAgB;IAC5D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAuC;IAEhE,8FAA8F;IACvF,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAM1C,6HAA6H;IACtH,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,IAAI;IAY3D,qGAAqG;IAC9F,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,GAAG,IAAI;IAIjF,sFAAsF;IAC/E,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAM5C;;;;OAIG;IACI,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,qBAAqB,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAU5F,0FAA0F;IACnF,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,IAAI;IAatE,6FAA6F;IACtF,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAarC,uFAAuF;IAChF,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAIxC,OAAO,CAAC,aAAa;CAQxB"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Per-call Media-Streams pump registry for the Twilio telephony ingress.
|
|
3
|
+
*
|
|
4
|
+
* This is the server half of the Twilio media plane: it implements the provider package's
|
|
5
|
+
* `ITwilioMediaPump` seam (which `RealTwilioBindings` drives) on top of the live Media-Streams
|
|
6
|
+
* websockets MJAPI accepts at `WSS /telephony/twilio/media`. It exists because of a lifecycle gap:
|
|
7
|
+
* when an INBOUND call's webhook fires, the bridge session starts and `RealTwilioBindings` registers
|
|
8
|
+
* its inbound-audio handler — but Twilio has not yet opened the media websocket (it does so only AFTER
|
|
9
|
+
* the webhook's `<Connect><Stream>` TwiML response). The registry bridges that gap by buffering
|
|
10
|
+
* handler registrations + outbound frames per Call SID and binding them to the socket once it connects
|
|
11
|
+
* (matched on the `start` frame's Call SID).
|
|
12
|
+
*
|
|
13
|
+
* Pure + unit-testable: the websocket is injected as the minimal {@link ITelephonyMediaSocket} surface,
|
|
14
|
+
* so the registry's buffering / dispatch / stream-SID capture logic is exercised with a fake socket and
|
|
15
|
+
* no `ws` install or network.
|
|
16
|
+
*
|
|
17
|
+
* @module @memberjunction/telephony-adapters
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Coordinates Media-Streams sockets with the bridge bindings, keyed by Call SID. One instance per
|
|
21
|
+
* server, shared between the inbound-webhook service (which binds `RealTwilioBindings` over this as the
|
|
22
|
+
* `ITwilioMediaPump`) and the WSS server (which attaches sockets + dispatches inbound frames).
|
|
23
|
+
*/
|
|
24
|
+
export class TwilioCallMediaRegistry {
|
|
25
|
+
constructor() {
|
|
26
|
+
this.channels = new Map();
|
|
27
|
+
}
|
|
28
|
+
/** Ensures a channel exists for a call (called when a bridge session for the call starts). */
|
|
29
|
+
RegisterCall(callSid) {
|
|
30
|
+
this.ensureChannel(callSid);
|
|
31
|
+
}
|
|
32
|
+
// ── ITwilioMediaPump ─────────────────────────────────────────────────────────
|
|
33
|
+
/** @inheritdoc — buffers when the socket has not yet connected; sends immediately once it has. Flushes buffer on 'clear'. */
|
|
34
|
+
Send(callSid, frame) {
|
|
35
|
+
const channel = this.ensureChannel(callSid);
|
|
36
|
+
if (frame.event === 'clear') {
|
|
37
|
+
channel.outboundBuffer.length = 0;
|
|
38
|
+
}
|
|
39
|
+
if (channel.socket) {
|
|
40
|
+
channel.socket.send(JSON.stringify(frame));
|
|
41
|
+
}
|
|
42
|
+
else if (frame.event !== 'clear') {
|
|
43
|
+
channel.outboundBuffer.push(frame);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/** @inheritdoc — stores the handler so frames delivered before AND after socket connect reach it. */
|
|
47
|
+
OnFrame(callSid, handler) {
|
|
48
|
+
this.ensureChannel(callSid).frameHandlers.push(handler);
|
|
49
|
+
}
|
|
50
|
+
/** @inheritdoc — the captured stream SID, or `''` until the `start` frame arrives. */
|
|
51
|
+
GetStreamSid(callSid) {
|
|
52
|
+
return this.channels.get(callSid)?.streamSid ?? '';
|
|
53
|
+
}
|
|
54
|
+
// ── WSS-server side ─────────────────────────────────────────────────────────
|
|
55
|
+
/**
|
|
56
|
+
* Binds a connected Media-Streams socket (and its captured stream SID) to a call, flushing any
|
|
57
|
+
* outbound frames produced while the socket was still connecting. Called by the WSS server on the
|
|
58
|
+
* `start` frame.
|
|
59
|
+
*/
|
|
60
|
+
AttachSocket(callSid, socket, streamSid) {
|
|
61
|
+
const channel = this.ensureChannel(callSid);
|
|
62
|
+
channel.socket = socket;
|
|
63
|
+
channel.streamSid = streamSid;
|
|
64
|
+
const buffered = channel.outboundBuffer.splice(0, channel.outboundBuffer.length);
|
|
65
|
+
for (const frame of buffered) {
|
|
66
|
+
socket.send(JSON.stringify(frame));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/** Dispatches one inbound Media-Streams frame to all registered handlers for the call. */
|
|
70
|
+
DispatchInbound(callSid, frame) {
|
|
71
|
+
const channel = this.channels.get(callSid);
|
|
72
|
+
if (!channel) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (frame.event === 'start' && frame.streamSid) {
|
|
76
|
+
channel.streamSid = frame.streamSid;
|
|
77
|
+
}
|
|
78
|
+
for (const handler of channel.frameHandlers) {
|
|
79
|
+
handler(frame);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/** Tears down a call's channel and closes its socket (called on socket close / call end). */
|
|
83
|
+
EndCall(callSid) {
|
|
84
|
+
const channel = this.channels.get(callSid);
|
|
85
|
+
if (!channel) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
channel.socket?.close();
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
/* best-effort */
|
|
93
|
+
}
|
|
94
|
+
this.channels.delete(callSid);
|
|
95
|
+
}
|
|
96
|
+
/** Whether a channel is currently tracked for the call (test/observability helper). */
|
|
97
|
+
HasCall(callSid) {
|
|
98
|
+
return this.channels.has(callSid);
|
|
99
|
+
}
|
|
100
|
+
ensureChannel(callSid) {
|
|
101
|
+
let channel = this.channels.get(callSid);
|
|
102
|
+
if (!channel) {
|
|
103
|
+
channel = { frameHandlers: [], outboundBuffer: [] };
|
|
104
|
+
this.channels.set(callSid, channel);
|
|
105
|
+
}
|
|
106
|
+
return channel;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=twilioMediaRegistry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"twilioMediaRegistry.js","sourceRoot":"","sources":["../../src/telephony/twilioMediaRegistry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Process-wide holder for the startup-constructed Vonage telephony service.
|
|
3
|
+
*
|
|
4
|
+
* @module @memberjunction/telephony-adapters
|
|
5
|
+
*/
|
|
6
|
+
import type { VonageTelephonyService } from './VonageTelephonyService.js';
|
|
7
|
+
/** Binds the startup-constructed Vonage telephony service (called from server boot). */
|
|
8
|
+
export declare function SetVonageTelephonyService(service: VonageTelephonyService | undefined): void;
|
|
9
|
+
/** Returns the bound Vonage telephony service, or `undefined` when telephony is not configured. */
|
|
10
|
+
export declare function GetVonageTelephonyService(): VonageTelephonyService | undefined;
|
|
11
|
+
//# sourceMappingURL=vonage-runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vonage-runtime.d.ts","sourceRoot":"","sources":["../../src/telephony/vonage-runtime.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAI1E,wFAAwF;AACxF,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,sBAAsB,GAAG,SAAS,GAAG,IAAI,CAK3F;AAED,mGAAmG;AACnG,wBAAgB,yBAAyB,IAAI,sBAAsB,GAAG,SAAS,CAG9E"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Process-wide holder for the startup-constructed Vonage telephony service.
|
|
3
|
+
*
|
|
4
|
+
* @module @memberjunction/telephony-adapters
|
|
5
|
+
*/
|
|
6
|
+
import { MJGlobal } from '@memberjunction/global';
|
|
7
|
+
const VONAGE_SERVICE_KEY = '__MJ_VONAGE_TELEPHONY_SERVICE__';
|
|
8
|
+
/** Binds the startup-constructed Vonage telephony service (called from server boot). */
|
|
9
|
+
export function SetVonageTelephonyService(service) {
|
|
10
|
+
const store = MJGlobal.Instance.GetGlobalObjectStore();
|
|
11
|
+
if (store) {
|
|
12
|
+
store[VONAGE_SERVICE_KEY] = service;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/** Returns the bound Vonage telephony service, or `undefined` when telephony is not configured. */
|
|
16
|
+
export function GetVonageTelephonyService() {
|
|
17
|
+
const store = MJGlobal.Instance.GetGlobalObjectStore();
|
|
18
|
+
return store ? store[VONAGE_SERVICE_KEY] : undefined;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=vonage-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vonage-runtime.js","sourceRoot":"","sources":["../../src/telephony/vonage-runtime.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAGlD,MAAM,kBAAkB,GAAG,iCAAiC,CAAC;AAE7D,wFAAwF;AACxF,MAAM,UAAU,yBAAyB,CAAC,OAA2C;IACjF,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,oBAAoB,EAAE,CAAC;IACvD,IAAI,KAAK,EAAE,CAAC;QACR,KAAK,CAAC,kBAAkB,CAAC,GAAG,OAAO,CAAC;IACxC,CAAC;AACL,CAAC;AAED,mGAAmG;AACnG,MAAM,UAAU,yBAAyB;IACrC,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,oBAAoB,EAAE,CAAC;IACvD,OAAO,KAAK,CAAC,CAAC,CAAE,KAAK,CAAC,kBAAkB,CAAwC,CAAC,CAAC,CAAC,SAAS,CAAC;AACjG,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Per-call WebSocket-media pump registry for the Vonage telephony ingress.
|
|
3
|
+
*
|
|
4
|
+
* @module @memberjunction/telephony-adapters
|
|
5
|
+
*/
|
|
6
|
+
import type { VonageControlEvent, IVonageMediaPump } from '@memberjunction/ai-bridge-vonage';
|
|
7
|
+
/**
|
|
8
|
+
* The minimal websocket surface the registry drives — a structural subset of a `ws` socket, so the
|
|
9
|
+
* registry never imports `ws` and is testable with a fake. Vonage audio is sent as BINARY frames (raw
|
|
10
|
+
* L16 PCM); the registry never sends text frames outbound (Vonage's media socket only accepts audio).
|
|
11
|
+
*/
|
|
12
|
+
export interface ITelephonyMediaSocket {
|
|
13
|
+
/** Sends one outbound BINARY audio frame (raw L16 PCM) on the call's socket. */
|
|
14
|
+
sendBinary(data: Uint8Array): void;
|
|
15
|
+
/** Sends one outbound TEXT control frame (JSON command, e.g. `{"action":"clear"}`) on the call's socket. */
|
|
16
|
+
sendText(data: string): void;
|
|
17
|
+
/** Closes the socket (best-effort; called on call end). */
|
|
18
|
+
close(): void;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Coordinates Vonage media websockets with the bridge bindings, keyed by call UUID.
|
|
22
|
+
*/
|
|
23
|
+
export declare class VonageCallMediaRegistry implements IVonageMediaPump {
|
|
24
|
+
private readonly channels;
|
|
25
|
+
/** Ensures a channel exists for a call (called when a bridge session for the call starts). */
|
|
26
|
+
RegisterCall(callUuid: string): void;
|
|
27
|
+
SendAudio(callUuid: string, pcm: ArrayBuffer): void;
|
|
28
|
+
OnAudio(callUuid: string, handler: (pcm: ArrayBuffer) => void): void;
|
|
29
|
+
OnEvent(callUuid: string, handler: (event: VonageControlEvent) => void): void;
|
|
30
|
+
Clear(callUuid: string): void;
|
|
31
|
+
AttachSocket(callUuid: string, socket: ITelephonyMediaSocket): void;
|
|
32
|
+
DispatchInboundAudio(callUuid: string, pcm: ArrayBuffer): void;
|
|
33
|
+
DispatchInboundEvent(callUuid: string, event: VonageControlEvent): void;
|
|
34
|
+
EndCall(callUuid: string): void;
|
|
35
|
+
HasCall(callUuid: string): boolean;
|
|
36
|
+
private ensureChannel;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=vonageMediaRegistry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vonageMediaRegistry.d.ts","sourceRoot":"","sources":["../../src/telephony/vonageMediaRegistry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAE7F;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IAClC,gFAAgF;IAChF,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;IACnC,4GAA4G;IAC5G,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,2DAA2D;IAC3D,KAAK,IAAI,IAAI,CAAC;CACjB;AAiBD;;GAEG;AACH,qBAAa,uBAAwB,YAAW,gBAAgB;IAC5D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAuC;IAEhE,8FAA8F;IACvF,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAMpC,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,IAAI;IAmBnD,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,IAAI,GAAG,IAAI;IAIpE,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,GAAG,IAAI;IAI7E,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAY7B,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,qBAAqB,GAAG,IAAI;IASnE,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,IAAI;IAU9D,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,GAAG,IAAI;IAUvE,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAa/B,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAIzC,OAAO,CAAC,aAAa;CAQxB"}
|