Skip to content

Commit 6c3a6f6

Browse files
authored
Merge pull request #197446 from chriswhilar/patch-40
Update video-calling-javascript.md
2 parents b28e0f1 + 4e1da4a commit 6c3a6f6

File tree

1 file changed

+116
-38
lines changed

1 file changed

+116
-38
lines changed

articles/communication-services/quickstarts/voice-video-calling/includes/video-calling/video-calling-javascript.md

Lines changed: 116 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,17 @@ This quickstart uses webpack to bundle the application assets. Run the following
3939
```console
4040
4141
```
42-
Create an `index.html` file in the root directory of your project. We'll use this file to configure a basic layout that will allow the user to place a 1:1 video call.
4342

4443
Here's the code:
44+
45+
Create an `index.html` file in the root directory of your project. We'll use this file to configure a basic layout that will allow the user to place a 1:1 video call.
4546
```html
4647
<!-- index.html -->
4748
<!DOCTYPE html>
4849
<html>
4950
<head>
5051
<title>Azure Communication Services - Calling Web SDK</title>
52+
<link rel="stylesheet" type="text/css" href="styles.css"/>
5153
</head>
5254
<body>
5355
<h4>Azure Communication Services - Calling Web SDK</h4>
@@ -71,7 +73,7 @@ Here's the code:
7173
<br>
7274
<div id="connectedLabel" style="color: #13bb13;" hidden>Call is connected!</div>
7375
<br>
74-
<div id="remoteVideoContainer" style="width: 40%;" hidden>Remote participants' video streams:</div>
76+
<div id="remoteVideosGallery" style="width: 40%;" hidden>Remote participants' video streams:</div>
7577
<br>
7678
<div id="localVideoContainer" style="width: 30%;" hidden>Local video stream:</div>
7779
<!-- points to the bundle generated from client.js -->
@@ -80,8 +82,6 @@ Here's the code:
8082
</html>
8183
```
8284

83-
## Azure Communication Services Calling Web SDK Object model
84-
8585
The following classes and interfaces handle some of the major features of the Azure Communication Services Calling SDK:
8686

8787
| Name | Description |
@@ -125,7 +125,7 @@ let acceptCallButton = document.getElementById('accept-call-button');
125125
let startVideoButton = document.getElementById('start-video-button');
126126
let stopVideoButton = document.getElementById('stop-video-button');
127127
let connectedLabel = document.getElementById('connectedLabel');
128-
let remoteVideoContainer = document.getElementById('remoteVideoContainer');
128+
let remoteVideosGallery = document.getElementById('remoteVideosGallery');
129129
let localVideoContainer = document.getElementById('localVideoContainer');
130130

