Skip to content

WebRTC

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

Categories

About Streaming

Terms

Tools

Server/libraries

Client

  • webrtc-adapter - adapter.js is a shim to insulate apps from spec changes and prefix differences.
  • OvenPlayer (HTML5 player)

Libraries

Use case

WebRTC는 기본적으로 P2P 프로토콜로서, 대규모의 미디어 방송 서비스를 구축하거나 나 컨텐츠 가공이 필요한 경우와 같이, 서비스 목적에 따라 별도의 중앙 서버를 구성해야 할 필요가 있다. 아키텍처는 유즈케이스에 따라 다음과 같은 구성을 고려해 볼 수 있다.

P2P (Peer to Peer)
중앙 서버 없이 종단 간 직접 연결 방식은 비용 측면에서 유리하나, 피어 수가 증가(mesh structure)할수록 시스템과 네트워크의 높은 capacity를 요구한다. 1:1 또는 소규모 미디어 교환에 적합하다.
SFU (Selective Forwarding Unit)
중앙 서버를 통해 종단 간 미디어 트래픽을 중계하는 중앙 서버 방식으로, 각 피어 연결 할당 및 decrypt/encrypt 처리 비용 정도를 감수한다. 영상 방송과 같은 1:M(or minimum-N:M) 스트리밍 서비스 구조에 적합하다.
MCU (Multi-point Control Unit)
다수의 송출 미디어를 중앙 서버에서 혼합(muxing) 또는 가공(transcoding)하여 수신측으로 전달하는 중앙 서버 방식으로, 클라이언트와 네트워크의 부담이 현저히 줄어드는 반면 중앙 서버의 높은 컴퓨팅 파워가 요구된다.

-

P2P

SFU

MCU

Client Uplink

High

Low

Low

Client Downlink

High

Low

High

Client CPU Usage

High

Low

Medium

Server CPU Usage

-

High

Low

Possible Latency

Depends on Network Bandwidth

Depends on CPU Power

Depends on Network Bandwidth

Transcode Capability

-

Yes

No

Simulcast/SVC Capability

-

-

Yes

ICE candidate

네트워크 연결에 관한 정보를 담고있음 UDP랑 TCP 두 가지가 존재. 일반적으로 UDP를 사용하게 되어있음. 유저 한명은 controlling agent로, 다른 유저는 controlled agent로 배정됨.

  • controlling agent가 어떤 candidate 쌍을 사용할지 결정
  • ICE 리셋 전까지는 결정된 candidate 쌍을 사용하게됨

UDP 타입

속도가 빠름고 MediaStream에 장애가 발생해도 상대적으로 더 쉽게 복구 가능

  • host: 유저의 실제 IP 주소 사용
  • prflx: peer reflexive, 두 유저간에 존재하는 Symmetric NAT에서 발생한 IP 주소 사용
  • srflx: server reflexive, STUN/TURN 서버가 생성한 IP 주소 사용
  • relay: TURN 서버에서 생성한 IP 주소 사용

TCP 타입

  • active: outbound 연결 시도
  • passive: 연결을 받도록 설정
  • so: 유저간에 연결을 동시에 개통하도록 시도

WebRTC Server streaming

Yes it is possible as the server can be one of the peers in that peer-to-peer session. If you respect the protocols and send the video in SRTP packets using VP8, the browser will play it. To help you build these components on other applications or servers, you can check this page and this project as a guide.

Now, comparing WebRTC with other streaming services... It will depend on several variables like the Codec or the protocol. But, for instance, comparing WebRTC (SRTP over UDP with VP8 Codec) against Flash (RTMP over TCP with H264 Codec), I would say that WebRTC wins.

  • The player will be Flash Player against the native <code><video>

    </code> tag.

  • The transport would be TCP against UDP.

But of course, everything depends on what you are sending to the client.

SDP Offer/Answer

자세한 내용은 JavaScript Session Establishment Protocol (JSEP) 항목 참조.

TypeScript 개발 설정

no-undef error

RTCConfiguration같은 심볼을 사용하면 다음과 같이 ESLint 에러(no-undef)가 나타날 수 있다:

ESLint: 'RTCConfiguration' is not defined.(no-undef)

TypeScript의 lib의 dom에 해당 심볼 정의가 존재한다. compilerOptions에 다음과 같이 추가한다:

{
  "compilerOptions": {
    "lib": [..., "dom"]
  }
}

혹은 타입 심볼을 설치하고,

yarn add -D @types/webrtc

compilerOptions에 다음과 같이 타입을 추가한다:

{
  "compilerOptions": {
    "types": [..., "webrtc"]
  }
}

