Skip to content

WebRTC Streaming

WebRTC streaming provides a live view of the phone screen in the browser at 720x1280 resolution. The server acts as a signaling proxy between the browser and the Droidrun Portal APK on the device.

Browser (dashboard or standalone viewer)
|
| 1. POST /api/phone/webrtc-signal {method: "stream/start"}
v
Server (Flask) -- sets callbackUrl
|
| 2. HTTP POST to Portal (localhost:<port>/stream/start)
v
Droidrun Portal APK (on device)
|
| 3. Captures screen via MediaProjection
| 4. POSTs signaling (offer/ice) -> /api/phone/webrtc-callback/<device>
v
Server stores in _signaling_queues[device]
|
| 5. Browser polls GET /api/phone/webrtc-poll-signals/<device>
| 6. Browser sends answer/ice -> POST /api/phone/webrtc-signal
v
WebRTC peer connection established -- video flows device -> browser
Terminal window
# Install Droidrun Portal APK on the device
adb install portal.apk
# Enable accessibility service
# Settings -> Accessibility -> Droidrun Portal -> Enable
# Port forwards (set up automatically by server)
adb -s <serial> forward tcp:18XXX tcp:8080 # Portal HTTP
adb -s <serial> forward tcp:19XXX tcp:8081 # Portal WebSocket

Port allocation is deterministic: _stable_port(serial, base) uses MD5 of the device serial. Each device gets a unique port pair.

  1. Start server: python3 run.py
  2. Open http://localhost:5055 -> Phone Admin tab
  3. Select device -> click Start Stream
  4. FPS counter overlay: green (20+), yellow (10-19), red (<10)
# Single device
http://localhost:5055/api/phone/webrtc-viewer?device=L9AIB7603188953
# Multi-device grid
http://localhost:5055/api/phone/webrtc-multi?device=L9AIB7603188953&device=RZCX125RE5L

If WebRTC fails, three MJPEG streaming modes are available:

ModeHow It WorksFPSQuality
portalPortal /screenshot -> base64 PNG -> JPEG~3-5Good
screencapadb exec-out screencap -p -> PIL -> JPEG~2OK
h264screenrecord --output-format=h264 -> ffmpeg -> MJPEG~25Best

All modes halve the resolution (width/2, height/2) for bandwidth. Access via:

GET /api/phone/stream/<device>?mode=portal

Use as an <img> src for live view in any HTML page.

MethodEndpointPurpose
GET/api/phone/stream/<device>MJPEG stream
POST/api/phone/webrtc-signalRelay signaling to Portal
POST/api/phone/webrtc-callback/<device>Receive signaling from Portal
GET/api/phone/webrtc-poll-signals/<device>Poll pending signaling messages
POST/api/phone/webrtc-ws-sendSend via Portal WebSocket
POST/api/phone/webrtc-ws-pollPoll WebSocket messages
GET/api/phone/webrtc-viewerStandalone single-device viewer
GET/api/phone/webrtc-multiMulti-device grid viewer
GET/api/phone/elements/<device>Interactive elements for overlay

When used in the Skill Creator tab, the WebRTC stream shows numbered labels on interactive elements. This overlay is generated from GET /api/phone/elements/<device> and rendered as positioned HTML elements on top of the video feed.

Terminal window
# Allow Flask server
sudo ufw allow 5055
# Allow WebRTC UDP traffic on local network
sudo ufw allow proto udp from 192.168.0.0/24
  1. Verify Portal APK is installed: adb shell pm list packages | grep droidrun
  2. Check accessibility service is enabled on the device
  3. The first stream/start may return prompting_user (MediaProjection dialog) — approve on device
  4. Fallback to MJPEG if WebRTC fails: Phone Admin tab -> MJPEG toggle
  • WebRTC is limited by Portal’s MediaProjection capture rate (~5-15 FPS)
  • MJPEG h264 mode gives ~25 FPS but requires ffmpeg

WebRTC uses UDP for media transport. If behind a strict firewall, use MJPEG mode instead.