@@ -159,38 +159,67 @@ Whenever availability of a remote stream changes you can choose to destroy the w
159
159
or keep them, but this will result in displaying blank video frame.
160
160
161
161
``` js
162
+ // Reference to the html's div where we would display a grid of all remote video stream from all participants.
163
+ let remoteVideosGallery = document .getElementById (' remoteVideosGallery' );
164
+
162
165
subscribeToRemoteVideoStream = async (remoteVideoStream ) => {
163
- // Create a video stream renderer for the remote video stream.
164
- let videoStreamRenderer = new VideoStreamRenderer (remoteVideoStream);
166
+ let renderer = new VideoStreamRenderer (remoteVideoStream);
165
167
let view;
166
- const remoteVideoContainer = document .getElementById (' remoteVideoContainer' );
167
- const renderVideo = async () => {
168
+ let remoteVideoContainer = document .createElement (' div' );
169
+ remoteVideoContainer .className = ' remote-video-container' ;
170
+
171
+ /**
172
+ * isReceiving API is currently an @alpha feature. Do not use in production.
173
+ * To use this api please use 'alpha' release of Azure Communication Services Calling Web SDK.
174
+ */
175
+ let loadingSpinner = document .createElement (' div' );
176
+ // See the css example below for styling the loading spinner.
177
+ loadingSpinner .className = ' loading-spinner' ;
178
+ remoteVideoStream .on (' isReceivingChanged' , () => {
168
179
try {
169
- // Create a renderer view for the remote video stream.
170
- view = await videoStreamRenderer .createView ();
171
- // Attach the renderer view to the UI.
172
- remoteVideoContainer .appendChild (view .target );
180
+ if (remoteVideoStream .isAvailable ) {
181
+ const isReceiving = remoteVideoStream .isReceiving ;
182
+ const isLoadingSpinnerActive = remoteVideoContainer .contains (loadingSpinner);
183
+ if (! isReceiving && ! isLoadingSpinnerActive) {
184
+ remoteVideoContainer .appendChild (loadingSpinner);
185
+ } else if (isReceiving && isLoadingSpinnerActive) {
186
+ remoteVideoContainer .removeChild (loadingSpinner);
187
+ }
188
+ }
173
189
} catch (e) {
174
- console .warn ( ` Failed to createView, reason= ${ e . message } , code= ${ e . code } ` );
190
+ console .error (e );
175
191
}
192
+ });
193
+
194
+ const createView = async () => {
195
+ // Create a renderer view for the remote video stream.
196
+ view = await renderer .createView ();
197
+ // Attach the renderer view to the UI.
198
+ remoteVideoContainer .appendChild (view .target );
199
+ remoteVideosGallery .appendChild (remoteVideoContainer);
176
200
}
177
- remoteVideoStream .on (' isAvailableChanged' , async () => {
178
- // Participant has switched video on.
179
- if (remoteVideoStream .isAvailable ) {
180
- await renderVideo ();
181
201
182
- // Participant has switched video off.
183
- } else {
184
- if (view) {
202
+ // Remote participant has switched video on/off
203
+ remoteVideoStream .on (' isAvailableChanged' , async () => {
204
+ try {
205
+ if (remoteVideoStream .isAvailable ) {
206
+ await createView ();
207
+ } else {
185
208
view .dispose ();
186
- view = undefined ;
209
+ remoteVideosGallery . removeChild (remoteVideoContainer) ;
187
210
}
211
+ } catch (e) {
212
+ console .error (e);
188
213
}
189
214
});
190
215
191
- // Participant has video on initially.
216
+ // Remote participant has video on initially.
192
217
if (remoteVideoStream .isAvailable ) {
193
- await renderVideo ();
218
+ try {
219
+ await createView ();
220
+ } catch (e) {
221
+ console .error (e);
222
+ }
194
223
}
195
224
196
225
console .log (` Initial stream size: height: ${ remoteVideoStream .size .height } , width: ${ remoteVideoStream .size .width } ` );
@@ -200,6 +229,38 @@ subscribeToRemoteVideoStream = async (remoteVideoStream) => {
200
229
}
201
230
```
202
231
232
+ CSS for styling the loading spinner over the remote video stream.
233
+ ``` css
234
+ .remote-video-container {
235
+ position : relative ;
236
+ }
237
+ .loading-spinner {
238
+ border : 12px solid #f3f3f3 ;
239
+ border-radius : 50% ;
240
+ border-top : 12px solid #ca5010 ;
241
+ width : 100px ;
242
+ height : 100px ;
243
+ -webkit-animation : spin 2s linear infinite ; /* Safari */
244
+ animation : spin 2s linear infinite ;
245
+ position : absolute ;
246
+ margin : auto ;
247
+ top : 0 ;
248
+ bottom : 0 ;
249
+ left : 0 ;
250
+ right : 0 ;
251
+ transform : translate (-50% , -50% );
252
+ }
253
+ @keyframes spin {
254
+ 0% { transform : rotate (0deg ); }
255
+ 100% { transform : rotate (360deg ); }
256
+ }
257
+ /* Safari */
258
+ @-webkit-keyframes spin {
259
+ 0% { -webkit-transform : rotate (0deg ); }
260
+ 100% { -webkit-transform : rotate (360deg ); }
261
+ }
262
+ ```
263
+
203
264
### Remote video stream properties
204
265
205
266
Remote video streams have the following properties:
@@ -222,6 +283,17 @@ const type: MediaStreamType = remoteVideoStream.mediaStreamType;
222
283
const isAvailable: boolean = remoteVideoStream .isAvailable ;
223
284
```
224
285
286
+ - ` isReceiving ` :
287
+ - *** This API is provided as a preview for developers and may change based on feedback that we receive. Do not use this API in a production environment. To use this api please use 'alpha' release of Azure Communication Services Calling Web SDK.***
288
+ - Will inform the application if remote video stream data is being received. Such cases are:
289
+ - When the remote mobile participant has their video on and they put the browser app in the background, they will stop sending video stream data until the app is brought back to the foreground.
290
+ - When the remote participant has their video on and they have bad network connectivity and video is cutting off / lagging
291
+ - This feature improves the user experience for rendering remote video streams.
292
+ - You can display a loading spinner over the remote video stream when isReceiving flag changes to false. You don't have to do a loading spinner, you can do anything you desire, but a loading spinner is the most common usage
293
+ ``` js
294
+ const isReceiving: boolean = remoteVideoStream .isReceiving ;
295
+ ```
296
+
225
297
- ` size ` : The stream size. The higher the stream size, the better the video quality.
226
298
227
299
``` js
0 commit comments