Ionic video call by peerjs
Tags: ionic, video, webrtc, peerjs
Published: 2020-02-11 17:06:36

Hello,
Before starting, this is ionic 5 angular 9 simple example of video call.
At the end you can connect two device in same network if the app is running on both of them.
if you want to wake up the app first you have to use something like push notification, we don't implement it now.
####let do it fast :D

ionic must be installed.

from your console run
```
ionic start ionic-peer blank
```
then inside of your project folder, get peerjs:
```
npm install peerjs --save
```
add `esModuleInterop` to your tsconfig.json  as below:
```json
"compilerOptions": {
    ....
    "esModuleInterop": true,
    ....
}
```
create peer service:
```
ionic generate service providers/webrtc
```

edit WebrtcService, it'll initiate peer-to-peer connection and make call.

```typescript
import Peer from 'peerjs';

export class WebrtcService {
  peer: Peer;
  myStream: MediaStream;
  myEl: HTMLMediaElement;
  partnerEl: HTMLMediaElement;

  stun = 'stun.l.google.com:19302';
  mediaConnection: Peer.MediaConnection;
  options: Peer.PeerJSOption;
  stunServer: RTCIceServer = {
    urls: 'stun:' + this.stun,
  };

  constructor() {

    this.options = {  // not used, by default it'll use peerjs server
      key: 'cd1ft79ro8g833di',
      debug: 3
    };
  }

  getMedia() {
    navigator.getUserMedia({ audio: true, video: true }, (stream) => {
      this.handleSuccess(stream);
    }, (error) => {
      this.handleError(error);
    });
  }

  async init(userId: string, myEl: HTMLMediaElement, partnerEl: HTMLMediaElement) {
    this.myEl = myEl;
    this.partnerEl = partnerEl;
    try {
      this.getMedia();
    } catch (e) {
      this.handleError(e);
    }
    await this.createPeer(userId);
  }

  async createPeer(userId: string) {
    this.peer = new Peer(userId);
    this.peer.on('open', () => {
      this.wait();
    });
  }

  call(partnerId: string) {
    const call = this.peer.call(partnerId, this.myStream);
    call.on('stream', (stream) => {
      this.partnerEl.srcObject = stream;
    });
  }

  wait() {
    this.peer.on('call', (call) => {
      call.answer(this.myStream);
      call.on('stream', (stream) => {
        this.partnerEl.srcObject = stream;
      });
    });
  }

  handleSuccess(stream: MediaStream) {
    this.myStream = stream;
    this.myEl.srcObject = stream;
  }

  handleError(error: any) {
    if (error.name === 'ConstraintNotSatisfiedError') {
      const v = constraints.video;
     // this.errorMsg(`The resolution ${v.width.exact}x${v.height.exact} px is not supported by your device.`);
      this.errorMsg(`The resolution px is not supported by your device.`);
    } else if (error.name === 'PermissionDeniedError') {
      this.errorMsg('Permissions have not been granted to use your camera and ' +
        'microphone, you need to allow the page access to your devices in ' +
        'order for the demo to work.');
    }
    this.errorMsg(`getUserMedia error: ${error.name}`, error);
  }

  errorMsg(msg: string, error?: any) {
    const errorElement = document.querySelector('#errorMsg');
    errorElement.innerHTML += `<p>${msg}</p>`;
    if (typeof error !== 'undefined') {
      console.error(error);
    }
  }
}
```
init method will create a peer connection with yourId and then register wait method to listen to any call .
if any call receive inside wait method, it'll answer the call automatically,
you can handel it by yourself
(new peer() without option will connect to default server, you can use other server or run your own peer server)
it'll also start to stream video/audio as you define in option and push it to object of html element.(we have to create a html element to show video in home.html page)

call method will ask peer server to connect you to your partner as call type.
both call method and wait method duty is streaming partner video/audio and show it inside of partner media frame(we will create it inside home page)

###Edit home.html

```html
<ion-content>
  <div id="errorMsg"></div>

  <video id="partner-video" (click)="swapVideo('my-video')" autoplay playsinline
    [ngClass]="{'top-video': topVideoFrame === 'partner-video', 'main-video': topVideoFrame != 'partner-video'}">
  </video>
  <video id="my-video" (click)="swapVideo('partner-video')" autoplay playsinline
    [ngClass]="{'top-video': topVideoFrame === 'my-video', 'main-video': topVideoFrame != 'my-video'}" >
  </video>


  <ion-row nowrap>
    <ion-button (click)="init()">Login As: </ion-button>
    <ion-item>
      <ion-input type="text" [(ngModel)]="userId" placeholder="enter your nick name"></ion-input>
    </ion-item>
  </ion-row>

  <ion-row nowrap>
    <ion-button (click)="call()">Call To: </ion-button>
    <ion-item>
      <ion-input type="text" [(ngModel)]="partnerId" placeholder="your partner nick name"></ion-input>
    </ion-item>
  </ion-row>  
</ion-content>

```
video tag will show you stream media of you and your partner.
you have to login with nick name, because of using default server, you may see other people with easy nick name :D

###Edit home.ts like this
```typescript
import { WebrtcService } from '../providers/webrtc.service';

export class HomePage {
  topVideoFrame = 'partner-video';
  userId: string;
  partnerId: string;
  myEl: HTMLMediaElement;
  partnerEl: HTMLMediaElement;

  constructor(
    public webRTC: WebrtcService,
    public elRef: ElementRef
  ) {}

  init() {
    this.myEl = this.elRef.nativeElement.querySelector('#my-video');
    this.partnerEl = this.elRef.nativeElement.querySelector('#partner-video');
    this.webRTC.init(this.userId, this.myEl, this.partnerEl);
  }

  call() {
    this.webRTC.call(this.partnerId);
    this.swapVideo('my-video');
  }

  swapVideo(topVideo: string) {
    this.topVideoFrame = topVideo;
  }
}

```
login method will assign video frame to html element and pass them to webrtcservice, so the service can push stream to them.

call method will pass partnerId to webrtc service for connection to your partner.

###Edit home.scss
```css
.top-video{
    position: absolute;
    top: 100px;
    right: 100px;
    max-width: 100px;
    z-index: 2;
}

.main-video{
    width: 100%;
    max-height: 70%;
}
```
after you and your partner get connected, you can swap video with swapVideo method and [ngClass].

webrtc service will ask for camera/microphone permission.
because of that, when we run application outside of localhost, browser will block permission, so we have to run it with --ssl parameter.
first join your pc/laptop with your second device (pc/laptop or mobile) to the same network
then run ionic serve with your ip address, for example:
```
ionic serve --address 192.168.43.105 --ssl
```
in your second device visit that address with https prefix:
```
https://192.168.43.105:8100
```
[source on github](https://github.com/timsar2/ionic-video-call.git)

###That's it, i hope it's useful.