perf: performance improvements 1

This commit is contained in:
2026-07-14 01:34:33 +02:00
parent edc4d935d8
commit 59dfd2de85
27 changed files with 762 additions and 94 deletions
@@ -340,6 +340,12 @@ export class PeerConnectionManager {
return false;
try {
// Release the failed channel before adopting the replacement; otherwise
// its SCTP resources and handlers stay alive for the connection lifetime.
try {
expectedChannel.close();
} catch { /* channel may already be closed */ }
const replacement = peerData.connection.createDataChannel(DATA_CHANNEL_LABEL, { ordered: true });
peerData.dataChannel = replacement;
@@ -5,7 +5,11 @@ import {
PeerConnectionManagerContext,
RecoveryHandlers
} from '../shared';
import { scheduleDataChannelRecovery } from './peer-recovery';
import {
closeAllPeers,
removePeer,
scheduleDataChannelRecovery
} from './peer-recovery';
describe('peer recovery', () => {
afterEach(() => {
@@ -13,6 +17,40 @@ describe('peer recovery', () => {
vi.useRealTimers();
});
it('removes every remote stream map entry for a removed peer, including camera streams', () => {
const channel = createDataChannel(DATA_CHANNEL_STATE_OPEN);
const context = createContext('alice');
context.state.activePeerConnections.set('bob', createPeerData(channel, 'connected'));
context.state.remotePeerStreams.set('bob', createMediaStream());
context.state.remotePeerVoiceStreams.set('bob', createMediaStream());
context.state.remotePeerScreenShareStreams.set('bob', createMediaStream());
context.state.remotePeerCameraStreams.set('bob', createMediaStream());
removePeer(context, 'bob');
expect(context.state.remotePeerStreams.has('bob')).toBe(false);
expect(context.state.remotePeerVoiceStreams.has('bob')).toBe(false);
expect(context.state.remotePeerScreenShareStreams.has('bob')).toBe(false);
expect(context.state.remotePeerCameraStreams.has('bob')).toBe(false);
});
it('clears every remote stream map when all peers close, including camera streams', () => {
const context = createContext('alice');
context.state.remotePeerStreams.set('bob', createMediaStream());
context.state.remotePeerVoiceStreams.set('bob', createMediaStream());
context.state.remotePeerScreenShareStreams.set('bob', createMediaStream());
context.state.remotePeerCameraStreams.set('bob', createMediaStream());
closeAllPeers(context.state);
expect(context.state.remotePeerStreams.size).toBe(0);
expect(context.state.remotePeerVoiceStreams.size).toBe(0);
expect(context.state.remotePeerScreenShareStreams.size).toBe(0);
expect(context.state.remotePeerCameraStreams.size).toBe(0);
});
it('recreates a peer immediately when the data channel is already closed', () => {
vi.useFakeTimers();
@@ -205,9 +243,14 @@ function createPeerData(
};
}
function createMediaStream(): MediaStream {
return { getTracks: () => [] } as unknown as MediaStream;
}
function createDataChannel(readyState: RTCDataChannelState): RTCDataChannel {
return {
bufferedAmount: 0,
close: vi.fn(),
label: 'chat',
readyState
} as unknown as RTCDataChannel;
@@ -14,6 +14,7 @@ import {
RemovePeerOptions
} from '../shared';
import { clearAllPingTimers, stopPingInterval } from '../messaging/ping';
import { clearDebugNetworkPeerMetrics } from '../../logging/debug-network-metrics';
/**
* Close and remove a peer connection, data channel, and emit a disconnect event.
@@ -33,11 +34,13 @@ export function removePeer(
if (!preserveReconnectState) {
clearPeerReconnectTimer(state, peerId);
state.disconnectedPeerTracker.delete(peerId);
clearDebugNetworkPeerMetrics(peerId);
}
state.remotePeerStreams.delete(peerId);
state.remotePeerVoiceStreams.delete(peerId);
state.remotePeerScreenShareStreams.delete(peerId);
state.remotePeerCameraStreams.delete(peerId);
if (peerData) {
if (peerData.dataChannel)
@@ -72,6 +75,7 @@ export function closeAllPeers(state: PeerConnectionManagerState): void {
state.remotePeerStreams.clear();
state.remotePeerVoiceStreams.clear();
state.remotePeerScreenShareStreams.clear();
state.remotePeerCameraStreams.clear();
state.peerNegotiationQueue.clear();
state.peerLatencies.clear();
state.pendingPings.clear();