twilio-video 2.18.1 → 2.18.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -67,6 +67,12 @@ class RemoteVideoTrack extends RemoteMediaVideoTrack {
67
67
  _invisibleElements: {
68
68
  value: new WeakSet(),
69
69
  },
70
+ _elToPipCallbacks: {
71
+ value: new WeakMap(),
72
+ },
73
+ _elToPipWindows: {
74
+ value: new WeakMap(),
75
+ },
70
76
  _turnOffTimer: {
71
77
  value: new Timeout(() => {
72
78
  this._setRenderHint({ enabled: false });
@@ -165,6 +171,50 @@ class RemoteVideoTrack extends RemoteMediaVideoTrack {
165
171
  return this;
166
172
  }
167
173
 
174
+ _unObservePip(el) {
175
+ const pipCallbacks = this._elToPipCallbacks.get(el);
176
+ if (pipCallbacks) {
177
+ el.removeEventListener('enterpictureinpicture', pipCallbacks.onEnterPip);
178
+ el.removeEventListener('leavepictureinpicture', pipCallbacks.onLeavePip);
179
+ this._elToPipCallbacks.delete(el);
180
+ }
181
+ }
182
+
183
+ _observePip(el) {
184
+ const pipCallbacks = this._elToPipCallbacks.get(el);
185
+ if (!pipCallbacks) {
186
+ const onEnterPip = event => this._onEnterPip(event, el);
187
+ const onLeavePip = event => this._onLeavePip(event, el);
188
+ const onResizePip = event => this._onResizePip(event, el);
189
+
190
+ el.addEventListener('enterpictureinpicture', onEnterPip);
191
+ el.addEventListener('leavepictureinpicture', onLeavePip);
192
+ this._elToPipCallbacks.set(el, { onEnterPip, onLeavePip, onResizePip });
193
+ }
194
+ }
195
+
196
+ _onEnterPip(event, videoEl) {
197
+ this._log.debug('onEnterPip');
198
+ const pipWindow = event.pictureInPictureWindow;
199
+ this._elToPipWindows.set(videoEl, pipWindow);
200
+ const { onResizePip } = this._elToPipCallbacks.get(videoEl);
201
+ pipWindow.addEventListener('resize', onResizePip);
202
+ maybeUpdateEnabledHint(this);
203
+ }
204
+
205
+ _onLeavePip(event, videoEl) {
206
+ this._log.debug('onLeavePip');
207
+ this._elToPipWindows.delete(videoEl);
208
+ const { onResizePip } = this._elToPipCallbacks.get(videoEl);
209
+ const pipWindow = event.pictureInPictureWindow;
210
+ pipWindow.removeEventListener('resize', onResizePip);
211
+ maybeUpdateEnabledHint(this);
212
+ }
213
+
214
+ _onResizePip() {
215
+ maybeUpdateDimensionHint(this);
216
+ }
217
+
168
218
  attach(el) {
169
219
  const result = super.attach(el);
170
220
 
@@ -181,6 +231,7 @@ class RemoteVideoTrack extends RemoteMediaVideoTrack {
181
231
  this._documentVisibilityTurnOffCleanup = this._documentVisibilityTurnOffCleanup || setupDocumentVisibilityTurnOff(this);
182
232
  }
183
233
 
234
+ this._observePip(result);
184
235
  return result;
185
236
  }
186
237
 
@@ -191,6 +242,7 @@ class RemoteVideoTrack extends RemoteMediaVideoTrack {
191
242
  this._intersectionObserver.unobserve(element);
192
243
  this._resizeObserver.unobserve(element);
193
244
  this._invisibleElements.delete(element);
245
+ this._unObservePip(element);
194
246
  });
195
247
 
196
248
  if (this._attachments.size === 0) {
@@ -297,34 +349,42 @@ function setupDocumentVisibilityTurnOff(removeVideoTrack) {
297
349
  };
298
350
  }
299
351
 
300
- function maybeUpdateEnabledHint(removeVideoTrack) {
301
- if (removeVideoTrack._clientTrackSwitchOffControl !== 'auto') {
352
+ function maybeUpdateEnabledHint(remoteVideoTrack) {
353
+ if (remoteVideoTrack._clientTrackSwitchOffControl !== 'auto') {
302
354
  return;
303
355
  }
304
356
 
305
- const visibleElements = removeVideoTrack._getAllAttachedElements().filter(el => !removeVideoTrack._invisibleElements.has(el));
306
- const enabled = document.visibilityState === 'visible' && visibleElements.length > 0;
357
+ const visibleElements = remoteVideoTrack._getAllAttachedElements().filter(el => !remoteVideoTrack._invisibleElements.has(el));
358
+ const pipWindows = remoteVideoTrack._getAllAttachedElements().filter(el => remoteVideoTrack._elToPipWindows.has(el));
359
+
360
+ // even when document is invisible we may have track playing in pip window.
361
+ const enabled = pipWindows.length > 0 || (document.visibilityState === 'visible' && visibleElements.length > 0);
307
362
 
308
363
  if (enabled === true) {
309
- removeVideoTrack._turnOffTimer.clear();
310
- removeVideoTrack._setRenderHint({ enabled: true });
311
- } else if (!removeVideoTrack._turnOffTimer.isSet) {
364
+ remoteVideoTrack._turnOffTimer.clear();
365
+ remoteVideoTrack._setRenderHint({ enabled: true });
366
+ } else if (!remoteVideoTrack._turnOffTimer.isSet) {
312
367
  // set the track to be turned off after some delay.
313
- removeVideoTrack._turnOffTimer.start();
368
+ remoteVideoTrack._turnOffTimer.start();
314
369
  }
315
370
  }
316
371
 
317
- function maybeUpdateDimensionHint(removeVideoTrack) {
318
- if (removeVideoTrack._contentPreferencesMode !== 'auto') {
372
+ function maybeUpdateDimensionHint(remoteVideoTrack) {
373
+ if (remoteVideoTrack._contentPreferencesMode !== 'auto') {
319
374
  return;
320
375
  }
321
376
 
322
- const visibleElements = removeVideoTrack._getAllAttachedElements().filter(el => !removeVideoTrack._invisibleElements.has(el));
323
- if (visibleElements.length > 0) {
324
- const [{ clientHeight, clientWidth }] = visibleElements.sort((el1, el2) =>
377
+ const visibleElements = remoteVideoTrack._getAllAttachedElements().filter(el => !remoteVideoTrack._invisibleElements.has(el));
378
+ const pipElements = remoteVideoTrack._getAllAttachedElements().map(el => {
379
+ const pipWindow = remoteVideoTrack._elToPipWindows.get(el);
380
+ return pipWindow ? { clientHeight: pipWindow.height, clientWidth: pipWindow.width } : { clientHeight: 0, clientWidth: 0 };
381
+ });
382
+ const totalElements = visibleElements.concat(pipElements);
383
+ if (totalElements.length > 0) {
384
+ const [{ clientHeight, clientWidth }] = totalElements.sort((el1, el2) =>
325
385
  el2.clientHeight + el2.clientWidth - el1.clientHeight - el1.clientWidth - 1);
326
386
  const renderDimensions = { height: clientHeight, width: clientWidth };
327
- removeVideoTrack._setRenderHint({ renderDimensions });
387
+ remoteVideoTrack._setRenderHint({ renderDimensions });
328
388
  }
329
389
  }
330
390
 
@@ -50,19 +50,16 @@ class MediaSignaling extends EventEmitter {
50
50
  const receiverPromise = this._getReceiver(id).then(receiver => {
51
51
  if (receiver.kind !== 'data') {
52
52
  this._log.error('Expected a DataTrackReceiver');
53
- throw new Error('Expected a DataTrackReceiver');
54
53
  } if (this._receiverPromise !== receiverPromise) {
55
54
  return;
56
55
  }
57
56
 
58
57
  try {
59
58
  this._transport = receiver.toDataTransport();
59
+ this.emit('ready', this._transport);
60
60
  } catch (ex) {
61
- this._log.error('Failed to toDataTransport');
62
- throw new Error('Failed to toDataTransport');
61
+ this._log.error(`Failed to toDataTransport: ${ex.message}`);
63
62
  }
64
- this.emit('ready', this._transport);
65
-
66
63
  receiver.once('close', () => this._teardown());
67
64
  });
68
65
  this._receiverPromise = receiverPromise;
@@ -904,7 +904,9 @@ class PeerConnectionV2 extends StateMachine {
904
904
  log.debug(`Starting ICE reconnect timeout: ${delay}`);
905
905
  this._iceReconnectTimeout.start();
906
906
  }
907
- this.offer();
907
+ this.offer().catch(ex => {
908
+ log.error(`offer failed in _initiateIceRestart with: ${ex.message}`);
909
+ });
908
910
  }
909
911
 
910
912
  /**
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "twilio-video",
3
3
  "title": "Twilio Video",
4
4
  "description": "Twilio Video JavaScript Library",
5
- "version": "2.18.1",
5
+ "version": "2.18.2",
6
6
  "homepage": "https://twilio.com",
7
7
  "author": "Mark Andrus Roberts <mroberts@twilio.com>",
8
8
  "contributors": [
@@ -97,7 +97,8 @@
97
97
  "lint:js": "eslint ./lib ./test/*.js ./docker/**/*.js ./test/framework/*.js ./test/lib/*.js ./test/integration/** ./test/unit/** ",
98
98
  "lint:ts": "eslint ./tsdef/*.ts ./lib/**/*.ts",
99
99
  "lint": "npm-run-all lint:js lint:ts",
100
- "test:unit": "npm-run-all build:es5 test:unit:js test:unit:ts",
100
+ "printVersion": "node --version && npm --version",
101
+ "test:unit": "npm-run-all printVersion build:es5 test:unit:js test:unit:ts",
101
102
  "test:unit:js": "nyc --report-dir=./coverage/js --extension=.js --include=lib/**/* --reporter=html --reporter=lcov --reporter=text mocha ./test/unit/index.js",
102
103
  "test:unit:ts": "nyc --report-dir=./coverage/ts --extension=.ts --include=lib/**/* --reporter=html --reporter=lcov --reporter=text mocha -r ts-node/register ./test/unit/index.ts",
103
104
  "test:serversiderender": "mocha ./test/serversiderender/index.js",