123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927 |
- import TUICallEngine, { EVENT, MEDIA_TYPE, AUDIO_PLAYBACK_DEVICE, STATUS } from 'tuicall-engine-wx';
- import { BellContext } from './serve/bellContext';
- import { throttle, isTabBarPage, tabBarConfig } from './utils/commom';
- import { THROTTLE_TIME } from './utils/constants';
- // 组件旨在跨终端维护一个通话状态管理机,以事件发布机制驱动上层进行管理,并通过API调用进行状态变更。
- // 组件设计思路将UI和状态管理分离。您可以通过修改`component`文件夹下的文件,适配您的业务场景,
- // 在UI展示上,您可以通过属性的方式,将上层的用户头像,名称等数据传入组件内部,`static`下的icon和默认头像图片,
- // 只是为了展示基础的效果,您需要根据业务场景进行修改。
- export const PREFIX = 'TUICallKit';
- const version = '1.4.4';
- let INVITER_BELL_FILEPATH = 'TUICallKit/TUICallKit/static/phone_dialing.mp3';
- let INVITEE_BELL_FILEPATH = 'TUICallKit/TUICallKit/static/phone_ringing.mp3';
- // 记录组件是否初始化完成
- let tuiCallInitReady = false;
- // 是否需要隐藏 tabBar 页面
- let shouldHideTabBar = false;
- Component({
- properties: {
- config: {
- type: Object,
- value: {
- sdkAppID: 0,
- userID: '',
- userSig: '',
- type: 1,
- tim: null,
- },
- },
- backgroundMute: {
- type: Boolean,
- value: false,
- },
- },
- data: {
- callStatus: STATUS.IDLE, // idle、calling、connection
- isSponsor: false, // 呼叫者身份 true为呼叫者 false为被叫者
- pusher: {}, // TRTC 本地流
- playerList: [], // TRTC 远端流
- playerProcess: {}, // 经过处理的的远端流(多人通话)
- isGroup: false, // 是否为多人通话
- remoteUsers: [], // 未排序的通话列表
- allUsers: [], // 排序后的通话列表
- sponsor: '', // 主叫方
- screen: 'pusher', // 视屏通话中,显示大屏幕的流(只限1v1聊天
- soundMode: AUDIO_PLAYBACK_DEVICE.SPEAKER, // 声音模式 听筒/扬声器
- showToatTime: 0, // 弹窗时长
- ownUserId: '',
- callingBell: null,
- bellFilePath: '', // 被叫方铃声地址
- },
- methods: {
- initialUI() {
- // 收起键盘
- wx.hideKeyboard();
- // 隐藏 tabBar
- if (shouldHideTabBar) {
- wx.hideTabBar();
- }
- },
- // 新的邀请回调事件
- async handleNewInvitationReceived(event) {
- this.initialUI();
- this.checkRunPlatform();
- this.data.config.type = event.data.inviteData.callType;
- this.data.callingBell.setBellSrc(this.data.bellFilePath || INVITEE_BELL_FILEPATH);
- this.data.callingBell.play();
- // 判断是否为多人通话
- if (event.data.isFromGroup) {
- this.setData({
- isGroup: true,
- sponsor: event.data.sponsor,
- });
- // 将主叫方和被叫列表合并在一起 组成全部通话人数
- const newList = [...event.data.inviteeList, event.data.sponsor];
- // 获取用户信息
- await this.getUserProfile(newList);
- } else {
- await this.getUserProfile([event.data.sponsor]);
- }
- this.setData({
- config: this.data.config,
- callStatus: STATUS.CALLING,
- isSponsor: false,
- });
- },
- // 用户接听
- handleUserAccept(event) {
- // 主叫方则唤起通话页面
- if (this.isSponsor()) {
- this.data.callingBell && this.data.callingBell.stop();
- this.setData({
- callStatus: STATUS.CONNECTED,
- });
- }
- },
- // 远端用户进入通话
- handleUserEnter(res) {
- const newList = this.data.allUsers;
- // 多人通话
- if (this.data.isGroup) {
- // 改变远端用户信息中的isEnter属性
- for (let i = 0;i < newList.length;i++) {
- if (newList[i].userID === res.data.userID) {
- newList[i].isEnter = true;
- }
- }
- }
- this.setData({
- playerList: res.playerList,
- allUsers: newList,
- });
- },
- // 远端用户离开通话
- handleUserLeave(res) {
- // 多人通话
- if (this.data.isGroup) {
- wx.showToast({
- title: `${this.getUserNickName(res.data.userID)}离开通话`,
- });
- this.deleteUsers(this.data.allUsers, res.data.userID);
- }
- this.setData({
- playerList: res.data.playerList,
- });
- },
- // 用户数据更新
- handleUserUpdate(res) {
- this.handleNetStatus(res.data);
- const newplayer = {};
- const newres = res.data.playerList;
- // 多人通话
- if (this.data.isGroup) {
- // 处理远端流
- for (let i = 0;i < newres.length;i++) {
- const { userID } = newres[i];
- newplayer[userID] = newres[i];
- }
- };
- this.setData({
- pusher: res.data.pusher,
- playerList: res.data.playerList,
- playerProcess: newplayer,
- });
- },
- // 判断网络状态
- handleNetStatus(data) {
- if (data.pusher.netQualityLevel > 4) {
- wx.showToast({
- icon: 'none',
- title: '您当前网络不佳',
- });
- }
- data.playerList.map((item) => {
- if (item.netStatus.netQualityLevel > 4) {
- const name = data.playerList.length > 1 ? item.nick : '对方';
- wx.showToast({
- icon: 'none',
- title: `${name}当前网络不佳`,
- });
- }
- return item;
- });
- },
- // 用户拒绝
- handleInviteeReject(event) {
- if (this.data.isGroup) {
- this.deleteUsers(this.data.allUsers, event.data.invitee);
- } else {
- this.data.callingBell && this.data.callingBell.stop();
- }
- wx.showToast({
- title: `${this.getUserNickName(event.data.invitee)}已拒绝`,
- });
- },
- // 用户不在线
- handleNoResponse(event) {
- if (this.data.isGroup) {
- this.deleteUsers(this.data.allUsers, event.data.timeoutUserList);
- } else {
- this.data.callingBell && this.data.callingBell.stop();
- }
- wx.showToast({
- icon: 'none',
- title: `${event.data.timeoutUserList}无应答`,
- });
- },
- // 获取用户昵称
- getUserNickName(userId) {
- const { remoteUsers } = this.data;
- const userObj = remoteUsers.find(item => item.userID === userId);
- return userObj.nick ? userObj.nick : userObj.userID;
- },
- // 用户忙线
- handleLineBusy(event) {
- if (this.data.isGroup) {
- this.deleteUsers(this.data.allUsers, event.data.invitee);
- } else {
- this.data.callingBell && this.data.callingBell.stop();
- }
- this.showToast(this.getUserNickName(event.data.invitee));
- },
- showToast(event) {
- this.setData({
- showToatTime: this.data.showToatTime + THROTTLE_TIME,
- });
- setTimeout(() => {
- wx.showToast({
- title: `${event}忙线中`,
- });
- }, this.data.showToatTime);
- },
- // 用户取消
- handleCallingCancel(event) {
- this.data.callingBell && this.data.callingBell.stop();
- if (event.data.invitee !== this.data.config.userID) {
- wx.showToast({
- title: `${this.getUserNickName(event.data.invitee)}取消通话`,
- });
- }
- this.reset();
- },
- // 通话超时未应答
- handleCallingTimeout(event) {
- if (this.data.isGroup) {
- // 若是自身未应答 则不弹窗
- if (this.data.config.userID === event.data.timeoutUserList[0]) {
- this.reset();
- return;
- }
- const newList = this.deleteUsers(this.data.allUsers, event.data.timeoutUserList);
- this.setData({
- allUsers: newList,
- });
- } else {
- this.data.callingBell && this.data.callingBell.stop();
- }
- if (this.data.playerList.length === 0) {
- this.reset();
- }
- wx.showToast({
- title: `${event.data.timeoutUserList[0]}超时无应答`,
- });
- },
- handleCallingUser(userIDList) {
- const remoteUsers = [...this.data.remoteUsers];
- const userProfile = remoteUsers.filter(item => userIDList.some(userItem => `${userItem}` === item.userID));
- this.setData({
- remoteUsers: remoteUsers.filter(item => userIDList.some(userItem => userItem !== item.userID)),
- });
- let nick = '';
- for (let i = 0; i < userProfile.length; i++) {
- nick += `${userProfile[i].nick}、`;
- }
- return nick.slice(0, -1);
- },
- // 通话结束
- handleCallingEnd(event) {
- wx.showToast({
- title: '通话结束',
- duration: 800,
- });
- this.reset();
- },
- // SDK Ready 回调
- handleSDKReady() {
- // 呼叫需在sdk ready之后
- },
- // 被踢下线
- handleKickedOut() {
- wx.showToast({
- title: '您已被踢下线',
- });
- },
- // 切换通话模式
- handleCallMode(event) {
- this.data.config.type = event.data.type;
- this.setSoundMode(AUDIO_PLAYBACK_DEVICE.EAR);
- this.setData({
- config: this.data.config,
- });
- },
- handleError(event) {
- const { code, message } = event.data || {};
- console.warn(`${PREFIX} errorCode: ${code}, errorMessage: ${message}`);
- },
- // 删除用户列表操作
- deleteUsers(usersList, userID) {
- // 若userID不是数组,则将其转换为数组
- if (!Array.isArray(userID)) {
- userID = [userID];
- }
- const list = usersList.filter(item => !userID.includes(item.userID));
- this.setData({
- allUsers: list,
- });
- },
- // 增加用户列表操作
- addUsers(usersList, userID) {
- // 若userID不是数组,则将其转换为数组
- if (!Array.isArray(userID)) {
- userID = [userID];
- }
- const newList = [...usersList, ...userID];
- return newList;
- },
- // 增加 tsignaling 事件监听
- _addTSignalingEvent() {
- wx.$TUICallEngine.on(EVENT.ERROR, this.handleError, this);
- // 被邀请通话
- wx.$TUICallEngine.on(EVENT.INVITED, this.handleNewInvitationReceived, this);
- // 用户接听
- wx.$TUICallEngine.on(EVENT.USER_ACCEPT, this.handleUserAccept, this);
- // 用户进入通话
- wx.$TUICallEngine.on(EVENT.USER_ENTER, this.handleUserEnter, this);
- // 用户离开通话
- wx.$TUICallEngine.on(EVENT.USER_LEAVE, this.handleUserLeave, this);
- // 用户更新数据
- wx.$TUICallEngine.on(EVENT.USER_UPDATE, this.handleUserUpdate, this);
- // 用户拒绝通话
- wx.$TUICallEngine.on(EVENT.REJECT, this.handleInviteeReject, this);
- // 用户无响应
- wx.$TUICallEngine.on(EVENT.NO_RESP, this.handleNoResponse, this);
- // 用户忙线
- wx.$TUICallEngine.on(EVENT.LINE_BUSY, this.handleLineBusy, this);
- // 通话被取消
- wx.$TUICallEngine.on(EVENT.CALLING_CANCEL, this.handleCallingCancel, this);
- // 通话超时未应答
- wx.$TUICallEngine.on(EVENT.CALLING_TIMEOUT, this.handleCallingTimeout, this);
- // 通话结束
- wx.$TUICallEngine.on(EVENT.CALL_END, this.handleCallingEnd, this);
- // SDK Ready 回调
- wx.$TUICallEngine.on(EVENT.SDK_READY, this.handleSDKReady, this);
- // 被踢下线
- wx.$TUICallEngine.on(EVENT.KICKED_OUT, this.handleKickedOut, this);
- // 切换通话模式
- wx.$TUICallEngine.on(EVENT.CALL_MODE, this.handleCallMode, this);
- // 自己发送消息
- wx.$TUICallEngine.on(EVENT.MESSAGE_SENT_BY_ME, this.messageSentByMe, this);
- },
- // 取消 tsignaling 事件监听
- _removeTSignalingEvent() {
- wx.$TUICallEngine.off(EVENT.ERROR, this.handleError);
- // 被邀请通话
- wx.$TUICallEngine.off(EVENT.INVITED, this.handleNewInvitationReceived);
- // 用户接听
- wx.$TUICallEngine.off(EVENT.USER_ACCEPT, this.handleUserAccept);
- // 用户进入通话
- wx.$TUICallEngine.off(EVENT.USER_ENTER, this.handleUserEnter);
- // 用户离开通话
- wx.$TUICallEngine.off(EVENT.USER_LEAVE, this.handleUserLeave);
- // 用户更新数据
- wx.$TUICallEngine.off(EVENT.USER_UPDATE, this.handleUserUpdate);
- // 用户拒绝通话
- wx.$TUICallEngine.off(EVENT.REJECT, this.handleInviteeReject);
- // 用户无响应
- wx.$TUICallEngine.off(EVENT.NO_RESP, this.handleNoResponse);
- // 用户忙线
- wx.$TUICallEngine.off(EVENT.LINE_BUSY, this.handleLineBusy);
- // 通话被取消
- wx.$TUICallEngine.off(EVENT.CALLING_CANCEL, this.handleCallingCancel);
- // 通话超时未应答
- wx.$TUICallEngine.off(EVENT.CALLING_TIMEOUT, this.handleCallingTimeout);
- // 通话结束
- wx.$TUICallEngine.off(EVENT.CALL_END, this.handleCallingEnd);
- // SDK Ready 回调
- wx.$TUICallEngine.off(EVENT.SDK_READY, this.handleSDKReady);
- // 被踢下线
- wx.$TUICallEngine.off(EVENT.KICKED_OUT, this.handleKickedOut);
- // 切换通话模式
- wx.$TUICallEngine.off(EVENT.CALL_MODE, this.handleCallMode);
- // 自己发送消息
- wx.$TUICallEngine.off(EVENT.MESSAGE_SENT_BY_ME, this.messageSentByMe);
- },
- /**
- * C2C邀请通话,被邀请方会收到的回调
- * 如果当前处于通话中,可以调用该函数以邀请第三方进入通话
- * @param {Object} params 呼叫参数
- * @param {String} params.userID 被邀请方
- * @param {Number} params.type 0-未知,1-语音通话,2-视频通话
- * @param {Number} params.roomID 数字房间号, 范围 1~2147483647
- * @param {String=} params.userData 扩展字段: 用于在邀请信令中增加扩展信息
- */
- call: throttle(async function (params) {
- this.initialUI();
- if (this.data.callStatus !== STATUS.IDLE) {
- return;
- }
- this.checkRunPlatform();
- this.data.config.type = params.type;
- // 检查设备权限
- const deviceMap = {
- microphone: true,
- camera: params.type === MEDIA_TYPE.VIDEO,
- };
- const hasDevicePermission = await wx.$TUICallEngine.deviceCheck(deviceMap);
- const callStatus = hasDevicePermission ? STATUS.CALLING : STATUS.IDLE;
- this.setData({
- callStatus,
- isSponsor: true,
- config: this.data.config,
- });
- try {
- await this.getUserProfile([params.userID]);
- } catch (error) {
- console.warn(error);
- }
- wx.$TUICallEngine.call({ userID: params.userID, type: params.type, roomID: params.roomID, userData: params.userData }).then(async (res) => {
- if (res) {
- this.setData({
- callStatus: STATUS.CALLING,
- pusher: res.pusher,
- });
- this.data.callingBell.setBellSrc(INVITER_BELL_FILEPATH);
- this.data.callingBell.play();
- this.setSoundMode(this.data.config.type === MEDIA_TYPE.AUDIO ? AUDIO_PLAYBACK_DEVICE.EAR : AUDIO_PLAYBACK_DEVICE.SPEAKER);
- }
- })
- .catch((error) => {
- if (error.code === -1002) {
- wx.showModal({
- icon: 'none',
- title: 'error',
- content: error.message,
- showCancel: false,
- });
- }
- this.reset();
- throw new Error(error);
- });
- }, THROTTLE_TIME),
- /**
- * IM群组邀请通话,被邀请方会收到的回调
- * 如果当前处于通话中,可以继续调用该函数继续邀请他人进入通话,同时正在通话的用户会收到的回调
- *
- * @param {Object} params 呼叫参数
- * @param {Array<String>} params.userIDList 邀请列表
- * @param {Number} params.type 1-语音通话,2-视频通话
- * @param {String} params.groupID IM群组ID
- * @param {Number} params.roomID 数字房间号, 范围 1~2147483647
- * @param {String=} params.userData 扩展字段: 用于在邀请信令中增加扩展信息
- */
- groupCall: throttle(async function (params) {
- // 判断是否存在groupID
- if (!params.groupID) {
- wx.showToast({
- title: '群ID为空',
- });
- return;
- }
- this.initialUI();
- if (this.data.callStatus !== STATUS.IDLE) {
- return;
- }
- this.checkRunPlatform();
- this.data.config.type = params.type;
- // 检查设备权限
- const deviceMap = {
- microphone: true,
- camera: params.type === MEDIA_TYPE.VIDEO,
- };
- const hasDevicePermission = await wx.$TUICallEngine.deviceCheck(deviceMap);
- const callStatus = hasDevicePermission ? STATUS.CALLING : STATUS.IDLE;
- this.setData({
- callStatus,
- isSponsor: true,
- isGroup: true,
- sponsor: this.data.config.userID,
- config: this.data.config,
- });
- // 将自身的userID插入到邀请列表中,组成完整的用户信息
- const list = JSON.parse(JSON.stringify(params.userIDList));
- list.unshift(this.data.config.userID);
- // 获取用户信息
- try {
- await this.getUserProfile(list);
- } catch (error) {
- console.warn(error);
- }
- wx.$TUICallEngine.groupCall({
- userIDList: params.userIDList,
- type: params.type,
- groupID: params.groupID,
- roomID: params.roomID,
- userData: params.userData,
- }).then(async (res) => {
- if (res) {
- this.data.config.type = params.type;
- this.setData({
- pusher: res.pusher,
- callStatus: STATUS.CALLING,
- });
- this.data.callingBell.setBellSrc(INVITER_BELL_FILEPATH);
- this.data.callingBell.play();
- }
- })
- .catch((error) => {
- if (error.code === -1002) {
- wx.showModal({
- icon: 'none',
- title: 'error',
- content: error.message,
- showCancel: false,
- });
- }
- this.reset();
- throw new Error(error);
- });
- }, THROTTLE_TIME),
- /**
- * 当您作为被邀请方收到 {@link TRTCCallingDelegate#onInvited } 的回调时,可以调用该函数接听来电
- */
- accept: throttle(async function () {
- wx.$TUICallEngine.accept().then((res) => {
- if (res) {
- this.data.callingBell && this.data.callingBell.stop();
- this.setData({
- pusher: res.pusher,
- callStatus: STATUS.CONNECTED,
- });
- // 多人通话需要对自身位置进行修正,将其放到首位
- if (this.data.isGroup) {
- const newList = this.data.allUsers;
- for (let i = 0;i < newList.length;i++) {
- if (newList[i].userID === this.data.config.userID) {
- newList[i].isEnter = true;
- [newList[i], newList[0]] = [newList[0], newList[i]];
- }
- };
- this.setData({
- allUsers: newList,
- });
- }
- }
- })
- .catch((error) => {
- console.error(error);
- this.reset();
- });
- }, THROTTLE_TIME),
- /**
- * 当您作为被邀请方收到的回调时,可以调用该函数拒绝来电
- */
- reject: throttle(async function () {
- wx.$TUICallEngine.reject().then((res) => {
- this.data.callingBell && this.data.callingBell.stop();
- this.reset();
- })
- .catch((error) => {
- console.error(error);
- this.reset();
- });
- }, THROTTLE_TIME),
- messageSentByMe(event) {
- const message = event.data.data;
- this.triggerEvent('sendMessage', {
- message,
- });
- },
- // xml层,是否开启扬声器
- setSoundMode(type) {
- this.setData({
- soundMode: wx.$TUICallEngine.selectAudioPlaybackDevice(type),
- });
- },
- // xml层,挂断
- hangup: throttle(async function () {
- try {
- await wx.$TUICallEngine.hangup();
- this.reset();
- } catch (error) {
- console.error(error);
- this.reset();
- }
- }, THROTTLE_TIME),
- // 切换大小屏 (仅支持1v1聊天)
- toggleViewSize(event) {
- this.setData({
- // FIXME _toggleViewSize 不应该为TUICallEngine的方法 后续修改
- screen: wx.$TUICallEngine._toggleViewSize(event),
- });
- },
- // 数据重置
- reset() {
- if (shouldHideTabBar) {
- wx.showTabBar();
- }
- this.setData({
- callStatus: STATUS.IDLE,
- isSponsor: false,
- isGroup: false,
- soundMode: AUDIO_PLAYBACK_DEVICE.SPEAKER,
- pusher: {}, // TRTC 本地流
- playerList: [], // TRTC 远端流
- showToatTime: 0,
- });
- },
- // 呼叫中的事件处理
- async handleCallingEvent(data) {
- const { name, event } = data.detail;
- switch (name) {
- case 'accept':
- this.setSoundMode(this.data.config.type === MEDIA_TYPE.AUDIO ? AUDIO_PLAYBACK_DEVICE.EAR : AUDIO_PLAYBACK_DEVICE.SPEAKER);
- this.accept();
- break;
- case 'hangup':
- await this.hangup();
- break;
- case 'reject':
- await this.reject();
- break;
- case 'toggleSwitchCamera':
- wx.$TUICallEngine.switchCamera();
- break;
- case 'switchAudioCall':
- wx.$TUICallEngine.switchCallMediaType(MEDIA_TYPE.AUDIO).then((res) => {
- this.data.config.type = MEDIA_TYPE.AUDIO;
- this.setSoundMode(AUDIO_PLAYBACK_DEVICE.EAR);
- this.setData({
- config: this.data.config,
- });
- });
- break;
- case 'pusherErrorHandler':
- this.pusherErrorHandler(event.errMsg);
- break;
- default:
- break;
- }
- },
- // 通话中的事件处理
- async handleConnectedEvent(data) {
- const { name, event } = data.detail;
- switch (name) {
- case 'toggleViewSize':
- this.toggleViewSize(event);
- break;
- case 'pusherNetStatus':
- wx.$TUICallEngine._pusherNetStatus(event);
- break;
- case 'playNetStatus':
- wx.$TUICallEngine._playNetStatus(event);
- break;
- case 'pusherStateChangeHandler':
- wx.$TUICallEngine._pusherStateChangeHandler(event);
- break;
- case 'pusherAudioVolumeNotify':
- wx.$TUICallEngine._pusherAudioVolumeNotify(event);
- break;
- case 'playerStateChange':
- wx.$TUICallEngine._playerStateChange(event);
- break;
- case 'playerAudioVolumeNotify':
- wx.$TUICallEngine._playerAudioVolumeNotify(event);
- break;
- case 'pusherAudioHandler':
- wx.$TUICallEngine._pusherAudioHandler(event);
- break;
- case 'hangup':
- await this.hangup();
- break;
- case 'toggleSoundMode':
- this.setSoundMode(this.data.soundMode === AUDIO_PLAYBACK_DEVICE.EAR ? AUDIO_PLAYBACK_DEVICE.SPEAKER : AUDIO_PLAYBACK_DEVICE.EAR);
- break;
- case 'pusherVideoHandler':
- wx.$TUICallEngine._pusherVideoHandler(event);
- break;
- case 'toggleSwitchCamera':
- wx.$TUICallEngine.switchCamera(event);
- break;
- case 'switchAudioCall':
- wx.$TUICallEngine.switchCallMediaType(MEDIA_TYPE.AUDIO).then((res) => {
- this.data.config.type = MEDIA_TYPE.AUDIO;
- this.setData({
- config: this.data.config,
- });
- this.setSoundMode(AUDIO_PLAYBACK_DEVICE.EAR);
- });
- break;
- case 'pusherErrorHandler':
- this.pusherErrorHandler(event.errMsg);
- break;
- default:
- break;
- }
- },
- // 处理 pusher 中的异常问题
- pusherErrorHandler(code) {
- switch (code) {
- case 'fail:access denied':
- wx.showModal({
- icon: 'none',
- title: '权限提示',
- content: '当前小程序 appid 不具备 <live-pusher> 和 <live-player> 的使用权限,您将无法正常使用实时通话能力,请使用企业小程序账号申请权限后再进行开发体验',
- showCancel: false,
- });
- break;
- default:
- break;
- }
- },
- // 设置用户的头像、昵称
- setSelfInfo(nickName, avatar) {
- return wx.$TUICallEngine.setSelfInfo(nickName, avatar);
- },
- // 获取用户资料
- async getUserProfile(userList) {
- const imResponse = await this.getTim().getUserProfile({ userIDList: userList });
- // 修正用户资料
- this.modifyUser(imResponse.data);
- },
- // 修正用户资料
- modifyUser(userIDList) {
- const { sponsor } = this.data;
- if (this.data.isGroup) {
- // 多人通话需要将呼叫者放到第一位 isEnter的作用是区分用户是否进入房间
- for (let i = 0;i < userIDList.length;i++) {
- // 主叫方的标志位设置成true
- if (userIDList[i].userID === sponsor) {
- userIDList[i].isEnter = true;
- // 对主叫方位置进行修正 将其放到首位
- [userIDList[i], userIDList[0]] = [userIDList[0], userIDList[i]];
- } else {
- // 其他用户默认未进入房间 设置为false
- userIDList[i].isEnter = false;
- }
- }
- this.setData({
- allUsers: userIDList,
- });
- }
- this.setData({
- remoteUsers: userIDList,
- });
- },
- // 获取 tim 实例
- getTim() {
- return wx.$TUICallEngine.getTim();
- },
- // 设置日志级别,低于 level 的日志将不会输出
- setLogLevel(leave) {
- wx.$TUICallEngine.setLogLevel(leave);
- },
- // 初始化TUICallKit
- async init(params) {
- if (tuiCallInitReady) return;
- tuiCallInitReady = true;
- // 关于 tabBar 页面的特化逻辑
- this.handleTabBarLogic();
- // 兼容从config和init中传值
- const { sdkAppID, tim, userID, userSig, SDKAppID } = { ...this.data.config, ...params };
- this.setData({
- ownUserId: userID,
- config: {
- ...this.data.config,
- sdkAppID: sdkAppID || SDKAppID,
- userID,
- userSig,
- },
- });
- // 取消全局监听
- if (wx.$globalCallSign) {
- wx.$CallManagerInstance.removeEngineInvite();
- }
- this.setUniBellFilePath();
- if (!this.data.callingBell) { // 创建铃声实例
- const bellContext = new BellContext();
- this.setData({
- callingBell: bellContext,
- });
- }
- if (!wx.$TUICallEngine) {
- wx.$TUICallEngine = TUICallEngine.createInstance({
- tim,
- sdkAppID: sdkAppID || SDKAppID,
- });
- /*
- _addTSignalingEvent 需要在 init 之前,回调才能正常触发
- tap:https://tapd.woa.com/20396022/prong/stories/view/1020396022885781069
- */
- this._addTSignalingEvent();
- try {
- await wx.$TUICallEngine.init({
- userID,
- userSig,
- });
- } catch (error) {
- tuiCallInitReady = false;
- throw new Error(error);
- }
- // 用于全局监听进入 TUICallKit 页面中绑定上当前页面的监听。
- } else {
- this._addTSignalingEvent();
- }
- console.log(`${PREFIX} init Ready!`);
- },
- // 销毁 TUICallEngine
- async destroyed() {
- if (!wx.$TUICallEngine || !tuiCallInitReady) return;
- tuiCallInitReady = false;
- this._removeTSignalingEvent();
- // 全局监听模式下,离开页面需要重新绑定全局监听,但不卸载 TUICallEngine
- if (wx.$globalCallSign) {
- // 处理异常退出
- if (this.getCallStatus() !== STATUS.IDLE) {
- await this.handleExceptionExit();
- }
- wx.$CallManagerInstance.addEngineInvite();
- } else {
- // 非全局监听模式下,离开页面需要卸载 TUICallEngine
- wx.$TUICallEngine.destroyInstance();
- wx.$TUICallEngine = null;
- }
- if (this.data.callingBell) {
- this.data.callingBell.destroyInstance();
- this.setData({
- callingBell: null,
- });
- }
- this.reset();
- console.log(`${PREFIX} destroyed OK!`);
- },
- /*
- 以下两种情况需要全部符合,则需要隐藏 tabBar
- 1.用户当前处于 tabBar 页面, isTabBar 为 true
- 2.用户没有使用了自定义 tabBar, isCustomTabBar 为 fales
- */
- handleTabBarLogic() {
- const isTabBar = isTabBarPage();
- const isCustomTabBar = tabBarConfig().custom || false;
- shouldHideTabBar = isTabBar && !isCustomTabBar;
- },
- // 检测运行时环境
- checkRunPlatform() {
- const systemInfo = wx.getSystemInfoSync();
- if (systemInfo.platform === 'devtools') {
- // 当前运行在微信开发者工具里
- wx.showModal({
- icon: 'none',
- title: '运行环境提醒',
- content: '微信开发者工具不支持原生推拉流组件(即 <live-pusher> 和 <live-player> 标签),请使用真机调试或者扫码预览。',
- showCancel: false,
- });
- }
- },
- // 运行在 uniapp 小程序需要修改铃声地址
- setUniBellFilePath() {
- // 防止用户退出再进入,在地址前重复拼接
- if (INVITER_BELL_FILEPATH.indexOf('wxcomponents') !== -1) {
- return;
- }
- // comType 用于 Vue2 的判断,wxcomponents 用于 Vue3 的判断
- if (this.dataset.comType === 'wx' || this.is.indexOf('wxcomponents') !== -1) {
- INVITER_BELL_FILEPATH = `wxcomponents/${INVITER_BELL_FILEPATH}`;
- INVITEE_BELL_FILEPATH = `wxcomponents/${INVITEE_BELL_FILEPATH}`;
- }
- },
- // 自定义铃声
- setCallingBell(filePath) {
- // 如需恢复默认铃声,filePath 传空即可
- this.setData({
- bellFilePath: filePath,
- });
- },
- // 处理用户异常退出的情况,处理了右滑退出,以及返回退出的情况。
- async handleExceptionExit() {
- // 在呼叫状态下,被叫调用 reject,主叫调用 hangup
- if (this.getCallStatus() === STATUS.CALLING) {
- if (this.isSponsor()) {
- await this.hangup();
- } else {
- await this.reject();
- }
- }
- // 在通话状态下,统一调用 hangup 接口
- if (this.getCallStatus() === STATUS.CONNECTED) {
- await this.hangup();
- }
- },
- getCallStatus() {
- return this.data.callStatus;
- },
- isSponsor() {
- return this.data.isSponsor;
- },
- },
- /**
- * 生命周期方法
- */
- lifetimes: {
- created() {
- this.reset();
- },
- attached() {
- },
- ready() {
- console.log(`${PREFIX} SDK Version: ${version}`);
- },
- async detached() {
- await this.destroyed();
- },
- error() {
- },
- },
- pageLifetimes: {
- async show() {
- if (this.data.config.sdkAppID) {
- await this.init(this.data.config);
- }
- },
- async hide() {
- if (this.getCallStatus() === STATUS.IDLE) {
- await this.destroyed();
- }
- },
- resize() {
- },
- },
- });
|