fix: guard voice controls against toggling intent while server muted/deafened
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import { useVoiceStore } from '../stores/voiceStore';
|
import { useVoiceStore } from '../stores/voiceStore';
|
||||||
|
import { useSpaceStore, getChannelOrigin, getMyUserIdForOrigin } from '../stores/spaceStore';
|
||||||
import { AudioManager } from './AudioManager';
|
import { AudioManager } from './AudioManager';
|
||||||
import type { ParticipantInfo } from '../hooks/useLiveKit';
|
import type { ParticipantInfo } from '../hooks/useLiveKit';
|
||||||
|
|
||||||
@@ -168,8 +169,24 @@ export class SpeakingDetector {
|
|||||||
|
|
||||||
// --- Local participant ---
|
// --- Local participant ---
|
||||||
if (this.localIdentity) {
|
if (this.localIdentity) {
|
||||||
if (store.isMuted) {
|
// Compute effective muted/deafened state (intent OR server enforcement)
|
||||||
// Muted → never speaking, reset hold counter
|
let effectiveMuted = store.isMuted;
|
||||||
|
let effectiveDeafened = store.isDeafened;
|
||||||
|
const channelId = store.currentVoiceChannelId;
|
||||||
|
if (channelId) {
|
||||||
|
const spaceId = useSpaceStore.getState().channelToSpaceMap.get(channelId);
|
||||||
|
if (spaceId) {
|
||||||
|
const myOriginId = getMyUserIdForOrigin(getChannelOrigin(channelId));
|
||||||
|
if (myOriginId) {
|
||||||
|
const serverKey = `${spaceId}:${myOriginId}`;
|
||||||
|
effectiveMuted = effectiveMuted || store.serverMutedUserIds.has(serverKey);
|
||||||
|
effectiveDeafened = effectiveDeafened || store.serverDeafenedUserIds.has(serverKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (effectiveMuted || effectiveDeafened) {
|
||||||
|
// Muted or deafened → never speaking, reset hold counter
|
||||||
this.holdCounters.delete(this.localIdentity);
|
this.holdCounters.delete(this.localIdentity);
|
||||||
} else {
|
} else {
|
||||||
const analyser = AudioManager.getInstance().getAnalyserNode();
|
const analyser = AudioManager.getInstance().getAnalyserNode();
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ export function ChannelSidebar() {
|
|||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
||||||
const handleMicToggle = async () => {
|
const handleMicToggle = async () => {
|
||||||
|
if (isServerMuted || isServerDeafened) return;
|
||||||
const wasDeafened = useVoiceStore.getState().isDeafened;
|
const wasDeafened = useVoiceStore.getState().isDeafened;
|
||||||
toggleMic();
|
toggleMic();
|
||||||
broadcastVoiceStatus();
|
broadcastVoiceStatus();
|
||||||
@@ -53,6 +54,7 @@ export function ChannelSidebar() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleDeafenToggle = async () => {
|
const handleDeafenToggle = async () => {
|
||||||
|
if (isServerDeafened) return;
|
||||||
toggleDeafen();
|
toggleDeafen();
|
||||||
broadcastVoiceStatus();
|
broadcastVoiceStatus();
|
||||||
broadcastDeafenViaLiveKit();
|
broadcastDeafenViaLiveKit();
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ export function VoiceControlBar() {
|
|||||||
const qualityBtnRef = useRef<HTMLButtonElement>(null);
|
const qualityBtnRef = useRef<HTMLButtonElement>(null);
|
||||||
|
|
||||||
const handleMute = React.useCallback(async () => {
|
const handleMute = React.useCallback(async () => {
|
||||||
|
if (isServerMuted || isServerDeafened) return;
|
||||||
const wasDeafened = useVoiceStore.getState().isDeafened;
|
const wasDeafened = useVoiceStore.getState().isDeafened;
|
||||||
toggleMic();
|
toggleMic();
|
||||||
broadcastVoiceStatus();
|
broadcastVoiceStatus();
|
||||||
@@ -46,13 +47,14 @@ export function VoiceControlBar() {
|
|||||||
if (wasDeafened && !useVoiceStore.getState().isDeafened) {
|
if (wasDeafened && !useVoiceStore.getState().isDeafened) {
|
||||||
broadcastDeafenViaLiveKit();
|
broadcastDeafenViaLiveKit();
|
||||||
}
|
}
|
||||||
}, [toggleMic]);
|
}, [isServerMuted, isServerDeafened, toggleMic]);
|
||||||
|
|
||||||
const handleDeafen = React.useCallback(async () => {
|
const handleDeafen = React.useCallback(async () => {
|
||||||
|
if (isServerDeafened) return;
|
||||||
toggleDeafen();
|
toggleDeafen();
|
||||||
broadcastVoiceStatus();
|
broadcastVoiceStatus();
|
||||||
broadcastDeafenViaLiveKit();
|
broadcastDeafenViaLiveKit();
|
||||||
}, [toggleDeafen]);
|
}, [isServerDeafened, toggleDeafen]);
|
||||||
|
|
||||||
const handleCamera = async () => {
|
const handleCamera = async () => {
|
||||||
const room = getActiveRoom();
|
const room = getActiveRoom();
|
||||||
|
|||||||
Reference in New Issue
Block a user