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:
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import { VoiceUser } from './VoiceUser';
|
||||
import { useVoiceStore } from '../../stores/voiceStore';
|
||||
import type { ParticipantInfo } from '../../hooks/useLiveKit';
|
||||
|
||||
interface VoiceGridProps {
|
||||
@@ -7,6 +8,9 @@ interface VoiceGridProps {
|
||||
}
|
||||
|
||||
export function VoiceGrid({ participants }: VoiceGridProps) {
|
||||
const focusedParticipantId = useVoiceStore((s) => s.focusedParticipantId);
|
||||
const setFocusedParticipant = useVoiceStore((s) => s.setFocusedParticipant);
|
||||
|
||||
if (participants.length === 0) {
|
||||
return (
|
||||
<div className="flex-1 flex items-center justify-center text-discord-text-muted">
|
||||
@@ -15,18 +19,61 @@ export function VoiceGrid({ participants }: VoiceGridProps) {
|
||||
);
|
||||
}
|
||||
|
||||
const focusedParticipant = focusedParticipantId
|
||||
? participants.find(p => p.identity === focusedParticipantId)
|
||||
: null;
|
||||
|
||||
// Focus mode: one large tile + sidebar strip
|
||||
if (focusedParticipant) {
|
||||
const otherParticipants = participants.filter(p => p.identity !== focusedParticipantId);
|
||||
return (
|
||||
<div className="flex-1 flex overflow-hidden">
|
||||
{/* Main focused view */}
|
||||
<div
|
||||
className="flex-1 p-2"
|
||||
onDoubleClick={() => setFocusedParticipant(null)}
|
||||
>
|
||||
<VoiceUser participant={focusedParticipant} large />
|
||||
</div>
|
||||
|
||||
{/* Side strip of other participants */}
|
||||
{otherParticipants.length > 0 && (
|
||||
<div className="w-[200px] flex-shrink-0 overflow-y-auto p-2 space-y-2">
|
||||
{otherParticipants.map((p) => (
|
||||
<div
|
||||
key={p.identity}
|
||||
onClick={() => setFocusedParticipant(p.identity)}
|
||||
className="cursor-pointer"
|
||||
>
|
||||
<VoiceUser participant={p} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Default grid mode
|
||||
const gridClass = (() => {
|
||||
if (participants.length === 1) return 'grid-cols-1 max-w-2xl mx-auto';
|
||||
if (participants.length === 2) return 'grid-cols-2 max-w-4xl mx-auto';
|
||||
if (participants.length <= 4) return 'grid-cols-2';
|
||||
return 'grid-cols-3';
|
||||
if (participants.length <= 9) return 'grid-cols-3';
|
||||
return 'grid-cols-4';
|
||||
})();
|
||||
|
||||
return (
|
||||
<div className="flex-1 p-4 overflow-auto">
|
||||
<div className={`grid ${gridClass} gap-2 h-full`}>
|
||||
{participants.map((p) => (
|
||||
<VoiceUser key={p.identity} participant={p} />
|
||||
<div
|
||||
key={p.identity}
|
||||
onClick={() => setFocusedParticipant(p.identity)}
|
||||
className="cursor-pointer"
|
||||
>
|
||||
<VoiceUser participant={p} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user