camera-streaming

作者: facebook

會話與串流能力設定、視訊幀、照片擷取、解析度與幀率配置

npx skills add https://github.com/facebook/meta-wearables-dat-android --skill camera-streaming

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

QualitySize
VideoQuality.HIGH720 x 1280
VideoQuality.MEDIUM504 x 896
VideoQuality.LOW360 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 camera data, then stop the parent session if the device interaction is finished. Stopping the camera cascades to its stream, and stopping the session cascades to every attached capability.

camera.stop()
session.stop()

Camera.stop() and Stream.stop() invalidate the instance — they cannot be restarted. Call session.removeCamera() to detach the capability so a later session.addCamera(...) on the same session can succeed.

Links

來自 facebook 的更多技能

gc-safe-coding
facebook
完整解釋與理由請參閱 doc/GCSafeCoding.md。
app-review-prep
facebook
準備將 Meta 應用程式提交至 App Review——檢查目前狀態、未完成的要求、已授予的權限及提交紀錄。請在提交應用程式前使用……
api-health
facebook
監控 Meta 應用程式的 API 健康狀態 — 檢查速率限制、呼叫量與 API 棄用情況。用於診斷節流問題、規劃容量,或為 API 版本…做好準備。
debug-webhooks
facebook
排解 Meta 應用程式的 webhook 問題——檢查作用中的訂閱、找出設定錯誤,並傳送測試負載以驗證傳遞。當……時使用。
api-integration
facebook
引導開發者從零開始設定 Meta API 整合 — 找出正確的 API、取得設定指南、驗證需求、…
webhook-setup
facebook
端到端設定 Meta 應用程式的 Webhook — 探索可用主題、訂閱欄位,並透過測試負載驗證。在為… 設定 Webhook 時使用。
test-ui
facebook
使用 iwsdk CLI 針對 poke 範例測試 UI 系統(PanelUI、ScreenSpace)。
flags
facebook
檢查並比較 React 發佈通道中的功能旗標狀態。檢視所有通道(www、www-modern、canary、next、experimental、rn 變體)的旗標,或使用 --diff 比較特定通道。輸出格式包括預設表格檢視、CSV 匯出及清理狀態分組。旗標狀態以符號表示:啟用(✅)、停用(❌)、變體測試(🧪)、僅分析(📊)。常見陷阱:__VARIANT__ 旗標在 www 上會以兩種狀態進行測試;使用 --diff 可找出有意義的差異。