Skip to content

Commit c93bc5d

Browse files
authored
Merge pull request #374 from boostcampwm-2024/Fix/341
[Fix] 캔버스 사용으로 인한 클라이언트 부하 문제 해결
2 parents 3d936d8 + 1324c18 commit c93bc5d

File tree

9 files changed

+235
-162
lines changed

9 files changed

+235
-162
lines changed

apps/client/src/hooks/useMedia.ts

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import { useEffect, useRef, useState } from 'react';
2+
3+
export const useMedia = () => {
4+
// 미디어 스트림 ref와 상태들
5+
const mediaStreamRef = useRef<MediaStream | null>(null);
6+
const [mediaStreamError, setMediaStreamError] = useState<Error | null>(null);
7+
const [isMediaStreamReady, setIsMediaStreamReady] = useState(false);
8+
9+
// 미디어 컨트롤 상태들
10+
const [isVideoEnabled, setIsVideoEnabled] = useState(true);
11+
const [isAudioEnabled, setIsAudioEnabled] = useState(true);
12+
13+
const initializeStream = async () => {
14+
try {
15+
const mediaStream = await navigator.mediaDevices.getUserMedia({
16+
video: {
17+
width: { ideal: 1920 },
18+
height: { ideal: 1080 },
19+
aspectRatio: { ideal: 16 / 9 },
20+
facingMode: { ideal: 'user' },
21+
},
22+
audio: true,
23+
});
24+
25+
mediaStreamRef.current = mediaStream;
26+
setIsMediaStreamReady(true);
27+
28+
// 초기 트랙 상태 설정
29+
const videoTrack = mediaStream.getVideoTracks()[0];
30+
const audioTrack = mediaStream.getAudioTracks()[0];
31+
setIsVideoEnabled(videoTrack?.enabled ?? false);
32+
setIsAudioEnabled(audioTrack?.enabled ?? false);
33+
} catch (err) {
34+
setMediaStreamError(err instanceof Error ? err : new Error('유저 미디어(비디오, 오디오) 갖고 오기 실패'));
35+
}
36+
};
37+
38+
const getNewVideoStream = async () => {
39+
try {
40+
// 비디오만 새로 받아옴
41+
const newVideoStream = await navigator.mediaDevices.getUserMedia({
42+
video: true,
43+
audio: false, // 오디오는 새로 받지 않음
44+
});
45+
46+
if (mediaStreamRef.current) {
47+
// 기존 오디오 트랙 유지
48+
const audioTrack = mediaStreamRef.current.getAudioTracks()[0];
49+
50+
// 기존 비디오 트랙만 정리
51+
mediaStreamRef.current.getVideoTracks().forEach(track => track.stop());
52+
53+
// 새로운 스트림에 기존 오디오 트랙 추가
54+
newVideoStream.addTrack(audioTrack);
55+
}
56+
57+
mediaStreamRef.current = newVideoStream;
58+
setIsVideoEnabled(true);
59+
60+
return newVideoStream;
61+
} catch (err) {
62+
setMediaStreamError(err instanceof Error ? err : new Error('비디오 스트림 획득 실패'));
63+
return null;
64+
}
65+
};
66+
67+
const toggleVideo = () => {
68+
if (!mediaStreamRef.current) return;
69+
const videoTrack = mediaStreamRef.current.getVideoTracks()[0];
70+
if (videoTrack) {
71+
videoTrack.enabled = !videoTrack.enabled;
72+
setIsVideoEnabled(videoTrack.enabled);
73+
}
74+
};
75+
76+
const toggleAudio = () => {
77+
if (!mediaStreamRef.current) return;
78+
79+
const audioTrack = mediaStreamRef.current.getAudioTracks()[0];
80+
if (audioTrack) {
81+
audioTrack.enabled = !audioTrack.enabled;
82+
setIsAudioEnabled(audioTrack.enabled);
83+
}
84+
};
85+
86+
// 초기화 및 클린업
87+
useEffect(() => {
88+
initializeStream();
89+
90+
return () => {
91+
if (mediaStreamRef.current) {
92+
mediaStreamRef.current.getTracks().forEach(track => track.stop());
93+
}
94+
};
95+
}, []);
96+
97+
return {
98+
getNewVideoStream,
99+
mediaStream: mediaStreamRef.current,
100+
mediaStreamError,
101+
isMediaStreamReady,
102+
isVideoEnabled,
103+
isAudioEnabled,
104+
toggleVideo,
105+
toggleAudio,
106+
};
107+
};

