Show dialog for GUM errors

This commit is contained in:
tsareg 2016-05-26 11:53:02 +03:00
parent 48b219111d
commit 448fcf36b6
4 changed files with 211 additions and 31 deletions

View File

@ -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();
});
}
);

View File

@ -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":
{

View File

@ -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);
};

View File

@ -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.