오늘은 화면 공유에 대해서 포스팅 하려고 한다. 줌이나 디스코드 등은 화면 공유를 할 시, 자신의 캠 화면이 화면 공유로 대체 된다. 하지만 Eyeve 프로젝트의 화면 공유는 화면 대체가 아닌 자신의 얼굴 화면과 공유 화면이 둘다 송출 되어야 했기 때문에 일반적인 로직들과 다소 달랐다.
또한 화면 대체만 하면 로직이 어렵지 않지만 공유된 화면과 캠 화면 둘 다 송출하는 경우에는 레퍼런스가 없어서 추측성으로 '이렇게 하면 되지 않을까?' 싶어서 로직들을 생각했다. 다행히도 우리의 추측은 맞았고 공유 화면과 캠 화면 둘 다 송출하는 방향으로 개발 완료했다.
이전 글에서 화상 회의 로직들을 설명 했으니, 이에 대한 이해를 전제로 설명하겠다.
결론부터 말하자면 화면 공유를 위한 WebRtcEndpoint를 추가적으로 생성하면 된다.
예시를 들어 보자면,
모든 사람들은 방 진입 시, 자신의 캠 화면을 송출하기 위한 WebRtcEndpoint를 만든다.
자신 이외의 다른 사람이 들어오면 기존에 방에 있던 사람들은 새로 들어온 사람의 미디어를 수신하기 위해 WebRtcEndpoint 객체를 만든다.
새로 들어온 사람도 기존 방에 있던 사람들의 미디어를 수신하기 위해 방에 있는 사람들의 수만큼 WebRtcEndpoint를 만든다.
이제 여기서 화면 공유를 위한 WebRtcEndpoint 객체를 추가하면 되는 것이다.
교수자만 화면 공유를 할 수 있으니, 교수자는 방 생성 시, 화면 공유 송출을 위한 WebRtcEndpoint 객체를 추가적으로 만든다.
아래의 SharingEndpoint가 화면 공유 송출 객체이다.
@RequiredArgsConstructor
public class UserSession {
private User user;
private WebSocketSession webSocketSession;
private WebRtcEndpoint webRtcEndpoint;
//화면 공유 송출 객체
private WebRtcEndpoint sharingEndpoint;
private ConcurrentMap<String, WebRtcEndpoint> downStreams;
private LearningStatus learningStatus;
private boolean concentrating;
private double concentrateRate = 0;
public UserSession(User user,
WebSocketSession session,
WebRtcEndpoint webRtcEP,
WebRtcEndpoint screenSharingEP,
ConcurrentMap<String, WebRtcEndpoint> downStreams,
LearningStatus learningStatus) {
this.user = user;
this.webSocketSession = session;
this.webRtcEndpoint = webRtcEP;
this.sharingEndpoint = screenSharingEP;
this.downStreams = downStreams;
this.learningStatus = learningStatus;
this.concentrating = false;
}
따라서 방 생성 이후, 교수자가 방에 JOIN 할 시, 자신의 캠 화면 송출 객체인 WebRtcEndpoint 이외의 sharingEndpoint를 하나 더 만들고, 이에 대한 Signaling 과정도 동일하게 해준다.
그리고 교수자가 아닌 학생들(방 생성자가 아닌 사람들)은 화면 공유 송출 객체인 sharingEndpoint를 만들 필요가 없다. 따라서 학생은 각 방에 있는 사람들의 수 + 1 만큼의 DownStream(WebRtcEndpoint) 객체를 만들어야 한다. (+1 해서 만든 객체가 공유 화면을 수신하기 위한 객체이다.)
이렇게 만든 DownStream도 똑같이 Signaling 과정을 진행하고 교수자의 화면 공유 객체와 connect를 해준다.
/*
화면공유 DownStream 생성
*/
public void createScreenSharingEP(Rooms roomJoined, UserSession senderSession, String creatorId) {
WebRtcEndpoint ScreenSharingEP = new WebRtcEndpoint.Builder(roomJoined.getPipeline()).build();
senderSession.getDownStreams().put("SCREEN_SHARING", ScreenSharingEP);
addIceEventListener(senderSession, ScreenSharingEP, "SCREEN_SHARING", "SCREEN_SHARING_ICE_CANDIDATE");
UserSession creatorSession = roomJoined.getUserInRoomList().get(creatorId);
//화면 공유 객체 연결
creatorSession.getSharingEndpoint().connect(ScreenSharingEP);
}
화면 공유 객체도 Signaling(Sdp 교환, Ice 후보자 교환)을 해야 하기 때문에 구별을 위해 senderId에 "SCREEN_SHARING"을 붙여서 구별하였다. (기존 같으면 senderId에는 userId가 들어갔다.)
이렇게 하면 화면 공유가 완료된다.