Add eslint

This commit is contained in:
2026-03-03 22:56:12 +01:00
parent d641229f9d
commit ad0e28bf84
92 changed files with 2656 additions and 1127 deletions

View File

@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/member-ordering, @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, id-length */
/**
* Manages local voice media: getUserMedia, mute, deafen,
* attaching/detaching audio tracks to peer connections, bitrate tuning,
@@ -22,7 +23,7 @@ import {
VOICE_HEARTBEAT_INTERVAL_MS,
DEFAULT_DISPLAY_NAME,
P2P_TYPE_VOICE_STATE,
LatencyProfile,
LatencyProfile
} from './webrtc.constants';
/**
@@ -82,7 +83,7 @@ export class MediaManager {
constructor(
private readonly logger: WebRTCLogger,
private callbacks: MediaManagerCallbacks,
private callbacks: MediaManagerCallbacks
) {
this.noiseReduction = new NoiseReductionManager(logger);
}
@@ -152,21 +153,23 @@ export class MediaManager {
audio: {
echoCancellation: true,
noiseSuppression: true,
autoGainControl: true,
autoGainControl: true
},
video: false,
video: false
};
this.logger.info('getUserMedia constraints', mediaConstraints);
if (!navigator.mediaDevices?.getUserMedia) {
throw new Error(
'navigator.mediaDevices is not available. ' +
'This requires a secure context (HTTPS or localhost). ' +
'If accessing from an external device, use HTTPS.',
'If accessing from an external device, use HTTPS.'
);
}
const stream = await navigator.mediaDevices.getUserMedia(mediaConstraints);
this.rawMicStream = stream;
// If the user wants noise reduction, pipe through the denoiser
@@ -200,11 +203,13 @@ export class MediaManager {
this.rawMicStream.getTracks().forEach((track) => track.stop());
this.rawMicStream = null;
}
this.localMediaStream = null;
// Remove audio senders but keep connections alive
this.callbacks.getActivePeers().forEach((peerData) => {
const senders = peerData.connection.getSenders();
senders.forEach((sender) => {
if (sender.track?.kind === TRACK_KIND_AUDIO) {
peerData.connection.removeTrack(sender);
@@ -250,6 +255,7 @@ export class MediaManager {
if (this.localMediaStream) {
const audioTracks = this.localMediaStream.getAudioTracks();
const newMutedState = muted !== undefined ? muted : !this.isMicMuted;
audioTracks.forEach((track) => {
track.enabled = !newMutedState;
});
@@ -284,23 +290,27 @@ export class MediaManager {
'Noise reduction desired =',
shouldEnable,
'| worklet active =',
this.noiseReduction.isEnabled,
this.noiseReduction.isEnabled
);
if (shouldEnable === this.noiseReduction.isEnabled) return;
if (shouldEnable === this.noiseReduction.isEnabled)
return;
if (shouldEnable) {
if (!this.rawMicStream) {
this.logger.warn(
'Cannot enable noise reduction — no mic stream yet (will apply on connect)',
'Cannot enable noise reduction — no mic stream yet (will apply on connect)'
);
return;
}
this.logger.info('Enabling noise reduction on raw mic stream');
const cleanStream = await this.noiseReduction.enable(this.rawMicStream);
this.localMediaStream = cleanStream;
} else {
this.noiseReduction.disable();
if (this.rawMicStream) {
this.localMediaStream = this.rawMicStream;
}
@@ -330,23 +340,29 @@ export class MediaManager {
async setAudioBitrate(kbps: number): Promise<void> {
const targetBps = Math.max(
AUDIO_BITRATE_MIN_BPS,
Math.min(AUDIO_BITRATE_MAX_BPS, Math.floor(kbps * KBPS_TO_BPS)),
Math.min(AUDIO_BITRATE_MAX_BPS, Math.floor(kbps * KBPS_TO_BPS))
);
this.callbacks.getActivePeers().forEach(async (peerData) => {
const sender =
peerData.audioSender ||
peerData.connection.getSenders().find((s) => s.track?.kind === TRACK_KIND_AUDIO);
if (!sender?.track) return;
if (peerData.connection.signalingState !== 'stable') return;
if (!sender?.track)
return;
if (peerData.connection.signalingState !== 'stable')
return;
let params: RTCRtpSendParameters;
try {
params = sender.getParameters();
} catch (error) {
this.logger.warn('getParameters failed; skipping bitrate apply', error as any);
return;
}
params.encodings = params.encodings || [{}];
params.encodings[0].maxBitrate = targetBps;
@@ -380,8 +396,11 @@ export class MediaManager {
this.stopVoiceHeartbeat();
// Persist voice channel context so heartbeats and state snapshots include it
if (roomId !== undefined) this.currentVoiceRoomId = roomId;
if (serverId !== undefined) this.currentVoiceServerId = serverId;
if (roomId !== undefined)
this.currentVoiceRoomId = roomId;
if (serverId !== undefined)
this.currentVoiceServerId = serverId;
this.voicePresenceTimer = setInterval(() => {
if (this.isVoiceActive) {
@@ -410,7 +429,9 @@ export class MediaManager {
*/
private bindLocalTracksToAllPeers(): void {
const peers = this.callbacks.getActivePeers();
if (!this.localMediaStream) return;
if (!this.localMediaStream)
return;
const localAudioTrack = this.localMediaStream.getAudioTracks()[0] || null;
const localVideoTrack = this.localMediaStream.getVideoTracks()[0] || null;
@@ -420,17 +441,20 @@ export class MediaManager {
let audioSender =
peerData.audioSender ||
peerData.connection.getSenders().find((s) => s.track?.kind === TRACK_KIND_AUDIO);
if (!audioSender) {
audioSender = peerData.connection.addTransceiver(TRACK_KIND_AUDIO, {
direction: TRANSCEIVER_SEND_RECV,
direction: TRANSCEIVER_SEND_RECV
}).sender;
}
peerData.audioSender = audioSender;
// Restore direction after removeTrack (which sets it to recvonly)
const audioTransceiver = peerData.connection
.getTransceivers()
.find((t) => t.sender === audioSender);
if (
audioTransceiver &&
(audioTransceiver.direction === TRANSCEIVER_RECV_ONLY ||
@@ -449,16 +473,19 @@ export class MediaManager {
let videoSender =
peerData.videoSender ||
peerData.connection.getSenders().find((s) => s.track?.kind === TRACK_KIND_VIDEO);
if (!videoSender) {
videoSender = peerData.connection.addTransceiver(TRACK_KIND_VIDEO, {
direction: TRANSCEIVER_SEND_RECV,
direction: TRANSCEIVER_SEND_RECV
}).sender;
}
peerData.videoSender = videoSender;
const videoTransceiver = peerData.connection
.getTransceivers()
.find((t) => t.sender === videoSender);
if (
videoTransceiver &&
(videoTransceiver.direction === TRANSCEIVER_RECV_ONLY ||
@@ -481,6 +508,7 @@ export class MediaManager {
private broadcastVoicePresence(): void {
const oderId = this.callbacks.getIdentifyOderId();
const displayName = this.callbacks.getIdentifyDisplayName();
this.callbacks.broadcastMessage({
type: P2P_TYPE_VOICE_STATE,
oderId,
@@ -490,8 +518,8 @@ export class MediaManager {
isMuted: this.isMicMuted,
isDeafened: this.isSelfDeafened,
roomId: this.currentVoiceRoomId,
serverId: this.currentVoiceServerId,
},
serverId: this.currentVoiceServerId
}
});
}