Quick Start for Conference in Angular 2
VideoSDK enables you to embed the video calling feature into your Angular 2 application in minutes.
In this quickstart, we are going to explore group calling feature of Video SDK. We will go through step by step guide of integrating video calling with Angular 2 Video SDK.
This guide will get you running with the VideoSDK video & audio calling in minutes.
Prerequisites
Before proceeding, ensure that your development environment meets the following requirements:
- Video SDK Developer Account (Not having one, follow Video SDK Dashboard)
- Have Node and NPM installed on your device.
One should have a VideoSDK account to generate token. Visit VideoSDK dashboard to generate token
Getting Started with the Code!
Follow the steps to create the environment necessary to add video calls into your app. Also you can find the code sample for quickstart here.
Install Video SDK
You can import VideoSDK using <script>
tag or you can install the VideoSDK using the below-mentioned npm command. Make sure you are in your app directory before you run this command.
- <script>
- npm
- yarn
<html>
<head>
....
</head>
<body>
.....
<script src="https://sdk.videosdk.live/js-sdk/0.0.67/videosdk.js"></script>
</body>
</html>
npm install @videosdk.live/js-sdk
yarn add @videosdk.live/js-sdk
Structure of the project
Your project structure should look like this.
root
├── node_modules
├── src
│ ├── app
│ ├── join-screen
│ ├── join-screen.component.html
│ ├── join-screen.component.ts
│ ├── top-bar
│ ├── top-bar.component.html
│ ├── top-bar.component.ts
│ ├── app-routing.module.ts // Default
│ ├── app.component.html // Default
│ ├── app.component.ts // Default
│ ├── app.module.ts // Default
│ ├── meeting.service.ts
│ ├── enviroments
│ ├── enviroment.ts
│ ├── styles.css // Default
│ ├── index.html // Default
We are going to work on following files:
- enviroment.ts: Responsible to store token.
- meeting.service.ts: Responsible to handle API calls such as generating unique meetingId, validate meetingId and token.
- join-screen.component.html: Responsible to create basic UI for joinScreen.
- top-bar.component.html: Responsible to create basic topbar with webcam,mic and leave meeting button.
- app.component.html: Responsible for render
Joinscreen
,Topbar
andParticipantGrid
. - join-screen.component.ts: Responsible for handling the logic and functionality related to the
join-screen.component.html
template. - top-bar.component.ts : Responsible for handling the logic and functionality related to the
top-bar.component.html
template. - app.component.ts: Responsible for handling
joinMeeting
,createMeeting
, handle meeting and participant related events and renderjoin-screen
,top-bar
andparticipantGrid
.
Step 1 : Get started with Meeting.service.ts
Prior to moving on, we must create an API request to generate unique meetingId and validated meetingId. You will need an authentication token, which you can create either through the videosdk-rtc-api-server-examples or directly from the VideoSDK Dashboard for developers.
Set token in enviroment.ts
file which is generated from VideoSDK Dashbord.
// We will use Auth token to generate a meetingId and connect to it
export const environment = {
token: "YOUR_TOKEN_HERE",
};
import { Injectable } from "@angular/core";
import { HttpClient, HttpHeaders } from "@angular/common/http";
import { Observable } from "rxjs";
import { map } from "rxjs/operators";
import { environment } from "src/enviroments/enviroment";
@Injectable({
providedIn: "root",
})
export class MeetingService {
private authToken = environment.token;
constructor(private http: HttpClient) {}
createMeeting(): Observable<string> {
const apiUrl = "https://api.videosdk.live/v2/rooms";
const headers = new HttpHeaders({
authorization: this.authToken,
"Content-Type": "application/json",
});
return this.http
.post<{ roomId: string }>(apiUrl, {}, { headers })
.pipe(map((response) => response.roomId));
}
validateMeeting(meetingId: string): Observable<boolean> {
const url = `https://api.videosdk.live/v2/rooms/validate/${meetingId}`;
const headers = new HttpHeaders({
authorization: this.authToken,
"Content-Type": "application/json",
});
return this.http
.get<{ roomId: string }>(url, {
headers,
})
.pipe(map((response) => response.roomId === meetingId));
}
ngOnInit() {}
}
- After creating meeting service we will import it to
app.module.ts
.
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
import { AppRoutingModule } from "./app-routing.module";
import { AppComponent } from "./app.component";
import { JoinScreenComponent } from "./join-screen/join-screen.component";
import { TopBarComponent } from "./top-bar/top-bar.component";
import { MeetingService } from "./meeting.service";
import { HttpClientModule } from "@angular/common/http";
import { FormsModule } from "@angular/forms";
@NgModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA],
declarations: [AppComponent, JoinScreenComponent, TopBarComponent],
imports: [BrowserModule, AppRoutingModule, HttpClientModule, FormsModule],
providers: [MeetingService],
bootstrap: [AppComponent],
})
export class AppModule {}
Step 2 : Create UI
In this step, we are going to create HTML file which will render join-screen
and top-bar
.
- First we will create
joinScreen
UI.
<div id="joinPage" class="main-bg" style="display: flex">
<div style="display: flex; flex-direction: column">
<h3>Angular 2 quickstart with Videosdk</h3>
<form name="myForm" style="display: flex">
<button (click)="fireCreateMeeting()">Create a meeting</button>
<p
style="
margin-left: 8px;
margin-right: 8px;
font-size: 14px;
margin-top: 2px;
margin-bottom: 0px;
"
>
OR
</p>
<input
name="meetingId"
type="text"
placeholder="Enter meeting id"
[(ngModel)]="meetingId"
/>
<button (click)="fireValidateMeeting()" style="margin-left: 8px">
Join a meeting
</button>
</form>
</div>
</div>
Output