apps/client/src/hooks/useMediaControls.ts

Lines changed: 0 additions & 54 deletions
This file was deleted.

apps/client/src/hooks/useMediaStream.ts

Lines changed: 0 additions & 39 deletions
This file was deleted.

apps/client/src/hooks/useProducer.ts

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
import { useEffect, useRef, useState } from 'react';
22
import { Transport, Device, Producer } from 'mediasoup-client/lib/types';
3-
import { ConnectTransportResponse, Tracks, TransportInfo } from '@/types/mediasoupTypes';
3+
import { ConnectTransportResponse, TransportInfo } from '@/types/mediasoupTypes';
44
import { Socket } from 'socket.io-client';
55
import { checkDependencies } from '@/utils/utils';
66
import { ENCODING_OPTIONS } from '@/constants/videoOptions';
77

88
interface UseProducerProps {
99
socket: Socket | null;
10-
tracks: Tracks;
11-
isStreamReady: boolean;
10+
// tracks: Tracks;
11+
// isStreamReady: boolean;
12+
mediaStream: MediaStream | null;
13+
isMediaStreamReady: boolean;
1214
roomId: string;
1315
device: Device | null;
1416
transportInfo: TransportInfo | null;
@@ -23,8 +25,8 @@ interface UseProducerReturn {
2325

2426
export const useProducer = ({
2527
socket,
26-
tracks,
27-
isStreamReady,
28+
mediaStream,
29+
isMediaStreamReady,
2830
roomId,
2931
device,
3032
transportInfo,
@@ -70,10 +72,10 @@ export const useProducer = ({
7072
};
7173

7274
const createProducer = async (socket: Socket, transportInfo: TransportInfo) => {
73-
if (!transport.current || !socket || !tracks) {
75+
if (!transport.current || !socket || !mediaStream) {
7476
const dependencyError = checkDependencies('createProducer', {
7577
socket,
76-
tracks,
78+
mediaStream,
7779
transport: transport.current,
7880
});
7981
setError(dependencyError);
@@ -99,28 +101,27 @@ export const useProducer = ({
99101
);
100102
});
101103

102-
(Object.keys(tracks) as Array<keyof Tracks>).forEach(kind => {
103-
if (tracks[kind]) {
104-
const producerConfig: Record<string, unknown> = {
105-
track: tracks[kind],
106-
};
104+
mediaStream.getTracks().forEach(track => {
105+
const producerConfig: Record<string, unknown> = {
106+
track: track,
107+
stopTracks: false,
108+
};
107109

108-
if (kind === 'video') {
109-
producerConfig['encodings'] = ENCODING_OPTIONS;
110-
producerConfig['codecOptions'] = {
111-
videoGoogleStartBitrate: 1000,
112-
};
113-
}
114-
115-
transport
116-
.current!.produce(producerConfig)
117-
.then(producer => setProducers(prev => new Map(prev).set(kind, producer)));
110+
if (track.kind === 'video') {
111+
producerConfig['encodings'] = ENCODING_OPTIONS;
112+
producerConfig['codecOptions'] = {
113+
videoGoogleStartBitrate: 1000,
114+
};
118115
}
116+
117+
transport.current!.produce(producerConfig).then(producer => {
118+
setProducers(prev => new Map(prev).set(track.kind, producer));
119+
});
119120
});
120121
};
121122

122123
useEffect(() => {
123-
if (!socket || !device || !roomId || !tracks || !isStreamReady || !transportInfo) {
124+
if (!socket || !device || !roomId || !mediaStream || !isMediaStreamReady || !transportInfo) {
124125
return;
125126
}
126127

@@ -134,7 +135,7 @@ export const useProducer = ({
134135
transport.current = null;
135136
}
136137
};
137-
}, [socket, device, roomId, transportInfo, isStreamReady]);
138+
}, [socket, device, roomId, transportInfo, isMediaStreamReady]);
138139

139140
return {
140141
transport: transport.current,

0 commit comments

Comments
 (0)