Don't show toolbar buttons on connecting tiles

Because connecting tiles don't have a feed, clicking the local volume button would cause a soft crash. This also fixes a few strict mode errors in the surrounding area while we're at it.
This commit is contained in:
Robin Townsend 2022-11-02 12:34:31 -04:00
parent 7b71e9b20f
commit 84a92845c3
5 changed files with 21 additions and 20 deletions

View file

@ -72,7 +72,7 @@ export const VideoTile = forwardRef<HTMLDivElement, Props>(
const { t } = useTranslation(); const { t } = useTranslation();
const toolbarButtons: JSX.Element[] = []; const toolbarButtons: JSX.Element[] = [];
if (!isLocal) { if (hasFeed && !isLocal) {
toolbarButtons.push( toolbarButtons.push(
<AudioButton <AudioButton
className={styles.button} className={styles.button}

View file

@ -68,7 +68,7 @@ export function VideoTileContainer({
} = useCallFeed(item.callFeed); } = useCallFeed(item.callFeed);
const { rawDisplayName } = useRoomMemberName(item.member); const { rawDisplayName } = useRoomMemberName(item.member);
const [tileRef, mediaRef] = useSpatialMediaStream( const [tileRef, mediaRef] = useSpatialMediaStream(
stream, stream ?? null,
audioContext, audioContext,
audioDestination, audioDestination,
isLocal, isLocal,
@ -109,7 +109,7 @@ export function VideoTileContainer({
onFullscreen={onFullscreenCallback} onFullscreen={onFullscreenCallback}
{...rest} {...rest}
/> />
{videoTileSettingsModalState.isOpen && !maximised && ( {videoTileSettingsModalState.isOpen && !maximised && item.callFeed && (
<VideoTileSettingsModal <VideoTileSettingsModal
{...videoTileSettingsModalProps} {...videoTileSettingsModalProps}
feed={item.callFeed} feed={item.callFeed}

View file

@ -18,7 +18,7 @@ import { RefObject, useEffect } from "react";
export function useAudioOutputDevice( export function useAudioOutputDevice(
mediaRef: RefObject<MediaElement>, mediaRef: RefObject<MediaElement>,
audioOutputDevice: string audioOutputDevice: string | undefined
): void { ): void {
useEffect(() => { useEffect(() => {
if ( if (

View file

@ -19,17 +19,18 @@ import { CallFeed, CallFeedEvent } from "matrix-js-sdk/src/webrtc/callFeed";
import { SDPStreamMetadataPurpose } from "matrix-js-sdk/src/webrtc/callEventTypes"; import { SDPStreamMetadataPurpose } from "matrix-js-sdk/src/webrtc/callEventTypes";
interface CallFeedState { interface CallFeedState {
callFeed: CallFeed; callFeed: CallFeed | undefined;
isLocal: boolean; isLocal: boolean;
speaking: boolean; speaking: boolean;
videoMuted: boolean; videoMuted: boolean;
audioMuted: boolean; audioMuted: boolean;
localVolume: number; localVolume: number;
disposed: boolean; disposed: boolean | undefined;
stream: MediaStream; stream: MediaStream | undefined;
purpose: SDPStreamMetadataPurpose; purpose: SDPStreamMetadataPurpose | undefined;
} }
function getCallFeedState(callFeed: CallFeed): CallFeedState {
function getCallFeedState(callFeed: CallFeed | undefined): CallFeedState {
return { return {
callFeed, callFeed,
isLocal: callFeed ? callFeed.isLocal() : false, isLocal: callFeed ? callFeed.isLocal() : false,
@ -43,7 +44,7 @@ function getCallFeedState(callFeed: CallFeed): CallFeedState {
}; };
} }
export function useCallFeed(callFeed: CallFeed): CallFeedState { export function useCallFeed(callFeed: CallFeed | undefined): CallFeedState {
const [state, setState] = useState<CallFeedState>(() => const [state, setState] = useState<CallFeedState>(() =>
getCallFeedState(callFeed) getCallFeedState(callFeed)
); );

View file

@ -64,8 +64,8 @@ export const useMediaStreamTrackCount = (
}; };
export const useMediaStream = ( export const useMediaStream = (
stream: MediaStream, stream: MediaStream | null,
audioOutputDevice: string, audioOutputDevice: string | null,
mute = false, mute = false,
localVolume?: number localVolume?: number
): RefObject<MediaElement> => { ): RefObject<MediaElement> => {
@ -158,7 +158,7 @@ const createLoopback = async (stream: MediaStream): Promise<MediaStream> => {
await loopbackConn.setRemoteDescription(offer); await loopbackConn.setRemoteDescription(offer);
const answer = await loopbackConn.createAnswer(); const answer = await loopbackConn.createAnswer();
// Rewrite SDP to be stereo and (variable) max bitrate // Rewrite SDP to be stereo and (variable) max bitrate
const parsedSdp = parseSdp(answer.sdp); const parsedSdp = parseSdp(answer.sdp!);
parsedSdp.media.forEach((m) => parsedSdp.media.forEach((m) =>
m.fmtp.forEach( m.fmtp.forEach(
(f) => (f.config += `;stereo=1;cbr=0;maxaveragebitrate=510000;`) (f) => (f.config += `;stereo=1;cbr=0;maxaveragebitrate=510000;`)
@ -206,11 +206,11 @@ export const useAudioContext = (): [
} }
}, []); }, []);
return [context.current, destination.current, audioRef]; return [context.current!, destination.current!, audioRef];
}; };
export const useSpatialMediaStream = ( export const useSpatialMediaStream = (
stream: MediaStream, stream: MediaStream | null,
audioContext: AudioContext, audioContext: AudioContext,
audioDestination: AudioNode, audioDestination: AudioNode,
mute = false, mute = false,
@ -219,7 +219,7 @@ export const useSpatialMediaStream = (
const tileRef = useRef<HTMLDivElement>(); const tileRef = useRef<HTMLDivElement>();
const [spatialAudio] = useSpatialAudio(); const [spatialAudio] = useSpatialAudio();
// We always handle audio separately form the video element // We always handle audio separately form the video element
const mediaRef = useMediaStream(stream, undefined, true, undefined); const mediaRef = useMediaStream(stream, null, true);
const [audioTrackCount] = useMediaStreamTrackCount(stream); const [audioTrackCount] = useMediaStreamTrackCount(stream);
const gainNodeRef = useRef<GainNode>(); const gainNodeRef = useRef<GainNode>();
@ -240,7 +240,7 @@ export const useSpatialMediaStream = (
}); });
} }
if (!sourceRef.current) { if (!sourceRef.current) {
sourceRef.current = audioContext.createMediaStreamSource(stream); sourceRef.current = audioContext.createMediaStreamSource(stream!);
} }
const tile = tileRef.current; const tile = tileRef.current;
@ -252,12 +252,12 @@ export const useSpatialMediaStream = (
const bounds = tile.getBoundingClientRect(); const bounds = tile.getBoundingClientRect();
const windowSize = Math.max(window.innerWidth, window.innerHeight); const windowSize = Math.max(window.innerWidth, window.innerHeight);
// Position the source relative to its placement in the window // Position the source relative to its placement in the window
pannerNodeRef.current.positionX.value = pannerNodeRef.current!.positionX.value =
(bounds.x + bounds.width / 2) / windowSize - 0.5; (bounds.x + bounds.width / 2) / windowSize - 0.5;
pannerNodeRef.current.positionY.value = pannerNodeRef.current!.positionY.value =
(bounds.y + bounds.height / 2) / windowSize - 0.5; (bounds.y + bounds.height / 2) / windowSize - 0.5;
// Put the source in front of the listener // Put the source in front of the listener
pannerNodeRef.current.positionZ.value = -2; pannerNodeRef.current!.positionZ.value = -2;
}; };
gainNode.gain.value = localVolume; gainNode.gain.value = localVolume;