- After joinScreen we will create
topBar
UI.
<div
style="height: 70px; background-color: lightgray"
ng-controller="myController"
ng-show="showMeetingScreen"
id="top-bar"
>
<div class="top-bar-div">
<div>
<p style="margin-top: 0px; margin-bottom: 0px; font-weight: 700">
MeetingId: {{meetingId}}
</p>
</div>
<div style="display: flex; align-items: center; margin-top: 8px">
<button style="cursor: pointer" ng-click="toggleWebcam()">
Toggle Webcam
</button>
<button style="margin-left: 4px; cursor: pointer" ng-click="toggleMic()">
Toggle Mic
</button>
<button class="leave-btn" ng-click="leaveMeeting()">Leave Meeting</button>
</div>
</div>
</div>
Output

- Now, we will place
join-screen
andtop-bar
component in one file calledapp.component.html
and createmeeting-container
here.
<div *ngIf="showJoinScreen">
<!-- join-screen Start -->
<app-join-screen></app-join-screen>
<!-- join-screen End -->
</div>
<div *ngIf="showMeetingScreen">
<!-- topbar Start -->
<app-top-bar></app-top-bar>
<!-- topbar End -->
<!-- Meeting Container -->
<div
style="
display: flex;
flex-direction: column;
overflow-y: auto;
max-height: calc(100vh - 85px);
"
>
<div class="container">
<div
#participantGridContainer
id="participant-grid-container"
class="row"
></div>
</div>
</div>
</div>
<router-outlet></router-outlet>
Step 3 : Implement Join Screen
In this step, we will implement createMeeting
and validateMeeting
function in app.component.ts
to call respective APIs.
import { Component, ElementRef, Renderer2, ViewChild } from "@angular/core";
import { VideoSDK } from "@videosdk.live/js-sdk";
import { environment } from "./../enviroments/enviroment";
import { MeetingService } from "./meeting.service";
@Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"],
})
export class AppComponent {
title = "videosdk_angular_2_quickstart";
meeting: any;
participantName: string = "";
meetingId: string = "";
showJoinScreen: boolean = true;
showMeetingScreen: boolean = false;
showTopBar: boolean = false;
constructor(
private renderer: Renderer2,
private meetingService: MeetingService
) {
this.participantName = "Homi J. Bhabha";
}
createMeeting() {
this.meetingService.createMeeting().subscribe(
(roomId) => {
this.meetingId = roomId;
this.joinMeeting();
},
(error) => {
console.error("Failed to create meeting:", error);
}
);
}
validateMeeting(meetingId: any) {
this.meetingService.validateMeeting(meetingId).subscribe(
(isValid) => {
if (isValid) {
this.meetingId = meetingId;
this.joinMeeting();
} else {
alert("Invalid meeting id");
}
},
(error) => {
console.error("Failed to validate meeting:", error);
// Handle the error
}
);
}
}
- After creating function we pass this function in
join-screen
component this way
<div *ngIf="showJoinScreen">
<app-join-screen
(validateMeeting)="validateMeeting($event)"
(createMeeting)="createMeeting()"
></app-join-screen>
</div>
- Now in
join-screen.component.ts
we fire this function.
import { Component, EventEmitter, Input, Output } from "@angular/core";
@Component({
selector: "app-join-screen",
templateUrl: "./join-screen.component.html",
styleUrls: ["./join-screen.component.css"],
})
export class JoinScreenComponent {
@Output() createMeeting = new EventEmitter();
@Output() validateMeeting = new EventEmitter<string>();
@Input() meetingId: string = "";
fireValidateMeeting() {
this.validateMeeting.emit(this.meetingId);
}
fireCreateMeeting() {
this.createMeeting.emit();
}
constructor() {}
ngOnInit() {}
}
Step 4 : Initialize meeting
In this step, we will initialize meeting through initMeeting()
function and join that meeting.
// Initialize meeting
async initMeeting() {
VideoSDK.config(environment.token);
this.meeting = VideoSDK.initMeeting({
meetingId: this.meetingId, // required
name: this.participantName, // required
micEnabled: true, // optional, default: true
webcamEnabled: true, // optional, default: true
});
}
joinMeeting() {
this.initMeeting();
this.meeting.join();
this.handleMeetingEvents(this.meeting);
const showJoinScreenMessage = this.renderer.createElement("div");
this.renderer.setAttribute(
showJoinScreenMessage,
"id",
"show-join-screen-message"
);
this.renderer.setProperty(
showJoinScreenMessage,
"innerHTML",
"Please wait to join meeting..."
);
this.renderer.setStyle(showJoinScreenMessage, "color", "black");
this.renderer.setStyle(showJoinScreenMessage, "fontSize", "20px");
this.renderer.setStyle(showJoinScreenMessage, "fontWeight", "bold");
this.renderer.setStyle(showJoinScreenMessage, "marginTop", "20px");
this.renderer.setStyle(showJoinScreenMessage, "marginLeft", "20px");
this.renderer.appendChild(document.body, showJoinScreenMessage);
}
// for handle meeting events
handleMeetingEvents(meeting: any) {}
Output

