mirror of
https://github.com/TencentCloud/TIMSDK.git
synced 2026-10-21 16:56:02 +08:00
b016c6183f
Co-authored-by: mileszzhang <mileszzhang@tencent.com>
513 lines
16 KiB
JavaScript
513 lines
16 KiB
JavaScript
import TRTCCalling from './TRTCCalling/TRTCCalling.js';
|
|
|
|
|
|
const TAG_NAME = 'TUICalling';
|
|
// 组件旨在跨终端维护一个通话状态管理机,以事件发布机制驱动上层进行管理,并通过API调用进行状态变更。
|
|
// 组件设计思路将UI和状态管理分离。您可以通过修改`component`文件夹下的文件,适配您的业务场景,
|
|
// 在UI展示上,您可以通过属性的方式,将上层的用户头像,名称等数据传入组件内部,`static`下的icon和默认头像图片,
|
|
// 只是为了展示基础的效果,您需要根据业务场景进行修改。
|
|
|
|
// eslint-disable-next-line no-undef
|
|
Component({
|
|
properties: {
|
|
config: {
|
|
type: Object,
|
|
value: {
|
|
sdkAppID: 0,
|
|
userID: '',
|
|
userSig: '',
|
|
type: 1,
|
|
tim: null,
|
|
},
|
|
},
|
|
backgroundMute: {
|
|
type: Boolean,
|
|
value: false,
|
|
},
|
|
},
|
|
observers: {
|
|
|
|
},
|
|
|
|
data: {
|
|
callStatus: 'idle', // idle、calling、connection
|
|
isSponsor: false,
|
|
pusher: {}, // TRTC 本地流
|
|
playerList: [], // TRTC 远端流
|
|
remoteUsers: [], // 远程用户资料
|
|
screen: 'pusher', // 视屏通话中,显示大屏幕的流(只限1v1聊天
|
|
soundMode: 'speaker', // 声音模式 听筒/扬声器
|
|
},
|
|
|
|
methods: {
|
|
initCall() {
|
|
// 收起键盘
|
|
wx.hideKeyboard();
|
|
},
|
|
// 新的邀请回调事件
|
|
handleNewInvitationReceived(event) {
|
|
this.initCall();
|
|
console.log(`${TAG_NAME}, handleNewInvitationReceived, event${JSON.stringify(event)}`);
|
|
this.data.config.type = event.data.inviteData.callType;
|
|
this.getUserProfile([event.data.sponsor]);
|
|
this.setData({
|
|
config: this.data.config,
|
|
callStatus: 'calling',
|
|
isSponsor: false,
|
|
});
|
|
},
|
|
|
|
// 用户接听
|
|
handleUserAccept(event) {
|
|
console.log(`${TAG_NAME}, handleUserAccept, event${JSON.stringify(event)}`);
|
|
this.setData({
|
|
callStatus: 'connection',
|
|
});
|
|
},
|
|
|
|
// 远端用户进入通话
|
|
handleUserEnter(res) {
|
|
this.setData({
|
|
playerList: res.playerList,
|
|
});
|
|
},
|
|
// 远端用户离开通话
|
|
handleUserLeave(res) {
|
|
this.setData({
|
|
playerList: res.data.playerList,
|
|
});
|
|
},
|
|
// 用户数据更新
|
|
handleUserUpdate(res) {
|
|
console.log(`${TAG_NAME}, handleUserUpdate, res`);
|
|
console.log(res);
|
|
this.handleNetStatus(res.data);
|
|
this.setData({
|
|
pusher: res.data.pusher,
|
|
playerList: res.data.playerList,
|
|
});
|
|
},
|
|
// 判断网络状态
|
|
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) {
|
|
console.log(`${TAG_NAME}, handleInviteeReject, event${JSON.stringify(event)}`);
|
|
wx.showToast({
|
|
title: `${this.handleCallingUser([event.data.invitee])}已拒绝`,
|
|
});
|
|
},
|
|
// 用户不在线
|
|
handleNoResponse(event) {
|
|
console.log(`${TAG_NAME}, handleNoResponse, event${JSON.stringify(event)}`);
|
|
wx.showToast({
|
|
title: `${this.handleCallingUser(event.data.timeoutUserList)}不在线`,
|
|
});
|
|
},
|
|
// 用户忙线
|
|
handleLineBusy(event) {
|
|
console.log(`${TAG_NAME}, handleLineBusy, event${JSON.stringify(event)}`);
|
|
wx.showToast({
|
|
title: `${this.handleCallingUser([event.data.invitee])}忙线中`,
|
|
});
|
|
},
|
|
// 用户取消
|
|
handleCallingCancel(event) {
|
|
console.log(`${TAG_NAME}, handleCallingCancel, event${JSON.stringify(event)}`);
|
|
wx.showToast({
|
|
title: `${this.handleCallingUser([event.data.invitee])}取消通话`,
|
|
});
|
|
},
|
|
// 通话超时未应答
|
|
handleCallingTimeout(event) {
|
|
console.log(`${TAG_NAME}, handleCallingTimeout, event${JSON.stringify(event)}`);
|
|
wx.showToast({
|
|
title: `${this.handleCallingUser(event.data.timeoutUserList)}超时无应答`,
|
|
});
|
|
},
|
|
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)),
|
|
});
|
|
console.log(`${TAG_NAME}, handleCallingUser, userProfile`, userProfile);
|
|
let nick = '';
|
|
for (let i = 0; i < userProfile.length; i++) {
|
|
nick += `${userProfile[i].nick}、`;
|
|
}
|
|
return nick.slice(0, -1);
|
|
},
|
|
// 通话结束
|
|
handleCallingEnd(event) {
|
|
console.log(`${TAG_NAME}, handleCallingEnd`);
|
|
console.log(event);
|
|
this.reset();
|
|
if (event.data.message) {
|
|
this.triggerEvent('sendMessage', {
|
|
message: event.data.message,
|
|
});
|
|
}
|
|
wx.showToast({
|
|
title: '通话结束',
|
|
duration: 800,
|
|
});
|
|
},
|
|
|
|
// SDK Ready 回调
|
|
handleSDKReady() {
|
|
// 呼叫需在sdk ready之后
|
|
},
|
|
// 被踢下线
|
|
handleKickedOut() {
|
|
wx.showToast({
|
|
title: '您已被踢下线',
|
|
});
|
|
},
|
|
// 切换通话模式
|
|
handleCallMode(event) {
|
|
this.data.config.type = event.data.type;
|
|
this.setData({
|
|
config: this.data.config,
|
|
});
|
|
this.triggerEvent('sendMessage', {
|
|
message: event.data.message,
|
|
});
|
|
},
|
|
// 增加 tsignaling 事件监听
|
|
_addTSignalingEvent() {
|
|
// 被邀请通话
|
|
wx.$TRTCCalling.on(wx.$TRTCCalling.EVENT.INVITED, this.handleNewInvitationReceived, this);
|
|
// 用户接听
|
|
wx.$TRTCCalling.on(wx.$TRTCCalling.EVENT.USER_ACCEPT, this.handleUserAccept, this);
|
|
// 用户进入通话
|
|
wx.$TRTCCalling.on(wx.$TRTCCalling.EVENT.USER_ENTER, this.handleUserEnter, this);
|
|
// 用户离开通话
|
|
wx.$TRTCCalling.on(wx.$TRTCCalling.EVENT.USER_LEAVE, this.handleUserLeave, this);
|
|
// 用户离开通话
|
|
wx.$TRTCCalling.on(wx.$TRTCCalling.EVENT.USER_UPDATE, this.handleUserUpdate, this);
|
|
// 用户拒绝通话
|
|
wx.$TRTCCalling.on(wx.$TRTCCalling.EVENT.REJECT, this.handleInviteeReject, this);
|
|
// 用户无响应
|
|
wx.$TRTCCalling.on(wx.$TRTCCalling.EVENT.NO_RESP, this.handleNoResponse, this);
|
|
// 用户忙线
|
|
wx.$TRTCCalling.on(wx.$TRTCCalling.EVENT.LINE_BUSY, this.handleLineBusy, this);
|
|
// 通话被取消
|
|
wx.$TRTCCalling.on(wx.$TRTCCalling.EVENT.CALLING_CANCEL, this.handleCallingCancel, this);
|
|
// 通话超时未应答
|
|
wx.$TRTCCalling.on(wx.$TRTCCalling.EVENT.CALLING_TIMEOUT, this.handleCallingTimeout, this);
|
|
// 通话结束
|
|
wx.$TRTCCalling.on(wx.$TRTCCalling.EVENT.CALL_END, this.handleCallingEnd, this);
|
|
// SDK Ready 回调
|
|
wx.$TRTCCalling.on(wx.$TRTCCalling.EVENT.SDK_READY, this.handleSDKReady, this);
|
|
// 被踢下线
|
|
wx.$TRTCCalling.on(wx.$TRTCCalling.EVENT.KICKED_OUT, this.handleKickedOut, this);
|
|
// 切换通话模式
|
|
wx.$TRTCCalling.on(wx.$TRTCCalling.EVENT.CALL_MODE, this.handleCallMode, this);
|
|
},
|
|
// 取消 tsignaling 事件监听
|
|
_removeTSignalingEvent() {
|
|
// 被邀请通话
|
|
wx.$TRTCCalling.off(wx.$TRTCCalling.EVENT.INVITED, this.handleNewInvitationReceived);
|
|
// 用户接听
|
|
wx.$TRTCCalling.off(wx.$TRTCCalling.EVENT.USER_ACCEPT, this.handleUserAccept);
|
|
// 用户进入通话
|
|
wx.$TRTCCalling.off(wx.$TRTCCalling.EVENT.USER_ENTER, this.handleUserEnter);
|
|
// 用户离开通话
|
|
wx.$TRTCCalling.off(wx.$TRTCCalling.EVENT.USER_LEAVE, this.handleUserLeave);
|
|
// 用户离开通话
|
|
wx.$TRTCCalling.off(wx.$TRTCCalling.EVENT.USER_UPDATE, this.handleUserUpdate);
|
|
// 用户拒绝通话
|
|
wx.$TRTCCalling.off(wx.$TRTCCalling.EVENT.REJECT, this.handleInviteeReject);
|
|
// 用户无响应
|
|
wx.$TRTCCalling.off(wx.$TRTCCalling.EVENT.NO_RESP, this.handleNoResponse);
|
|
// 用户忙线
|
|
wx.$TRTCCalling.off(wx.$TRTCCalling.EVENT.LINE_BUSY, this.handleLineBusy);
|
|
// 通话被取消
|
|
wx.$TRTCCalling.off(wx.$TRTCCalling.EVENT.CALLING_CANCEL, this.handleCallingCancel);
|
|
// 通话超时未应答
|
|
wx.$TRTCCalling.off(wx.$TRTCCalling.EVENT.CALLING_TIMEOUT, this.handleCallingTimeout);
|
|
// 通话结束
|
|
wx.$TRTCCalling.off(wx.$TRTCCalling.EVENT.CALL_END, this.handleCallingEnd);
|
|
// SDK Ready 回调
|
|
wx.$TRTCCalling.off(wx.$TRTCCalling.EVENT.SDK_READY, this.handleSDKReady);
|
|
// 被踢下线
|
|
wx.$TRTCCalling.off(wx.$TRTCCalling.EVENT.KICKED_OUT, this.handleKickedOut);
|
|
// 切换通话模式
|
|
wx.$TRTCCalling.off(wx.$TRTCCalling.EVENT.CALL_MODE, this.handleCallMode);
|
|
},
|
|
/**
|
|
* C2C邀请通话,被邀请方会收到的回调
|
|
* 如果当前处于通话中,可以调用该函数以邀请第三方进入通话
|
|
*
|
|
* @param userID 被邀请方
|
|
* @param type 0-为之, 1-语音通话,2-视频通话
|
|
*/
|
|
async call(params) {
|
|
this.initCall();
|
|
wx.$TRTCCalling.call({ userID: params.userID, type: params.type }).then((res) => {
|
|
this.data.config.type = params.type;
|
|
this.getUserProfile([params.userID]);
|
|
this.setData({
|
|
pusher: res.pusher,
|
|
config: this.data.config,
|
|
callStatus: 'calling',
|
|
isSponsor: true,
|
|
});
|
|
this.triggerEvent('sendMessage', {
|
|
message: res.data.message,
|
|
});
|
|
});
|
|
},
|
|
/**
|
|
* IM群组邀请通话,被邀请方会收到的回调
|
|
* 如果当前处于通话中,可以继续调用该函数继续邀请他人进入通话,同时正在通话的用户会收到的回调
|
|
*
|
|
* @param userIDList 邀请列表
|
|
* @param type 1-语音通话,2-视频通话
|
|
* @param groupID IM群组ID
|
|
*/
|
|
async groupCall(params) {
|
|
this.initCall();
|
|
wx.$TRTCCalling.groupCall({ userIDList: params.userIDList, type: params.type, groupID: params.groupID }).then((res) => {
|
|
this.data.config.type = params.type;
|
|
this.getUserProfile(params.userIDList);
|
|
this.setData({
|
|
pusher: res.pusher,
|
|
config: this.data.config,
|
|
callStatus: 'calling',
|
|
isSponsor: true,
|
|
});
|
|
});
|
|
},
|
|
/**
|
|
* 当您作为被邀请方收到 {@link TRTCCallingDelegate#onInvited } 的回调时,可以调用该函数接听来电
|
|
*/
|
|
async accept() {
|
|
wx.$TRTCCalling.accept().then((res) => {
|
|
this.setData({
|
|
pusher: res.pusher,
|
|
callStatus: 'connection',
|
|
});
|
|
this.triggerEvent('sendMessage', {
|
|
message: res.message,
|
|
});
|
|
});
|
|
},
|
|
/**
|
|
* 当您作为被邀请方收到的回调时,可以调用该函数拒绝来电
|
|
*/
|
|
async reject() {
|
|
console.log(`${TAG_NAME}, reject`);
|
|
wx.$TRTCCalling.reject().then((res) => {
|
|
this.triggerEvent('sendMessage', {
|
|
message: res.data.message,
|
|
});
|
|
});
|
|
this.reset();
|
|
},
|
|
|
|
// xml层,是否开启扬声器
|
|
toggleSoundMode() {
|
|
this.setData({
|
|
soundMode: wx.$TRTCCalling._toggleSoundMode(),
|
|
});
|
|
},
|
|
|
|
// xml层,挂断
|
|
_hangUp() {
|
|
console.log(`${TAG_NAME}, hangup`);
|
|
wx.$TRTCCalling.hangup();
|
|
this.reset();
|
|
},
|
|
|
|
// 切换大小屏 (仅支持1v1聊天)
|
|
toggleViewSize(event) {
|
|
this.setData({
|
|
screen: wx.$TRTCCalling._toggleViewSize(event),
|
|
});
|
|
},
|
|
// 数据重置
|
|
reset() {
|
|
this.setData({
|
|
callStatus: 'idle',
|
|
isSponsor: false,
|
|
pusher: {}, // TRTC 本地流
|
|
playerList: [], // TRTC 远端流
|
|
});
|
|
},
|
|
// 呼叫中的事件处理
|
|
handleCallingEvent(data) {
|
|
const { name } = data.detail;
|
|
switch (name) {
|
|
case 'accept':
|
|
this.accept();
|
|
break;
|
|
case 'hangup':
|
|
this._hangUp();
|
|
break;
|
|
case 'reject':
|
|
this.reject();
|
|
break;
|
|
case 'toggleSwitchCamera':
|
|
wx.$TRTCCalling.switchCamera();
|
|
break;
|
|
case 'switchAudioCall':
|
|
wx.$TRTCCalling.switchAudioCall().then((res) => {
|
|
this.data.config.type = wx.$TRTCCalling.CALL_TYPE.AUDIO;
|
|
this.setData({
|
|
config: this.data.config,
|
|
});
|
|
this.triggerEvent('sendMessage', {
|
|
message: res.data.message,
|
|
});
|
|
});
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
},
|
|
// 通话中的事件处理
|
|
handleConnectedEvent(data) {
|
|
console.log(`${TAG_NAME}, handleVideoEvent--`, data);
|
|
const { name, event } = data.detail;
|
|
switch (name) {
|
|
case 'toggleViewSize':
|
|
this.toggleViewSize(event);
|
|
break;
|
|
case 'pusherNetStatus':
|
|
wx.$TRTCCalling._pusherNetStatus(event);
|
|
break;
|
|
case 'playNetStatus':
|
|
wx.$TRTCCalling._playNetStatus(event);
|
|
break;
|
|
case 'pusherStateChangeHandler':
|
|
wx.$TRTCCalling._pusherStateChangeHandler(event);
|
|
break;
|
|
case 'pusherAudioVolumeNotify':
|
|
wx.$TRTCCalling._pusherAudioVolumeNotify(event);
|
|
break;
|
|
case 'playerStateChange':
|
|
wx.$TRTCCalling._playerStateChange(event);
|
|
break;
|
|
case 'playerAudioVolumeNotify':
|
|
wx.$TRTCCalling._playerAudioVolumeNotify(event);
|
|
break;
|
|
case 'pusherAudioHandler':
|
|
wx.$TRTCCalling._pusherAudioHandler(event);
|
|
break;
|
|
case 'hangup':
|
|
this._hangUp();
|
|
break;
|
|
case 'toggleSoundMode':
|
|
this.toggleSoundMode();
|
|
break;
|
|
case 'pusherVideoHandler':
|
|
wx.$TRTCCalling._pusherVideoHandler(event);
|
|
break;
|
|
case 'toggleSwitchCamera':
|
|
wx.$TRTCCalling.switchCamera(event);
|
|
break;
|
|
case 'switchAudioCall':
|
|
wx.$TRTCCalling.switchAudioCall().then((res) => {
|
|
this.data.config.type = 1;
|
|
this.setData({
|
|
config: this.data.config,
|
|
});
|
|
this.triggerEvent('sendMessage', {
|
|
message: res.data.message,
|
|
});
|
|
});
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
},
|
|
|
|
// 获取用户资料
|
|
async getUserProfile(userList) {
|
|
const imResponse = await this.getTim().getUserProfile({ userIDList: userList });
|
|
this.setData({
|
|
remoteUsers: imResponse.data,
|
|
});
|
|
},
|
|
// 获取 tim 实例
|
|
getTim() {
|
|
return wx.$TRTCCalling.getTim();
|
|
},
|
|
// 初始化TRTCCalling
|
|
async init() {
|
|
try {
|
|
const res = await wx.$TRTCCalling.login({
|
|
userID: this.data.config.userID,
|
|
userSig: this.data.config.userSig,
|
|
});
|
|
this._addTSignalingEvent();
|
|
return res;
|
|
} catch (error) {
|
|
throw new Error('TRTCCalling login failure', error);
|
|
}
|
|
},
|
|
// 销毁 TRTCCalling
|
|
destroyed() {
|
|
this._removeTSignalingEvent();
|
|
if (this.data.config.tim) {
|
|
wx.$TRTCCalling.destroyed();
|
|
} else {
|
|
wx.$TRTCCalling.logout();
|
|
}
|
|
},
|
|
},
|
|
|
|
/**
|
|
* 生命周期方法
|
|
*/
|
|
lifetimes: {
|
|
created() {
|
|
|
|
},
|
|
attached() {
|
|
},
|
|
ready() {
|
|
if (!wx.$TRTCCalling) {
|
|
wx.$TRTCCalling = new TRTCCalling({
|
|
sdkAppID: this.data.config.sdkAppID,
|
|
tim: this.data.config.tim,
|
|
});
|
|
}
|
|
wx.$TRTCCalling.initData();
|
|
this.reset();
|
|
},
|
|
detached() {
|
|
this.reset();
|
|
},
|
|
error() {
|
|
},
|
|
},
|
|
pageLifetimes: {
|
|
show() {
|
|
|
|
},
|
|
hide() {
|
|
},
|
|
resize() {
|
|
},
|
|
},
|
|
});
|