{
  "schema": "leumas.docs.page/1",
  "id": "pkg:@leumas/devices",
  "slug": "packages/devices",
  "kind": "capabilities",
  "bucket": "package",
  "title": "@leumas/devices",
  "name": "@leumas/devices",
  "eyebrow": null,
  "chip": null,
  "summary": "The shared device layer. Today: the browser half — enumerating media devices, the ONE permission latch a denied prompt sets, camera streams that are ref-counted and time-out on a hung prompt, a mic...",
  "keywords": [
    "devices",
    "latch",
    "hung",
    "recorder",
    "denied",
    "devices api",
    "leumas devices",
    "how to use devices"
  ],
  "audience": "both",
  "funnel": {
    "product": null,
    "cta": null
  },
  "body": "# @leumas/devices\n\nThe shared device layer behind Studio's **Devices HUD** (`/admin/devices`).\n\nToday it ships the **browser half** — everything a surface needs to list, open, test and capture the\ncameras, microphones and speakers attached to the machine the browser is running on. Nothing in it\ntalks to an API.\n\n## Why it exists\n\nThree copies of \"enumerate the media devices\" were already in the tree, each grouping, labelling and\nfailing slightly differently, so the same machine described itself differently depending on which\nsurface you opened:\n\n| Was | Now |\n|---|---|\n| `products/leumas-studio/src/admin/surveillance/utils/browserCamera.js` | a re-export shim over `./media/camera.js` |\n| `shared/packages/os/src/apps/device-manager/DeviceManager.jsx` | consumes `useMediaDevices()` |\n| `shared/packages/splats/src/capture/recorder.js` | generalised into `./media/recorder.js` |\n\n`@leumas/sing`'s `createMicSource` keeps its own latch: it is bound to Sing's AudioContext lifecycle\nand its game loop, and prising that apart would be a refactor of a working game for no visible gain.\nWhat is shared here is the **rule**, not the plumbing.\n\n## The one rule\n\n**A refused permission LATCHES OFF.** A denied `getUserMedia` can never be fixed by asking again —\nthe browser remembers the decision — so a surface that re-requests on the next render prompts\nforever. `permission.js` holds a sticky per-kind `denied` state that only `retryMedia(kind)` clears,\nand it must be called from a real click. This has shipped as a live defect in this repo before.\n\n## API\n\n```js\nimport {\n  useMediaDevices,          // cameras/microphones/speakers + `devicechange` + needsPermission\n  useMicLevel,              // RMS meter for one mic; tears down track, node and AudioContext\n  requestMedia, retryMedia, stopStream, describeMediaError,   // the latch\n  listCameraDevices, startBrowserCamera, stopBrowserCamera, captureFrame,\n  isRecordingSupported, startRecording, downloadBlob, stamp,\n} from '@leumas/devices/media';\n\nimport { TRANSPORTS, SIDES, STATES, isPresent } from '@leumas/devices';\n```\n\nThe **barrel exports nothing from `./media`** on purpose: that half is React and browser-only, and a\nNode consumer (a guard, the API, a test) importing the barrel must not be handed `navigator`.\n\n## Traps worth knowing\n\n- Before any grant, `enumerateDevices()` returns the right **number** of devices with **empty labels\n  and empty ids**. Nothing is broken — the browser is refusing to fingerprint you. `needsPermission`\n  is the tell; `ensureLabels()` asks once, through the latch, and stops the probe stream immediately.\n- `getUserMedia` **never settles** while a prompt sits unanswered, so caching the pending promise (to\n  share one camera between tiles) makes a hung prompt immortal. `camera.js` races it against a 15s\n  timeout for that reason alone.\n- A preview holds the camera open. Stop every track on unmount or the recording light stays on and\n  the next app to ask is told the device is busy.\n- `setSinkId` (routing audio to a chosen output) is **Chromium-only**. Show it disabled with a\n  reason rather than hiding it.\n- `useMicLevel` measures **RMS, not peak**: a peak meter pins to 1.0 on the first consonant and says\n  \"working\" for a mic that has picked up one click and gone silent.\n\n## Next\n\nPass 4 of the Devices roadmap adds the isomorphic half to the barrel — the device record,\n`defineDeviceDriver`, `defineDeviceProvider` — plus a `./host` subpath for the machine-local reads\n(ports, adapters, the paired Bluetooth list) that only mount under `caps.localHardware`.\n",
  "source": {
    "path": "shared/packages/devices/README.md",
    "blobSha": "",
    "commit": "",
    "committedAt": "",
    "provenance": "no-git",
    "bytes": 3738,
    "hash": "f289374849bb030974aa017a217a22e0af026dc0"
  },
  "urls": {
    "html": "/p/packages/devices",
    "json": "/docs/packages/devices.json",
    "md": "/docs/packages/devices.md"
  },
  "links": {
    "composes": [
      "pkg:@leumas/exporters"
    ],
    "usedBy": [
      "pkg:@leumas/studio",
      "pkg:@leumas/tv"
    ],
    "product": [
      "pkg:@leumas/studio"
    ],
    "howTo": [],
    "skills": [
      "skill:leumas-network#capabilities"
    ]
  },
  "exports": {
    "total": 166,
    "component": 35,
    "hook": 2,
    "helper": 129,
    "names": [
      {
        "n": "AGGREGATES",
        "k": "component"
      },
      {
        "n": "AUDIO_SERVICES",
        "k": "component"
      },
      {
        "n": "BAUD_RATES",
        "k": "component"
      },
      {
        "n": "CAPABILITY_RE",
        "k": "component"
      },
      {
        "n": "CHANNEL_TYPES",
        "k": "component"
      },
      {
        "n": "CHANNELS_PER_MUX",
        "k": "component"
      },
      {
        "n": "CODE_ALIASES",
        "k": "component"
      },
      {
        "n": "DEFAULT_DEADLINE_MS",
        "k": "component"
      },
      {
        "n": "DEFAULT_ENTRY_LIMIT",
        "k": "component"
      },
      {
        "n": "DEFAULT_LIMITS",
        "k": "component"
      },
      {
        "n": "DEFAULT_MAX_DEPTH",
        "k": "component"
      },
      {
        "n": "DRIVE_KINDS",
        "k": "component"
      },
      {
        "n": "EEPROM_WRITING",
        "k": "component"
      },
      {
        "n": "EMPTY_CODE",
        "k": "component"
      },
      {
        "n": "EMPTY_LAYOUT",
        "k": "component"
      },
      {
        "n": "FALLBACK_MS",
        "k": "component"
      },
      {
        "n": "IDLE_MS",
        "k": "component"
      },
      {
        "n": "IS_MAC",
        "k": "component"
      },
      {
        "n": "IS_WIN",
        "k": "component"
      },
      {
        "n": "MAX_LINE_BYTES",
        "k": "component"
      },
      {
        "n": "MQTT_INSTALL_HINT",
        "k": "component"
      },
      {
        "n": "MUX_COUNT",
        "k": "component"
      },
      {
        "n": "OFFLINE_MS",
        "k": "component"
      },
      {
        "n": "OUTPUTS",
        "k": "component"
      },
      {
        "n": "OVERFLOW_MODES",
        "k": "component"
      },
      {
        "n": "PROBE_PORTS",
        "k": "component"
      },
      {
        "n": "PROBE_TIMEOUT_MS",
        "k": "component"
      },
      {
        "n": "RAW_MAX",
        "k": "component"
      },
      {
        "n": "RAW_MIN",
        "k": "component"
      },
      {
        "n": "RULE_SAFE",
        "k": "component"
      },
      {
        "n": "SEMANTIC_TYPES",
        "k": "component"
      },
      {
        "n": "SIDES",
        "k": "component"
      },
      {
        "n": "SSDP_AUDIO_TARGETS",
        "k": "component"
      },
      {
        "n": "STATES",
        "k": "component"
      },
      {
        "n": "TRANSPORTS",
        "k": "component"
      },
      {
        "n": "useMediaDevices",
        "k": "hook"
      },
      {
        "n": "useMicLevel",
        "k": "hook"
      },
      {
        "n": "adapterThroughput",
        "k": "helper"
      },
      {
        "n": "applyCalibration",
        "k": "helper"
      },
      {
        "n": "arpNeighbours",
        "k": "helper"
      },
      {
        "n": "bleDriver",
        "k": "helper"
      },
      {
        "n": "buildSizeTree",
        "k": "helper"
      },
      {
        "n": "capabilitiesFromLayout",
        "k": "helper"
      },
      {
        "n": "capabilityId",
        "k": "helper"
      },
      {
        "n": "captureFrame",
        "k": "helper"
      },
      {
        "n": "captureFrameToBlob",
        "k": "helper"
      },
      {
        "n": "channelsOf",
        "k": "helper"
      },
      {
        "n": "convertTemperature",
        "k": "helper"
      },
      {
        "n": "createDeviceRegistry",
        "k": "helper"
      },
      {
        "n": "createGroboticsSession",
        "k": "helper"
      },
      {
        "n": "createGroboticsWsListener",
        "k": "helper"
      },
      {
        "n": "createLineSplitter",
        "k": "helper"
      },
      {
        "n": "createRecorder",
        "k": "helper"
      },
      {
        "n": "decodeFrame",
        "k": "helper"
      },
      {
        "n": "decodeLine",
        "k": "helper"
      },
      {
        "n": "decodeReading",
        "k": "helper"
      },
      {
        "n": "defineDeviceDriver",
        "k": "helper"
      },
      {
        "n": "defineDeviceProvider",
        "k": "helper"
      },
      {
        "n": "describeBrowserCameraError",
        "k": "helper"
      },
      {
        "n": "describeBrowserMicError",
        "k": "helper"
      },
      {
        "n": "describeMediaError",
        "k": "helper"
      },
      {
        "n": "describeScreenShareError",
        "k": "helper"
      },
      {
        "n": "diffLayouts",
        "k": "helper"
      },
      {
        "n": "discover",
        "k": "helper"
      },
      {
        "n": "downloadBlob",
        "k": "helper"
      },
      {
        "n": "encodeQuery",
        "k": "helper"
      },
      {
        "n": "fakeClock",
        "k": "helper"
      },
      {
        "n": "fromLegacySetup",
        "k": "helper"
      },
      {
        "n": "getBrowserDriver",
        "k": "helper"
      },
      {
        "n": "getConfig",
        "k": "helper"
      },
      {
        "n": "getMediaError",
        "k": "helper"
      },
      {
        "n": "getMediaState",
        "k": "helper"
      },
      {
        "n": "goodbyeInstances",
        "k": "helper"
      },
      {
        "n": "groboticsSerialDriver",
        "k": "helper"
      },
      {
        "n": "hasWebBluetooth",
        "k": "helper"
      },
      {
        "n": "hasWebHid",
        "k": "helper"
      },
      {
        "n": "hasWebSerial",
        "k": "helper"
      },
      {
        "n": "isChromium",
        "k": "helper"
      },
      {
        "n": "isPresent",
        "k": "helper"
      },
      {
        "n": "isPrivateIpv4",
        "k": "helper"
      },
      {
        "n": "isRandomizedMac",
        "k": "helper"
      },
      {
        "n": "isRecordingSupported",
        "k": "helper"
      },
      {
        "n": "isScreenShareSupported",
        "k": "helper"
      },
      {
        "n": "isSecure",
        "k": "helper"
      },
      {
        "n": "killPort",
        "k": "helper"
      },
      {
        "n": "labelDrift",
        "k": "helper"
      },
      {
        "n": "layoutHash",
        "k": "helper"
      },
      {
        "n": "layoutWarnings",
        "k": "helper"
      },
      {
        "n": "listAdapters",
        "k": "helper"
      },
      {
        "n": "listAudioInputsAsync",
        "k": "helper"
      },
      {
        "n": "listAudioOutputs",
        "k": "helper"
      },
      {
        "n": "listAudioOutputsAsync",
        "k": "helper"
      },
      {
        "n": "listBrowserDrivers",
        "k": "helper"
      },
      {
        "n": "listCameraDevices",
        "k": "helper"
      },
      {
        "n": "listMicDevices",
        "k": "helper"
      },
      {
        "n": "listPorts",
        "k": "helper"
      },
      {
        "n": "listVolumes",
        "k": "helper"
      },
      {
        "n": "localSubnets",
        "k": "helper"
      },
      {
        "n": "mapRawToPercent",
        "k": "helper"
      },
      {
        "n": "mdnsListen",
        "k": "helper"
      },
      {
        "n": "mdnsProbe",
        "k": "helper"
      },
      {
        "n": "mockTransport",
        "k": "helper"
      },
      {
        "n": "mqttDriver",
        "k": "helper"
      },
      {
        "n": "networkSnapshot",
        "k": "helper"
      },
      {
        "n": "normalizeDevice",
        "k": "helper"
      },
      {
        "n": "normalizeLayout",
        "k": "helper"
      },
      {
        "n": "normalizeLayouts",
        "k": "helper"
      },
      {
        "n": "normalizeReading",
        "k": "helper"
      },
      {
        "n": "onMediaState",
        "k": "helper"
      },
      {
        "n": "ouiVendor",
        "k": "helper"
      },
      {
        "n": "pairedBluetooth",
        "k": "helper"
      },
      {
        "n": "pairedBluetoothAsync",
        "k": "helper"
      },
      {
        "n": "parseAnswers",
        "k": "helper"
      },
      {
        "n": "parseCapabilityId",
        "k": "helper"
      },
      {
        "n": "parsePactl",
        "k": "helper"
      },
      {
        "n": "pauseStream",
        "k": "helper"
      },
      {
        "n": "pidsOnPort",
        "k": "helper"
      },
      {
        "n": "ping",
        "k": "helper"
      },
      {
        "n": "platformWarnings",
        "k": "helper"
      },
      {
        "n": "presenceOf",
        "k": "helper"
      },
      {
        "n": "previouslyPermittedBluetooth",
        "k": "helper"
      },
      {
        "n": "psJson",
        "k": "helper"
      },
      {
        "n": "rawToMilliCelsius",
        "k": "helper"
      },
      {
        "n": "readCharacteristic",
        "k": "helper"
      },
      {
        "n": "readName",
        "k": "helper"
      },
      {
        "n": "registerBrowserDriver",
        "k": "helper"
      },
      {
        "n": "requestMedia",
        "k": "helper"
      },
      {
        "n": "retryMedia",
        "k": "helper"
      },
      {
        "n": "routeInfo",
        "k": "helper"
      },
      {
        "n": "run",
        "k": "helper"
      },
      {
        "n": "sanitizeDevice",
        "k": "helper"
      },
      {
        "n": "saveThresholds",
        "k": "helper"
      },
      {
        "n": "scaleReading",
        "k": "helper"
      },
      {
        "n": "scan",
        "k": "helper"
      },
      {
        "n": "sendIr",
        "k": "helper"
      },
      {
        "n": "serialDriver",
        "k": "helper"
      },
      {
        "n": "serialTransport",
        "k": "helper"
      },
      {
        "n": "setConfig",
        "k": "helper"
      },
      {
        "n": "setOutput",
        "k": "helper"
      },
      {
        "n": "setThreshold",
        "k": "helper"
      },
      {
        "n": "shapeBluetooth",
        "k": "helper"
      },
      {
        "n": "shapeWindows",
        "k": "helper"
      },
      {
        "n": "shouldIgnore",
        "k": "helper"
      },
      {
        "n": "spawnAsync",
        "k": "helper"
      },
      {
        "n": "ssdpListen",
        "k": "helper"
      },
      {
        "n": "ssdpProbe",
        "k": "helper"
      },
      {
        "n": "stamp",
        "k": "helper"
      },
      {
        "n": "startBrowserCamera",
        "k": "helper"
      },
      {
        "n": "startBrowserMic",
        "k": "helper"
      },
      {
        "n": "startRecording",
        "k": "helper"
      },
      {
        "n": "startScreenShare",
        "k": "helper"
      },
      {
        "n": "stopBrowserCamera",
        "k": "helper"
      },
      {
        "n": "stopBrowserMic",
        "k": "helper"
      },
      {
        "n": "stopScreenShare",
        "k": "helper"
      },
      {
        "n": "stopStream",
        "k": "helper"
      },
      {
        "n": "stream",
        "k": "helper"
      },
      {
        "n": "supportsCanvasFilter",
        "k": "helper"
      },
      {
        "n": "topicMatches",
        "k": "helper"
      },
      {
        "n": "typeForCode",
        "k": "helper"
      },
      {
        "n": "typeForSemantic",
        "k": "helper"
      },
      {
        "n": "typeForWire",
        "k": "helper"
      },
      {
        "n": "unavailableReason",
        "k": "helper"
      },
      {
        "n": "watchAudioDevices",
        "k": "helper"
      },
      {
        "n": "windowsLabel",
        "k": "helper"
      },
      {
        "n": "wirelessStatus",
        "k": "helper"
      },
      {
        "n": "writesEeprom",
        "k": "helper"
      }
    ]
  }
}
