Fairoj : [UPGRADE] video conference layout with additional features are implemented

This commit is contained in:
venbatechnologies@gmail.com 2021-06-21 11:12:06 +05:30
parent 4c52c353a4
commit 083bc9a7d6
7 changed files with 456 additions and 125 deletions

View File

@ -62,6 +62,29 @@
"maximumError": "10kb"
}
]
},
"staging": {
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "6kb",
"maximumError": "10kb"
}
]
}
}
},
@ -75,6 +98,9 @@
"configurations": {
"production": {
"browserTarget": "video-chat-user:build:production"
},
"staging": {
"browserTarget": "video-chat-user:build:staging"
}
}
},

View File

@ -7,7 +7,9 @@
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
"e2e": "ng e2e",
"staging":"ng build --configuration=staging",
"production":"ng build --prod"
},
"private": true,
"dependencies": {

View File

@ -8,20 +8,22 @@
<!-- <mat-dialog-content> -->
<!-- <div fxLayout="row"> -->
<div [style.visibility] ="is_video_enable? 'visible' : 'hidden'" >
<!-- <div class="my_video"> -->
<div #myvideo id="myvideo" muted></div>
<!-- <div #myvideo id="myvideo" muted></div> -->
<!-- </div> -->
<div class="peer_video" fxLayoutAlign="center" [ngStyle] = "{'height': !peerVideoEnable ? '5%': ''}">
<div id="peervideo" #peervideo [style.visibility]="peerVideoEnable? 'visible' : 'hidden'"></div>
</div>
<!-- <div class="peer_video" fxLayoutAlign="center" [ngStyle] = "{'height': !peerVideoEnable ? '5%': ''}"> -->
<div id="peervideo" #peervideo class="grid grid--{{twilioService.roomParticipants ? twilioService.roomParticipants.size+1 : '1'}}" ></div>
<!-- </div> -->
<div [style.visibility] ="is_video_enable? 'visible' : 'hidden'" >
<!-- <input type="text" ><br/> -->
<!-- {{peerVideoEnable}} -->
<div class="peer_message" *ngIf="peerVideoEnable == false" fxLayoutAlign="center" style="position: absolute;bottom:15%;width: 100%;justify-content: center">
<p style="text-align: center;"> {{message}} </p><br/>
</div>
<div *ngIf="type == '2' && !peerVideoEnable" class="copy_link">
<div *ngIf="(type == '2' || type == '3') && !peerVideoEnable" class="copy_link">
<p>To Copy Customer Link <button mat-stroked-button (click)="copyToClipBoard(cusUrl)"><mat-icon>content_copy</mat-icon>Click here</button></p>
</div>
<!-- <div class="input-group mb-3">
@ -40,30 +42,30 @@
<!-- <button type="button" style="width: 90px" (click)="start_Calling('notinit')" class="btn btn-primary btn-lg" *ngIf="!peerVideoEnable">Recieve</button><br/> -->
<!-- <button class="mr-1 mb-1 hover-icon" type="button" matTooltip="Disconnect"
matTooltipPosition="above" *ngIf="peerVideoEnable"><mat-icon>call_end</mat-icon></button><br/> -->
<button mat-raised-button mat-icon-button class="mr-1 mb-1 hover-icon" type="button" matTooltip="Video Off / On"
<button style="align-self: center;" mat-raised-button mat-icon-button class="mr-1 mb-1 hover-icon" type="button" matTooltip="Video Off / On"
matTooltipPosition="above" (click)="videoHandling()" >
<mat-icon *ngIf="!twilioService.camera">videocam_off</mat-icon>
<mat-icon *ngIf="twilioService.camera">videocam</mat-icon>
</button>&nbsp;&nbsp;&nbsp;
<button mat-raised-button mat-icon-button class="mr-1 mb-1 hover-icon" type="button" matTooltip="Mic Off / On"
<button style="align-self: center;" mat-raised-button mat-icon-button class="mr-1 mb-1 hover-icon" type="button" matTooltip="Mic Off / On"
matTooltipPosition="above" (click)="micMuteHandling()" >
<mat-icon *ngIf="!twilioService.microphone">mic_off</mat-icon>
<mat-icon *ngIf="twilioService.microphone">mic</mat-icon>
</button>&nbsp;&nbsp;&nbsp;
<span style="margin: 0px !important;" *ngIf="twilioService.switch_camera_option">
<button mat-raised-button mat-icon-button class="mr-1 mb-1 hover-icon" type="button" matTooltip="Switch Camera"
<span style="margin: 0px !important;align-self: center;" *ngIf="twilioService.switch_camera_option">
<button style="align-self: center;" mat-raised-button mat-icon-button class="mr-1 mb-1 hover-icon" type="button" matTooltip="Switch Camera"
matTooltipPosition="above" (click)="twilioService.switchCamera()" >
<mat-icon>switch_camera</mat-icon>
</button> &nbsp;&nbsp;&nbsp;
<mat-icon>cached</mat-icon>
</button>&nbsp;&nbsp;&nbsp;
</span>
<button mat-raised-button mat-icon-button class="mr-1 mb-1 hover-icon" type="button" matTooltip="Disconnect"
<button style="height: 45px;width: 45px;" mat-raised-button mat-icon-button class="mr-1 mb-1 hover-icon" type="button" matTooltip="Disconnect"
matTooltipPosition="above" (click)="twilioService.disconnect()" >
<mat-icon>call_end</mat-icon>
</button>
</div>
</div>
<div fxLayoutAlign="center center" *ngIf="!is_video_enable" >
<div style="position: relative;bottom: 50%">
<div style="position: absolute;top: 20%">
<mat-spinner *ngIf="is_spinner"></mat-spinner>
</div>
<div fxLayout="column" fxLayoutAlign="center center" style="position: absolute;bottom: 40%">

View File

@ -6,98 +6,109 @@ body{
.copy_link {
// position: absolute;
// bottom: 40%;
margin-top: 21%;
// margin-top: 21%;
text-align: center;
border: 1px dashed #cececef5;
padding: 5px;
// padding: 5px;
border-radius: 10px;
position: absolute;
top:10px;
right: 10px;
background-color: darkgray;
opacity: 0.7;
p{
color: #840000c9;
// color: #840000c9;
color: black;
font-weight: 500;
font-family: monospace;
padding: 5px;
}
}
@media(max-width:500px) {
// @media(max-width:500px) {
div#myvideo {
max-width: 32%;
// min-width: 150px;
position: absolute;
// border: 2px solid #9E9E9E;
top:0;
left: 0;
// border-radius: 10px;
margin: 1%
// /* top: 20px;
}
.body-container {
padding: 0px !important;
}
div#peervideo {
/* height: 498px; */
// position: relative;
// margin-top: 126px;
width: 100%;
// margin-top: 25%;
}
// .peer_message{
// font-size: 20px;
// div#myvideo {
// max-width: 32%;
// // min-width: 150px;
// position: absolute;
// top: 11%;
// bottom: 10%;
// float: right;
// padding: 57px;
// /* border: 2px solid lavender; */
// left: 8%;
// p{
// text-align: center;
// // border: 2px solid #9E9E9E;
// top:0;
// left: 0;
// // border-radius: 10px;
// margin: 1%
// // /* top: 20px;
// }
// .body-container {
// padding: 0px !important;
// }
// div#peervideo {
// /* height: 498px; */
// // position: relative;
// // margin-top: 126px;
// width: 100%;
// // margin-top: 25%;
// }
// // .peer_message{
// // font-size: 20px;
// // position: absolute;
// // top: 11%;
// // bottom: 10%;
// // float: right;
// // padding: 57px;
// // /* border: 2px solid lavender; */
// // left: 8%;
// // p{
// // text-align: center;
// // }
// // }
// }
.peer_message > p {
padding: 3px;
border-radius: 5px;
background-color: darkgray;
}
@media(min-width:500px) {
.peer_video{
max-height: 80vh;
}
div#myvideo {
max-width: 22%;
// min-width: 150px;
position: absolute;
// border: 2px solid #9E9E9E;
top:0;
left: 0;
// border-radius: 10px;
margin: 1%
// max-width: 45%;
// text-align: center;
// margin-left:3%;
// margin-top:1%;
// min-width: 150px;
// position: absolute;
// border: 2px solid #9E9E9E;
// /* top: 20px;
}
// div#myvideo {
// max-width: 22%;
// // min-width: 150px;
// position: absolute;
// // border: 2px solid #9E9E9E;
// top:0;
// left: 0;
// // border-radius: 10px;
// margin: 1%
// // max-width: 45%;
// // text-align: center;
// // margin-left:3%;
// // margin-top:1%;
// // min-width: 150px;
// // position: absolute;
// // border: 2px solid #9E9E9E;
// // /* top: 20px;
// }
div#peervideo {
/* height: 498px; */
max-width: 100%;
text-align: center;
margin-left:3%;
margin-top:1%;
// position: relative;
// margin-top: 126px;
// width: 100%;
}
}
.peer_video{
max-height: 85vh !important;
text-align: center
}
body{
margin:10px !important;
// div#peervideo {
// /* height: 498px; */
// max-width: 100%;
// text-align: center;
// margin-left:3%;
// margin-top:1%;
// // position: relative;
// // margin-top: 126px;
// // width: 100%;
// }
}
// .peer_video{
// max-height: 85vh !important;
// text-align: center
// }
// body{
// margin:10px !important;
// }
.note-label{
justify-content: center;
text-align: center;
@ -108,3 +119,193 @@ body{
margin-right: 0px !important;
}
}
.grid {
display: grid;
}
:root {
--one-row: 87vh;
--two-rows: repeat(2, calc(87vh / 2));
--three-rows: repeat(3, calc(87vh / 3));
--four-rows: repeat(4, calc(87vh / 4));
}
$one-row:88vh;
// @media (orientation: portrait) {
// $one-row:88vh !important;
// }
$two-rows:repeat(2, calc(#{$one-row} / 2));
$three-rows:repeat(3, calc(#{$one-row} / 3));
$four-rows:repeat(4, calc(#{$one-row} / 4));
.grid--1 {
grid-template-rows: $one-row;
grid-template-areas:
"A";
@media (orientation: portrait) {
grid-template-areas:
"A";
}
}
.grid--2 {
grid-template-rows: $one-row;
grid-template-areas:
"A B";
@media (orientation: portrait) {
grid-template-rows: $one-row;
grid-template-areas:
"A";
::ng-deep .my-video{
position: absolute;
top: 0;
height:145px;
width: 140px;
}
}
}
.grid--3 {
grid-template-rows: $one-row;
// grid-template-areas:
// "A B"
// "C C";
grid-template-areas: "A B C";
@media (orientation: portrait) {
grid-template-rows: $one-row;
// grid-template-areas:
// "A B"
// "C C";
grid-template-areas:
"A B";
::ng-deep .my-video{
position: absolute;
top: 0;
height:145px;
width: 140px;
}
}
}
.grid--4 {
grid-template-rows: $two-rows;
grid-template-areas:
"A B"
"C D";
}
.grid--5 {
grid-template-rows: $two-rows;
grid-template-areas:
"A A B B C C"
"D D D E E E";
@media (orientation: portrait) {
grid-template-rows: $three-rows;
grid-template-areas:
"A A B B"
"C C D D"
"E E E E";
}
}
.grid--6 {
grid-template-rows: $two-rows;
grid-template-areas:
"A B C"
"D E F";
@media (orientation: portrait) {
grid-template-rows: $three-rows;
grid-template-areas:
"A B"
"C D"
"E F";
}
}
.grid--7 {
grid-template-rows: $two-rows;
grid-template-areas:
"A A A B B B C C C D D D"
"E E E E F F F F G G G G";
@media (orientation: portrait) {
grid-template-rows: $three-rows;
grid-template-areas:
"A A A B B B"
"C C C D D D"
"E E F F G G";
}
}
.grid--8 {
grid-template-rows: $two-rows;
grid-template-areas:
"A B C D"
"E F G H";
@media (orientation: portrait) {
grid-template-rows: $four-rows;
grid-template-areas:
"A B"
"C D"
"E F"
"G H";
}
}
::ng-deep .video-wrapper {
height: 100%;
overflow: hidden;
width: 100%;
padding: 2px;
.identity-name {
position: relative;
background-color: #b1b1b1;
text-align: center;
opacity: 0.8;
padding: 0;
bottom: 39px;
left: 0%;
.praticipant-name {
// width: 80%;
margin-left: 30px;
margin-right: 30px;
text-align: center;
align-items: center;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
}
.icons_participant {
display: none;
/* background: blue; */
/* color: darkslategray; */
position: absolute;
z-index: 3;
/* top: 0; */
bottom: 6px;
right: 5px;
@media (orientation: portrait) {
bottom: 1px !important;
}
}
.audio {
left: 5px !important;
}
}
::ng-deep video {
height: 100%;
display: block;
object-fit: cover;
width: 100%;
}

View File

@ -67,7 +67,7 @@ export class ChatComponentComponent implements OnInit {
return
}
this.type_name = this.type == '1' ? 'CUSTOMER' : this.type == '2' ? 'PDOFFICER' : this.type == '3' ? this.cm_name : 'UNKNOWN'
if(this.type == '2') {
if(this.type == '2' || this.type == '3') {
if(window.location.origin.includes('localhost')){
this.cusUrl = window.location.origin+'/#/chat/'+this.randomStr+";id="+this.pd_id+";type=1;";
}

View File

@ -192,7 +192,7 @@ export class TwilioService {
// When a Participant adds a Track, attach it to the DOM.
room.on('trackPublished', (track, participant) => {
console.log("Track Published",participant);
this.attachTracks([track]);
this.attachTracks([track],'');
});
// When a Participant removes a Track, detach it from the DOM.
@ -225,7 +225,7 @@ export class TwilioService {
while (element.firstChild) {
element.removeChild(element.firstChild);
}
let localElement = this.localVideo.nativeElement;
let localElement = this.remoteVideo.nativeElement;
while (localElement.firstChild) {
localElement.removeChild(localElement.firstChild);
}
@ -291,50 +291,129 @@ console.log("Room participants", this.roomParticipants,this.roomObj)
// },0)
}
attachParticipantTracks(participant): void {
console.log(participant)
// debugger;
participant.tracks.forEach(part => {
console.log("attachParticipantTracks",participant);
this.trackPublished(part);
this.trackPublished(part, participant);
});
}
trackPublished(publication) {
trackPublished(publication, participantObj) {
console.log("trackPublished publication",publication);
if (publication.isSubscribed)
this.attachTracks(publication.track);
this.attachTracks(publication.track,participantObj);
if (!publication.isSubscribed)
publication.on('subscribed', track => {
console.log(track);
this.attachTracks(track);
this.attachTracks(track, participantObj);
});
participantObj.on('trackSubscribed', track => {
console.log("Track Sbu",track)
track.on('disabled', (tt) => {
let participantEle = document.getElementsByName(tt.sid)
console.log("disabled",tt,tt.sid,participantEle)
// do something with the UI here
this.participantMuteUI(tt,'0')
// debugger;
});
track.on('enabled', (tt) => {
console.log("enabled",tt)
this.participantMuteUI(tt,'1')
// do something with the UI here
// debugger;
});
});
}
attachTracks(tracks) {
console.log("attachTracks",tracks);
participantMuteUI(track,status) {
// for (let track of participant.tracks) {
Array.from(this.remoteVideo.nativeElement.children).forEach((child:any) => {
// console.log('children.length=' + this.remoteVideo.nativeElement.children.length,child.getAttribute('sid'),track[0],track);
if(child.getAttribute('sid') == track.sid) {
console.log(child,child.getAttribute('participant-sid'))
let id = child.getAttribute('participant-sid')+'-'+track.kind
let currentVideoEle = document.getElementById(id)
console.log(currentVideoEle,id)
if(currentVideoEle && currentVideoEle != null) {
this.renderer.setStyle(currentVideoEle, 'display', status == '0' ? 'block' : 'none');
}
}
});
// }
}
createMatIcon(iconName,kind,participant_sid) {
const matIcon = this.renderer.createElement('mat-icon');
this.renderer.addClass(matIcon, 'mat-icon');
this.renderer.addClass(matIcon, 'material-icons');
this.renderer.addClass(matIcon,'icons_participant')
this.renderer.setAttribute(matIcon,'id',participant_sid+'-'+kind,)
this.renderer.addClass(matIcon,kind)
matIcon.innerHTML = iconName
return matIcon
}
attachTracks(tracks,participantObj) {
console.log("attachTracks",tracks,participantObj.videoTracks['Entries']);
const element = tracks.attach();
this.renderer.data.id = tracks.sid;
console.log("Renderer",this.renderer,tracks.sid)
if(tracks.kind == 'video') {
this.renderer.setAttribute(element,'class','inner')
}
this.renderer.setAttribute(element,'sid',tracks.sid)
this.renderer.setStyle(element, 'min-height', '80vh');
this.renderer.setStyle(element, 'height', '100%');
console.log("Width",window.screen.width);
if(window.screen.width >= 500) {
this.renderer.setStyle(element, 'width', '100%');
}
// this.renderer.setStyle(element, 'min-width', '100%');
this.renderer.setStyle(element, 'max-width', '100%');
this.renderer.setStyle(element,'object-fit','fill');
this.renderer.appendChild(this.remoteVideo.nativeElement, element);
const divEle = this.renderer.createElement('div')
setTimeout(()=>{
console.log("Remote video size",this.remoteVideo.nativeElement.offsetHeight,this.remoteVideo)
if(this.remoteVideo.nativeElement.offsetHeight < 350) {
// this.remoteVideo.nativeElement.style.marginTop = '0px'
// this.renderer.setStyle(element,'object-fit','fill');
if(!tracks.isEnabled) {
this.renderer.setStyle(element,'background-color','black');
}
},5000)
this.renderer.appendChild(divEle,element)
if(tracks.kind == 'video') {
this.renderer.setAttribute(divEle,'class','video-wrapper')
if(participantObj && participantObj.hasOwnProperty('identity') && participantObj.identity) {
const pEle = this.renderer.createElement('div')
this.renderer.setAttribute(pEle,'class','identity-name')
const spanEle = this.renderer.createElement('p');
this.renderer.setAttribute(spanEle,'class','praticipant-name')
spanEle.innerHTML = participantObj.identity
this.renderer.appendChild(pEle,spanEle)
this.renderer.appendChild(pEle,this.createMatIcon('videocam_off','video',participantObj.sid))
this.renderer.appendChild(pEle,this.createMatIcon('mic_off','audio',participantObj.sid))
this.renderer.appendChild(divEle,pEle)
}
}
else{
this.renderer.setStyle(divEle, 'display', 'none');
}
// FOR PARTICIPANT SID
// this.renderer.setAttribute(divEle,participantObj.sid,'')
this.renderer.setAttribute(divEle,'participant-sid',participantObj.sid)
// this.renderer.setAttribute(divEle,'id',participantObj.sid)
// FOR TRACK SID
this.renderer.setAttribute(divEle,'sid',tracks.sid)
// this.renderer.setStyle(element, 'min-height', '80vh');
// this.renderer.setStyle(element, 'height', '100%');
// console.log("Width",window.screen.width);
// if(window.screen.width >= 500) {
// // this.renderer.setStyle(element, 'width', '100%');
// }
// this.renderer.setStyle(element, 'min-width', '100%');
// this.renderer.setStyle(element, 'max-width', '100%');
// this.renderer.setStyle(element,'object-fit','fill');
this.renderer.appendChild(this.remoteVideo.nativeElement, divEle);
setTimeout(() => {
this.participantMuteUI(tracks,tracks.isEnabled ? '1' : '0')
},0)
// setTimeout(()=>{
// console.log("Remote video size",this.remoteVideo.nativeElement.offsetHeight,this.remoteVideo)
// if(this.remoteVideo.nativeElement.offsetHeight < 350) {
// // this.remoteVideo.nativeElement.style.marginTop = '0px'
// // this.renderer.setStyle(element,'object-fit','fill');
// }
// },5000)
this.btnSubject.next({name:"peerVideoEnable",id:'1',value:true})
}
@ -342,12 +421,33 @@ console.log("Room participants", this.roomParticipants,this.roomObj)
console.log("Local Video",this.roomObj.localParticipant)
this.roomObj.localParticipant.videoTracks.forEach(publication => {
const element = publication.track.attach();
const divEle = this.renderer.createElement('div')
this.renderer.setAttribute(divEle,'class','video-wrapper my-video')
this.renderer.data.id = publication.track.sid;
this.renderer.setStyle(element, 'width', '100%');
if(publication.track.kind == 'video') {
this.renderer.setAttribute(element,'class','inner')
}
this.renderer.appendChild(this.localVideo.nativeElement, element);
this.renderer.appendChild(divEle,element)
const pEle = this.renderer.createElement('div')
this.renderer.setAttribute(pEle,'class','identity-name')
const spanEle = this.renderer.createElement('p');
this.renderer.setAttribute(spanEle,'class','praticipant-name')
spanEle.innerHTML = "You"
this.renderer.appendChild(pEle,spanEle)
this.renderer.appendChild(divEle,pEle)
// const pEle = this.renderer.createElement('p')
// this.renderer.setAttribute(pEle,'class','praticipant-name')
// pEle.innerHTML = "You"
// this.renderer.setAttribute(pEle,'class','identity-name')
this.renderer.appendChild(this.remoteVideo.nativeElement, divEle);
this.btnSubject.next({name:"is_video_enable",id:'1',value:true})
this.msgSubject.next("Waiting for participant...")
})

View File

@ -189,14 +189,14 @@
overflow-x: hidden;
overflow-y: auto;
position: relative;
padding: 1.5rem;
padding: 0;
background: #eeeeee;
// margin-bottom: 2rem;
}
@media(max-width:991px) {
.body-container {
padding: 0.5rem;
padding: 0;
}
html {
font-size: 14px;