Giter VIP home page Giter VIP logo

media-devices's Introduction

Media Devices

Easily manage media devices in the browser

Purpose

media-devices wraps the native browser API and tries to normalize as many cross-browser quirks as possible (reference). It also provides a device list diffing observer that notifies you as devices are added, removed, or updated.

API

The API is a carbon copy of navigator.mediaDevices, with the exception of ondevicechange which was replaced for more bells and whistles.

Here's the gist:

import MediaDevices from 'media-devices'

// List the available hardware
await MediaDevices.enumerateDevices()

// Get the user's camera & microphone
await MediaDevices.getUserMedia({ video: true, audio: true })

// Share your screen
await MediaDevices.getDisplayMedia()

// Listen for changes in available devices
MediaDevices.ondevicechange = ({ changes }) => {
  // [{ type: 'add', ... }, { type: 'update', ... }]
}

supportsMediaDevices()

Exported as a separate utility function, this helps determine if your browser supports the navigator.mediaDevices API. Be aware that some browsers only expose it on secure sites.

import { supportsMediaDevices } from 'media-devices'

if (supportsMediaDevices()) {
  // yey
}

ondevicechange

MediaDevices emits this event whenever the list of devices changes. It passes two things:

  1. A list of changes
  2. The full list of devices
MediaDevices.ondevicechange = ({ changes, devices }) => {
  // ...
}

The list of devices is exactly what you'd get from enumerateDevices(). The changes are a diff between this list and the last, showing which devices were added, which were removed, and which were updated.

[
  // A device was just plugged in.
  {
    type: 'add',
    device: DeviceInfo,
  },

  // A device was disconnected.
  {
    type: 'remove',
    device: DeviceInfo,
  },

  // The browser gave us more information about a device.
  {
    type: 'update',
    oldInfo: DeviceInfo,
    newInfo: DeviceInfo,
  },
]

Update events are odd. Browsers redact information until the user explicitly grants trust, so things like labels and device IDs might start off null. Another quirk regarding speakers may cause the device to update in-place.


Known Quirks

For the curious...

Duplicate Devices

Preferred devices are represented through list order: preferred devices are show up first. Chrome has a "feature" where preferred devices are duplicated in the list with a "default" device ID. You'll notice some meeting apps get confused this and list them twice in their device dropdowns. I can't find any sources or justified reasoning, and they're the only browser that does it.

Since that information is already available in list ordering, media-devices strips out the duplicates.

Redacted Device Names

Until the first approved getUserMedia(...) query, browsers assume you're not trusted enough to see the list of device names. That's fair. Device names are an easy target for user fingerprinting. They patched it by setting device.label to an empty string.

It works, but it can break certain UIs if they're not carefully checking for empty strings. media-devices makes this behavior explicit by setting the label to null.

This library updates the device list after a successful getUserMedia(...) query ensuring your device state is as accurate as possible.

Redacted Device IDs

According to the spec, device IDs are meant to persist until the user clears site data, which is a dream come true if you're one of those assholes writing fingerprinting software. Some browsers thwart those efforts by redacting the device ID until you've been approved a getUserMedia(...) request.

That makes it hard to tell whether the device list actually changed. This library handles the heavy lifting of fuzzy matching devices to determine if new ones were added, others were removed, or if you just got permission to see the real ID/label.

Device IDs are set to null in this case.

Missing Group IDs

As of Safari v14, even with permissions, the browser doesn't provide group IDs. Why? Because they're monsters.

Group IDs are null in Safari.

Hidden Devices

Chrome and Safari only show the first of each device type (mic, camera, speakers) until getUserMedia(...) is approved. Other options are hidden. If you have 10 cameras, you'll only see the first until you're authorized. Even then, Chrome only shows you cameras, microphones are still hidden.

While we can't work around it, we can automatically identify that old camera in the list of 10 and show the other 9 as added devices.

Speaker Replacement

There's a subtle difference between wired speakers vs bluetooth devices. It seems that by default, many computers list internal speakers as a single device (expected), but if you plug in an auxiliary jack, it swaps the label in-place and uses the same device ID (unexpected). So if you plug in headphones but you've also got speakers on your computer, it may only list one device.

