Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions frontend/src/components/session/MediaPreviewModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,7 @@ const MediaPreviewModal = ({
const getMediaPreview = useCallback(async () => {
const mediaStream = await getMediaStream("video");
if (!mediaStream) {
toast.error(
"비디오 장치를 찾을 수 없습니다. 비디오 장치 없이 세션에 참가합니다."
);
toast.error("비디오 장치를 찾을 수 없습니다.");
}
setPreview(mediaStream);
}, []);
Expand Down Expand Up @@ -100,7 +98,7 @@ const MediaPreviewModal = ({
className={"w-6 h-6"}
type={"checkbox"}
title={"dd"}
onClick={() => setIsVideoOn(!isVideoOn)}
onChange={() => setIsVideoOn(!isVideoOn)}
/>
<span>내 비디오 끄고 참가하기</span>
</label>
Expand Down Expand Up @@ -134,6 +132,7 @@ const MediaPreviewModal = ({
onConfirm();
setReady(true);
modal.closeModal();
preview?.getTracks().forEach((track) => track.stop());
}}
className={
"rounded-custom-m px-16 py-4 bg-green-500 text-white hover:bg-green-600"
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/pages/SessionPage/hooks/useBlockNavigate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ const useBlockNavigate = () => {
}
}, [blocker]);

useEffect(() => {
return () => {
if (blocker) setShouldBlock(false);
};
}, []);

useEffect(() => {
const handleBeforeUnload = (e: BeforeUnloadEvent) => {
e.preventDefault();
Expand Down
63 changes: 36 additions & 27 deletions frontend/src/pages/SessionPage/hooks/useMediaDevices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ const useMediaDevices = (dataChannels: DataChannels) => {
};
}, []);

const getMedia = async (videoOn = true) => {
const getMedia = async () => {
try {
if (streamRef.current) {
// 이미 스트림이 있으면 종료
Expand All @@ -90,14 +90,14 @@ const useMediaDevices = (dataChannels: DataChannels) => {
let audioStream = null;

try {
videoStream = await navigator.mediaDevices.getUserMedia({
video: videoOn
? selectedVideoDeviceId
? { deviceId: selectedVideoDeviceId }
: true
: false,
audio: false,
});
videoStream = isVideoOn
? await navigator.mediaDevices.getUserMedia({
video: selectedVideoDeviceId
? { deviceId: selectedVideoDeviceId }
: true,
audio: false,
})
: null;
} catch (videoError) {
console.warn("비디오 스트림을 가져오는데 실패했습니다:", videoError);
setIsVideoOn(false);
Expand All @@ -120,7 +120,7 @@ const useMediaDevices = (dataChannels: DataChannels) => {
// 스트림 병합 또는 개별 스트림 사용
let combinedStream = null;
const tracks = [
...(videoStream?.getVideoTracks() || []),
...(videoStream?.getVideoTracks() || [createDummyStream()]),
...(audioStream?.getAudioTracks() || []),
];

Expand All @@ -139,7 +139,6 @@ const useMediaDevices = (dataChannels: DataChannels) => {
"미디어 스트림을 가져오는 도중 문제가 발생했습니다.",
error
);
// 에러 처리 로직 (예: 사용자에게 알림)
} finally {
setVideoLoading(false);
}
Expand Down Expand Up @@ -182,20 +181,10 @@ const useMediaDevices = (dataChannels: DataChannels) => {
if (isVideoOn) {
for (const videoTrack of stream.getVideoTracks()) {
// 비디오 끄기
if (!videoTrack.enabled) {
setIsVideoOn((prev) => !prev);
return;
}
videoTrack.stop();

const blackCanvas = document.createElement("canvas");
blackCanvas.width = 640;
blackCanvas.height = 480;
const ctx = blackCanvas.getContext("2d");
ctx!.fillRect(0, 0, blackCanvas.width, blackCanvas.height);
videoTrack.stop();

const blackStream = blackCanvas.captureStream();
const blackTrack = blackStream.getVideoTracks()[0];
const blackTrack = createDummyStream();
Object.values(peerConnections || {}).forEach((pc) => {
const sender = pc
.getSenders()
Expand All @@ -219,18 +208,22 @@ const useMediaDevices = (dataChannels: DataChannels) => {
if (videoStream) {
if (streamRef.current) {
const oldVideoTracks = streamRef.current.getVideoTracks();
oldVideoTracks.forEach((track) =>
streamRef.current?.removeTrack(track)
);
oldVideoTracks.forEach((track) => {
track.stop();
streamRef.current?.removeTrack(track);
});

streamRef.current.addTrack(newVideoTrack);
setStream(streamRef.current);

console.log("피어업데이트", peerConnections);
Object.values(peerConnections || {}).forEach((pc) => {
const sender = pc
.getSenders()
.find((s) => s.track?.kind === "video");
.find((s) => s.track!.kind === "video");
if (sender) {
console.log("비디오 켜기 업데이트");

sender.replaceTrack(newVideoTrack);
}
});
Expand Down Expand Up @@ -284,6 +277,22 @@ const useMediaDevices = (dataChannels: DataChannels) => {
}
};

const createDummyStream = () => {
const blackCanvas = document.createElement("canvas");
blackCanvas.width = 640;
blackCanvas.height = 480;
const ctx = blackCanvas.getContext("2d");
ctx!.fillRect(0, 0, blackCanvas.width, blackCanvas.height);

const blackStream = blackCanvas.captureStream();
const blackTrack = blackStream.getVideoTracks()[0];
Object.defineProperty(blackTrack, "label", {
value: "blackTrack",
writable: false,
});
return blackTrack;
};

return {
userAudioDevices,
userVideoDevices,
Expand Down
31 changes: 29 additions & 2 deletions frontend/src/pages/SessionPage/hooks/usePeerConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,25 @@ const usePeerConnection = (socket: Socket) => {
mediaDataChannel.onopen = () => {
console.log("Media data channel opened.");
dataChannels.current[peerSocketId] = mediaDataChannel;

const audioTracks = stream.getAudioTracks();
const audioEnabled = audioTracks.length > 0 && audioTracks[0].enabled;

const videoTracks = stream.getVideoTracks();
const videoEnabled =
videoTracks.length > 0 && videoTracks[0].label !== "blackTrack";
mediaDataChannel.send(
JSON.stringify({
type: "audio",
status: audioEnabled,
})
);
mediaDataChannel.send(
JSON.stringify({
type: "video",
status: videoEnabled,
})
);
};

mediaDataChannel.onclose = () => {
Expand Down Expand Up @@ -178,12 +197,20 @@ const usePeerConnection = (socket: Socket) => {
},
];
});

const audioTracks = e.streams[0].getAudioTracks();
const audioEnabled = audioTracks.length > 0 && audioTracks[0].enabled;

const videoTracks = e.streams[0].getVideoTracks();
const videoEnabled =
videoTracks.length > 0 && videoTracks[0].label !== "blackTrack";

setPeerMediaStatus((prev) => {
return {
...prev,
[peerSocketId]: {
audio: e.streams[0].getAudioTracks().length > 0,
video: e.streams[0].getVideoTracks().length > 0,
audio: audioEnabled,
video: videoEnabled,
},
};
});
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/pages/SessionPage/hooks/useSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export const useSession = (sessionId: string) => {
return;
}

const mediaStream = await getMedia(isVideoOn);
const mediaStream = await getMedia();
if (!mediaStream) {
toast.error(
"미디어 스트림을 가져오지 못했습니다. 미디어 장치를 확인 후 다시 시도해주세요."
Expand Down