Skip to content

SYSTEM Cited by 1 source

Meta WebRTC Shim

What it is

A proxy library sitting between Meta's application code and two statically-linked copies of WebRTC (a legacy fork and a latest upstream Chromium build), exposing a single unified version-agnostic API and dispatching each call to one of the flavors based on a runtime configuration flag. Used across 50+ RTC use cases — Messenger + Instagram video calling, Cloud Gaming, Meta Quest VR casting — to A/B test each new upstream WebRTC release against the legacy baseline without branching the call-orchestration library or duplicating it.

Why it exists

Meta had a years-divergent internal WebRTC fork carrying dozens of internal optimizations. Upgrading directly to upstream was too risky at Meta's scale (billions of users, heterogeneous devices, no one-shot rollback). Meta needed:

  1. A/B test per-app capability with legacy + latest living in the same binary.
  2. Static linking of both copies (build-graph and binary-size constraints disallow dynamic loading).
  3. No large call-orchestration-library duplication (would have added ~38 MB uncompressed; shimming at the WebRTC layer was ~5 MB, an 87% reduction — see concepts/binary-size-bloat).

The shim is the primitive that makes (1)+(2)+(3) coexist.

How it works

Symbol coexistence

Two WebRTC copies statically linked in one binary trigger thousands of ODR violations. Meta's scripts perform automated namespace rewritingwebrtc:: in the upstream copy becomes webrtc_latest::, legacy becomes webrtc_legacy::. Non-namespaced global C functions, free variables, and intentionally non-namespaced classes are moved into namespaces or given flavor-suffixed names. rtc_base and similar internal modules are shared between flavors where safe, shrinking both the shim surface and the binary.

Backward compatibility

Existing call sites use webrtc::. Instead of hand-forward-declaring every symbol, the shim uses bulk C++ using declarations"importing an entire flavor namespace into the familiar webrtc:: namespace" — giving zero binary-size cost, automatic handling of new symbols, and a concise header.

Runtime dispatch

Each adapter/converter decides between webrtc_legacy:: and webrtc_latest:: based on a global flavor enum set early in app startup. Shared logic lives in generic templates; version-specific behavior lives in template specializations — see concepts/runtime-flavor-dispatch. Adapters and converters come in two directional shapes: directional adapters expose internal WebRTC classes to external callers (or vice-versa); directional converters translate structs/enums across the shim/WebRTC boundary.

Shim generation

AST-based code generation produces baseline shim classes, structs, enums, and constants, with unit tests included. Velocity went from 1 shim/day to 3–4 shims/day; for simple symmetric APIs the generated code required near-zero manual intervention.

Injected components

Some internal components plug deeply into WebRTC internals (decoders, network components, encoders). Shimming them would mean "proxying WebRTC against itself." Instead Meta uses Buck build-time target duplication plus C++ macros — the build graph produces two copies of the internal component at different namespaces (one per WebRTC flavor) exposed through a single header.

Scale

  • 50+ RTC use cases (apps / features) migrated.
  • > 10,000 lines of new shim code; hundreds of thousands of lines modified across thousands of files.
  • 5 MB uncompressed binary-size cost (vs 38 MB for the call-orchestration-layer alternative).
  • 100–200 KB compressed binary-size reduction as a downstream win from the upstream WebRTC's own efficiency improvements.
  • Up to 10% CPU drop, up to 3% crash-rate improvement across major apps after migration.

Status

  • Launched webrtc/latest at M120, currently at M145.
  • No longer years behind upstream — "living at head" with each new release ingested and A/B'd before rollout.
  • The shim remains in production as the ongoing upgrade-A/B substrate.

Seen in

Last updated · 319 distilled / 1,201 read