Skip to content
Search

WebRTC

lastmod 2026-04-02created 2014-03-11113 edits

WebRTC (Web Real-Time Communication) is an API designed to let web browsers communicate with each other without the help of plugins. It is a draft proposed by the W3C and can be used for voice calls, video calls, P2P file sharing, and more.

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 is basically a P2P protocol, so depending on the purpose of the service, such as building a large-scale media broadcasting service or when content processing is needed, you may need to set up a separate central server. Depending on the use case, the following architectures can be considered.

P2P (Peer to Peer)
Direct end-to-end connection without a central server is advantageous in terms of cost, but as the number of peers grows (mesh structure), it demands high system and network capacity. Suitable for 1:1 or small-scale media exchange.
SFU (Selective Forwarding Unit)
A central server approach that relays end-to-end media traffic through a central server, accepting the cost of allocating each peer connection and of decrypt/encrypt processing. Suitable for 1:M (or minimum-N:M) streaming service structures such as video broadcasting.
MCU (Multi-point Control Unit)
A central server approach in which the central server mixes (muxing) or processes (transcoding) multiple outgoing media streams and delivers them to the receivers; it significantly reduces the load on clients and the network, but requires high computing power on the central server.

-

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

Contains information about the network connection. There are two kinds, UDP and TCP. UDP is normally used. One user is assigned as the controlling agent and the other as the controlled agent.

  • The controlling agent decides which candidate pair to use
  • The chosen candidate pair is used until an ICE reset

UDP types

Fast, and relatively easier to recover even if the MediaStream fails

  • host: Uses the user's actual IP address
  • prflx: peer reflexive; uses an IP address produced by a Symmetric NAT between the two users
  • srflx: server reflexive; uses an IP address generated by a STUN/TURN server
  • relay: Uses an IP address generated by a TURN server

TCP types

  • active: Attempts an outbound connection
  • passive: Set up to accept connections
  • so: Attempts to open the connection between users simultaneously

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

See JavaScript Session Establishment Protocol (JSEP) for details.

TypeScript development setup

no-undef error

Using a symbol such as RTCConfiguration may produce an ESLint error (no-undef) like this:

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

The symbol is defined in the dom lib of TypeScript. Add the following to compilerOptions:

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

Or install the type symbols,

yarn add -D @types/webrtc

and add the type to compilerOptions as follows:

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

If it still does not work, register global symbols in 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

See 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 

If the STUN or TURN server is on localhost and you use Firefox, change the setting below on the about:config page.

media.peerconnection.ice.no_host;true

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

In Firefox, if the host information of candidate in the RTCPeerConnection.onicecandidate event comes in a form like 127.0.0.1, or if event.candidate is not Null but the value of event.candidate.candidate is an empty string "", it is a good idea to check the connection URL. Do not connect via an address like 0.0.0.0.

Normal case:

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" }

Abnormal case:

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" }

Sending a Close signal to the remote Peer

When you close a peer, the remote peer does not receive the close immediately. (A typical example is when connected over UDP.) This is because signaling is done through ICE. When signaling through ICE, about 5 seconds are needed for the ICE check.

If you want to close immediately, you must close it yourself using a method such as JSEP.

Alternatively, create a DataChannel connected over SCTP and terminate when the DataChannel closes.

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 ↩

author Zer0 sitemap