WebRTC Streaming¶
Stream the Android device or iOS simulator driven by an AutoMobile daemon to a WHIP server such as MediaMTX, then watch it through WHEP in a browser.
CI worker → WHIP ingest → MediaMTX → WHEP browser viewer
Configure the worker¶
Start the daemon with a booted Android device or iOS simulator, then set a unique WHIP path for each CI job:
export AUTOMOBILE_WEBRTC_WHIP_ENDPOINT="https://mediamtx.example.com:8889/$CI_JOB_ID/whip"
# Optional for authenticated or NAT-restricted deployments:
export AUTOMOBILE_WEBRTC_WHIP_TOKEN="<user>:<pass>"
export AUTOMOBILE_WEBRTC_ICE_SERVERS='[{"urls":"turn:turn.example.com:3478","username":"user","credential":"secret"}]'
MediaMTX must expose its WHIP/WHEP listener and reachable ICE candidates. For containerized or firewalled deployments, expose its WebRTC UDP port too.
Start, watch, and stop¶
The daemon accepts newline-delimited JSON on
~/.auto-mobile/webrtc-stream.sock:
SESSION_UUID="<sessionUuid returned by the MCP getAndroid or getApple tool>"
DEVICE_ID="<device id returned by the same tool>"
PLATFORM="android" # Use "ios" for an iOS Simulator.
STREAM_ID="$CI_JOB_ID"
WHIP="https://mediamtx.example.com:8889/$CI_JOB_ID/whip"
START_RESPONSE="$(
jq -nc \
--arg sessionUuid "$SESSION_UUID" \
--arg deviceId "$DEVICE_ID" \
--arg platform "$PLATFORM" \
--arg streamId "$STREAM_ID" \
--arg whipEndpoint "$WHIP" \
'{action:"start",$sessionUuid,$deviceId,$platform,$streamId,$whipEndpoint}' \
| nc -U ~/.auto-mobile/webrtc-stream.sock
)"
LEASE_ID="$(jq -er '.stream.lease.id' <<<"$START_RESPONSE")"
# Watch: https://mediamtx.example.com:8889/$CI_JOB_ID
# Send this status request at least once every 60 seconds while the job runs;
# carrying leaseId renews the stream lease.
jq -nc \
--arg sessionUuid "$SESSION_UUID" \
--arg streamId "$STREAM_ID" \
--arg leaseId "$LEASE_ID" \
'{action:"status",$sessionUuid,$streamId,$leaseId}' \
| nc -U ~/.auto-mobile/webrtc-stream.sock
jq -nc \
--arg sessionUuid "$SESSION_UUID" \
--arg streamId "$STREAM_ID" \
--arg leaseId "$LEASE_ID" \
'{action:"stop",$sessionUuid,$streamId,$leaseId}' \
| nc -U ~/.auto-mobile/webrtc-stream.sock
Acquire a fresh daemon session with the public MCP getAndroid or getApple
tool before opening the socket; every request must carry that tool’s
sessionUuid. The example always includes deviceId and platform so the iOS
path cannot silently fall back to Android. The stream reconnects after transient
network failures; browser viewers may need to reconnect too.
Troubleshooting¶
No WHIP endpoint configured: setAUTOMOBILE_WEBRTC_WHIP_ENDPOINTor passwhipEndpointin the start request.401: configure MediaMTX credentials and setAUTOMOBILE_WEBRTC_WHIP_TOKEN.- Connected but black video: configure a reachable TURN server or MediaMTX ICE host.
iOS Simulator highlights¶
On macOS, highlight draws over the Simulator through screen-capture-helper;
With a helper advertising simulator-highlights, Simulators do not need the
AutoMobile SDK in the target app. Older pinned helpers retain the SDK route until
a capable helper is released; a local helper can be selected using the override below. Physical iOS devices
continue to use the SDK overlay. The host helper needs Screen Recording and
Accessibility access in System Settings → Privacy & Security. The Simulator window
must be visible. For capture of highlights, keep the window fully on one monitor.
Highlights draw a red hand-drawn circle using Android’s irregular arcs, varying
stroke width, and 1.2-second draw/hold/fade animation. Circle bounds use device
coordinates, with bounds.sourceWidth and bounds.sourceHeight describing their
source coordinate space. Selector-based highlights obtain these dimensions from
the hierarchy automatically. The helper reads the Simulator’s accessibility
display bounds to exclude its toolbar and bezel when positioning circles. Box, path, color, and stroke-style options are not supported.
While a highlight is visible, ScreenCaptureKit captures only the selected Simulator and the helper’s overlay windows, cropped to the Simulator window. The same capture path feeds raw frames and H.264 streams. Separate device screenshots do not include the host overlay. Outside highlights, capture uses its independent-window filter. The overlay host stays alive until its parent daemon exits because ScreenCaptureKit retains connections to applications whose windows have appeared in a stream.
For a local development build, build ios/screen-capture with SwiftPM and set
AUTOMOBILE_IOS_SCREEN_CAPTURE_HELPER to the absolute path of its
screen-capture-helper executable when starting AutoMobile. Both capture and
highlighting must use this build; older released helpers do not support the overlay
command. Rebuilt or unsigned executables may require renewed macOS privacy approval.