From 2281b1acd21c07575dad2bec18ed809bfaafb0f8 Mon Sep 17 00:00:00 2001 From: paweldomas Date: Wed, 28 Jun 2017 09:15:46 -0500 Subject: [PATCH] ref: enable/disable video button Dynamically enables/disables the toolbar video button. Prior to that commit if we would start with no video there would be no way to enable it later on. --- conference.js | 32 +++++++++++++-- modules/UI/UI.js | 13 ------ modules/devices/mediaDeviceHelper.js | 5 --- react/features/base/media/actionTypes.js | 10 +++++ react/features/base/media/actions.js | 18 +++++++++ react/features/base/media/reducer.js | 10 ++++- react/features/toolbox/actions.native.js | 21 ---------- react/features/toolbox/middleware.js | 50 ++++++++++++++++++++++++ 8 files changed, 116 insertions(+), 43 deletions(-) diff --git a/conference.js b/conference.js index 0dcef6c8e..5fb01f080 100644 --- a/conference.js +++ b/conference.js @@ -35,6 +35,9 @@ import { import { isFatalJitsiConnectionError } from './react/features/base/lib-jitsi-meet'; +import { + setVideoAvailable +} from './react/features/base/media'; import { localParticipantRoleChanged, MAX_DISPLAY_NAME_LENGTH, @@ -1036,15 +1039,13 @@ export default { this.isSharingScreen = newStream.videoType === 'desktop'; APP.UI.addLocalStream(newStream); - - newStream.videoType === 'camera' - && APP.UI.setCameraButtonEnabled(true); } else { // No video is treated the same way as being video muted this.videoMuted = true; this.isSharingScreen = false; } APP.UI.setVideoMuted(this.getMyUserId(), this.videoMuted); + this.updateVideoIconEnabled(); APP.UI.updateDesktopSharingButtons(); }); }, @@ -1953,6 +1954,7 @@ export default { mediaDeviceHelper.setCurrentMediaDevices(devices); APP.UI.onAvailableDevicesChanged(devices); APP.store.dispatch(updateDeviceList(devices)); + this.updateVideoIconEnabled(); }); this.deviceChangeListener = (devices) => @@ -2030,8 +2032,32 @@ export default { .then(() => { mediaDeviceHelper.setCurrentMediaDevices(devices); APP.UI.onAvailableDevicesChanged(devices); + this.updateVideoIconEnabled(); }); }, + /** + * Determines whether or not the video button should be enabled. + */ + updateVideoIconEnabled() { + const videoMediaDevices + = mediaDeviceHelper.getCurrentMediaDevices().videoinput; + const videoDeviceCount + = videoMediaDevices ? videoMediaDevices.length : 0; + // The video functionality is considered available if there are any + // video devices detected or if there is local video stream already + // active which could be either screensharing stream or a video track + // created before the permissions were rejected (through browser + // config). + const available = videoDeviceCount > 0 || Boolean(localVideo); + + logger.debug( + 'Camera button enabled: ' + available, + 'local video: ' + localVideo, + 'video devices: ' + videoMediaDevices, + 'device count: ' + videoDeviceCount); + + APP.store.dispatch(setVideoAvailable(available)); + }, /** * Toggles the local "raised hand" status. diff --git a/modules/UI/UI.js b/modules/UI/UI.js index 46f8cc374..723b500c0 100644 --- a/modules/UI/UI.js +++ b/modules/UI/UI.js @@ -34,7 +34,6 @@ import { dockToolbox, setAudioIconEnabled, setToolbarButton, - setVideoIconEnabled, showDialPadButton, showEtherpadButton, showSharedVideoButton, @@ -724,9 +723,6 @@ UI.setVideoMuted = function (id, muted) { VideoLayout.onVideoMute(id, muted); if (APP.conference.isLocalId(id)) { APP.store.dispatch(setVideoMuted(muted)); - APP.store.dispatch(setToolbarButton('camera', { - toggled: muted - })); } }; @@ -1341,15 +1337,6 @@ UI.onSharedVideoStop = function (id, attributes) { sharedVideoManager.onSharedVideoStop(id, attributes); }; -/** - * Enables / disables camera toolbar button. - * - * @param {boolean} enabled indicates if the camera button should be enabled - * or disabled - */ -UI.setCameraButtonEnabled - = enabled => APP.store.dispatch(setVideoIconEnabled(enabled)); - /** * Enables / disables microphone toolbar button. * diff --git a/modules/devices/mediaDeviceHelper.js b/modules/devices/mediaDeviceHelper.js index 77efeaae6..2a1d7c7ea 100644 --- a/modules/devices/mediaDeviceHelper.js +++ b/modules/devices/mediaDeviceHelper.js @@ -97,11 +97,6 @@ function getNewVideoInputDevice(newDevices, localVideo) { availableVideoInputDevices[0].label !== '') { return availableVideoInputDevices[0].deviceId; } - // Otherwise we assume that we don't have any video input devices - // to use and that's why disable microphone button on UI. - else { - APP.UI.setCameraButtonEnabled(false); - } } else { // And here we handle case when we already have some device working, // but we plug-in a "preferred" (previously selected in settings, stored diff --git a/react/features/base/media/actionTypes.js b/react/features/base/media/actionTypes.js index 10a8f791d..da9d5c820 100644 --- a/react/features/base/media/actionTypes.js +++ b/react/features/base/media/actionTypes.js @@ -19,6 +19,16 @@ export const SET_AUDIO_MUTED = Symbol('SET_AUDIO_MUTED'); */ export const SET_CAMERA_FACING_MODE = Symbol('SET_CAMERA_FACING_MODE'); +/** + * The type of (redux) action to adjust the availability of the local video. + * + * { + * type: SET_VIDEO_AVAILABLE, + * muted: boolean + * } + */ +export const SET_VIDEO_AVAILABLE = Symbol('SET_VIDEO_AVAILABLE'); + /** * The type of (redux) action to set the muted state of the local video. * diff --git a/react/features/base/media/actions.js b/react/features/base/media/actions.js index 8e4144a22..81ebb20c6 100644 --- a/react/features/base/media/actions.js +++ b/react/features/base/media/actions.js @@ -5,6 +5,7 @@ import type { Dispatch } from 'redux'; import { SET_AUDIO_MUTED, SET_CAMERA_FACING_MODE, + SET_VIDEO_AVAILABLE, SET_VIDEO_MUTED, TOGGLE_CAMERA_FACING_MODE } from './actionTypes'; @@ -43,6 +44,23 @@ export function setCameraFacingMode(cameraFacingMode: CAMERA_FACING_MODE) { }; } +/** + * Action to adjust the availability of the local video. + * + * @param {boolean} available - True if the local video is to be marked as + * available or false if the local video is not available. + * @returns {{ + * type: SET_VIDEO_AVAILABLE, + * available: boolean + * }} + */ +export function setVideoAvailable(available: boolean) { + return { + type: SET_VIDEO_AVAILABLE, + available + }; +} + /** * Action to set the muted state of the local video. * diff --git a/react/features/base/media/reducer.js b/react/features/base/media/reducer.js index 1e2f3142b..e673d7a2b 100644 --- a/react/features/base/media/reducer.js +++ b/react/features/base/media/reducer.js @@ -6,6 +6,7 @@ import { SET_AUDIO_MUTED, SET_CAMERA_FACING_MODE, SET_VIDEO_MUTED, + SET_VIDEO_AVAILABLE, TOGGLE_CAMERA_FACING_MODE } from './actionTypes'; import { CAMERA_FACING_MODE } from './constants'; @@ -63,7 +64,8 @@ function _audio(state = AUDIO_INITIAL_MEDIA_STATE, action) { */ const VIDEO_INITIAL_MEDIA_STATE = { facingMode: CAMERA_FACING_MODE.USER, - muted: false + muted: true, + available: true }; /** @@ -77,6 +79,12 @@ const VIDEO_INITIAL_MEDIA_STATE = { */ function _video(state = VIDEO_INITIAL_MEDIA_STATE, action) { switch (action.type) { + case SET_VIDEO_AVAILABLE: + return { + ...state, + available: action.available + }; + case SET_CAMERA_FACING_MODE: return { ...state, diff --git a/react/features/toolbox/actions.native.js b/react/features/toolbox/actions.native.js index 168dca127..6511c4190 100644 --- a/react/features/toolbox/actions.native.js +++ b/react/features/toolbox/actions.native.js @@ -225,27 +225,6 @@ export function setToolboxVisible(visible: boolean): Object { }; } -/** - * Enables/disables audio toolbar button. - * - * @param {boolean} enabled - True if the button should be enabled; otherwise, - * false. - * @returns {Function} - */ -export function setVideoIconEnabled(enabled: boolean = false): Function { - return (dispatch: Dispatch<*>) => { - const i18nKey = enabled ? 'videomute' : 'cameraDisabled'; - const i18n = `[content]toolbar.${i18nKey}`; - const button = { - enabled, - i18n, - toggled: !enabled - }; - - dispatch(setToolbarButton('camera', button)); - }; -} - /** * Shows etherpad button if it's not shown. * diff --git a/react/features/toolbox/middleware.js b/react/features/toolbox/middleware.js index 794bea9fa..c7050bfd8 100644 --- a/react/features/toolbox/middleware.js +++ b/react/features/toolbox/middleware.js @@ -7,6 +7,48 @@ import { SET_TOOLBOX_TIMEOUT } from './actionTypes'; +import { + SET_VIDEO_AVAILABLE, + SET_VIDEO_MUTED +} from '../../features/base/media/actionTypes'; + +import { + setToolbarButton +} from './actions'; + +/** + * Adjusts the state of toolbar's camera button. + * + * @param {Store} store - The Redux store instance. + * @param {Object} action - Either SET_VIDEO_AVAILABLE or SET_VIDEO_MUTED. + * + * @returns {*} + */ +function setCameraButton(store, action) { + const video = store.getState()['features/base/media'].video; + let available = video.available; + + if (typeof action.available === 'boolean') { + available = action.available; + } + + let muted = video.muted; + + if (typeof action.muted === 'boolean') { + muted = action.muted; + } + + const i18nKey = available ? 'videomute' : 'cameraDisabled'; + const i18n = `[content]toolbar.${i18nKey}`; + const button = { + enabled: available, + i18n, + toggled: available ? muted : true + }; + + store.dispatch(setToolbarButton('camera', button)); +} + /** * Middleware which intercepts Toolbox actions to handle changes to the * visibility timeout of the Toolbox. @@ -33,6 +75,14 @@ MiddlewareRegistry.register(store => next => action => { action.timeoutID = newTimeoutId; break; } + + case SET_VIDEO_AVAILABLE: + case SET_VIDEO_MUTED: { + setCameraButton(store, action); + break; + } + + } return next(action);