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

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 the` ember 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:
- [Ember-Modifier](https://github.com/ember-modifier/ember-modifier)
- [MDN](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia)
- [Github Repo](https://github.com/abulsayyad123/ember-dual-camera)




