0

I'm writing Webrtc chrome desktop app by accessing 2 camera simultaneously using latest Chrome Windows version.

Accessing camera list by navigator.mediaDevices.enumerateDevices() is ok but accessing these device by their specific id using navigator.mediaDevices.getUserMedia not work.

It only occurs sometimes. But no error in the catch.

So, I tried navigator.mediaDevices.getUserMedia is really exists or not.

if (navigator && navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { }

Yes, it was.

Just not getting any log info in calling navigator.mediaDevices.getUserMedia()

getVideoSources_ = function() {
    return new Promise(function(resolve, reject) {
        if (typeof navigator.mediaDevices.enumerateDevices === 'undefined') {
            alert('Your browser does not support navigator.mediaDevices.enumerateDevices, aborting.');
            reject(Error("Your browser does not support navigator.mediaDevices.enumerateDevices, aborting."));
            return;
        }

        requestVideoSetTimeout = 500;
        navigator.mediaDevices.enumerateDevices().then((devices) => {

            // get the list first by sorting mibunsho camera in first place
            for (var i = 0; i < devices.length; i++) {
                log("devices[i]", JSON.stringify(devices[i]));
                log("devices[i].label", devices[i].label);
                if (devices[i].kind === 'videoinput' && devices[i].deviceId && devices[i].label) {
                    if (devices[i].label.indexOf("USB_Camera") > -1) {
                        deviceList[1] = devices[i];
                    } else {
                        deviceList[0] = devices[i];
                    }
                }
            }

            // request video by sorted plan
            for (var i = 0; i < deviceList.length; i++) {
                requestVideo_(deviceList[i].deviceId, deviceList[i].label, resolve, reject);
                requestVideoSetTimeout = 1000; // change requestVideoSetTimeout for next video request
            }
        }).catch((err) => {
            log("getVideoSources_:" + err.name + ": " + err.message);
            reject(Error("getVideoSources_ catch error"));
        });
    });
}
getVideoSources_().then(function(result) {
    ....
}).catch(function(err) {
    ....
});

function requestVideo_(id, label, resolve, reject) {
    if (navigator && navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
        log("navigator.mediaDevices.getUserMedia found!");

        navigator.mediaDevices.getUserMedia({
            video: {
                deviceId: {exact: id},
                width: 640,
                height: 480,
                frameRate: {
                    ideal: 20,
                    max: 20
                }
            },
            audio: false}).then(
            (stream) => {
                log("***requestVideo_", id);
                log("***requestVideo_", label);
                log("***requestVideo_", stream);
          // USB_Camera is face camera
          if (label.indexOf("USB_Camera") > -1) {
            log("***requestVideo_001");
            myStream2 = stream;
            log("***requestVideo_myStream2", myStream2);
          } else {
            log("***requestVideo_002");
            myStream = stream;
            log("***requestVideo_myStream", myStream);
            getUserMediaOkCallback_(myStream, label);
          }
          resolve("###Video Stream got###");

          stream.getVideoTracks()[0].addEventListener('ended', function(){
            log("***Camera ended event fired. " + id + " " + label);
            endedDevice[id] = label;
          });
      },
      getUserMediaFailedCallback_
      ).catch((error) => {
        log('requestVideo_: ' + error.name);
        reject(Error("requestVideo_ catch error" + error.name));
      });
    }
}

function getUserMediaFailedCallback_(error) {
    log("getUserMediaFailedCallback_ error:", error.name);
    alert('User media request denied with error: ' + error.name);
}
jib
  • 40,579
  • 17
  • 100
  • 158
Thura Aung
  • 83
  • 1
  • 7
  • Where do you define `i`, `resolve`, `reject`, `log`? There are ReferenceError in your catch block too, so for us it's normal it won't log anything. And assuming all these are declared somewhere, if `i` is an integer, but the device at index `i` is not a videoinput, then your code won't do anything. – Kaiido Jan 16 '19 at 02:35
  • I'm sorry, for the sake of simplicity I just copied some of my working code, now I edited the code again. Yes some variables like `log` is defined in somewhere. Thank you. – Thura Aung Jan 16 '19 at 03:08
  • 1
    A promise can be resolved only once. Here you are passing both `resolve` and `reject` to `requestVideo_` in a loop. – Kaiido Jan 16 '19 at 03:10
  • Thank you. It could be a problem why there is no log sometimes. I will fix that first. – Thura Aung Jan 16 '19 at 04:57
  • @Kaiido is right. This is the [promise constructor anti-pattern](https://stackoverflow.com/questions/23803743/what-is-the-explicit-promise-construction-antipattern-and-how-do-i-avoid-it). In short: Don't write code inside promise constructors. Don't pass `resolve` and `reject` functions down. Instead, let functions return promises to you, and return them all so they form a chain. – jib Jan 16 '19 at 19:08

1 Answers1

3

@Kaiido is right, resolve is called in a for-loop here, which is all over the place, and before all the code has finished. Any error after this point is basically lost.

This is the promise constructor anti-pattern. In short: Don't write app code inside promise constructors. Don't pass resolve and reject functions down. Instead, let functions return promises up to you, and add all app code in then callbacks on them. Then return all promises so they form a single chain. Only then do errors propagate correctly.

See Using promises on MDN for more.

jib
  • 40,579
  • 17
  • 100
  • 158