diff --git a/README.md b/README.md
index af8d7e9a..54abff5e 100644
--- a/README.md
+++ b/README.md
@@ -147,6 +147,7 @@
## 프론트엔드
+
> 최대한 많은 유저가 들어와 화상 서비스를 이용하는 것을 목적으로 하는 만큼 소켓 이벤트, 기존 할당된 자원에 대한 관리를 진행하며 최대한 적은 자원으로 나은 환경을 제공하기 위해 최적화를 진행하였습니다.
diff --git a/apps/media/src/mediasoup/config.ts b/apps/media/src/mediasoup/config.ts
index 7371a5e8..0d27a8f5 100644
--- a/apps/media/src/mediasoup/config.ts
+++ b/apps/media/src/mediasoup/config.ts
@@ -29,10 +29,22 @@ export class MediasoupConfig {
useinbandfec: 1,
},
},
+ {
+ kind: 'video',
+ mimeType: 'video/H264',
+ clockRate: 90000,
+ parameters: {
+ 'packetization-mode': 1,
+ 'profile-level-id': '42e01f',
+ },
+ },
{
kind: 'video',
mimeType: 'video/VP8',
clockRate: 90000,
+ parameters: {
+ 'x-google-start-bitrate': 10000,
+ },
},
] as RtpCodecCapability[],
};
diff --git a/apps/media/src/mediasoup/mediasoup.service.ts b/apps/media/src/mediasoup/mediasoup.service.ts
index 5b4549dd..e82cf215 100644
--- a/apps/media/src/mediasoup/mediasoup.service.ts
+++ b/apps/media/src/mediasoup/mediasoup.service.ts
@@ -113,10 +113,6 @@ export class MediasoupService implements OnModuleInit {
const peer = room.getPeer(socketId);
const transport = peer.getTransport(transportId);
- if (appData.mediaTypes !== 'audio') {
- rtpParameters.encodings = server.PRODUCER_OPTIONS.encodings;
- }
-
const producer = await transport.produce({
kind,
rtpParameters,
@@ -269,6 +265,8 @@ export class MediasoupService implements OnModuleInit {
const peer = room.peers.get(socketId);
const consumer = peer.getConsumer(consumerId);
+ if (!consumer) return;
+
consumer?.pause();
return { paused: true, consumerId, producerId: consumer.producerId };
@@ -279,6 +277,8 @@ export class MediasoupService implements OnModuleInit {
const peer = room.peers.get(socketId);
const consumer = peer.getConsumer(consumerId);
+ if (!consumer) return;
+
if (consumer?.producerPaused) {
return { paused: true, consumerId, producerId: consumer.producerId };
}
@@ -289,11 +289,15 @@ export class MediasoupService implements OnModuleInit {
}
pauseConsumers(socketId: string, roomId: string, consumerIds: string[]) {
- return consumerIds.map((consumerId) => this.pauseConsumer(socketId, consumerId, roomId));
+ return consumerIds
+ .map((consumerId) => this.pauseConsumer(socketId, consumerId, roomId))
+ .filter(Boolean);
}
resumeConsumers(socketId: string, roomId: string, consumerIds: string[]) {
- return consumerIds.map((consumerId) => this.resumeConsumer(socketId, consumerId, roomId));
+ return consumerIds
+ .map((consumerId) => this.resumeConsumer(socketId, consumerId, roomId))
+ .filter(Boolean);
}
changeConsumerPreferredLayers(
@@ -307,10 +311,9 @@ export class MediasoupService implements OnModuleInit {
const consumer = peer.getConsumer(consumerId);
- consumer?.setPreferredLayers({
- spatialLayer: networkQuality,
- temporalLayer: networkQuality,
- });
+ if (!consumer || consumer.closed || consumer.paused) return;
+
+ consumer.setPreferredLayers({ spatialLayer: networkQuality });
});
}
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/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/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,
- },
-};