代码拉取完成,页面将自动刷新
/*
* Copyright (c) 2020 WildFireChat. All rights reserved.
*/
import EventType from "../../client/wfcEvent";
import {BrowserWindow, ipcRenderer, isElectron, remote} from "../../../platform";
import ConversationType from "../../model/conversationType";
import MessageContentType from "../../messages/messageContentType";
import wfc from "../../client/wfc";
import MessageConfig from "../../client/messageConfig";
import DetectRTC from 'detectrtc';
import Config from "../../../config";
import {longValue, numberValue} from '../../util/longUtil'
import Conversation from "../../../wfc/model/conversation";
import CallEndReason from "./callEndReason";
import CallByeMessageContent from "../messages/callByeMessageContent";
// main window renderer process -> voip window renderer process
// voip window renderer process -> main process -> main window renderer process
export class AvEngineKitProxy {
wfc;
queueEvents = [];
callWin;
isVoipWindowReady = false;
type;
conference = false;
conversation;
callId;
inviteMessageUid;
participants = [];
isSupportVoip = false;
hasMicrophone = false;
hasSpeaker = false;
hasWebcam = false;
/**
* 无法正常弹出音视频通话窗口是的回调
* 回到参数说明:-1,有音视频通话正在进行中;-2,设备不支持音视频通话,可能原因是不支持webrtc,没有摄像头或麦克风等
* @type {(Number) => {}}
*/
onVoipCallErrorCallback;
/**
* 音视频通话通话状态回调
*/
onVoipCallStatusCallback = (covnersation, ongonging) => {
};
/**
* 应用初始化的时候调用
* @param wfc
*/
setup(wfc) {
if (this.wfc === wfc) {
console.log('re-setup, just ignore');
return;
}
this.wfc = wfc;
DetectRTC.load(() => {
this.isSupportVoip = DetectRTC.isWebRTCSupported;
this.hasMicrophone = DetectRTC.hasMicrophone;
// Safari 14.0 版本,hasSpeakers一直为false,先全部置为true
//this.hasSpeaker = DetectRTC.hasSpeakers;
this.hasSpeaker = true;
this.hasWebcam = DetectRTC.hasWebcam;
console.log(`detectRTC, isWebRTCSupported: ${DetectRTC.isWebRTCSupported}, hasWebcam: ${DetectRTC.hasWebcam}, hasSpeakers: ${DetectRTC.hasSpeakers}, hasMicrophone: ${DetectRTC.hasMicrophone}`, this.isSupportVoip);
});
this.event = wfc.eventEmitter;
this.event.on(EventType.ReceiveMessage, this.onReceiveMessage);
this.event.on(EventType.ConferenceEvent, this.onReceiveConferenceEvent);
this.event.on(EventType.ConnectionStatusChanged, this.onConnectionStatusChange)
if (!isElectron()) {
const EventEmitter = require("events").EventEmitter;
this.events = new EventEmitter();
this.events.on('voip-message', this.sendVoipListener)
this.events.on('conference-request', this.sendConferenceRequestListener);
this.events.on('update-call-start-message', this.updateCallStartMessageContentListener)
}
}
updateCallStartMessageContentListener = (event, message) => {
let messageUid = message.messageUid;
let content = message.content;
let msg = wfc.getMessageByUid(messageUid);
let orgContent = msg.messageContent;
orgContent.connectTime = content.connectTime ? content.connectTime : orgContent.connectTime;
orgContent.endTime = content.endTime ? content.endTime : orgContent.endTime;
orgContent.status = content.status;
orgContent.audioOnly = content.audioOnly;
wfc.updateMessageContent(msg.messageId, orgContent);
}
sendConferenceRequestListener = (event, request) => {
console.log('to send conference request', request)
wfc.sendConferenceRequestEx(request.sessionId ? request.sessionId : 0, request.roomId ? request.roomId : '', request.request, request.data, request.advance, (errorCode, res) => {
this.emitToVoip('sendConferenceRequestResult', {
error: errorCode,
sendConferenceRequestId: request.sendConferenceRequestId,
response: res
})
});
}
// 发送消息时,返回的timestamp,已经过修正,后面使用时,不用考虑和服务器的时间差
sendVoipListener = (event, msg) => {
let contentClazz = MessageConfig.getMessageContentClazz(msg.content.type);
let content = new contentClazz();
content.decode(msg.content);
console.log('to send voip message', content.type, content.callId, content);
let delta = wfc.getServerDeltaTime();
if (content.type === MessageContentType.VOIP_CONTENT_TYPE_ADD_PARTICIPANT) {
this.participants.push(content.participants);
} else if (content.type === MessageContentType.VOIP_CONTENT_TYPE_END) {
console.log('to send end message', content.reason, content);
// 窗口关闭时,会重置
// this.conversation = null;
// this.queueEvents = [];
// this.callId = null;
// this.inviteMessageUid = null;
// this.participants = [];
// 仅仅为了通知proxy,其他端已经接听电话了,关闭窗口时,不应当发送挂断信令
if (!content.callId) {
return;
}
}
let conversation = new Conversation(msg.conversation.type, msg.conversation.target, msg.conversation.line)
wfc.sendConversationMessage(conversation, content, msg.toUsers, (messageId, timestamp) => {
// do nothing
}, (uploaded, total) => {
// do nothing
}, (messageUid, timestamp) => {
this.emitToVoip('sendMessageResult', {
error: 0,
sendMessageId: msg.sendMessageId,
messageUid: messageUid,
timestamp: longValue(numberValue(timestamp) - delta)
})
if (content.type === MessageContentType.VOIP_CONTENT_TYPE_START) {
this.inviteMessageUid = messageUid;
}
}, (errorCode) => {
this.emitToVoip('sendMessageResult', {error: errorCode, sendMessageId: msg.sendMessageId})
});
}
onReceiveConferenceEvent = (event) => {
this.emitToVoip("conferenceEvent", event);
}
onConnectionStatusChange = (status) => {
this.emitToVoip('connectionStatus', status);
}
// 收到消息时,timestamp已经过修正,后面使用时,不用考虑和服务器的时间差
onReceiveMessage = (msg) => {
if (!Config.ENABLE_MULTI_VOIP_CALL && msg.conversation.type === ConversationType.Group) {
console.log('not enable multi call ');
return;
}
if (!Config.ENABLE_SINGLE_VOIP_CALL && msg.conversation.type === ConversationType.Single) {
console.log('not enable multi call ');
return;
}
let now = (new Date()).valueOf();
let delta = wfc.getServerDeltaTime();
if (now - (numberValue(msg.timestamp) - delta) >= 90 * 1000) {
// 消息已失效,不做处理
return;
}
let content = msg.messageContent;
if (this.callWin && this.conference && content.type !== MessageContentType.CONFERENCE_CONTENT_TYPE_COMMAND) {
console.log('in conference, ignore all other msg');
return;
}
if (msg.direction === 1 &&
(content.type === MessageContentType.VOIP_CONTENT_TYPE_START || content.type === MessageContentType.VOIP_CONTENT_TYPE_ADD_PARTICIPANT)) {
if (this.callWin) {
if (content.type === MessageContentType.VOIP_CONTENT_TYPE_START
|| (content.type === MessageContentType.VOIP_CONTENT_TYPE_ADD_PARTICIPANT && content.participants.indexOf(wfc.getUserId()) >= 0)) {
// 已在音视频通话中,其他的音视频通话,又邀请自己,这儿是只是让主界面提示一下,拒绝逻辑在 engine 里面
this.onVoipCallErrorCallback && this.onVoipCallErrorCallback(-1);
}
}
if (!this.isSupportVoip || !this.hasMicrophone || !this.hasSpeaker) {
this.onVoipCallErrorCallback && this.onVoipCallErrorCallback(-2);
return;
}
}
if ((msg.conversation.type === ConversationType.Single || msg.conversation.type === ConversationType.Group || (this.conference && msg.conversation.type === ConversationType.ChatRoom))) {
if (content.type === MessageContentType.VOIP_CONTENT_TYPE_START
|| content.type === MessageContentType.VOIP_CONTENT_TYPE_END
|| content.type === MessageContentType.VOIP_CONTENT_TYPE_ACCEPT
|| content.type === MessageContentType.VOIP_CONTENT_TYPE_SIGNAL
|| content.type === MessageContentType.VOIP_CONTENT_TYPE_MODIFY
|| content.type === MessageContentType.VOIP_CONTENT_TYPE_ACCEPT_T
|| content.type === MessageContentType.VOIP_CONTENT_TYPE_ADD_PARTICIPANT
|| content.type === MessageContentType.VOIP_CONTENT_TYPE_MUTE_VIDEO
|| content.type === MessageContentType.VOIP_Join_Call_Request
|| content.type === MessageContentType.CONFERENCE_CONTENT_TYPE_KICKOFF_MEMBER
|| content.type === MessageContentType.CONFERENCE_CONTENT_TYPE_CHANGE_MODE
|| content.type === MessageContentType.CONFERENCE_CONTENT_TYPE_COMMAND
) {
console.log("receive voip message", msg.messageContent.type, msg.messageContent.callId, msg.messageUid.toString(), msg);
if (msg.direction === 0
&& content.type !== MessageContentType.VOIP_CONTENT_TYPE_END
&& content.type !== MessageContentType.VOIP_CONTENT_TYPE_ACCEPT
&& content.type !== MessageContentType.VOIP_CONTENT_TYPE_ACCEPT) {
return;
}
let participantUserInfos = [];
let selfUserInfo = wfc.getUserInfo(wfc.getUserId());
if (content.type === MessageContentType.VOIP_CONTENT_TYPE_START) {
this.conversation = msg.conversation;
this.callId = content.callId;
this.inviteMessageUid = msg.messageUid;
this.participants.push(...content.targetIds);
this.participants.push(msg.from);
// 参与者不包含自己
this.participants = this.participants.filter(uid => uid !== selfUserInfo.uid)
if (msg.conversation.type === ConversationType.Single) {
participantUserInfos = [wfc.getUserInfo(msg.from)];
} else {
let targetIds = content.targetIds.filter(id => id !== selfUserInfo.uid);
targetIds.push(msg.from);
participantUserInfos = wfc.getUserInfos(targetIds, msg.conversation.target);
}
if (!this.callWin) {
if (this.conversation) {
this.showCallUI(msg.conversation, false, {
event: 'message',
args: msg
});
} else {
console.log('call ended')
}
}
} else if (content.type === MessageContentType.VOIP_CONTENT_TYPE_ADD_PARTICIPANT) {
let participantIds = [...content.participants];
if (content.existParticipants) {
content.existParticipants.forEach(p => {
participantIds.push(p.userId);
});
}
this.conversation = msg.conversation;
this.callId = content.callId;
this.inviteMessageUid = msg.messageUid;
this.participants.push(...participantIds);
participantIds = participantIds.filter(u => u.uid !== selfUserInfo.uid);
participantUserInfos = wfc.getUserInfos(participantIds, msg.conversation.target);
if (!this.callWin && content.participants.indexOf(selfUserInfo.uid) > -1) {
if (this.conversation) {
this.showCallUI(msg.conversation, false, {
event: 'message',
args: msg
});
} else {
console.log('call ended')
}
}
} else if (content.type === MessageContentType.VOIP_CONTENT_TYPE_END) {
if (content.callId !== this.callId) {
return;
}
}
if (msg.conversation.type === ConversationType.Group
&& (content.type === MessageContentType.VOIP_CONTENT_TYPE_START
|| content.type === MessageContentType.VOIP_CONTENT_TYPE_ADD_PARTICIPANT
)) {
let memberIds = wfc.getGroupMemberIds(msg.conversation.target);
msg.groupMemberUserInfos = wfc.getUserInfos(memberIds, msg.conversation.target);
}
msg.participantUserInfos = participantUserInfos;
msg.selfUserInfo = selfUserInfo;
msg.timestamp = longValue(numberValue(msg.timestamp) - delta)
// 这两条消息,显示 ui 的时候,会传过去,这儿就不用再次传了
if (this.callWin && [MessageContentType.VOIP_CONTENT_TYPE_START, MessageContentType.VOIP_CONTENT_TYPE_ADD_PARTICIPANT].indexOf(msg.messageContent.type) === -1) {
this.emitToVoip("message", msg);
}
}
}
};
emitToVoip(event, args) {
console.log('emitToVoip', event, args)
if (isElectron()) {
// renderer/main to renderer
if (this.isVoipWindowReady) {
// fix object of long.js can be send inter-process
args = JSON.stringify(args)
if (!this.callWin.isDestroyed()){
try {
this.callWin.webContents.send(event, args);
}catch (e) {
// ignore, do nothing
// Object has been destroyed
}
}
} else if (this.queueEvents) {
this.queueEvents.push({event, args});
}
} else {
if (this.events) {
this.events.emit(event, event, args);
} else if (this.queueEvents) {
this.queueEvents.push({event, args});
}
}
}
emitToMain(event, args) {
console.log('emit to main', event, args);
if (isElectron()) {
// renderer to main
ipcRenderer.send(event, args);
} else {
this.events.emit(event, event, args);
}
}
listenVoipEvent = (event, listener) => {
console.log('listenVoipEvent ', event, listener)
if (isElectron()) {
// listen for event from renderer
ipcRenderer.on(event, listener);
} else {
this.events.on(event, listener);
}
};
/**
* 发起音视频通话
* @param {Conversation} conversation 会话
* @param {Boolean} audioOnly 是否是音频通话
* @param {[String]} participants 参与者用户id列表
* @param {string} callExtra 通话附加信息,会议版有效
*/
startCall(conversation, audioOnly, participants, callExtra = '') {
if (this.callWin) {
console.log('voip call is ongoing');
this.onVoipCallErrorCallback && this.onVoipCallErrorCallback(-1);
return;
}
console.log(`startCall speaker、microphone、webcam检测结果分别为:${this.hasSpeaker} , ${this.hasMicrophone}, ${this.hasWebcam},如果不全为true,请检查硬件设备是否正常,否则通话可能存在异常`)
if (!this.isSupportVoip || !this.hasSpeaker || !this.hasMicrophone) {
console.log('not support voip', this.isSupportVoip, this.hasSpeaker, this.hasMicrophone, this.hasWebcam);
this.onVoipCallErrorCallback && this.onVoipCallErrorCallback(-2);
return;
}
// vue3里面,delete property 会触发reactivity
conversation = Object.assign(new Conversation(), conversation)
delete conversation._target;
let selfUserInfo = wfc.getUserInfo(wfc.getUserId());
participants = participants.filter(uid => uid !== selfUserInfo.uid);
let callId = conversation.target + Math.floor(Math.random() * 10000);
this.conversation = conversation;
this.participants.push(...participants)
this.callId = callId;
let participantUserInfos = wfc.getUserInfos(participants);
let groupMemberUserInfos;
if (conversation.type === ConversationType.Group) {
let memberIds = wfc.getGroupMemberIds(conversation.target);
groupMemberUserInfos = wfc.getUserInfos(memberIds, conversation.target);
}
this.showCallUI(conversation, false, {
event: 'startCall',
args: {
conversation: conversation,
audioOnly: audioOnly,
callId: callId,
selfUserInfo: selfUserInfo,
groupMemberUserInfos: groupMemberUserInfos,
participantUserInfos: participantUserInfos,
callExtra: callExtra,
}
});
}
/**
* 开始会议
* @param {string} callId 会议id
* @param {boolean} audioOnly 是否仅仅开启音频; true,音频会议;false,视频会议
* @param {string} pin 入会pin码
* @param {string} host 主持人用户id
* @param {string} title 会议标题
* @param {string} desc 会议描述
* @param {boolean} audience 其他人加入会议时,是否默认为观众;true,默认为观众;false,默认为互动者
* @param {boolean} advance 是否为高级会议,当预计参与人员很多的时候,开需要开启超级会议
* @param {boolean} record 是否开启服务端录制
* @param {Object} extra 一些额外信息,主要用于将信息传到音视频通话窗口,会议的其他参与者,无法看到该附加信息
* @param {Object} callExtra 通话附件信息,会议的所有参与者都能看到该附加信息
* @param {boolean} muteAudio 是否是静音加入会议
* @param {boolean} muteVideo 是否是关闭摄像头加入会议
*/
startConference(callId, audioOnly, pin, host, title, desc, audience, advance, record = false, extra, callExtra, muteAudio = false, muteVideo = false) {
if (this.callWin) {
console.log('voip call is ongoing');
this.onVoipCallErrorCallback && this.onVoipCallErrorCallback(-1);
return;
}
if (!this.isSupportVoip || !this.hasSpeaker || !this.hasMicrophone) {
console.log('not support voip', this.isSupportVoip, this.hasSpeaker);
this.onVoipCallErrorCallback && this.onVoipCallErrorCallback(-2);
return;
}
callId = callId ? callId : wfc.getUserId() + Math.floor(Math.random() * 10000);
this.callId = callId;
this.conversation = null;
this.conference = true;
wfc.joinChatroom(callId, () => {
console.log('join conference chatRoom success', callId)
}, (err) => {
console.error('join conference chatRoom fail', callId, err);
});
let selfUserInfo = wfc.getUserInfo(wfc.getUserId());
this.showCallUI(null, true, {
event: 'startConference',
args: {
audioOnly: audioOnly,
callId: callId,
pin: pin ? pin : Math.ceil(Math.random() * 1000000) + '',
host: host,
title: title,
desc: desc,
audience: audience,
advance: advance,
record: record,
selfUserInfo: selfUserInfo,
extra: extra,
callExtra: callExtra,
muteAudio: muteAudio,
muteVideo: muteVideo,
}
});
}
/**
* 加入会议
* @param {string} callId 会议id
* @param {string} audioOnly 是否只开启音频
* @param {string} pin 会议pin码
* @param {string} host 会议主持人
* @param {string} title 会议标题
* @param {string} desc 会议描述
* @param {boolean} audience 是否是以观众角色入会
* @param {string} advance 是否是高级会议
* @param {boolean} muteAudio 是否是静音加入会议
* @param {boolean} muteVideo 是否是关闭摄像头加入会议
* @param {Object} extra 一些额外信息,主要用于将信息传到音视频通话窗口
* @param {Object} callExtra 通话附加信息,会议的所有参与者都能看到该附加信息
*/
joinConference(callId, audioOnly, pin, host, title, desc, audience, advance, muteAudio, muteVideo, extra = null, callExtra = null) {
if (this.callWin) {
console.log('voip call is ongoing');
this.onVoipCallErrorCallback && this.onVoipCallErrorCallback(-1);
return;
}
if (!this.isSupportVoip || !this.hasSpeaker || !this.hasMicrophone) {
console.log('not support voip', this.isSupportVoip, this.hasSpeaker, this.hasMicrophone);
this.onVoipCallErrorCallback && this.onVoipCallErrorCallback(-2);
return;
}
this.conversation = null;
this.conference = true;
this.callId = callId;
wfc.joinChatroom(callId, () => {
console.log('join conference chatRoom success', callId)
}, (err) => {
console.error('join conference chatRoom fail', callId, err);
});
let selfUserInfo = wfc.getUserInfo(wfc.getUserId());
this.showCallUI(null, true, {
event: 'joinConference',
args: {
audioOnly: audioOnly,
callId: callId,
pin: pin,
host: host,
title: title,
desc: desc,
audience: audience,
advance: advance,
muteAudio: muteAudio,
muteVideo: muteVideo,
selfUserInfo: selfUserInfo,
extra: extra,
callExtra: callExtra,
}
});
}
showCallUI(conversation, isConference, options) {
let type = isConference ? 'conference' : (conversation.type === ConversationType.Single ? 'single' : 'multi');
this.type = type;
let width = 360;
let height = 640;
let minWidth = 360;
let minHeight = 640;
switch (type) {
case 'single':
width = 360;
height = 640;
break;
case 'multi':
case 'conference':
width = 960;
height = 600;
minWidth = 800;
minHeight = 480;
break;
default:
break;
}
if (isElectron()) {
let win = new BrowserWindow(
{
width: width,
height: height,
minWidth: minWidth,
minHeight: minHeight,
resizable: true,
maximizable: true,
transparent: !!isConference,
frame: !isConference,
webPreferences: {
scrollBounce: false,
nativeWindowOpen: true,
nodeIntegration: true,
contextIsolation: false,
},
}
);
this.callWin = win;
this.isVoipWindowReady = false;
// const remoteMain = require("@electron/remote").require("@electron/remote/main");
const remoteMain = remote.require("@electron/remote/main");
remoteMain.enable(win.webContents);
win.webContents.on('did-finish-load', () => {
this.onVoipWindowReady(win);
});
if (localStorage.getItem("enable_voip_debug")) {
win.webContents.openDevTools();
}
win.on('close', () => {
this.onVoipWindowClose();
});
// win.loadURL(path.join('file://', AppPath, 'src/index.html?' + type));
let hash = window.location.hash;
let url = window.location.origin;
if (hash) {
url = window.location.href.replace(hash, '#/voip');
} else {
url += "/voip"
}
url += '/' + type + '?t=' + new Date().getTime()
win.loadURL(url);
console.log('voip windows url', url)
win.show();
win.removeMenu();
this.emitToVoip(options.event, options.args);
} else {
this.callWin = window;
console.log('windowEmitter subscribe events');
this.events.once('close-voip-div', () => {
console.log('on close-voip-div', this.conversation, this.onVoipCallStatusCallback)
this.onVoipCallStatusCallback && this.onVoipCallStatusCallback(this.conversation, false)
this.callWin = null;
this.isVoipWindowReady = false;
if (this.conference) {
wfc.quitChatroom(this.callId);
this.conference = false;
}
this.conference = false;
this.callId = null;
this.conversation = null;
this.participants = [];
this.queueEvents = [];
})
// 等 voip view mounted
setTimeout(() => {
this.isVoipWindowReady = true;
this.emitToVoip(options.event, options.args);
}, 200)
this.onVoipCallStatusCallback && this.onVoipCallStatusCallback(this.conversation, true)
}
}
onVoipWindowClose = (event) => {
if (event && event.srcElement && event.srcElement.URL === 'about:blank') {
// fix safari bug: safari 浏览器,页面刚打开的时候,也会走到这个地方
return;
}
// 让voip内部先处理关闭事件,内部处理时,可能还需要发消息
console.log('onVoipWindowClose')
if (!this.callWin) {
return;
}
setTimeout(() => {
this.onVoipCallStatusCallback && this.onVoipCallStatusCallback(this.conversation, false);
this.conversation = null;
if (this.conference) {
wfc.quitChatroom(this.callId);
this.conference = false;
}
this.callId = null;
this.participants = [];
this.queueEvents = [];
this.callWin = null;
this.isVoipWindowReady = false;
this.voipEventRemoveAllListeners('voip-message', 'conference-request', 'update-call-start-message', 'start-screen-share');
}, 2000);
}
onVoipWindowReady() {
if (!this.callId) {
return;
}
this.isVoipWindowReady = true;
console.log('onVoipWindowReady', this.onVoipCallStatusCallback)
this.onVoipCallStatusCallback && this.onVoipCallStatusCallback(this.conversation, true);
if (!isElectron()) {
// 启动页面的时候就监听,不然太慢了,会丢事件
} else {
console.log('ipcRenderer subscribe events');
ipcRenderer.on('voip-message', this.sendVoipListener);
ipcRenderer.on('conference-request', this.sendConferenceRequestListener);
ipcRenderer.on('update-call-start-message', this.updateCallStartMessageContentListener)
ipcRenderer.on(/*IPCEventType.START_SCREEN_SHARE*/'start-screen-share', (event, args) => {
if (this.callWin) {
let screenWidth = args.width;
this.callWin.resizable = true;
this.callWin.closable = true;
this.callWin.maximizable = false;
this.callWin.transparent = true;
this.callWin.setMinimumSize(800, 800);
this.callWin.setSize(800, 800);
// console.log('screen width', screen, screen.width);
this.callWin.setPosition((screenWidth - 800) / 2, 0, true);
}
});
ipcRenderer.on(/*IPCEventType.STOP_SCREEN_SHARE*/'stop-screen-share', (event, args) => {
if (this.callWin) {
let type = args.type;
let width = 360;
let height = 640;
switch (type) {
case 'single':
width = 360;
height = 640;
break;
case 'multi':
case 'conference':
width = 1024;
height = 800;
break;
default:
break;
}
this.callWin.resizable = true;
this.callWin.closable = true;
this.callWin.maximizable = true;
this.callWin.setMinimumSize(width, height);
this.callWin.setSize(width, height);
this.callWin.center();
}
})
}
if (this.queueEvents.length > 0) {
this.queueEvents.forEach((eventArgs) => {
console.log('process queued event', eventArgs);
this.emitToVoip(eventArgs.event, eventArgs.args);
})
}
}
voipEventRemoveAllListeners(...events) {
if (isElectron()) {
// renderer
events.forEach(e => ipcRenderer.removeAllListeners(e));
}
}
forceCloseVoipWindow() {
if (isElectron() && this.callWin) {
this.callWin.close();
}
this.callId = null;
this.callWin = null;
}
// 仅 web 端,单人、多人通话有效
forceCloseVoipWindowAndHangup() {
if (this.callWin && !this.conference) {
let byeMessage = new CallByeMessageContent();
// 处理用户没有主动挂断,而是直接返回页面时,补偿一个挂断消息
// 现在还无法处理会议的情况,会议只能等待超时
byeMessage.callId = this.callId;
byeMessage.inviteMsgUid = this.inviteMessageUid;
byeMessage.reason = CallEndReason.REASON_Hangup;
wfc.sendConversationMessage(this.conversation, byeMessage);
this.onVoipWindowClose()
}
}
}
const self = new AvEngineKitProxy();
export default self;
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。