
Key takeaways
• Android WebRTC is well-supported in 2026. Google’s libwebrtc is the canonical engine; Stream WebRTC Android, Wire SDK, LiveKit Android, Daily Android, Agora Android, and 100ms cover the main wrapper choices.
• The flow is the same across SDKs. Capture → PeerConnection → SDP offer/answer → ICE candidates → media tracks. SDKs add convenience APIs, room concepts, and adaptive bitrate — not new physics.
• Five Android-specific gotchas eat sprints. Foreground service for the camera, audio focus, hardware codec selection, simulcast tuning, and Doze-mode network handling. Plan for them.
• Jetpack Compose is the default UI for new builds. Surface views (SurfaceViewRenderer) compose cleanly with the Compose layout tree, but you must control recomposition tightly — covered in our Vkompose performance article.
• Fora Soft has shipped Android WebRTC at scale. Around 40% of our active engineering capacity sits in real-time and mobile. We use Agent Engineering to compress every project’s calendar.
Why Fora Soft wrote this playbook
We have shipped Android WebRTC clients on every credible engine — libwebrtc directly, Stream Android SDK, LiveKit Android, Daily, Agora, 100ms, and bespoke SFU clients. BrainCert, ProvideoMeeting, and a number of NDA-bound healthcare and surveillance products run Android WebRTC clients we wrote. Around 40% of our engineering capacity sits in real-time and mobile.
This article is the playbook we hand to Android engineers joining a WebRTC project. It explains the canonical flow, names the five Android-specific gotchas that eat sprints, and points to the SDK choice for a given product profile. Conceptual primers on WebRTC sit in our What is WebRTC explainer; the architecture map sits in our WebRTC architecture guide for business 2026.
Building an Android WebRTC client?
A 30-minute call with our Android engineering leads gets you an SDK pick, a camera/audio plan, a Compose-friendly architecture, and a calendar.
WebRTC core concepts — the pieces every Android client needs
Every Android WebRTC client — whether you build directly on libwebrtc or via an SDK — reuses the same five primitives. Knowing them up front prevents most of the head-scratching.
| Concept | Android API | Purpose |
|---|---|---|
| PeerConnectionFactory | org.webrtc.PeerConnectionFactory |
Boots libwebrtc, registers codecs, sets capture devices |
| PeerConnection | PeerConnection |
The session: ICE candidates, SDP offer/answer, media tracks |
| MediaStream / MediaStreamTrack | VideoTrack, AudioTrack |
Wraps camera and mic capture for transmission |
| DataChannel | DataChannel |
Out-of-band messaging (chat, control, file transfer) |
| SurfaceViewRenderer | SurfaceViewRenderer |
Renders incoming or local video to the UI |
Camera capture — the part Android-specific bugs love
libwebrtc ships with two camera capturers: Camera1Enumerator (legacy) and Camera2Enumerator (post-Lollipop). Always pick Camera2 for new code.
val enumerator = Camera2Enumerator(context)
val capturer = enumerator.deviceNames.firstOrNull { enumerator.isFrontFacing(it) }
?.let { enumerator.createCapturer(it, null) }
?: throw IllegalStateException("No front camera")
capturer.initialize(surfaceTextureHelper, context, source.capturerObserver)
capturer.startCapture(1280, 720, 30)
Mind the foreground service. From Android 14 onwards, camera capture from a background or background-launching activity is restricted. Wrap the capture in a FOREGROUND_SERVICE_TYPE_CAMERA service for any session that survives backgrounding.
Signalling — SDP offer/answer and ICE candidates
WebRTC does not specify the signalling channel; you bring your own. Most products use Socket.IO, plain WebSocket, gRPC, or a vendor SDK’s built-in signalling. The protocol carries three message types between peers (or to the SFU):
1. SDP offer — the offerer’s media capabilities. 2. SDP answer — the answerer’s capabilities. 3. ICE candidates — network-path candidates exchanged as both sides discover them.
peerConnection.createOffer(object : SdpObserver {
override fun onCreateSuccess(sdp: SessionDescription) {
peerConnection.setLocalDescription(this, sdp)
signalingClient.sendOffer(sdp)
}
override fun onSetSuccess() {}
override fun onCreateFailure(p0: String?) { /* handle */ }
override fun onSetFailure(p0: String?) { /* handle */ }
}, MediaConstraints())
Android WebRTC SDKs compared — libwebrtc, Stream, LiveKit, Daily, Agora, 100ms
Most teams ship via an SDK rather than libwebrtc directly. The SDK adds room concepts, adaptive bitrate, and a steady migration path through Android API changes. Below is the lay of the land.
| SDK | License | Strengths | Best for |
|---|---|---|---|
| libwebrtc (Google) | BSD 3 | Maximum control; no licensing cost | Bespoke SFUs, deep customisation, on-prem |
| LiveKit Android | Apache 2 | Same code Cloud ↔ OSS, Compose-friendly | Most modern Android products |
| Stream Video Android | Mixed (free + paid) | Ready-made UI, low-code rooms | Fast time-to-MVP for chat-first apps |
| Daily Android | Proprietary | HIPAA-friendly, well-documented | Healthcare-adjacent products |
| Agora Android | Proprietary | Strong APAC presence; cheap at volume | High-volume tutoring / live |
| 100ms Android | Proprietary | Native polls, engagement analytics | Interactive live events |
| Zoom Video SDK Android | Proprietary | Brand trust; SOC 2 baked in | Education and enterprise products |
Reach for libwebrtc directly when: you are building or migrating to a custom SFU and need full control of the codec list, packetisation, and transport. Otherwise an SDK saves weeks.
Stuck choosing an Android WebRTC SDK?
We have shipped Android clients on all of them. We will pick the right SDK for your scale, compliance, and language mix in one call.
Five Android-specific gotchas that eat sprints
1. Foreground service for camera and mic. Android 14+ blocks camera capture from background activities. Wrap the call in a FOREGROUND_SERVICE_TYPE_CAMERA/_MICROPHONE service or your sessions die when users navigate away.
2. Audio focus and mode. WebRTC needs MODE_IN_COMMUNICATION on the AudioManager and an AudioFocusRequest with USAGE_VOICE_COMMUNICATION. Skipping this gives you echo, low volume, and Bluetooth-routing chaos.
3. Hardware codec selection. H.264 hardware encoders on older Snapdragons mishandle keyframes; VP9 is more reliable across the fleet but uses more CPU. Override the codec preference list per device class.
4. Simulcast tuning. Default simulcast layers are configured for desktops. On phones, drop one layer (typically the 1080p one) to keep CPU within budget. Keep the 360p “low” layer for receivers on weak networks.
5. Doze and Network changes. When the device dozes or switches network, ICE restarts. Implement peerConnection.restartIce() with backoff; without it your reconnects fail in unintuitive ways.
Jetpack Compose UI — rendering remote video without recomposition jank
SurfaceViewRenderer is a View, not a composable. Wrap it in AndroidView and remember the renderer instance to avoid repeated init/release on recomposition.
@Composable
fun RemoteVideoRenderer(track: VideoTrack, modifier: Modifier = Modifier) {
val renderer = remember {
SurfaceViewRenderer(context).apply { init(eglBase.eglBaseContext, null) }
}
DisposableEffect(track) {
track.addSink(renderer)
onDispose { track.removeSink(renderer); renderer.release() }
}
AndroidView(factory = { renderer }, modifier = modifier)
}
Track instability in Compose is a known headache. Our Vkompose performance guide covers Strong Skipping, Modifier.Node, and the recomposition traps that affect WebRTC video grids specifically.
Recording, screen sharing, and PiP on Android
Recording. Per-track recording happens on the SFU; the Android client only emits its own MediaStream. For client-side recording use MediaRecorder with the encoder track, but expect file-size, sync, and battery costs.
Screen share. Use MediaProjection + VirtualDisplay; libwebrtc’s ScreenCapturerAndroid wraps the media projection token. The full implementation walk-through is in our Android WebRTC screen sharing guide.
Picture-in-picture. Plan PiP on phones (Android 8+) and on Android TV. Pause low-tier simulcast layers when entering PiP to save battery; some SDKs do this automatically, others need a hook.
Network handling — congestion, ICE restart, and weak-network UX
Android phones move between Wi-Fi and cellular constantly. Three patterns keep sessions alive:
1. ICE restart with exponential backoff. When PeerConnection.iceConnectionState reports DISCONNECTED, wait 2–5 s before calling restartIce(). Many transient issues self-heal.
2. Adaptive bitrate signalling. Use simulcast layers and let the SFU pick the right one for each receiver; do not try to second-guess the bitrate selection in your app.
3. Bad-network UX. Show a low-quality avatar or last-frame still when stats fall below a threshold. Test with Charles Proxy or our methodology in Simulating slow network connections for video apps.
Testing Android WebRTC — unit, instrumented, and synthetic load
Unit tests. Mock the SDP and ICE callbacks; test signalling state machines independently of libwebrtc.
Instrumented tests. Espresso + UI automator can drive a test client; pair with a CI-controlled SFU sandbox to assert join/leave/freeze metrics.
Synthetic load. Tools like our streaming-optimization guide describe the harness we use to generate 1K+ concurrent fake clients against an SFU; the same approach applies to validating Android WebRTC client robustness.
Cost of building an Android WebRTC client
| Scope | Included | Indicative range | Calendar |
|---|---|---|---|
| SDK-based MVP (LiveKit / Stream) | 1:1 + group call, Compose UI, basic recording | $15K–$35K | 3–6 weeks |
| Custom UI on top of SDK | Branded video grid, custom controls, PiP, in-app chat | +$10K–$25K | +2–4 weeks |
| Direct libwebrtc client (custom SFU) | Bespoke signalling + capture + render | $40K–$80K | 8–12 weeks |
| Screen sharing pack | MediaProjection wiring, foreground service, simulcast tuning | $8K–$15K | 1–2 weeks |
| PiP + Android TV | Picture-in-picture, leanback, remote-control input | $10K–$20K | 1–3 weeks |
A decision framework — pick an Android WebRTC path in five questions
1. Does your team have WebRTC experience? No → SDK (LiveKit / Stream / Daily). Yes → libwebrtc directly is on the table.
2. What is the user’s primary device class? Phones → default 720p simulcast. Tablets / TV → bigger video grid, plan for landscape and PiP.
3. Compose or XML? Compose for new builds; XML only for legacy codebases or specific OEM constraints.
4. Do you need screen sharing on Android? Yes → budget $8–$15K and plan a foreground service. No → defer to v2.
5. What is your concurrent-user target? < 200 → SDK fees are tolerable. > 500 → pair the Android client with a self-hosted SFU.
Pitfalls we have watched Android WebRTC teams fall into
1. Skipping the foreground service. Sessions die on backgrounding; reviewers reject the app. Build it from sprint 1.
2. Picking 1080p as the default. Phones overheat and burn battery. Default to 720p simulcast and opt up only on confirmed hardware.
3. Initialising EglBase on every recomposition. A classic Compose mistake; the second instance crashes the renderer. Wrap in remember.
4. Ignoring AudioManager mode. Without MODE_IN_COMMUNICATION you fight echo, low volume, and Bluetooth routing forever.
5. Using Camera1Enumerator in 2026. It still works, but newer devices and codec paths assume Camera2; you will hit obscure bugs.
KPIs — what to measure on the Android client
Quality KPIs. p95 join time < 4 s, freeze rate < 1%, audio MOS > 4.0, simulcast-layer-up success rate > 90%.
Business KPIs. Crash-free sessions > 99.5%, install-to-day-1 retention movement after performance ships, Play Store Vitals “bad behaviours” under threshold.
Reliability KPIs. Reconnect success rate > 95%, Doze-mode session resumption < 5 s, foreground-service uptime 100% during active calls.
When NOT to use WebRTC on Android
Skip WebRTC when (a) the use case is one-way live broadcast to thousands — HLS or LL-HLS scales better; (b) the latency budget is over five seconds — LL-HLS is cheaper; or (c) the team has neither SDK budget nor WebRTC experience — consider a managed video conferencing iframe instead.
Need a stage-matched Android WebRTC plan?
A 30-minute call gets you an SDK pick, a Compose-friendly architecture, screen-sharing budget, and a calendar.
FAQ
What is the easiest Android WebRTC SDK to start with?
LiveKit Android for Compose-first builds, Stream Video Android for chat-heavy products, Daily for HIPAA-friendly contexts. All ship 1:1 + group call MVPs in 3–6 weeks.
When should we use libwebrtc directly instead of an SDK?
When you are building or migrating to a custom SFU and need full control over codec preferences, packetisation, and transport. Otherwise an SDK is materially faster and cheaper.
Does WebRTC work in the background on Android?
Only if you wrap the camera/mic capture in a foreground service with the appropriate type (FOREGROUND_SERVICE_TYPE_CAMERA, _MICROPHONE). Without it Android 14+ kills the capture when the activity backgrounds.
How do we handle network changes (Wi-Fi to LTE)?
Watch PeerConnection.iceConnectionState. On DISCONNECTED wait 2–5 s and call restartIce() with exponential backoff. Most transient changes self-heal.
How do we record a session on Android?
Per-track recording happens on the SFU (cloud or self-hosted). Client-side recording is possible with MediaRecorder but burns battery and disk; we recommend server-side recording for any production product.
Compose or XML for the UI?
Compose for any new build. SurfaceViewRenderer wraps cleanly inside AndroidView; just remember the renderer with remember { } to avoid recomposition reinit.
Has Fora Soft shipped Android WebRTC products at scale?
Yes — BrainCert ships Android clients to 100K+ paying customers; ProvideoMeeting ships an enterprise client. Many more are under NDA.
What is the cost of building an Android WebRTC client?
$15–$35K for an SDK-based MVP, +$10–$25K for a custom UI, $40–$80K for a libwebrtc-direct client tied to a custom SFU. Add $8–$15K for screen sharing and $10–$20K for PiP/Android TV support.
What to Read Next
Implementation
Android WebRTC screen sharing — the complete guide
A worked example of an Android feature whose performance budget is unforgiving.
Compose performance
Vkompose & Jetpack Compose performance
The recomposition traps that affect WebRTC video grids.
Topology
P2P vs MCU vs SFU for video conferencing
A practical comparison of the topologies the Android client connects to.
iOS counterpart
WebRTC in iOS — how to add video calls
The same playbook applied to iOS — useful when you build for both platforms.
Ready to ship a clean Android WebRTC client?
Android WebRTC in 2026 is a solved problem when you respect the platform’s rules: foreground service for capture, audio focus, hardware codec selection, simulcast tuning, and Doze-mode reconnects. SDK choice is downstream of those rules. Compose is the default UI; libwebrtc directly is the right pick for custom SFUs only.
If you want a stage-matched plan — SDK choice, screen sharing, recording, PiP, and a realistic calendar — the fastest next step is a 30-minute call. We will pick the path, scope the work, and tell you honestly when an SDK MVP beats a custom build.
Talk to our Android engineering leads
Book a 30-minute call. We will scope the Android WebRTC client — SDK, capture, render, screen share, calendar, budget — in one session.



.avif)

Comments