twilio-video 2.21.3 → 2.22.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.
Files changed (53) hide show
  1. package/CHANGELOG.md +83 -1
  2. package/COMMON_ISSUES.md +34 -0
  3. package/README.md +1 -1
  4. package/dist/twilio-video.js +377 -116
  5. package/dist/twilio-video.min.js +20 -20
  6. package/es5/connect.js +9 -0
  7. package/es5/connect.js.map +1 -1
  8. package/es5/localparticipant.js +57 -33
  9. package/es5/localparticipant.js.map +1 -1
  10. package/es5/media/track/localtrackpublication.js +56 -4
  11. package/es5/media/track/localtrackpublication.js.map +1 -1
  12. package/es5/room.js +59 -0
  13. package/es5/room.js.map +1 -1
  14. package/es5/signaling/v2/cancelableroomsignalingpromise.js +2 -1
  15. package/es5/signaling/v2/cancelableroomsignalingpromise.js.map +1 -1
  16. package/es5/signaling/v2/localparticipant.js +13 -1
  17. package/es5/signaling/v2/localparticipant.js.map +1 -1
  18. package/es5/signaling/v2/localtrackpublication.js +38 -2
  19. package/es5/signaling/v2/localtrackpublication.js.map +1 -1
  20. package/es5/signaling/v2/peerconnection.js +23 -7
  21. package/es5/signaling/v2/peerconnection.js.map +1 -1
  22. package/es5/signaling/v2/room.js +9 -0
  23. package/es5/signaling/v2/room.js.map +1 -1
  24. package/es5/signaling/v2/twilioconnectiontransport.js +8 -1
  25. package/es5/signaling/v2/twilioconnectiontransport.js.map +1 -1
  26. package/es5/util/index.js +11 -0
  27. package/es5/util/index.js.map +1 -1
  28. package/es5/util/support.js +2 -0
  29. package/es5/util/support.js.map +1 -1
  30. package/es5/util/twiliowarning.js +12 -0
  31. package/es5/util/twiliowarning.js.map +1 -0
  32. package/es5/webrtc/util/sdp.js +10 -1
  33. package/es5/webrtc/util/sdp.js.map +1 -1
  34. package/lib/connect.js +9 -0
  35. package/lib/localparticipant.js +64 -37
  36. package/lib/media/track/localtrackpublication.js +32 -4
  37. package/lib/room.js +53 -0
  38. package/lib/signaling/v2/cancelableroomsignalingpromise.js +2 -0
  39. package/lib/signaling/v2/localparticipant.js +15 -1
  40. package/lib/signaling/v2/localtrackpublication.js +38 -1
  41. package/lib/signaling/v2/peerconnection.js +22 -7
  42. package/lib/signaling/v2/room.js +10 -0
  43. package/lib/signaling/v2/twilioconnectiontransport.js +10 -0
  44. package/lib/util/index.js +11 -0
  45. package/lib/util/support.js +2 -0
  46. package/lib/util/twiliowarning.js +13 -0
  47. package/lib/webrtc/util/sdp.js +11 -1
  48. package/package.json +2 -1
  49. package/tsdef/LocalParticipant.d.ts +2 -0
  50. package/tsdef/LocalTrackPublication.d.ts +2 -0
  51. package/tsdef/Room.d.ts +4 -1
  52. package/tsdef/twilio-video-tests.ts +38 -0
  53. package/tsdef/types.d.ts +3 -0
package/lib/room.js CHANGED
@@ -49,6 +49,8 @@ let nInstances = 0;
49
49
  * @emits Room#trackSwitchedOn
50
50
  * @emits Room#trackUnpublished
51
51
  * @emits Room#trackUnsubscribed
52
+ * @emits Room#trackWarning
53
+ * @emits Room#trackWarningsCleared
52
54
  */
