Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AIWebcam

A Flutter app that turns a phone into a networked camera + sensor server — an ad-free, self-hosted alternative to IP Webcam, with an MCP endpoint so an AI can see through and control the camera.

Plain HTTP on :8080, TLS on :8443 (self-signed). Both expose the same API. The app is a menu that flows into per-feature screens; the server and camera run above the navigation, so every endpoint is live from launch regardless of the current screen.

API

Camera

Endpoint Returns
/photo.jpg, /shot.jpg Full-sensor-resolution JPEG
/video, /videofeed MJPEG stream (multipart/x-mixed-replace), ~4–5 fps / 640px
/audio.wav Live 16 kHz mono PCM as streaming WAV

Controls (thin wrappers over the camera plugin)

Endpoint Effect
/settings/zoom?set=2.5 Zoom level (clamped to device range)
/settings/exposure?set=-1 Exposure offset (EV)
/settings/focusmode?set=locked auto | locked
/settings/exposuremode?set=locked auto | locked
/focus?x=0.5&y=0.5 Focus point (omit params → auto)
/enabletorch, /disabletorch, /settings/torch?set=on Torch
/front, /back, /settings/camera?set=2 Camera select
/settings/resolution?set=high lowmax (re-inits)

Telemetry

/sensors.json (accel/gyro/mag) · /battery.json · /gps.json · /status.json · / (HTML docs index)

AI / MCP

POST /mcp — Model Context Protocol over Streamable HTTP (JSON-RPC 2.0). Tools: capture_photo (returns an image block — the model sees the frame), set_zoom, set_exposure, set_torch, switch_camera, set_resolution, get_status, get_sensors, get_battery, get_gps.

Point any MCP client at http://<phone-ip>:8080/mcp.

Run it

  1. Connect an Android phone (USB or wireless debugging).
  2. flutter run
  3. Grant camera permission. Mic/location are requested lazily the first time /audio.wav / /gps.json are hit.

Use as a real computer webcam (Linux)

The app can't make the OS see a webcam by itself — bridge /video into a virtual V4L2 device:

sudo modprobe v4l2loopback card_label="AIWebcam" exclusive_caps=1
ffmpeg -f mjpeg -i http://<phone-ip>:8080/video -vf format=yuv420p -f v4l2 /dev/videoN

Then AIWebcam appears as a camera in Zoom/Meet/OBS/Chrome. (Cross-platform: pull /video into OBS → Start Virtual Camera.) Quality is bounded by the pure-Dart MJPEG encoder (~4–5 fps / 640px).

TLS notes

The certificate is generated on the device, not shipped with the app. On the first start, lib/tls_identity.dart generates a 2048-bit RSA key and a self-signed certificate in an isolate and caches both under the app's support directory; every later start reuses them. So each install is a distinct identity and the private key never leaves the phone.

That is deliberate. A key committed to the repository would be the same key on every install, and anyone with a copy could impersonate or decrypt any other user's camera — which is exactly what shipping assets/certs/key.pem used to do here.

HTTPS is best-effort: if an identity can't be established for any reason, the app logs it and keeps serving plain HTTP on :8080 rather than failing to start.

The certificate is self-signed, so a client still has to accept it on first connection — unavoidable for a device on a private network with no stable hostname. curl -k works anywhere. For full verification, pull the cert off the device once and pin it:

openssl s_client -connect <phone-ip>:8443 -showcerts </dev/null \
  | openssl x509 -outform PEM > aiwebcam.pem
curl --cacert aiwebcam.pem https://<phone-ip>:8443/photo.jpg

Give the phone a static DHCP reservation to keep that stable. To roll the identity — if a device is lost, or a pinned cert should be invalidated — call TlsIdentity.reset(); the next start generates a fresh one.

Architecture

lib/
  main.dart           bootstrap + AppServices + lifecycle + entry menu
  screens.dart        Menu → Camera / Video / Audio / Telemetry / Docs
  camera_engine.dart  owns CameraController; stills, controls, MJPEG (isolate encode)
  telemetry.dart      sensors / battery / GPS
  audio_streamer.dart mic → streaming WAV
  webcam_server.dart  dual HTTP/HTTPS + REST route registry
  tls_identity.dart   per-install self-signed cert, generated on first run
  mcp_server.dart     MCP (JSON-RPC) tools

Limits

  • Stills vs. stream are exclusive. While /video streams, the camera can't also takePicture(), so /photo.jpg returns the latest stream frame (preview-res) until the stream ends. With no stream, /photo.jpg is full-res.
  • No H.264/RTSP/WebRTC/ONVIF. Those need native hardware-encoder access (platform channels) — intentionally out of scope.
  • Dedicated-phone model. Wakelock keeps the screen on; on iOS the app must stay foregrounded. Disable auto-lock.

Stack

Flutter · camera · shelf · network_info_plus · wakelock_plus · sensors_plus · battery_plus · geolocator · image · record.

About

Turns a phone into a networked camera and sensor server, with an MCP endpoint so an AI agent can see through and control the camera. Flutter, on-device HTTP/HTTPS.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages