Skip to content

⬅️ Back to Table of Contents

📄 useDevicesList

📊 Analysis Summary

Metric Count
🔧 Functions 3
📦 Imports 10
⚡ Async/Await Patterns 3
🟢 Vue Composition API 3
📐 Interfaces 2

📚 Table of Contents

🛠️ File Location:

📂 packages/core/useDevicesList/index.ts

📦 Imports

Name Source
ComputedRef vue
ShallowRef vue
ConfigurableNavigator ../_configurable
Supportable ../types
computed vue
shallowRef vue
defaultNavigator ../_configurable
useEventListener ../useEventListener
usePermission ../usePermission
useSupported ../useSupported

Async/Await Patterns

Type Function Await Expressions Promise Chains
await-expression useDevicesList navigator!.mediaDevices.enumerateDevices(), query(), navigator!.mediaDevices.... none
async-function update navigator!.mediaDevices.enumerateDevices() none
async-function ensurePermissions query(), navigator!.mediaDevices.enumerateDevices(), navigator!.mediaDevices.... none

Vue Composition API

Name Type Reactive Variables Composables
computed computed none none
computed computed none none
computed computed none none

Functions

useDevicesList(options: UseDevicesListOptions): UseDevicesListReturn

Reactive enumerateDevices listing available input/output devices

Parameters:

  • options any: No description

See: https://vueuse.org/useDevicesList

Raw JSDoc
/**
 * Reactive `enumerateDevices` listing available input/output devices
 *
 * @see https://vueuse.org/useDevicesList
 * @param options
 */

Calls:

  • shallowRef (from vue)
  • computed (from vue)
  • devices.value.filter
  • useSupported (from ../useSupported)
  • navigator!.mediaDevices.enumerateDevices
  • onUpdated
  • stream.getTracks().forEach
  • t.stop
  • usePermission (from ../usePermission)
  • query
  • allDevices.some
  • navigator!.mediaDevices.getUserMedia
  • update
  • ensurePermissions
  • useEventListener (from ../useEventListener)
Code
export function useDevicesList(options: UseDevicesListOptions = {}): UseDevicesListReturn {
  const {
    navigator = defaultNavigator,
    requestPermissions = false,
    constraints = { audio: true, video: true },
    onUpdated,
  } = options

  const devices = shallowRef<MediaDeviceInfo[]>([])
  const videoInputs = computed(() => devices.value.filter(i => i.kind === 'videoinput'))
  const audioInputs = computed(() => devices.value.filter(i => i.kind === 'audioinput'))
  const audioOutputs = computed(() => devices.value.filter(i => i.kind === 'audiooutput'))
  const isSupported = useSupported(() => navigator && navigator.mediaDevices && navigator.mediaDevices.enumerateDevices)
  const permissionGranted = shallowRef(false)
  let stream: MediaStream | null

  async function update() {
    if (!isSupported.value)
      return

    devices.value = await navigator!.mediaDevices.enumerateDevices()
    onUpdated?.(devices.value)
    if (stream) {
      stream.getTracks().forEach(t => t.stop())
      stream = null
    }
  }

  async function ensurePermissions() {
    const deviceName = constraints.video ? 'camera' : 'microphone'

    if (!isSupported.value)
      return false

    if (permissionGranted.value)
      return true

    const { state, query } = usePermission(deviceName, { controls: true })
    await query()
    if (state.value !== 'granted') {
      let granted = true
      try {
        const allDevices = await navigator!.mediaDevices.enumerateDevices()
        const hasCamera = allDevices.some(device => device.kind === 'videoinput')
        const hasMicrophone = allDevices.some(device => device.kind === 'audioinput' || device.kind === 'audiooutput')
        constraints.video = hasCamera ? constraints.video : false
        constraints.audio = hasMicrophone ? constraints.audio : false
        stream = await navigator!.mediaDevices.getUserMedia(constraints)
      }
      catch {
        stream = null
        granted = false
      }
      update()
      permissionGranted.value = granted
    }
    else {
      permissionGranted.value = true
    }

    return permissionGranted.value
  }

  if (isSupported.value) {
    if (requestPermissions)
      ensurePermissions()

    useEventListener(navigator!.mediaDevices, 'devicechange', update, { passive: true })
    update()
  }

  return {
    devices,
    ensurePermissions,
    permissionGranted,
    videoInputs,
    audioInputs,
    audioOutputs,
    isSupported,
  }
}

