본문 바로가기

개발/WebRTC

WebRTC란?

💡 WebRTC is a free, open project that provides browsers and mobile applications with Real-Time Communications (RTC) capabilities via simple APIs.
- https://webrtc.org

WebRTC (Web Real-Time Communication)는 웹 브라우저 간에 플러그인의 도움 없이 서로 통신할 수 있도록 설계된 API이다. W3C에서 제시된 초안이며, 음성 통화, 영상 통화, P2P 파일 공유 등으로 활용될 수 있다. - 위키백과

 

WebRTC는 위의 위키백과의 한줄로 잘 소개되어 있듯이 웹(Web)에서 복잡한 플러그인 없이 서로가(P2P) 통신할 수 있도록(RTC) 만들어진 API입니다.

간략히 역사를 따라가면 구글이 2010년 2월 VP8 기술을 가진 On2 Technology를 인수하고, 그 해 5월 iLBC, iSAC 오디오 코덱 기술을 가지고 있던 GIPS를 인수하며 실시간 미디어 통신의 핵심 엔진을 모두 갖추게 되고, 그리고 이를 WebRTC라는 이름으로 오픈 소스화 시켜서 2011년 5월에 발표한 게 그 시작이라고 합니다.

(https://blog.naver.com/koys007/220896666709)

W3C는 WebRTC 1.0 사양의 첫번째 초안을 2011년 10월에 게시하였고, 10년뒤인 2021년 1월에 권고안(Recommendation)으로 확정되었습니다.


WebRTC 3대 API

WebRTC에서는 RTC를 지원하기 위해 제공하는 API들이 있습니다. 이 중에서 표준 API라고 불리는 3개의 API 가 있습니다. 이 API에 대해서 하나씩 알아보겠습니다.

PeerConnection

암호화 및 대역폭 관리를 하는 기능을 가지고 있고, 오디오 또는 비디오 연결을 담당합니다. 애플리케이션이 채집한 음성 및 영상 데이터를 서로 주고 받는 채널을 추상화하였다고 생각하면 됩니다.

MediaStream

사용자의 카메라와 마이크 같은 곳의 데이터 스트림에 접근합니다. 우리의 애플리케이션이 사용자의 음성, 영상 데이터를 채집해 올 때 자주 사용하게 됩니다.

DataChannel

음성 및 영상 데이터를 제외한 나머지 데이터들을 주고받는 채널을 추상화한 API 입니다.

MediaStream과 DataChannel은 서로 독립적으로 작동합니다.

 

Signaling & Stun/Turn

Signaling

앞에서 본 PeerConnection의 역할은 각각의 사용자들을 실제로 연결시켜서 MediaStream과 DataChannel를 통해 얻는 데이터들을 주고받게 합니다. 그럼 이 PeerConnection은 사용자들을 어떻게 찾아서 연결을 하게 해줄까요?

전화를 거는 Caller와 전화를 받는 Callee가 서로를 알고 자신의 위치나 접속 정보들을 서로 교환해야 PeerConnection이 맺어지게 되는데 이 과정을 Signaling이라고 부르고, 자신의 위치나 접속 정보들을 얻기 위해 ICE, Stun/Turn이란 기술들을 쓰게 됩니다.

다시 정리하면, Signaling 단계는 서로 다른 두 peer(WebRTC Client) 가 Communication 하기 위한 준비단계이며, 이 과정에서는 3가지 종류의 정보를 교환해야 합니다.

  • Network 정보를 교환합니다.
  • Media Capability 를 교환합니다.
  • Session Control Messages 교환합니다.

그런데, WebRTC에는 따로 정해진 시그널링 규격은 없습니다. 위의 3가지 정보만 서로간에 잘 교환한다면 시그널링은 어떻게 구현되든 WebRTC에서는 신경쓰지 않는다는 의미입니다.

ICE, Stun/Turn

앞서 말했듯이 Signlaing 단계는 피어와 피어가 서로를 찾을 수 있도록 돕는 중간 매개자 역할을 하는 서버인 Signaling Server 를 필요로 합니다. Signaling에는 별도의 규격이 없기에 Signaling Sever 의 구현 방식에는 제약이 없습니다.

Network 정보를 교환하는 과정이 있는데, 이 과정에서는 자신의 IP, Port와 상대방의 IP, Port를 서로 주고받습니다. WebRTC는 직접적으로 IP를 연결하는 방식으로 통신이 이루어지기 때문에 방화벽, NAT환경에서 Private IP(사설망)를 부여받는 Client는 연결이 불가능합니다. 그래서 중간에 무언가 중개해줘야할 누군가가 필요한데 이러한 방식을 UDP Hole Punching 방식이라고 합니다. 그 방식중에 하나인 Stun에 대해서 알아보겠습니다.

STUN

STUN 은 Session Traversal Utilities for NAT 의 약자입니다. STUN 은 IETF RFC 5389에 정의된 네트워크 프로토콜/패킷 포맷으로, 네트워크 환경에 대한 Discovery 를 위한 것입니다. 메신저들끼리 통신하기 위하여 STUN 패킷을 이용한다고 합니다.

STUN 서버의 구조도

NAT환경에서는 Private IP를 별도로 가지고 있기 때문에 Peer to Peer(이하 P2P) 통신이 불가능합니다. 따라서 클라이언트는 자신의 Public IP를 확인하기 위해 STUN 서버로 요청을 보내고 서버로부터 자신의 Public IP를 받게 됩니다. 그래서 이때부터 클라이언트는 자신이 받은 Public IP를 이용하여 시그널링을 할때 받은 그 정보를 이용해서 시그널링을 하게합니다.

하지만 STUN으로 모든걸 해결할 수는 없는데 바로 두 Client가 같은 네트워크에 존재하고 있을때는 이것으로는 해결이 되지 않습니다. 또한, NAT 환경에서는 Symmetirc NAT의 경우는 어플리케이션이 달라지면 NAT의 매핑테이블이 바뀔 수 있어서 IP나 Port가 STUN 서버로 알아낸 정보와 일치하지 않는 경우가 있을 수 있습니다.

TURN

TURN은 Traversal Using Relays around NAT의 약자입니다. NAT 보안 정책이 너무 엄격하거나 NAT 순회를 하기 위해 필요한 NAT 바인딩을 성공적으로 생성할 수 없는 경우에 TURN을 사용합니다. TURN 서버는 인터넷망에 위치하고 각 Peer(단말)들이 사설망(Private IP) 안에서 통신합니다. 각 Peer들이 직접 통신하는 것이 아니라 릴레이 역할을 하는 TURN 서버를 사용하여 경유합니다. TURN은 이러한 릴레이로부터 IP주소와 포트를 클라이언트가 취득할 수 있는 릴레이 주소를 할당해줍니다.

TURN 서버의 구조도

하지만, 이런 TURN에게 장점만 있는 것은 아닙니다. 클라이언트와의 연결을 거의 항상 제공하지만 미디어를 릴레이 하기 때문에 네트워크와 컴퓨팅 자원이 소모되어 STUN에 비해 리소스 낭비가 심합니다. 그렇기 때문에, ICE Candidate과정에서 local IP로 연결할 수 있는지, Public IP로 연결할 수 있는지를 (모든 후보군을 찾은 후) 알아낸 후 최후의 수단으로 사용해야 합니다.

ICE

여태껏 이야기한 STUN, TURN 서버를 이용해서 획득했던 IP 주소와 프로토콜, 포트의 조합으로 구성된 연결 가능한 네트워크 주소들을 후보(Candidate)라고 부릅니다. 그리고 이 과정을 후보 찾기(ICE Candidate gathering)라고 부릅니다.

이렇게 후보들을 수집하면 일반적으로 3개의 주소를 얻게 됩니다.

  • 자신의 사설 IP와 포트 넘버
  • 자신의 공인 IP와 포트 넘버 (STUN, TURN 서버로부터 획득 가능)
  • TURN 서버의 IP와 포트 넘버 (TURN 서버로부터 획득 가능)

한편, 이 모든 과정은 ICE(Interactive Connectivity Establishment)라는 프레임워크 위에서 이루어집니다. ICE는 Interactive Connectivity Establishment의 약어로 RFC 5245 A protocol for Network Address Translator (NAT) Traversal for Off/Answer Protocols에 정의되었습니다. ICE는 두 단말이 서로 통신할 수 있는 최적의 경로를 찾을 수 있도록 도와주는 프레임워크입니다. ICE는 STUN (Session Traversal Utilities for NAT, RFC 5389)와 TURN (Traversal Using Relay NAT, RFC 5766)을 활용하는 프레임워크로 SDP 제안 및 수락 모델(Offer / Answer Model)에 적용할 수 있습니다.

지금까지의 내용을 요약하자면, ICE 프레임워크가 STUN, 또는 TURN 서버를 이용해 상대방과 연결 가능한 후보들을 갖고 있다는 것입니다. 그러니까 두 Peer/Client가 P2P 통신을 위해 통신할 수 있는 주소만큼은 확실하게 알아낸 셈입니다. 따라서 마지막으로 남은 것은 이제 미디어와 관련된 정보를 교환하는 것입니다.

 


STUN과 TURN 초간단 정리

STUN은 단말이 자신의 공인 IP 주소와 포트를 확인하는 과정에 대한 프로토콜이고, TURN은 단말이 패킷을 릴레이 시켜 줄 서버를 확인하는 과정에 대한 프로토콜입니다.

SDP

SDP는 Session Description Protocol의 약어로 멀티미디어 세션 파라미터를 협상하는 프로토콜입니다. Stun, Turn 서버를 통해 ICE Candidate의 수집이 끝나면 Caller의 PeerConnection은 자신의 미디어 정보를 담은 SDP를 만들어서 Callee에게 전달합니다. 이 SDP 교환이 끝나면 Caller와 Callee가 직접적으로 연결되어 서로 통신이 가능해집니다.

SDP를 교환하는 방식은 offer/answer 모델이라고 하는데 그 과정은 다음과 같습니다.

  1. Caller가 자신의 ICE정보와 미디어 정보를 수집하여 Offer SDP를 생성
  2. Signaling Server등을 통해 Callee에게 Offer SDP를 발송
  3. Callee는 Offer SDP를 저장하고 이를 바탕으로 하여 Answer SDP를 생성
  4. 다시 Signaling Server등을 통해 Caller에게 Answer SDP를 답장함
  5. Caller는 Answer SDP를 저장하고 이를 바탕으로 하여 P2P 연결이 수립됨

아래의 텍스트는 실제 Offer SDP의 전문을 가져온 것입니다.

v=0
o=- 5508840588494898710 3 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE 0 1 2
a=extmap-allow-mixed
a=msid-semantic: WMS stream

m=audio 59235 UDP/TLS/RTP/SAVPF 111 63 103 104 9 102 0 8 106 105 13 110 112 113 126
c=IN IP4 211.177.20.208
a=rtcp:9 IN IP4 0.0.0.0
a=candidate:1654867310 1 udp 2122260223 192.168.0.15 59235 typ host generation 0 network-id 1 network-cost 10
a=candidate:2136268881 1 udp 2122194687 169.254.156.105 55786 typ host generation 0 network-id 2 network-cost 10
a=candidate:2494774458 1 udp 1686052607 211.177.20.208 59235 typ srflx raddr 192.168.0.15 rport 59235 generation 0 network-id 1 network-cost 10
a=candidate:740342174 1 tcp 1518280447 192.168.0.15 50118 typ host tcptype passive generation 0 network-id 1 network-cost 10
a=candidate:836181153 1 tcp 1518214911 169.254.156.105 50119 typ host tcptype passive generation 0 network-id 2 network-cost 10
a=ice-ufrag:kmK/
a=ice-pwd:KSWhBgN1uxnFzrGa0oJxR5xE
a=ice-options:trickle renomination
a=fingerprint:sha-256 DE:FB:56:67:B9:D0:6C:8F:F1:D9:26:6D:A1:EB:46:F0:1A:D9:5E:6D:9B:AA:F6:92:48:DD:2C:40:D2:CE:5D:24
a=setup:actpass
a=mid:0
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid
a=extmap:5 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id
a=extmap:6 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id
a=sendrecv
a=msid:stream audio0
a=rtcp-mux
a=rtpmap:111 opus/48000/2
a=rtcp-fb:111 transport-cc
a=fmtp:111 minptime=10;useinbandfec=1
a=rtpmap:63 red/48000/2
a=fmtp:63 111/111
a=rtpmap:103 ISAC/16000
a=rtpmap:104 ISAC/32000
a=rtpmap:9 G722/8000
a=rtpmap:102 ILBC/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:106 CN/32000
a=rtpmap:105 CN/16000
a=rtpmap:13 CN/8000
a=rtpmap:110 telephone-event/48000
a=rtpmap:112 telephone-event/32000
a=rtpmap:113 telephone-event/16000
a=rtpmap:126 telephone-event/8000
a=ssrc:3988739923 cname:uZT/0HXQGzzcEOoM
a=ssrc:3988739923 msid:stream audio0
a=ssrc:3988739923 mslabel:stream
a=ssrc:3988739923 label:audio0

m=video 55389 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 127 124 35 36 123 122 125
c=IN IP4 211.177.20.208
a=rtcp:9 IN IP4 0.0.0.0
a=candidate:1654867310 1 udp 2122260223 192.168.0.15 55389 typ host generation 0 network-id 1 network-cost 10
a=candidate:2136268881 1 udp 2122194687 169.254.156.105 59438 typ host generation 0 network-id 2 network-cost 10
a=candidate:2494774458 1 udp 1686052607 211.177.20.208 55389 typ srflx raddr 192.168.0.15 rport 55389 generation 0 network-id 1 network-cost 10
a=candidate:740342174 1 tcp 1518280447 192.168.0.15 50120 typ host tcptype passive generation 0 network-id 1 network-cost 10
a=candidate:836181153 1 tcp 1518214911 169.254.156.105 50121 typ host tcptype passive generation 0 network-id 2 network-cost 10
a=ice-ufrag:kmK/
a=ice-pwd:KSWhBgN1uxnFzrGa0oJxR5xE
a=ice-options:trickle renomination
a=fingerprint:sha-256 DE:FB:56:67:B9:D0:6C:8F:F1:D9:26:6D:A1:EB:46:F0:1A:D9:5E:6D:9B:AA:F6:92:48:DD:2C:40:D2:CE:5D:24
a=setup:actpass
a=mid:1
a=extmap:14 urn:ietf:params:rtp-hdrext:toffset
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:13 urn:3gpp:video-orientation
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=extmap:12 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay
a=extmap:11 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type
a=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-timing
a=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/color-space
a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid
a=extmap:5 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id
a=extmap:6 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id
a=sendrecv
a=msid:stream video0
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:96 H264/90000
a=rtcp-fb:96 goog-remb
a=rtcp-fb:96 transport-cc
a=rtcp-fb:96 ccm fir
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=fmtp:96 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640c1f
a=rtpmap:97 rtx/90000
a=fmtp:97 apt=96
a=rtpmap:98 H264/90000
a=rtcp-fb:98 goog-remb
a=rtcp-fb:98 transport-cc
a=rtcp-fb:98 ccm fir
a=rtcp-fb:98 nack
a=rtcp-fb:98 nack pli
a=fmtp:98 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
a=rtpmap:99 rtx/90000
a=fmtp:99 apt=98
a=rtpmap:100 VP8/90000
a=rtcp-fb:100 goog-remb
a=rtcp-fb:100 transport-cc
a=rtcp-fb:100 ccm fir
a=rtcp-fb:100 nack
a=rtcp-fb:100 nack pli
a=rtpmap:101 rtx/90000
a=fmtp:101 apt=100
a=rtpmap:127 VP9/90000
a=rtcp-fb:127 goog-remb
a=rtcp-fb:127 transport-cc
a=rtcp-fb:127 ccm fir
a=rtcp-fb:127 nack
a=rtcp-fb:127 nack pli
a=rtpmap:124 rtx/90000
a=fmtp:124 apt=127
a=rtpmap:35 AV1/90000
a=rtcp-fb:35 goog-remb
a=rtcp-fb:35 transport-cc
a=rtcp-fb:35 ccm fir
a=rtcp-fb:35 nack
a=rtcp-fb:35 nack pli
a=rtpmap:36 rtx/90000
a=fmtp:36 apt=35
a=rtpmap:123 red/90000
a=rtpmap:122 rtx/90000
a=fmtp:122 apt=123
a=rtpmap:125 ulpfec/90000
a=ssrc-group:FID 3459686956 2014633108
a=ssrc:3459686956 cname:uZT/0HXQGzzcEOoM
a=ssrc:3459686956 msid:stream video0
a=ssrc:3459686956 mslabel:stream
a=ssrc:3459686956 label:video0
a=ssrc:2014633108 cname:uZT/0HXQGzzcEOoM
a=ssrc:2014633108 msid:stream video0
a=ssrc:2014633108 mslabel:stream
a=ssrc:2014633108 label:video0

m=application 56060 UDP/DTLS/SCTP webrtc-datachannel
c=IN IP4 211.177.20.208
a=candidate:1654867310 1 udp 2122260223 192.168.0.15 56060 typ host generation 0 network-id 1 network-cost 10
a=candidate:2136268881 1 udp 2122194687 169.254.156.105 58695 typ host generation 0 network-id 2 network-cost 10
a=candidate:2494774458 1 udp 1686052607 211.177.20.208 56060 typ srflx raddr 192.168.0.15 rport 56060 generation 0 network-id 1 network-cost 10
a=candidate:740342174 1 tcp 1518280447 192.168.0.15 50122 typ host tcptype passive generation 0 network-id 1 network-cost 10
a=candidate:836181153 1 tcp 1518214911 169.254.156.105 50123 typ host tcptype passive generation 0 network-id 2 network-cost 10
a=ice-ufrag:kmK/
a=ice-pwd:KSWhBgN1uxnFzrGa0oJxR5xE
a=ice-options:trickle renomination
a=fingerprint:sha-256 DE:FB:56:67:B9:D0:6C:8F:F1:D9:26:6D:A1:EB:46:F0:1A:D9:5E:6D:9B:AA:F6:92:48:DD:2C:40:D2:CE:5D:24
a=setup:actpass
a=mid:2
a=sctp-port:5000
a=max-message-size:262144

참고

UDP HolePunching 기법

NAT의 종류

WebRTC 연결구조방식

'개발 > WebRTC' 카테고리의 다른 글

iOS CallKit  (0) 2023.05.07
WebRTC remind  (0) 2020.11.02