Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How should (Android) / Chrome getUserMedia() constraints be formatted?

I've been trying to access the rear camera on an LG G4 Android phone running Chrome. I'm able to filter out the video sources from MediaStreamTrack.getSources(), but when I try to set a constraint to prefer the rear camera, I get the error TypeError: Failed to execute 'webkitGetUserMedia' on 'Navigator': Malformed constraints object. Below I have the code I'm using to filter the video sources:

if (navigator.getUserMedia) {
  if (MediaStreamTrack.getSources) {
    MediaStreamTrack.getSources(function(sourceInfos) {
      var sources = [];
      _.forEach(sourceInfos, function(info) {
        if (info.kind === 'video') {
          sources.push(info);
        }              
      })
      handleSources(sources);
    })
  }
}

Then I'm trying to select a source in the handleSources function mentioned above:

function handleSources(sources) {
  var constraints = {
    video: {
      facingMode: 'environment' // Yeah, this definitely doesn't work.
    }
  }
  getMedia(constraints); // This calls getUserMedia with the selected contraints
}

I've tried tons of different formats for the constraints object, but none of them seem to work. I know I'd be able to loop through all the sources and select the environmental camera from there, but I'd love to know how the actual syntax for this works. Googling for the answer only brings up https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia#Parameters, the syntax of which doesn't work.

like image 480
Fissio Avatar asked Feb 09 '23 02:02

Fissio


1 Answers

It would appear as though earlier/different versions of the Android browser implement a different API for camera discovery. I have found that each phone I have access to (emulator and physical) seems to respect a different set of options. To make matters worse this seems to be an area where various documentation repositories insist on ignoring or removing the previously implemented APIs (even though we still need to know how to use them if we are going to be able to implement on anything but the newest phones).

The two major flavors of the API that I have found are the one that's currently documented (you refer to that API above) and one that was documented in a version of the WebRTC specification from October 2013. That flavor has a significantly different constraints specification that includes mandatory and optional properties. Your call above to getMedia would look like this under the older specification:

var constraints = {
  video: {
    mandatory: {
      facingMode: 'environment'
    }
  }
}
getMedia(constraints);

Alternately, you can use optional settings, which are provided as an array instead so you can have multiple choices (these are evaluated in order):

var constraints = {
  video: {
    optional: [{
      facingMode: 'environment'
    }]
  }
}
getMedia(constraints);

That having been said, your mileage may vary when it comes to finding filters that work. For example, the facingMode filter above does not function in my Android 5.0 emulator (it doesn't throw an error but it also doesn't present the environment-facing camera); however, using a device ID does work (which looks like this when mapped to your example):

var constraints = {
  video: {
    mandatory: {
      sourceId: '<your source ID here>'
    }
  }
}
getMedia(constraints);

In the case of the Android 5.0 emulated device that I have done some testing with I am able to use MediaStreamTrack.getSources() to find the device I want (it returns the facing property with each camera). Note that the "recommended" replacement method navigator.mediaDevices.enumerateDevices() method is not present in this emulated device.

There are numerous other issues that you will see when using different emulated and physical devices, each of which has been quite problematic for me when implementing these APIs in the real world. I highly recommend using a combination of multiple physical devices (if you are in a work environment where you can get access to them), BrowserStack (to give you lots of real and emulated devices to test on), console.log(), and Vorlon.js (to view the console.log() output in real-time from all those emulated devices so you can see what's really going on).

I am currently working on this exact problem right now - if I find anything additional with respect to different API flavors that need supporting I will post an update here.

like image 197
Joe Friesenhan Avatar answered Feb 11 '23 01:02

Joe Friesenhan