Internal helpers

Declared inside another function in this file.

update(): Promise<void>

Returns: Promise<void>

Calls:

  • navigator!.mediaDevices.enumerateDevices
  • onUpdated
  • stream.getTracks().forEach
  • t.stop
Code
async function update() {
    if (!isSupported.value)
      return

    devices.value = await navigator!.mediaDevices.enumerateDevices()
    onUpdated?.(devices.value)
    if (stream) {
      stream.getTracks().forEach(t => t.stop())
      stream = null
    }
  }

ensurePermissions(): Promise<any>

Returns: Promise<any>

Calls:

  • usePermission (from ../usePermission)
  • query
  • navigator!.mediaDevices.enumerateDevices
  • allDevices.some
  • navigator!.mediaDevices.getUserMedia
  • update
Code
async function ensurePermissions() {
    const deviceName = constraints.video ? 'camera' : 'microphone'

    if (!isSupported.value)
      return false

    if (permissionGranted.value)
      return true

    const { state, query } = usePermission(deviceName, { controls: true })
    await query()
    if (state.value !== 'granted') {
      let granted = true
      try {
        const allDevices = await navigator!.mediaDevices.enumerateDevices()
        const hasCamera = allDevices.some(device => device.kind === 'videoinput')
        const hasMicrophone = allDevices.some(device => device.kind === 'audioinput' || device.kind === 'audiooutput')
        constraints.video = hasCamera ? constraints.video : false
        constraints.audio = hasMicrophone ? constraints.audio : false
        stream = await navigator!.mediaDevices.getUserMedia(constraints)
      }
      catch {
        stream = null
        granted = false
      }
      update()
      permissionGranted.value = granted
    }
    else {
      permissionGranted.value = true
    }

    return permissionGranted.value
  }

Interfaces

UseDevicesListOptions

Interface Code
export interface UseDevicesListOptions extends ConfigurableNavigator {
  onUpdated?: (devices: MediaDeviceInfo[]) => void
  /**
   * Request for permissions immediately if it's not granted,
   * otherwise label and deviceIds could be empty
   *
   * @default false
   */
  requestPermissions?: boolean
  /**
   * Request for types of media permissions
   *
   * @default { audio: true, video: true }
   */
  constraints?: MediaStreamConstraints
}

Properties

Name Type Optional Description
onUpdated (devices: MediaDeviceInfo[]) => void not shown
requestPermissions boolean not shown
constraints MediaStreamConstraints not shown

UseDevicesListReturn

Interface Code
export interface UseDevicesListReturn extends Supportable {
  /**
   * All devices
   */
  devices: ShallowRef<MediaDeviceInfo[]>
  videoInputs: ComputedRef<MediaDeviceInfo[]>
  audioInputs: ComputedRef<MediaDeviceInfo[]>
  audioOutputs: ComputedRef<MediaDeviceInfo[]>
  permissionGranted: ShallowRef<boolean>
  ensurePermissions: () => Promise<boolean>
}

Properties

Name Type Optional Description
devices ShallowRef<MediaDeviceInfo[]> not shown
videoInputs ComputedRef<MediaDeviceInfo[]> not shown
audioInputs ComputedRef<MediaDeviceInfo[]> not shown
audioOutputs ComputedRef<MediaDeviceInfo[]> not shown
permissionGranted ShallowRef<boolean> not shown
ensurePermissions () => Promise<boolean> not shown

Generated by Syntax Scribe