Samir Paruthi
Samir Paruthi

Reputation: 121

How to check if my all promises are fulfilled

Currently I am writing a block of code. I want to start webcamera when video will start play and stop camera when video is paused but before loading camera I want to check if my all models are loaded or not. I want to load the model once until page refresh.thats totaly a seprate case that if user page refersh it will load again. Now if I click on play button in video it starts my camera. How can i configure it in a way where if user pause the button it only disable the camera and press play button it only load the camera (not load my models again).

    <html>
 <head>
     <title>Video detecting and emotion storing in database</title>
     <script type="text/css" defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"></script>
     <script type="text/css" src="style.css"></script>
     <script defer type="text/javascript" src="script/face-api.min.js"></script>
     <script defer type="text/javascript" src="script/script.js"></script>
     <style>
         #livecam{
             height: 400px;
             width: 600px;
             float: right;

         }
     </style>
 </head>
 <body>
    <div class="container">
            <video id="myvideo" src="laravel.mp4" controls height="400" width="600" >
            </video>

        <video id="livecam" autoplay muted height="400" width="600" ></video>
    </div>
 </body>
 </html>

..................................... Index.php

now my script.js

   var video = document.getElementById('myvideo');
const liveview = document.getElementById('livecam');
const height = 400;
const width = 600;


Promise.all([
    faceapi.nets.tinyFaceDetector.loadFromUri('/models'),
    faceapi.nets.faceLandmark68Net.loadFromUri('/models'),
    faceapi.nets.faceRecognitionNet.loadFromUri('/models'),
    faceapi.nets.faceExpressionNet.loadFromUri('/models')
])

video.onplaying = function(){
    enablewebcam();
    alert("Video is playing");
};

video.onpause = function(){
    disablecam();
}
function enablewebcam(){
    navigator.mediaDevices.getUserMedia({video:{width:600, height:400},
        audio:false}).then((stream) => {
        liveview.srcObject = stream;
    })
};


function disablecam(){
    liveview.srcObject = null;
}

Upvotes: 1

Views: 1235

Answers (4)

traktor
traktor

Reputation: 19386

To make sure the models have loaded when the user clicks play, delay adding the controls attribute until after the models have been fetched.

If you do this in a then handler of the Promise.all call, you can add event listeners to the video element to start and stop the video in the same place - the user can then start and stop the video at will. You may want to get rid of the alert message` however.

The snippet has been cut down for testing but unfortunately does not work on Stack overflow:

"use strict";
var video = document.getElementById('myvideo');
const liveview = document.getElementById('livecam');
const height = 400;
const width = 600;

Promise.all([
 // production
   // faceapi.nets.tinyFaceDetector.loadFromUri('/models'),
   // faceapi.nets.faceLandmark68Net.loadFromUri('/models'),
   // faceapi.nets.faceRecognitionNet.loadFromUri('/models'),
   // faceapi.nets.faceExpressionNet.loadFromUri('/models')
 // testing
   Promise.resolve(true),
   Promise.resolve(true),
   Promise.resolve(true),
   Promise.resolve(true)
])

.then( ()=> {
    video.onplaying = function(){
        enablewebcam();
        alert("Video is playing");
    };
    video.onpause = function(){
        disablecam();
    }
    // show video controls:
    video.setAttribute("controls", "");

    function enablewebcam(){
          navigator.mediaDevices.getUserMedia({video:{width:600, height:400},
            audio:false})
          .then((stream) => {
            liveview.srcObject = stream;
          })
          .catch( err => { 
            console.log("no cam, ", err.message)
          });
      };

    function disablecam(){
        liveview.srcObject = null;
    }

})
.catch(err => {
    console.log(err);
    alert("Something went wrong");
});
video { border: thin solid blue}
<div class="container">
    <video id="myvideo"
     src="https://i.imgur.com/LTc02xw_lq.mp4"
     height="400" width="600">
    </video>
    <video id="livecam" autoplay muted height="400" width="600" ></video>
</div>

Upvotes: 1

Ritik Banger
Ritik Banger

Reputation: 2768

To check if your models have already been loaded before enabling the webcam, you can use a flag variable that is set to true after the models are loaded. Then, in your enablewebcam function, you can check the value of this flag before enabling the webcam:

let modelsLoaded = false;

Promise.all([
  faceapi.nets.tinyFaceDetector.loadFromUri('/models'),
  faceapi.nets.faceLandmark68Net.loadFromUri('/models'),
  faceapi.nets.faceRecognitionNet.loadFromUri('/models'),
  faceapi.nets.faceExpressionNet.loadFromUri('/models')
]).then(() => {
  modelsLoaded = true;
});

function enablewebcam() {
  if (modelsLoaded) {
    navigator.mediaDevices.getUserMedia({ video: { width: 600, height: 400 }, audio: false }).then((stream) => {
      liveview.srcObject = stream;
    });
  }
}

Alternatively, you can use the faceapi.nets.tinyFaceDetector.isLoaded() function to check if the tinyFaceDetector model has been loaded. If it has, you can assume that all the models have been loaded, since they are all being loaded in the same Promise.all block.

function enablewebcam() {
  if (faceapi.nets.tinyFaceDetector.isLoaded()) {
    navigator.mediaDevices.getUserMedia({ video: { width: 600, height: 400 }, audio: false }).then((stream) => {
      liveview.srcObject = stream;
    });
  }
}

Either way, you can use the video.onpause event to stop the webcam when the video is paused, as you have already done in your code.

Upvotes: 1

Samir Paruthi
Samir Paruthi

Reputation: 121

So I found the answer as Hint by Ritik

Setting a variable true after successfull loading of model and everytime before enabling the camera will check that variable if it true or false.

    Promise.all([
    faceapi.nets.tinyFaceDetector.loadFromUri('/mmodels'),
    faceapi.nets.faceLandmark68Net.loadFromUri('/models'),
    faceapi.nets.faceRecognitionNet.loadFromUri('/models'),
    faceapi.nets.faceExpressionNet.loadFromUri('/models')
]).then(function(){
    modeloadedstatus = true;
})

checking modeloadedstatus before everytime enabling camera

 video.onplaying = function(){
    if(modeloadedstatus) {
        enablewebcam();
        console.log(modeloadedstatus)
        alert("Video is playing");
    } else{
        alert("Error in model loading");
    }
    };

Upvotes: 0

lazlomeli
lazlomeli

Reputation: 61

You can create an array of promises because the Promise class has an all method that receives an array of promises and returns the result once they are all fullfilled. If you think that one of the promises could fail, you should instead use allSettled because the all method returns Pending if one of the promises fails.

The allSettled method will return the promises data with a status and a value field. status giving you fullfilled or rejected and value giving you the promise data.

An example of this would be:

// Your array of promises
promises = [
...
]

// 'all' method
Promises.all(promises)
.then(data => console.log(data))

// 'allSettled' method
Promises.allSettled(promises)
.then(data => console.log(data))

Upvotes: 0

Related Questions