53
55
  class Room extends EventEmitter {
54
56
  /**
@@ -125,6 +127,7 @@ class Room extends EventEmitter {
125
127
  }
126
128
  });
127
129
 
130
+ handleLocalParticipantEvents(this, localParticipant);
128
131
  handleRecordingEvents(this, signaling.recording);
129
132
  handleSignalingEvents(this, signaling);
130
133
 
@@ -455,6 +458,42 @@ function rewriteLocalTrackIds(room, trackStats) {
455
458
  * });
456
459
  */
457
460
 
461
+ /**
462
+ * One of the {@link LocalParticipant}'s {@link LocalTrackPublication}s in the {@link Room} encountered a warning.
463
+ * This event is only raised if you enabled warnings using <code>notifyWarnings</code> in <code>ConnectOptions</code>.
464
+ * @param {string} name - The warning that was raised.
465
+ * @param {LocalTrackPublication} publication - The {@link LocalTrackPublication} that encountered the warning.
466
+ * @param {LocalParticipant} participant - The {@link LocalParticipant}
467
+ * @event Room#trackWarning
468
+ * @example
469
+ * room.on('trackWarning', (name, publication, participant) => {
470
+ * if (name === 'recording-media-lost') {
471
+ * log(`LocalTrack ${publication.track.name} is not recording media.`,
472
+ * name, publication, participant);
473
+ *
474
+ * // Wait a reasonable amount of time to clear the warning.
475
+ * const timer = setTimeout(() => {
476
+ * // If the warning is not cleared, you can manually
477
+ * // reconnect to the room, or show a dialog to the user
478
+ * }, 5000);
479
+ *
480
+ * room.once('trackWarningsCleared', (publication, participant) => {
481
+ * log('LocalTrack warnings have cleared!',
482
+ * publication, participant);
483
+ * clearTimeout(timer);
484
+ * });
485
+ * }
486
+ });
487
+ */
488
+
489
+ /**
490
+ * One of the {@link LocalParticipant}'s {@link LocalTrackPublication}s in the {@link Room} cleared all warnings.
491
+ * This event is only raised if you enabled warnings using <code>notifyWarnings</code> in <code>ConnectOptions</code>.
492
+ * @param {LocalTrackPublication} publication - The {@link LocalTrackPublication} that cleared all warnings.
493
+ * @param {LocalParticipant} participant - The {@link LocalParticipant}
494
+ * @event Room#trackWarningsCleared
495
+ */
496
+
458
497
  function connectParticipant(room, participantSignaling) {
459
498
  const { _log: log, _clientTrackSwitchOffControl: clientTrackSwitchOffControl, _contentPreferencesMode: contentPreferencesMode } = room;
460
499
  const participant = new RemoteParticipant(participantSignaling, { log, clientTrackSwitchOffControl, contentPreferencesMode });
@@ -509,6 +548,20 @@ function connectParticipant(room, participantSignaling) {
509
548
  });
510
549
  }
511
550
 
