-
Notifications
You must be signed in to change notification settings - Fork 0
Feature(#39, #43, #44, #207) socket 통신으로 화이트보드 공유 구현 #210
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
비디오 스트리밍을 사용하지 않고 화이트보드를 공유하는 과정을 구현했습니다.
경과시간을 ms 단위로 저장하도록 개선했습니다.
fabric canvas의 높이와 너비를 전달할 수 있도록 했습니다.
참여자 페이지에서 발표자 화면 비율에 맞춰 화이트보드를 출력하고, 변경 내영 반영과정을 내용/viewport/size로 나누어 변경 내용만 반영하도록 해서 delay를 줄였습니다.
원본 화이트보드의 비율을 가로 기준으로 줄인 후, 해당 화이트보드의 높이가 브라우저 높이보다 클 때, 브라우저 높이에 맞춰 추가로 화이트보드의 크기를 조정합니다.
참여자 페이지에서 화이트보드 데이터를 수신하기 전에 안내 문구를 추가했습니다. 추가로 화이트보드 높이를 변경된 헤더 높이에 맞췄습니다.
❌ Deploy Preview for boarlog failed.
|
function saveCanvasData() { | ||
if (!fabricCanvasRef || !fabricCanvasRef.viewportTransform) return; | ||
|
||
const newJSONData = JSON.stringify(fabricCanvasRef); | ||
const newViewport = fabricCanvasRef.viewportTransform; | ||
const newWidth = fabricCanvasRef.getWidth(); | ||
const newHegiht = fabricCanvasRef.getHeight(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
height 오타인 것 같아요!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
헉 바로 수정하겠습니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
방식 변경 때문에 바뀌는 부분이 많았을 텐데 고생하셨습니다.
frontend/src/components/Header/components/HeaderInstructorControls.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
코드 잘 읽었습니다! 캔버스... 주완님께서 캐리하셨습니다 💫💫
@@ -109,7 +109,7 @@ const HeaderInstructorControls = () => { | |||
if (!socketRef2.current) return; | |||
socketRef2.current.emit("end", { | |||
type: "lecture", | |||
roomId: `1` | |||
roomId: roomid |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
드디어 roomId를 따로 가져갈 수 있군요 :)
interface ICanvasData { | ||
canvasJSON: string; | ||
viewport: number[]; | ||
eventTime: number; | ||
width: number; | ||
height: number; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
interface 정의 좋습니다! 나중에 이러한 정의를 위에 정리할지, 하나의 파일로 따로 구분할지는 함께 생각해봐요 :)
width: data.content.width, | ||
height: data.content.height | ||
}, | ||
{ backstoreOnly: true } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
혹시 이 옵션값은 무엇인가요?
newCanvas.backgroundColor = "lightgray"; | ||
newCanvas.defaultCursor = "default"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이 부분은 비율 구분을 위한 코드인가요?
}, []); | ||
|
||
return ( | ||
<> | ||
<Header type="participant" /> | ||
<section className="relative"> | ||
<video className="w-[100vw] h-[calc(100vh-5rem)]" autoPlay muted ref={videoRef}></video> | ||
<section className="relative w-[100vw] h-[calc(100vh-5rem)]" ref={canvasContainerRef}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
w-[100vw]는 w-screen으로 대체 가능할 것 같습니다 :)
작업 개요
close #39
서버로부터 진행자의 화이트보드를 받아 화면에 렌더링한다.
close #43
화면의 정보들을 주기적으로 서버로 보낸다.
close #44
강의 참여자는 서버로부터 화면의 정보를 받아 화이트보드를 구성한다.
close #207
발표자의 화이트 보드를 공유 될 때, 화질이 저하되어 참여자에게 전달된다.
작업 사항
고민한 점들
1) 화이트보드 정보 전송 과정 변경
기존 방식
변경된 방식
지난 주에 비디오 형태로 전송하기로 한 이유는
위의 2가지 였는데, 현재 미디어 서버에서 소켓 통신이 정상적으로 작동하게 되었고, 화이트보드의 비디오 스트림이 영상으로 잘 저장되지 않는 문제, 참여자 페이지에서 화질 저하가 발생하지만 원인을 찾지 못하고 있는 문제가 생겨 새로운 방식으로 변경해야 할 필요성을 느꼈습니다.
지난 PR (#164 ) 에서 고민한 방법 중 2번 방법으로 새로 구현하기로 결정했습니다.
단점으로 손꼽혔던 아래 3가지 문제에 대해 다시 살펴보겠습니다.
가장 먼저, 데이터를 크게 3가지 (캔버스 내부 객체 변경, 뷰포트(확대, 축소, 이동), 캔버스 크기(발표자 브라우저 크기 변경)) 변경을 1/60초 단위로 체크해서 변경 사항이 있을 때만 데이터를 전송하고, 전송된 데이터는 BE 서버에서 저장하는 것으로 했습니다.
1번은 이번에 구현에 성공하였고, 미디어 서버도 어느 정도 데이터를 잘 전송하는 것을 확인했습니다.
2번의 경우 약식으로 캔버스에 많은 데이터를 그려놓고 테스트를 했을 때에는 문제가 없음을 확인했으나 추가적으로 점검이 필요합니다.
3번은 데이터를 저장할 때, 시작 시간으로부터 경과한 시간을 ms 단위로 저장해서 불러오기 할 예정입니다. 소요 시간이 좀 걸릴 것 같으나, 남은 기간 밤 늦게까지 하다보면 가능 할 것으로 보입니다.
2) 강의자와 같은 화이트보드를 참여자가 보게 하는 과정
현재 참여자 페이지에서 데이터를 받아 로드하는 과정에서 확인해야 할 점은 3가지가 있습니다.
1번은 강의자의 fabric.canvas를 JSON.stringify()로 JSON 형태로 만든 후, fabric.canvas의 loadFromJSON 메서드를 이용해서 구현했습니다.
2번의 경우 지난 주말 동안 여러 방식으로 구현을 시도했는데, 중요한 점은 강의자가 보고있는 canvas의 시점 좌표, 그리고 줌인/줌아웃 정도 2가지였습니다. 고정 크기의 canvas를 사용하는 일반적인 프로젝트들과 달리 우리 화이트보드 프로젝트는 hand 툴과 스크롤을 이용해서 줌인 줌아웃이 가능하고, 강의자의 시점을 그대로 공유해주는 것이 중요하기 때문에 꼭 반영을 해주어야 했습니다.
일차적으로 zoomValue와 fabric.Point를 가지고 다시 랜더링하는 것을 고려했습니다. 이 경우 fabric.Point가 zoomValue에 따라 유동적으로 변할 뿐 아니라, fabric.Point를 계산하는 과정도 적당한 메서드가 없어서 발표자의 화면과 동일한 시점을 확인해주기가 매우 어렵습니다.
결과적으로는 zoomValue와 fabric.Point를 계산할 때 사용하는 fabric.canvas의 속성인 viewportTransform 배열을 강의자가 그대로 전송해서, 참여자가 배열의 viewport 정보를 적용하는 방법으로 구현했습니다.
3번의 경우는 강의자의 화이트보드 크기와 참여자의 화이트보드 크기가 브라우저 크기에 따라 달라져서 생기는 문제입니다.
강의자가 (1920x1080)크기의 화이트보드를 사용하는데, 참여자가 (1280x720) 크기의 화이트보드를 사용하면 꽤 많은 영역이 참여자 페이지에서 보이지 않고 스크롤 바가 생기는 문제가 있습니다.
fabric.canvas에서는 setDimensions 메서드로 크기를 조절하고, 옵션으로 backstoreOnly:true를 줘서 참여자 페이지 크기에 맞춰서 강제로 캔버스 내용을 조절할 수 있습니다. 다만 이 경우에는 원본 비율을 유지하지 못해서 캔버스 내용이 찌그러든다는 단점이 있습니다.
이를 해결하기 위해서 참여자 페이지에서 보여질 캔버스 크기를 원본 비율에 맞춰 계산해서 만들어준 후, 해당 크기에 맞춰 backstoreOnly:true를 주는 방식으로 해결했습니다. 캔버스 크기를 새로 계산하는 과정은 2가지 과정이 필요합니다.
스크린샷
결과물은 다음과 같습니다.
231206.mp4
231206-2.mp4