README
物联网平台 SIP 安全帽视频通话库
润得安全帽 js 调用 SDK
安装
npm i @zjzg/runde
使用
/**
* 引入依赖
*/
import { Runde } from "../runde";
import {
CALL_STATE,
CMD,
CMDMessage,
DeviceInfo,
SosInfo,
UserInfo,
} from "../runde/class";
/**
* 开始使用
*/
rende = new Runde({
name: "xxxxx",
password: "xxxxx",
host: "https://xxxxxx.runde.xxx",
wsurl: "ws://xxxx.runde.xxx:10000",
poolDuration: 20000, //轮询心跳的间隔默认5秒 范围应该小于30秒
});
rende.addListener({
cmdMessage: (e: CMDMessage) => {
console.log("接收的回调", e);
if (e.cmd == CMD.GET_ONLINE_DEVICES) {
li.value = e.data;
} else if (e.cmd == CMD.SOS) {
sosInfo.value = e;
showSos.value = true;
setTimeout(() => {
//30秒未响应就挂断了
showSos.value = false;
}, 30000);
}
},
callState: (type: CALL_STATE, response?: any) => {
console.log("通话状态:===", type, response);
callState.value = type;
},
});
/**
* 在页面销毁时销毁实例
*/
rende?.destroy();
rende = null;
完整 Vue3 的使用示例
<script setup lang="ts">
import { IncomingResponseMessage } from "sip.js/lib/core";
import { onBeforeUnmount } from "vue";
import { onMounted, ref } from "vue";
import { Runde } from "../runde";
import {
CALL_STATE,
CMD,
CMDMessage,
DeviceInfo,
SosInfo,
UserInfo,
} from "../runde/class";
defineProps<{ msg: string }>();
const count = ref(0);
var rende: Runde | null;
const li = ref<DeviceInfo[]>([]);
const sosInfo = ref<SosInfo>();
const showSos = ref(false);
const video = ref<HTMLMediaElement>();
const callState = ref("");
onMounted(() => {
rende = new Runde({
name: "xxxxx",
password: "xxxxx",
host: "https://xxxxxx.runde.xxx",
wsurl: "ws://xxxx.runde.xxx:10000",
poolDuration: 20000,
});
rende.addListener({
cmdMessage: (e: CMDMessage) => {
console.log("接收的回调", e);
if (e.cmd == CMD.GET_ONLINE_DEVICES) {
li.value = e.data;
} else if (e.cmd == CMD.SOS) {
sosInfo.value = e;
showSos.value = true;
setTimeout(() => {
//30秒未响应就挂断了
showSos.value = false;
}, 30000);
}
},
callState: (type: CALL_STATE, response?: any) => {
console.log("通话状态:===", type, response);
callState.value = type;
},
});
});
onBeforeUnmount(() => {
rende?.destroy();
rende = null;
});
const getDevice = function () {
rende?.getDevice();
};
const call = function (user?: UserInfo, type?: string) {
if (user && video.value) {
rende?.call(user, video.value, type || "1");
}
};
const sendMessage = function (device: DeviceInfo) {
if (device.user_info?.user_id) {
rende?.sendSMS(device.user_info?.user_id, smsInput.value.value);
}
};
const hangUp = () => {
rende?.hangUp();
};
const enterRoom = () => {
if (video.value) {
rende?.enterRoom(sosInfo.value, video.value, "2");
}
};
const smsInput = ref();
</script>
<template>
<div v-if="showSos">
<div>
{{
`${sosInfo?.ca_info?.department} - 的 -> ${sosInfo?.ca_info?.user_name} `
}}来电
</div>
<button @click="enterRoom()">接听</button>
</div>
<input type="text" ref="smsInput" />
<p @click="getDevice">获取设备信息</p>
<template v-for="(item, i) in li" :key="i">
<div style="display: flex">
<span style="padding: 8px"> {{ item.user_info?.user_name }}</span>
<span style="padding: 8px"> {{ item.user_info?.sip_id }}</span>
<div style="padding: 8px" @click="call(item.user_info, '1')">语音</div>
<div style="padding: 8px" @click="call(item.user_info, '2')">视频</div>
<div style="padding: 8px" @click="sendMessage(item)">发消息</div>
</div>
</template>
<div>通话状态:{{ callState }}</div>
<video
ref="video"
style="height: 250px; width: 400px"
id="remoteVideo"
></video>
<button type="button" @click="hangUp()">挂断</button>
</template>
<style scoped>
a {
color: #42b983;
}
label {
margin: 0 0.5em;
font-weight: bold;
}
code {
background-color: #eee;
padding: 2px 4px;
border-radius: 4px;
color: #304455;
}
</style>
import ReconnectingWebSocket from "reconnecting-websocket";
import { SimpleUser } from "sip.js/lib/platform/web";
import { IncomingResponseMessage } from "sip.js/lib/core";
import {
AdminInfo,
CALL_STATE,
CMDMessage,
MsgListener,
RundeOpt,
SosInfo,
UserInfo,
} from "./class";
/**
* 润德api实体类
*/
export declare class Runde {
udid: string;
connectState: number;
opt: RundeOpt | undefined;
rws: ReconnectingWebSocket | undefined;
admin_info: AdminInfo | undefined | null;
onlineDevices: Array<any>;
listeners: Array<MsgListener>;
heartPool: number;
sUser: SimpleUser | undefined;
toUserSip: string;
el: HTMLMediaElement | null;
callType: string;
constructor(opt: RundeOpt);
/**
* 初始化
* @param opt
*/
init(opt: RundeOpt): void;
/**
* 初始化 SIP
*/
_initSip(): void;
/**
* 添加监听
* @param listener
* @returns 监听的key 方便取消监听用
*/
addListener(listener: MsgListener): string;
/**
* 根据key取消监听
*/
removeListener(key: string): void;
/**
* 发送 通话状态
* @param type
* @param data
*/
emitCallState(type: CALL_STATE, data?: any): void;
/**
* 登录
* 如果传入账号密码会覆盖通过设置配置的账号密码
*/
login(name?: string, password?: string): void;
/**
* 发送获取当前在线设备的指令信息
*/
getDevice(): void;
/**
* 发送指令或信息
* @param msg
*/
sendMessage(msg: any): void;
/**
* 开启通话
* @param user_id
* @param to_sip
* @param el 播放视频的DOM元素
* @param type 1音频 2视频
*/
call(user: UserInfo, el: HTMLMediaElement, type: string): void;
/**
* 响应SOS 进入房间
* @param sos
* @param el 播放视频的DOM元素
* @param type 1音频 2视频
*/
enterRoom(sos: SosInfo | undefined, el: HTMLMediaElement, type: string): void;
/**
* SIP 拨打电话
* @param toUser
*/
_sipCall(toUser: string): void;
_emitRequestDelegate(
type: CALL_STATE,
response: IncomingResponseMessage
): void;
/**
* 挂断通话
*/
hangUp(): void;
/**
* 发送消息
* @param user_id 用户ID
* @param msg 消息
* @returns
*/
sendSMS(user_id: string, msg: string): void;
/**
* 解析ws返回的指令信息,遍历并广播给监听器
* @param data
*/
onMessage(data: CMDMessage): void;
/**
* 设置video
* @param el
*/
setRemoteMedia(): void;
/**
* 释放 media 资源
*/
cleanupMedia(): void;
/**
* 心跳,不然后台会主动断开ws连接
* 登录成功后自动开启3秒轮询心跳
*/
starHeartbeat(): void;
/**
* 连接断开后或实例销毁后停止心跳
*/
stopHeartbeat(): void;
/**
* 销毁实例
*/
destroy(): void;
_logError(error: any): void;
}
类型
import { IncomingResponseMessage } from "sip.js/lib/core";
export declare class SosInfo {
cmd?: string;
type?: string;
room_id?: string;
ca_info?: CAInfo;
x_point?: string;
y_point?: string;
time?: number;
}
export declare class CAInfo {
user_id?: string;
device_id?: string;
ca_ver?: string;
mobile?: string;
sim?: string;
pwd?: string;
c_time?: string;
app_last_login_time?: string;
ca_last_login_time?: string;
user_name?: string;
real_name?: string;
user_img?: string;
department?: string;
role?: string;
f_id?: string;
cap_type?: string;
b1?: string;
b2?: string;
sos_height?: string;
tk?: string;
nearvolt?: string;
health?: string;
pressure?: string;
account_id?: string;
w_id?: string;
acc_list?: string;
c_user_id?: string;
gas_volt?: string;
new_low?: string;
uwb_device_id?: string;
rtmp_open?: string;
voice_pkg?: string;
fb_id?: string;
min_o2?: string;
max_o2?: string;
watch?: string;
local_record?: string;
last_count_online_time?: string;
watch_mac?: string;
co?: string;
app_version?: string;
min_temp?: string;
max_temp?: string;
max_heartbeat?: string;
min_heartbeat?: string;
shrink?: string;
diastolic?: string;
video_pre?: string;
push_sos_url?: string;
electrostatic?: string;
headset?: string;
upload_video_num?: string;
notuploaded_video_count?: string;
privacy_switch?: string;
boot_broadcast?: string;
gas_mac?: string;
check_upgrade?: string;
new_app_id?: string;
check_system_upgrade?: string;
new_system_app_id?: string;
}
export declare class DeviceInfo {
location_info?: LocationInfo;
user_info?: UserInfo;
}
export declare class UserInfo {
account_id?: string;
app_last_login_time?: string;
app_version?: string;
b1?: string;
b2?: string;
boot_broadcast?: string;
c_time?: string;
c_user_id?: string;
ca_last_login_time?: string;
ca_ver?: string;
cap_type?: string;
co?: string;
department?: string;
device_id?: string;
diastolic?: string;
electrostatic?: string;
f_id?: string;
fb_id?: string;
g_id?: string;
gas_volt?: string;
headset?: string;
health?: string;
last_count_online_time?: string;
local_record?: string;
max_heartbeat?: string;
max_o2?: string;
max_temp?: string;
min_heartbeat?: string;
min_o2?: string;
min_temp?: string;
mobile?: string;
nearvolt?: string;
new_low?: string;
notuploaded_video_count?: string;
pressure?: string;
privacy_switch?: string;
push_sos_url?: string;
real_name?: string;
role?: string;
rtmp_open?: string;
shrink?: string;
sim?: string;
sip_id?: string;
sos_height?: string;
tk?: string;
upload_video_num?: string;
user_id?: string;
user_img?: string;
user_name?: string;
uwb_device_id?: string;
video_pre?: string;
voice_pkg?: string;
w_id?: string;
watch?: string;
watch_mac?: string;
}
export declare class LocationInfo {
Altitude?: string;
act?: string;
bat_l?: string;
bat_v?: string;
body_info?: string;
body_simple_info?: string;
bt_signal_info?: string;
c_angle?: string;
c_speed?: string;
c_time?: string;
c_trust?: string;
charging?: string;
ctime?: string;
gas_data?: string;
gps?: string;
gps_level?: string;
in_use?: string;
is_weared?: string;
net_strenth?: string;
net_type?: string;
notuploaded_video_count?: string;
oxygen_data?: string;
phoneNumber?: string;
rail_status?: string;
record_switch?: string;
sim_data_num?: string;
sim_status?: string;
tcard_status?: string;
tempdata?: string;
user_id?: string;
x_point?: string;
y_point?: string;
}
/**
* 润德设备配置信息
*/
export interface RundeOpt {
/**
* API 接口地址
*/
host?: string;
/**
* 账号
*/
name: string;
/**
* 密码
*/
password: string;
/**
* websocket 连接地址
*/
wsurl: string;
/**
* 通过接口登录,舍弃
*/
newApi?: boolean;
/**
* 心跳间隔,会影响实时获取在线设备的刷新,可以通过手动获取实时设备达到预期效果。
*/
poolDuration?: number;
}
/**
* 指令消息格式
*/
export declare type CMDMessage = {
cmd: string;
status: boolean;
msg: string;
data: any;
} & any;
/**
* 润德SIP信息
*/
export interface SIPInfo {
sip_host: string;
sip_id: number;
sip_pwd: string;
stun_host: string;
turn_host: string;
turn_pwd: string;
turn_user: string;
wss_url: string;
}
/**
* 管理员账号信息
*/
export interface AdminInfo {
acc_list: string;
account_id: string;
admin_id: string;
c_time: string;
department: string;
device_list: string;
expire_time: string;
group_room_list: string;
is_top: number;
last_login_time: string;
mobile: string;
p_id: string;
permission_list: string;
pwd: string;
pwd2: string;
role: string;
rtmp_open: string;
user_name: string;
sip_info: SIPInfo;
}
/**
* 监听器
*/
export interface MsgListener {
key?: string;
cmd?: string | CMD;
callback?: Function;
cmdMessage?: (data: CMDMessage) => void;
callState?: (type: CALL_STATE, data?: any) => void;
requestDelegate?: (
type: CALL_STATE,
response: IncomingResponseMessage
) => void;
}
export declare enum CMD {
LOGIN = "ma_login",
GET_ONLINE_DEVICES = "ma_get_active_devices",
CALL_SIP = "ma_set_sip_info",
/**
* 安全帽紧急呼叫SOS
*/
SOS = "server_push_ca_sip_sos",
}
export declare enum CALL_STATE {
/**
* 呼叫中
*/
ON_PROGRESS = "onProgress",
/**
* 接通时
*/
ON_ACCEPT = "onAccept",
/**
* 拒绝时
*/
ON_REJECT = "onReject",
/**
* Called when a call is answered.
* @remarks
* Callback for handling establishment of a new Session.
*/
onCallAnswered = "onCallAnswered",
/**
* Called when a call is created.
* @remarks
* Callback for handling the creation of a new Session.
*/
onCallCreated = "onCallCreated",
/**
* Called when a call is received.
* @remarks
* Callback for handling incoming INVITE requests.
* The callback must either accept or reject the incoming call by calling `answer()` or `decline()` respectively.
*/
onCallReceived = "onCallReceived",
/**
* Called when a call is hung up.
* @remarks
* Callback for handling termination of a Session.
*/
onCallHangup = "onCallHangup",
/**
* Called when a call is put on hold or taken off hold.
* @remarks
* Callback for handling re-INVITE responses.
*/
onCallHold = "onCallHold",
/**
* Called when a call receives an incoming DTMF tone.
* @remarks
* Callback for handling an incoming INFO request with content type application/dtmf-relay.
*/
onCallDTMFReceived = "onCallDTMFReceived",
/**
* Called upon receiving a message.
* @remarks
* Callback for handling incoming MESSAGE requests.
* @param message - The message received.
*/
onMessageReceived = "onMessageReceived",
/**
* Called when user is registered to received calls.
*/
onRegistered = "onRegistered",
/**
* Called when user is no longer registered to received calls.
*/
onUnregistered = "onUnregistered",
/**
* Called when user is connected to server.
* @remarks
* Callback for handling user becomes connected.
*/
onServerConnect = "onServerConnect",
/**
* Called when user is no longer connected.
* @remarks
* Callback for handling user becomes disconnected.
*
* @param error - An Error if server caused the disconnect. Otherwise undefined.
*/
onServerDisconnect = "onServerDisconnect",
}
SIP 工具类
import { SimpleUser, SimpleUserOptions } from "sip.js/lib/platform/web";
import { AdminInfo } from "./class";
export declare function getAudioElement(id: string): HTMLAudioElement;
export declare function getVideoElement(id: string): HTMLVideoElement;
export declare const useSimpleUA: (
admin: AdminInfo,
sipOption: SimpleUserOptions
) => Promise<SimpleUser>;