Skip to content

Screenshot backend: DroidCast APK HTTP stream #39

@Coldaine

Description

@Coldaine

Goal

Implement the _capture_droidcast() backend in adb_vision/screenshot.py.

DroidCast is an Android app that streams the device screen over HTTP as JPEG/PNG. It works by using Android's hidden SurfaceControl API (or MediaProjection), bypassing the Linux framebuffer entirely — which is critical because adb shell screencap returns blank images on MEmu/VirtualBox (the GPU never populates /dev/graphics/fb0).

Interface

The function signature is already defined in adb_vision/screenshot.py:

async def _capture_droidcast(*, adb_run: AdbRunFn, serial: str, adb_exe: str) -> str:
    """Return base64-encoded PNG screenshot via DroidCast HTTP stream."""

adb_run is an async helper: async def _adb_run(*args, timeout) -> bytes that runs adb -s <serial> <args>.

Implementation Plan

  1. Push the DroidCast APK to the device if not already installed:

    • APK source: alas_wrapped/bin/DroidCast/DroidCast-debug-1.2.3.apk (already in repo)
    • adb_run("install", "-r", apk_path, timeout=30.0)
  2. Start the DroidCast service on the device:

    • adb_run("shell", "am", "start-foreground-service", "-n", "com.rayworks.droidcast/.Main", "-a", "android.intent.action.MAIN", timeout=10.0)
    • Or use the app_process method: adb_run("shell", "CLASSPATH=/data/local/tmp/DroidCast.dex", "app_process", "/", "com.rayworks.droidcast.Main", timeout=5.0) (background)
  3. Forward the port: adb_run("forward", "tcp:53516", "tcp:53516", timeout=5.0)

  4. Fetch the screenshot via HTTP: GET http://localhost:53516/screenshot?format=png

    • Use asyncio + aiohttp or raw urllib in an executor
  5. Return base64-encoded PNG string

Testing (TDD)

Write tests in adb_vision/test_server.py (or a new adb_vision/test_droidcast.py):

  • Mock test: Mock adb_run to verify install/start/forward commands are called correctly. Mock HTTP response with a fake PNG (use _fake_png() helper already in test_server.py).
  • Failure test: Mock HTTP returning 404 → should raise RuntimeError.
  • Already-running test: If port forward already works, skip install/start.

Tests must pass without a device — all ADB and HTTP calls mocked.

Files to Modify

  • adb_vision/screenshot.py — replace the _capture_droidcast stub
  • adb_vision/test_server.py or new adb_vision/test_droidcast.py — add tests

Acceptance Criteria

  • _capture_droidcast() returns valid base64 PNG when DroidCast is running
  • All existing tests still pass (uv run pytest test_server.py -v in adb_vision/)
  • New tests cover: happy path, HTTP failure, idempotent start
  • No ALAS imports anywhere

Metadata

Metadata

Assignees

No one assigned

    Labels

    JulesAssigned to Jules (GitHub Copilot agent)enhancementNew feature or requestgood first issueGood for newcomerskilo-auto-fixAuto-generated label by Kilokilo-triagedAuto-generated label by KiloscreenshotScreenshot capture backends

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions