/* * Wire * Copyright (C) 2021 Wire Swiss GmbH * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. * */ import React, {useEffect, useRef, useState} from 'react'; import * as Icon from 'Components/Icon'; import {MediaDeviceType} from 'src/script/media/MediaDeviceType'; import {useKoSubscribableChildren} from 'Util/ComponentUtil'; import {t} from 'Util/LocalizerUtil'; import {getLogger} from 'Util/Logger'; import {DeviceSelect} from './DeviceSelect'; import {Config} from '../../../../../Config'; import {MediaDevicesHandler} from '../../../../../media/MediaDevicesHandler'; import {MediaStreamHandler} from '../../../../../media/MediaStreamHandler'; import {MediaType} from '../../../../../media/MediaType'; import {PreferencesSection} from '../components/PreferencesSection'; const logger = getLogger('CameraPreferences'); interface CameraPreferencesProps { devicesHandler: MediaDevicesHandler; hasActiveCameraStream: boolean; refreshStream: () => Promise; streamHandler: MediaStreamHandler; } const CameraPreferences: React.FC = ({ devicesHandler, streamHandler, refreshStream, hasActiveCameraStream, }) => { const [isRequesting, setIsRequesting] = useState(false); const [stream, setStream] = useState(null); const videoElement = useRef(null); const {[MediaDeviceType.VIDEO_INPUT]: availableDevices} = useKoSubscribableChildren( devicesHandler?.availableDevices, [MediaDeviceType.VIDEO_INPUT], ); const {[MediaDeviceType.VIDEO_INPUT]: currentDeviceId} = useKoSubscribableChildren(devicesHandler?.currentDeviceId, [ MediaDeviceType.VIDEO_INPUT, ]); const {URL: urls, BRAND_NAME: brandName} = Config.getConfig(); const requestStream = async () => { setIsRequesting(true); try { // we should be able to change camera from preferences page in middle of the call if (hasActiveCameraStream) { const refreshedStream = await refreshStream(); if (!refreshedStream) { throw new Error('No stream returned'); } setStream(refreshedStream); } else { const stream = await streamHandler.requestMediaStream(false, true, false, false); if (!stream) { throw new Error('No stream returned'); } setStream(stream); } } catch (error) { logger.warn(`Requesting MediaStream for type "${MediaType.VIDEO}" failed: ${error.message}`, error); setStream(null); } finally { setIsRequesting(false); } }; useEffect(() => { requestStream(); }, [currentDeviceId]); useEffect(() => { if (videoElement.current && stream) { videoElement.current.srcObject = stream; } }, [stream]); useEffect( () => () => { if (stream && !hasActiveCameraStream) { streamHandler.releaseTracksFromStream(stream); } }, [stream], ); return ( {!stream && !isRequesting && ( )} devicesHandler.currentDeviceId[MediaDeviceType.VIDEO_INPUT](deviceId)} title={t('preferencesAVCamera')} /> {isRequesting ? (