Persist audio and video mute state in video rooms (#8376)
…so that video lobbies remember whether you've disabled your camera.
This commit is contained in:
parent
6f5900557b
commit
c70816d763
2 changed files with 55 additions and 5 deletions
|
@ -21,7 +21,6 @@ import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
|
|
||||||
import { _t } from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
import { useAsyncMemo } from "../../../hooks/useAsyncMemo";
|
import { useAsyncMemo } from "../../../hooks/useAsyncMemo";
|
||||||
import { useStateToggle } from "../../../hooks/useStateToggle";
|
|
||||||
import { useConnectedMembers } from "../../../utils/VideoChannelUtils";
|
import { useConnectedMembers } from "../../../utils/VideoChannelUtils";
|
||||||
import VideoChannelStore from "../../../stores/VideoChannelStore";
|
import VideoChannelStore from "../../../stores/VideoChannelStore";
|
||||||
import IconizedContextMenu, {
|
import IconizedContextMenu, {
|
||||||
|
@ -108,6 +107,7 @@ const DeviceButton: FC<IDeviceButtonProps> = ({
|
||||||
const MAX_FACES = 8;
|
const MAX_FACES = 8;
|
||||||
|
|
||||||
const VideoLobby: FC<{ room: Room }> = ({ room }) => {
|
const VideoLobby: FC<{ room: Room }> = ({ room }) => {
|
||||||
|
const store = VideoChannelStore.instance;
|
||||||
const [connecting, setConnecting] = useState(false);
|
const [connecting, setConnecting] = useState(false);
|
||||||
const me = useMemo(() => room.getMember(room.myUserId), [room]);
|
const me = useMemo(() => room.getMember(room.myUserId), [room]);
|
||||||
const connectedMembers = useConnectedMembers(room, false);
|
const connectedMembers = useConnectedMembers(room, false);
|
||||||
|
@ -130,8 +130,16 @@ const VideoLobby: FC<{ room: Room }> = ({ room }) => {
|
||||||
const audioDevice = selectedAudioDevice ?? audioDevices[0];
|
const audioDevice = selectedAudioDevice ?? audioDevices[0];
|
||||||
const videoDevice = selectedVideoDevice ?? videoDevices[0];
|
const videoDevice = selectedVideoDevice ?? videoDevices[0];
|
||||||
|
|
||||||
const [audioActive, toggleAudio] = useStateToggle(true);
|
const [audioActive, setAudioActive] = useState(!store.audioMuted);
|
||||||
const [videoActive, toggleVideo] = useStateToggle(true);
|
const [videoActive, setVideoActive] = useState(!store.videoMuted);
|
||||||
|
const toggleAudio = () => {
|
||||||
|
store.audioMuted = audioActive;
|
||||||
|
setAudioActive(!audioActive);
|
||||||
|
};
|
||||||
|
const toggleVideo = () => {
|
||||||
|
store.videoMuted = videoActive;
|
||||||
|
setVideoActive(!videoActive);
|
||||||
|
};
|
||||||
|
|
||||||
const videoStream = useAsyncMemo(async () => {
|
const videoStream = useAsyncMemo(async () => {
|
||||||
if (videoDevice && videoActive) {
|
if (videoDevice && videoActive) {
|
||||||
|
@ -162,7 +170,7 @@ const VideoLobby: FC<{ room: Room }> = ({ room }) => {
|
||||||
const connect = async () => {
|
const connect = async () => {
|
||||||
setConnecting(true);
|
setConnecting(true);
|
||||||
try {
|
try {
|
||||||
await VideoChannelStore.instance.connect(
|
await store.connect(
|
||||||
room.roomId, audioActive ? audioDevice : null, videoActive ? videoDevice : null,
|
room.roomId, audioActive ? audioDevice : null, videoActive ? videoDevice : null,
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -94,6 +94,20 @@ export default class VideoChannelStore extends AsyncStoreWithClient<null> {
|
||||||
public get participants(): IJitsiParticipant[] { return this._participants; }
|
public get participants(): IJitsiParticipant[] { return this._participants; }
|
||||||
private set participants(value: IJitsiParticipant[]) { this._participants = value; }
|
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) => {
|
public connect = async (roomId: string, audioDevice: MediaDeviceInfo, videoDevice: MediaDeviceInfo) => {
|
||||||
if (this.activeChannel) await this.disconnect();
|
if (this.activeChannel) await this.disconnect();
|
||||||
|
|
||||||
|
@ -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.activeChannel = messaging;
|
||||||
this.roomId = roomId;
|
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.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);
|
this.emit(VideoChannelEvent.StartConnect, roomId);
|
||||||
|
|
||||||
|
@ -163,6 +181,10 @@ export default class VideoChannelStore extends AsyncStoreWithClient<null> {
|
||||||
this.activeChannel = null;
|
this.activeChannel = null;
|
||||||
this.roomId = null;
|
this.roomId = null;
|
||||||
messaging.off(`action:${ElementWidgetActions.CallParticipants}`, this.onParticipants);
|
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);
|
this.emit(VideoChannelEvent.Disconnect, roomId);
|
||||||
|
|
||||||
|
@ -238,4 +260,24 @@ export default class VideoChannelStore extends AsyncStoreWithClient<null> {
|
||||||
this.emit(VideoChannelEvent.Participants, this.roomId, ev.detail.data.participants);
|
this.emit(VideoChannelEvent.Participants, this.roomId, ev.detail.data.participants);
|
||||||
this.ack(ev);
|
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);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue