feat: Optimize WebRTC pipeline for 60fps screen sharing

- Implemented 'Overdrive' logic to force high bitrates on Chrome
- Fixed 'Auto' preset to default to stable 720p60
- Added persistent 'Triple-Kick' hammer to prevent bitrate throttling
- Fixed sidebar connection status sync
- Added comprehensive diagnostic logger
This commit is contained in:
Jannis Braun
2026-02-19 03:34:20 +01:00
parent 435d12e5b8
commit 7ae3e8c687
56 changed files with 3558 additions and 577 deletions
+15 -6
View File
@@ -80,7 +80,8 @@ export const useChatStore = create((set, get) => ({
const isDm = isDmChannel(channelId);
if (isDm) {
await api.dm.updateMessage(messageId, { content });
} else {
}
else {
await api.messages.update(messageId, { content });
}
// Update will arrive via WebSocket
@@ -89,7 +90,8 @@ export const useChatStore = create((set, get) => ({
const isDm = isDmChannel(channelId);
if (isDm) {
await api.dm.deleteMessage(messageId);
} else {
}
else {
await api.messages.delete(messageId);
}
// Deletion will arrive via WebSocket
@@ -106,8 +108,10 @@ export const useChatStore = create((set, get) => ({
});
},
updateMessage: (message) => {
// DM messages have dmChannelId instead of channelId — check both
const channelKey = message.channelId || message.dmChannelId;
if (!channelKey) return;
if (!channelKey)
return;
set((state) => {
const newMessages = new Map(state.messages);
const current = newMessages.get(channelKey);
@@ -219,7 +223,8 @@ export const useChatStore = create((set, get) => ({
},
markChannelUnread: (channelId) => {
set((state) => {
if (state.unreadChannels.has(channelId)) return state;
if (state.unreadChannels.has(channelId))
return state;
const newUnread = new Set(state.unreadChannels);
newUnread.add(channelId);
return { unreadChannels: newUnread };
@@ -227,10 +232,13 @@ export const useChatStore = create((set, get) => ({
},
ackChannel: (channelId) => {
const msgs = get().messages.get(channelId);
if (!msgs || msgs.length === 0) return;
if (!msgs || msgs.length === 0)
return;
const lastMsg = msgs[msgs.length - 1];
if (!lastMsg) return;
if (!lastMsg)
return;
const messageId = lastMsg.id;
// Update local state immediately
set((state) => {
const newReadStates = new Map(state.readStates);
newReadStates.set(channelId, messageId);
@@ -238,6 +246,7 @@ export const useChatStore = create((set, get) => ({
newUnread.delete(channelId);
return { readStates: newReadStates, unreadChannels: newUnread };
});
// Send to server
wsSend({ type: 'channel_ack', channelId, messageId });
},
onChannelAck: (channelId, messageId) => {
+7 -1
View File
@@ -140,6 +140,7 @@ export const useServerStore = create((set, get) => ({
inviteCode: s.inviteCode,
createdAt: s.createdAt,
}));
// Build channel→server map and channel→lastMessageId map
const channelToServerMap = new Map();
const channelLastMessageIds = new Map();
for (const srv of servers) {
@@ -150,6 +151,7 @@ export const useServerStore = create((set, get) => ({
}
}
}
// Also map DM channels
const dms = dmChannels || [];
for (const dm of dms) {
if (dm.lastMessage?.id) {
@@ -165,7 +167,11 @@ export const useServerStore = create((set, get) => ({
});
},
}));
/**
* Data-driven DM channel detection. Returns true if the given channelId
* belongs to a DM channel. Authoritative because dmChannels is populated
* from the WS ready event and DM/server channel IDs never overlap.
*/
export function isDmChannel(channelId) {
const dmChannels = useServerStore.getState().dmChannels;
if (dmChannels.length > 0) {
+5
View File
@@ -29,4 +29,9 @@ export const useUIStore = create((set) => ({
closeUserProfile: () => set({
userProfilePopout: { user: null, position: null }
}),
voiceChatOpen: false,
voiceFullscreen: false,
toggleVoiceChat: () => set((state) => ({ voiceChatOpen: !state.voiceChatOpen })),
toggleVoiceFullscreen: () => set((state) => ({ voiceFullscreen: !state.voiceFullscreen })),
setVoiceFullscreen: (fullscreen) => set({ voiceFullscreen: fullscreen }),
}));
+11
View File
@@ -34,6 +34,11 @@ interface UIState {
closeImagePreview: () => void;
openUserProfile: (user: User, position: { top: number; left: number }) => void;
closeUserProfile: () => void;
voiceChatOpen: boolean;
voiceFullscreen: boolean;
toggleVoiceChat: () => void;
toggleVoiceFullscreen: () => void;
setVoiceFullscreen: (fullscreen: boolean) => void;
}
export const useUIStore = create<UIState>((set) => ({
@@ -72,4 +77,10 @@ export const useUIStore = create<UIState>((set) => ({
closeUserProfile: () => set({
userProfilePopout: { user: null, position: null }
}),
voiceChatOpen: false,
voiceFullscreen: false,
toggleVoiceChat: () => set((state) => ({ voiceChatOpen: !state.voiceChatOpen })),
toggleVoiceFullscreen: () => set((state) => ({ voiceFullscreen: !state.voiceFullscreen })),
setVoiceFullscreen: (fullscreen) => set({ voiceFullscreen: fullscreen }),
}));
+35
View File
@@ -9,6 +9,25 @@ export const useVoiceStore = create((set, get) => ({
participants: [],
connectionError: null,
isLiveKitConnected: false,
inputVolume: 100,
outputVolume: 100,
focusedParticipantId: null,
videoQuality: 'auto',
participantVolumes: new Map(),
setParticipantVolume: (userId, volume) => {
set((state) => {
const newMap = new Map(state.participantVolumes);
newMap.set(userId, volume);
return { participantVolumes: newMap };
});
},
getParticipantVolume: (userId) => get().participantVolumes.get(userId) ?? 100,
incomingCall: null,
outgoingCall: null,
activeDmCall: null,
setIncomingCall: (call) => set({ incomingCall: call }),
setOutgoingCall: (call) => set({ outgoingCall: call }),
setActiveDmCall: (call) => set({ activeDmCall: call }),
setVoiceUsers: (channelId, userIds) => {
set((state) => {
const newMap = new Map(state.voiceUsers);
@@ -38,10 +57,14 @@ export const useVoiceStore = create((set, get) => ({
setParticipants: (participants) => set({ participants }),
setConnectionError: (error) => set({ connectionError: error }),
setIsLiveKitConnected: (connected) => set({ isLiveKitConnected: connected }),
setInputVolume: (volume) => set({ inputVolume: volume }),
setOutputVolume: (volume) => set({ outputVolume: volume }),
toggleMic: () => set((state) => ({ isMuted: !state.isMuted })),
toggleDeafen: () => set((state) => ({ isDeafened: !state.isDeafened })),
toggleCamera: () => set((state) => ({ isCameraOn: !state.isCameraOn })),
toggleScreenShare: () => set((state) => ({ isScreenSharing: !state.isScreenSharing })),
setFocusedParticipant: (id) => set({ focusedParticipantId: id }),
setVideoQuality: (quality) => set({ videoQuality: quality }),
getVoiceUsers: (channelId) => get().voiceUsers.get(channelId) ?? [],
clearAllVoiceUsers: () => set({ voiceUsers: new Map() }),
// Leave voice without wiping the voiceUsers map (so sidebar still shows others)
@@ -54,6 +77,11 @@ export const useVoiceStore = create((set, get) => ({
participants: [],
connectionError: null,
isLiveKitConnected: false,
inputVolume: 100,
outputVolume: 100,
focusedParticipantId: null,
activeDmCall: null,
outgoingCall: null,
}),
reset: () => set({
voiceUsers: new Map(),
@@ -65,5 +93,12 @@ export const useVoiceStore = create((set, get) => ({
participants: [],
connectionError: null,
isLiveKitConnected: false,
inputVolume: 100,
outputVolume: 100,
focusedParticipantId: null,
participantVolumes: new Map(),
incomingCall: null,
outgoingCall: null,
activeDmCall: null,
}),
}));
+45
View File
@@ -13,6 +13,19 @@ interface VoiceState {
isLiveKitConnected: boolean;
inputVolume: number; // 0-200 (100 = default)
outputVolume: number; // 0-200 (100 = default)
focusedParticipantId: string | null;
videoQuality: 'auto' | '1080p' | '1080p60' | '720p' | '720p60' | '540p' | '360p';
// Per-participant volume (userId → 0-200, 100 = default)
participantVolumes: Map<string, number>;
setParticipantVolume: (userId: string, volume: number) => void;
getParticipantVolume: (userId: string) => number;
// DM call state
incomingCall: { dmChannelId: string; callerId: string; callerName: string } | null;
outgoingCall: { dmChannelId: string } | null;
activeDmCall: { dmChannelId: string } | null;
setIncomingCall: (call: { dmChannelId: string; callerId: string; callerName: string } | null) => void;
setOutgoingCall: (call: { dmChannelId: string } | null) => void;
setActiveDmCall: (call: { dmChannelId: string } | null) => void;
setVoiceUsers: (channelId: string, userIds: string[]) => void;
addVoiceUser: (channelId: string, userId: string) => void;
removeVoiceUser: (channelId: string, userId: string) => void;
@@ -26,6 +39,8 @@ interface VoiceState {
toggleCamera: () => void;
toggleScreenShare: () => void;
toggleDeafen: () => void;
setFocusedParticipant: (id: string | null) => void;
setVideoQuality: (quality: 'auto' | '1080p' | '1080p60' | '720p' | '720p60' | '540p' | '360p') => void;
getVoiceUsers: (channelId: string) => string[];
clearAllVoiceUsers: () => void;
leaveVoice: () => void;
@@ -44,6 +59,25 @@ export const useVoiceStore = create<VoiceState>((set, get) => ({
isLiveKitConnected: false,
inputVolume: 100,
outputVolume: 100,
focusedParticipantId: null,
videoQuality: 'auto',
participantVolumes: new Map(),
setParticipantVolume: (userId, volume) => {
set((state) => {
const newMap = new Map(state.participantVolumes);
newMap.set(userId, volume);
return { participantVolumes: newMap };
});
},
getParticipantVolume: (userId) => get().participantVolumes.get(userId) ?? 100,
incomingCall: null,
outgoingCall: null,
activeDmCall: null,
setIncomingCall: (call) => set({ incomingCall: call }),
setOutgoingCall: (call) => set({ outgoingCall: call }),
setActiveDmCall: (call) => set({ activeDmCall: call }),
setVoiceUsers: (channelId, userIds) => {
set((state) => {
@@ -87,6 +121,9 @@ export const useVoiceStore = create<VoiceState>((set, get) => ({
toggleCamera: () => set((state) => ({ isCameraOn: !state.isCameraOn })),
toggleScreenShare: () => set((state) => ({ isScreenSharing: !state.isScreenSharing })),
setFocusedParticipant: (id) => set({ focusedParticipantId: id }),
setVideoQuality: (quality) => set({ videoQuality: quality }),
getVoiceUsers: (channelId) => get().voiceUsers.get(channelId) ?? [],
clearAllVoiceUsers: () => set({ voiceUsers: new Map() }),
@@ -103,6 +140,9 @@ export const useVoiceStore = create<VoiceState>((set, get) => ({
isLiveKitConnected: false,
inputVolume: 100,
outputVolume: 100,
focusedParticipantId: null,
activeDmCall: null,
outgoingCall: null,
}),
reset: () => set({
@@ -117,5 +157,10 @@ export const useVoiceStore = create<VoiceState>((set, get) => ({
isLiveKitConnected: false,
inputVolume: 100,
outputVolume: 100,
focusedParticipantId: null,
participantVolumes: new Map(),
incomingCall: null,
outgoingCall: null,
activeDmCall: null,
}),
}));