ploffer11 / WebRTC-Group-Chatting

WebRTC를 통한 Group Chatting 구현
0 stars 2 forks source link

WebRTC 를 통한 화상 채팅 구현 #17

Open ploffer11 opened 1 year ago

ploffer11 commented 1 year ago

소규모 화상채팅을 위한 WebRTC 프로젝트인 만큼, WebRTC에 대한 논의가 충분히 이뤄져야 한다고 생각합니다.

아래의 내용을 참고해서 API를 좀 더 구체적으로 설계하면 좋을 것 같습니다.

MDN 참고

Interactive Connectivity Establishment (ICE)

Interactive Connectivity Establishment (ICE) 는 브라우저가 peer를 통한 연결이 가능하도록 하게 해주는 framework입니다. Peer A에서 Peer B까지 단순하게 연결하는 것으로는 작동하지 않는 것에 대한 이유는 많이 있습니다. 연결을 시도하는 방화벽을 통과해야 하기도 하고, 단말에 public IP가 없다면 유일한 주소값을 할당해야할 필요도 있으며 라우터가 peer간의 직접 연결을 허용하지 않을 때에는 데이터를 릴레이해야할 경우도 있습니다. ICE는 이러한 작업을 수행하기 위해 STUN과 TURN 서버 둘 다 혹은 하나의 서버를 사용합니다.

STUN 서버

Session Traversal Utilities for NAT (STUN) 서로 다른 클라이언트가 연결하기 전에, 클라이언트는 STUN 서버를 통해 "자신의 public ip"가 무엇인지 질문합니다. 물론, 서로 public ip를 STUN서버를 통해 알아냈다고 해도 NAT에 따라서 직접 연결이 불가능할 수도 있습니다.

TURN 서버

Symmetric NAT란 peer들이 오직 이전에 연결한 적 있는 연결만 허용하는 NAT를 말합니다. 만약 클라이언트의 NAT가 Symmetric할 경우, 다른 모든 peer들에게 "모든 패킷을 내가 아니라 TURN 서버에 보내줘" 라고 전달하고, TURN 서버를 통해 모든 패킷을 전달 받아야 합니다.

Session Description Protocol (SDP)

해상도나 형식, 코덱, 암호화 등의 멀티미디어 컨텐츠의 연결을 설명하기 위한 표준입니다. 이러한 것이 두 개의 peer가 다른 한쪽이 데이터가 전송되고 있다는 것을 알게 해줍니다. 이것은 기본적으로 미디어 컨텐츠 자체가 아닌 컨텐츠에 대한 메타 데이터 설명이 됩니다.

기술적으로 보자면 SDP 는 프로토콜이 아닙니다. 그러나 데이터 format은 디바이스간의 미디어를 공유하기 위한 연결을 설명하기 위해 사용됩니다.

Signaling 서버

WebRTC 두 peer가 연결하려면 각 client는 ICE Candidate와 Session Description을 주고 받아야 합니다. 이는 중개 서버가 없이는 불가능하고, 이를 중개해주는 서버를 Signaling Server라고 합니다.

Offer and Answer

peer가 서로 연결하기 위해서는 SDP를 포함한 Offer와 Answer를 교환해야 합니다. Connection을 여는 Caller가 Offer를 만들고, Signal Channel에 보냅니다. Callee는 signal channel을 통해 Offer를 받고, Answer를 생성해 Signal Channel에 보냅니다.

Session Description

WebRTC 연결을 위한 configuration을 Session Description라고 합니다. 여기에는 SDP, IP, 프로토콜 등 통신에 필요한 정보가 저장됩니다. 위에서 얘기한 Offer and Answer 과정은 사실 통신하기 전에 서로의 Session Description을 교환하는 내용입니다.

이 교환은 ICE(STUN/TURN 서버를 사용해 두 peer를 연결하는 프레임워크)에 의해 핸들링 됩니다.

Peer connection 절차

  1. Caller가 local Media를 MediaDevices.getUserMedia 로 캡쳐합니다.

  2. Caller가 RTCPeerConnection을 만들고, RTCPeerConnection.addTrack()을 호출합니다.

  3. Caller가 RTCPeerConnection.createOffer() 로 Offer를 생성합니다.

  4. Caller가 RTCPeerConnection.setLocalDescription()로 offer를 local description으로 설정합니다.

  5. setLocalDescription()을 한 후에, caller는 STUN 서버에 ICE Candidate를 생성해달라고 요청합니다.

  6. Caller는 signaling server를 사용해 Offer를 전송합니다.

  7. Callee는 Offer를 받고, RTCPeerConnection.setRemoteDescription()를 호출해 이를 remote description으로 설정합니다.

  8. Callee는 call의 end를 위한 설정을 하고, local media를 캡쳐해 media track을 RTCPeerConnection.addTrck()을 통해 피어 연결에 attach합니다.

  9. Callee는 RTCPeerConnection.createAnswer()로 Answer를 생성합니다.

  10. Callee는 RTCPeerConnection.setLocalDescription()를 호출해 Answer를 local description으로 설정하고해 생성된 답변을 전달합니다. 이제 Callee는 connection의 양쪽 끝의 configuration을 알게 되었습니다.

  11. Callee는 signal server를 사용해 caller에게 Answer를 전달하고, caller는 Answer를 수신합니다.

  12. Caller는 RTCPeerConnection.setRemoteDescription()를 호출해 Answer를 call의 end를 위한 remote description으로 설정합니다. 이제 둘 다 서로의 configuration을 알고 있으므로, media는 configured된대로 흐르게 됩니다.

Handling Symmetric NAT

위의 절차에서는 Symmetric NAT에 대한 고려가 없습니다. 이를 고려하기 위해 연결 전에 각 peer는 STUN 서버에 자신의 public ip와 Symmetric NAT 여부를 전달 받습니다. 이후 Signaling Server를 통해 Offer/Answer로 Session Description을 주고 받는 동시에 new RTCIceCandidate(candidate)로 만들어낸 ICECandidate 정보를 주고 받습니다. 여기서 둘 중 하나라도 Symmetric NAT일 경우, TURN 서버를 이용해 데이터를 릴레이해야 합니다.

ICE Configuration에서 iceServers로 TURN 서버에 대한 정보를 등록해둘 수 있고, STUN 서버도 등록해둘 수 있습니다. TURN 서버를 등록해두면 Symmetric할 경우 TURN 서버를 통해 데이터의 릴레이가 진행됩니다.

ploffer11 commented 1 year ago

채팅방 API까지 완성된 상태에서 WebRTC API 이식을 위한 절차를 제안합니다.

채팅방에 webrtc 유저가 있는 상태에서 새로온 유저가 webrtc로 enter하는 상황

프론트엔드에서는 다음과 같은 절차가 필요합니다.

ploffer11 commented 1 year ago