Anapher/Strive

View on GitHub
src/Web/WebSPA/Client/src/features/media/useDeviceManagement.ts

Summary

Maintainability
C
1 day
Test Coverage
import _ from 'lodash';
import { Dispatch, useEffect, useRef } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { sendEquipmentCommand } from 'src/core-hub';
import { EquipmentCommandAction } from 'src/equipment-hub.types';
import { RootState } from 'src/store';
import { UseMediaState } from 'src/store/webrtc/hooks/useMedia';
import { ProducerSource } from 'src/store/webrtc/types';
import { AnyInputDevice } from '../settings/types';
import { EquipmentConnection } from './types';

function wrapControl(
   source: ProducerSource,
   device: AnyInputDevice | undefined,
   local: UseMediaState,
   equipment: Record<string, EquipmentConnection> | undefined,
   dispatch: Dispatch<any>,
): UseMediaState {
   if (!device || device.type === 'local') {
      return local;
   } else {
      const equipmentInfo = equipment?.[device.connectionId]?.status?.[source] ?? {
         connected: false,
         enabled: false,
         paused: false,
      };

      const executeEquipmentCommand = (action: EquipmentCommandAction) => {
         dispatch(
            sendEquipmentCommand({ action, connectionId: device.connectionId, source, deviceId: device.deviceId }),
         );
      };

      return {
         enable: () => executeEquipmentCommand('enable'),
         disable: () => executeEquipmentCommand('disable'),
         pause: () => executeEquipmentCommand('pause'),
         resume: () => executeEquipmentCommand('resume'),
         switchDevice: (deviceId) => {
            dispatch(
               sendEquipmentCommand({
                  action: 'switchDevice',
                  connectionId: device.connectionId,
                  source,
                  deviceId,
               }),
            );
         },
         ...equipmentInfo,
      };
   }
}

export default function useDeviceManagement(
   source: ProducerSource,
   local: UseMediaState,
   device?: AnyInputDevice,
): UseMediaState {
   const currentDevice = useRef<AnyInputDevice | undefined>();
   const dispatch = useDispatch();
   const equipment = useSelector((state: RootState) => state.media.equipment?.connections);

   useEffect(() => {
      console.log('source', source);

      console.log('new device', device);
      console.log('previous device', currentDevice.current);

      if (_.isEqual(currentDevice.current, device)) return;

      const deviceType = device?.type || 'local'; // undefined device is default device locally
      const previousDeviceType = currentDevice.current?.type || 'local';

      // disable previous device
      if (previousDeviceType !== deviceType) {
         if (previousDeviceType === 'local') {
            local.disable();
            console.log('disable local device');
         } else if (currentDevice.current?.type === 'equipment') {
            console.log('disable remote device');

            dispatch(
               sendEquipmentCommand({
                  action: 'disable',
                  connectionId: currentDevice.current.connectionId,
                  source,
                  deviceId: currentDevice.current.deviceId,
               }),
            );
         }
      }

      if (device?.type === 'equipment') {
         dispatch(
            sendEquipmentCommand({
               action: 'switchDevice',
               connectionId: device.connectionId,
               source,
               deviceId: device.deviceId,
            }),
         );
      } else {
         local.switchDevice(device?.deviceId);
      }

      currentDevice.current = device;
   }, [device]);

   const controller = wrapControl(source, device, local, equipment, dispatch);

   useEffect(() => {
      return () => {
         if (currentDevice.current?.type === 'equipment') {
            console.log('unmount, disable equipment device');
            dispatch(
               sendEquipmentCommand({
                  action: 'disable',
                  connectionId: currentDevice.current.connectionId,
                  source,
                  deviceId: currentDevice.current.deviceId,
               }),
            );
         }
      };
   }, []);

   return controller;
}