131131
/**
@@ -197,8 +197,10 @@ acceptCallButton.onclick = async () => {
197197
}
198198
}
199199

200-
// Subscribe to a call obj.
201-
// Listen for property changes and collection updates.
200+
/**
201+
* Subscribe to a call obj.
202+
* Listen for property changes and collection updates.
203+
*/
202204
subscribeToCall = (call) => {
203205
try {
204206
// Inspect the initial call.id value.
@@ -220,6 +222,7 @@ subscribeToCall = (call) => {
220222
hangUpCallButton.disabled = false;
221223
startVideoButton.disabled = false;
222224
stopVideoButton.disabled = false;
225+
remoteVideosGallery.hidden = false;
223226
} else if (call.state === 'Disconnected') {
224227
connectedLabel.hidden = true;
225228
startCallButton.disabled = false;
@@ -265,8 +268,10 @@ subscribeToCall = (call) => {
265268
}
266269
}
267270

268-
// Subscribe to a remote participant obj.
269-
// Listen for property changes and collection udpates.
271+
/**
272+
* Subscribe to a remote participant obj.
273+
* Listen for property changes and collection udpates.
274+
*/
270275
subscribeToRemoteParticipant = (remoteParticipant) => {
271276
try {
272277
// Inspect the initial remoteParticipant.state value.
@@ -304,43 +309,72 @@ subscribeToRemoteParticipant = (remoteParticipant) => {
304309
* you can choose to destroy the whole 'Renderer', a specific 'RendererView' or keep them, but this will result in displaying blank video frame.
305310
*/
306311
subscribeToRemoteVideoStream = async (remoteVideoStream) => {
307-
// Create a video stream renderer for the remote video stream.
308-
let videoStreamRenderer = new VideoStreamRenderer(remoteVideoStream);
312+
let renderer = new VideoStreamRenderer(remoteVideoStream);
309313
let view;
310-
const renderVideo = async () => {
314+
let remoteVideoContainer = document.createElement('div');
315+
remoteVideoContainer.className = 'remote-video-container';
316+
317+
/**
318+
* isReceiving API is currently an @alpha feature. Do not use in production.
319+
* To use this api please use 'alpha' release of Azure Communication Services Calling Web SDK.
320+
* Create a CSS class to style your loading spinner. Take a look at our
321+
* video calling quickstart, to see how to create a loading spinner.
322+
*
323+
let loadingSpinner = document.createElement('div');
324+
loadingSpinner.className = 'loading-spinner';
325+
remoteVideoStream.on('isReceivingChanged', () => {
311326
try {
312-
// Create a renderer view for the remote video stream.
313-
view = await videoStreamRenderer.createView();
314-
// Attach the renderer view to the UI.
315-
remoteVideoContainer.hidden = false;
316-
remoteVideoContainer.appendChild(view.target);
327+
if (remoteVideoStream.isAvailable) {
328+
const isReceiving = remoteVideoStream.isReceiving;
329+
const isLoadingSpinnerActive = remoteVideoContainer.contains(loadingSpinner);
330+
if (!isReceiving && !isLoadingSpinnerActive) {
331+
remoteVideoContainer.appendChild(loadingSpinner);
332+
} else if (isReceiving && isLoadingSpinnerActive) {
333+
remoteVideoContainer.removeChild(loadingSpinner);
334+
}
335+
}
317336
} catch (e) {
318-
console.warn(`Failed to createView, reason=${e.message}, code=${e.code}`);
319-
}
337+
console.error(e);
338+
}
339+
});
340+
*/
341+
342+
const createView = async () => {
343+
// Create a renderer view for the remote video stream.
344+
view = await renderer.createView();
345+
// Attach the renderer view to the UI.
346+
remoteVideoContainer.appendChild(view.target);
347+
remoteVideosGallery.appendChild(remoteVideoContainer);
320348
}
321-
322-
remoteVideoStream.on('isAvailableChanged', async () => {
323-
// Participant has switched video on.
324-
if (remoteVideoStream.isAvailable) {
325-
await renderVideo();
326349

327-
// Participant has switched video off.
328-
} else {
329-
if (view) {
350+
// Remote participant has switched video on/off
351+
remoteVideoStream.on('isAvailableChanged', async () => {
352+
try {
353+
if (remoteVideoStream.isAvailable) {
354+
await createView();
355+
} else {
330356
view.dispose();
331-
view = undefined;
357+
remoteVideosGallery.removeChild(remoteVideoContainer);
332358
}
359+
} catch (e) {
360+
console.error(e);
333361
}
334362
});
335363

336-
// Participant has video on initially.
364+
// Remote participant has video on initially.
337365
if (remoteVideoStream.isAvailable) {
338-
await renderVideo();
366+
try {
367+
await createView();
368+
} catch (e) {
369+
console.error(e);
370+
}
339371
}
340372
}
341373

342-
// Start your local video stream.
343-
// This will send your local video stream to remote participants so they can view it.
374+
/**
375+
* Start your local video stream.
376+
* This will send your local video stream to remote participants so they can view it.
377+
*/
344378
startVideoButton.onclick = async () => {
345379
try {
346380
const localVideoStream = await createLocalVideoStream();
@@ -350,8 +384,10 @@ startVideoButton.onclick = async () => {
350384
}
351385
}
352386

353-
// Stop your local video stream.
354-
// This will stop your local video stream from being sent to remote participants.
387+
/**
388+
* Stop your local video stream.
389+
* This will stop your local video stream from being sent to remote participants.
390+
*/
355391
stopVideoButton.onclick = async () => {
356392
try {
357393
await call.stopVideo(localVideoStream);
@@ -365,7 +401,6 @@ stopVideoButton.onclick = async () => {
365401
* create a new VideoStreamRendererView instance using the asynchronous createView() method.
366402
* You may then attach view.target to any UI element.
367403
*/
368-
// Create a local video stream for your camera device
369404
createLocalVideoStream = async () => {
370405
const camera = (await deviceManager.getCameras())[0];
371406
if (camera) {
@@ -374,7 +409,10 @@ createLocalVideoStream = async () => {
374409
console.error(`No camera device found on the system`);
375410
}
376411
}
377-
// Display your local video stream preview in your UI
412+
413+
/**
414+
* Display your local video stream preview in your UI
415+
*/
378416
displayLocalVideoStream = async () => {
379417
try {
380418
localVideoStreamRenderer = new VideoStreamRenderer(localVideoStream);
@@ -385,7 +423,10 @@ displayLocalVideoStream = async () => {
385423
console.error(error);
386424
}
387425
}
388-
// Remove your local video stream preview from your UI
426+
427+
/**
428+
* Remove your local video stream preview from your UI
429+
*/
389430
removeLocalVideoStream = async() => {
390431
try {
391432
localVideoStreamRenderer.dispose();
@@ -395,13 +436,50 @@ removeLocalVideoStream = async() => {
395436
}
396437
}
397438

398-
// End the current call
439+
/**
440+
* End current call
441+
*/
399442
hangUpCallButton.addEventListener("click", async () => {
400443
// end the current call
401444
await call.hangUp();
402445
});
403446
```
404447

448+
Create a file in the root directory of your project called `styles.css` to contain the application styling for this quickstart. Add the following code to styles.css:
449+
```css
450+
/**
451+
* CSS for styling the loading spinner over the remote video stream
452+
*/
453+
.remote-video-container {
454+
position: relative;
455+
}
456+
.loading-spinner {
457+
border: 12px solid #f3f3f3;
458+
border-radius: 50%;
459+
border-top: 12px solid #ca5010;
460+
width: 100px;
461+
height: 100px;
462+
-webkit-animation: spin 2s linear infinite; /* Safari */
463+
animation: spin 2s linear infinite;
464+
position: absolute;
465+
margin: auto;
466+
top: 0;
467+
bottom: 0;
468+
left: 0;
469+
right: 0;
470+
transform: translate(-50%, -50%);
471+
}
472+
@keyframes spin {
473+
0% { transform: rotate(0deg); }
474+
100% { transform: rotate(360deg); }
475+
}
476+
/* Safari */
477+
@-webkit-keyframes spin {
478+
0% { -webkit-transform: rotate(0deg); }
479+
100% { -webkit-transform: rotate(360deg); }
480+
}
481+
```
482+
405483
## Run the code
406484
Use the `webpack-dev-server` to build and run your app. Run the following command to bundle the application host in a local webserver:
407485

0 commit comments

Comments
 (0)