Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Persist audio and video mute state in video rooms #8376

Merged
merged 2 commits into from
Apr 21, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions src/components/views/voip/VideoLobby.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import { Room } from "matrix-js-sdk/src/models/room";

import { _t } from "../../../languageHandler";
import { useAsyncMemo } from "../../../hooks/useAsyncMemo";
import { useStateToggle } from "../../../hooks/useStateToggle";
import { useConnectedMembers } from "../../../utils/VideoChannelUtils";
import VideoChannelStore from "../../../stores/VideoChannelStore";
import IconizedContextMenu, {
Expand Down Expand Up @@ -108,6 +107,7 @@ const DeviceButton: FC<IDeviceButtonProps> = ({
const MAX_FACES = 8;

const VideoLobby: FC<{ room: Room }> = ({ room }) => {
const store = VideoChannelStore.instance;
const [connecting, setConnecting] = useState(false);
const me = useMemo(() => room.getMember(room.myUserId), [room]);
const connectedMembers = useConnectedMembers(room.currentState);
Expand All @@ -130,8 +130,16 @@ const VideoLobby: FC<{ room: Room }> = ({ room }) => {
const audioDevice = selectedAudioDevice ?? audioDevices[0];
const videoDevice = selectedVideoDevice ?? videoDevices[0];

const [audioActive, toggleAudio] = useStateToggle(true);
const [videoActive, toggleVideo] = useStateToggle(true);
const [audioActive, setAudioActive] = useState(!store.audioMuted);
const [videoActive, setVideoActive] = useState(!store.videoMuted);
const toggleAudio = () => {
store.audioMuted = audioActive;
setAudioActive(!audioActive);
};
const toggleVideo = () => {
store.videoMuted = videoActive;
setVideoActive(!videoActive);
};

const videoStream = useAsyncMemo(async () => {
if (videoDevice && videoActive) {
Expand Down Expand Up @@ -162,7 +170,7 @@ const VideoLobby: FC<{ room: Room }> = ({ room }) => {
const connect = async () => {
setConnecting(true);
try {
await VideoChannelStore.instance.connect(
await store.connect(
room.roomId, audioActive ? audioDevice : null, videoActive ? videoDevice : null,
);
} catch (e) {
Expand Down
44 changes: 43 additions & 1 deletion src/stores/VideoChannelStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,20 @@ export default class VideoChannelStore extends AsyncStoreWithClient<null> {
public get participants(): IJitsiParticipant[] { return this._participants; }
private set participants(value: IJitsiParticipant[]) { this._participants = value; }

private _audioMuted = localStorage.getItem("mx_audioMuted") === "true";
public get audioMuted(): boolean { return this._audioMuted; }
public set audioMuted(value: boolean) {
this._audioMuted = value;
localStorage.setItem("mx_audioMuted", value.toString());
}

private _videoMuted = localStorage.getItem("mx_videoMuted") === "true";
public get videoMuted(): boolean { return this._videoMuted; }
public set videoMuted(value: boolean) {
this._videoMuted = value;
localStorage.setItem("mx_videoMuted", value.toString());
}

public connect = async (roomId: string, audioDevice: MediaDeviceInfo, videoDevice: MediaDeviceInfo) => {
if (this.activeChannel) await this.disconnect();

Expand Down Expand Up @@ -136,10 +150,14 @@ export default class VideoChannelStore extends AsyncStoreWithClient<null> {
}
}

// Participant data and mute state will come down the event pipeline quickly, so prepare in advance
this.activeChannel = messaging;
this.roomId = roomId;
// Participant data will come down the event pipeline quickly, so prepare in advance
messaging.on(`action:${ElementWidgetActions.CallParticipants}`, this.onParticipants);
messaging.on(`action:${ElementWidgetActions.MuteAudio}`, this.onMuteAudio);
messaging.on(`action:${ElementWidgetActions.UnmuteAudio}`, this.onUnmuteAudio);
messaging.on(`action:${ElementWidgetActions.MuteVideo}`, this.onMuteVideo);
messaging.on(`action:${ElementWidgetActions.UnmuteVideo}`, this.onUnmuteVideo);

this.emit(VideoChannelEvent.StartConnect, roomId);

Expand All @@ -163,6 +181,10 @@ export default class VideoChannelStore extends AsyncStoreWithClient<null> {
this.activeChannel = null;
this.roomId = null;
messaging.off(`action:${ElementWidgetActions.CallParticipants}`, this.onParticipants);
messaging.off(`action:${ElementWidgetActions.MuteAudio}`, this.onMuteAudio);
messaging.off(`action:${ElementWidgetActions.UnmuteAudio}`, this.onUnmuteAudio);
messaging.off(`action:${ElementWidgetActions.MuteVideo}`, this.onMuteVideo);
messaging.off(`action:${ElementWidgetActions.UnmuteVideo}`, this.onUnmuteVideo);

this.emit(VideoChannelEvent.Disconnect, roomId);

Expand Down Expand Up @@ -233,4 +255,24 @@ export default class VideoChannelStore extends AsyncStoreWithClient<null> {
this.emit(VideoChannelEvent.Participants, this.roomId, ev.detail.data.participants);
this.ack(ev);
};

private onMuteAudio = (ev: CustomEvent<IWidgetApiRequest>) => {
this.audioMuted = true;
this.ack(ev);
};

private onUnmuteAudio = (ev: CustomEvent<IWidgetApiRequest>) => {
this.audioMuted = false;
this.ack(ev);
};

private onMuteVideo = (ev: CustomEvent<IWidgetApiRequest>) => {
this.videoMuted = true;
this.ack(ev);
};

private onUnmuteVideo = (ev: CustomEvent<IWidgetApiRequest>) => {
this.videoMuted = false;
this.ack(ev);
};
}