Step 5: Handle Meeting Events
In this step, we will create participant grid and handle events like meeting-joined
, meeting-left
and participant events.
export class AppComponent {
handleMeetingEvents(meeting: any) {
this.localParticipant = meeting.localParticipant;
this.participants = meeting.participants;
if (meeting) {
this.showJoinScreen = false;
this.showMeetingScreen = true;
}
// meeting joined event
meeting.on("meeting-joined", () => {
var showJoinScreenMessage = document.getElementById(
"show-join-screen-message"
);
this.renderer.removeChild(document.body, showJoinScreenMessage);
const { participantMediaElement } = this.participantGridGenerator(
this.meeting.localParticipant
);
this.showTopBar = true;
meeting.localParticipant.on("stream-enabled", (stream: any) => {
console.log("Stream Enabled: ");
this.handleStreamEnabled(
stream,
meeting.localParticipant,
true,
participantMediaElement
);
});
meeting.localParticipant.on("stream-disabled", (stream: any) => {
console.log("Stream Disabled: ");
this.handleStreamDisabled(
stream,
meeting.localParticipant,
true,
participantMediaElement
);
});
});
// meeting left event
meeting.on("meeting-left", () => {
while (this.participantGridContainer.nativeElement.firstChild) {
this.participantGridContainer.nativeElement.removeChild(
this.participantGridContainer.nativeElement.firstChild
);
}
this.showMeetingScreen = false;
this.showJoinScreen = true;
});
//remote participant events
// participant joined
meeting.on("participant-joined", (participant) => {
console.log("New Participant Joined: ", participant.id);
participant.on("stream-enabled", (stream) => {
//...
});
participant.on("stream-disabled", (stream) => {
//...
});
});
// participant left
meeting.on("participant-left", (participant) => {
//...
});
}
}
Step 6 : Create Media Elements
In this step, we will create a function that helps us to create audio and video elements for displaying local and remote participants. We will also set the appropriate media track based on whether it's a video or audio.
export class AppComponent {
isWebcamOn: boolean = true;
isMicOn: boolean = true;
// creating video element
createVideoElement(
stream: any,
participant: any,
participantMediaElement: any
) {
const video = this.renderer.createElement("video");
const mediaStream = new MediaStream();
mediaStream.addTrack(stream.track);
this.renderer.setAttribute(video, "id", `v-${participant.id}`);
this.renderer.setAttribute(video, "autoplay", "true");
this.renderer.setAttribute(video, "playsinline", "true");
this.renderer.setAttribute(video, "muted", "true");
this.renderer.setAttribute(
video,
"style",
"width: 100%; height: 100%;position: absolute;top: 0;left: 0;object-fit: cover;"
);
this.renderer.setProperty(video, "srcObject", mediaStream);
const videoElement = this.renderer.createElement("div");
this.renderer.setAttribute(
videoElement,
"id",
`video-container-${participant.id}`
);
this.renderer.setAttribute(
videoElement,
"style",
"width: 100%; height: 100%;"
);
this.renderer.setStyle(videoElement, "position", "relative");
this.renderer.appendChild(participantMediaElement, videoElement);
this.renderer.appendChild(videoElement, video);
const cornerDisplayName = this.renderer.createElement("div");
this.renderer.setAttribute(
cornerDisplayName,
"id",
`name-container-${participant.id}`
);
this.renderer.setStyle(cornerDisplayName, "position", "absolute");
this.renderer.setStyle(cornerDisplayName, "bottom", "16px");
this.renderer.setStyle(cornerDisplayName, "left", "16px");
this.renderer.setStyle(cornerDisplayName, "color", "white");
this.renderer.setStyle(
cornerDisplayName,
"backgroundColor",
"rgba(0, 0, 0, 0.5)"
);
this.renderer.setStyle(cornerDisplayName, "padding", "2px");
this.renderer.setStyle(cornerDisplayName, "borderRadius", "2px");
this.renderer.setStyle(cornerDisplayName, "fontSize", "12px");
this.renderer.setStyle(cornerDisplayName, "fontWeight", "bold");
this.renderer.setStyle(cornerDisplayName, "zIndex", "1");
this.renderer.setStyle(cornerDisplayName, "padding", "4px");
cornerDisplayName.innerHTML =
participant.displayName.length > 15
? participant.displayName.substring(0, 15) + "..."
: participant.displayName;
this.renderer.appendChild(videoElement, cornerDisplayName);
}
// creating audio element
createAudioElement(
stream: any,
participant: any,
participantMediaElement: any
) {
const audio = this.renderer.createElement("audio");
const mediaStream = new MediaStream();
mediaStream.addTrack(stream.track);
this.renderer.setAttribute(audio, "id", `audio-${participant.id}`);
this.renderer.setAttribute(audio, "autoplay", "true");
this.renderer.setAttribute(audio, "playsinline", "true");
this.renderer.setAttribute(audio, "muted", "true");
this.renderer.setProperty(audio, "srcObject", mediaStream);
const audioElement = this.renderer.createElement("div");
this.renderer.setAttribute(
audioElement,
"id",
`audio-container-${participant.id}`
);
this.renderer.appendChild(participantMediaElement, audioElement);
this.renderer.appendChild(audioElement, audio);
}
// creating name element
createNameElemeent(participant: any) {
var nameElement = this.renderer.createElement("div");
this.renderer.setAttribute(
nameElement,
"id",
`name-container-${participant.id}`
);
nameElement.innerHTML = participant.displayName.charAt(0).toUpperCase();
this.renderer.setStyle(nameElement, "backgroundColor", "black");
this.renderer.setStyle(nameElement, "color", "white");
this.renderer.setStyle(nameElement, "textAlign", "center");
this.renderer.setStyle(nameElement, "padding", "32px");
this.renderer.setStyle(nameElement, "borderRadius", "100%");
this.renderer.setStyle(nameElement, "fontSize", "20px");
return nameElement;
}
// handle streams
handleStreamEnabled(
stream: any,
participant: any,
isLocal: any,
participantMediaElement: any
) {
if (stream.kind == "video") {
var nameElement = document.getElementById(
`name-container-${participant.id}`
);
participantMediaElement.removeChild(nameElement);
this.createVideoElement(stream, participant, participantMediaElement);
}
if (!isLocal) {
if (stream.kind == "audio") {
this.createAudioElement(stream, participant, participantMediaElement);
}
}
}
handleStreamDisabled(
stream: any,
participant: any,
isLocal: any,
participantMediaElement: any
) {
if (stream.kind == "video") {
var videoElement = document.getElementById(
`video-container-${participant.id}`
);
var nameElement = this.createNameElemeent(participant);
this.renderer.removeChild(participantMediaElement, videoElement);
this.renderer.appendChild(participantMediaElement, nameElement);
}
if (!isLocal) {
if (stream.kind == "audio") {
var audioElement = document.getElementById(
`audio-container-${participant.id}`
);
this.renderer.removeChild(participantMediaElement, audioElement);
}
}
}
// generate participant grid
participantGridGenerator(participant: any) {
var participantGridItem = this.renderer.createElement("div");
this.renderer.setStyle(participantGridItem, "backgroundColor", "lightgrey");
this.renderer.setStyle(participantGridItem, "borderRadius", "10px");
this.renderer.setStyle(participantGridItem, "aspectRatio", 16 / 9);
this.renderer.setStyle(participantGridItem, "width", "360px");
this.renderer.setStyle(participantGridItem, "marginTop", "8px");
this.renderer.setStyle(participantGridItem, "display", "flex");
this.renderer.setStyle(participantGridItem, "alignItems", "center");
this.renderer.setStyle(participantGridItem, "justifyContent", "center");
this.renderer.setStyle(participantGridItem, "overflow", "hidden");
this.renderer.setAttribute(
participantGridItem,
"id",
`participant-grid-item-${participant.id}`
);
this.renderer.setAttribute(participantGridItem, "class", "col-4");
var participantMediaElement = this.renderer.createElement("div");
this.renderer.setAttribute(
participantMediaElement,
"id",
`participant-media-container-${participant.id}`
);
this.renderer.setStyle(participantMediaElement, "position", "relative");
this.renderer.setStyle(participantMediaElement, "width", "100%");
this.renderer.setStyle(participantMediaElement, "height", "100%");
this.renderer.setStyle(participantMediaElement, "display", "flex");
this.renderer.setStyle(participantMediaElement, "alignItems", "center");
this.renderer.setStyle(participantMediaElement, "justifyContent", "center");
var nameElement = this.createNameElemeent(participant);
this.renderer.appendChild(
this.participantGridContainer.nativeElement,
participantGridItem
);
this.renderer.appendChild(participantGridItem, participantMediaElement);
this.renderer.appendChild(participantMediaElement, nameElement);
var getParticipantMediaElement = document.getElementById(
`participant-media-container-${participant.id}`
);
return {
getParticipantMediaElement,
};
}
}
Step 7 : Handle participant events
In this step, we will implement four events participant-joined
, participant-left
, stream-enabled
and stream-disabled
.
Let's understand the use of that events.
participant-joined
: When a remote participant joins, this event will trigger. In event callback will create video and audio elements which we had define in previous steps for rendering their video and audio streams.participant-left
: When a remote participant leaves, this event will trigger. In event callback will remove the corresponding video and audio elements.stream-enabled
: It Handle the media track of a specific participant by associating it with the appropriate video or audio element.stream-disabled
: It Handle the media track of a specific participant when participant toogle video or audio by associating it with the appropriate video or audio element.
// participant joined
//remote participant
meeting.on("participant-joined", (participant: any) => {
console.log("New Participant Joined: ", participant.id);
var { getParticipantMediaElement } =
this.participantGridGenerator(participant);
participant.setQuality("high");
participant.on("stream-enabled", (stream: any) => {
this.handleStreamEnabled(
stream,
participant,
false,
getParticipantMediaElement
);
});
participant.on("stream-disabled", (stream: any) => {
this.handleStreamDisabled(
stream,
participant,
false,
getParticipantMediaElement
);
});
});
// participants left
meeting.on("participant-left", (participant: any) => {
console.log("Participant Left: ", participant.id);
var participantGridItem = document.getElementById(
`participant-grid-item-${participant.id}`
);
this.participantGridContainer.nativeElement.removeChild(participantGridItem);
});
Output

