(feat): good call progress, mandatory update due to ttp changes #3

Merged
alois merged 7 commits from dev into main 2026-05-20 23:11:22 +03:00
5 changed files with 34 additions and 9 deletions
Showing only changes of commit c795f691bf - Show all commits

(feat): improved microphone gate
All checks were successful
/ build-web (push) Successful in 1m16s
/ build-desktop (push) Successful in 14m2s
/ build-mobile (push) Successful in 19m13s
/ release (push) Successful in 24s

(fix): weird behaviour related to users that are screensharing
Alois 2026-05-15 16:19:03 +02:00

View file

@ -152,12 +152,12 @@ export default function Base({
const onClick = () => {
if (view === "grid") {
focusParticipant(user.user_id);
focusParticipant(user.user_id, type);
} else {
if (user.user_id === focusedParticipantId) {
setCallView("grid");
} else {
focusParticipant(user.user_id);
focusParticipant(user.user_id, type);
}
}
};
@ -215,7 +215,7 @@ export default function Base({
ref={currentCard}
className={`transition-all duration-150 z-10 bg-card absolute top-0 left-0 w-full h-full flex gap-2 items-center justify-center ${
flush ? "rounded-none" : "rounded-sm"
} ${isSpeaking ? "border-4 border-(--primary-foreground-alt)/75" : "border-0"}`}
} ${type === "user" && isSpeaking ? "border-4 border-(--primary-foreground-alt)/75" : "border-0"}`}
style={{ containerType: "size" }}
>
{/* Detect video / user and place here */}

View file

@ -1,7 +1,8 @@
import { log } from "@tensamin/shared/log";
import { useCall } from "./store";
const SPEAKING_THRESHOLD = 0.01;
const SPEAKING_HANGTIME_MS = 250;
const SPEAKING_HANGTIME_MS = 500;
const ANALYSIS_INTERVAL_MS = 30;
const FFT_SIZE = 256;
@ -137,8 +138,10 @@ class SpeakingDetector {
const db = 20 * Math.log10(Math.max(rms, 0.0001));
if (!this.localMicGateClosed && db < this.gateThresholdStart) {
log(3, "noise gate", "purple", "closed");
this.muteLocalTrack(true);
} else if (this.localMicGateClosed && db > this.gateThresholdEnd) {
log(3, "noise gate", "purple", "opened");
this.muteLocalTrack(false);
}
}

View file

@ -91,6 +91,7 @@ type CallStore = {
screenShareEnabled: boolean;
screenShareSession: ScreenShareSession | null;
focusedParticipantId: number | null;
focusedParticipantType: "user" | "stream" | null;
usersInFocusedViewHidden: boolean;
watchedStreamParticipantIds: number[];
pendingWatchedParticipantIds: number[];
@ -464,6 +465,8 @@ function syncScreenShareParticipants() {
watchedStreamParticipantIds,
pendingWatchedParticipantIds,
focusedParticipantId,
focusedParticipantType:
focusedParticipantId == null ? null : state.focusedParticipantType,
view:
state.view === "focused" && focusedParticipantId == null
? "grid"
@ -634,6 +637,7 @@ export function startWatchingStream(participantId: number) {
? state.pendingWatchedParticipantIds
: [...state.pendingWatchedParticipantIds, participantId],
focusedParticipantId: participantId,
focusedParticipantType: "stream",
}));
}
@ -653,9 +657,13 @@ export function setParticipantTrackSubscribed(
}
// Focus a participant in the main call view even when they are not sharing a screen.
export function focusParticipant(participantId: number) {
export function focusParticipant(
participantId: number,
type: "user" | "stream" = "user",
) {
useCall.setState({
focusedParticipantId: participantId,
focusedParticipantType: type,
view: "focused",
});
}
@ -675,6 +683,10 @@ export function stopWatchingStream(participantId: number) {
state.focusedParticipantId === participantId
? null
: state.focusedParticipantId,
focusedParticipantType:
state.focusedParticipantId === participantId
? null
: state.focusedParticipantType,
view:
state.view === "focused" && state.focusedParticipantId === participantId
? "grid"
@ -790,6 +802,7 @@ export async function disconnect() {
view: "preview",
screenShareSession: null,
focusedParticipantId: null,
focusedParticipantType: null,
usersInFocusedViewHidden: false,
watchedStreamParticipantIds: [],
pendingWatchedParticipantIds: [],
@ -950,6 +963,7 @@ export function resetCallState() {
deaf: false,
screenShareSession: null,
focusedParticipantId: null,
focusedParticipantType: null,
usersInFocusedViewHidden: false,
watchedStreamParticipantIds: [],
pendingWatchedParticipantIds: [],
@ -1002,6 +1016,7 @@ export const useCall = create<CallStore>(() => ({
screenShareEnabled: room.localParticipant.isScreenShareEnabled,
screenShareSession: null,
focusedParticipantId: null,
focusedParticipantType: null,
usersInFocusedViewHidden: false,
watchedStreamParticipantIds: [],
pendingWatchedParticipantIds: [],
@ -1038,7 +1053,7 @@ export function useInitializeCall() {
new DeepFilterNoiseFilterProcessor({
enabled: true,
enableNoiseReduction: true,
noiseReductionLevel: 80,
noiseReductionLevel: 60,
sampleRate: 48000,
assetConfig: {
cdnUrl: "/assets",

View file

@ -16,6 +16,9 @@ export default function View() {
const callIsFullscreen = useCall((state) => state.callIsFullscreen);
const focusedParticipantId = useCall((state) => state.focusedParticipantId);
const focusedParticipantType = useCall(
(state) => state.focusedParticipantType,
);
const activeScreenShareParticipantIds = useCall(
(state) => state.activeScreenShareParticipantIds,
);
@ -157,6 +160,10 @@ export default function View() {
const focusedParticipant = getParticipantById(focusedParticipantId);
const focusedParticipantHasActiveScreenShare =
activeScreenShareParticipantIdSet.has(focusedParticipantId);
const focusedTileType: "user" | "stream" =
focusedParticipantType === "stream" && focusedParticipantHasActiveScreenShare
? "stream"
: "user";
const isImmersiveFocusedView = callIsFullscreen && usersInFocusedViewHidden;
return (
@ -179,7 +186,7 @@ export default function View() {
<Base
fill={isImmersiveFocusedView}
flush={isImmersiveFocusedView || isFocusedTileFlush}
type={focusedParticipantHasActiveScreenShare ? "stream" : "user"}
type={focusedTileType}
participant={focusedParticipant}
/>
</div>

View file

@ -280,6 +280,6 @@ export const storageDefaults: Storage = {
cached_contacts: [],
cached_communities: [],
ttp_url: "https://tensamin.net:959",
call_mute_range_start: -50,
call_mute_range_end: -40,
call_mute_range_start: -55,
call_mute_range_end: -45,
};