From 459dfb3432aa43864cfcbf3cd93d72ea8f9f1823 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=BE=B7=E5=B8=83=E7=BD=97=E7=85=9C?= <1056317718@qq.com>
Date: Tue, 31 May 2022 19:06:14 +0800
Subject: [PATCH] =?UTF-8?q?=E7=A7=81=E8=81=8A=E8=A7=86=E9=A2=91=E9=80=9A?=
=?UTF-8?q?=E8=AF=9D=E5=AF=86=E9=92=A5=E5=8D=8F=E5=95=86=E9=80=BB=E8=BE=91?=
=?UTF-8?q?=E6=9E=B6=E6=9E=84=E4=BF=AE=E6=94=B9:building=5Fconstruction:?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/Components/ChatComponent/ChatRTC.tsx | 340 ++++++++++++-----------
src/Utils/Constraints.ts | 2 +
2 files changed, 177 insertions(+), 165 deletions(-)
diff --git a/src/Components/ChatComponent/ChatRTC.tsx b/src/Components/ChatComponent/ChatRTC.tsx
index 81b6b88..c39411a 100644
--- a/src/Components/ChatComponent/ChatRTC.tsx
+++ b/src/Components/ChatComponent/ChatRTC.tsx
@@ -63,127 +63,176 @@ export class ChatRTC extends EventEmitter {
this.localStream = null;
this.remoteStream = null;
this.useSecurity = false;
- this.security = '';
+ this.security = '[]';
- this.socket.on('ON_PRIVATE_WEBRTC_OFFER', (msg) => {
- this.sender = msg.sender;
- this.receiver = this.myId;
-
- const rejectOffer = (reason: number) => {
- this.socket.send({
- type: ChatWebSocketType.CHAT_PRIVATE_WEBRTC_ANSWER,
- accept: reason,
- sender: msg.sender,
- receiver: msg.receiver,
- });
- };
-
- if (store.getState().callStatus === CALL_STATUS_FREE) {
- eventBus.emit('GET_PRIVATE_CALLED');
- this.answerAudioPrompt[0]();
- store.dispatch(setNowChattingId(msg.sender));
- const pgArr = JSON.parse(msg.security);
- this.answerModal = Modal.confirm({
- icon: msg.security ? : ,
- title: '视频通话邀请',
- content: (
-
- 用户 {msg.senderName}(id: {msg.sender})向您发出视频通话请求,是否接受?
- {pgArr.length === 3 ? (
-
-
- 注意:对方启用了私聊视频会话加密功能,接受此会话可能会导致您的CPU占用被大幅度提高,请与对方确认后选择是否接受此会话
-
- ) : (
- ''
- )}
-
- ),
- cancelText: (
- <>
-
- 拒绝接受
- >
- ),
- okText: (
- <>
-
- 同意请求
- >
- ),
- onOk: () => {
- this.useSecurity = pgArr.length === 3;
- console.log(pgArr);
-
- if (this.useSecurity) this.createAnswer(msg.sender, msg.sdp, pgArr);
- else this.createAnswer(msg.sender, msg.sdp);
- },
- onCancel: () => {
- rejectOffer(PRIVATE_WEBRTC_ANSWER_TYPE.REJECT);
- this.answerModal = null;
- this.sender = undefined;
- this.receiver = undefined;
- },
- afterClose: this.answerAudioPrompt[1],
- centered: true,
- getContainer: getMainContent,
- });
- } else rejectOffer(PRIVATE_WEBRTC_ANSWER_TYPE.BUSY);
+ this.socket.on('ON_PRIVATE_WEBRTC_REQUEST', (msg) => {
+ this.responseCall(msg);
});
- this.socket.on(
- 'ON_PRIVATE_WEBRTC_ANSWER',
- ({ accept, sdp, sender, receiver, security }) => {
- if (sender === this.sender && receiver === this.receiver) {
- this.callAudioPrompt[1]();
- if (this.offerModal) {
- this.offerModal.destroy();
- this.offerModal = null;
- }
- if (accept === PRIVATE_WEBRTC_ANSWER_TYPE.ACCEPT) {
- this.receiveAnswer(sdp, security);
- } else {
- switch (accept) {
- case PRIVATE_WEBRTC_ANSWER_TYPE.BUSY:
- globalMessage.error({
- content: '对方正在通话中',
- duration: 1.5,
- });
- break;
- case PRIVATE_WEBRTC_ANSWER_TYPE.NO_USER:
- globalMessage.error({
- content: '呼叫的用户不存在',
- duration: 1.5,
- });
- break;
- case PRIVATE_WEBRTC_ANSWER_TYPE.REJECT:
- globalMessage.error({
- content: '对方拒绝了您的通话邀请',
- duration: 1.5,
- });
- break;
- }
- this.onEnded();
+ this.socket.on('ON_PRIVATE_WEBRTC_RESPONSE', ({ accept, sender, receiver, security }) => {
+ if (sender === this.sender && receiver === this.receiver) {
+ this.callAudioPrompt[1]();
+ if (this.offerModal) {
+ this.offerModal.destroy();
+ this.offerModal = null;
+ }
+ if (accept === PRIVATE_WEBRTC_ANSWER_TYPE.ACCEPT) {
+ this.createOffer(security);
+ } else {
+ switch (accept) {
+ case PRIVATE_WEBRTC_ANSWER_TYPE.BUSY:
+ globalMessage.error({
+ content: '对方正在通话中',
+ duration: 1.5,
+ });
+ break;
+ case PRIVATE_WEBRTC_ANSWER_TYPE.NO_USER:
+ globalMessage.error({
+ content: '呼叫的用户不存在',
+ duration: 1.5,
+ });
+ break;
+ case PRIVATE_WEBRTC_ANSWER_TYPE.REJECT:
+ globalMessage.error({
+ content: '对方拒绝了您的通话邀请',
+ duration: 1.5,
+ });
+ break;
}
+ this.onEnded();
}
}
- );
+ });
- this.socket.on('ON_PRIVATE_WEBRTC_CANDIDATE', this.handleCandidate.bind(this));
+ this.socket.on('ON_PRIVATE_WEBRTC_OFFER', (msg) => {
+ if (msg.sender === this.sender && msg.receiver === this.receiver)
+ this.createAnswer(msg.sdp);
+ });
+
+ this.socket.on('ON_PRIVATE_WEBRTC_CANDIDATE', (msg) => {
+ if (msg.sender === this.sender && msg.receiver === this.receiver) {
+ this.handleCandidate(msg);
+ }
+ });
this.socket.on('ON_PRIVATE_WEBRTC_DISCONNECT', (msg) => {
this.onHangUp(msg);
});
}
- async createOffer(targetId: number, myName: string, offerModal: any) {
+ async callRemote(targetId: number, myName: string, offerModal: any) {
this.useSecurity = localStorage.getItem('securityPrivateWebrtc') === 'true';
- this.peer = this.buildPeer();
this.callAudioPrompt[0]();
store.dispatch(setCallStatus(CALL_STATUS_OFFERING));
store.dispatch(setNowWebrtcFriendId(targetId));
this.sender = this.myId;
this.receiver = targetId;
+ let pgArr: Array = [];
+ if (this.useSecurity) {
+ pgArr = await eWindow.ipc.invoke('DIFFIE_HELLMAN');
+ }
+ this.socket.send({
+ type: ChatWebSocketType.CHAT_PRIVATE_WEBRTC_REQUEST,
+ sender: this.myId,
+ senderName: myName,
+ security: JSON.stringify(pgArr),
+ receiver: targetId,
+ });
+ this.offerModal = offerModal;
+ }
+
+ responseCall(msg: any) {
+ this.sender = msg.sender;
+ this.receiver = this.myId;
+
+ const rejectOffer = (reason: number) => {
+ this.socket.send({
+ type: ChatWebSocketType.CHAT_PRIVATE_WEBRTC_RESPONSE,
+ security: '',
+ accept: reason,
+ sender: msg.sender,
+ receiver: msg.receiver,
+ });
+ };
+
+ if (store.getState().callStatus === CALL_STATUS_FREE) {
+ eventBus.emit('GET_PRIVATE_CALLED');
+ this.answerAudioPrompt[0]();
+ store.dispatch(setNowChattingId(msg.sender));
+ const pgArr = JSON.parse(msg.security);
+ const useSecurity = pgArr.length === 3;
+ this.answerModal = Modal.confirm({
+ icon: useSecurity ? : ,
+ title: '视频通话邀请',
+ content: (
+
+ 用户 {msg.senderName}(id: {msg.sender})向您发出视频通话请求,是否接受?
+ {useSecurity ? (
+
+
+ 注意:对方启用了私聊视频会话加密功能,接受此会话可能会导致您的CPU占用被大幅度提高,请与对方确认后选择是否接受此会话
+
+ ) : (
+ ''
+ )}
+
+ ),
+ cancelText: (
+ <>
+
+ 拒绝接受
+ >
+ ),
+ okText: (
+ <>
+
+ 同意请求
+ >
+ ),
+ onOk: () => {
+ this.useSecurity = useSecurity;
+ if (useSecurity) {
+ eWindow.ipc
+ .invoke('DIFFIE_HELLMAN', pgArr[0], pgArr[1], pgArr[2])
+ .then((serverArr) => {
+ const [privateKey, publicKey] = serverArr;
+ this.security = privateKey;
+ this.socket.send({
+ type: ChatWebSocketType.CHAT_PRIVATE_WEBRTC_RESPONSE,
+ accept: PRIVATE_WEBRTC_ANSWER_TYPE.ACCEPT,
+ sender: this.sender,
+ receiver: this.receiver,
+ security: publicKey,
+ });
+ });
+ } else {
+ this.socket.send({
+ type: ChatWebSocketType.CHAT_PRIVATE_WEBRTC_RESPONSE,
+ accept: PRIVATE_WEBRTC_ANSWER_TYPE.ACCEPT,
+ sender: this.sender,
+ receiver: this.receiver,
+ security: '[]',
+ });
+ }
+
+ store.dispatch(setCallStatus(CALL_STATUS_ANSWERING));
+ store.dispatch(setNowWebrtcFriendId(msg.sender));
+ },
+ onCancel: () => {
+ rejectOffer(PRIVATE_WEBRTC_ANSWER_TYPE.REJECT);
+ this.answerModal = null;
+ this.sender = undefined;
+ this.receiver = undefined;
+ },
+ afterClose: this.answerAudioPrompt[1],
+ centered: true,
+ getContainer: getMainContent,
+ });
+ } else rejectOffer(PRIVATE_WEBRTC_ANSWER_TYPE.BUSY);
+ }
+
+ async createOffer(publicKey: string) {
+ this.peer = this.buildPeer();
this.localStream = new MediaStream();
this.localStream.addTrack(
(await getDeviceStream(DEVICE_TYPE.VIDEO_DEVICE)).getVideoTracks()[0]
@@ -195,9 +244,13 @@ export class ChatRTC extends EventEmitter {
this.peer.addTrack(track, this.localStream);
}
- let pgArr: Array = [];
- if (this.useSecurity) {
- pgArr = await eWindow.ipc.invoke('DIFFIE_HELLMAN');
+ // NOTE: 加密
+ if (publicKey) {
+ const privateKey = await eWindow.ipc.invoke('DIFFIE_HELLMAN', publicKey);
+ this.security = privateKey;
+ this.peer.getSenders().forEach((sender) => {
+ setupSenderTransform(sender, privateKey);
+ });
} else if (senderCodecs) {
this.peer
.getTransceivers()
@@ -215,19 +268,14 @@ export class ChatRTC extends EventEmitter {
this.socket.send({
type: ChatWebSocketType.CHAT_PRIVATE_WEBRTC_OFFER,
sdp: sdp.sdp,
- sender: this.myId,
- senderName: myName,
- receiver: targetId,
- security: JSON.stringify(pgArr),
+ sender: this.sender,
+ receiver: this.receiver,
});
});
- this.offerModal = offerModal;
}
- async createAnswer(sender: number, remoteSdp: any, pgArr?: Array) {
+ async createAnswer(remoteSdp: any) {
this.peer = this.buildPeer();
- store.dispatch(setCallStatus(CALL_STATUS_ANSWERING));
- store.dispatch(setNowWebrtcFriendId(sender));
this.peer.setRemoteDescription(
new RTCSessionDescription({
@@ -251,34 +299,10 @@ export class ChatRTC extends EventEmitter {
}
// NOTE: 加密
- let privateKey: string, publicKey: string;
- if (pgArr) {
- const serverArr = await eWindow.ipc.invoke(
- 'DIFFIE_HELLMAN',
- pgArr[0],
- pgArr[1],
- pgArr[2]
- );
- privateKey = serverArr[0];
- publicKey = serverArr[1];
- this.security = privateKey;
+ if (this.useSecurity) {
this.peer.getSenders().forEach((sender) => {
- setupSenderTransform(sender, privateKey);
+ setupSenderTransform(sender, this.security);
});
-
- this.remoteStream = new MediaStream();
- // NOTE: 解密
- if (this.useSecurity) {
- this.peer.getReceivers().forEach((receiver) => {
- setupReceiverTransform(receiver, privateKey);
- this.remoteStream?.addTrack(receiver.track);
- });
- } else if (receiverCodecs)
- this.peer
- .getTransceivers()
- .find((t) => t.receiver.track.kind === 'video')
- ?.setCodecPreferences(receiverCodecs);
- this.emit('REMOTE_STREAM_READY', this.remoteStream);
} else if (senderCodecs) {
this.peer
.getTransceivers()
@@ -297,26 +321,15 @@ export class ChatRTC extends EventEmitter {
this.peer.setLocalDescription(sdp);
this.socket.send({
type: ChatWebSocketType.CHAT_PRIVATE_WEBRTC_ANSWER,
- accept: PRIVATE_WEBRTC_ANSWER_TYPE.ACCEPT,
sdp: sdp.sdp,
sender: this.sender,
receiver: this.receiver,
- security: this.useSecurity ? publicKey : '',
});
store.dispatch(setCallStatus(CALL_STATUS_CALLING));
});
}
- async receiveAnswer(remoteSdp: any, publicKey: string) {
- // NOTE: 加密
- if (this.useSecurity) {
- const privateKey = await eWindow.ipc.invoke('DIFFIE_HELLMAN', publicKey);
- this.security = privateKey;
- this.peer.getSenders().forEach((sender) => {
- setupSenderTransform(sender, privateKey);
- });
- }
-
+ async receiveAnswer(remoteSdp: any) {
this.peer.setRemoteDescription(
new RTCSessionDescription({
sdp: remoteSdp,
@@ -391,19 +404,17 @@ export class ChatRTC extends EventEmitter {
}
};
peer.ontrack = (evt) => {
- if (this.myId === this.sender) {
- // NOTE: 解密
- if (this.useSecurity) setupReceiverTransform(evt.receiver, this.security);
- else if (receiverCodecs)
- peer.getTransceivers()
- .find((t) => t.receiver.track.kind === 'video')
- ?.setCodecPreferences(receiverCodecs);
+ // NOTE: 解密
+ if (this.useSecurity) setupReceiverTransform(evt.receiver, this.security);
+ else if (receiverCodecs)
+ peer.getTransceivers()
+ .find((t) => t.receiver.track.kind === 'video')
+ ?.setCodecPreferences(receiverCodecs);
- this.remoteStream = this.remoteStream || new MediaStream();
- this.remoteStream.addTrack(evt.track);
- if (this.remoteStream.getTracks().length === 2)
- this.emit('REMOTE_STREAM_READY', this.remoteStream);
- }
+ this.remoteStream = this.remoteStream || new MediaStream();
+ this.remoteStream.addTrack(evt.track);
+ if (this.remoteStream.getTracks().length === 2)
+ this.emit('REMOTE_STREAM_READY', this.remoteStream);
};
// NOTE: 断连检测
@@ -427,12 +438,11 @@ export class ChatRTC extends EventEmitter {
this.sender = undefined;
this.receiver = undefined;
this.useSecurity = false;
- this.security = '';
+ this.security = '[]';
store.dispatch(setNowWebrtcFriendId(null));
this.localStream = null;
this.remoteStream = null;
if (this.peer) this.peer.close();
- // this.peer = undefined;
store.dispatch(setCallStatus(CALL_STATUS_FREE));
}
}
diff --git a/src/Utils/Constraints.ts b/src/Utils/Constraints.ts
index 5a5a518..936bb3f 100644
--- a/src/Utils/Constraints.ts
+++ b/src/Utils/Constraints.ts
@@ -36,6 +36,8 @@ export enum ChatWebSocketType {
CHAT_PRIVATE_WEBRTC_ANSWER, // 响应视频聊天请求 ANSWER
CHAT_PRIVATE_WEBRTC_CANDIDATE, // 视频聊天 ICE 候选者
CHAT_PRIVATE_WEBRTC_DISCONNECT, // 断开视频聊天
+ CHAT_PRIVATE_WEBRTC_REQUEST, // 发送视频通话请求
+ CHAT_PRIVATE_WEBRTC_RESPONSE, // 响应视频通话请求
}
/**