Bluetooth behaves more as you'd expect. They are shown as distinct devices and you can switch between them.

Once again, there's not much this library can do. Just something to be aware of.

media-devices's People

Contributors

renovate[bot] avatar psychollama avatar renovate-bot avatar

Stargazers

 avatar Niranjan Anandkumar avatar Ludgie avatar  avatar CMDSYSTEM avatar aric avatar Mohamad Irfan avatar Roman avatar Bagus avatar Cleiber Rodrigues Reis avatar Davi da Costa avatar Danny van der Jagt avatar Tim Herby avatar Ben Ritchie avatar

Watchers

Lucian avatar James Cloos avatar  avatar  avatar

media-devices's Issues

Support missing group IDs in Safari

Safari has a quirk. What am I saying, Safari is a quirk. For whatever reason, they don't include group IDs on devices, even after permissioned requests.

I should make the field nullable to reflect that.

Dependency Dashboard

This issue provides visibility into Renovate updates and their statuses. Learn more

This repository currently has no open or pending branches.


  • Check this box to trigger a request for Renovate to run again on this repository

Pass full device list to change handler

In practice, I'm finding it tempting to call enumerateDevices() in the change handler to get the full list of devices. Obviously that's a bad idea. I should pass the full list of devices to the event handlers in addition to the changeset.

Avoid errors in unsupported environments

media-devices currently throws an error immediately after loading in an unsupported environment. You can observe this by importing from Node. Things should fail when you try to call methods, not when you import.

Export utility types

DeviceInfo deviates from MediaDeviceInfo by using null fields. The type should be exported. Same thing for DeviceChangeEvent.

Log errors and informative events

Add debugging logs at key points:

  • on load, indicate if the browser is supported.
  • getUserMedia(...)/getDisplayMedia(...) failed, show the error code.
  • enumerateDevices(...) failed, show the error message.
  • On change event, show stat summary of changes.

ES Module Error

Given this package.json:

{
  "type": "module",
  "dependencies": {
    "media-devices": "^0.4.0"
  }
}

And this index.js:

import MediaDevices from 'media-devices'

Running node index.js gives the following error:

Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
(Use `node --trace-warnings ...` to show where the warning was created)
/home/t/r88/proboscis/more/node_modules/media-devices/dist/media-devices.es.js:131
export { DeviceKind, OperationType, index as default, supportsMediaDevices };
^^^^^^

SyntaxError: Unexpected token 'export'
 (stack trace)
Node.js v20.8.0

Device cache is stale after querying display

Successfully querying the display unlocks protected device labels in Firefox 94.0.2 on macOS Monterey. I should automatically refresh the device list after the first successful getDisplayMedia(...) call.

Fall back to just audio or just video if simultaneous audio & video unavailable

I haven't tested that it's the case here, but in other libraries I've written, getting audio & video at the same time can result in people with just a mic on their device (or just a camera) being unable to participate.

I'll probably be playing around with media-devices a bit more here (nice lib!) but I just wanted to see if you'd considered this case already, or if you're looking for / would consider a PR.

Type error: 'oldDevice' is possibly 'undefined'.

Problem Description

While using the [email protected] package along with the MediaDevices.enumerateDevices method, I encountered a compilation error when attempting to build the project. Everything worked as expected during development, but upon trying to build the project, the following error was encountered:

./node_modules/.pnpm/[email protected]/node_modules/media-devices/src/device-manager.ts:149:33
Type error: 'oldDevice' is possibly 'undefined'.

Steps to Reproduce

  1. Installed the [email protected] package using pnpm.
  2. Used the MediaDevices.enumerateDevices method in my code.
  3. Upon attempting the build process, the aforementioned error was encountered.

Temporary Solution

To work around the error, I needed to adjust the TypeScript configuration in the tsconfig.json, by removing the strict option and setting noEmitOnError to false.

Additional Information

  • React Version: 18.2.0
  • media-devices Library Version: 0.4.0
  • Node.js Version: 20.10.0

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.