diff --git a/apps/web/src/hooks/api/dashboard.ts b/apps/web/src/hooks/api/dashboard.ts
index ade5fbaf..5e9b7ccd 100644
--- a/apps/web/src/hooks/api/dashboard.ts
+++ b/apps/web/src/hooks/api/dashboard.ts
@@ -31,6 +31,7 @@ export const useApplicantsTicle = (ticleId: string) => {
queryKey: ['applicantsTicle', ticleId],
queryFn: () => getApplicantsTicle(ticleId),
enabled: !!ticleId,
+ staleTime: 0,
});
};
@@ -39,6 +40,7 @@ export const useAiSummary = (ticleId: string) => {
queryKey: ['aiSummary', ticleId],
queryFn: () => getAiSummary(ticleId),
enabled: !!ticleId,
+ staleTime: 0,
});
};
diff --git a/apps/web/src/hooks/mediasoup/useMediasoup.ts b/apps/web/src/hooks/mediasoup/useMediasoup.ts
index e3e7db48..9c37157e 100644
--- a/apps/web/src/hooks/mediasoup/useMediasoup.ts
+++ b/apps/web/src/hooks/mediasoup/useMediasoup.ts
@@ -102,11 +102,11 @@ const useMediasoup = () => {
clearMediasoup();
};
- window.addEventListener('beforeunload', clearAll);
+ window.addEventListener('unload', clearAll);
return () => {
clearAll();
- window.removeEventListener('beforeunload', clearAll);
+ window.removeEventListener('unload', clearAll);
};
}, []);
};
diff --git a/apps/web/src/hooks/mediasoup/useNetworkMonitor.ts b/apps/web/src/hooks/mediasoup/useNetworkMonitor.ts
index 7a842a01..acf5acb7 100644
--- a/apps/web/src/hooks/mediasoup/useNetworkMonitor.ts
+++ b/apps/web/src/hooks/mediasoup/useNetworkMonitor.ts
@@ -13,7 +13,7 @@ const QUALITY_LEVEL = {
},
poor: {
quality: 0,
- options: { packetLossRate: 5, jitter: 30, frameDropRate: 10, averageRTT: 300, nackCount: 50 },
+ options: { packetLossRate: 10, jitter: 30, frameDropRate: 10, averageRTT: 300, nackCount: 50 },
},
} as const;
@@ -89,12 +89,12 @@ const useNetworkMonitor = ({ streams }: UseNetworkMonitorProps) => {
[]
);
- const checkNetworkQuality = async (streams: client.RemoteStream[]) => {
+ const checkNetworkQualities = async (streams: client.RemoteStream[]) => {
const networkQualities = await Promise.all(
streams.map(async (data) => {
const { consumer } = data;
- if (!consumer) return;
+ if (!consumer || consumer.closed || consumer.paused) return;
let networkQuality = 2; // 0: poor, 1: average, 2: good
@@ -131,7 +131,15 @@ const useNetworkMonitor = ({ streams }: UseNetworkMonitorProps) => {
})
);
- return networkQualities;
+ return networkQualities.filter(Boolean).reduce(
+ (acc, cur) => {
+ if (!cur) return acc;
+ if (acc.some((data) => data.consumerId === cur.consumerId)) return acc;
+
+ return [...acc, cur];
+ },
+ [] as { consumerId: string; networkQuality: number }[]
+ );
};
useEffect(() => {
@@ -142,7 +150,9 @@ const useNetworkMonitor = ({ streams }: UseNetworkMonitorProps) => {
const interval = setInterval(async () => {
const notPausedStreams = getNotPausedStreams(streams);
- const networkQualities = await checkNetworkQuality(notPausedStreams);
+ const networkQualities = await checkNetworkQualities(notPausedStreams);
+
+ if (!networkQualities || !networkQualities.length) return;
socket.emit(SOCKET_EVENTS.changeConsumerPreferredLayers, {
roomId: ticleId,
diff --git a/apps/web/src/hooks/mediasoup/useRemoteStream.ts b/apps/web/src/hooks/mediasoup/useRemoteStream.ts
index fbf3e9b7..a1f15a4b 100644
--- a/apps/web/src/hooks/mediasoup/useRemoteStream.ts
+++ b/apps/web/src/hooks/mediasoup/useRemoteStream.ts
@@ -249,7 +249,7 @@ const useRemoteStream = () => {
const newStreams = [...prevStreams];
const stream = newStreams.find((stream) => stream.consumer?.producerId === producerId);
- if (!stream) {
+ if (!stream || stream.consumer?.closed) {
return prevStreams;
}
@@ -280,7 +280,7 @@ const useRemoteStream = () => {
const newStreams = [...prevStreams];
const stream = newStreams.find((stream) => stream.consumer?.producerId === producerId);
- if (!stream) {
+ if (!stream || stream.consumer?.closed) {
return prevStreams;
}
diff --git a/apps/web/src/hooks/mediasoup/useSocket.ts b/apps/web/src/hooks/mediasoup/useSocket.ts
index 9675cb66..018eda2e 100644
--- a/apps/web/src/hooks/mediasoup/useSocket.ts
+++ b/apps/web/src/hooks/mediasoup/useSocket.ts
@@ -50,7 +50,6 @@ const useSocket = (): UseSocketReturn => {
});
socket.on(SOCKET_EVENTS.disconnect, () => {
- navigate({ to: '/', replace: true });
setIsConnected(false);
setIsError(null);
});
diff --git a/apps/web/src/hooks/useMediaTracks.ts b/apps/web/src/hooks/useMediaTracks.ts
index 41c7787c..187516e2 100644
--- a/apps/web/src/hooks/useMediaTracks.ts
+++ b/apps/web/src/hooks/useMediaTracks.ts
@@ -12,7 +12,7 @@ const DEFAULT_LOCAL_STREAM = {
const getMediaDevices = (kind: MediaDeviceKind, devices: MediaDeviceInfo[]) => {
return devices
- .filter((device) => device.kind === kind && device.deviceId && device.deviceId !== 'default')
+ .filter((device) => device.kind === kind && device.deviceId)
.map((device) => ({ label: device.label, value: device.deviceId }));
};
@@ -116,16 +116,22 @@ const useMediaTracks = () => {
setAudioDevices(audioInputs);
setAudioOutputDevices(audioOutputs);
- if (videoInputs[0]) setSelectedVideoDeviceId(videoInputs[0].value);
- if (audioInputs[0]) setSelectedAudioDeviceId(audioInputs[0].value);
- if (audioOutputs[0]) setSelectedAudioOutputDeviceId(audioOutputs[0].value);
+ if (videoInputs[0] && !selectedVideoDeviceId) {
+ setSelectedVideoDeviceId(videoInputs[0].value);
+ }
+ if (audioInputs[0] && !selectedAudioDeviceId) {
+ setSelectedAudioDeviceId(audioInputs[0].value);
+ }
+ if (audioOutputs[0] && !selectedAudioOutputDeviceId) {
+ setSelectedAudioOutputDeviceId(audioOutputs[0].value);
+ }
} catch (_) {
toast('미디어 정보를 가져올 수 없습니다.');
}
};
fetchMediaDevices();
- }, []);
+ }, [video, audio]);
return {
video,
diff --git a/apps/web/src/routes/__root.tsx b/apps/web/src/routes/__root.tsx
index f3ef751b..0244f2c3 100644
--- a/apps/web/src/routes/__root.tsx
+++ b/apps/web/src/routes/__root.tsx
@@ -1,12 +1,19 @@
import { Outlet, ScrollRestoration, createRootRoute } from '@tanstack/react-router';
+import NotFound from '@/components/NotFound';
+import NotSupportedMobile from '@/components/NotSupportedMobile';
import { ToastContainer } from '@/components/toast/ToastContainer';
export const Route = createRootRoute({
component: RootComponent,
+ notFoundComponent: NotFound,
});
function RootComponent() {
+ if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
+ return
;
+ }
+
return (
diff --git a/packages/mediasoup/src/client/index.ts b/packages/mediasoup/src/client/index.ts
index 29c8cb40..3b748c97 100644
--- a/packages/mediasoup/src/client/index.ts
+++ b/packages/mediasoup/src/client/index.ts
@@ -65,25 +65,26 @@ export interface ResumeConsumersRes {
paused: boolean;
}
-export const PRODUCER_OPTIONS: ProducerOptions = {
- encodings: [
- { rid: 'r0', maxBitrate: 50000, scalabilityMode: 'S1T3' },
- { rid: 'r1', maxBitrate: 150000, scalabilityMode: 'S1T3' },
- { rid: 'r2', maxBitrate: 500000, scalabilityMode: 'S1T3' },
- ],
- codecOptions: {
- videoGoogleStartBitrate: 1000,
- },
-};
-
export const VIDEO_PRODUCER_OPTIONS: ProducerOptions = {
encodings: [
- { rid: 'r0', maxBitrate: 50000, scalabilityMode: 'S1T3' },
- { rid: 'r1', maxBitrate: 150000, scalabilityMode: 'S1T3' },
- { rid: 'r2', maxBitrate: 500000, scalabilityMode: 'S1T3' },
+ {
+ rid: 'r0',
+ maxBitrate: 750000,
+ maxFramerate: 30,
+ },
+ {
+ rid: 'r1',
+ maxBitrate: 2000000,
+ maxFramerate: 30,
+ },
+ {
+ rid: 'r2',
+ maxBitrate: 3500000,
+ maxFramerate: 30,
+ },
],
codecOptions: {
- videoGoogleStartBitrate: 1000,
+ videoGoogleStartBitrate: 100000,
opusDtx: true,
},
};
diff --git a/packages/mediasoup/src/server/index.ts b/packages/mediasoup/src/server/index.ts
index 43402b54..6e3afd84 100644
--- a/packages/mediasoup/src/server/index.ts
+++ b/packages/mediasoup/src/server/index.ts
@@ -77,14 +77,3 @@ export interface ChangeConsumerPreferredLayersDto {
roomId: string;
networkQualities: NetworkQualityDto[];
}
-
-export const PRODUCER_OPTIONS = {
- encodings: [
- { rid: 'r0', maxBitrate: 50000, scalabilityMode: 'S1T3', active: true, dtx: false },
- { rid: 'r1', maxBitrate: 150000, scalabilityMode: 'S1T3', active: true, dtx: false },
- { rid: 'r2', maxBitrate: 500000, scalabilityMode: 'S1T3', active: true, dtx: false },
- ],
- codecOptions: {
- videoGoogleStartBitrate: 1000,
- },
-};
diff --git a/packages/types/src/dashboard/getDashboardList.ts b/packages/types/src/dashboard/getDashboardList.ts
index 0c1349db..a8c4dd26 100644
--- a/packages/types/src/dashboard/getDashboardList.ts
+++ b/packages/types/src/dashboard/getDashboardList.ts
@@ -36,6 +36,7 @@ const BaseDashboardResponseSchema = z.object({
startTime: z.string().datetime(),
endTime: z.string().datetime(),
ticleStatus: z.enum([TicleStatus.CLOSED, TicleStatus.OPEN, TicleStatus.IN_PROGRESS]),
+ summary: z.boolean(),
});
const AppliedTicleSchema = BaseDashboardResponseSchema.extend({