[WebRTC 박살내기 #1] WebRTC 개념과 연결 구조 완전 정리
WebRTC 박살내기 시리즈의 첫 번째 글입니다. WebRTC 기본 개념부터 시그널링, Offer와 Answer(SDP), Trickle ICE, STUN과 TURN, NAT, Mesh와 SFU, MCU 아키텍처까지 한 번에 정리합니다.
TL;DR
현재 재직 중인 회사에서 원격 솔루션을 개발하고 있는데요. 그중 제가 담당하는 서비스의 가장 핵심 기능이 실시간 영상 상담이고, 이 모든 것의 기반 기술이 바로 WebRTC(Web Real-Time Communication)입니다.
처음 WebRTC를 접했을 때는 브라우저에서 영상 통화를 할 수 있게 해주는 기술 정도로만 이해했어요. 실제 운영 환경에서 다뤄보니 달랐습니다. 네트워크 개념이 여러 겹으로 얽힌 기반 기술이었어요.
- 시그널링(Signaling)과 SDP
- ICE, STUN과 TURN
- NAT 우회
- 다자간 통신의 Mesh와 SFU, MCU 아키텍처 선택
이 글은 WebRTC 박살내기 시리즈의 시작이에요. WebRTC를 처음 접하는 개발자도 따라올 수 있게 기본 개념부터 실제 연결 구조, 핵심 기술까지 정리합니다.
WebRTC는 브라우저끼리 직접 연결합니다
플러그인을 깔지 않고 서버를 최소한만 거쳐 P2P로 통신해요.
P2P(Peer-to-Peer)는 미디어를 주고받을 때 서버를 거치지 않고 브라우저끼리 바로 연결되는 방식이에요. 두 사람이 직접 만나서 대화하는 것과 같아요. 중간에 전달자가 없으니 빠르고 서버 비용도 아낍니다.
2011년 Google이 오픈소스로 공개했고 지금은 주요 브라우저가 모두 지원하는 웹 표준이에요.
WebRTC가 다른 기술과 갈리는 점은 넷입니다
플러그인이 필요 없습니다
Flash나 ActiveX 설치 없이 브라우저만 있으면 돼요. 사용자가 따로 뭘 깔지 않아도 되는 것이 장점입니다.
진짜 실시간 통신입니다
| 서비스 | 지연 시간 | 기술 |
|---|---|---|
| YouTube 라이브 | 2-5초 | RTMP/HLS |
| 인스타그램 라이브 | 3-8초 | RTMP |
| WebRTC (P2P) | 50-200ms | WebRTC |
| WebRTC (SFU) | 200-500ms | WebRTC |
표의 값은 각 방식이 설계상 목표로 하는 범위예요. HLS와 RTMP는 영상을 조각내 보내는 방식이라 조각 길이만큼 지연이 쌓이고, WebRTC는 조각을 만들지 않고 바로 보내서 1초 아래로 내려가요.
지연 시간(Latency)은 내가 "안녕?"이라고 말했을 때 상대방이 듣기까지 걸리는 시간이에요. 0.2초라면 거의 직접 대화하는 것처럼 느껴져요.
보안이 기본으로 들어 있습니다
모든 데이터가 DTLS와 SRTP로 암호화돼요. 중간에 누가 가로채도 내용은 볼 수 없습니다.
DTLS는 "이 사람이 진짜 맞나?"를 확인하고 암호 키를 나누는 역할이고, SRTP는 그 키로 실제 영상과 음성을 잠그는 역할이에요.
다양한 코덱을 지원합니다
비디오 코덱은 셋으로 갈라 보면 돼요.
- VP8과 H.264: WebRTC가 반드시 구현하라고 정한 코덱이에요. 어느 브라우저에서나 통해요
- VP9: 같은 화질을 더 낮은 비트레이트로 담아요
- AV1: VP9보다 더 잘 압축하지만 기기를 가려요
코덱은 브라우저끼리 협상해서 자동으로 정해집니다. 어디서나 통해야 하면 VP8이나 H.264로 두는 것이 안전해요.
WebRTC에도 약점이 있습니다
브라우저마다 쓸 수 있는 코덱이 다릅니다
지금 쓰이는 브라우저는 전부 WebRTC를 지원해요. 연결 자체는 Chrome과 Edge, Firefox, Safari 어디서나 됩니다. 실제로 갈리는 것은 버전이 아니라 코덱이에요.
| 브라우저 | 안심할 수 있는 코덱 |
|---|---|
| Chrome, Edge | VP8, VP9, H.264, AV1 |
| Firefox | VP8, VP9, H.264 |
| Safari | H.264, VP8 |
어느 브라우저에서나 반드시 통하는 조합은 H.264와 VP8이에요. 둘 중 하나로 협상되게 두면 코덱 때문에 화면이 안 나오는 일은 없습니다.
P2P인데 서버가 필요합니다
P2P라고 하면 서버가 아예 없는 그림을 떠올리기 쉬워요.
그런데 NAT 환경에서 두 브라우저를 붙이려면 특별한 서버의 도움이 필요합니다.
정확히는 연결을 시작할 때만 필요해요.
공유기(NAT) 뒤에 있는 두 기기는 서로를 찾을 수단이 없거든요.
- STUN 서버: "너의 공인 IP는 이거야!"라고 알려줍니다
- TURN 서버: "내가 대신 전달해줄게"라고 나섭니다 (비용 발생)
STUN/TURN은 조금 뒤에 자세히 다룰게요.
연결은 네 단계를 지납니다
WebRTC 연결은 중고거래 직거래와 비슷해요.
- 시그널링: 거래 앱 채팅으로 연락 (앱을 거쳐 말을 주고받기)
- Offer/Answer: "현금 되세요?" "계좌이체만 돼요" (결제 방법 맞추기)
- ICE: "○○역 3번 출구 어때요?" "거긴 멀어서요, 편의점 앞은요?" (둘 다 갈 수 있는 곳 찾기)
- 연결 완료: 만나서 물건과 돈을 주고받기 (앱 없이 직접)
여기서 장소를 정하는 세 번째가 가장 오래 걸려요. 한 번에 정해지지 않고 후보를 몇 번 주고받아야 하거든요. ICE도 똑같이 연결 경로 후보를 서로 보내고 되는 것을 고릅니다.
하나씩 볼게요.
Step 1. 시그널링으로 약속을 잡습니다
시그널링은 두 브라우저가 만나기 전에 조건을 맞추는 과정이에요.
브라우저 A: "나 720p 지원해, H.264 코덱 써"
브라우저 B: "나도! 그럼 그걸로 하자"
이런 정보를 주고받는 과정을 시그널링이라고 해요.
그런데 WebRTC 표준에는 시그널링 방법이 정의되어 있지 않아요. 서비스마다 환경이 다르니까요. 어떤 곳은 WebSocket을 쓰고 어떤 곳은 REST API를 써요. 그래서 서비스가 직접 고르게 열어 뒀어요.
많이 쓰는 방법들이 있어요.
- WebSocket (가장 흔함)
- MQTT Protocol
- REST API + 폴링
- Firebase Realtime Database
이 시리즈의 예제도 WebSocket을 쓴다고 가정합니다.
Step 2. Offer와 Answer로 서로 맞춥니다
Offer와 Answer는 SDP(Session Description Protocol)를 주고받는 과정이에요.
먼저 건 쪽이 자기 미디어 정보를 담아 Offer를 보내면, 받은 쪽이 그중 자기도 되는 것만 골라 Answer로 답합니다. 이렇게 두 피어가 어떤 조건으로 통신할지 맞춰요.
SDP는 내가 할 수 있는 것을 적은 목록입니다
SDP(Session Description Protocol)는 "나는 이런 걸 할 수 있어"를 적은 목록이에요.
서로 되는 시간을 맞추는 것과 비슷해요. "나는 화요일과 목요일 돼"라고 보내면 상대가 "나는 목요일과 금요일 돼"라고 답하고, 겹치는 목요일로 정해지잖아요.
적어 보내는 것은 이런 것들입니다.
- 다룰 수 있는 코덱 (H.264, VP8, Opus 같은 것들)
- 쓸 수 있는 대역폭
- 암호화 방식
Offer가 먼저 가고 Answer가 돌아옵니다
발신자가 Offer로 먼저 말을 겁니다. "나는 이런 걸 지원해!" 비디오는 H.264 720p, 오디오는 Opus 48kHz, 암호화는 이렇게 하자고 제안해요.
수신자는 Answer로 답합니다. "나도 그거 지원해! 그럼 H.264로 하고 Opus로 하자."
이렇게 둘 다 지원하는 최적의 방법으로 협상이 완료돼요.
실제 SDP는 이렇게 생겼습니다
아래는 Chrome에서 pc.createOffer()를 부른 뒤 pc.localDescription.sdp를 그대로 찍은 것의 앞부분이에요.
v=0
o=- 4611731400430051336 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE 0 1
m=audio 9 UDP/TLS/RTP/SAVPF 111 103 9 0 8
c=IN IP4 0.0.0.0
a=rtcp-mux
a=ice-ufrag:4ZcD
a=ice-pwd:2/1muCWoOi3uLifh0NuRHlsy
a=fingerprint:sha-256 75:74:5A:A6:A4:E5:52:F4:...
a=setup:actpass
a=mid:0
a=rtpmap:111 opus/48000/2
한 줄에 하나씩 키=값 형태로 나열돼 있어요. 눈에 먼저 들어오는 것은 m=audio 줄의 UDP/TLS/RTP/SAVPF입니다. SAVPF의 S가 SRTP이고, 앞에서 말한 DTLS는 a=fingerprint와 a=setup에 적혀요. 보안이 SDP의 어디에 들어가는지가 이 두 줄이에요.
c=가 0.0.0.0인 것도 특이해요. 실제 주소는 여기가 아니라 뒤에 붙는 a=candidate 줄로 따로 나가거든요. Chrome은 사설 IP를 그대로 노출하지 않고 .local로 끝나는 이름으로 가려서 보내니, SDP에서 192.168.x.x를 찾으려 하면 안 나올 수 있어요.
각 줄 앞의 한 글자가 무엇을 뜻하는지는 아래 표로 정리했어요.
| 필드 | 의미 | 예시 |
|---|---|---|
v= | SDP 버전 | v=0 |
o= | 세션 발신자 정보 | 사용자명, 세션 ID, IP |
c= | 연결 정보 (IP 주소) | c=IN IP4 0.0.0.0 |
m= | 미디어 정보 | m=audio 9 UDP/TLS/RTP/SAVPF … |
a= | 속성 (코덱, 방향 등) | a=rtpmap:111 opus/48000/2 |
SDP를 직접 읽을 일은 많지 않아요. 라이브러리가 대신 처리해주거든요. 다만 디버깅할 때 SDP를 읽을 수 있으면 문제를 빠르게 찾을 수 있어요.
Step 3. ICE로 길을 찾습니다
공유기 뒤에 있으면 서로를 못 찾습니다
집이나 사무실에서 쓰는 인터넷은 공유기를 거치니까 사용자는 공유기(NAT) 뒤에 있다고 봐야 해요.
문제는 외부에서 192.168.0.5로 직접 접근할 수 없다는 점이에요.
NAT(Network Address Translation)는 하나의 공인 IP로 여러 기기를 관리하는 시스템이에요. 아파트 주소 하나로 여러 세대를 관리하는 우편함과 같아요. 공인 IP가 부족해서 이렇게 공유해 씁니다.
NAT 종류에 따라 뚫리기도 하고 안 뚫리기도 합니다
NAT도 종류가 있어서 어떤 건 직접 연결이 되고 어떤 건 거의 안 됩니다. 갈리는 지점은 하나예요. 공유기가 나에게 배정한 바깥 포트를 상대가 누구든 그대로 유지하느냐예요.
| NAT 종류 | 바깥 포트 | 직접 연결 |
|---|---|---|
| Full Cone, Restricted Cone, Port Restricted Cone | 상대와 무관하게 유지 | 됩니다 (STUN으로 충분) |
| Symmetric NAT | 상대마다 새로 배정 | 거의 안 됩니다 (TURN 필요) |
앞의 셋은 이름이 다르지만 바깥 포트가 유지된다는 점이 같아서, STUN으로 알아낸 주소가 그대로 통합니다. Symmetric만 다릅니다. 상대가 바뀔 때마다 포트를 새로 배정하니 미리 알아낸 주소가 소용없어요.
이 네 갈래 이름은 RFC 3489가 정의한 분류이고, 지금은 RFC 4787 (새 창에서 열림)이 매핑 동작과 필터링 동작을 나눠 보는 방식으로 대체했어요.
ICE가 해결합니다
ICE(Interactive Connectivity Establishment)는 모든 가능한 경로를 찾아서 테스트하는 프레임워크입니다.
ICE는 네 단계로 움직입니다.
- candidate 수집: 연결 가능한 모든 경로 찾기
- 로컬 IP (같은 네트워크)
- 공인 IP (STUN으로 확인)
- TURN 중계 서버 경로
- candidate 교환: 시그널링으로 서로 공유
- 연결 테스트: 모든 경로 조합을 실제로 시도
- 최적 경로 선택: 가장 빠르고 안정적인 경로로 확정
ICE가 이 경로를 찾으려면 두 가지 특별한 서버의 도움이 필요해요.
STUN은 내 공인 IP를 알려주는 길잡이이고 TURN은 직접 연결이 안 될 때 중간에서 데이터를 전달해주는 중개인입니다.
STUN은 내 공인 IP를 알려줍니다
STUN(Session Traversal Utilities for NAT)은 내 공인 IP를 알려주는 서버입니다.
RTCPeerConnection은 피어 사이의 연결을 만드는 객체예요. 만들 때 iceServers에 STUN 주소를 적어두면 ICE가 candidate를 모으는 단계에서 이 서버에 물어 내 공인 IP를 알아내요.
const peerConnection = new RTCPeerConnection({
iceServers: [{ urls: "stun:stun.l.google.com:19302" }]
});여기서는 공개된 STUN 서버 주소 하나만 등록했어요. 자격 증명이 필요 없으니 urls 한 줄로 끝납니다.
장점은 무료이고 빠르고 가볍다는 것이에요. 단점은 Symmetric NAT 같은 환경에서는 연결이 안 된다는 것입니다.
공개 STUN 서버는 배우고 시험할 때 써요. 서비스를 운영할 때는 직접 세우는 편이 나아요. 뒤에 나오는 TURN 서버가 STUN 역할도 함께 하니 서버가 더 늘지도 않습니다.
TURN은 직접 연결이 안 될 때 중계합니다
TURN(Traversal Using Relays around NAT)은 직접 연결이 불가능할 때 중계해주는 서버입니다.
앞의 설정에 TURN 항목을 하나 더 얹으면 이렇게 돼요. STUN과 달리 TURN은 username과 credential로 자격 증명을 요구해요.
const peerConnection = new RTCPeerConnection({
iceServers: [
{ urls: "stun:stun.l.google.com:19302" },
{
urls: "turn:your-turn-server.com:3478",
username: "user",
credential: "password"
}
]
});두 서버를 함께 등록해두면 ICE가 공인 IP 경로와 TURN 중계 경로를 모두 candidate로 모아요.
직거래 비유로 돌아가면 편의점 택배에 해당해요. 서로 만나기 어려우면 물건을 편의점에 맡기고 상대가 거기서 찾아가잖아요. 한 번 더 거치니 느리고 택배비도 들지만 어쨌든 거래는 됩니다.
장점은 거의 모든 환경에서 연결된다는 것이고, 단점은 서버 비용과 대역폭 소모, 약간의 지연이에요. 비용은 중계한 데이터 양으로 붙습니다.
TURN이 필요한 경우는 UDP를 차단하는 기업 방화벽 뒤, Symmetric NAT 환경, 그리고 공유기 뒤에 또 공유기가 있는 이중 NAT예요.
Trickle ICE는 찾는 대로 보내서 빨리 붙습니다
예전 방식은 모든 candidate를 수집한 뒤에 교환했어요. 이것을 Vanilla ICE라고 부릅니다. 이러면 시간이 오래 걸려요.
Trickle ICE는 candidate를 찾는 즉시 바로 보내요.
먼저 Vanilla ICE입니다.
그리고 Trickle ICE입니다.
지금은 Trickle ICE가 WebRTC 구현의 기본이에요.
Step 4. 연결이 서면 통신이 시작됩니다
모든 과정이 끝나면 미디어는 피어끼리 직접 흐릅니다. 영상과 음성이 서버를 거치지 않고 바로 오가요.
다만 시그널링 서버를 닫으면 안 됩니다. 통화 중에 화면 공유를 켜거나 트랙을 하나 더 얹으면 그때마다 offer와 answer를 다시 주고받아야 하고, Wi-Fi에서 LTE로 넘어가 경로를 다시 찾을 때도 같은 채널을 써요. 미디어만 서버를 안 거치는 것이고 제어 신호는 통화가 끝날 때까지 서버를 지납니다.
참가자가 늘면 연결 수가 제곱으로 붑니다
1:1은 쉽습니다. 그런데 10명, 100명이 동시에 화상 회의를 한다면?
N명이 참여하면 N(N-1)/2 개의 연결이 필요해요.
- 4명: 6개 연결
- 10명: 45개 연결
- 100명: 4,950개 연결
각 참가자가 다른 모든 사람에게 직접 영상을 보내야 하니 참여자가 늘어날수록 연결 수가 제곱에 가깝게 늘어나요.
이제 WebRTC의 다자간 연결 아키텍처를 볼게요.
문제를 해결하는 방식에 따라 크게 세 가지로 나뉘어요.
Mesh는 서버 없이 서로 직접 잇습니다
가장 단순한 구조예요. 모든 사람이 모든 사람과 직접 연결됩니다.
5명이 참가하면 나(A)는 B와 C, D, E 네 명에게 각각 영상을 보내고 네 명에게서 각각 영상을 받아요. 아래 대역폭은 720p 30fps 한 줄기를 1Mbps로 잡고 계산한 값입니다.
| 항목 | 5명 기준 |
|---|---|
| 내가 보내는 횟수 | 4번 인코딩 |
| 받는 영상 개수 | 4개 디코딩 |
| 업로드 대역폭 | 약 4-5Mbps |
| 다운로드 대역폭 | 약 4-5Mbps |
Mesh가 막히는 경우는 셋이에요.
- 업로드 대역폭: 쓰는 상품에 따라 모자랄 수 있음
- CPU와 GPU: 참가자마다 따로 인코딩
- 메모리: 모든 연결을 유지
셋 중 먼저 막히는 것은 대개 인코딩이에요. 요즘 기가 인터넷은 업로드도 넉넉해서 5명 정도는 회선이 버팁니다. 반면 인코더는 참가자 수만큼 돌아가서 5명이면 네 개를 동시에 돌리는 셈이라, 노트북 팬이 먼저 돌아요.
Mesh를 쓸 만한 경우예요.
- 2-4명 소규모 회의
- 1:1 화상 통화
- 서버 비용 없이 낮은 지연 시간이 중요한 경우
이럴 때는 피합니다.
- 5명 이상
- 모바일이나 저사양 기기
SFU는 서버가 받은 것을 그대로 뿌립니다
SFU(Selective Forwarding Unit)는 서버가 중계자 역할을 합니다.
서버는 영상을 변환하지 않고 그대로 전달만 해요.
5명이 참가하면 나(A)는 서버에 영상을 한 번만 보내고, 서버가 그것을 B와 C, D, E에게 전달해요.
| 항목 | Mesh (5명) | SFU (5명) |
|---|---|---|
| 내가 보내는 횟수 | 4번 인코딩 | 1번만 인코딩 |
| 받는 영상 개수 | 4개 디코딩 | 4개 디코딩 |
| 업로드 대역폭 | 약 4-5Mbps | 약 1-1.5Mbps |
| 다운로드 대역폭 | 약 4-5Mbps | 약 4-5Mbps |
개선된 점은 이렇습니다.
- 업로드 대역폭 75퍼센트 감소
- 인코딩 부하 75퍼센트 감소
- 서버가 현재 발언자를 강조하거나 네트워크 상황에 맞춰 화질을 조절할 수 있음
여기에 Simulcast를 얹으면 한 사람이 화질 여러 개를 동시에 올리고 서버가 받는 쪽 사정에 맞춰 골라 보내요. 대신 위의 75퍼센트는 그만큼 줄어듭니다. 저사양 기기가 섞인 회의에서 화질을 나눠 줄 수 있는 대가예요.
그래도 남는 부하가 있습니다. 디코딩은 여전히 참가자 수만큼 필요하고 다운로드 대역폭도 그대로예요.
SFU를 쓸 만한 경우예요.
- 5-50명 중규모 회의
- Google Meet, Zoom처럼 널리 쓰이는 화상 회의
- 서버 비용은 있지만 사용자 부담을 줄이고 싶을 때
이럴 때는 피합니다.
- 50명 이상 대규모
- 저사양 모바일 기기가 많은 환경
MCU는 서버가 하나로 합쳐 보냅니다
MCU(Multipoint Control Unit)는 서버가 모든 영상을 하나로 합쳐서 전달합니다.
TV 뉴스의 화상 회의 화면처럼 격자 형태로 합성해요.
피어가 받는 것은 언제나 합성된 영상 1개입니다.
5명이 참가해도 서버가 영상 5개를 디코딩해 하나로 합성한 뒤 다시 하나로 인코딩하고, 나(A)는 영상 1개만 디코딩해요.
| 항목 | SFU (5명) | MCU (5명) |
|---|---|---|
| 서버 처리 | 중계만 | 5개 디코딩 + 합성 |
| 내가 받는 영상 | 4개 디코딩 | 1개만 디코딩 |
| 다운로드 대역폭 | 약 4-5Mbps | 약 1-1.5Mbps |
| 서버 CPU | 낮음 | 매우 높음 |
MCU가 주는 것과 잃는 것을 나란히 놓으면 이렇습니다.
주는 것부터 보면 피어 부하가 최소로 줄어 저사양 기기도 버팁니다. 참가자가 100명이어도 받는 영상은 1개라 다운로드 대역폭이 75퍼센트 줄고, 인원과 무관하게 데이터 사용량을 예측할 수 있어요.
잃는 것은 서버 쪽에 몰립니다. CPU 사용량과 비용이 매우 높아지고 지연 시간이 조금 늘어요. 레이아웃을 서버가 정하니 화면 배치를 사용자가 바꾸기도 어렵습니다.
서버 부하가 높은 이유는 100명 회의를 떠올려보면 드러납니다. 영상 100개를 각각 디코딩하고 격자 형태로 실시간 합성한 뒤 1개로 다시 인코딩해야 하거든요. 이걸 실시간으로 처리하려면 강력한 CPU가 필요해요.
MCU를 쓸 만한 경우예요.
- 50명 이상 대규모 웨비나
- 저사양 모바일 기기 지원 필수
- 제한된 데이터 요금제 사용자가 많을 때
- 모든 참가자에게 동일한 화면
이럴 때는 피합니다.
- 소규모 회의 (비용 낭비)
- 낮은 지연 시간이 중요한 경우
셋을 한 표로 비교합니다
| 구분 | Mesh | SFU | MCU |
|---|---|---|---|
| 미디어 서버 역할 | 없음 | 중계 (변환 X) | 합성 (변환 O) |
| 피어 업로드 | N-1개 | 1개만 | 1개만 |
| 피어 디코딩 | N-1개 | N-1개 | 1개만 |
| 서버 부하 | 거의 없음 | 대역폭 높음 | CPU 매우 높음 |
| 서버 비용 | 없음 | 중간 | 매우 높음 |
| 피어 부하 | 높음 | 중간 | 낮음 |
| 적정 인원 | 2-4명 | 5-50명 | 50명 이상 |
| 지연 시간 | 가장 낮음 | 낮음 | 약간 높음 |
마무리
WebRTC 하나를 쓰려면 네트워크와 미디어, 보안을 함께 다뤄야 합니다.
지금까지 다룬 것을 한 번에 다시 세워보면 이렇게 돼요.
- 시그널링: 약속 잡기
- Offer/Answer: 방식 맞추기 (SDP)
- ICE: 길 찾기 (STUN/TURN)
- 연결 완료: 실시간 통신 시작
- STUN: 내 공인 IP 확인
- TURN: 중계 서버
- ICE: 최적 경로 자동 선택
- Mesh: 2-4명 소규모, 서버 비용 없음
- SFU: 5-50명 중규모, 가장 많이 쓰이는 선택
- MCU: 50명 이상, 저사양 기기 지원
다음 편에서는 다음 주제를 다룹니다.
- 카메라와 마이크 접근하기 (
getUserMedia) - 화면 공유 구현하기 (
getDisplayMedia) - 트랙을 담고 꺼내고 복제하기 (
MediaStreamTrack)
참고자료
이런 글도 읽어보세요
[WebRTC 박살내기 #3] PeerConnection API와 이벤트 흐름
WebRTC 박살내기 시리즈의 세 번째 글입니다. 핵심인 RTCPeerConnection API를 다룹니다. 연결 생성과 iceServers 설정부터 이벤트 흐름, Offer와 Answer 교환, 패킷 손실률 관측과 비트레이트 조절, 연결 복구까지 실전 예제와 함께 알아봅니다.
[WebRTC 박살내기 #4] 데이터 채널 구조와 활용법
WebRTC 박살내기 시리즈의 마지막 글입니다. RTCDataChannel API를 이해하고, 채팅과 파일 전송, 게임 상태 동기화까지 영상과 음성이 아닌 데이터를 P2P로 보내는 방법을 실전 예제와 함께 다룹니다.
[WebRTC 박살내기 #2] 미디어 스트림과 트랙 완벽 이해
WebRTC 박살내기 시리즈의 두 번째 글입니다. WebRTC의 MediaStream과 MediaStreamTrack 객체를 깊이 이해하고, getUserMedia부터 트랙 제어, 품질 관리, 화면 공유까지 실전 예제와 함께 알아봅니다.