@94ai/softphone v5.0.8
前言
94ai软电话前端SDK,框架无关(支持vue,react,angular等)
项目参考demo: https://gitee.com/softphone-demo(有权限问题,具体找94智能开发同事拉入团队组织即可)
本地调试: yarn add sip.js@portal:../SIP修改v2.js
安装
94智能sdk目前暂不在公网公布sdk源码,如有需要,可以联系94智能开发同事加入团队,具体步骤:
获取加入团队邀请链接
向94智能开发同事申请到【加入到团队的连接】,如: https://account-devops.aliyun.com/account/invite?sign=ab965d478dbed5dad3cc145a5a5b406c&next_url=https%3A%2F%2Fpackages.aliyun.com%3ForgId%3D644f755a97d94d909e43534c
进入上述链接后,进到阿里云登录页
如果你是主账号,直接登录即可:

如果你是RAM子账号,选择下面RAM用户登录:

进入RAM 用户登录页登录即可:

阿里的数字安全码
登录过程会提示你填写 验证虚拟MFA设备数字安全码
1.如果以前使用过阿里云产品并绑定过
可以直接在【阿里云app】或使用【虚拟MFA验证小程序】获取【数字安全码】填写即可,如下:
- 下载阿里云app

- 定位首页的mfa图标

- 找到对应账号的数字安全码

2.如果以前没有绑定过
如下面选择 虚拟 MFA 设备

然后在手机安装【阿里云app】或使用【小程序虚拟MFA验证】,然后扫码绑定设备

在设备添加账号点确定

之后会每隔一小段时间会刷新获取到最新的【数字安全码】

3.如果使用小程序
在微信搜索mfa二次验证如下,具体可以百度下:

4.设置昵称申请加入
登录成功后会提示你加入团队,设置号昵称点加入


查看个人账号信息
等待审核通过后,刷新页面,点击进入企业

1.选择角色
选择作为研发者,开始工作

2.进入制品仓库
在工作台选择【制品仓库】进入

3.查看账号密码
选择设置查看个人账号信息


设置私库源
1.新建rc文件
在需要使用94智能sdk的项目根目录,新建一个rc文件:
- 如果你使用的npm或pnpm,新建.npmrc,内容如下:
@94ai:registry=https://packages.aliyun.com/644f755a97d94d909e43534c/npm/npm-registry/
//packages.aliyun.com/644f755a97d94d909e43534c/npm/npm-registry/:username=username
//packages.aliyun.com/644f755a97d94d909e43534c/npm/npm-registry/:_password=password
//packages.aliyun.com/644f755a97d94d909e43534c/npm/npm-registry/:always-auth=true- 如果你使用的yarn1,新建.yarnrc,内容如下:
"@94ai:registry" "https://packages.aliyun.com/644f755a97d94d909e43534c/npm/npm-registry/"
"//packages.aliyun.com/644f755a97d94d909e43534c/npm/npm-registry/:username" "username"
"//packages.aliyun.com/644f755a97d94d909e43534c/npm/npm-registry/:_password" "password"
"//packages.aliyun.com/644f755a97d94d909e43534c/npm/npm-registry/:always-auth" true- 如果你使用的yarn2~3,新建.yarnrc.yml,内容如下:
enableImmutableInstalls: false
nodeLinker: node-modules
yarnPath: .yarn/releases/yarn-3.1.1.cjs
#npmRegistryServer: "https://nexusdev.k8s.94ai.pro/repository/npm-group/"
npmScopes:
94ai:
npmRegistryServer: "https://packages.aliyun.com/644f755a97d94d909e43534c/npm/npm-registry/"
npmAlwaysAuth: true
npmAuthIdent: "username:password"
#unsafeHttpWhitelist:
# - 192.168.20.92.配置个人账号信息
把对应rc文件
username替换成你的账号名称如果你使用的是yarn1,npm或pnpm,则把你的账号密码做base64加密之后替换掉对应rc文件
password,如在这里在线base64加密获取base64加密的密码

