UNPKG

@solid-primitives/devices

Version:
142 lines (141 loc) 5.22 kB
import { createMemo, createSignal, getOwner, onCleanup } from "solid-js"; import { isServer } from "solid-js/web"; import { createStore } from "solid-js/store"; /** * Creates a list of all media devices * * @returns () => MediaDeviceInfo[] * * If the permissions to use the media devices are not granted, you'll get a single device of that kind with empty ids and label to show that devices are available at all. * * If the array does not contain a device of a certain kind, you cannot get permissions, as requesting permissions requires requesting a stream on any device of the kind. */ export const createDevices = () => { if (isServer) { return () => []; } const [devices, setDevices] = createSignal([]); const enumerate = () => { navigator.mediaDevices.enumerateDevices().then(setDevices); }; enumerate(); navigator.mediaDevices.addEventListener("devicechange", enumerate); onCleanup(() => navigator.mediaDevices.removeEventListener("devicechange", enumerate)); return devices; }; const equalDeviceLists = (prev, next) => prev.length === next.length && prev.every(device => next.includes(device)); /** * Creates a list of all media devices that are microphones * * @returns () => MediaDeviceInfo[] * * If the microphone permissions are not granted, you'll get a single device with empty ids and label to show that devices are available at all. * * Without a device, you cannot get permissions, as requesting permissions requires requesting a stream on any device of the kind. */ export const createMicrophones = () => { if (isServer) { return () => []; } const devices = createDevices(); return createMemo(() => devices().filter(device => device.kind === "audioinput"), [], { name: "microphones", equals: equalDeviceLists, }); }; /** * Creates a list of all media devices that are speakers * * @returns () => MediaDeviceInfo[] * * If the speaker permissions are not granted, you'll get a single device with empty ids and label to show that devices are available at all. * * Microphone permissions automatically include speaker permissions. You can use the device id of the speaker to use the setSinkId-API of any audio tag. */ export const createSpeakers = () => { if (isServer) { return () => []; } const devices = createDevices(); return createMemo(() => devices().filter(device => device.kind === "audiooutput"), [], { name: "speakers", equals: equalDeviceLists, }); }; /** * Creates a list of all media devices that are cameras * * @returns () => MediaDeviceInfo[] * * If the camera permissions are not granted, you'll get a single device with empty ids and label to show that devices are available at all. * * Without a device, you cannot get permissions, as requesting permissions requires requesting a stream on any device of the kind. */ export const createCameras = () => { if (isServer) { return () => []; } const devices = createDevices(); return createMemo(() => devices().filter(device => device.kind === "videoinput"), [], { name: "cameras", equals: equalDeviceLists, }); }; /** * Creates a reactive wrapper to get device acceleration * @param includeGravity boolean. default value false * @param interval number as ms. default value 100 * @returnValue Acceleration: Accessor<DeviceMotionEventAcceleration | undefined> */ export const createAccelerometer = (includeGravity = false, interval = 100) => { if (isServer) { return () => ({ x: 0, y: 0, z: 0, }); } const [acceleration, setAcceleration] = createSignal(); let throttled = false; const accelerationEvent = (e) => { if (throttled) return; throttled = true; setTimeout(() => { throttled = false; }, interval); const acceleration = includeGravity ? e.accelerationIncludingGravity : e.acceleration; setAcceleration(acceleration ? acceleration : undefined); }; addEventListener("devicemotion", accelerationEvent); getOwner() && onCleanup(() => removeEventListener("devicemotion", accelerationEvent)); return acceleration; }; /** * Creates a reactive wrapper to get device orientation * @param interval number as ms. default value 100 * @returnValue { alpha: 0, beta: 0, gamma: 0 } */ export const createGyroscope = (interval = 100) => { if (isServer) { return { alpha: 0, beta: 0, gamma: 0 }; } const [orientation, setOrientation] = createStore({ alpha: 0, beta: 0, gamma: 0 }); let throttled = false; const orientationEvent = (e) => { if (throttled) return; throttled = true; setTimeout(() => { throttled = false; }, interval); setOrientation({ alpha: e.alpha ? e.alpha : 0, beta: e.beta ? e.beta : 0, gamma: e.gamma ? e.gamma : 0, }); }; addEventListener("deviceorientation", orientationEvent); getOwner() && onCleanup(() => removeEventListener("deviceorientation", orientationEvent)); return orientation; };