refactor: replace unpublishTrack mute with setMicrophoneEnabled (Phase 1 RNNoise prep)
- syncMic now uses setMicrophoneEnabled(false/true) to mute/unmute the mic track in-place instead of tearing down and re-publishing via unpublishTrack(). This eliminates WebRTC renegotiation on every mute cycle and preserves the Web Audio pipeline for future AudioWorklet injection (RNNoise WASM). - Unify DmCallView mute/deafen with the primary syncMic path — removed direct setMicrophoneEnabled calls, added missing auto-mute/unmute on deafen toggle. - Strip redundant applyConstraints from VoiceControls noise suppression toggle that was hardcoding echoCancellation:true/autoGainControl:true and fighting AudioManager's constraint pipeline.
This commit is contained in:
@@ -33,31 +33,23 @@ export function DmCallView() {
|
||||
const otherUser = dmChannel?.members.find(m => m.id !== authUser?.id);
|
||||
const otherName = otherUser?.displayName ?? otherUser?.username ?? 'User';
|
||||
const handleMute = () => {
|
||||
const room = getActiveRoom();
|
||||
if (room) {
|
||||
room.localParticipant.setMicrophoneEnabled(isMuted);
|
||||
}
|
||||
toggleMic();
|
||||
};
|
||||
const handleDeafen = () => {
|
||||
const room = getActiveRoom();
|
||||
const willDeafen = !isDeafened;
|
||||
if (room) {
|
||||
const newDeafened = !isDeafened;
|
||||
room.remoteParticipants.forEach((p) => {
|
||||
p.audioTrackPublications.forEach((pub) => {
|
||||
if (pub.track) {
|
||||
pub.track.setVolume?.(newDeafened ? 0 : 1);
|
||||
pub.track.setVolume?.(willDeafen ? 0 : 1);
|
||||
}
|
||||
});
|
||||
});
|
||||
if (newDeafened) {
|
||||
room.localParticipant.setMicrophoneEnabled(false);
|
||||
}
|
||||
else if (!isMuted) {
|
||||
room.localParticipant.setMicrophoneEnabled(true);
|
||||
}
|
||||
}
|
||||
toggleDeafen();
|
||||
if (willDeafen && !isMuted) toggleMic();
|
||||
if (!willDeafen && isMuted) toggleMic();
|
||||
};
|
||||
const handleCamera = async () => {
|
||||
const room = getActiveRoom();
|
||||
|
||||
@@ -37,32 +37,29 @@ export function DmCallView() {
|
||||
const otherUser = dmChannel?.members.find(m => m.id !== authUser?.id);
|
||||
const otherName = otherUser?.displayName ?? otherUser?.username ?? 'User';
|
||||
|
||||
// Mute/deafen toggling is handled by syncMic in useLiveKit via store state.
|
||||
// DmCallView only needs to toggle store + handle remote audio silencing for deafen.
|
||||
const handleMute = () => {
|
||||
const room = getActiveRoom();
|
||||
if (room) {
|
||||
room.localParticipant.setMicrophoneEnabled(isMuted);
|
||||
}
|
||||
toggleMic();
|
||||
};
|
||||
|
||||
const handleDeafen = () => {
|
||||
const room = getActiveRoom();
|
||||
const willDeafen = !isDeafened;
|
||||
// Silence/restore remote participant audio for deafen
|
||||
if (room) {
|
||||
const newDeafened = !isDeafened;
|
||||
room.remoteParticipants.forEach((p) => {
|
||||
p.audioTrackPublications.forEach((pub) => {
|
||||
if (pub.track) {
|
||||
(pub.track as any).setVolume?.(newDeafened ? 0 : 1);
|
||||
(pub.track as any).setVolume?.(willDeafen ? 0 : 1);
|
||||
}
|
||||
});
|
||||
});
|
||||
if (newDeafened) {
|
||||
room.localParticipant.setMicrophoneEnabled(false);
|
||||
} else if (!isMuted) {
|
||||
room.localParticipant.setMicrophoneEnabled(true);
|
||||
}
|
||||
}
|
||||
toggleDeafen();
|
||||
// Auto-mute on deafen, auto-unmute on undeafen
|
||||
if (willDeafen && !isMuted) toggleMic();
|
||||
if (!willDeafen && isMuted) toggleMic();
|
||||
};
|
||||
|
||||
const handleCamera = async () => {
|
||||
|
||||
@@ -54,24 +54,7 @@ export function VoiceControls() {
|
||||
console.error('[VoiceControls] Failed to toggle screen share:', err);
|
||||
}
|
||||
};
|
||||
const handleNoiseSuppression = async () => {
|
||||
const room = getActiveRoom();
|
||||
if (room) {
|
||||
try {
|
||||
const micPub = room.localParticipant.getTrackPublications().find(p => p.source === 'microphone');
|
||||
const mediaTrack = micPub?.track?.mediaStreamTrack;
|
||||
if (mediaTrack) {
|
||||
await mediaTrack.applyConstraints({
|
||||
noiseSuppression: !noiseSuppression,
|
||||
echoCancellation: true,
|
||||
autoGainControl: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.error('[VoiceControls] Failed to toggle noise suppression:', err);
|
||||
}
|
||||
}
|
||||
const handleNoiseSuppression = () => {
|
||||
toggleNoiseSuppression();
|
||||
};
|
||||
const handleDisconnect = () => {
|
||||
|
||||
@@ -56,25 +56,8 @@ export function VoiceControls() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleNoiseSuppression = async () => {
|
||||
const room = getActiveRoom();
|
||||
if (room) {
|
||||
try {
|
||||
const micPub = room.localParticipant.getTrackPublications().find(
|
||||
p => p.source === 'microphone'
|
||||
);
|
||||
const mediaTrack = micPub?.track?.mediaStreamTrack;
|
||||
if (mediaTrack) {
|
||||
await mediaTrack.applyConstraints({
|
||||
noiseSuppression: !noiseSuppression,
|
||||
echoCancellation: true,
|
||||
autoGainControl: true,
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[VoiceControls] Failed to toggle noise suppression:', err);
|
||||
}
|
||||
}
|
||||
const handleNoiseSuppression = () => {
|
||||
// Store toggle triggers syncMic → AudioManager re-acquires stream with correct constraints
|
||||
toggleNoiseSuppression();
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user