ionic-capacitor: Added mute and toggle media devices

This commit is contained in:
csantosm 2022-07-20 13:31:48 +02:00
parent 3b7ab62b4c
commit cc87de9541
4 changed files with 131 additions and 62 deletions

View File

@ -7,9 +7,9 @@
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"android": "ionic cap run android -l --external",
"ios": "ionic cap run ios",
"sync": "ionic capacitor sync android --watch",
"android": "ionic capacitor run android",
"ios": "ionic capacitor run ios",
"sync": "ionic capacitor sync android",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"

View File

@ -1,61 +1,55 @@
<ion-app class="transparent">
<ion-header>
<ion-toolbar color="dark">
<img
class="demo-logo"
src="assets/images/openvidu_vert_white_bg_trans_cropped.png"
/>
<ion-buttons slot="primary">
<ion-button
color="light"
href="https://github.com/OpenVidu/openvidu-tutorials/tree/master/openvidu-ionic"
>
<ion-icon slot="icon-only" name="logo-github"></ion-icon>
</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-header>
<ion-toolbar color="dark">
<img class="demo-logo" src="assets/images/openvidu_vert_white_bg_trans_cropped.png" />
<ion-buttons slot="primary">
<ion-button color="light" href="https://github.com/OpenVidu/openvidu-tutorials/tree/master/openvidu-ionic">
<ion-icon slot="icon-only" name="logo-github"></ion-icon>
</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding transparent" *ngIf="!session">
<div id="img-div">
<img src="assets/images/openvidu_grey_bg_transp_cropped.png" />
</div>
<h1 align="center" id="title">Join a video session</h1>
<ion-item>
<ion-label position="floating">Participant</ion-label>
<ion-input [(ngModel)]="myUserName"></ion-input>
</ion-item>
<ion-item>
<ion-label position="floating">Session</ion-label>
<ion-input [(ngModel)]="mySessionId"></ion-input>
</ion-item>
<ion-content class="ion-padding transparent" *ngIf="!session">
<div id="img-div">
<img src="assets/images/openvidu_grey_bg_transp_cropped.png" />
</div>
<h1 align="center" id="title">Join a video session</h1>
<ion-item>
<ion-label position="floating">Participant</ion-label>
<ion-input [(ngModel)]="myUserName"></ion-input>
</ion-item>
<ion-item>
<ion-label position="floating">Session</ion-label>
<ion-input [(ngModel)]="mySessionId"></ion-input>
</ion-item>
<ion-button
id="join-button"
[disabled]="!mySessionId && !myUserName"
(click)="joinSession()"
expand="block"
shape="round"
color="primary"
>
<ion-icon slot="start" name="videocam"></ion-icon>
Join
</ion-button>
<ion-button
id="join-button"
[disabled]="!mySessionId && !myUserName"
(click)="joinSession()"
expand="block"
shape="round"
color="primary"
>
<ion-icon slot="start" name="videocam"></ion-icon>
Join
</ion-button>
<ion-fab vertical="bottom" horizontal="end" slot="fixed">
<ion-fab-button
id="settings-button"
[disabled]="!mySessionId && !myUserName"
(click)="presentSettingsAlert()"
size="small"
color="dark"
>
<ion-icon name="settings"></ion-icon>
</ion-fab-button>
</ion-fab>
</ion-content>
<ion-fab vertical="bottom" horizontal="end" slot="fixed">
<ion-fab-button
id="settings-button"
[disabled]="!mySessionId && !myUserName"
(click)="presentSettingsAlert()"
size="small"
color="dark"
>
<ion-icon name="settings"></ion-icon>
</ion-fab-button>
</ion-fab>
</ion-content>
<ion-content [scrollEvents]="true" (ionScroll)="refreshVideos()" *ngIf="session" class="transparent">
<ion-content [scrollEvents]="true" *ngIf="session" class="transparent">
<div id="session-header">
<h1 id="session-title">{{ mySessionId }}</h1>
</div>
@ -77,8 +71,20 @@
</ion-row>
</ion-grid>
<ion-fab vertical="bottom" horizontal="center" slot="fixed">
<ion-fab-button size="small" color="danger" (click)="leaveSession()">
<ion-fab vertical="bottom" horizontal="end" slot="fixed">
<ion-fab-button class="action-button" color="light" id="camButton" (click)="swapCamera()">
<ion-icon name="camera-reverse-sharp"></ion-icon>
</ion-fab-button>
<ion-fab-button (click)="toggleMicrophone()" class="action-button">
<ion-icon name="{{ microphoneIcon }}"></ion-icon>
</ion-fab-button>
<ion-fab-button (click)="toggleCamera()" class="action-button">
<ion-icon name="{{ cameraIcon }}"></ion-icon>
</ion-fab-button>
<ion-fab-button color="danger" (click)="leaveSession()" class="action-button">
<ion-icon name="power"></ion-icon>
</ion-fab-button>
</ion-fab>