Step 8 : Implement Controls
In this step, we will implement meeting functionalities such as toggleMic, toggleWebcam and leave meeting function in app.component.ts
to call respective APIs.
export class AppComponent {
//..
toogleWebcam() {
if (this.isWebcamOn) {
this.meeting.disableWebcam();
} else {
this.meeting.enableWebcam();
}
this.isWebcamOn = !this.isWebcamOn;
}
toogleMic() {
if (this.isMicOn) {
this.meeting.muteMic();
} else {
this.meeting.unmuteMic();
}
this.isMicOn = !this.isMicOn;
}
leaveMeeting() {
this.meeting.leave();
this.showMeetingScreen = false;
this.showJoinScreen = true;
}
}
- After creating function we pass this function in
top-bar
component this way
<app-top-bar
[meetingId]="meetingId"
[showTopBar]="showTopBar"
(toogleWebcam)="toogleWebcam()"
(toogleMic)="toogleMic()"
(leaveMeeting)="leaveMeeting()"
></app-top-bar>
- Now in
top-bar.component.ts
we fire this function.
import { Component, EventEmitter, Input, Output } from "@angular/core";
@Component({
selector: "app-top-bar",
templateUrl: "./top-bar.component.html",
})
export class TopBarComponent {
@Input() showTopBar: boolean = false;
@Output() toogleWebcam = new EventEmitter();
@Output() toogleMic = new EventEmitter();
@Output() leaveMeeting = new EventEmitter();
@Input() meetingId: string = "";
constructor() {}
fireToggleWebcam() {
this.toogleWebcam.emit();
}
fireToggleMic() {
this.toogleMic.emit();
}
fireLeaveMeeting() {
this.leaveMeeting.emit();
}
}
Run your code
Once you are all set with the steps mentioned above run your application as mentioned in the code-block below.
ng serve
Final Output
We are done with implementation of customised video calling app in Angular JS using Video SDK. To explore more features go through Basic and Advanced features.
You can checkout the complete quick start example here.
Got a Question? Ask us on discord