@ 3cx/ 呼叫控制- sdk
TypeScript的3CX呼叫控制SDK为3CX呼叫控制API提供了更高级的接口.
安装
npm install @3cx/call-control-sdk
快速启动
import { CallControlClient } from "@3cx/call-control-sdk";
const client = new CallControlClient({
pbxBase: "https://your-pbx.example.com",
appId: "your-app-id",
appSecret: "your-app-secret",
});
await client.connect();
client.on("participantConnected", async (participant) => {
console.log(`Participant ${participant.id} connected`);
// Get audio stream from the caller (PCM 8kHz 16-bit mono)
const audioStream = await participant.getAudioStream();
// Create audio writer to the caller
const audioWriter = participant.getAudioWriter();
// Pipe audio through your AI provider (STT -> Agent -> TTS)
// ...
// Write PCM 8kHz 16-bit mono audio back
audioWriter.write(pcmBuffer);
// Call actions directly on the participant
await participant.transfer("1001");
});
client.on("participantDisconnected", (participantId) => {
// SDK automatically cleans up audio streams/writers
console.log(`Participant ${participantId} disconnected`);
});
WebSocket 重新连接
在出人意料的断开时,SDK会自动与指数回放连接.
默认的 永不放弃 (单位:千美元)maxReconnects: Infinity) (中文(简体) ).
| 选项 | 默认 | 说明 |
|---|---|---|
websocket.maxReconnects | Infinity | 放弃前的尝试。 设定一个有限的数字以停止重试 . |
websocket.reconnectDelayMs | 5000 | 第一次重试前的基数延后( 每次尝试都用 Doubles) . |
websocket.reconnectBackoffMaxMs | 120000 | 每回试2分)上盖. |
延迟会增加大约5分 10分 20分 达到上限 抓取失败 重新连接使用相同的回放. 限制重试 :
websocket: { maxReconnects: 5 }
延期参与者监测
当扩展附着在应用程序的服务本位( 受控 DNs) 时, SDK 发布单独的事件 用于他们的呼叫活动。 这样你就可以监视那些电话 扩展时不将其与应用程序自己的可编程DN的调用相混为一谈.
// Calls on the app's own DN - full control (audio + call actions)
client.on("participantConnected", async (participant) => {
console.log(`Own DN call from ${participant.info.party_caller_id}`);
const audio = await participant.getAudioStream(); // works
// ...
});
// Calls on monitored extensions - call actions only, no audio
client.on("extensionParticipantConnected", async (participant) => {
console.log(
`Extension ${participant.dn} call from ${participant.info.party_caller_id}`,
);
// participant.getAudioStream() -> throws Error
await participant.transfer("1001"); // works
});
client.on("extensionParticipantDisconnected", (participantId) => {
console.log(`Extension call ${participantId} ended`);
});
为什么没有关于扩展参与者的音频?
音频流和DTMF仅供应用程序自己的可编程DN(RoutePoint)使用.
分机电话由分机自己的设备(IP电话、软电话、,
——媒体路径在PBX和那个设备之间直接走. 可编程
扩展从不为这些电话坐在媒体的道路上,所以没有音频可以截取
或注射 。 调用控制动作( 调用、 调用、 调用、 路由) 在信号中工作
级别; answer() 需要扩展时 supportsDirectControl (中文(简体) ).
事件周期说明
路由点( app's own DN) 自动回答来电 - 参与者
几乎总是以身份到达 Connected这样 participantConnected 立即开火.
扩展功能行为不同: 设备上的第一个调用环( S)Ringing),且仅限
变成 Connected 用户接后. 这个 extensionParticipantConnected 事件
只有在扩展部分实际响应呼叫时才开火. 检测进货( 环行)
呼叫扩展名, 请收听 extensionParticipantUpdated 检查
participant.info.status数字 :
client.on("extensionParticipantUpdated", (participant) => {
if (participant.info.status === "Ringing") {
console.log(`Extension ${participant.dn} is ringing`);
if (participant.supportsDirectControl) {
void participant.answer(); // uaCSTA leg only
}
}
});
多设备扩展获取 每个设备一个参与者腿调用 answer() 编辑
带脚的 supportsDirectControl === true而不是移动/软手机腿上.
| 能力 | 拥有 DN( RoutePoint) | 扩展DNA |
|---|---|---|
| 调用事件 | participantConnected 编号 : Updated 编号 : Disconnected | extensionParticipantConnected 编号 : Updated 编号 : Disconnected |
| 音频流 | 对 | 没有 |
| 自动取款机 | 对 | 没有 |
| 传送/ 丢弃 | 对 | 对 |
| 变形 | 对 | 对.. Ringing 仅输入 |
| 路径到 | 对 | 对.. Ringing 或者说 Connected |
| 答复 | 对 | 仅与 supportsDirectControl (华夏) |
| 附加数据 | 对 | 对 |
divert() 重定向一个未回复的呼叫——在 Ringing 入境 脚步( 失败)
Connected) (中文(简体) ). routeTo() 在参与者留在电话中时增加其他路线:
有效时间 Ringing 或者说 Connected启用 transfer() 已确认的盲转
打电话 也不适用于出入境 Dialing 脚.
外出通话
makeCall 返回直接从 API 响应中创建的参与者ID,所以您
用不着等WebSocket事件来联系到这个电话:
const participantId = await client.makeCall("101");
// or from a specific source DN:
const participantId = await client.makeCall("101", "cctest2");
if (participantId !== undefined) {
await client.attachPartyData(participantId, { public_ticket: "1234" });
}
PBX 可返回 202 Accepted (电话已接受,id尚未提供)。 这样的话
makeCall 决定: undefined - 通过WebSocket事件追踪电话.
所附数据
将元数据附加到呼叫中 attachParticipantData 编号 : attachPartyData。 。 。 . 每把钥匙
必须是前缀 public_ - PBX 拒绝带有 HTTP 的其他密钥 422。 。 。 .
两种方法都采用 同一参与方的身份证 并撰写两个不同的字段 那个 参与人 记录(同一条呼叫腿)。 没错 没有 瞄准焦距的 DN 或第二个参与者反对:
| SDK API/访问器 | 此参与者的 PBX 字段 | 含义 |
|---|---|---|
attachParticipantData 编号 : participantData | participant_attached_data | 有关这名参与者自己的腿的数据 |
attachPartyData 编号 : partyData | caller_attached_data | 此段的会场( 相同的参与者 ID) 中的会场数据 |
两个值都从 受控参与人手柄 ——相机没有 暴露为单独的对象。 需要时随附缔约方关于监测扩展的数据 元数据以活过传输或类似操作.
// via the client (same participantId for both)
await client.attachParticipantData(participantId, { public_ticket: "1234" });
await client.attachPartyData(participantId, { public_peer: "181" });
// or via a participant handle
await participant.attachParticipantData({ public_ticket: "1234" });
await participant.attachPartyData({ public_peer: "181" });
console.log(participant.participantData.public_ticket); // '1234'
console.log(participant.partyData.public_peer); // '181'
await participant.attachPartyData({ public_ticket: "5678" });
await participant.refresh(); // party data is not pushed over WebSocket
console.log(participant.partyData.public_ticket); // '5678'
为了检查另一个DNA的腿,使用 client.getState().callcontrol.get(dn)?.participants
(或从 getExtensionParticipantHandle) (中文(简体) ). 没有
getParticipantByDn 帮手.
MCP 一体化
使用带有 3CX MCP 服务器的 SDK 令牌商店 :
const authProvider = client.createMcpAuthProvider();
const mcpUrl = client.getMcpUrl();
const mcpServer = new MCPServerStreamableHttp({
url: mcpUrl,
authProvider,
});
API 参考
Participant
| 方法 | 说明 |
|---|---|
id | 数字参与者编号 |
dn | DN 号码 此参与者属于 |
isExtensionParticipant | true 如果这是受监视的扩展参与者 |
info | 原始 3CX CallParticipant 元数据 |
destroyed | 是否清理了参与者 |
supportsDirectControl | 密码 direct_control (uACSTA); 所需时间 answer() 扩展时 |
participantData | 这条腿 participant_attached_data 通过 attachParticipantData() (单位:千美元){} (无) |
partyData | 剪辑器 caller_attached_data 穿过这条腿 attachPartyData() (单位:千美元){} (无) |
getAudioStream() | 获取可读 PCM 音频流( 仅拥有 DN) |
getAudioWriter() | 获取可写音频频道( 仅拥有 DN) |
makeCall(to) | 从此参与者的 DN 中设置一个新的独立外出呼叫 |
transfer(destination, reason?) | 转移到目的地 |
drop() | 调用 |
answer() | 回答呼叫( Route Point 或 supportsDirectControl 仅限) |
routeTo(destination, timeout?, reason?) | 添加可选择的路由( N)Ringing 或者说 Connected(中文(简体) ) |
divert(destination, reason?) | 重定向未回复的呼叫( N)Ringing (仅输入) |
transferToVoiceMail(dn, reason?) | 转入语音信箱 |
routeToVoiceMail(dn, timeout?, reason?) | 语音邮件路径 |
divertToVoiceMail(dn, reason?) | 切入语音邮件 |
attachParticipantData(data) | 写入 participant_attached_data 在这条腿上 |
attachPartyData(data) | 写入 caller_attached_data (不是远程DN) |
refresh() | 从 REST API 中获取此腿并更新缓存状态 |
cancelStreamQueue() | 取消 PBX 排队的外出音频( 结束活动 POST; 偏好) getAudioWriter().clear() (用于驳船) |
CallControlClient
| 方法 | 说明 |
|---|---|
connect() | 连接到 3CX PBX (Auth + WebSocket) |
disconnect() | 断开和清理资源 |
getParticipantHandle(id) | 搜索活动 自定义 Participant 由 ID 处理 |
getExtensionParticipantHandle(id) | 搜索活动 扩展 Participant 用ID处理( 用于监测的DNA) |
getAudioStream(participantId) | 获取可读 PCM 音频流 |
createAudioWriter(participantId) | 创建可写入的音频频道, 并保持保留 |
transfer(participantId, destination) | 转会参与者转会至延期 |
drop(participantId) | 从呼叫中放弃参与者 |
answer(participantId) | 回答呼叫( Route Point 或 direct_control / 仅限 uACSTA ) |
routeTo(participantId, destination) | 添加可选择的路由( N)Ringing 或者说 Connected) (中文(简体) ). 没有 timeout ——使用 participant.routeTo() 暂停 |
divert(participantId, destination) | 重定向未回复的呼叫( N)Ringing (仅输入) |
makeCall(to, from?) | 发送呼叫 返回创建的参与者ID( HTTP 200) 或 undefined (HTTP 202) (韩语). from 默认为 appId |
attachParticipantData(participantId, data) | 写入 participant_attached_data 在那个参与者的腿上 |
attachPartyData(participantId, data) | 写入 caller_attached_data 该参与者的腿上(相同的身份证;而不是远程DNA) |
cancelStreamQueue(participantId) | 取消 PBX 排队的外出音频( 结束活动 POST; 偏好) createAudioWriter().clear() (用于驳船) |
controlParticipant(participantId, method, body?) | 通用呼叫控制动作 |
getParticipant(id) | 原始内容 CallParticipant 从状态到 只有应用程序自己的 DN。扩展腿:使用 getExtensionParticipantHandle(id) 或者说 getState().callcontrol.get(dn)?.participants |
getState() | 获取全调控制状态( 所有可见 DN 及其参与者) |
getFullInfo() | 从 REST API 获取完整状态( 不更新缓存) |
refreshParticipant(participantId) | 从 REST API 中获取一个参与者并更新缓存状态 + 控件 |
createMcpAuthProvider() | 创建 MCP 认证提供者 |
getMcpUrl() | 获取 MCP 端点 URL |
事件 - 路由点( Own DN)
在应用程序自己的可编程DN上为参与者被炒作. 全能控制:音频流,DTMF,和调用动作.
| 活动 | 有效载荷 | 说明 |
|---|---|---|
participantConnected | Participant | 连接到呼叫的参与者 |
participantDisconnected | number | 取消召集 |
participantUpdated | Participant | 参加国已更改 |
dtmf | string, number | DTMF 收到的数字和按键的参与者 |
事件 - 有监测的扩展
在服务校长的延期上为与会者解雇。 仅调用控制 - 没有音频或DTMF(媒体路径由扩展自己的设备处理,而不是由可编程扩展处理).
| 活动 | 有效载荷 | 说明 |
|---|---|---|
extensionParticipantConnected | Participant | 连接扩展参与者 |
extensionParticipantDisconnected | number | 延期参与者已删除 |
extensionParticipantUpdated | Participant | 扩展参与者状态已更改 |
事件 - 连接
| 活动 | 有效载荷 | 说明 |
|---|---|---|
connected | - 说吧 | 已连接 WebSocket |
disconnected | - 说吧 | WebSocket 已断开 |
error | Error | 发生错误 |
许可证
麻省理工学院