Handling device permissions

Accessing media input devices cams, mics, and screens can involve many and sometimes conflicting permissions layers. Browsers, operating systems, devices, and participants are all factors that can complicate whether audio or video is shared or hidden as desired.

This guide walks through common media device errors and how to help call participants resolve them, and then covers general best practices for handling media devices.

Common media device errors

Daily accesses participant media input devices through the MediaDevices interface.

The interface's getUserMedia() method prompts the user for device permissions. It then creates a MediaStream with the corresponding tracks if permission is granted.

If something goes wrong, the browser throws an exception, and Daily emits a "camera-error" event. Browsers are inconsistent in their implementations of these exceptions for any given root issue. For example, if there is no camera plugged in, Chrome and Firefox will throw a NotFoundError, but Safari will throw an OverconstrainedError. For this reason, we handle these inconsistencies for you and categorize the errors into basic types to ensure that the same issue will generate the same error no matter which browser or OS the user is on. The most common device errors are detailed below and include recommendations for how to handle each type of error. For full details about all the categories of device errors, see the "camera-error" reference.

Feel free to borrow from our template help material when writing prompts to help participants solve these issues.

Device in use

This is most common on Windows when another app is using the participant's camera.

The Daily camera-error event object's error.type value will specify one of the following: cam-in-use, mic-in-use, or cam-mic-in-use. For example:

To handle this error, alert participants that another application is using their device. Daily Prebuilt, for example, instructs participants to quit the other application and reload the Daily call.

Prompt in a video call asks participant to restart an application

Permissions denied

This happens when the call is not granted permissions to access the user's media device. Either a participant has denied access (e.g. clicked "Block" in the permissions pop-up) or the browser itself has not been granted access in the OS settings. This is one of the most common getUserMedia() errors.

The Daily "camera-error" event object's error.type value will be set to 'permissions'. Whether the permissions were blocked by a user action or due to OS level permissions will be specified in the error.blockedBy field. There is also an error.blockedMedia field to indicate which media is blocked due to permissions. For example:

Whether the participant denied access on purpose or by accident, it is important that the call UI reflects that the device is blocked. In Daily Prebuilt, the media icons are displayed in red with the text "Allow" underneath. When clicked, the participant sees instructions for how to unblock their devices.

Video call displays a prompt that instructs a participant how to unblock their camera

How to unblock a device can depend on the device's manufacturer and the browser that the participant is using. On some devices, such as iOS, a page refresh is enough to re-trigger the browser prompt asking for device access. On other devices, such as some Android phones, participants may need to go into their device's settings to allow camera and microphone permissions. Testing on multiple devices and browsers is recommended.

No available devices

If the browser can't find any input devices for a given type of media, the Daily "camera-error" event object's error.type value will be "not-found". It will also include an error.missingDevices field detailing which devices were not found. For example:

Prompting the participants to check their devices and reload the call can help solve this issue; that is how Daily Prebuilt handles it.

Video call displays prompt to participant to check their input devices

Best practices for handling media devices

Prompt for all device permissions at once

It is critical to ask call participants for microphone and camera access at the same time. These device permissions are closely related at a low level in daily-js. Blocking one can unintentionally block the other. Prompting for both cam and mic permissions simultaneously not only prevents this error, but also is a better user experience because participants only have to answer one prompt.

Adjust instructions according to browser and device

Device manufacturers and browsers don't always handle device permissions in the same way. For example, allowing device access after the browser has thrown a permissions error can differ per OS, device, and browser. For the best user experience, the call UI should reflect how to handle the error given the participant's device and browser. Daily Prebuilt, for example, shows a different access prompt on iOS and Android after a permissions error:

Granting access prompt on iOS and Android after a NotAllowedError

You can use user agent detection to display information based on the user's device. At Daily, we use ua-parser-js to detect the user's browser and OS, so we can adjust our messaging accordingly.

Create a space for participants to set up devices before joining a call

A test call page, lobby, "green room" or a space by any other name where participants can set up their devices before joining a call provides a safe space for callers to read all prompts, accept or deny them, and configure their devices without the pressure of being live in a call. This also gives them the chance to resolve any unintended mistakes before entering the call.

To enable Daily Prebuilt's prejoin UI, set the enable_prejoin_ui property to true at either the room or the domain level. This can be done either through an API request, or from the "Create room" page of the Daily dashboard.

Lobby interface of Daily Prebuilt call prompts a participant to set up camera and mic

There are lots of ways to go about building a lobby in a custom application. The startCamera() method is a good place to start.

How to start calls with mic access only

By default, daily-js assumes that calls start with microphones and cameras turned on, and automatically asks for permissions to both.

If a participant blocks the request, the event emitter fires a camera-error event. Access to both devices is denied, so for the duration of the session, neither the microphone nor the camera will be accessible. This might not be what a participant wants. They might want to join the call with audio-only access (granting microphone permissions), for example, but block the camera entirely. To enable a participant to join a call with mic access granted but camera blocked:

  • Turn off Daily's default automatic permissions request by setting the start_video_off or start_audio_off properties to true at the room or the token level.
  • Call getUserMedia() before using daily-js to access participants' media streams.
  • Pass the streams to Daily. This can be done either via join(), using the audioSource and videoSource properties, or after join through setInputDevicesAsync().

iOS development and device permissions

Media device permission requests are async when using AVFoundation, Apple's audiovisual framework. The completion handler for these requests is called on arbitrary dispatch queue.

These permissions should never be blocked, as that can lead to deadlocks. An API that was intended to be synchronous and blocking may have to be changed to be async with a callback block when adapted for iOS.