그래도 안된다면 ESLint에 전역 심볼을 등록해 주면 된다:

  "eslintConfig": {
    "root": true,
    "env": {
      "browser": true,
      "node": true
    },
    "globals": {
      "RTCIceGatheringState": true,
      "RTCIceServer": true,
      "RTCConfiguration": true,
      "RTCSessionDescriptionInit": true,
      "RTCErrorEvent": true
    },

Sample URLs

Troubleshooting

stun:localhost is not connect

Session Traversal Utilities for NAT#stun:localhost is not connect 항목 참조.

ICE failed, your TURN server appears to be broken, see about:webrtc for more details

ICE failed, your TURN server appears to be broken, see about:webrtc for more details 

만약 STUN 또는 TURN 서버가 로컬 호스트에 있고, Firefox를 사용한다면 about:config 페이지 에서 아래 설정을 바꾼다.

media.peerconnection.ice.no_host;true

ICE failed, add a TURN server and see about:webrtc for more details

Firefox에서 RTCPeerConnection.onicecandidate 이벤트에서 candidate의 host 정보가 127.0.0.1과 같은 형태로 들어가거나 event.candidate는 Null이 아니지만 event.candidate.candidate의 값이 빈 문자열""일 경우 접속 URL을 확인하는 것이 좋다. 0.0.0.0과 같은 주소로 접속하면 안된다.

정상적일경우:

RTCIceCandidate { candidate: "candidate:0 1 UDP 2122252543 192.168.1.10 50077 typ host", sdpMid: "2", sdpMLineIndex: 2, usernameFragment: "2c97a5b3" }
RTCIceCandidate { candidate: "candidate:2 1 TCP 2105524479 192.168.1.10 9 typ host tcptype active", sdpMid: "2", sdpMLineIndex: 2, usernameFragment: "2c97a5b3" }
RTCIceCandidate { candidate: "candidate:0 1 UDP 2122252543 192.168.1.10 49330 typ host", sdpMid: "0", sdpMLineIndex: 0, usernameFragment: "2c97a5b3" }
RTCIceCandidate { candidate: "candidate:2 1 TCP 2105524479 192.168.1.10 9 typ host tcptype active", sdpMid: "0", sdpMLineIndex: 0, usernameFragment: "2c97a5b3" }
RTCIceCandidate { candidate: "candidate:0 2 UDP 2122252542 192.168.1.10 50790 typ host", sdpMid: "0", sdpMLineIndex: 0, usernameFragment: "2c97a5b3" }
RTCIceCandidate { candidate: "candidate:2 2 TCP 2105524478 192.168.1.10 9 typ host tcptype active", sdpMid: "0", sdpMLineIndex: 0, usernameFragment: "2c97a5b3" }
RTCIceCandidate { candidate: "candidate:0 1 UDP 2122252543 192.168.1.10 64160 typ host", sdpMid: "1", sdpMLineIndex: 1, usernameFragment: "2c97a5b3" }
RTCIceCandidate { candidate: "candidate:2 1 TCP 2105524479 192.168.1.10 9 typ host tcptype active", sdpMid: "1", sdpMLineIndex: 1, usernameFragment: "2c97a5b3" }
RTCIceCandidate { candidate: "candidate:0 2 UDP 2122252542 192.168.1.10 58270 typ host", sdpMid: "1", sdpMLineIndex: 1, usernameFragment: "2c97a5b3" }
RTCIceCandidate { candidate: "candidate:2 2 TCP 2105524478 192.168.1.10 9 typ host tcptype active", sdpMid: "1", sdpMLineIndex: 1, usernameFragment: "2c97a5b3" }

비정상적일경우:

RTCIceCandidate { candidate: "candidate:0 1 UDP 2122252543 127.0.0.1 49837 typ host", sdpMid: "2", sdpMLineIndex: 2, usernameFragment: "4ecc8976" }
RTCIceCandidate { candidate: "candidate:2 1 TCP 2105524479 127.0.0.1 9 typ host tcptype active", sdpMid: "2", sdpMLineIndex: 2, usernameFragment: "4ecc8976" }
RTCIceCandidate { candidate: "candidate:2 1 TCP 2105524479 127.0.0.1 9 typ host tcptype active", sdpMid: "0", sdpMLineIndex: 0, usernameFragment: "4ecc8976" }
RTCIceCandidate { candidate: "candidate:2 2 TCP 2105524478 127.0.0.1 9 typ host tcptype active", sdpMid: "0", sdpMLineIndex: 0, usernameFragment: "4ecc8976" }
RTCIceCandidate { candidate: "", sdpMid: "0", sdpMLineIndex: 0, usernameFragment: "4ecc8976" }
RTCIceCandidate { candidate: "candidate:2 1 TCP 2105524479 127.0.0.1 9 typ host tcptype active", sdpMid: "1", sdpMLineIndex: 1, usernameFragment: "4ecc8976" }
RTCIceCandidate { candidate: "candidate:2 2 TCP 2105524478 127.0.0.1 9 typ host tcptype active", sdpMid: "1", sdpMLineIndex: 1, usernameFragment: "4ecc8976" }
RTCIceCandidate { candidate: "", sdpMid: "1", sdpMLineIndex: 1, usernameFragment: "4ecc8976" }

원격 Peer 에 Close 신호 보내기

peer를 close 했을 때, 원격 peer 는 바로 close 를 수신하지 못한다. (UDP로 연결되었을 경우가 대표적인 예시) 이는 ICE 로 시그널링하기 때문이다. ICE로 시그널링할 경우 ICE 확인을 위한 시간이 약 5초 정도 필요하다.

바로 close 하고싶다면 JSEP와 같은 방법으로 직접 close 해야 한다.

아니면, SCTP로 연결되는 DataChannel을 생성한 후, DataChannel 이 닫히면 종료하도록 하면 된다.

See also

Favorite site

Documentation

Guide

Understanding WebRTC and ICE

Video Chat Tutorials

Article

Demo

References


  1. Hello_world_-_RTCS.pdf 

  2. Getting_Started_with_WebRTC_-_HTML5_Rocks.pdf 

  3. WebRTC_in_the_real_world_-_STUN_TURN_and_signaling.pdf 

  4. JIYUN.ME_-_WebRTC_intro.pdf 

  5. 7_ways_to_stream_RTSP_on_the_page.pdf 

  6. Migrating_your_native_mobile_application_to_Unified_Plan_WebRTC_1.pdf