551
+ function handleLocalParticipantEvents(room, localParticipant) {
552
+ const events = ['trackWarning', 'trackWarningsCleared'].map(event => ({
553
+ eventName: event,
554
+ handler: (...args) => room.emit(event, ...[...args, localParticipant]),
555
+ }));
556
+
557
+ events.forEach(({ eventName, handler }) =>
558
+ localParticipant.on(eventName, handler));
559
+
560
+ room.once('disconnected', () =>
561
+ events.forEach(({ eventName, handler }) =>
562
+ localParticipant.removeListener(eventName, handler)));
563
+ }
564
+
512
565
  function handleRecordingEvents(room, recording) {
513
566
  recording.on('updated', function updated() {
514
567
  const started = recording.isEnabled;
@@ -68,6 +68,7 @@ function createCancelableRoomSignalingPromise(token, wsServer, localParticipant,
68
68
  name,
69
69
  networkMonitor,
70
70
  networkQuality,
71
+ notifyWarnings,
71
72
  realm,
72
73
  sdpSemantics,
73
74
  } = options;
@@ -89,6 +90,7 @@ function createCancelableRoomSignalingPromise(token, wsServer, localParticipant,
89
90
  logLevel,
90
91
  networkMonitor,
91
92
  networkQuality,
93
+ notifyWarnings,
92
94
  iceServers,
93
95
  onIced,
94
96
  realm,
@@ -165,6 +165,20 @@ class LocalParticipantV2 extends LocalParticipantSignaling {
165
165
  return this;
166
166
  }
167
167
 
168
+ updateMediaStates(mediaStates) {
169
+ if (!mediaStates || !mediaStates.tracks) {
170
+ return this;
171
+ }
172
+
173
+ Array.from(this.tracks.values()).forEach(publication => {
174
+ const states = mediaStates.tracks[publication.sid];
175
+ if (states) {
176
+ publication.updateMediaStates(states);
177
+ }
178
+ });
179
+ return this;
180
+ }
181
+
168
182
  /**
169
183
  * @protected
170
184
  * @param {DataTrackSender|MediaTrackSender} trackSender
@@ -173,7 +187,7 @@ class LocalParticipantV2 extends LocalParticipantSignaling {
173
187
  * @returns {LocalTrackPublicationV2}
174
188
  */
175
189
  _createLocalTrackPublicationSignaling(trackSender, name, priority) {
176
- return new this._LocalTrackPublicationV2(trackSender, name, priority);
190
+ return new this._LocalTrackPublicationV2(trackSender, name, priority, { log: this._log });
177
191
  }
178
192
 
179
193
  /**
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const LocalTrackPublicationSignaling = require('../localtrackpublication');
4
+ const TwilioWarning = require('../../util/twiliowarning');
4
5
  const createTwilioError = require('../../util/twilio-video-errors').createTwilioError;
5
6
 
6
7
  /**
@@ -12,9 +13,19 @@ class LocalTrackPublicationV2 extends LocalTrackPublicationSignaling {
12
13
  * @param {DataTrackSender|MediaTrackSender} trackSender
13
14
  * @param {string} name
14
15
  * @param {Track.Priority} priority
16
+ * @param {object} [options]
15
17
  */
16
- constructor(trackSender, name, priority) {
18
+ constructor(trackSender, name, priority, options) {
17
19
  super(trackSender, name, priority);
20
+ Object.defineProperties(this, {
21
+ _log: {
22
+ value: options.log.createLog('default', this)
23
+ },
24
+ _mediaStates: {
25
+ value: { recordings: null },
26
+ writable: true
27
+ }
28
+ });
18
29
  }
19
30
 
20
31
  /**
@@ -31,6 +42,10 @@ class LocalTrackPublicationV2 extends LocalTrackPublicationSignaling {
31
42
  };
32
43
  }
33
44
 
45
+ toString() {
46
+ return `[LocalTrackPublicationV2: ${this.sid}]`;
47
+ }
48
+
34
49
  /**
35
50
  * Compare the {@link LocalTrackPublicationV2} to a {@link LocalTrackPublicationV2#Representation} of itself
36
51
  * and perform any updates necessary.
@@ -53,6 +68,28 @@ class LocalTrackPublicationV2 extends LocalTrackPublicationSignaling {
53
68
  }
54
69
  return this;
55
70
  }
71
+
72
+ updateMediaStates(mediaStates) {
73
+ if (!mediaStates || !mediaStates.recordings ||
74
+ this._mediaStates.recordings === mediaStates.recordings) {
75
+ return this;
76
+ }
77
+ this._mediaStates.recordings = mediaStates.recordings;
78
+ switch (this._mediaStates.recordings) {
79
+ case 'OK':
80
+ this._log.info('Warnings have cleared.');
81
+ this.emit('warningsCleared');
82
+ break;
83
+ case 'NO_MEDIA':
84
+ this._log.warn('Recording media lost.');
85
+ this.emit('warning', TwilioWarning.recordingMediaLost);
86
+ break;
87
+ default:
88
+ this._log.warn(`Unknown media state detected: ${this._mediaStates.recordings}`);
89
+ break;
90
+ }
91
+ return this;
92
+ }
56
93
  }
57
94
 
58
95
  /**
@@ -1851,13 +1851,28 @@ function updateEncodingParameters(pcv2) {
1851
1851
  setMaxBitrate(params, maxBitrate);
1852
1852
  }
1853
1853
 
1854
- if (!isFirefox && pcv2._enableDscp && params.encodings.length > 0) {
1855
- // NOTE(mmalavalli): "networkPriority" is a per-sender property and not
1856
- // a per-encoding-layer property. So, we set the value only on the first
1857
- // encoding layer. Any attempt to set the value on subsequent encoding
1858
- // layers (in the case of simulcast) will result in the Promise returned
1859
- // by RTCRtpSender.setParameters() being rejected.
1860
- params.encodings[0].networkPriority = 'high';
1854
+ if (!isFirefox && params.encodings.length > 0) {
1855
+ if (sender.track.kind === 'audio') {
1856
+ // NOTE(mmalavalli): "priority" is a per-sender property and not
1857
+ // a per-encoding-layer property. So, we set the value only on the first
1858
+ // encoding layer. Any attempt to set the value on subsequent encoding
1859
+ // layers (in the case of simulcast) will result in the Promise returned
1860
+ // by RTCRtpSender.setParameters() being rejected. With this, audio encoding
1861
+ // is prioritized the most.
1862
+ params.encodings[0].priority = 'high';
1863
+ } else if (pcv2._isChromeScreenShareTrack(sender.track)) {
1864
+ // NOTE(mmalavalli): Screen share encodings are prioritized more than those
1865
+ // of the camera.
1866
+ params.encodings[0].priority = 'medium';
1867
+ }
1868
+ if (pcv2._enableDscp) {
1869
+ // NOTE(mmalavalli): "networkPriority" is a per-sender property and not
1870
+ // a per-encoding-layer property. So, we set the value only on the first
1871
+ // encoding layer. Any attempt to set the value on subsequent encoding
1872
+ // layers (in the case of simulcast) will result in the Promise returned
1873
+ // by RTCRtpSender.setParameters() being rejected.
1874
+ params.encodings[0].networkPriority = 'high';
1875
+ }
1861
1876
  }
1862
1877
 
1863
1878
  // when a sender is reused, delete any active encodings set by server.
@@ -70,6 +70,10 @@ class RoomV2 extends RoomSignaling {
70
70
  value: localParticipant.bandwidthProfileRevision,
71
71
  writable: true
72
72
  },
73
+ _mediaStatesWarningsRevision: {
74
+ value: 0,
75
+ writable: true
76
+ },
73
77
  _networkQualityMonitor: {
74
78
  value: null,
75
79
  writable: true
@@ -442,6 +446,12 @@ class RoomV2 extends RoomSignaling {
442
446
  }
443
447
  });
444
448
 
449
+ if (roomState.type === 'warning' && roomState.states &&
450
+ roomState.states.revision > this._mediaStatesWarningsRevision) {
451
+ this._mediaStatesWarningsRevision = roomState.states.revision;
452
+ this.localParticipant.updateMediaStates(roomState.states);
453
+ }
454
+
445
455
  return this;
446
456
  }
447
457
 
@@ -10,6 +10,7 @@ const { SDK_NAME, SDK_VERSION, SDP_FORMAT } = require('../../util/constants');
10
10
  const {
11
11
  createBandwidthProfilePayload,
12
12
  createMediaSignalingPayload,
13
+ createMediaWarningsPayload,
13
14
  createSubscribePayload,
14
15
  getUserAgent,
15
16
  isNonArrayObject
@@ -132,6 +133,9 @@ class TwilioConnectionTransport extends StateMachine {
132
133
  _networkQuality: {
133
134
  value: isNonArrayObject(options.networkQuality) || options.networkQuality
134
135
  },
136
+ _notifyWarnings: {
137
+ value: options.notifyWarnings
138
+ },
135
139
  _options: {
136
140
  value: options
137
141
  },
@@ -226,6 +230,11 @@ class TwilioConnectionTransport extends StateMachine {
226
230
  this._bandwidthProfile);
227
231
  }
228
232
 
233
+ if (this._notifyWarnings) {
234
+ message.participant.media_warnings = createMediaWarningsPayload(
235
+ this._notifyWarnings);
236
+ }
237
+
229
238
  message.media_signaling = createMediaSignalingPayload(
230
239
  this._dominantSpeaker,
231
240
  this._networkQuality,
@@ -524,6 +533,7 @@ function setupTransport(transport) {
524
533
  case 'connected':
525
534
  case 'synced':
526
535
  case 'update':
536
+ case 'warning':
527
537
  transport.emit('message', message);
528
538
  return;
529
539
  case 'disconnected':
package/lib/util/index.js CHANGED
@@ -4,6 +4,7 @@ const constants = require('./constants');
4
4
  const { typeErrors: E, trackPriority } = constants;
5
5
  const util = require('../webrtc/util');
6
6
  const { sessionSID } = require('./sid');
7
+ const TwilioWarning = require('./twiliowarning');
7
8
 
8
9
  /**
9
10
  * Return the given {@link LocalTrack} or a new {@link LocalTrack} for the
@@ -779,6 +780,15 @@ function createSubscribePayload(automaticSubscription) {
779
780
  };
780
781
  }
781
782
 
783
+ function createMediaWarningsPayload(notifyWarnings) {
784
+ const mediaWarnings = {
785
+ [TwilioWarning.recordingMediaLost]: 'recordings'
786
+ };
787
+ return notifyWarnings
788
+ .map(twilioWarningName => mediaWarnings[twilioWarningName])
789
+ .filter(name => !!name);
790
+ }
791
+
782
792
  /**
783
793
  * Add random jitter to a given value in the range [-jitter, jitter].
784
794
  * @private
@@ -852,6 +862,7 @@ function waitForEvent(eventTarget, event) {
852
862
  exports.constants = constants;
853
863
  exports.createBandwidthProfilePayload = createBandwidthProfilePayload;
854
864
  exports.createMediaSignalingPayload = createMediaSignalingPayload;
865
+ exports.createMediaWarningsPayload = createMediaWarningsPayload;
855
866
  exports.createRoomConnectEventPayload = createRoomConnectEventPayload;
856
867
  exports.createSubscribePayload = createSubscribePayload;
857
868
  exports.asLocalTrack = asLocalTrack;
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const { guessBrowser, support: isWebRTCSupported } = require('../webrtc/util');
4
+ const { getSdpFormat } = require('../webrtc/util/sdp');
4
5
  const { isAndroid, isMobile, isNonChromiumEdge, rebrandedChromeBrowser, mobileWebKitBrowser } = require('./browserdetection');
5
6
 
6
7
  const SUPPORTED_CHROME_BASED_BROWSERS = [
@@ -41,6 +42,7 @@ function isSupported() {
41
42
 
42
43
  return !!browser
43
44
  && isWebRTCSupported()
45
+ && getSdpFormat() === 'unified'
44
46
  && (!rebrandedChrome || SUPPORTED_CHROME_BASED_BROWSERS.includes(rebrandedChrome))
45
47
  && !isNonChromiumEdge(browser)
46
48
  && (!mobileWebKit || SUPPORTED_MOBILE_WEBKIT_BASED_BROWSERS.includes(mobileWebKit))
@@ -0,0 +1,13 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * @private
5
+ * Represents a warning encountered when
6
+ * interacting with one of Twilio's services.
7
+ */
8
+ // eslint-disable-next-line
9
+ const TwilioWarning = {
10
+ recordingMediaLost: 'recording-media-lost'
11
+ };
12
+
13
+ module.exports = TwilioWarning;
@@ -35,6 +35,13 @@ function checkIfSdpSemanticsIsSupported() {
35
35
  // instantiation of more than one RTCPeerConnection.
36
36
  var chromeSdpFormat = null;
37
37
 
38
+ /**
39
+ * Clear cached Chrome's SDP format
40
+ */
41
+ function clearChromeCachedSdpFormat() {
42
+ chromeSdpFormat = null;
43
+ }
44
+
38
45
  /**
39
46
  * Get Chrome's default SDP format.
40
47
  * @returns {'planb'|'unified'}
@@ -43,12 +50,14 @@ function getChromeDefaultSdpFormat() {
43
50
  if (!chromeSdpFormat) {
44
51
  if (typeof RTCPeerConnection !== 'undefined'
45
52
  && 'addTransceiver' in RTCPeerConnection.prototype) {
53
+ const pc = new RTCPeerConnection();
46
54
  try {
47
- new RTCPeerConnection().addTransceiver('audio');
55
+ pc.addTransceiver('audio');
48
56
  chromeSdpFormat = 'unified';
49
57
  } catch (e) {
50
58
  chromeSdpFormat = 'planb';
51
59
  }
60
+ pc.close();
52
61
  } else {
53
62
  chromeSdpFormat = 'planb';
54
63
  }
@@ -299,6 +308,7 @@ function updateUnifiedPlanTrackIdsToSSRCs(trackIdsToSSRCs, sdp) {
299
308
  return updateTrackIdsToSSRCs(getUnifiedPlanTrackIdsToSSRCs, trackIdsToSSRCs, sdp);
300
309
  }
301
310
 
311
+ exports.clearChromeCachedSdpFormat = clearChromeCachedSdpFormat;
302
312
  exports.getSdpFormat = getSdpFormat;
303
313
  exports.getMediaSections = getMediaSections;
304
314
  exports.getPlanBTrackIds = getPlanBTrackIds;
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.21.3",
5
+ "version": "2.22.2",
6
6
  "homepage": "https://twilio.com",
7
7
  "author": "Mark Andrus Roberts <mroberts@twilio.com>",
8
8
  "contributors": [
@@ -99,6 +99,7 @@
99
99
  "lint": "npm-run-all lint:js lint:ts",
100
100
  "printVersion": "node --version && npm --version",
101
101
  "test:unit": "npm-run-all printVersion build:es5 && nyc --report-dir=./coverage --include=lib/**/* --reporter=html --reporter=lcov --reporter=text mocha -r ts-node/register ./test/unit/*",
102
+ "test:unit:quick": "nyc --report-dir=./coverage --include=lib/**/* --reporter=html --reporter=lcov mocha -r ts-node/register",
102
103
  "test:serversiderender": "mocha ./test/serversiderender/index.js",
103
104
  "test:integration:adapter": "node ./scripts/karma.js karma/integration.adapter.conf.js",
104
105
  "test:integration": "npm run build:es5 && node ./scripts/karma.js karma/integration.conf.js",
@@ -31,5 +31,7 @@ export class LocalParticipant extends Participant {
31
31
  on(event: 'trackPublished', listener: (publication: LocalTrackPublication) => void): this;
32
32
  on(event: 'trackStarted', listener: (track: LocalTrack) => void): this;
33
33
  on(event: 'trackStopped', listener: (track: LocalTrack) => void): this;
34
+ on(event: 'trackWarning', listener: (name: string, publication: LocalTrackPublication) => void): this;
35
+ on(event: 'trackWarningsCleared', listener: (publication: LocalTrackPublication) => void): this;
34
36
  on(event: string, listener: (...args: any[]) => void): this;
35
37
  }
@@ -13,5 +13,7 @@ export class LocalTrackPublication extends TrackPublication {
13
13
 
14
14
  on(event: 'trackDisabled', listener: () => void): this;
15
15
  on(event: 'trackEnabled', listener: () => void): this;
16
+ on(event: 'warning', listener: (name: string) => void): this;
17
+ on(event: 'warningsCleared', listener: () => void): this;
16
18
  on(event: string, listener: (...args: any[]) => void): this;
17
19
  }
package/tsdef/Room.d.ts CHANGED
@@ -1,6 +1,7 @@
1
- import { RemoteTrack, StatsReport } from './types';
1
+ import { LocalTrack, RemoteTrack, StatsReport } from './types';
2
2
  import { EventEmitter } from 'events';
3
3
  import { LocalParticipant } from './LocalParticipant';
4
+ import { LocalTrackPublication } from './LocalTrackPublication';
4
5
  import { Participant } from './Participant';
5
6
  import { RemoteDataTrack } from './RemoteDataTrack';
6
7
  import { RemoteParticipant } from './RemoteParticipant';
@@ -49,4 +50,6 @@ export class Room extends EventEmitter {
49
50
  on(event: 'trackSwitchedOn', listener: (track: RemoteTrack, publication: RemoteTrackPublication, participant: RemoteParticipant) => void): this;
50
51
  on(event: 'trackUnpublished', listener: (publication: RemoteTrackPublication, participant: RemoteParticipant) => void): this;
51
52
  on(event: 'trackUnsubscribed', listener: (track: RemoteTrack, publication: RemoteTrackPublication, participant: RemoteParticipant) => void): this;
53
+ on(event: 'trackWarning', listener: (name: string, publication: LocalTrackPublication, participant: LocalParticipant) => void): this;
54
+ on(event: 'trackWarningsCleared', listener: (publication: LocalTrackPublication, participant: LocalParticipant) => void): this;
52
55
  }
@@ -392,6 +392,44 @@ function runPreflight() {
392
392
  preflight.stop();
393
393
  }
394
394
 
395
+ async function mediaWarnings() {
396
+ let room = await Video.connect('$TOKEN', {
397
+ notifyWarnings: []
398
+ });
399
+ room = await Video.connect('$TOKEN', {
400
+ notifyWarnings: ['recording-media-lost']
401
+ });
402
+
403
+ room.localParticipant.tracks.forEach((publication: Video.LocalTrackPublication) => {
404
+ publication.on('warning', (name: string) => {
405
+ // eslint-disable-next-line no-console
406
+ console.log(name);
407
+ });
408
+ publication.on('warningsCleared', () => {
409
+ // eslint-disable-next-line no-console
410
+ console.log('warningsCleared');
411
+ });
412
+ });
413
+ room.localParticipant.on('trackWarning', (name: string, publication: Video.LocalTrackPublication) => {
414
+ // eslint-disable-next-line no-console
415
+ console.log(name, publication);
416
+ });
417
+ room.localParticipant.on('trackWarningsCleared', (publication: Video.LocalTrackPublication) => {
418
+ // eslint-disable-next-line no-console
419
+ console.log('warningsCleared', publication);
420
+ });
421
+
422
+ room.on('trackWarning', (name: string, publication: Video.LocalTrackPublication, participant: Video.LocalParticipant) => {
423
+ // eslint-disable-next-line no-console
424
+ console.log(name, publication, participant);
425
+ });
426
+ room.on('trackWarningsCleared', (publication: Video.LocalTrackPublication, participant: Video.LocalParticipant) => {
427
+ // eslint-disable-next-line no-console
428
+ console.log('warningsCleared', publication, participant);
429
+ });
430
+ }
431
+
395
432
  initRoom();
396
433
  unpublishTracks();
397
434
  runPreflight();
435
+ mediaWarnings();
package/tsdef/types.d.ts CHANGED
@@ -98,6 +98,8 @@ export type BandwidthProfileMode = 'grid' | 'collaboration' | 'presentation';
98
98
  export type VideoContentPreferencesMode = 'auto' | 'manual';
99
99
  export type ClientTrackSwitchOffControl = 'auto' | 'manual';
100
100
 
101
+ export type NotifyWarning = 'recording-media-lost';
102
+
101
103
  /**
102
104
  * @deprecated
103
105
  */
@@ -188,6 +190,7 @@ export interface ConnectOptions {
188
190
  maxVideoBitrate?: number | null;
189
191
  name?: string | null;
190
192
  networkQuality?: boolean | NetworkQualityConfiguration;
193
+ notifyWarnings?: Array<NotifyWarning>;
191
194
  region?: string;
192
195
  preferredAudioCodecs?: Array<AudioCodec | AudioCodecSettings | OpusCodecSettings>;
193
196
  preferredVideoCodecs?: Array<VideoCodec | VideoCodecSettings | VP8CodecSettings> | VideoEncodingMode;