Ai_GirlFriend/xuniYou/components/emCallKit/index.js
2026-01-31 19:15:41 +08:00

393 lines
16 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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,
};
};