import { IStore } from '../app/types'; import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app/actionTypes'; import { getWebHIDFeatureConfig } from '../base/config/functions.web'; import { SET_AUDIO_MUTED } from '../base/media/actionTypes'; import { isAudioMuted } from '../base/media/functions'; import MiddlewareRegistry from '../base/redux/MiddlewareRegistry'; import { CLOSE_HID_DEVICE, REQUEST_HID_DEVICE } from './actionTypes'; import { initDeviceInfo } from './actions'; import { attachHidEventListeners, getWebHidInstance, handleUpdateHidDevice, isDeviceHidSupported, removeHidEventListeners } from './functions'; import logger from './logger'; import { COMMANDS, IDeviceInfo } from './types'; /** * A listener for initialising the webhid device. */ let initDeviceListener: (e: any) => void; /** * A listener for updating the webhid device. */ let updateDeviceListener: (e: any) => void; /** * The redux middleware for {@link WebHid}. * * @param {Store} store - The redux store. * @returns {Function} */ MiddlewareRegistry.register((store: IStore) => next => action => { const { dispatch, getState } = store; if (!getWebHIDFeatureConfig(getState())) { return next(action); } switch (action.type) { case APP_WILL_MOUNT: { const hidManager = getWebHidInstance(); if (!hidManager.isSupported()) { logger.warn('HID is not supported'); break; } const _initDeviceListener = (e: CustomEvent<{ deviceInfo: IDeviceInfo; }>) => dispatch(initDeviceInfo(e.detail.deviceInfo)); const _updateDeviceListener = (e: CustomEvent<{ actionResult: { eventName: string; }; deviceInfo: IDeviceInfo; }>) => handleUpdateHidDevice(dispatch, e); initDeviceListener = _initDeviceListener; updateDeviceListener = _updateDeviceListener; hidManager.listenToConnectedHid(); attachHidEventListeners(initDeviceListener, updateDeviceListener); break; } case APP_WILL_UNMOUNT: { const hidManager = getWebHidInstance(); if (!isDeviceHidSupported()) { break; } removeHidEventListeners(initDeviceListener, updateDeviceListener); hidManager.close(); break; } case CLOSE_HID_DEVICE: { const hidManager = getWebHidInstance(); // cleanup event handlers when hid device is removed from Settings. removeHidEventListeners(initDeviceListener, updateDeviceListener); hidManager.close(); break; } case REQUEST_HID_DEVICE: { _onRequestHIDDevice(store); break; } case SET_AUDIO_MUTED: { const hidManager = getWebHidInstance(); if (!isDeviceHidSupported()) { break; } hidManager.sendDeviceReport({ command: action.muted ? COMMANDS.MUTE_ON : COMMANDS.MUTE_OFF }); break; } } return next(action); }); /** * Handles HID device requests. * * @param {IStore} store - The redux store. * @returns {Promise} */ async function _onRequestHIDDevice(store: IStore) { const { dispatch } = store; const hidManager = getWebHidInstance(); const availableDevices = await hidManager.requestHidDevices(); // eslint-disable-next-line @typescript-eslint/prefer-optional-chain if (!availableDevices || !availableDevices.length) { logger.info('HID device not available'); return; } const _initDeviceListener = (e: CustomEvent<{ deviceInfo: IDeviceInfo; }>) => dispatch(initDeviceInfo(e.detail.deviceInfo)); const _updateDeviceListener = (e: CustomEvent<{ actionResult: { eventName: string; }; deviceInfo: IDeviceInfo; }>) => { handleUpdateHidDevice(dispatch, e); }; initDeviceListener = _initDeviceListener; updateDeviceListener = _updateDeviceListener; attachHidEventListeners(initDeviceListener, updateDeviceListener); await hidManager.listenToConnectedHid(); // sync headset to mute if participant is already muted. if (isAudioMuted(store.getState())) { hidManager.sendDeviceReport({ command: COMMANDS.MUTE_ON }); } }