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.
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.
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.missingMedia
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.
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:
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.
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
orstart_audio_off
properties totrue
at the room or the token level. - Call
getUserMedia()
before usingdaily-js
to access participants' media streams. - Pass the streams to Daily. This can be done either via
join()
, using theaudioSource
andvideoSource
properties, or after join throughsetInputDevicesAsync()
.
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.