- 如果你使用的是yarn2~3,则把你的账号密码直接替换掉对应rc文件
password
3.安装依赖
之后该项目只要是@94ai域的私包都会经过94智能私服抓取
其他包【包括@94ai域私包的子包(非@94ai域)】都会经由个人电脑配置的npm包registry源抓取
执行install命令即可成功安装@94ai域的所有私包,包括sdk,如
$ yarn add @94ai/softphone
# or
$ npm i @94ai/softphone
# or
$ pnpm add @94ai/softphone使用
初始化
1.作为NPM包使用
// Example:
// 1.softphone.ts
import { UserAgent, UserAgentManager, URI } from '@94ai/softphone'
import FingerprintJS from '@fingerprintjs/fingerprintjs'
import useToast from '@/utils/useToast'
export function createRandomToken(size, base = 32) {
let token = "";
for (let i = 0; i < size; i++) {
const r = Math.floor(Math.random() * base);
token += r.toString(base);
}
return token;
}
// transport层配置
export interface TransportOptions {
/** websocket协商地址, server和wsServers 必须二选一*/
server?: string
/** 多个地址开启负载均衡模式 */
wsServers?: string | string[] | {
/** websocket协商地址 */
ws_uri: string,
/** 权重 */
weight: number
}[]
/**
* websocke初始化连接等待超时时间
* @default 5
*/
connectionTimeout?: number
/**
* transport层客户端保活最大重连尝试次数
* @default 3
*/
maxReconnectionAttempts?: number
/**
* transport层客户端保活重连动作执行间隔时间,单位秒,同UserAgentOptions.reconnectionDelay
* @default 4
*/
reconnectionTimeout?: number
/**
* transport层The time (Number) in seconds to wait in between CLRF keepAlive sequences are sent.
* @default 0
*/
keepAliveInterval?: number
/**
* transport层The time (Number) in seconds to debounce sending CLRF keepAlive sequences by
* @default 10
*/
keepAliveDebounce?: number
/**
* transport层If true, messages sent and received by the transport are logged.
* @default false
*/
traceSip?: boolean
}
// sip层配置
export interface UserAgentOptions {
/**
* 通过openApi获取坐席账号分机密码
* @default ''
*/
authorizationPassword: string,
/**
* 通过openApi获取坐席账号分机用户名
* @default ''
*/
authorizationUsername: string,
/**
* 指纹,唯一标志,用来排查线路故障,默认随机指纹,可选
* @default createRandomToken(12) + ".invalid"
*/
viaHost?: string,
/**
* sip服务地址,必填,需要服务可达的地址
* @default new URI("sip", "anonymous." + createRandomToken(6), "anonymous.invalid") })
*/
uri: URI,
/**
* sip日志查看等级,一般情况下生产开error,开发用debugger
* @default 'log'
*/
logLevel?: 'debug' | 'log' | 'warn' | 'error',
/**
* 一般设置同authorizationUsername,相当于MicroSIP的显示名称
* @default createRandomToken(8)
*/
contactName?: string
/**
* 签入来电后多长时间不执行接听会话自动结束会话,单位秒
* @default 60
*/
noAnswerTimeout?: number,
/**
* transport层协议配置
*/
transportOptions: TransportOptions,
/**
* sip层 - 重连尝试间隔,为了兼容sipjs,同reconnectionInterval
* @default 3
*/
reconnectionDelay?: number,
/**
* sip层 - 重连尝试间隔,单位秒
* @default 3
*/
reconnectionInterval?: number,
/**
* sip层 - 重连失败最大尝试次数
* @default 100
*/
reconnectionAttempts?: number,
/**
* sip层 - 重连成功后尝试重新注册检间隔,单位秒
* @default 3
*/
registerInterval?: number,
/**
* sip层 - 重连成功最大尝试注册次数
* @default 3
*/
registerAttempts?: number
/**
* sip层 - ping动作间隔,单位秒
* @default 8
*/
optionsPingInterval?: number
/**
* sip层 - ping最大失败尝试次数后开始重连,防止网络抖动引起非必要重连
* @default 3
*/
optionsPingAttempts?: number
/**
* sip层 - 自定义通讯header
*/
sipHeaders?: Array<string>;
}
export class SoftphoneManager {
static #getDeviceId: () => Promise<string>
#userAgentManager: InstanceType<typeof UserAgentManager>
static {
/**
* 获取指纹
*/
SoftphoneManager.#getDeviceId = (() => {
let visitorId = ''
return async (): Promise<string> => {
if (visitorId) return visitorId
const fp = await FingerprintJS.load()
const result = await fp.get()
visitorId = result.visitorId
return visitorId
}
})()
}
public async getUserAgentManager = () => {
if (!this.#userAgentManager) {
this.#userAgentManager = UserAgentFactory.getUserAgentManager(await this.initSeatsInfo()) // 👈 得到softphone代理对象
}
return this.#userAgentManager
}
public getUserAgentManagerSync = (config?: UserAgentOptions) => {
if (!this.#userAgentManager) {
this.#userAgentManager = UserAgentFactory.getUserAgentManager(config) // 👈 得到softphone代理对象
}
return this.#userAgentManager
}
/**
* 通过openApi获取分机信息
*/
public async initSeatsInfo = (): Promise<UserAgentOptions> => {
const result = await getSeatsInfo()
if (result.code === 200) {
const {
extPassword, // 分机密码
extensionNumber, // 分机号
wsRegisterAddress, // socket地址
wsProtocol // socket协议
} = result.data
return {
authorizationPassword: extPassword,
authorizationUsername: extensionNumber,
viaHost: `${await SoftphoneManager.#getDeviceId()}.sip`,
uri: UserAgent.makeURI(`sip:${extensionNumber}@${wsRegisterAddress}`),
logLevel: 'error',
transportOptions: {
server: `${wsProtocol}://${wsRegisterAddress}`
},
contactName: extensionNumber
}
}
useToast.showToast('获取分机信息失败')
throw new Error('获取分机信息失败')
}
/**
* 签入
*/
public connect = async () => {
try {
await this.getUserAgentManagerSync().prepareUserAgent(
/** config */
{
/** 当软电话状态变化时会实时刷新这个方法 */
refresh: (path: keyof typeof userAgentStatusDefault, value: boolean) => {
}
},
/** event */
{
/** 当有外呼过来 */
onInvite: async (invitation: Invitation) => {
}
})
} catch (e) {
const errorInfo = e as Error
if (errorInfo.message === 'sip register fail with code 503' ||
errorInfo.message.indexOf('WebSocket closed') > -1 && errorInfo.message.indexOf('code: 1006') > -1) {
useToast.showToast('软电话服务器异常,签入失败')
} else {
useToast.showToast(errorInfo.message)
}
throw e
}
}
// ...
}
export default new SoftphoneManager()
// 2.App.vue
import commonSoftphone from './softphone.ts'
onBeforeMount(async () => {
await commonSoftphone.getUserAgentManager()
})
// 3. softphone.vue
// <button @click="connect">签入</button>
import commonSoftphone from './softphone.ts'
// 签入
const connect = async () => {
await commonSoftphone.connect()
}2.直接在JavaScript中使用
- 获取umd文件
- 确保安装了node,随手新建一个目录,打开cmd或bash。
- 设置@4ai域账号授权,依次执行执行如下,其中
:username=xxxx替换你的账号名字,:_password=xxxx替换你的账号密码在做base64加密后的结果
npm config set @94ai:registry=https://packages.aliyun.com/644f755a97d94d909e43534c/npm/npm-registry/
npm config set //packages.aliyun.com/644f755a97d94d909e43534c/npm/npm-registry/:username=xxx
npm config set //packages.aliyun.com/644f755a97d94d909e43534c/npm/npm-registry/:_password=xxx
npm config set //packages.aliyun.com/644f755a97d94d909e43534c/npm/npm-registry/:always-auth=true- 最后执行
npx -y @94ai/softphone -- sdk-umd,之后在当前执行命令路径下即可获取到softphone.umd.min.js
- 在index.html引入
softphone.umd.min.js文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" />
<title>softphone</title>
<style>
#softphone-app {
text-align: center;
padding-top: 50px;
}
</style>
</head>
<body>
<div id="softphone-app">
<button id="connectToServer">连接服务器</button>
<br>
<br>
<button id="disconnect" disabled>断开连接服务器</button>
<br>
<br>
<button id="ignore" disabled>忽略</button>
<br>
<br>
<button id="answer" disabled>接听</button>
<br>
<br>
<button id="hangUp" disabled>挂断</button>
<br>
<br>
<button id="press" disabled>按*转人工</button>
<br>
<br>
<button id="localVoiceAccess" disabled>本地声音接入</button>
<br>
<br>
<button id="remoteSoundAccess" disabled>远程声音接入</button>
<br>
<br>
<button id="localSoundDisconnection" disabled>本地声音断开</button>
<br>
<br>
<button id="remoteSoundDisconnection" disabled>远程声音断开</button>
<br>
<br>
<audio
id="remoteAudio"
controls
style="display:none"
>
<p>Your browser doesn't support HTML5 audio - remoteAudio</p>
</audio>
<audio
id="localAudio"
style="display:none"
src="./antique_phone.mp3"
controls
loop
>
<p>Your browser doesn't support HTML5 audio - localAudio</p>
</audio>
</div>
<script src="../lib/softphone.umd.min.js"></script>
<script src="./fp.umd.min.js"></script>
<script>
/**
* 1.确保你的企业 【坐席外呼依赖】配置项 是【标识】 (默认是【登录】,如果不确定联系94运维在管理后台查看以及配置)
* 2. 使用 【https://94ai.yuque.com/staff-kqoz0c/xed39g/obnqst?singleDoc# 《SG-九四智能API开放文档(全)》 密码:tvgm】 3.1 获取坐席信息,以及3.2 修改坐席状态接口,保证坐席状态在线
* 3. 点击连接服务器
* 4. 在决策外呼一个任务,确保你的坐席账号在任务配置的坐席组里
* 5. 电话过来后会触发签入注册好的onInvite,这个时候就可以接听,挂断,忽略,转人工,静音等等
* 6. 《SG-九四智能API开放文档(全)》该文档获取授权调用接口的问题找 航航同学
*/
const getDeviceId = (() => {
let visitorId = ''
return async () => {
if (visitorId) return visitorId
const fp = await FingerprintJS.load()
const result = await fp.get()
visitorId = result.visitorId
return visitorId
}
})()
document.addEventListener('DOMContentLoaded', async (event) => {
const phoneRing = './antique_phone.mp3' // 👈 铃声自己当以一个音频即可
const ignore = document.getElementById('ignore')
const answer = document.getElementById('answer')
const hangUp = document.getElementById('hangUp')
const connectToServer = document.getElementById('connectToServer')
const disconnect = document.getElementById('disconnect')
const press = document.getElementById('press')
const localVoiceAccess = document.getElementById('localVoiceAccess')
const remoteSoundAccess = document.getElementById('remoteSoundAccess')
const localSoundDisconnection = document.getElementById('localSoundDisconnection')
const remoteSoundDisconnection = document.getElementById('remoteSoundDisconnection')
const localAudio = document.getElementById('localAudio')
const remoteAudio = document.getElementById('remoteAudio')
const viaHost = `${await getDeviceId()}.sip`
/** 接口获取开始 */
/** 通过接口获取 https://94ai.yuque.com/staff-kqoz0c/xed39g/obnqst?singleDoc# 《SG-九四智能API开放文档(全)》 密码:tvgm 👈 不知道怎么调接口找 航航同学 */
/** 3.1坐席相关接口查询坐席信息 */
const extensionNumber = '9288'
const extPassword = 'zjh13542240708'
const wsProtocol = 'wss'
const wsRegisterAddress = 's28.94ai.com:7443'
const sipServerHost = `sip:${extensionNumber}@${wsRegisterAddress}`
const wsAddress = `${wsProtocol}://${wsRegisterAddress}`
/** 3.2修改坐席账号状态 */
const request = {
post(url) {
console.log('写你的调用的openapi改坐席状态,要写好它')
}
}
const editSeats = async (params) => {
return request.post('/seats/editLineStatus')
}
await editSeats({ lineStatus: 1 })
/** 接口获取结束 */
const {
UserAgentFactory,
UserAgent,
playMedia,
pauseMedia,
SessionState,
getMedia
} = softphone // 👈 sdk
/**
* 开启电话响铃
*/
const phoneRings = () => {
remoteAudio.src = phoneRing
playMedia('localAudio')
}
/**
* 关闭电话响铃
*/
const stopPhoneRings = () => {
remoteAudio.src = ''
pauseMedia('localAudio')
}
/**
* 获取软电话代理实例
*/
const userAgentManager = UserAgentFactory.getUserAgentManager({
authorizationPassword: extPassword,
authorizationUsername: extensionNumber,
viaHost,
uri: UserAgent.makeURI(sipServerHost),
logLevel: 'error',
transportOptions: {
server: wsAddress
},
contactName: extensionNumber
})
/**
* 签入
*/
const connect = () => {
userAgentManager.prepareUserAgent(
{ // config
refresh (path, value) { // 当软电话状态变化时会实时刷新这个方法
console.log(path, value)
}
},
{ // event
onInvite (invitation) { // 当有外呼过来
syncSipMessage(invitation.incomingInviteRequest.message.headers)
phoneRings() // 播放模拟来电响铃
ignore.disabled = false
answer.disabled = false
localSoundDisconnection.disabled = false
remoteSoundDisconnection.disabled = false
invitation.stateChange.addListener((state) => { // 一旦接听(执行accept),监听会话的生命周期
switch (state) {
case SessionState.Initial:
break
case SessionState.Establishing:
break
case SessionState.Established: // session建立后就可拿到webrtc的各种基础api,如userAgentManager.getPeerConnection(),如userAgentManager.getSenders()等等
const mediaElement1 = getMedia('remoteAudio')
mediaElement1.srcObject = userAgentManager.getStream() // 获取流
mediaElement1.play() // 把softphone流导入到audio接入用户语音
hangUp.disabled = false
break
case SessionState.Terminating:
case SessionState.Terminated: // 在挂断电话时候会执行
ignore.disabled = true
answer.disabled = true
hangUp.disabled = true
localSoundDisconnection.disabled = true
remoteSoundDisconnection.disabled = true
localVoiceAccess.disabled = true
remoteSoundAccess.disabled = true
const mediaElement2 = getMedia('remoteAudio') // 获取audio dom
mediaElement2.srcObject = null
mediaElement2.pause() // 释放audio
stopPhoneRings()
break
default:
throw new Error('Unknown session state.')
}
})
}
}
)
disconnect.disabled = false
connectToServer.disabled = true
ignore.disabled = true
answer.disabled = true
hangUp.disabled = true
localSoundDisconnection.disabled = true
remoteSoundDisconnection.disabled = true
localVoiceAccess.disabled = true
remoteSoundAccess.disabled = true
}
/**
* 签出
*/
const disConnect = () => {
userAgentManager.dispose() // 👈 一个方法安全销毁
connectToServer.disabled = false
disconnect.disabled = true
ignore.disabled = true
answer.disabled = true
hangUp.disabled = true
localSoundDisconnection.disabled = true
remoteSoundDisconnection.disabled = true
localVoiceAccess.disabled = true
remoteSoundAccess.disabled = true
}
/**
* 先监听后接听
*/
let monitorFirstAnswerAfter = true // 先监听任务需要 按*号转人工 才可以让用户听到坐席声音
/**
* sip协议通讯
*/
const syncSipMessage = (headers) => {
monitorFirstAnswerAfter = !(String(headers['X-Aftertransferlabour'] && headers['X-Aftertransferlabour'][0].raw) === '1')
}
/**
* 按*号转人工
*/
const sendStarDtmf = () => {
if (monitorFirstAnswerAfter) {
userAgentManager.sendStarDtmf()
press.disabled = true
}
}
/**
* 挂断
*/
const hangUpInvite = () => {
stopPhoneRings() // 暂停来电铃声
userAgentManager.hangUpInvite() // 👈
ignore.disabled = true
answer.disabled = true
hangUp.disabled = true
localSoundDisconnection.disabled = true
remoteSoundDisconnection.disabled = true
localVoiceAccess.disabled = true
remoteSoundAccess.disabled = true
}
/**
* 忽略
*/
const ignoreInvite = () => {
stopPhoneRings() // 暂停来电铃声
userAgentManager.ignoreInvite()
ignore.disabled = true
answer.disabled = true
hangUp.disabled = true
localSoundDisconnection.disabled = true
remoteSoundDisconnection.disabled = true
localVoiceAccess.disabled = true
remoteSoundAccess.disabled = true
}
/**
* 接听
*/
const acceptInvite = () => {
stopPhoneRings() // 暂停来电铃声
userAgentManager.acceptInvite()
if (monitorFirstAnswerAfter) {
press.disabled = false
}
hangUp.disabled = false
answer.disabled = true
ignore.disabled = true
}
/**
* 传输本地声音到远端
*/
const unMuteLocalAudio = () => {
localVoiceAccess.disabled = true
localSoundDisconnection.disabled = false
userAgentManager.unMuteLocalAudio()
}
/**
* 不传输本地声音到远端
*/
const muteLocalAudio = () => {
remoteSoundAccess.disabled = true
remoteSoundDisconnection.disabled = false
userAgentManager.muteLocalAudio()
}
/**
* 接听远端声音
*/
const unMuteRemoteAudio = () => {
localSoundDisconnection.disabled = true
localVoiceAccess.disabled = false
userAgentManager.unMuteRemoteAudio()
}
/**
* 不接听远端声音
*/
const muteRemoteAudio = () => {
remoteSoundDisconnection.disabled = true
remoteSoundAccess.disabled = false
userAgentManager.muteRemoteAudio()
}
/** 注册事件开始 */
ignore.addEventListener('click', ignoreInvite)
answer.addEventListener('click', acceptInvite)
hangUp.addEventListener('click', hangUpInvite)
connectToServer.addEventListener('click', connect)
disconnect.addEventListener('click', disConnect)
press.addEventListener('click', sendStarDtmf)
localVoiceAccess.addEventListener('click', unMuteLocalAudio)
remoteSoundAccess.addEventListener('click', muteLocalAudio)
localSoundDisconnection.addEventListener('click', unMuteRemoteAudio)
remoteSoundDisconnection.addEventListener('click', muteRemoteAudio)
/** 注册事件结束 */
})
</script>
</body>
</html>
- tip 获取fingerprintjs: https://unpkg.com/@fingerprintjs/fingerprintjs@3.4.1/dist/fp.umd.min.js
- const phoneRing = './antique_phone.mp3' // 👈 铃声自己当以一个音频即可
- 直接双击打开的html的demo打电话这个模拟不了线上域名部署环境可能出现的问题,可以实现看各种接听挂断签入转人工等效果,file协议和localhost默认在浏览器安全域名内。注意线上环境浏览器是有限制要https协议的,http是使用不了浏览器webrtc的api的,要配置下浏览器安全上下文域名白名单
签入
import { playMedia, getMedia, SessionState } from '@94ai/softphone'
import { ref } from 'vue'
import popNotice from './usePopNotice.ts' // 通知工具,见下面demo说明
const userAgentStatus = ref({ // 视图层响应式
connectStatus: false, // 软电话是否已签入
registerStatus: false, // 软电话是否已注册
invitatingStatus: false, // 软电话是否正拨出
incomingStatus: false, // 软电话是否正来电
answerStatus: false, // 软电话是否正接听
reconnectStatus: false, // 软电话是否正重连
})
userAgentManager.prepareUserAgent(
{ // config
refresh(path, value) { // 当软电话状态变化时会实时刷新这个方法
userAgentStatus[path] = value // 外部想要响应状态可以实时更新外部的userAgentStatus
}
},
{ // event
onInvite(invitation) { // 当有外呼过来
playMedia('localAudio') // 播放模拟来电响铃
popNotice.popNotification('来电了') // 提示通知 来电了
invitation.stateChange.addListener((state) => { // 一旦接听(执行accept),监听会话的生命周期
switch (state) {
case SessionState.Initial:
break
case SessionState.Establishing:
break
case SessionState.Established: // session建立后就可拿到webrtc的各种基础api,如userAgentManager.getPeerConnection(),如userAgentManager.getSenders()等等
const mediaElement1 = getMedia('remoteAudio')
mediaElement1.srcObject = userAgentManager.getStream() // 获取流
mediaElement1.play() // 把softphone流导入到audio接入用户语音
break
case SessionState.Terminating:
case SessionState.Terminated: // 在挂断电话时候会执行
const mediaElement2 = getMedia('remoteAudio') // 获取audio dom
mediaElement2.srcObject = null
mediaElement2.pause() // 释放audio
break
default:
throw new Error('Unknown session state.')
}
})
}
})接听
import { refreshShowTime, pauseMedia } from '@94ai/softphone'
const acceptInvite = () => {
refreshShowTime() // 重新计算通话时长(非必须)
pauseMedia('localAudio') // 暂停来电铃声(非必须)
userAgentManager.acceptInvite() // 👈 接入电话流
}忽略
import { pauseMedia } from '@94ai/softphone'
const ignoreInvite = () => {
pauseMedia('localAudio') // 暂停来电铃声(非必须)
userAgentManager.ignoreInvite() // 👈 忽略
}挂断
import { refreshShowTime } from '@94ai/softphone'
const hangUpInvite = () => {
refreshShowTime() // 重新计算通话时长(非必须)
userAgentManager.hangUpInvite() // 👈 挂断
}按*号转人工
import { refreshShowTime } from '@94ai/softphone'
const sendStarDtmf = () => {
refreshShowTime() // 重新计算通话时长(非必须)
userAgentManager.sendStarDtmf() // 👈 按*号转人工
}销毁
import { refreshShowTime } from '@94ai/softphone'
const disconnect = () => {
refreshShowTime() // 重新计算通话时长(非必须)
userAgentManager.dispose() // 👈 一个方法安全销毁
}传输本地声音到远端
const unMuteLocalAudio = () => {
userAgentManager.unMuteLocalAudio() // 👈 通过webrtc的方式控制 本地音频流 推送到 远端
}不传输本地声音到远端
const muteLocalAudio = () => {
userAgentManager.muteLocalAudio() // 👈 通过webrtc的方式控制 本地音频流 禁用推送
}接听远端声音
const unMuteRemoteAudio = () => {
userAgentManager.unMuteRemoteAudio() // 👈 通过webrtc的方式控制 是否接受 远端音频流
} 不接听远端声音
const muteRemoteAudio = () => {
userAgentManager.muteRemoteAudio() // 👈 通过webrtc的方式控制 是否接受 远端音频流
}获取webrtc基础api
const senders = userAgentManager.getSenders()
const receivers = userAgentManager.getReceivers()
const peerConnection = userAgentManager.getPeerConnection()获取代理用户相关sip协议通讯实例
const userAgent = userAgentManager.getUserAgent()
const sessionDescriptionHandler = userAgentManager.getSessionDescriptionHandler()
const currentInvitation = userAgentManager.getCurrentInvitation()
const currentInviter = userAgentManager.getCurrentInviter()
const localMixedMediaStream = userAgentManager.getStream()查看代理用户目前状态
interface userAgentStatus {
connectStatus: boolean, // 软电话是否已签入
registerStatus: boolean, // 软电话是否已注册
invitatingStatus: boolean, // 软电话是否正拨出
incomingStatus: boolean, // 软电话是否正来电
answerStatus: boolean, // 软电话是否正接听
reconnectStatus: boolean, // 软电话是否正在重连,网络断掉,服务器重启,宕机等引起服务不可达时软电话代理会尝试重新连接并签入。这个时候用户拨出等动作可以通过此状态做拦截,通知用户软电话服务器可能正重启或断网等导致服务不可用
}
const userAgentStatus: userAgentStatus = userAgentManager.getUserAgentStatue()软电话状态可以根据企业特定业务流程定制扩展额外的状态,如94智能决策系统 额外扩展了 【监听中】,【整理中】,【小休中】等状态
8 months ago
8 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
1 year ago
1 year ago
1 year ago
1 year ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago