Skip to content
Mobile
Skill

/camera-streaming

Session and Stream capability setup, video frames, photo capture, resolution and frame rate configuration

BOOST
From plugin
meta-wearables-dat-android
38117 skills
Install
$ npx -y skills add facebook/meta-wearables-dat-android --skill camera-streaming --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/camera-streaming

Context preview

The summary Claude sees to decide when to auto-load this skill.

Session and Stream capability setup, video frames, photo capture, resolution and frame rate configuration

SKILL.md

camera-streaming.SKILL.md
name: camera-streaming
description: Session and Stream capability setup, video frames, photo capture, resolution and frame rate configuration

Camera Streaming (Android)

Use a `DeviceSession` and an attached `Camera` to receive frames and capture photos through `camera.stream`.

For PCM audio delivered with this stream, use the `audio-streaming` skill.

Key concepts

  • **DeviceSession**: Device connection lifecycle created through `Wearables.createSession(...)`
  • **Camera**: Camera capability attached to a session with `session.addCamera(...)`
  • **Stream**: Video stream accessed through `camera.stream`
  • **StreamConfiguration**: Video quality, frame rate, and compression configuration for the stream
  • **PhotoData**: Still image captured from glasses while streaming

Create a session and attach a stream

`DeviceSession.start()` is fire-and-forget: it returns `Unit` and the connection completes in the background. A capability can only be added once the session reports `DeviceSessionState.STARTED` — calling `addCamera(...)` right after `start()` fails with `DeviceSessionError.SESSION_IDLE`. Add the camera from the session-state collector.

import com.meta.wearable.dat.camera.Camera
import com.meta.wearable.dat.camera.addCamera
import com.meta.wearable.dat.camera.types.StreamConfiguration
import com.meta.wearable.dat.camera.types.VideoQuality
import com.meta.wearable.dat.core.Wearables
import com.meta.wearable.dat.core.selectors.AutoDeviceSelector
import com.meta.wearable.dat.core.session.DeviceSessionState

var camera: Camera? = null

Wearables.createSession(AutoDeviceSelector()).fold(
    onSuccess = { session ->
        lifecycleScope.launch {
            session.errors.collect { error -> showError(error.description) }
        }
        lifecycleScope.launch {
            session.state.collect { state ->
                if (state == DeviceSessionState.STARTED && camera == null) {
                    session.addCamera(
                        StreamConfiguration(
                            videoQuality = VideoQuality.MEDIUM,
                            frameRate = 24,
                        ),
                    ).fold(
                        onSuccess = { addedCamera ->
                            camera = addedCamera
                            addedCamera.stream.start().onFailure { error, _ ->
                                showError(error.description)
                            }
                        },
                        onFailure = { error, _ -> showError(error.description) },
                    )
                }
            }
        }
        // Subscribe before start() so no initial transition is missed.
        session.start()
    },
    onFailure = { error, _ -> showError(error.description) },
)

Check `Wearables.checkPermissionStatus(Permission.CAMERA)` before starting the stream; see the `permissions-registration` skill.

Resolution options

| Quality | Size | |---------|------| | `VideoQuality.HIGH` | 720 x 1280 | | `VideoQuality.MEDIUM` | 504 x 896 | | `VideoQuality.LOW` | 360 x 640 |

Frame rate options

Valid values: `2`, `7`, `15`, `24`, `30` FPS.

Lower resolution and frame rate usually produce better visual quality per frame over Bluetooth.

Observe stream state

`StreamState` transitions: `STOPPED` -> `STARTING` -> `STARTED` -> `STREAMING` -> `STOPPING` -> `STOPPED`, and `CLOSED` once the stream is terminal. `PAUSED` is reported when the device pauses the stream, for example on a single cap-touch tap; the stream can resume on its own from `PAUSED`.

lifecycleScope.launch {
    camera.stream.state.collect { state ->
        when (state) {
            StreamState.STREAMING -> {
                // Frames are flowing
            }
            StreamState.PAUSED -> {
                // Paused by the device; wait for it to resume
            }
            StreamState.STOPPED -> {
                // Streaming ended
            }
            StreamState.CLOSED -> {
                // Stream fully closed
            }
            else -> Unit
        }
    }
}

Observe `camera.stream.errorStream` alongside the state. `StreamError.STREAM_ERROR` is informational and does not stop the stream, while `StreamError.CRITICAL_STREAM_ERROR` means the stream should be torn down.

lifecycleScope.launch {
    camera.stream.errorStream.collect { error ->
        showStreamError(error.description)
    }
}

Receive frames

lifecycleScope.launch {
    camera.stream.videoStream.collect { frame ->
        updatePreview(frame)
    }
}

By default the SDK decodes on the phone and `VideoFrame.buffer` holds YUV pixel data. Set `StreamConfiguration(compressVideo = true)` to receive compressed HEVC buffers instead; then check `frame.isCompressed` and `frame.isCodecConfig` and feed the frames to your own decoder. Keep frame handling off the main thread for anything heavier than a buffer copy.

In-stream photo capture

This path captures while video streaming remains active. For standalone high-quality capture with resolution, quality, transfer progress, and its own lifecycle, use the `camera-capture` skill.

`capturePhoto()` only succeeds while the stream is active, and returns a `PhotoData` sealed type — branch on the variant instead of reading a single `data` property.

import com.meta.wearable.dat.camera.types.PhotoData

lifecycleScope.launch {
    camera.stream.capturePhoto()
        .onSuccess { photoData ->
            when (photoData) {
                is PhotoData.Bitmap -> savePhoto(photoData.bitmap)
                is PhotoData.HEIC -> saveHeic(photoData.data) // ByteBuffer of HEIC bytes
            }
        }
        .onFailure { error, _ ->
            showCaptureError(error.description)
        }
}

Only one capture can be in flight at a time; a second concurrent call fails with `CaptureError.CaptureInProgress`.

Clean up

Stop the camera when you no longer need camer

Read more
Ships withmeta-wearables-dat-android

The Meta Wearables Device Access Toolkit enables developers to utilize Meta's AI glasses to build hands-free wearable experiences into their mobile applications.

Get the whole plugin