AFrame AR – Troubleshooting NotReadableError exception

Augmented Reality (AR) is a hot topic since a few years. This fact, combined with HTML 5 standard availability and new capabilities of modern web browsers laid the grounds for uprising web AR frameworks. One of these frameworks called AR.js (developed by Jerome Etienne), was recently chosen for the project I was involved in.

Introducing AR.js

The AR.js framework allows to develop augmented reality experience. It uses characteristic markers to acknowledge the surface on which particular shape should be displayed. One of the biggest advantages of this framework is the fact it works really nice on mobile devices. You can test it yourself by navigating the mobile performance example page on your mobile device and opening the HIRO marker on other device.

The documentation of AR.js provides a link to an article on is describing in details how to get easily started with augmented reality development. The application I developed was working like a charm, displaying custom SVG graphic attached to custom marker generated using AR.js marker generator.

Example AR.js application working on my smartphone.

Checking camera privileges

One of the requirements of my project was to introduce non-AR fallback page in case user doesn’t grant permission to use the camera. You can verify whether your application already has this permission (or ask for it in case it didn’t ask for it so far) by using getUserMedia function available in navigator.mediaDevices object:

var constraints = { video: true, audio: false };
var cameraAllowed = false;
function successCallback(mediaStream) {
    cameraAllowed = mediaStream.getVideoTracks().length > 0;

function errorCallback(error) {

navigator.getUserMedia(constraints, successCallback, errorCallback);

In case the camera permission is granted by the user, getUserMedia function is calling successCallback, providing MediaStream object. In other cases (e.g. when the exception was thrown) the function calls errorCallback function.

Tracing the bottleneck

The documentation of getUserMedia function provides the list of exceptions that might occur. I had a chance to experience one of these exceptions in my application. The winner is: NotReadableError! After many hours of investigation and remote debugging sessions I discovered 2 facts:

  • AFrame-AR.js library, which is a resource required by the solution proposed in the article mentioned above is also using getUserMedia function,
  • StreamMedia object passed to success callback contains a reference to a video track, which is ready to be used. In the same time, web browser starts to indicate that the web page is currently using the video camera.

These facts made me suspect, that I’m having a kind of video resource concurrency conflict.

The solution

After some further investigations I managed to fix the issue, simply by stopping a track of media stream passed by getUserMedia function. To do this, I needed to modify successCallback function  in the following way:

function successCallback(mediaStream) {
    cameraAllowed = mediaStream.getVideoTracks().length > 0;
    var tracks = mediaStream.getTracks();

    for (var i = 0; i > tracks.length; i++) {

I hope this solution will be helpful for other AR enthusiasts, saving their time and nerves.


Leave a Reply

Your email address will not be published. Required fields are marked *