Merge pull request #5971 from MaximKhlobystov/ice-connection-state-errors
Better handling of video ice connection state errors.
This commit is contained in:
commit
f83374491b
@ -45,6 +45,10 @@ const intlClientErrors = defineMessages({
|
||||
id: 'app.video.notReadableError',
|
||||
description: 'error message When the webcam is being used by other software',
|
||||
},
|
||||
iceConnectionStateError: {
|
||||
id: 'app.video.iceConnectionStateError',
|
||||
description: 'Error message for ice connection state being failed',
|
||||
},
|
||||
});
|
||||
|
||||
const intlSFUErrors = defineMessages({
|
||||
@ -62,7 +66,7 @@ const intlSFUErrors = defineMessages({
|
||||
},
|
||||
2003: {
|
||||
id: 'app.sfu.mediaServerRequestTimeout2003',
|
||||
description: "Error message fired when requests are timing out due to lack of resources",
|
||||
description: 'Error message fired when requests are timing out due to lack of resources',
|
||||
},
|
||||
2021: {
|
||||
id: 'app.sfu.serverIceGatheringFailed2021',
|
||||
@ -79,7 +83,7 @@ const intlSFUErrors = defineMessages({
|
||||
2203: {
|
||||
id: 'app.sfu.noAvailableCodec2203',
|
||||
description: 'Error message fired when the server has no available codec for the client',
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const CAMERA_SHARE_FAILED_WAIT_TIME = 15000;
|
||||
@ -123,10 +127,10 @@ class VideoProvider extends Component {
|
||||
}
|
||||
|
||||
logger(type, message, options = {}) {
|
||||
const {userId, userName} = this.props;
|
||||
const { userId, userName } = this.props;
|
||||
const topic = options.topic || 'video';
|
||||
|
||||
logger[type]({obj: Object.assign(options, {userId, userName, topic})}, `[${topic}] ${message}`);
|
||||
logger[type]({ obj: Object.assign(options, { userId, userName, topic }) }, `[${topic}] ${message}`);
|
||||
}
|
||||
|
||||
_sendPauseStream(id, role, state) {
|
||||
@ -215,7 +219,7 @@ class VideoProvider extends Component {
|
||||
}
|
||||
|
||||
onWsOpen() {
|
||||
this.logger('debug', '------ Websocket connection opened.', {topic: 'ws'});
|
||||
this.logger('debug', '------ Websocket connection opened.', { topic: 'ws' });
|
||||
|
||||
// -- Resend queued messages that happened when socket was not connected
|
||||
while (this.wsQueue.length > 0) {
|
||||
@ -228,7 +232,7 @@ class VideoProvider extends Component {
|
||||
}
|
||||
|
||||
onWsClose(error) {
|
||||
this.logger('debug', '------ Websocket connection closed.', {topic: 'ws'});
|
||||
this.logger('debug', '------ Websocket connection closed.', { topic: 'ws' });
|
||||
|
||||
this.stopWebRTCPeer(this.props.userId);
|
||||
clearInterval(this.pingInterval);
|
||||
@ -246,7 +250,7 @@ class VideoProvider extends Component {
|
||||
onWsMessage(msg) {
|
||||
const parsedMessage = JSON.parse(msg.data);
|
||||
|
||||
this.logger('debug', `Received new message '${parsedMessage.id}'`, {topic: 'ws', message: parsedMessage});
|
||||
this.logger('debug', `Received new message '${parsedMessage.id}'`, { topic: 'ws', message: parsedMessage });
|
||||
|
||||
switch (parsedMessage.id) {
|
||||
case 'startResponse':
|
||||
@ -266,7 +270,7 @@ class VideoProvider extends Component {
|
||||
break;
|
||||
|
||||
case 'pong':
|
||||
this.logger('debug', 'Received pong from server', {topic: 'ws'});
|
||||
this.logger('debug', 'Received pong from server', { topic: 'ws' });
|
||||
break;
|
||||
|
||||
case 'error':
|
||||
@ -281,10 +285,10 @@ class VideoProvider extends Component {
|
||||
|
||||
if (this.connectedToMediaServer()) {
|
||||
const jsonMessage = JSON.stringify(message);
|
||||
this.logger('debug', `Sending message '${message.id}'`, {topic: 'ws', message});
|
||||
this.logger('debug', `Sending message '${message.id}'`, { topic: 'ws', message });
|
||||
ws.send(jsonMessage, (error) => {
|
||||
if (error) {
|
||||
this.logger(`client: Websocket error '${error}' on message '${message.id}'`, {topic: 'ws'});
|
||||
this.logger(`client: Websocket error '${error}' on message '${message.id}'`, { topic: 'ws' });
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@ -303,12 +307,12 @@ class VideoProvider extends Component {
|
||||
const id = message.cameraId;
|
||||
const peer = this.webRtcPeers[id];
|
||||
|
||||
this.logger('debug', 'SDP answer received from server. Processing ...', {cameraId: id, sdpAnswer: message.sdpAnswer});
|
||||
this.logger('debug', 'SDP answer received from server. Processing ...', { cameraId: id, sdpAnswer: message.sdpAnswer });
|
||||
|
||||
if (peer) {
|
||||
peer.processAnswer(message.sdpAnswer, (error) => {
|
||||
if (error) {
|
||||
return this.logger('debug', JSON.stringify(error), {cameraId: id});
|
||||
return this.logger('debug', JSON.stringify(error), { cameraId: id });
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@ -319,13 +323,13 @@ class VideoProvider extends Component {
|
||||
handleIceCandidate(message) {
|
||||
const webRtcPeer = this.webRtcPeers[message.cameraId];
|
||||
|
||||
this.logger('debug', 'Received remote ice candidate', {topic: 'ice', candidate: message.candidate})
|
||||
this.logger('debug', 'Received remote ice candidate', { topic: 'ice', candidate: message.candidate });
|
||||
|
||||
if (webRtcPeer) {
|
||||
if (webRtcPeer.didSDPAnswered) {
|
||||
webRtcPeer.addIceCandidate(message.candidate, (err) => {
|
||||
if (err) {
|
||||
return this.logger('error', `Error adding candidate: ${err}`, {cameraId: message.cameraId});
|
||||
return this.logger('error', `Error adding candidate: ${err}`, { cameraId: message.cameraId });
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@ -335,15 +339,19 @@ class VideoProvider extends Component {
|
||||
webRtcPeer.iceQueue.push(message.candidate);
|
||||
}
|
||||
} else {
|
||||
this.logger('warn', ' [iceCandidate] Message arrived after the peer was already thrown out, discarding it...', {cameraId: message.cameraId});
|
||||
this.logger('warn', ' [iceCandidate] Message arrived after the peer was already thrown out, discarding it...', { cameraId: message.cameraId });
|
||||
}
|
||||
}
|
||||
|
||||
stopWebRTCPeer(id) {
|
||||
this.logger('info', 'Stopping webcam', {cameraId: id});
|
||||
this.logger('info', 'Stopping webcam', { cameraId: id });
|
||||
const { userId } = this.props;
|
||||
const shareWebcam = id === userId;
|
||||
|
||||
// in this case, 'closed' state is not caused by an error;
|
||||
// we stop listening to prevent this from being treated as an error
|
||||
this.webRtcPeers[id].peerConnection.oniceconnectionstatechange = null;
|
||||
|
||||
if (shareWebcam) {
|
||||
this.unshareWebcam();
|
||||
}
|
||||
@ -365,11 +373,11 @@ class VideoProvider extends Component {
|
||||
destroyWebRTCPeer(id) {
|
||||
const webRtcPeer = this.webRtcPeers[id];
|
||||
if (webRtcPeer) {
|
||||
this.logger('info', 'Stopping WebRTC peer', {cameraId: id});
|
||||
this.logger('info', 'Stopping WebRTC peer', { cameraId: id });
|
||||
webRtcPeer.dispose();
|
||||
delete this.webRtcPeers[id];
|
||||
} else {
|
||||
this.logger('warn', 'No WebRTC peer to stop (not an error)', {cameraId: id});
|
||||
this.logger('warn', 'No WebRTC peer to stop (not an error)', { cameraId: id });
|
||||
}
|
||||
}
|
||||
|
||||
@ -436,7 +444,7 @@ class VideoProvider extends Component {
|
||||
return this._webRTCOnError(errorGenOffer, id, shareWebcam);
|
||||
}
|
||||
|
||||
this.logger('debug', `Invoking SDP offer callback function ${location.host}`, {cameraId: id, offerSdp});
|
||||
this.logger('debug', `Invoking SDP offer callback function ${location.host}`, { cameraId: id, offerSdp });
|
||||
|
||||
const message = {
|
||||
type: 'video',
|
||||
@ -453,6 +461,8 @@ class VideoProvider extends Component {
|
||||
peer.didSDPAnswered = true;
|
||||
});
|
||||
});
|
||||
this.webRtcPeers[id].peerConnection.oniceconnectionstatechange =
|
||||
this._getOnIceConnectionStateChangeCallback(id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -460,7 +470,7 @@ class VideoProvider extends Component {
|
||||
const { intl } = this.props;
|
||||
|
||||
return () => {
|
||||
this.logger('error', `Camera share has not suceeded in ${CAMERA_SHARE_FAILED_WAIT_TIME}`, {cameraId: id});
|
||||
this.logger('error', `Camera share has not suceeded in ${CAMERA_SHARE_FAILED_WAIT_TIME}`, { cameraId: id });
|
||||
|
||||
if (this.props.userId === id) {
|
||||
this.notifyError(intl.formatMessage(intlClientErrors.sharingError));
|
||||
@ -489,7 +499,7 @@ class VideoProvider extends Component {
|
||||
peer.addIceCandidate(candidate, (err) => {
|
||||
if (err) {
|
||||
this.notifyError(intl.formatMessage(intlClientErrors.iceCandidateError));
|
||||
return this.logger('error', `Error adding candidate: ${err}`, {cameraId});
|
||||
return this.logger('error', `Error adding candidate: ${err}`, { cameraId });
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -510,7 +520,7 @@ class VideoProvider extends Component {
|
||||
|
||||
this.stopWebRTCPeer(id);
|
||||
|
||||
return this.logger('error', errorMessage, {cameraId: id});
|
||||
return this.logger('error', errorMessage, { cameraId: id });
|
||||
}
|
||||
|
||||
_getOnIceCandidateCallback(id, shareWebcam) {
|
||||
@ -521,11 +531,11 @@ class VideoProvider extends Component {
|
||||
if (!this.restartTimeout[id]) {
|
||||
this.restartTimer[id] = this.restartTimer[id] || CAMERA_SHARE_FAILED_WAIT_TIME;
|
||||
|
||||
this.logger('debug', `Setting a camera connection restart in ${this.restartTimer[id]}`, {cameraId: id});
|
||||
this.logger('debug', `Setting a camera connection restart in ${this.restartTimer[id]}`, { cameraId: id });
|
||||
this.restartTimeout[id] = setTimeout(this._getWebRTCStartTimeout(id, shareWebcam, peer), this.restartTimer[id]);
|
||||
}
|
||||
|
||||
this.logger('debug', 'Generated local ice candidate', {topic: 'ice', candidate})
|
||||
this.logger('debug', 'Generated local ice candidate', { topic: 'ice', candidate });
|
||||
|
||||
const message = {
|
||||
type: 'video',
|
||||
@ -538,6 +548,24 @@ class VideoProvider extends Component {
|
||||
};
|
||||
}
|
||||
|
||||
_getOnIceConnectionStateChangeCallback(id) {
|
||||
const { intl } = this.props;
|
||||
const peer = this.webRtcPeers[id];
|
||||
|
||||
return (event) => {
|
||||
const connectionState = peer.peerConnection.iceConnectionState;
|
||||
if (connectionState === 'failed' || connectionState === 'closed') {
|
||||
|
||||
// prevent the same error from being detected multiple times
|
||||
peer.peerConnection.oniceconnectionstatechange = null;
|
||||
|
||||
this.logger('error', 'ICE connection state', id);
|
||||
this.stopWebRTCPeer(id);
|
||||
this.notifyError(intl.formatMessage(intlClientErrors.iceConnectionStateError));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
attachVideoStream(id) {
|
||||
const video = this.videoTags[id];
|
||||
if (video == null) {
|
||||
@ -706,7 +734,7 @@ class VideoProvider extends Component {
|
||||
|
||||
monitorTrackStart(peer, track, local, callback) {
|
||||
const that = this;
|
||||
this.logger('info', 'Starting stats monitoring on', {cameraId: track.id});
|
||||
this.logger('info', 'Starting stats monitoring on', { cameraId: track.id });
|
||||
const getStatsInterval = 2000;
|
||||
|
||||
const callGetStats = () => {
|
||||
@ -772,9 +800,9 @@ class VideoProvider extends Component {
|
||||
}
|
||||
|
||||
handlePlayStop(message) {
|
||||
const {cameraId} = message;
|
||||
const { cameraId } = message;
|
||||
|
||||
this.logger('info', 'Handle play stop for camera', {cameraId});
|
||||
this.logger('info', 'Handle play stop for camera', { cameraId });
|
||||
this.stopWebRTCPeer(id);
|
||||
}
|
||||
|
||||
@ -784,7 +812,7 @@ class VideoProvider extends Component {
|
||||
const videoTag = this.videoTags[id];
|
||||
|
||||
if (peer) {
|
||||
this.logger('info', 'Handle play start for camera', {cameraId: id});
|
||||
this.logger('info', 'Handle play start for camera', { cameraId: id });
|
||||
|
||||
// Clear camera shared timeout when camera succesfully starts
|
||||
clearTimeout(this.restartTimeout[id]);
|
||||
|
@ -322,6 +322,7 @@
|
||||
"app.video.joinVideo": "Share Webcam",
|
||||
"app.video.leaveVideo": "Unshare Webcam",
|
||||
"app.video.iceCandidateError": "Error on adding ice candidate",
|
||||
"app.video.iceConnectionStateError": "Error 1107: ICE negotiation failed",
|
||||
"app.video.permissionError": "Error on sharing webcam. Please check permissions",
|
||||
"app.video.sharingError": "Error on sharing webcam",
|
||||
"app.video.notFoundError": "Could not find webcam. Please make sure it's connected",
|
||||
|
Loading…
Reference in New Issue
Block a user