Ai_GirlFriend/xuniYou/components/emCallKit/index.js

393 lines
16 KiB
JavaScript
Raw Normal View History

2026-01-31 19:15:41 +08:00
import { watch, computed } from 'vue';
import useAgoraChannelStore from './stores/channelManger';
import { CALLSTATUS, ANSWER_TYPE, CALL_ACTIONS_TYPE } from './contants';
import useCallKitEvent from './callKitManage/useCallKitEvent';
/* 频道信令发送 */
import useSendSignalMsgs from './callKitManage/useSendSignalMsgs';
let CallKitEMClient = null;
let CallKitCreateMsgFun = null;
const {
EVENT_NAME,
EVENT_LEVEL,
CALLKIT_EVENT_TYPE,
CALLKIT_EVENT_CODE,
PUB_CHANNEL_EVENT,
} = useCallKitEvent();
//监听本地状态改变做出不同的状态处理。
export const useInitCallKit = () => {
const agoraChannelStore = useAgoraChannelStore();
const { updateChannelInfos, updateLocalStatus } = agoraChannelStore;
const callKitStatus = computed(() => agoraChannelStore.callKitStatus);
const callKitTimer = computed(() => agoraChannelStore.callKitTimer);
//监听频道状态变更做出对应操作。
const onCallKitStatusChangeListener = () => {
console.log('>>>>>频道状态监听已挂载');
watch(
() => callKitStatus.value.localClientStatus,
(newClientStatus, oldClientStatus) => {
handleClientStatusForAction(newClientStatus);
}
);
//处理不同clientstatus执行不同的操作
const handleClientStatusForAction = (clientStatus) => {
switch (clientStatus) {
case CALLSTATUS.idle:
console.log('%c >>>监听新状态为空闲处理,执行初始化', 'color:red');
// initChannelInfos();
agoraChannelStore.initChannelInfos();
break;
case CALLSTATUS.inviting:
// if (callKitStatus.value.channelInfos.callType <= 1) {
// }
// if (callKitStatus.value.channelInfos.callType === 2) {
// }
// console.log('>>>>>可以展开邀请窗口');
break;
case CALLSTATUS.receivedConfirmRing:
const eventParams = {
type: CALLKIT_EVENT_TYPE[CALLKIT_EVENT_CODE.ALERT_SCREEN],
ext: { message: '可以弹出通话接听UI组件' },
callType: callKitStatus.value.channelInfos.callType,
eventHxId: '',
};
PUB_CHANNEL_EVENT(EVENT_NAME, { ...eventParams });
break;
case CALLSTATUS.answerCall:
console.log('>>>>>可以弹出通话接听UI组件');
// if (callKitStatus.value.channelInfos.callType <= 1) {
// console.log('>>>>>>>展示单人音视频组件');
// // callComponents.value = 'singleCall';
// }
// if (callKitStatus.value.channelInfos.callType === 2) {
// console.log('》》》》》展示多人音视频组件');
// // callComponents.value = 'multiCall';
// }
break;
case CALLSTATUS.confirmCallee:
{
// console.log('%c >>>>>可以加入房间了', 'color:green;');
// console.log(
// '++++++将入的频道类型是',
// callKitStatus.value.channelInfos.callType
// );
// console.log(
// '++++++频道名是',
// callKitStatus.value.channelInfos.channelName
// );
}
break;
default:
break;
}
};
};
//初始化EMClient之Callkit内
const setCallKitClient = (EMClient, CreateMsgFun) => {
CallKitEMClient = EMClient;
CallKitCreateMsgFun = CreateMsgFun;
mountSignallingListener();
};
//挂载Callkit信令相关监听
const mountSignallingListener = () => {
console.log('>>>>>>>callkit 监听已挂载');
const { sendAnswerMsg, sendAlertMsg, sendConfirmRing, sendConfirmCallee } =
useSendSignalMsgs();
onCallKitStatusChangeListener();
CallKitEMClient.addEventHandler('callkitConnected', {
onConnected: () => {
//连接成功初始化emClient信息
agoraChannelStore.initEmClientInfos(CallKitEMClient);
},
});
CallKitEMClient.addEventHandler('callkitSignal', {
onTextMessage: (message) => {
const { ext } = message;
if (ext && ext?.action === CALL_ACTIONS_TYPE.INVITE)
handleCallKitInvite(message);
console.log('>>>>>收到文本信令消息', message);
},
onCmdMessage: (msg) => {
console.log('>>>>>收到命令信令消息', msg);
if (msg && msg?.action === CALL_ACTIONS_TYPE.RTC_CALL)
handleCallKitCommand(msg);
},
});
//处理收到为文本的邀请信息
const handleCallKitInvite = (msgBody) => {
console.log('>>>>>开始处理被邀请消息');
const { from, ext } = msgBody || {};
//邀请消息发送者为自己则忽略
if (from === CallKitEMClient.user) return;
//非空闲回复busy
if (callKitStatus.value.localClientStatus > CALLSTATUS.idle) {
const payload = {
targetId: from,
sendBody: ext,
};
sendAnswerMsg(payload, ANSWER_TYPE.BUSY);
} else {
//更新当前频道信息
updateChannelInfos(msgBody);
//更新呼叫状态为alerting
updateLocalStatus(CALLSTATUS.alerting);
//通知呼叫方可以调起通话窗口
sendAlertMsg(msgBody);
}
};
//处理接收到通话交互过程的CMD命令消息
const handleCallKitCommand = (msgBody) => {
//多端状态下信令消息发送者为自己则忽略
if (msgBody.from === CallKitEMClient.user) return;
const cmdMsgBody = Object.assign({}, msgBody.ext) || {};
const { calleeDevId, callerDevId } = cmdMsgBody;
const clientResource = CallKitEMClient.context.jid.clientResource;
const { action } = cmdMsgBody;
const { localClientStatus, channelInfos } = callKitStatus.value;
//当前有效会议ID
const currentCallKitCallId = callKitStatus.value.channelInfos.callId;
//返回给对方的confirmRing状态
let status = true;
const params = {
targetId: msgBody.from,
sendBody: cmdMsgBody,
status,
};
//对方发布事件所需参数
const eventParams = {
type: {},
ext: {},
callType: 0,
eventHxId: '',
};
switch (action) {
case CALL_ACTIONS_TYPE.ALERT: //回复confirmring
updateLocalStatus(CALLSTATUS.alerting);
if (cmdMsgBody.callId !== currentCallKitCallId) {
status = false;
console.warn('callId 于当前呼叫端callId 不一致');
return;
}
if (
localClientStatus > CALLSTATUS.receivedConfirmRing &&
channelInfos.callType !== 2
) {
status = false;
}
if (callerDevId !== clientResource) {
console.warn('callerDevId 设备不相同');
status = false;
}
//如果status为true表明为有效的邀请再更改为inviting,false表示无效邀请则更改为空闲状态。
if (status) {
sendConfirmRing(params);
updateLocalStatus(CALLSTATUS.inviting);
} else {
sendConfirmRing(params);
updateLocalStatus(CALLSTATUS.idle);
}
break;
case CALL_ACTIONS_TYPE.CONFIRM_RING: //回复 receivedConfirmRing
{
//调起confirm待接听界面
if (calleeDevId !== clientResource) return; //【多端情况】被叫方设备id 如果不为当前用户登陆设备ID则不处理。
if (
!cmdMsgBody.status &&
callKitStatus.value.localClientStatus <
CALLSTATUS.receivedConfirmRing
) {
updateLocalStatus(CALLSTATUS.idle); //重置为闲置状态
} //邀请失效,不弹出接听确认框
//有效邀请则设置状态为收到confirmRing
updateLocalStatus(CALLSTATUS.receivedConfirmRing);
}
break;
case CALL_ACTIONS_TYPE.ANSWER: //回复 confirmCallee
{
if (callerDevId !== clientResource) return; //【多端情况】呼叫方设备id 如果不为当前用户登陆设备ID则不处理。
updateLocalStatus(CALLSTATUS.receivedAnswerCall);
callKitTimer.value && clearTimeout(callKitTimer.value);
const params = {
targetId: msgBody.from,
sendBody: cmdMsgBody,
};
console.log('>>>>>>>>>收到answer信令', params);
if (
!callKitStatus.value.channelInfos.calleeDevId &&
callKitStatus.value.channelInfos.callType !== 2
) {
//如果calleeDevId不存在并且非多人音视频模式主动更新频道信息
if (cmdMsgBody.videoToVoice) {
callKitStatus.value.channelInfos.callType = 0;
}
updateChannelInfos(msgBody);
} else if (
callKitStatus.value.channelInfos.calleeDevId !==
cmdMsgBody.calleeDevId &&
callKitStatus.value.channelInfos.callType !== 2
) {
//如果存在频道信息但是与待呼叫确认的calleeDevId不一致直接发送拒绝应答。
params.sendBody.result = ANSWER_TYPE.REFUSE;
}
sendConfirmCallee(params);
updateLocalStatus(CALLSTATUS.confirmCallee);
if (cmdMsgBody.result !== ANSWER_TYPE.ACCPET) {
if (callKitStatus.value.channelInfos.callType !== 2) {
//无论对方是忙碌还是拒接都讲通话状态更改为闲置。
if (cmdMsgBody.result === ANSWER_TYPE.BUSY) {
uni.showToast({
title: '对方正忙',
icon: 'none',
duration: 2000,
});
eventParams.type =
CALLKIT_EVENT_TYPE[CALLKIT_EVENT_CODE.CALLEE_BUSY];
eventParams.ext = { message: '对方正忙' };
}
if (cmdMsgBody.result === ANSWER_TYPE.REFUSE) {
eventParams.type =
CALLKIT_EVENT_TYPE[CALLKIT_EVENT_CODE.CALLEE_REFUSE];
eventParams.ext = { message: '对方拒绝接听' };
uni.showToast({
title: '对方拒绝接听',
icon: 'none',
duration: 2000,
});
}
eventParams.callType =
callKitStatus.value.channelInfos.callType;
eventParams.eventHxId = msgBody.from || '';
PUB_CHANNEL_EVENT(EVENT_NAME, { ...eventParams });
//修改当前状态为空闲
console.log('>>>>>修改当前状态为空闲');
return updateLocalStatus(CALLSTATUS.idle);
}
}
}
break;
case CALL_ACTIONS_TYPE.CONFIRM_CALLEE: //被叫方认证
{
//如果calleeDevId不等于当前设备resource
if (msgBody.to === CallKitEMClient.user) {
if (cmdMsgBody.result && cmdMsgBody.result === ANSWER_TYPE.BUSY) {
return;
}
if (cmdMsgBody.calleeDevId !== clientResource) {
updateLocalStatus(CALLSTATUS.idle); //更改状态为闲置
console.log('%c 已在其他设备处理', 'color:red;');
eventParams.type =
CALLKIT_EVENT_TYPE[CALLKIT_EVENT_CODE.OTHER_HANDLE];
eventParams.ext = { message: '已在其他设备处理' };
eventParams.callType =
callKitStatus.value.channelInfos.callType;
eventParams.eventHxId = msgBody.from || '';
PUB_CHANNEL_EVENT(EVENT_NAME, { ...eventParams });
uni.showToast({
title: '该通话已在其他设备处理',
icon: 'none',
duration: 2000,
});
return;
}
}
// 防止通话中收到 busy refuse时挂断
if (
cmdMsgBody.result !== ANSWER_TYPE.ACCPET &&
callKitStatus.value.localClientStatus !== CALLSTATUS.confirmCallee
) {
return updateLocalStatus(CALLSTATUS.idle); //更改状态为闲置
}
//变更状态为confirmCallee
updateLocalStatus(CALLSTATUS.confirmCallee);
}
break;
case CALL_ACTIONS_TYPE.CANCEL: {
if (msgBody.from === CallKitEMClient.user) return; //【多端情况】被叫方设备id 如果不为当前用户登陆设备ID则不处理。
if (msgBody.from === callKitStatus.value.channelInfos.callerIMName)
return updateLocalStatus(CALLSTATUS.idle);
eventParams.type =
CALLKIT_EVENT_TYPE[CALLKIT_EVENT_CODE.CALLER_CANCEL];
eventParams.ext = { message: '对方取消呼叫' };
eventParams.callType = callKitStatus.value.channelInfos.callType;
eventParams.eventHxId = msgBody.from || '';
PUB_CHANNEL_EVENT(EVENT_NAME, { ...eventParams });
break;
}
case CALL_ACTIONS_TYPE.VIDEO_TO_VOICE: {
if (cmdMsgBody.callId !== callKitStatus.value.channelInfos.callType)
return;
callKitStatus.value.channelInfos.callType = CALL_TYPES.SINGLE_VOICE;
break;
}
default:
console.log('>>>其他未知状态');
break;
}
};
};
//发送接听或者拒接信令
const handleSendAnswerMsg = (sendType) => {
const { sendAnswerMsg } = useSendSignalMsgs();
const channelInfos = callKitStatus.value.channelInfos;
const payload = {
targetId: channelInfos.callerIMName,
sendBody: {
callerDevId: channelInfos.callerDevId,
callId: channelInfos.callId,
},
};
if (sendType === ANSWER_TYPE.ACCPET) {
sendAnswerMsg(payload, ANSWER_TYPE.ACCPET);
updateLocalStatus(CALLSTATUS.answerCall); //更改状态为已应答
console.log('>>>>开始发送接听信令', payload);
//对外频道接听事件发布事件
const eventParams = {
type: CALLKIT_EVENT_TYPE[CALLKIT_EVENT_CODE.CALLEE_ACCPET],
ext: { message: '通话已接听' },
callType: callKitStatus.value.channelInfos.callType,
eventHxId: channelInfos.callerIMName,
};
//如果是多人就取对应群组ID
if (callKitStatus.value.channelInfos.callType === 2) {
eventParams.eventHxId = callKitStatus.value.channelInfos.groupId;
}
uni.showToast({
title: '通话已接听',
icon: 'none',
duration: 2000,
});
PUB_CHANNEL_EVENT(EVENT_NAME, { ...eventParams });
}
if (sendType === ANSWER_TYPE.REFUSE) {
sendAnswerMsg(payload, ANSWER_TYPE.REFUSE);
updateLocalStatus(CALLSTATUS.idle); //更改状态为闲置
console.log('>>>>开始发送挂断信令');
//对外频道接听事件发布事件
const eventParams = {
type: CALLKIT_EVENT_TYPE[CALLKIT_EVENT_CODE.CALLEE_REFUSE],
ext: { message: '已拒绝通话邀请' },
callType: callKitStatus.value.channelInfos.callType,
eventHxId: channelInfos.callerIMName,
};
uni.showToast({
title: '已拒绝通话邀请',
icon: 'none',
duration: 2000,
});
//如果是多人就取对应群组ID
if (callKitStatus.value.channelInfos.callType === 2) {
eventParams.eventHxId = callKitStatus.value.channelInfos.groupId;
}
PUB_CHANNEL_EVENT(EVENT_NAME, { ...eventParams });
}
};
return {
CallKitEMClient,
CallKitCreateMsgFun,
setCallKitClient,
handleSendAnswerMsg,
};
};