본문 바로가기
프로그래밍/WebRTC

[WebRTC] SFU 서버 구현

by YuminK 2023. 9. 19.

SFU 서버 구현은 쉽지 않았다... 라고 하지만 밀로님께서 이미 구현해놓으신 코드가 있어서 많은 참고가 되었다. 로직 자체가 크게 어렵지 않으니까 보다보면 충분히 이해된다. 참고로 Signaling 같은 고급 기술은 포함되어 있지 않다. 단순히 Peer간의 컨셉만 구현했다. 

 

SFU 서버 구축에 대한 이해도가 부족해서, 다른 소스는 어떤 식으로 작성이 되었는지 찾아보았다. 서버와 클라간 Peer를 연결하고 서버에서 유저의 스트림을 관리한다는 컨셉은 동일하더라.

 

핵심 로직에 대한 언급을 하기 이전에 컨셉을 이해 해야 한다. 

 

SFU 방식은 브라우저간 직접적인 P2P 통신을 하지 않는다. 각 브라우저는 서버와 P2P 연결을 하는데 서버에 자신의 스트림을 주는 SendPeer와 다른 브라우저의 스트림을 받는 RecvPeer가 존재한다. 여기서 Send와 Recv는 상대적인 개념인데 유저의 입장에서 Send라면 서버의 입장에선 Recv라고 이름을 짓는다. 

 

새로 들어온 유저의 경우에는 기존에 있던 유저의 id List를 받아서(id를 식별자로 사용) 서버와 RecvPeer를 만들고 SendPeer를 생성한다. 그리고 SendPeer의 track이 추가되는 시점에 다른 클라이언트에게 newStream 이벤트를 넘겨서 새로 들어온 유저의 스트림을 받는 RecvPeer를 하나 생성한다. (그림 참고)

 

유저의 입장에서는 다른 유저에 해당하는 수만큼 RecvPeer가 있어야 한다. 나의 경우 Map<id, PeerConnection>의 형태로 관리했다. 반면 SendPeer의 경우에는 1개만 있으면 된다. 

 

서버의 입장에서는 유저의 수만큼 RecvPeer가 있으면 된다. Map<id, PeerConnection>으로 관리한다. 그리고 특정 유저의 스트림을 받는 다른 유저들의 관계를 표현하는 Peer가 있어야 한다.

 

A를 기준으로 한다면 A=>B, A=>C를 표현할 수 있어야 한다. 따라서 타입은 Map<sendId, Map<recvId, PeerConnection>>으로 처리했다. 이러면 특정 유저의 스트림을 받는 그 외의 유저들간의 PeerConnection을 처리할 수 있으니까.

(여기서 주의할 점은 A와 B를 직접적으로 연결하는 개념이 아니다. 서버에서 Stream 정보를 갖고 있다가 연결되는 Peer에 할당하는 개념이다.)

 

또한 Stream을 관리하기 위한 Map을 하나 둔다. Room별로 구분하여 타입은 Map<roomName, Map<id, Stream>>이 된다. 특정 룸 내부에 존재하는 모든 유저에 대한 스트림을 관리한다. 

 

그림에서 화살표는 Stream의 방향을 의미한다. 유저 입장에서 SendPeer의 경우 자신은 Stream을 받지 않는다. (offerTo*** = false) 반대로 RecvPeer의 경우에는 스트림을 받도록 처리한다. (offerTo*** = true)

 

서버 입장에서 RecvPeer에서는 Stream을 받고, SendPeer에서는 Stream을 받지 않는다. 또한 유저의 스트림 정보가 추가되었을 때(서버 기준 RecvPeer의 track) 다른 클라에게 이벤트(newStream)를 주게 된다. 

 

서버가 SendPeer를 생성하는 과정에서 해당 Peer와 매칭되는 id의 stream 정보를 넘겨주고 있고....

 

새로운 유저가 들어왔을 때의 이벤트 순서는 유저 기준 Send, Recv(거의 동시) 그리고 다른 유저에 대한 RecvPeer 순으로 진행된다. 특정 유저가 나갔을 때는 서버에서 유저 스트림 정보, RecvPeerMap, SendPeerMap에서 정보를 날리고.. 클라쪽에서도 RecvPeerMap 정보를 정리해주고 있다. 

소스코드

https://github.com/Yumin2019/WebRTC-P2P-Implement/tree/sfu-server

 

참고 자료

https://millo-l.github.io/WebRTC-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0-1-N-SFU/

https://github.com/tiger2380/simple_sfu

댓글