Add eslint
This commit is contained in:
@@ -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
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user