Accessing Front and Rear camera on a Mobile browser in Emberjs App

Accessing Front and Rear camera on a Mobile browser in Emberjs App

ยท

5 min read

Suppose, you are having a web application that has the feature to open a camera. For a Laptop or desktop machine, it is fine to access the one camera you are having. What if you are accessing the same web app on mobile or tablet, wouldn't it be cool to access both front and rear cameras. In this blog, we are going to create an Ember component using which will have features to access both Front and Rear cameras.

Let's build one!! ๐Ÿ‘ท

  • First of all, I am assuming you have one running ember application. If not create one ember new my-camera-access.
  • Navigate to your project cd my-camera-access.
  • I like to use ember-modifier, so let's install ember-modifier by running ember install ember-modifier in your terminal.
  • Go to app/templates/application.hbs and remove ember generated boilerplate HTML code. Just leave {{outlet}}
    {{outlet}}
    
  • Run, ember server and your application will run at localhost:4200. You can see a blank page.
  • Now, we are ready to add dual-camera component.

Creating dual-camera component:

  • Run theember g component dual-camera command in your terminal.
  • This will generate app/components/dual-camera.hbs. In the latest Ember version, it may skip the component js class. You can add one by running ember generate component-class dual-camera. This will add app/components/dual-camera.js.
  • Let's add some dummy code in the view file of the component.
    <h1> Camera Test</h1>
    
  • Now, to render the component we will place the camera component in application.hbs.
    <DualCamera />
    {{outlet}}
    
  • Now, on the web app you can see the text Camera Test.

Accessing camera and adding video-tag ๐ŸŽฅ

  • Before working on accessing front/rear camera logic, we have to understand how the camera is accessed and how we can display the video captured by the camera.
  • In HTML5 there is MediaDevices API which provides access to the camera.
  • With this API we can provide video feeds to the browser to display video streams.
  • We use mediaDevices.getUserMedia method to access the video feeds from the camera and play it in the browser.
  • getUserMedia method prompts the user for permission to access the camera. You can see Allow/Block options.
  • When the user selects "Allows" its returns a Promise that resolves to a media stream. The device access is blocked if the user clicks the "Block" button.
    navigator.mediaDevices.getUserMedia({video: true}). //we will add other options later.
    
  • The process of accessing the camera permission is achieved with the above line.
  • As we discussed earlier it returns video feeds as a promise. This video feeds needs to be played somewhere.
  • So, we are going to add the video tag in our component view i.e app/components/dual-camera.hbs.
    <video autoplay id="video-player"></video>
    
  • We will add some styling to the video tag to make it a little large in size.
  • For now, it is just video tag with autoplay property. It still does not have video streams.
  • We will add this data fetching logic in did-insert hook of the glimmer component which will be called from did-insert modifier in the video.
    <video autoplay id="video-player" {{did-insert this.onRender}}></video>
    
  • did-insert will call onRender action with video tag as the parameter.
@action
onRender(videoPlayer) {
    videoPlayer.play();
    this.video = videoPlayer; // we are maintaining `videoPlayer` instance in the class to use it later.
    this.initializeCamera();
}
  • As soon as the view is inserted in the DOM, onRender method will be called, which will have access to the video tag. We can use it to play the stream.
  • But if you notice, we still haven't provided a video stream it is just a video tag.

Providing video stream to the video tag

  • As discussed earlier, after allowing the permission to access the video. It returns video feeds as a promise.
  • let's add this permission code in initializeCamera method.
    async initializeCamera() {
      ......
      ......
      const videoStream= await navigator.mediaDevices.getUserMedia(this.videoOpts);
      this.videoStream = videoStream;
      this.video.srcObject = videoStream;
    }
    
  • As you can see getUserMedia returns stream which is assigned to video.srcObject. video.srcObject is nothing but video player instance.
  • This will start displaying video on the web app.

Accessing Rear camera

  • With the above implementation, we can access the front camera. How to access the rear camera?
  • It's very easy, the options we provide to getUserMedia need to pass facingMode options with a value of environment by default its value is user.
  • We will add one button in the view which will change the camera view.
    <button {{action this.changeCamera}}>Change</button>
    
  • We will add changeCamera action to change the camera view.
    @action
    changeCamera() {
      this.useFrontCamera = !this.useFrontCamera;
      this.initializeCamera();
    }
    
  • We are maintaining a boolean value of useFrontCamera to initialize the camera with facingMode options of user and environment. Something like below,
    async initializeCamera() {
      const cameraType = this.useFrontCamera ? "user" : "environment";
      this.videoOpts.video.facingMode =  cameraType;
      ......
      ......
      ......
    }
    

Final Implementation of the javascript code is below

import Component from '@glimmer/component';
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';

export default class DualCameraComponent extends Component {
  @tracked videoStream = "";
  @tracked useFrontCamera = true;

  @tracked videoOpts = {
    video: {
      width: {
        min: 1280,
        ideal: 1920,
        max: 2560
      },
      height: {
        min: 720,
        ideal: 1080,
        max: 1440
      }
    }
  };

  async initializeCamera() {
    const cameraType = this.useFrontCamera ? "user" : "environment";
    this.videoOpts.video.facingMode =  cameraType;

    const videoStream = await navigator.mediaDevices.getUserMedia(this.videoOpts);
    this.videoStream = videoStream;
    this.video.srcObject = videoStream;
  }

  @action
  onRender(videoPlayer) {
    videoPlayer.play();
    this.video = videoPlayer;
    this.initializeCamera();
  }

  @action
  changeCamera() {
    this.useFrontCamera = !this.useFrontCamera;
    this.initializeCamera();
  }
}

I hope you like this easy implementation of accessing the front and rear cameras in the Ember application. If you have any questions then please comment below.

References:

Did you find this article valuable?

Support Abul Asar's Blog by becoming a sponsor. Any amount is appreciated!