Show dialog for GUM errors
This commit is contained in:
parent
48b219111d
commit
448fcf36b6
111
conference.js
111
conference.js
|
@ -375,17 +375,39 @@ export default {
|
|||
};
|
||||
}
|
||||
|
||||
let audioAndVideoError, audioOnlyError;
|
||||
|
||||
return JitsiMeetJS.init(config).then(() => {
|
||||
return Promise.all([
|
||||
// try to retrieve audio and video
|
||||
createLocalTracks(['audio', 'video'])
|
||||
// if failed then try to retrieve only audio
|
||||
.catch(() => createLocalTracks(['audio']))
|
||||
.catch(err => {
|
||||
audioAndVideoError = err;
|
||||
return createLocalTracks(['audio']);
|
||||
})
|
||||
// if audio also failed then just return empty array
|
||||
.catch(() => []),
|
||||
.catch(err => {
|
||||
audioOnlyError = err;
|
||||
return [];
|
||||
}),
|
||||
connect(options.roomName)
|
||||
]);
|
||||
}).then(([tracks, con]) => {
|
||||
if (audioAndVideoError) {
|
||||
if (audioOnlyError) {
|
||||
// If both requests for 'audio' + 'video' and 'audio' only
|
||||
// failed, we assume that there is some problems with user's
|
||||
// microphone and show corresponding dialog.
|
||||
APP.UI.showDeviceErrorDialog('microphone', audioOnlyError);
|
||||
} else {
|
||||
// If request for 'audio' + 'video' failed, but request for
|
||||
// 'audio' only was OK, we assume that we had problems with
|
||||
// camera and show corresponding dialog.
|
||||
APP.UI.showDeviceErrorDialog('camera', audioAndVideoError);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('initialized with %s local tracks', tracks.length);
|
||||
APP.connection = connection = con;
|
||||
this._createRoom(tracks);
|
||||
|
@ -541,9 +563,11 @@ export default {
|
|||
}
|
||||
|
||||
function createNewTracks(type, cameraDeviceId, micDeviceId) {
|
||||
let audioOnlyError, videoOnlyError;
|
||||
|
||||
return createLocalTracks(type, cameraDeviceId, micDeviceId)
|
||||
.then(onTracksCreated)
|
||||
.catch(() => {
|
||||
.catch((err) => {
|
||||
// if we tried to create both audio and video tracks
|
||||
// at once and failed, let's try again only with
|
||||
// audio. Such situation may happen in case if we
|
||||
|
@ -553,16 +577,21 @@ export default {
|
|||
&& type.indexOf('video') !== -1) {
|
||||
return createLocalTracks(['audio'], null,
|
||||
micDeviceId);
|
||||
} else if (type.indexOf('audio') !== -1) {
|
||||
audioOnlyError = err;
|
||||
} else if (type.indexOf('video') !== -1) {
|
||||
videoOnlyError = err;
|
||||
}
|
||||
|
||||
})
|
||||
.then(onTracksCreated)
|
||||
.catch(() => {
|
||||
.catch((err) => {
|
||||
// if we tried to create both audio and video tracks
|
||||
// at once and failed, let's try again only with
|
||||
// video. Such situation may happen in case if we
|
||||
// granted access only to camera, but not to
|
||||
// microphone.
|
||||
audioOnlyError = err;
|
||||
if (type.indexOf('audio') !== -1
|
||||
&& type.indexOf('video') !== -1) {
|
||||
return createLocalTracks(['video'],
|
||||
|
@ -571,8 +600,18 @@ export default {
|
|||
}
|
||||
})
|
||||
.then(onTracksCreated)
|
||||
.catch(() => {
|
||||
// can't do anything in this case, so just ignore;
|
||||
.catch((err) => {
|
||||
videoOnlyError = err;
|
||||
|
||||
if (videoOnlyError) {
|
||||
APP.UI.showDeviceErrorDialog(
|
||||
'camera', videoOnlyError);
|
||||
}
|
||||
|
||||
if (audioOnlyError) {
|
||||
APP.UI.showDeviceErrorDialog(
|
||||
'microphone', audioOnlyError);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -896,13 +935,13 @@ export default {
|
|||
this.isSharingScreen = stream.videoType === 'desktop';
|
||||
|
||||
APP.UI.addLocalStream(stream);
|
||||
|
||||
stream.videoType === 'camera' && APP.UI.enableCameraButton();
|
||||
} else {
|
||||
this.videoMuted = false;
|
||||
this.isSharingScreen = false;
|
||||
}
|
||||
|
||||
stream.videoType === 'camera' && APP.UI.enableCameraButton();
|
||||
|
||||
APP.UI.setVideoMuted(this.localId, this.videoMuted);
|
||||
|
||||
APP.UI.updateDesktopSharingButtons();
|
||||
|
@ -990,21 +1029,22 @@ export default {
|
|||
return;
|
||||
}
|
||||
|
||||
// TODO: handle Permission error
|
||||
|
||||
// Handling:
|
||||
// TrackErrors.PERMISSION_DENIED
|
||||
// TrackErrors.CHROME_EXTENSION_INSTALLATION_ERROR
|
||||
// TrackErrors.GENERAL
|
||||
// and any other
|
||||
let dialogTxt = APP.translation
|
||||
.generateTranslationHTML("dialog.failtoinstall");
|
||||
let dialogTitle = APP.translation
|
||||
.generateTranslationHTML("dialog.error");
|
||||
APP.UI.messageHandler.openDialog(
|
||||
dialogTitle,
|
||||
dialogTxt,
|
||||
false
|
||||
);
|
||||
let dialogTxt = APP.translation.generateTranslationHTML(
|
||||
err.name === TrackErrors.PERMISSION_DENIED
|
||||
? "dialog.screenSharingPermissionDeniedError"
|
||||
: "dialog.failtoinstall");
|
||||
|
||||
let dialogTitle = APP.translation.generateTranslationHTML(
|
||||
err.name === TrackErrors.PERMISSION_DENIED
|
||||
? "dialog.permissionDenied"
|
||||
: "dialog.error");
|
||||
|
||||
APP.UI.messageHandler.openDialog(dialogTitle, dialogTxt, false);
|
||||
});
|
||||
} else {
|
||||
createLocalTracks(['video']).then(
|
||||
|
@ -1016,6 +1056,8 @@ export default {
|
|||
this.useVideoStream(null);
|
||||
this.videoSwitchInProgress = false;
|
||||
console.error('failed to share local video', err);
|
||||
|
||||
APP.UI.showDeviceErrorDialog('camera', err);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
@ -1357,22 +1399,32 @@ export default {
|
|||
APP.UI.addListener(
|
||||
UIEvents.VIDEO_DEVICE_CHANGED,
|
||||
(cameraDeviceId) => {
|
||||
APP.settings.setCameraDeviceId(cameraDeviceId);
|
||||
createLocalTracks(['video']).then(([stream]) => {
|
||||
this.useVideoStream(stream);
|
||||
console.log('switched local video device');
|
||||
});
|
||||
createLocalTracks(['video'])
|
||||
.then(([stream]) => {
|
||||
this.useVideoStream(stream);
|
||||
console.log('switched local video device');
|
||||
APP.settings.setCameraDeviceId(cameraDeviceId);
|
||||
})
|
||||
.catch((err) => {
|
||||
APP.UI.showDeviceErrorDialog('camera', err);
|
||||
APP.UI.setSelectedCameraFromSettings();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
APP.UI.addListener(
|
||||
UIEvents.AUDIO_DEVICE_CHANGED,
|
||||
(micDeviceId) => {
|
||||
APP.settings.setMicDeviceId(micDeviceId);
|
||||
createLocalTracks(['audio']).then(([stream]) => {
|
||||
this.useAudioStream(stream);
|
||||
console.log('switched local audio device');
|
||||
});
|
||||
createLocalTracks(['audio'])
|
||||
.then(([stream]) => {
|
||||
this.useAudioStream(stream);
|
||||
console.log('switched local audio device');
|
||||
APP.settings.setMicDeviceId(micDeviceId);
|
||||
})
|
||||
.catch((err) => {
|
||||
APP.UI.showDeviceErrorDialog('microphone', err);
|
||||
APP.UI.setSelectedMicFromSettings();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -1383,6 +1435,7 @@ export default {
|
|||
.then(() => console.log('changed audio output device'))
|
||||
.catch((err) => {
|
||||
console.error('failed to set audio output device', err);
|
||||
APP.UI.setSelectedAudioOutputFromSettings();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
|
|
@ -222,7 +222,19 @@
|
|||
"stopStreamingWarning": "Are you sure you would like to stop the live streaming?",
|
||||
"stopRecordingWarning": "Are you sure you would like to stop the recording?",
|
||||
"stopLiveStreaming": "Stop live streaming",
|
||||
"stopRecording": "Stop recording"
|
||||
"stopRecording": "Stop recording",
|
||||
"doNotShowWarningAgain": "Don't show this warning again",
|
||||
"permissionDenied": "Permission Denied",
|
||||
"screenSharingPermissionDeniedError": "You have not granted permission to share your screen.",
|
||||
"cameraUnsupportedResolutionError": "Your camera does not support required video resolution.",
|
||||
"cameraUnknownError": "Cannot use camera for a unknown reason.",
|
||||
"cameraPermissionDeniedError": "You have not granted permission to use your camera.",
|
||||
"cameraNotFoundError": "Requested camera was not found.",
|
||||
"cameraConstraintFailedError": "Yor camera does not satisfy some of required constraints.",
|
||||
"micUnknownError": "Cannot use microphone for a unknown reason.",
|
||||
"micPermissionDeniedError": "You have not granted permission to use your microphone.",
|
||||
"micNotFoundError": "Requested microphone was not found.",
|
||||
"micConstraintFailedError": "Yor microphone does not satisfy some of required constraints."
|
||||
},
|
||||
"email":
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* global APP, $, config, interfaceConfig, toastr */
|
||||
/* global APP, JitsiMeetJS, $, config, interfaceConfig, toastr */
|
||||
/* jshint -W101 */
|
||||
var UI = {};
|
||||
|
||||
|
@ -38,6 +38,32 @@ let sharedVideoManager;
|
|||
|
||||
let followMeHandler;
|
||||
|
||||
const TrackErrors = JitsiMeetJS.errors.track;
|
||||
|
||||
const JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP = {
|
||||
microphone: {},
|
||||
camera: {}
|
||||
};
|
||||
|
||||
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[TrackErrors.UNSUPPORTED_RESOLUTION]
|
||||
= "dialog.cameraUnsupportedResolutionError";
|
||||
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[TrackErrors.GENERAL]
|
||||
= "dialog.cameraUnknownError";
|
||||
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[TrackErrors.PERMISSION_DENIED]
|
||||
= "dialog.cameraPermissionDeniedError";
|
||||
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[TrackErrors.NOT_FOUND]
|
||||
= "dialog.cameraNotFoundError";
|
||||
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[TrackErrors.CONSTRAINT_FAILED]
|
||||
= "dialog.cameraConstraintFailedError";
|
||||
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.microphone[TrackErrors.GENERAL]
|
||||
= "dialog.micUnknownError";
|
||||
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.microphone[TrackErrors.PERMISSION_DENIED]
|
||||
= "dialog.micPermissionDeniedError";
|
||||
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.microphone[TrackErrors.NOT_FOUND]
|
||||
= "dialog.micNotFoundError";
|
||||
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.microphone[TrackErrors.CONSTRAINT_FAILED]
|
||||
= "dialog.micConstraintFailedError";
|
||||
|
||||
/**
|
||||
* Prompt user for nickname.
|
||||
*/
|
||||
|
@ -1078,6 +1104,28 @@ UI.onAvailableDevicesChanged = function (devices) {
|
|||
SettingsMenu.changeDevicesList(devices);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets microphone's <select> element to select microphone ID from settings.
|
||||
*/
|
||||
UI.setSelectedMicFromSettings = function () {
|
||||
SettingsMenu.setSelectedMicFromSettings();
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets camera's <select> element to select camera ID from settings.
|
||||
*/
|
||||
UI.setSelectedCameraFromSettings = function () {
|
||||
SettingsMenu.setSelectedCameraFromSettings();
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets audio outputs's <select> element to select audio output ID from
|
||||
* settings.
|
||||
*/
|
||||
UI.setSelectedAudioOutputFromSettings = function () {
|
||||
SettingsMenu.setSelectedAudioOutputFromSettings();
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the id of the current video shown on large.
|
||||
* Currently used by tests (torture).
|
||||
|
@ -1106,6 +1154,51 @@ UI.showExtensionRequiredDialog = function (url) {
|
|||
"dialog.firefoxExtensionPrompt", {url: url}));
|
||||
};
|
||||
|
||||
/**
|
||||
* Shows dialog with information about camera or microphone error.
|
||||
* @param {'microphone'|'camera'} type
|
||||
* @param {JitsiTrackError} error
|
||||
*/
|
||||
UI.showDeviceErrorDialog = function (type, error) {
|
||||
if (type !== "microphone" && type !== "camera") {
|
||||
throw new Error("Invalid device type");
|
||||
}
|
||||
|
||||
if (window.localStorage[type + "DoNotShowErrorAgain-" + error.name]
|
||||
=== "true") {
|
||||
return;
|
||||
}
|
||||
|
||||
let titleKey = error.name === TrackErrors.PERMISSION_DENIED
|
||||
? "dialog.permissionDenied"
|
||||
: "dialog.error",
|
||||
errorMsg = JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP[type][error.name],
|
||||
doNotShowAgainMsg = "dialog.doNotShowWarningAgain",
|
||||
title = `<span data-i18n="${titleKey}"></span>`,
|
||||
message = `
|
||||
<h4 data-i18n="${errorMsg}"></h4>
|
||||
<label>
|
||||
<input type="checkbox" id="doNotShowWarningAgain">
|
||||
<span data-i18n="${doNotShowAgainMsg}"></span>
|
||||
</label>`;
|
||||
|
||||
messageHandler.openDialog(
|
||||
title,
|
||||
message,
|
||||
false,
|
||||
{Ok: true},
|
||||
function () {
|
||||
let form = $.prompt.getPrompt(),
|
||||
input = form.find("#doNotShowWarningAgain");
|
||||
|
||||
window.localStorage[type + "DoNotShowErrorAgain-" + error.name]
|
||||
= input.prop("checked");
|
||||
}
|
||||
);
|
||||
|
||||
APP.translation.translateElement($(".jqibox"));
|
||||
};
|
||||
|
||||
UI.updateDevicesAvailability = function (id, devices) {
|
||||
VideoLayout.setDeviceAvailabilityIcons(id, devices);
|
||||
};
|
||||
|
|
|
@ -203,6 +203,28 @@ export default {
|
|||
$('#avatar').attr('src', avatarUrl);
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets microphone's <select> element to select microphone ID from settings.
|
||||
*/
|
||||
setSelectedMicFromSettings () {
|
||||
$('#selectMic').val(Settings.getMicDeviceId());
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets camera's <select> element to select camera ID from settings.
|
||||
*/
|
||||
setSelectedCameraFromSettings () {
|
||||
$('#selectCamera').val(Settings.getCameraDeviceId());
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets audio outputs's <select> element to select audio output ID from
|
||||
* settings.
|
||||
*/
|
||||
setSelectedAudioOutputFromSettings () {
|
||||
$('#selectAudioOutput').val(Settings.getAudioOutputDeviceId());
|
||||
},
|
||||
|
||||
/**
|
||||
* Change available cameras/microphones or hide selects completely if
|
||||
* no devices available.
|
||||
|
|
Loading…
Reference in New Issue