Turn on phone flashlight on web app using JavaScript and HTML

Viewed 1743

I would like to ask how to turn on a phone flashlight on a web app using JavaScript and HTML. I had created a web app that is able to scan QR codes using a phone camera. I had managed to turn on a phone camera, but I faced some difficulties regarding to turning on the phone flashlight on a different platform which is Android and iOS.

For Android OS, I had managed to turn on the phone camera on my web app, and was also able to turn on the phone flashlight right after the camera has been turned on. However, after I turned on the flashlight, closed the web app, and reopened it again, the flashlight wasn't working anymore.

For iOS, the camera seems to be turned on, but I can't view anything through the web app. Besides, the phone flashlight doesn't work as well.

My code:

HTML part

<!DOCTYPE html>
<html>
 <head>
  <title>HOME PAGE</title>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1" >
  <script src="https://rawgit.com/sitepoint-editors/jsqrcode/master/src/qr_packed.js"></script>
 </head>

 <body>
     <button class="switch"><i class="fa fa-lightbulb-o" id="flashlight-icon"></i>Flashlight</button>
        
     <canvas id="qr-canvas"></canvas>
      <div id="qr-result" hidden="">
        <b>Data:</b> <span id="outputData"></span>
      </div>

    <script src="src/torch.js"></script>  
    <script src="src/qrCodeScanner.js"></script>
  
 </body>
</html>

torch.js:

//Test browser support
const SUPPORTS_MEDIA_DEVICES = 'mediaDevices' in navigator;

if (SUPPORTS_MEDIA_DEVICES) {
  //Get the environment camera (usually the second one)
  navigator.mediaDevices.enumerateDevices().then(devices => {
  
    const cameras = devices.filter((device) => device.kind === 'videoinput');

    if (cameras.length === 0) {
      throw 'No camera found on this device.';
    }
    const camera = cameras[cameras.length - 1];

    // Create stream and get video track
    navigator.mediaDevices.getUserMedia({
      video: {
        deviceId: camera.deviceId,
        facingMode: ['user', 'environment'],
        height: {ideal: 1080},
        width: {ideal: 1920}
      }
    }).then(stream => {
      const track = stream.getVideoTracks()[0];

      //Create image capture object and get camera capabilities
      const imageCapture = new ImageCapture(track)
      const photoCapabilities = imageCapture.getPhotoCapabilities().then(() => {

        //todo: check if camera has a torch

        //let there be light!
        const btn = document.querySelector('.switch');
        btn.addEventListener('click', function(){
          track.applyConstraints({
            advanced: [{torch: true}]
          });
        });
      });
    });
  });
  
  //The light will be on as long the track exists
  
  
}

qrCodeScanner.js:

const qrcode1 = window.qrcode;
const video = document.createElement("video");
const canvasElement = document.getElementById("qr-canvas");
const canvas = canvasElement.getContext("2d");
const qrResult = document.getElementById("qr-result");
const outputData = document.getElementById("outputData");
const btnScanQR = document.getElementById("btn-scan-qr");

let scanning = false;

qrcode1.callback = res => {
  if (res) {
    outputData.innerText = res;
        if (res.match("^[0-9A-Z]{4}$")) {
                window.location="worker.php?ennm="+res;
                scanning = false;
                video.srcObject.getTracks().forEach(track => {
                  track.stop();
                });

                qrResult.hidden = false;
                canvasElement.hidden = true;
                btnScanQR.hidden = false;

          } else {
            alert("Wrong scanning!");
            window.location="qr.php";
          }

  }
};

  navigator.mediaDevices
    .getUserMedia({ video: { facingMode: "environment" } })
    .then(function(stream) {
      scanning = true;
      canvasElement.hidden = false;
      video.setAttribute("playsinline", true); // required to tell iOS safari we don't want fullscreen
      video.srcObject = stream;
      video.play();
      tick();
      scan();
    });

function tick() {
  canvasElement.height = video.videoHeight;
  canvasElement.width = video.videoWidth;
  canvas.drawImage(video, 0, 0, canvasElement.width, canvasElement.height);

  scanning && requestAnimationFrame(tick);
}

function scan() {
  try {
    qrcode1.decode();
  } catch (e) {
    setTimeout(scan, 300);
  }
}

Is there anything wrong with my code? Please, can anyone point out which part is wrong? I am a newbie to JavaScript and I would really appreciate it if someone can help me, thanks in advance!

1 Answers

I already figured out the solution by myself, I just combined torch.js with qrCodeScanner.js into the following js:

const qrcode1 = window.qrcode;
const qrResult = document.getElementById("qr-result");
const outputData = document.getElementById("outputData");
const btnScanQR = document.getElementById("btn-scan-qr");
const video = document.createElement("video");
const canvasElement = document.getElementById("qr-canvas");
const canvas = canvasElement.getContext("2d");

let scanning = false;

// scanning qr code
qrcode1.callback = res => {
  if (res) {
    outputData.innerText = res;
        if (res.match("^[0-9A-Z]{4}$")) {
                window.location="worker.php?ennm="+res;
                scanning = false;

                video.srcObject.getTracks().forEach(track => {
                  track.stop();
                });

                qrResult.hidden = false;
                canvasElement.hidden = true;
                btnScanQR.hidden = false;


          } else {
            alert("WARNING! You are scanning the wrong QR code, please try again. Please be aware that this is not MySejahtera app, thanks.");
            window.location="qr.php";
          }
  }
};

//Test browser support
const SUPPORTS_MEDIA_DEVICES = 'mediaDevices' in navigator;

if (SUPPORTS_MEDIA_DEVICES) {
  //Get the environment camera (usually the second one)
  navigator.mediaDevices.enumerateDevices().then(devices => {
  
    const cameras = devices.filter((device) => device.kind === 'videoinput');

    if (cameras.length === 0) {
      throw 'No camera found on this device.';
    }
    const camera = cameras[cameras.length - 1];

    // Create stream and get video track
    navigator.mediaDevices.getUserMedia({
      video: {
        facingMode: ['environment']
      }

    })

    .then(function(stream) {
      scanning = true;
      canvasElement.hidden = false;
      video.setAttribute("playsinline", true); // required to tell iOS safari we don't want fullscreen
      video.srcObject = stream;
      video.play();
      tick();
      scan();
      
      const track = stream.getVideoTracks()[0];

      //Create image capture object and get camera capabilities
      const imageCapture = new ImageCapture(track)
      const photoCapabilities = imageCapture.getPhotoCapabilities().then(() => {

        //let there be light!
        const btn = document.querySelector('.switch');
        btn.addEventListener('click', function(){
          track.applyConstraints({
            advanced: [{torch: true}]
          });
        });
      });
    });
  });
  
  //The light will be on as long the track exists
  
}


function tick() {
  canvasElement.height = video.videoHeight;
  canvasElement.width = video.videoWidth;
  canvas.drawImage(video, 0, 0, canvasElement.width, canvasElement.height);
  scanning && requestAnimationFrame(tick);
}

function scan() {
  try {
    qrcode1.decode();
  } catch (e) {
    setTimeout(scan, 300);
  }
}

Then, I hid the qrCodeScanner.js path in HTML, it works like a charm! However, this is only works in Android phone, js function of web app that triggered flashlight in iOS is inapplicable.

Related