Disable mute button if media is not yet available. (#1218)

---------

Signed-off-by: Timo K <toger5@hotmail.de>
This commit is contained in:
Timo
2023-07-10 12:26:47 +02:00
committed by GitHub
parent a3220afc32
commit 7b19980a83
3 changed files with 42 additions and 7 deletions

View File

@@ -61,6 +61,10 @@ limitations under the License.
outline: auto; outline: auto;
} }
.toolbarButton:disabled {
opacity: 0.55;
}
.toolbarButton, .toolbarButton,
.toolbarButtonSecondary { .toolbarButtonSecondary {
width: 50px; width: 50px;

View File

@@ -77,6 +77,7 @@ interface Props {
children: Element[]; children: Element[];
onPress: (e: PressEvent) => void; onPress: (e: PressEvent) => void;
onPressStart: (e: PressEvent) => void; onPressStart: (e: PressEvent) => void;
disabled: boolean;
// TODO: add all props for <Button> // TODO: add all props for <Button>
[index: string]: unknown; [index: string]: unknown;
} }

View File

@@ -66,10 +66,14 @@ export function VideoPreview({ matrixInfo, onUserChoicesChanged }: Props) {
const [videoEnabled, setVideoEnabled] = useState<boolean>(true); const [videoEnabled, setVideoEnabled] = useState<boolean>(true);
const [audioEnabled, setAudioEnabled] = useState<boolean>(true); const [audioEnabled, setAudioEnabled] = useState<boolean>(true);
// we store if the tracks are currently initializing to not show them as muted.
// showing them as muted while they are not yet available makes the buttons flicker undesirable during startup.
const [initializingVideo, setInitializingVideo] = useState<boolean>(true);
const [initializingAudio, setInitializingAudio] = useState<boolean>(true);
// The settings are updated as soon as the device changes. We wrap the settings value in a ref to store their initial value. // The settings are updated as soon as the device changes. We wrap the settings value in a ref to store their initial value.
// Not changing the device options prohibits the usePreviewTracks hook to recreate the tracks. // Not changing the device options prohibits the usePreviewTracks hook to recreate the tracks.
const initialDefaultDevices = useRef(useDefaultDevices()[0]); const initialDefaultDevices = useRef(useDefaultDevices()[0]);
const tracks = usePreviewTracks( const tracks = usePreviewTracks(
{ {
audio: { deviceId: initialDefaultDevices.current.audioinput }, audio: { deviceId: initialDefaultDevices.current.audioinput },
@@ -89,6 +93,7 @@ export function VideoPreview({ matrixInfo, onUserChoicesChanged }: Props) {
tracks?.filter((t) => t.kind === Track.Kind.Audio)[0] as LocalAudioTrack, tracks?.filter((t) => t.kind === Track.Kind.Audio)[0] as LocalAudioTrack,
[tracks] [tracks]
); );
// Only let the MediaDeviceSwitcher request permissions if a video track is already available. // Only let the MediaDeviceSwitcher request permissions if a video track is already available.
// Otherwise we would end up asking for permissions in usePreviewTracks and in useMediaDevicesSwitcher. // Otherwise we would end up asking for permissions in usePreviewTracks and in useMediaDevicesSwitcher.
const requestPermissions = !!videoTrack; const requestPermissions = !!videoTrack;
@@ -104,6 +109,12 @@ export function VideoPreview({ matrixInfo, onUserChoicesChanged }: Props) {
const videoEl = React.useRef(null); const videoEl = React.useRef(null);
// pretend the video is available until the initialization is over
const videoAvailableAndEndabled =
videoEnabled && (!!videoTrack || initializingVideo);
const audioAvailableAndEndabled =
audioEnabled && (!!videoTrack || initializingAudio);
useEffect(() => { useEffect(() => {
// Effect to update the settings // Effect to update the settings
const createChoices = ( const createChoices = (
@@ -118,8 +129,8 @@ export function VideoPreview({ matrixInfo, onUserChoicesChanged }: Props) {
: undefined; : undefined;
}; };
onUserChoicesChanged({ onUserChoicesChanged({
video: createChoices(videoEnabled, videoIn.selectedId), video: createChoices(videoAvailableAndEndabled, videoIn.selectedId),
audio: createChoices(audioEnabled, audioIn.selectedId), audio: createChoices(audioAvailableAndEndabled, audioIn.selectedId),
}); });
}, [ }, [
onUserChoicesChanged, onUserChoicesChanged,
@@ -127,11 +138,16 @@ export function VideoPreview({ matrixInfo, onUserChoicesChanged }: Props) {
videoEnabled, videoEnabled,
audioIn.selectedId, audioIn.selectedId,
audioEnabled, audioEnabled,
videoAvailableAndEndabled,
audioAvailableAndEndabled,
]); ]);
useEffect(() => { useEffect(() => {
// Effect to update the initial device selection for the ui elements based on the current preview track. // Effect to update the initial device selection for the ui elements based on the current preview track.
if (!videoIn.selectedId || videoIn.selectedId == "") { if (!videoIn.selectedId || videoIn.selectedId == "") {
if (videoTrack) {
setInitializingVideo(false);
}
videoTrack?.getDeviceId().then((videoId) => { videoTrack?.getDeviceId().then((videoId) => {
if (videoId) { if (videoId) {
videoIn.setSelected(videoId); videoIn.setSelected(videoId);
@@ -139,6 +155,9 @@ export function VideoPreview({ matrixInfo, onUserChoicesChanged }: Props) {
}); });
} }
if (!audioIn.selectedId || audioIn.selectedId == "") { if (!audioIn.selectedId || audioIn.selectedId == "") {
if (audioTrack) {
setInitializingAudio(false);
}
audioTrack?.getDeviceId().then((audioId) => { audioTrack?.getDeviceId().then((audioId) => {
if (audioId) { if (audioId) {
audioIn.setSelected(audioId); audioIn.setSelected(audioId);
@@ -158,6 +177,15 @@ export function VideoPreview({ matrixInfo, onUserChoicesChanged }: Props) {
}; };
}, [videoTrack]); }, [videoTrack]);
useEffect(() => {
// Effect to mute/unmute video track. (This has to be done, so that the hardware camera indicator does not confuse the user)
if (videoTrack && videoEnabled) {
videoTrack?.unmute();
} else if (videoTrack) {
videoTrack?.mute();
}
}, [videoEnabled, videoTrack]);
return ( return (
<div className={styles.preview} ref={previewRef}> <div className={styles.preview} ref={previewRef}>
<video ref={videoEl} muted playsInline disablePictureInPicture /> <video ref={videoEl} muted playsInline disablePictureInPicture />
@@ -173,12 +201,14 @@ export function VideoPreview({ matrixInfo, onUserChoicesChanged }: Props) {
)} )}
<div className={styles.previewButtons}> <div className={styles.previewButtons}>
<MicButton <MicButton
muted={!audioEnabled} muted={!audioAvailableAndEndabled}
onPress={() => setAudioEnabled(!audioEnabled)} onPress={() => setAudioEnabled(!audioAvailableAndEndabled)}
disabled={!audioTrack}
/> />
<VideoButton <VideoButton
muted={!videoEnabled} muted={!videoAvailableAndEndabled}
onPress={() => setVideoEnabled(!videoEnabled)} onPress={() => setVideoEnabled(!videoAvailableAndEndabled)}
disabled={!videoTrack}
/> />
<SettingsButton onPress={openSettings} /> <SettingsButton onPress={openSettings} />
</div> </div>