feat(api): notify api of mic and camera errors (#4289)
- Use actions to notify the rest of the app that a mic or camera error has occurred - Use middleware to respond to those notifications of errors by showing in-app notifications and notifying the external api
This commit is contained in:
parent
9712804040
commit
251da1861a
|
@ -51,6 +51,8 @@ import {
|
||||||
import {
|
import {
|
||||||
checkAndNotifyForNewDevice,
|
checkAndNotifyForNewDevice,
|
||||||
getAvailableDevices,
|
getAvailableDevices,
|
||||||
|
notifyCameraError,
|
||||||
|
notifyMicError,
|
||||||
setAudioOutputDeviceId,
|
setAudioOutputDeviceId,
|
||||||
updateDeviceList
|
updateDeviceList
|
||||||
} from './react/features/base/devices';
|
} from './react/features/base/devices';
|
||||||
|
@ -694,13 +696,14 @@ export default {
|
||||||
// If both requests for 'audio' + 'video' and 'audio'
|
// If both requests for 'audio' + 'video' and 'audio'
|
||||||
// only failed, we assume that there are some problems
|
// only failed, we assume that there are some problems
|
||||||
// with user's microphone and show corresponding dialog.
|
// with user's microphone and show corresponding dialog.
|
||||||
APP.UI.showMicErrorNotification(audioOnlyError);
|
APP.store.dispatch(notifyMicError(audioOnlyError));
|
||||||
APP.UI.showCameraErrorNotification(videoOnlyError);
|
APP.store.dispatch(notifyCameraError(videoOnlyError));
|
||||||
} else {
|
} else {
|
||||||
// If request for 'audio' + 'video' failed, but request
|
// If request for 'audio' + 'video' failed, but request
|
||||||
// for 'audio' only was OK, we assume that we had
|
// for 'audio' only was OK, we assume that we had
|
||||||
// problems with camera and show corresponding dialog.
|
// problems with camera and show corresponding dialog.
|
||||||
APP.UI.showCameraErrorNotification(audioAndVideoError);
|
APP.store.dispatch(
|
||||||
|
notifyCameraError(audioAndVideoError));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -839,7 +842,7 @@ export default {
|
||||||
|
|
||||||
if (!this.localAudio && !mute) {
|
if (!this.localAudio && !mute) {
|
||||||
const maybeShowErrorDialog = error => {
|
const maybeShowErrorDialog = error => {
|
||||||
showUI && APP.UI.showMicErrorNotification(error);
|
showUI && APP.store.dispatch(notifyMicError(error));
|
||||||
};
|
};
|
||||||
|
|
||||||
createLocalTracksF({ devices: [ 'audio' ] }, false)
|
createLocalTracksF({ devices: [ 'audio' ] }, false)
|
||||||
|
@ -902,7 +905,7 @@ export default {
|
||||||
|
|
||||||
if (!this.localVideo && !mute) {
|
if (!this.localVideo && !mute) {
|
||||||
const maybeShowErrorDialog = error => {
|
const maybeShowErrorDialog = error => {
|
||||||
showUI && APP.UI.showCameraErrorNotification(error);
|
showUI && APP.store.dispatch(notifyCameraError(error));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Try to create local video if there wasn't any.
|
// Try to create local video if there wasn't any.
|
||||||
|
@ -2109,7 +2112,7 @@ export default {
|
||||||
this._updateVideoDeviceId();
|
this._updateVideoDeviceId();
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
APP.UI.showCameraErrorNotification(err);
|
APP.store.dispatch(notifyCameraError(err));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -2142,7 +2145,7 @@ export default {
|
||||||
this._updateAudioDeviceId();
|
this._updateAudioDeviceId();
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
APP.UI.showMicErrorNotification(err);
|
APP.store.dispatch(notifyMicError(err));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
16
doc/api.md
16
doc/api.md
|
@ -264,6 +264,14 @@ The `event` parameter is a String object with the name of the event.
|
||||||
The `listener` parameter is a Function object with one argument that will be notified when the event occurs with data related to the event.
|
The `listener` parameter is a Function object with one argument that will be notified when the event occurs with data related to the event.
|
||||||
|
|
||||||
The following events are currently supported:
|
The following events are currently supported:
|
||||||
|
* **cameraError** - event notifications about Jitsi-Meet having failed to access the camera. The listener will receive an object with the following structure:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
type: string, // A constant representing the overall type of the error.
|
||||||
|
message: string // Additional information about the error.
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
* **avatarChanged** - event notifications about avatar
|
* **avatarChanged** - event notifications about avatar
|
||||||
changes. The listener will receive an object with the following structure:
|
changes. The listener will receive an object with the following structure:
|
||||||
```javascript
|
```javascript
|
||||||
|
@ -287,6 +295,14 @@ changes. The listener will receive an object with the following structure:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
* **micError** - event notifications about Jitsi-Meet having failed to access the mic. The listener will receive an object with the following structure:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
type: string, // A constant representing the overall type of the error.
|
||||||
|
message: string // Additional information about the error.
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
* **screenSharingStatusChanged** - receives event notifications about turning on/off the local user screen sharing. The listener will receive object with the following structure:
|
* **screenSharingStatusChanged** - receives event notifications about turning on/off the local user screen sharing. The listener will receive object with the following structure:
|
||||||
```javascript
|
```javascript
|
||||||
{
|
{
|
||||||
|
|
|
@ -559,6 +559,38 @@ class API {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify external application of an unexpected camera-related error having
|
||||||
|
* occurred.
|
||||||
|
*
|
||||||
|
* @param {string} type - The type of the camera error.
|
||||||
|
* @param {string} message - Additional information about the error.
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
notifyOnCameraError(type: string, message: string) {
|
||||||
|
this._sendEvent({
|
||||||
|
name: 'camera-error',
|
||||||
|
type,
|
||||||
|
message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify external application of an unexpected mic-related error having
|
||||||
|
* occurred.
|
||||||
|
*
|
||||||
|
* @param {string} type - The type of the mic error.
|
||||||
|
* @param {string} message - Additional information about the error.
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
notifyOnMicError(type: string, message: string) {
|
||||||
|
this._sendEvent({
|
||||||
|
name: 'mic-error',
|
||||||
|
type,
|
||||||
|
message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify external application (if API is enabled) that conference feedback
|
* Notify external application (if API is enabled) that conference feedback
|
||||||
* has been submitted. Intended to be used in conjunction with the
|
* has been submitted. Intended to be used in conjunction with the
|
||||||
|
|
|
@ -51,6 +51,7 @@ const events = {
|
||||||
'avatar-changed': 'avatarChanged',
|
'avatar-changed': 'avatarChanged',
|
||||||
'audio-availability-changed': 'audioAvailabilityChanged',
|
'audio-availability-changed': 'audioAvailabilityChanged',
|
||||||
'audio-mute-status-changed': 'audioMuteStatusChanged',
|
'audio-mute-status-changed': 'audioMuteStatusChanged',
|
||||||
|
'camera-error': 'cameraError',
|
||||||
'device-list-changed': 'deviceListChanged',
|
'device-list-changed': 'deviceListChanged',
|
||||||
'display-name-change': 'displayNameChange',
|
'display-name-change': 'displayNameChange',
|
||||||
'email-change': 'emailChange',
|
'email-change': 'emailChange',
|
||||||
|
@ -58,6 +59,7 @@ const events = {
|
||||||
'feedback-prompt-displayed': 'feedbackPromptDisplayed',
|
'feedback-prompt-displayed': 'feedbackPromptDisplayed',
|
||||||
'filmstrip-display-changed': 'filmstripDisplayChanged',
|
'filmstrip-display-changed': 'filmstripDisplayChanged',
|
||||||
'incoming-message': 'incomingMessage',
|
'incoming-message': 'incomingMessage',
|
||||||
|
'mic-error': 'micError',
|
||||||
'outgoing-message': 'outgoingMessage',
|
'outgoing-message': 'outgoingMessage',
|
||||||
'participant-joined': 'participantJoined',
|
'participant-joined': 'participantJoined',
|
||||||
'participant-left': 'participantLeft',
|
'participant-left': 'participantLeft',
|
||||||
|
|
|
@ -13,16 +13,12 @@ import SharedVideoManager from './shared_video/SharedVideo';
|
||||||
import VideoLayout from './videolayout/VideoLayout';
|
import VideoLayout from './videolayout/VideoLayout';
|
||||||
import Filmstrip from './videolayout/Filmstrip';
|
import Filmstrip from './videolayout/Filmstrip';
|
||||||
|
|
||||||
import { JitsiTrackErrors } from '../../react/features/base/lib-jitsi-meet';
|
|
||||||
import { getLocalParticipant } from '../../react/features/base/participants';
|
import { getLocalParticipant } from '../../react/features/base/participants';
|
||||||
import { toggleChat } from '../../react/features/chat';
|
import { toggleChat } from '../../react/features/chat';
|
||||||
import { openDisplayNamePrompt } from '../../react/features/display-name';
|
import { openDisplayNamePrompt } from '../../react/features/display-name';
|
||||||
import { setEtherpadHasInitialzied } from '../../react/features/etherpad';
|
import { setEtherpadHasInitialzied } from '../../react/features/etherpad';
|
||||||
import { setFilmstripVisible } from '../../react/features/filmstrip';
|
import { setFilmstripVisible } from '../../react/features/filmstrip';
|
||||||
import {
|
import { setNotificationsEnabled } from '../../react/features/notifications';
|
||||||
setNotificationsEnabled,
|
|
||||||
showWarningNotification
|
|
||||||
} from '../../react/features/notifications';
|
|
||||||
import {
|
import {
|
||||||
dockToolbox,
|
dockToolbox,
|
||||||
setToolboxEnabled,
|
setToolboxEnabled,
|
||||||
|
@ -40,39 +36,6 @@ UI.eventEmitter = eventEmitter;
|
||||||
let etherpadManager;
|
let etherpadManager;
|
||||||
let sharedVideoManager;
|
let sharedVideoManager;
|
||||||
|
|
||||||
const JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP = {
|
|
||||||
microphone: {},
|
|
||||||
camera: {}
|
|
||||||
};
|
|
||||||
|
|
||||||
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP
|
|
||||||
.camera[JitsiTrackErrors.UNSUPPORTED_RESOLUTION]
|
|
||||||
= 'dialog.cameraUnsupportedResolutionError';
|
|
||||||
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[JitsiTrackErrors.GENERAL]
|
|
||||||
= 'dialog.cameraUnknownError';
|
|
||||||
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[JitsiTrackErrors.PERMISSION_DENIED]
|
|
||||||
= 'dialog.cameraPermissionDeniedError';
|
|
||||||
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[JitsiTrackErrors.NOT_FOUND]
|
|
||||||
= 'dialog.cameraNotFoundError';
|
|
||||||
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[JitsiTrackErrors.CONSTRAINT_FAILED]
|
|
||||||
= 'dialog.cameraConstraintFailedError';
|
|
||||||
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP
|
|
||||||
.camera[JitsiTrackErrors.NO_DATA_FROM_SOURCE]
|
|
||||||
= 'dialog.cameraNotSendingData';
|
|
||||||
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.microphone[JitsiTrackErrors.GENERAL]
|
|
||||||
= 'dialog.micUnknownError';
|
|
||||||
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP
|
|
||||||
.microphone[JitsiTrackErrors.PERMISSION_DENIED]
|
|
||||||
= 'dialog.micPermissionDeniedError';
|
|
||||||
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.microphone[JitsiTrackErrors.NOT_FOUND]
|
|
||||||
= 'dialog.micNotFoundError';
|
|
||||||
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP
|
|
||||||
.microphone[JitsiTrackErrors.CONSTRAINT_FAILED]
|
|
||||||
= 'dialog.micConstraintFailedError';
|
|
||||||
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP
|
|
||||||
.microphone[JitsiTrackErrors.NO_DATA_FROM_SOURCE]
|
|
||||||
= 'dialog.micNotSendingData';
|
|
||||||
|
|
||||||
const UIListeners = new Map([
|
const UIListeners = new Map([
|
||||||
[
|
[
|
||||||
UIEvents.ETHERPAD_CLICKED,
|
UIEvents.ETHERPAD_CLICKED,
|
||||||
|
@ -774,65 +737,6 @@ UI.showExtensionInlineInstallationDialog = function(callback) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows a notifications about the passed in microphone error.
|
|
||||||
*
|
|
||||||
* @param {JitsiTrackError} micError - An error object related to using or
|
|
||||||
* acquiring an audio stream.
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
UI.showMicErrorNotification = function(micError) {
|
|
||||||
if (!micError) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { message, name } = micError;
|
|
||||||
|
|
||||||
const micJitsiTrackErrorMsg
|
|
||||||
= JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.microphone[name];
|
|
||||||
const micErrorMsg = micJitsiTrackErrorMsg
|
|
||||||
|| JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP
|
|
||||||
.microphone[JitsiTrackErrors.GENERAL];
|
|
||||||
const additionalMicErrorMsg = micJitsiTrackErrorMsg ? null : message;
|
|
||||||
|
|
||||||
APP.store.dispatch(showWarningNotification({
|
|
||||||
description: additionalMicErrorMsg,
|
|
||||||
descriptionKey: micErrorMsg,
|
|
||||||
titleKey: name === JitsiTrackErrors.PERMISSION_DENIED
|
|
||||||
? 'deviceError.microphonePermission'
|
|
||||||
: 'deviceError.microphoneError'
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows a notifications about the passed in camera error.
|
|
||||||
*
|
|
||||||
* @param {JitsiTrackError} cameraError - An error object related to using or
|
|
||||||
* acquiring a video stream.
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
UI.showCameraErrorNotification = function(cameraError) {
|
|
||||||
if (!cameraError) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { message, name } = cameraError;
|
|
||||||
|
|
||||||
const cameraJitsiTrackErrorMsg
|
|
||||||
= JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[name];
|
|
||||||
const cameraErrorMsg = cameraJitsiTrackErrorMsg
|
|
||||||
|| JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP
|
|
||||||
.camera[JitsiTrackErrors.GENERAL];
|
|
||||||
const additionalCameraErrorMsg = cameraJitsiTrackErrorMsg ? null : message;
|
|
||||||
|
|
||||||
APP.store.dispatch(showWarningNotification({
|
|
||||||
description: additionalCameraErrorMsg,
|
|
||||||
descriptionKey: cameraErrorMsg,
|
|
||||||
titleKey: name === JitsiTrackErrors.PERMISSION_DENIED
|
|
||||||
? 'deviceError.cameraPermission' : 'deviceError.cameraError'
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows error dialog that informs the user that no data is received from the
|
* Shows error dialog that informs the user that no data is received from the
|
||||||
* device.
|
* device.
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
/* global APP, JitsiMeetJS */
|
/* global APP, JitsiMeetJS */
|
||||||
|
|
||||||
import { getAudioOutputDeviceId } from '../../react/features/base/devices';
|
import {
|
||||||
|
getAudioOutputDeviceId,
|
||||||
|
notifyCameraError,
|
||||||
|
notifyMicError
|
||||||
|
} from '../../react/features/base/devices';
|
||||||
import {
|
import {
|
||||||
getUserSelectedCameraDeviceId,
|
getUserSelectedCameraDeviceId,
|
||||||
getUserSelectedMicDeviceId,
|
getUserSelectedMicDeviceId,
|
||||||
|
@ -176,11 +180,11 @@ export default {
|
||||||
]))
|
]))
|
||||||
.then(tracks => {
|
.then(tracks => {
|
||||||
if (audioTrackError) {
|
if (audioTrackError) {
|
||||||
APP.UI.showMicErrorNotification(audioTrackError);
|
APP.store.dispatch(notifyMicError(audioTrackError));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (videoTrackError) {
|
if (videoTrackError) {
|
||||||
APP.UI.showCameraErrorNotification(videoTrackError);
|
APP.store.dispatch(notifyCameraError(videoTrackError));
|
||||||
}
|
}
|
||||||
|
|
||||||
return tracks.filter(t => typeof t !== 'undefined');
|
return tracks.filter(t => typeof t !== 'undefined');
|
||||||
|
@ -205,7 +209,7 @@ export default {
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
audioTrackError = err;
|
audioTrackError = err;
|
||||||
showError && APP.UI.showMicErrorNotification(err);
|
showError && APP.store.disptach(notifyMicError(err));
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
}));
|
}));
|
||||||
|
@ -223,7 +227,7 @@ export default {
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
videoTrackError = err;
|
videoTrackError = err;
|
||||||
showError && APP.UI.showCameraErrorNotification(err);
|
showError && APP.store.dispatch(notifyCameraError(err));
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -6,6 +6,7 @@ import React from 'react';
|
||||||
import { DialogContainer } from '../../base/dialog';
|
import { DialogContainer } from '../../base/dialog';
|
||||||
import '../../base/responsive-ui';
|
import '../../base/responsive-ui';
|
||||||
import '../../chat';
|
import '../../chat';
|
||||||
|
import '../../external-api';
|
||||||
import '../../room-lock';
|
import '../../room-lock';
|
||||||
import '../../video-layout';
|
import '../../video-layout';
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,25 @@
|
||||||
|
/**
|
||||||
|
* The type of Redux action which signals that an error occurred while obtaining
|
||||||
|
* a camera.
|
||||||
|
*
|
||||||
|
* {
|
||||||
|
* type: NOTIFY_CAMERA_ERROR,
|
||||||
|
* error: Object
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
export const NOTIFY_CAMERA_ERROR = 'NOTIFY_CAMERA_ERROR';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of Redux action which signals that an error occurred while obtaining
|
||||||
|
* a microphone.
|
||||||
|
*
|
||||||
|
* {
|
||||||
|
* type: NOTIFY_MIC_ERROR,
|
||||||
|
* error: Object
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
export const NOTIFY_MIC_ERROR = 'NOTIFY_MIC_ERROR';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of Redux action which signals that the currently used audio
|
* The type of Redux action which signals that the currently used audio
|
||||||
* input device should be changed.
|
* input device should be changed.
|
||||||
|
|
|
@ -7,6 +7,8 @@ import {
|
||||||
import {
|
import {
|
||||||
ADD_PENDING_DEVICE_REQUEST,
|
ADD_PENDING_DEVICE_REQUEST,
|
||||||
CHECK_AND_NOTIFY_FOR_NEW_DEVICE,
|
CHECK_AND_NOTIFY_FOR_NEW_DEVICE,
|
||||||
|
NOTIFY_CAMERA_ERROR,
|
||||||
|
NOTIFY_MIC_ERROR,
|
||||||
REMOVE_PENDING_DEVICE_REQUESTS,
|
REMOVE_PENDING_DEVICE_REQUESTS,
|
||||||
SET_AUDIO_INPUT_DEVICE,
|
SET_AUDIO_INPUT_DEVICE,
|
||||||
SET_VIDEO_INPUT_DEVICE,
|
SET_VIDEO_INPUT_DEVICE,
|
||||||
|
@ -148,6 +150,43 @@ export function getAvailableDevices() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signals that an error occurred while trying to obtain a track from a camera.
|
||||||
|
*
|
||||||
|
* @param {Object} error - The device error, as provided by lib-jitsi-meet.
|
||||||
|
* @param {string} error.name - The constant for the type of the error.
|
||||||
|
* @param {string} error.message - Optional additional information about the
|
||||||
|
* error.
|
||||||
|
* @returns {{
|
||||||
|
* type: NOTIFY_CAMERA_ERROR,
|
||||||
|
* error: Object
|
||||||
|
* }}
|
||||||
|
*/
|
||||||
|
export function notifyCameraError(error) {
|
||||||
|
return {
|
||||||
|
type: NOTIFY_CAMERA_ERROR,
|
||||||
|
error
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signals that an error occurred while trying to obtain a track from a mic.
|
||||||
|
*
|
||||||
|
* @param {Object} error - The device error, as provided by lib-jitsi-meet.
|
||||||
|
* @param {Object} error.name - The constant for the type of the error.
|
||||||
|
* @param {string} error.message - Optional additional information about the
|
||||||
|
* error.
|
||||||
|
* @returns {{
|
||||||
|
* type: NOTIFY_MIC_ERROR,
|
||||||
|
* error: Object
|
||||||
|
* }}
|
||||||
|
*/
|
||||||
|
export function notifyMicError(error) {
|
||||||
|
return {
|
||||||
|
type: NOTIFY_MIC_ERROR,
|
||||||
|
error
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove all pending device requests.
|
* Remove all pending device requests.
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { CONFERENCE_JOINED } from '../conference';
|
||||||
import { processExternalDeviceRequest } from '../../device-selection';
|
import { processExternalDeviceRequest } from '../../device-selection';
|
||||||
import { MiddlewareRegistry } from '../redux';
|
import { MiddlewareRegistry } from '../redux';
|
||||||
import UIEvents from '../../../../service/UI/UIEvents';
|
import UIEvents from '../../../../service/UI/UIEvents';
|
||||||
|
import { JitsiTrackErrors } from '../lib-jitsi-meet';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
removePendingDeviceRequests,
|
removePendingDeviceRequests,
|
||||||
|
@ -12,15 +13,35 @@ import {
|
||||||
} from './actions';
|
} from './actions';
|
||||||
import {
|
import {
|
||||||
CHECK_AND_NOTIFY_FOR_NEW_DEVICE,
|
CHECK_AND_NOTIFY_FOR_NEW_DEVICE,
|
||||||
|
NOTIFY_CAMERA_ERROR,
|
||||||
|
NOTIFY_MIC_ERROR,
|
||||||
SET_AUDIO_INPUT_DEVICE,
|
SET_AUDIO_INPUT_DEVICE,
|
||||||
SET_VIDEO_INPUT_DEVICE
|
SET_VIDEO_INPUT_DEVICE
|
||||||
} from './actionTypes';
|
} from './actionTypes';
|
||||||
import { showNotification } from '../../notifications';
|
import { showNotification, showWarningNotification } from '../../notifications';
|
||||||
import { updateSettings } from '../settings';
|
import { updateSettings } from '../settings';
|
||||||
import { setAudioOutputDeviceId } from './functions';
|
import { setAudioOutputDeviceId } from './functions';
|
||||||
|
|
||||||
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||||
|
|
||||||
|
const JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP = {
|
||||||
|
microphone: {
|
||||||
|
[JitsiTrackErrors.CONSTRAINT_FAILED]: 'dialog.micConstraintFailedError',
|
||||||
|
[JitsiTrackErrors.GENERAL]: 'dialog.micUnknownError',
|
||||||
|
[JitsiTrackErrors.NO_DATA_FROM_SOURCE]: 'dialog.micNotSendingData',
|
||||||
|
[JitsiTrackErrors.NOT_FOUND]: 'dialog.micNotFoundError',
|
||||||
|
[JitsiTrackErrors.PERMISSION_DENIED]: 'dialog.micPermissionDeniedError'
|
||||||
|
},
|
||||||
|
camera: {
|
||||||
|
[JitsiTrackErrors.CONSTRAINT_FAILED]: 'dialog.cameraConstraintFailedError',
|
||||||
|
[JitsiTrackErrors.GENERAL]: 'dialog.cameraUnknownError',
|
||||||
|
[JitsiTrackErrors.NO_DATA_FROM_SOURCE]: 'dialog.cameraNotSendingData',
|
||||||
|
[JitsiTrackErrors.NOT_FOUND]: 'dialog.cameraNotFoundError',
|
||||||
|
[JitsiTrackErrors.PERMISSION_DENIED]: 'dialog.cameraPermissionDeniedError',
|
||||||
|
[JitsiTrackErrors.UNSUPPORTED_RESOLUTION]: 'dialog.cameraUnsupportedResolutionError'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements the middleware of the feature base/devices.
|
* Implements the middleware of the feature base/devices.
|
||||||
*
|
*
|
||||||
|
@ -32,6 +53,53 @@ MiddlewareRegistry.register(store => next => action => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case CONFERENCE_JOINED:
|
case CONFERENCE_JOINED:
|
||||||
return _conferenceJoined(store, next, action);
|
return _conferenceJoined(store, next, action);
|
||||||
|
case NOTIFY_CAMERA_ERROR: {
|
||||||
|
if (typeof APP !== 'object' || !action.error) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { message, name } = action.error;
|
||||||
|
|
||||||
|
const cameraJitsiTrackErrorMsg
|
||||||
|
= JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[name];
|
||||||
|
const cameraErrorMsg = cameraJitsiTrackErrorMsg
|
||||||
|
|| JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP
|
||||||
|
.camera[JitsiTrackErrors.GENERAL];
|
||||||
|
const additionalCameraErrorMsg = cameraJitsiTrackErrorMsg ? null : message;
|
||||||
|
|
||||||
|
store.dispatch(showWarningNotification({
|
||||||
|
description: additionalCameraErrorMsg,
|
||||||
|
descriptionKey: cameraErrorMsg,
|
||||||
|
titleKey: name === JitsiTrackErrors.PERMISSION_DENIED
|
||||||
|
? 'deviceError.cameraPermission' : 'deviceError.cameraError'
|
||||||
|
}));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NOTIFY_MIC_ERROR: {
|
||||||
|
if (typeof APP !== 'object' || !action.error) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { message, name } = action.error;
|
||||||
|
|
||||||
|
const micJitsiTrackErrorMsg
|
||||||
|
= JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.microphone[name];
|
||||||
|
const micErrorMsg = micJitsiTrackErrorMsg
|
||||||
|
|| JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP
|
||||||
|
.microphone[JitsiTrackErrors.GENERAL];
|
||||||
|
const additionalMicErrorMsg = micJitsiTrackErrorMsg ? null : message;
|
||||||
|
|
||||||
|
store.dispatch(showWarningNotification({
|
||||||
|
description: additionalMicErrorMsg,
|
||||||
|
descriptionKey: micErrorMsg,
|
||||||
|
titleKey: name === JitsiTrackErrors.PERMISSION_DENIED
|
||||||
|
? 'deviceError.microphonePermission'
|
||||||
|
: 'deviceError.microphoneError'
|
||||||
|
}));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
case SET_AUDIO_INPUT_DEVICE:
|
case SET_AUDIO_INPUT_DEVICE:
|
||||||
APP.UI.emitEvent(UIEvents.AUDIO_DEVICE_CHANGED, action.deviceId);
|
APP.UI.emitEvent(UIEvents.AUDIO_DEVICE_CHANGED, action.deviceId);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
import './middleware';
|
|
@ -0,0 +1,30 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import { NOTIFY_CAMERA_ERROR, NOTIFY_MIC_ERROR } from '../base/devices';
|
||||||
|
import { MiddlewareRegistry } from '../base/redux';
|
||||||
|
|
||||||
|
declare var APP: Object;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The middleware of the feature {@code external-api}.
|
||||||
|
*
|
||||||
|
* @returns {Function}
|
||||||
|
*/
|
||||||
|
MiddlewareRegistry.register((/* store */) => next => action => {
|
||||||
|
switch (action.type) {
|
||||||
|
case NOTIFY_CAMERA_ERROR:
|
||||||
|
if (action.error) {
|
||||||
|
APP.API.notifyOnCameraError(
|
||||||
|
action.error.name, action.error.message);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NOTIFY_MIC_ERROR:
|
||||||
|
if (action.error) {
|
||||||
|
APP.API.notifyOnMicError(action.error.name, action.error.message);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return next(action);
|
||||||
|
});
|
Loading…
Reference in New Issue