Add ADB-based Android screen capture engine with display picker integration
New scrcpy/ADB capture engine that captures Android device screens over ADB using screencap polling. Supports USB and WiFi ADB connections with device auto-discovery. Engine-aware display picker shows Android devices when scrcpy engine is selected, with inline ADB connect form for WiFi devices. Key changes: - New scrcpy_engine.py using adb screencap polling (~1-2 FPS over WiFi) - Engine-aware GET /config/displays?engine_type= API - ADB connect/disconnect API endpoints (POST /adb/connect, /adb/disconnect) - Display picker supports engine-specific device lists - Stream/test modals pass engine type to display picker - Test template handler changed to sync def to prevent event loop blocking - Restart script merges registry PATH for newly-installed tools - All engines (including unavailable) shown in engine list with status flag Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -215,22 +215,23 @@ async def delete_template(
|
||||
|
||||
@router.get("/api/v1/capture-engines", response_model=EngineListResponse, tags=["Templates"])
|
||||
async def list_engines(_auth: AuthRequired):
|
||||
"""List available capture engines on this system.
|
||||
"""List all registered capture engines.
|
||||
|
||||
Returns all registered engines that are available on the current platform.
|
||||
Returns every registered engine with an ``available`` flag showing
|
||||
whether it can be used on the current system.
|
||||
"""
|
||||
try:
|
||||
available_engine_types = EngineRegistry.get_available_engines()
|
||||
available_set = set(EngineRegistry.get_available_engines())
|
||||
all_engines = EngineRegistry.get_all_engines()
|
||||
|
||||
engines = []
|
||||
for engine_type in available_engine_types:
|
||||
engine_class = EngineRegistry.get_engine(engine_type)
|
||||
for engine_type, engine_class in all_engines.items():
|
||||
engines.append(
|
||||
EngineInfo(
|
||||
type=engine_type,
|
||||
name=engine_type.upper(),
|
||||
default_config=engine_class.get_default_config(),
|
||||
available=True,
|
||||
available=(engine_type in available_set),
|
||||
)
|
||||
)
|
||||
|
||||
@@ -242,7 +243,7 @@ async def list_engines(_auth: AuthRequired):
|
||||
|
||||
|
||||
@router.post("/api/v1/capture-templates/test", response_model=TemplateTestResponse, tags=["Templates"])
|
||||
async def test_template(
|
||||
def test_template(
|
||||
test_request: TemplateTestRequest,
|
||||
_auth: AuthRequired,
|
||||
processor_manager: ProcessorManager = Depends(get_processor_manager),
|
||||
@@ -250,6 +251,10 @@ async def test_template(
|
||||
):
|
||||
"""Test a capture template configuration.
|
||||
|
||||
Uses sync ``def`` so FastAPI runs it in a thread pool — the engine
|
||||
initialisation and capture loop are blocking and would stall the
|
||||
event loop if run in an ``async def`` handler.
|
||||
|
||||
Temporarily instantiates an engine with the provided configuration,
|
||||
captures frames for the specified duration, and returns actual FPS metrics.
|
||||
"""
|
||||
@@ -301,8 +306,9 @@ async def test_template(
|
||||
screen_capture = stream.capture_frame()
|
||||
capture_elapsed = time.perf_counter() - capture_start
|
||||
|
||||
# Skip if no new frame (screen unchanged)
|
||||
# Skip if no new frame (screen unchanged); yield CPU
|
||||
if screen_capture is None:
|
||||
time.sleep(0.005)
|
||||
continue
|
||||
|
||||
total_capture_time += capture_elapsed
|
||||
|
||||
Reference in New Issue
Block a user