Browse Source

feat: optimize the video and audio call

feat_video_fine
konenet 4 years ago
parent
commit
d6bc54cb13
  1. 6
      README.md
  2. 31
      src/chat/Panel.jsx
  3. 55
      src/chat/panel/right/component/ChatAudioOline.jsx
  4. 50
      src/chat/panel/right/component/ChatVideoOline.jsx
  5. 63
      src/chat/panel/right/index.jsx

6
README.md

@ -70,3 +70,9 @@ https://github.com/kone-net/go-chat-web @@ -70,3 +70,9 @@ https://github.com/kone-net/go-chat-web
* 屏幕共享
![screen-share](/public/screenshot/screen-share.png)
## 分支说明
one-file分支:
该分支是所有逻辑都在一个文件实现,包括语音,文字,图片,视频消息,视频通话,语音电话,屏幕共享。
main分支:
是将各个部分进行拆分。将Panel拆分成,左、中、右。又将右边的发送文件,图片,文件拆分成更小的组件。

31
src/chat/Panel.jsx

@ -80,7 +80,6 @@ class Panel extends React.Component { @@ -80,7 +80,6 @@ class Panel extends React.Component {
height: 0,
width: 0
},
rtcType: 'answer',
}
}
@ -191,11 +190,10 @@ class Panel extends React.Component { @@ -191,11 +190,10 @@ class Panel extends React.Component {
* @param {候选人信息} e
*/
peer.onicecandidate = (e) => {
console.log(this.state.rtcType + '_ice', e)
if (e.candidate) {
// rtcTypeansweroffer
let candidate = {
type: this.state.rtcType + '_ice',
type: 'answer_ice',
iceCandidate: e.candidate
}
let message = {
@ -212,10 +210,9 @@ class Panel extends React.Component { @@ -212,10 +210,9 @@ class Panel extends React.Component {
* @param {包含语音视频流} e
*/
peer.ontrack = (e) => {
console.log(e)
if (e && e.streams) {
if (this.state.onlineType === 1) {
let remoteVideo = document.getElementById("remoteVideo");
let remoteVideo = document.getElementById("remoteVideoReceiver");
remoteVideo.srcObject = e.streams[0];
} else {
let remoteAudio = document.getElementById("audioPhone");
@ -231,10 +228,10 @@ class Panel extends React.Component { @@ -231,10 +228,10 @@ class Panel extends React.Component {
*/
dealWebRtcMessage = (messagePB) => {
const { type, sdp, iceCandidate } = JSON.parse(messagePB.content);
console.log(type)
if (type === "answer") {
const offerSdp = new RTCSessionDescription({ type, sdp });
this.props.peer.localPeer.setRemoteDescription(offerSdp)
const answerSdp = new RTCSessionDescription({ type, sdp });
this.props.peer.localPeer.setRemoteDescription(answerSdp)
} else if (type === "answer_ice") {
this.props.peer.localPeer.addIceCandidate(iceCandidate)
} else if (type === "offer_ice") {
@ -247,7 +244,7 @@ class Panel extends React.Component { @@ -247,7 +244,7 @@ class Panel extends React.Component {
let video = false;
if (messagePB.contentType === Constant.VIDEO_ONLINE) {
preview = document.getElementById("preview1");
preview = document.getElementById("localVideoReceiver");
video = true
this.setState({
onlineType: 1,
@ -368,9 +365,9 @@ class Panel extends React.Component { @@ -368,9 +365,9 @@ class Panel extends React.Component {
isRecord: false
})
let preview1 = document.getElementById("preview1");
if (preview1 && preview1.srcObject && preview1.srcObject.getTracks()) {
preview1.srcObject.getTracks().forEach((track) => track.stop());
let localVideoReceiver = document.getElementById("localVideoReceiver");
if (localVideoReceiver && localVideoReceiver.srcObject && localVideoReceiver.srcObject.getTracks()) {
localVideoReceiver.srcObject.getTracks().forEach((track) => track.stop());
}
let preview = document.getElementById("preview");
@ -419,7 +416,11 @@ class Panel extends React.Component { @@ -419,7 +416,11 @@ class Panel extends React.Component {
</Col>
<Col offset={1} span={16}>
<Right history={this.props.history} />
<Right
history={this.props.history}
sendMessage={this.sendMessage}
checkMediaPermisssion={this.checkMediaPermisssion}
/>
</Col>
</Row>
@ -434,8 +435,8 @@ class Panel extends React.Component { @@ -434,8 +435,8 @@ class Panel extends React.Component {
/>
</Tooltip>
<br />
<video id="preview1" width="700px" height="auto" autoPlay muted controls />
<video id="remoteVideo" width="700px" height="auto" autoPlay muted controls />
<video id="localVideoReceiver" width="700px" height="auto" autoPlay muted controls />
<video id="remoteVideoReceiver" width="700px" height="auto" autoPlay muted controls />
<img id="receiver" width={this.state.currentScreen.width} height="auto" alt="" />
<canvas id="canvas" width={this.state.currentScreen.width} height={this.state.currentScreen.height} />

55
src/chat/panel/right/component/ChatAudioOline.jsx

@ -19,7 +19,7 @@ class ChatAudioOline extends React.Component { @@ -19,7 +19,7 @@ class ChatAudioOline extends React.Component {
constructor(props) {
super(props)
this.state = {
mediaPanelDrawerVisible: false,
}
}
@ -40,25 +40,19 @@ class ChatAudioOline extends React.Component { @@ -40,25 +40,19 @@ class ChatAudioOline extends React.Component {
}
this.webrtcConnection();
console.log(this.props.peer)
this.setState({
onlineType: 2,
rtcType: 'offer'
})
navigator.mediaDevices
.getUserMedia({
audio: true,
video: false,
}).then((stream) => {
stream.getTracks().forEach(track => {
this.props.peer.localPeer.addTrack(track, stream);
localPeer.addTrack(track, stream);
});
// offer
this.props.peer.localPeer.createOffer()
localPeer.createOffer()
.then(offer => {
this.props.peer.localPeer.setLocalDescription(offer);
localPeer.setLocalDescription(offer);
let data = {
contentType: Constant.AUDIO_ONLINE, //
content: JSON.stringify(offer),
@ -77,14 +71,12 @@ class ChatAudioOline extends React.Component { @@ -77,14 +71,12 @@ class ChatAudioOline extends React.Component {
* webrtc 绑定事件
*/
webrtcConnection = () => {
/**
* 对等方收到ice信息后通过调用 addIceCandidate 将接收的候选者信息传递给浏览器的ICE代理
* @param {候选人信息} e
*/
localPeer.onicecandidate = (e) => {
console.log(e)
localPeer.onicecandidate = (e) => {
if (e.candidate) {
// rtcTypeansweroffer
let candidate = {
@ -104,29 +96,30 @@ class ChatAudioOline extends React.Component { @@ -104,29 +96,30 @@ class ChatAudioOline extends React.Component {
* 当连接成功后从里面获取语音视频流
* @param {包含语音视频流} e
*/
localPeer.ontrack = (e) => {
localPeer.ontrack = (e) => {
if (e && e.streams) {
if (this.state.onlineType === 1) {
let remoteVideo = document.getElementById("remoteVideo");
remoteVideo.srcObject = e.streams[0];
} else {
let remoteAudio = document.getElementById("audioPhone");
remoteAudio.srcObject = e.streams[0];
}
let remoteAudio = document.getElementById("remoteAudioPhone");
remoteAudio.srcObject = e.streams[0];
}
};
}
/**
* 停止视频电话,屏幕共享
* 停止语音电话
*/
stopVideoOnline = () => {
let audioPhone = document.getElementById("audioPhone");
stopAudioOnline = () => {
let audioPhone = document.getElementById("remoteAudioPhone");
if (audioPhone && audioPhone.srcObject && audioPhone.srcObject.getTracks()) {
audioPhone.srcObject.getTracks().forEach((track) => track.stop());
}
}
mediaPanelDrawerOnClose = () => {
this.setState({
mediaPanelDrawerVisible: false
})
}
render() {
const { chooseUser } = this.props;
return (
@ -141,18 +134,24 @@ class ChatAudioOline extends React.Component { @@ -141,18 +134,24 @@ class ChatAudioOline extends React.Component {
/>
</Tooltip>
<Drawer width='820px' forceRender={true} title="媒体面板" placement="right" onClose={this.mediaPanelDrawerOnClose} visible={this.state.mediaPanelDrawerVisible}>
<Drawer width='420px'
forceRender={true}
title="媒体面板"
placement="right"
onClose={this.mediaPanelDrawerOnClose}
visible={this.state.mediaPanelDrawerVisible}
>
<Tooltip title="结束视频语音">
<Button
shape="circle"
onClick={this.stopVideoOnline}
onClick={this.stopAudioOnline}
style={{ marginRight: 10, float: 'right' }}
icon={<PoweroffOutlined style={{ color: 'red' }} />}
/>
</Tooltip>
<br />
<audio id="audioPhone" autoPlay controls />
<audio id="remoteAudioPhone" autoPlay controls />
</Drawer>
</>
);

50
src/chat/panel/right/component/ChatVideoOline.jsx

@ -19,17 +19,25 @@ class ChatVideoOline extends React.Component { @@ -19,17 +19,25 @@ class ChatVideoOline extends React.Component {
constructor(props) {
super(props)
this.state = {
mediaPanelDrawerVisible: false,
}
}
componentDidMount() {
// const configuration = {
// iceServers: [{
// "url": "stun:23.21.150.121"
// }, {
// "url": "stun:stun.l.google.com:19302"
// }]
// };
localPeer = new RTCPeerConnection();
let peer = {
...this.props.peer,
localPeer: localPeer
}
this.props.setPeer(peer);
this.webrtcConnection();
}
/**
* 开启视频电话
@ -38,28 +46,22 @@ class ChatVideoOline extends React.Component { @@ -38,28 +46,22 @@ class ChatVideoOline extends React.Component {
if (!this.props.checkMediaPermisssion()) {
return;
}
this.webrtcConnection();
let preview = document.getElementById("preview");
this.setState({
onlineType: 1,
rtcType: 'offer'
})
let preview = document.getElementById("localPreviewSender");
navigator.mediaDevices
.getUserMedia({
audio: true,
video: true,
}).then((stream) => {
console.log(stream)
preview.srcObject = stream;
stream.getTracks().forEach(track => {
this.props.peer.localPeer.addTrack(track, stream);
localPeer.addTrack(track, stream);
});
// offer
this.props.peer.localPeer.createOffer()
localPeer.createOffer()
.then(offer => {
this.props.peer.localPeer.setLocalDescription(offer);
localPeer.setLocalDescription(offer);
let data = {
contentType: Constant.VIDEO_ONLINE,
content: JSON.stringify(offer),
@ -79,13 +81,11 @@ class ChatVideoOline extends React.Component { @@ -79,13 +81,11 @@ class ChatVideoOline extends React.Component {
*/
webrtcConnection = () => {
/**
* 对等方收到ice信息后通过调用 addIceCandidate 将接收的候选者信息传递给浏览器的ICE代理
* @param {候选人信息} e
*/
localPeer.onicecandidate = (e) => {
console.log(e)
if (e.candidate) {
// rtcTypeansweroffer
let candidate = {
@ -107,7 +107,7 @@ class ChatVideoOline extends React.Component { @@ -107,7 +107,7 @@ class ChatVideoOline extends React.Component {
*/
localPeer.ontrack = (e) => {
if (e && e.streams) {
let remoteVideo = document.getElementById("remoteVideo");
let remoteVideo = document.getElementById("remoteVideoSender");
remoteVideo.srcObject = e.streams[0];
}
};
@ -117,17 +117,23 @@ class ChatVideoOline extends React.Component { @@ -117,17 +117,23 @@ class ChatVideoOline extends React.Component {
* 停止视频电话,屏幕共享
*/
stopVideoOnline = () => {
let preview = document.getElementById("preview");
let preview = document.getElementById("localPreviewSender");
if (preview && preview.srcObject && preview.srcObject.getTracks()) {
preview.srcObject.getTracks().forEach((track) => track.stop());
}
let remoteVideo = document.getElementById("remoteVideo");
let remoteVideo = document.getElementById("remoteVideoSender");
if (remoteVideo && remoteVideo.srcObject && remoteVideo.srcObject.getTracks()) {
remoteVideo.srcObject.getTracks().forEach((track) => track.stop());
}
}
mediaPanelDrawerOnClose = () => {
this.setState({
mediaPanelDrawerVisible: false
})
}
render() {
const { chooseUser } = this.props;
return (
@ -141,7 +147,13 @@ class ChatVideoOline extends React.Component { @@ -141,7 +147,13 @@ class ChatVideoOline extends React.Component {
/>
</Tooltip>
<Drawer width='820px' forceRender={true} title="媒体面板" placement="right" onClose={this.mediaPanelDrawerOnClose} visible={this.state.mediaPanelDrawerVisible}>
<Drawer width='820px'
forceRender={true}
title="媒体面板"
placement="right"
onClose={this.mediaPanelDrawerOnClose}
visible={this.state.mediaPanelDrawerVisible}
>
<Tooltip title="结束视频语音">
<Button
shape="circle"
@ -151,8 +163,8 @@ class ChatVideoOline extends React.Component { @@ -151,8 +163,8 @@ class ChatVideoOline extends React.Component {
/>
</Tooltip>
<br />
<video id="preview" width="700px" height="auto" autoPlay muted controls />
<video id="remoteVideo" width="700px" height="auto" autoPlay muted controls />
<video id="localPreviewSender" width="700px" height="auto" autoPlay muted controls />
<video id="remoteVideoSender" width="700px" height="auto" autoPlay muted controls />
</Drawer>
</>
);

63
src/chat/panel/right/index.jsx

@ -1,7 +1,6 @@ @@ -1,7 +1,6 @@
import React from 'react';
import {
message,
Tag,
Tooltip,
Button
@ -22,7 +21,6 @@ import ChatVideoOline from './component/ChatVideoOline'; @@ -22,7 +21,6 @@ import ChatVideoOline from './component/ChatVideoOline';
import ChatEdit from './component/ChatEdit';
import moment from 'moment';
import protobuf from '../../proto/proto';
import { connect } from 'react-redux';
import { actions } from '../../redux/module/panel';
@ -62,45 +60,6 @@ class RightIndex extends React.Component { @@ -62,45 +60,6 @@ class RightIndex extends React.Component {
this.appendMessage(<img src={base64String} alt="" width="150px" />);
}
/**
* 发送消息
* @param {消息内容} messageData
*/
sendMessage = (messageData) => {
let data = {
...messageData,
messageType: this.props.chooseUser.messageType, // 1. 2.
fromUsername: localStorage.username,
from: localStorage.uuid,
to: this.props.chooseUser.toUser,
}
let message = protobuf.lookup("protocol.Message")
const messagePB = message.create(data)
let socket = this.props.socket;
if (null == socket) {
message.error("socket未连接");
return;
}
socket.send(message.encode(messagePB).finish())
}
/**
* 检查媒体权限是否开启
* @returns 媒体权限是否开启
*/
checkMediaPermisssion = () => {
navigator.getUserMedia = navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia; //
if (!navigator || !navigator.mediaDevices) {
message.error("获取摄像头权限失败!")
return false;
}
return true;
}
showMediaPanel = () => {
let media = {
...this.props.media,
@ -119,37 +78,37 @@ class RightIndex extends React.Component { @@ -119,37 +78,37 @@ class RightIndex extends React.Component {
history={this.props.history}
appendMessage={this.appendMessage}
appendImgToPanel={this.appendImgToPanel}
sendMessage={this.sendMessage}
sendMessage={this.props.sendMessage}
/>
<ChatAudio
history={this.props.history}
appendMessage={this.appendMessage}
sendMessage={this.sendMessage}
sendMessage={this.props.sendMessage}
/>
<ChatVideo
history={this.props.history}
appendMessage={this.appendMessage}
sendMessage={this.sendMessage}
checkMediaPermisssion={this.checkMediaPermisssion}
sendMessage={this.props.sendMessage}
checkMediaPermisssion={this.props.checkMediaPermisssion}
/>
<ChatShareScreen
history={this.props.history}
sendMessage={this.sendMessage}
checkMediaPermisssion={this.checkMediaPermisssion}
sendMessage={this.props.sendMessage}
checkMediaPermisssion={this.props.checkMediaPermisssion}
/>
<ChatAudioOline
history={this.props.history}
sendMessage={this.sendMessage}
checkMediaPermisssion={this.checkMediaPermisssion}
sendMessage={this.props.sendMessage}
checkMediaPermisssion={this.props.checkMediaPermisssion}
/>
<ChatVideoOline
history={this.props.history}
sendMessage={this.sendMessage}
checkMediaPermisssion={this.checkMediaPermisssion}
sendMessage={this.props.sendMessage}
checkMediaPermisssion={this.props.checkMediaPermisssion}
/>
<Tooltip title="显示视频面板">
@ -169,7 +128,7 @@ class RightIndex extends React.Component { @@ -169,7 +128,7 @@ class RightIndex extends React.Component {
history={this.props.history}
appendMessage={this.appendMessage}
appendImgToPanel={this.appendImgToPanel}
sendMessage={this.sendMessage}
sendMessage={this.props.sendMessage}
/>
</>

Loading…
Cancel
Save