View File

@ -24,3 +24,7 @@
ion-col {
padding: 1px;
}
.action-button {
padding: 5px;
}

View File

@ -3,7 +3,7 @@
import { Component, HostListener, OnDestroy, OnInit } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { OpenVidu, Publisher, Session, StreamEvent, StreamManager, Subscriber } from 'openvidu-browser';
import { Device, OpenVidu, Publisher, PublisherProperties, Session, StreamEvent, StreamManager, Subscriber } from 'openvidu-browser';
import { throwError as observableThrowError } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { AlertController, Platform } from '@ionic/angular';
@ -34,6 +34,16 @@ export class AppComponent implements OnInit, OnDestroy {
mySessionId: string;
myUserName: string;
cameraIcon = 'videocam';
microphoneIcon = 'mic';
private devices: Device[];
private cameras: Device[];
private microphones: Device[];
private cameraSelected: Device;
private microphoneSelected: Device;
private isFrontCamera = true;
constructor(
private httpClient: HttpClient,
private platform: Platform,
@ -61,6 +71,8 @@ export class AppComponent implements OnInit, OnDestroy {
this.OV = new OpenVidu();
this.initDevices();
// --- 2) Init a session ---
this.session = this.OV.initSession();
@ -113,14 +125,14 @@ export class AppComponent implements OnInit, OnDestroy {
// Init a publisher passing undefined as targetElement (we don't want OpenVidu to insert a video
// element: we will manage it on our own) and with the desired properties
const publisher: Publisher = this.OV.initPublisher(undefined, {
audioSource: undefined, // The source of audio. If undefined default microphone
videoSource: undefined, // The source of video. If undefined default webcam
audioSource: this.microphones[0].deviceId, // The source of audio. If undefined default microphone
videoSource: this.cameras[0].deviceId, // The source of video. If undefined default webcam
publishAudio: true, // Whether you want to start publishing with your audio unmuted or not
publishVideo: true, // Whether you want to start publishing with your video enabled or not
resolution: '640x480', // The resolution of your video
frameRate: 30, // The frame rate of your video
insertMode: 'APPEND', // How the video is inserted in the target element 'video-container'
mirror: true // Whether to mirror your local video or not
mirror: this.isFrontCamera // Whether to mirror your local video or not
});
// --- 6) Publish your stream ---
@ -149,6 +161,43 @@ export class AppComponent implements OnInit, OnDestroy {
this.generateParticipantInfo();
}
async swapCamera() {
try {
const newCamera = this.cameras.find((cam) => cam.deviceId !== this.cameraSelected.deviceId);
if (!!newCamera) {
this.isFrontCamera = !this.isFrontCamera;
const pp: PublisherProperties = {
videoSource: newCamera.deviceId,
audioSource: false,
mirror: this.isFrontCamera
};
// Stopping the video tracks after request for another MediaStream
this.publisher.stream.getMediaStream().getVideoTracks().forEach((track) => {
track.stop();
});
const newTrack = await this.OV.getUserMedia(pp);
const videoTrack: MediaStreamTrack = newTrack.getVideoTracks()[0];
await (this.publisher as Publisher).replaceTrack(videoTrack);
this.cameraSelected = newCamera;
}
} catch (error) {
console.error(error);
}
}
toggleCamera() {
const publish = !this.publisher.stream.videoActive;
(this.publisher as Publisher).publishVideo(publish, true);
this.cameraIcon = publish ? 'videocam' : 'eye-off';
}
toggleMicrophone() {
const publish = !this.publisher.stream.audioActive;
(this.publisher as Publisher).publishAudio(publish);
this.microphoneIcon = publish ? 'mic' : 'mic-off';
}
async presentSettingsAlert() {
const alert = await this.alertController.create({
header: 'OpenVidu Server config',
@ -185,6 +234,16 @@ export class AppComponent implements OnInit, OnDestroy {
await alert.present();
}
private async initDevices() {
this.devices = await this.OV.getDevices();
this.cameras = this.devices.filter((d) => d.kind === 'videoinput');
this.microphones = this.devices.filter((d) => d.kind === 'audioinput' && d.label !== 'Default');
this.cameraSelected = this.cameras[0];
this.microphoneSelected = this.microphones[0];
}
private checkAndroidPermissions(): Promise<void> {
console.log('Requesting Android Permissions');
return new Promise((resolve, reject) => {