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

Commit c70816d

Browse files
authored
Persist audio and video mute state in video rooms (#8376)
…so that video lobbies remember whether you've disabled your camera.
1 parent 6f59005 commit c70816d

File tree

2 files changed

+55
-5
lines changed

2 files changed

+55
-5
lines changed

src/components/views/voip/VideoLobby.tsx

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import { Room } from "matrix-js-sdk/src/models/room";
2121

2222
import { _t } from "../../../languageHandler";
2323
import { useAsyncMemo } from "../../../hooks/useAsyncMemo";
24-
import { useStateToggle } from "../../../hooks/useStateToggle";
2524
import { useConnectedMembers } from "../../../utils/VideoChannelUtils";
2625
import VideoChannelStore from "../../../stores/VideoChannelStore";
2726
import IconizedContextMenu, {
@@ -108,6 +107,7 @@ const DeviceButton: FC<IDeviceButtonProps> = ({
108107
const MAX_FACES = 8;
109108

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

133-
const [audioActive, toggleAudio] = useStateToggle(true);
134-
const [videoActive, toggleVideo] = useStateToggle(true);
133+
const [audioActive, setAudioActive] = useState(!store.audioMuted);
134+
const [videoActive, setVideoActive] = useState(!store.videoMuted);
135+
const toggleAudio = () => {
136+
store.audioMuted = audioActive;
137+
setAudioActive(!audioActive);
138+
};
139+
const toggleVideo = () => {
140+
store.videoMuted = videoActive;
141+
setVideoActive(!videoActive);
142+
};
135143

136144
const videoStream = useAsyncMemo(async () => {
137145
if (videoDevice && videoActive) {
@@ -162,7 +170,7 @@ const VideoLobby: FC<{ room: Room }> = ({ room }) => {
162170
const connect = async () => {
163171
setConnecting(true);
164172
try {
165-
await VideoChannelStore.instance.connect(
173+
await store.connect(
166174
room.roomId, audioActive ? audioDevice : null, videoActive ? videoDevice : null,
167175
);
168176
} catch (e) {

src/stores/VideoChannelStore.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,20 @@ export default class VideoChannelStore extends AsyncStoreWithClient<null> {
9494
public get participants(): IJitsiParticipant[] { return this._participants; }
9595
private set participants(value: IJitsiParticipant[]) { this._participants = value; }
9696

97+
private _audioMuted = localStorage.getItem("mx_audioMuted") === "true";
98+
public get audioMuted(): boolean { return this._audioMuted; }
99+
public set audioMuted(value: boolean) {
100+
this._audioMuted = value;
101+
localStorage.setItem("mx_audioMuted", value.toString());
102+
}
103+
104+
private _videoMuted = localStorage.getItem("mx_videoMuted") === "true";
105+
public get videoMuted(): boolean { return this._videoMuted; }
106+
public set videoMuted(value: boolean) {
107+
this._videoMuted = value;
108+
localStorage.setItem("mx_videoMuted", value.toString());
109+
}
110+
97111
public connect = async (roomId: string, audioDevice: MediaDeviceInfo, videoDevice: MediaDeviceInfo) => {
98112
if (this.activeChannel) await this.disconnect();
99113

@@ -136,10 +150,14 @@ export default class VideoChannelStore extends AsyncStoreWithClient<null> {
136150
}
137151
}
138152

153+
// Participant data and mute state will come down the event pipeline quickly, so prepare in advance
139154
this.activeChannel = messaging;
140155
this.roomId = roomId;
141-
// Participant data will come down the event pipeline quickly, so prepare in advance
142156
messaging.on(`action:${ElementWidgetActions.CallParticipants}`, this.onParticipants);
157+
messaging.on(`action:${ElementWidgetActions.MuteAudio}`, this.onMuteAudio);
158+
messaging.on(`action:${ElementWidgetActions.UnmuteAudio}`, this.onUnmuteAudio);
159+
messaging.on(`action:${ElementWidgetActions.MuteVideo}`, this.onMuteVideo);
160+
messaging.on(`action:${ElementWidgetActions.UnmuteVideo}`, this.onUnmuteVideo);
143161

144162
this.emit(VideoChannelEvent.StartConnect, roomId);
145163

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

167189
this.emit(VideoChannelEvent.Disconnect, roomId);
168190

@@ -238,4 +260,24 @@ export default class VideoChannelStore extends AsyncStoreWithClient<null> {
238260
this.emit(VideoChannelEvent.Participants, this.roomId, ev.detail.data.participants);
239261
this.ack(ev);
240262
};
263+
264+
private onMuteAudio = (ev: CustomEvent<IWidgetApiRequest>) => {
265+
this.audioMuted = true;
266+
this.ack(ev);
267+
};
268+
269+
private onUnmuteAudio = (ev: CustomEvent<IWidgetApiRequest>) => {
270+
this.audioMuted = false;
271+
this.ack(ev);
272+
};
273+
274+
private onMuteVideo = (ev: CustomEvent<IWidgetApiRequest>) => {
275+
this.videoMuted = true;
276+
this.ack(ev);
277+
};
278+
279+
private onUnmuteVideo = (ev: CustomEvent<IWidgetApiRequest>) => {
280+
this.videoMuted = false;
281+
this.ack(ev);
282+
};
241283
}

0 commit comments

Comments
 (0)