Merge pull request #5081 from lfzawacki/video-shouldupdatecomponent-bbb

Video share button timeout and re-written shouldComponentUpdate method
This commit is contained in:
Anton Georgiev 2018-02-02 11:03:14 -05:00 committed by GitHub
commit c65e7c15c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 107 additions and 45 deletions

View File

@ -32,6 +32,7 @@ const intlMessages = defineMessages({
const RECONNECT_WAIT_TIME = 5000;
const INITIAL_SHARE_WAIT_TIME = 2000;
const CAMERA_SHARE_FAILED_WAIT_TIME = 10000;
class VideoElement extends Component {
constructor(props) {
@ -57,8 +58,7 @@ class VideoDock extends Component {
this.webRtcPeers = {};
this.reconnectWebcam = false;
this.reconnectList = [];
this.sharedCameraTimeout = null;
this.subscribedCamerasTimeouts = [];
this.cameraTimeouts = {};
this.state = {
videos: {},
@ -130,7 +130,7 @@ class VideoDock extends Component {
this.ws.addEventListener('close', this.onWsClose);
window.addEventListener('online', this.ws.open.bind(this.ws));
window.addEventListener('offline', this.ws.close.bind(this.ws));
window.addEventListener('offline', this.onWsClose);
}
componentWillUnmount () {
@ -144,8 +144,8 @@ class VideoDock extends Component {
this.ws.removeEventListener('close', this.onWsClose);
// Close websocket connection to prevent multiple reconnects from happening
window.removeEventListener('online', this.ws.open);
window.removeEventListener('offline', this.ws.close);
window.removeEventListener('online', this.ws.open.bind(this.ws));
window.removeEventListener('offline', this.onWsClose);
this.ws.close();
}
@ -186,10 +186,6 @@ class VideoDock extends Component {
this.startResponse(parsedMessage);
break;
case 'error':
this.handleError(parsedMessage);
break;
case 'playStart':
this.handlePlayStart(parsedMessage);
break;
@ -218,14 +214,31 @@ class VideoDock extends Component {
log('error', ' [ICE] Message arrived after the peer was already thrown out, discarding it...');
}
break;
case 'error':
default:
this.handleError(parsedMessage);
break;
}
};
start(id, shareWebcam) {
const that = this;
const { intl } = this.props;
console.log(`Starting video call for video: ${id} with ${shareWebcam}`);
this.cameraTimeouts[id] = setTimeout(() => {
log('error', `Camera share has not suceeded in ${CAMERA_SHARE_FAILED_WAIT_TIME}`);
if (that.myId == id) {
that.notifyError(intl.formatMessage(intlMessages.sharingError));
that.unshareWebcam();
} else {
that.stop(id);
that.start(id, shareWebcam);
}
}, CAMERA_SHARE_FAILED_WAIT_TIME);
if (shareWebcam) {
VideoService.joiningVideo();
this.setState({sharedWebcam: true});
@ -389,6 +402,10 @@ class VideoDock extends Component {
destroyWebRTCPeer(id) {
const webRtcPeer = this.webRtcPeers[id];
// Clear the shared camera fail timeout when destroying
clearTimeout(this.cameraTimeouts[id]);
this.cameraTimeouts[id] = null;
if (webRtcPeer) {
log('info', 'Stopping WebRTC peer');
@ -439,12 +456,12 @@ class VideoDock extends Component {
if (error) {
return log('error', error);
}
});
if (message.cameraId == this.props.userId) {
log('info', "camera id sendusershare ", id);
VideoService.sendUserShareWebcam(id);
}
if (message.cameraId == this.props.userId) {
log('info', "camera id sendusershare ", id);
VideoService.sendUserShareWebcam(id);
}
});
}
sendMessage(message) {
@ -488,6 +505,10 @@ class VideoDock extends Component {
handlePlayStart(message) {
log('info', 'Handle play start <===================');
// Clear camera shared timeout when camera succesfully starts
clearTimeout(this.cameraTimeouts[message.cameraId]);
this.cameraTimeouts[message.cameraId] = null;
if (message.cameraId == this.props.userId) {
VideoService.joinedVideo();
}
@ -495,10 +516,10 @@ class VideoDock extends Component {
handleError(message) {
const { intl, userId } = this.props;
this.notifyError(intl.formatMessage(intlMessages.sharingError));
if (message.cameraId == userId) {
this.unshareWebcam();
this.notifyError(intl.formatMessage(intlMessages.sharingError));
} else {
this.stop(message.cameraId);
}
@ -545,38 +566,61 @@ class VideoDock extends Component {
}
shouldComponentUpdate(nextProps, nextState) {
const { users, userId } = this.props;
const { userId } = this.props;
const currentUsers = this.props.users || {};
const nextUsers = nextProps.users;
if (users) {
let suc = false;
let users = {};
let present = {};
for (let i = 0; i < users.length; i++) {
if (users && users[i] &&
nextUsers && nextUsers[i]) {
if (users[i].has_stream !== nextUsers[i].has_stream) {
console.log(`User ${nextUsers[i].has_stream ? '' : 'un'}shared webcam ${users[i].userId}`);
if (!currentUsers)
return false;
if (nextUsers[i].has_stream) {
if (userId !== users[i].userId) {
this.start(users[i].userId, false);
}
} else {
this.stop(users[i].userId);
}
// Map user objectos to an object in the form {userId: has_stream}
currentUsers.forEach((user) => {
users[user.userId] = user.has_stream;
});
if (!nextUsers[i].has_stream) {
this.destroyVideoTag(users[i].userId);
}
// Keep instances where the flag has changed or next user adds it
nextUsers.forEach((user) => {
let id = user.userId;
// The case when a user exists and stream status has not changed
if (users[id] === user.has_stream) {
delete users[id];
} else {
// Case when a user has been added to the list
users[id] = user.has_stream;
}
suc = suc || true;
}
// Mark the ids which are present in nextUsers
present[id] = true;
});
const userIds = Object.keys(users);
for (let i = 0; i < userIds.length; i++) {
let id = userIds[i];
// If a userId is not present in nextUsers let's stop it
if (!present[id]) {
this.stop(id);
continue;
}
console.log(`User ${users[id] ? '' : 'un'}shared webcam ${id}`);
// If a user stream is true, changed and was shared by other
// user we'll start it. If it is false and changed we stop it
if (users[id]) {
if (userId !== id) {
this.start(id, false);
}
}
return true;
else {
this.stop(id);
}
}
return false;
return true;
}
}

View File

@ -23,6 +23,7 @@ module.exports = class Video {
this.iceQueue = null;
this.candidatesQueue = [];
this.notFlowingTimeout = null;
}
onIceCandidate (_candidate) {
@ -80,15 +81,26 @@ module.exports = class Video {
Logger.info('[video] ' + msEvent.type + '[' + msEvent.state + ']' + ' for media session', event.id, "for video", this.id);
if (msEvent.state === 'NOT_FLOWING') {
this.bbbGW.publish(JSON.stringify({
connectionId: this.sessionId,
type: 'video',
role: this.role,
id : 'playStop',
cameraId: this.id,
}), C.FROM_VIDEO);
Logger.warn("Setting up a timeout for " + this.sessionId + " camera " + this.id);
if (!this.notFlowingTimeout) {
this.notFlowingTimeout = setTimeout(() => {
this.bbbGW.publish(JSON.stringify({
connectionId: this.sessionId,
type: 'video',
role: this.role,
id : 'playStop',
cameraId: this.id,
}), C.FROM_VIDEO);
}, config.get('mediaFlowTimeoutDuration'));
}
}
else if (msEvent.state === 'FLOWING') {
if (this.notFlowingTimeout) {
Logger.warn("Received a media flow before stopping " + this.sessionId + " camera " + this.id);
clearTimeout(this.notFlowingTimeout);
this.notFlowingTimeout = null;
}
this.bbbGW.publish(JSON.stringify({
connectionId: this.sessionId,
type: 'video',
@ -152,6 +164,12 @@ module.exports = class Video {
if (this.shared) {
sharedWebcams[this.id] = null;
}
if (this.notFlowingTimeout) {
clearTimeout(this.notFlowingTimeout);
this.notFlowingTimeout = null;
}
this._candidatesQueue = null;
Promise.resolve();
}