twilio-video 2.22.2 → 2.24.1

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 (63) hide show
  1. package/CHANGELOG.md +72 -1
  2. package/README.md +1 -1
  3. package/dist/twilio-video.js +767 -204
  4. package/dist/twilio-video.min.js +21 -20
  5. package/es5/connect.js +1 -1
  6. package/es5/connect.js.map +1 -1
  7. package/es5/createlocaltrack.js +38 -8
  8. package/es5/createlocaltrack.js.map +1 -1
  9. package/es5/createlocaltracks.js +36 -11
  10. package/es5/createlocaltracks.js.map +1 -1
  11. package/es5/index.js +1 -1
  12. package/es5/index.js.map +1 -1
  13. package/es5/localparticipant.js +10 -1
  14. package/es5/localparticipant.js.map +1 -1
  15. package/es5/media/track/localaudiotrack.js +30 -1
  16. package/es5/media/track/localaudiotrack.js.map +1 -1
  17. package/es5/media/track/localvideotrack.js +1 -1
  18. package/es5/media/track/localvideotrack.js.map +1 -1
  19. package/es5/media/track/noisecancellationimpl.js +228 -0
  20. package/es5/media/track/noisecancellationimpl.js.map +1 -0
  21. package/es5/noisecancellationadapter.js +155 -0
  22. package/es5/noisecancellationadapter.js.map +1 -0
  23. package/es5/preflight/preflighttest.js +2 -2
  24. package/es5/preflight/preflighttest.js.map +1 -1
  25. package/es5/room.js +12 -0
  26. package/es5/room.js.map +1 -1
  27. package/es5/signaling/localparticipant.js +4 -2
  28. package/es5/signaling/localparticipant.js.map +1 -1
  29. package/es5/signaling/v2/cancelableroomsignalingpromise.js +0 -2
  30. package/es5/signaling/v2/cancelableroomsignalingpromise.js.map +1 -1
  31. package/es5/signaling/v2/localparticipant.js +16 -4
  32. package/es5/signaling/v2/localparticipant.js.map +1 -1
  33. package/es5/signaling/v2/localtrackpublication.js +12 -3
  34. package/es5/signaling/v2/localtrackpublication.js.map +1 -1
  35. package/es5/signaling/v2/room.js +8 -1
  36. package/es5/signaling/v2/room.js.map +1 -1
  37. package/es5/vendor/dynamicimport.js +44 -0
  38. package/es5/vendor/dynamicimport.js.map +1 -0
  39. package/karma/makeconf.js +11 -1
  40. package/lib/connect.js +2 -1
  41. package/lib/createlocaltrack.js +41 -8
  42. package/lib/createlocaltracks.ts +35 -11
  43. package/lib/index.ts +5 -3
  44. package/lib/localparticipant.js +10 -1
  45. package/lib/media/track/localaudiotrack.js +30 -0
  46. package/lib/media/track/localvideotrack.js +1 -1
  47. package/lib/media/track/noisecancellationimpl.ts +176 -0
  48. package/lib/noisecancellationadapter.ts +134 -0
  49. package/lib/preflight/preflighttest.ts +1 -1
  50. package/lib/room.js +13 -0
  51. package/lib/signaling/localparticipant.js +3 -2
  52. package/lib/signaling/v2/cancelableroomsignalingpromise.js +0 -3
  53. package/lib/signaling/v2/localparticipant.js +17 -4
  54. package/lib/signaling/v2/localtrackpublication.js +14 -3
  55. package/lib/signaling/v2/room.js +13 -1
  56. package/lib/vendor/dynamicimport.js +44 -0
  57. package/package.json +2 -2
  58. package/tsconfig.json +1 -0
  59. package/tsdef/AudioProcessor.d.ts +65 -0
  60. package/tsdef/LocalAudioTrack.d.ts +2 -0
  61. package/tsdef/LocalTrackOptions.d.ts +1 -1
  62. package/tsdef/index.d.ts +7 -2
  63. package/tsdef/types.d.ts +23 -2
@@ -15,6 +15,9 @@ const LocalMediaAudioTrack = mixinLocalMediaTrack(AudioTrack);
15
15
  * @property {Track.ID} id - The {@link LocalAudioTrack}'s ID
16
16
  * @property {boolean} isStopped - Whether or not the {@link LocalAudioTrack} is
17
17
  * stopped
18
+ * @property {NoiseCancellation?} noiseCancellation - When a LocalAudioTrack is created
19
+ * with {@link NoiseCancellationOptions}, this property provides interface
20
+ * to enable or disable the noise cancellation at runtime.
18
21
  * @emits LocalAudioTrack#disabled
19
22
  * @emits LocalAudioTrack#enabled
20
23
  * @emits LocalAudioTrack#started
@@ -27,7 +30,16 @@ class LocalAudioTrack extends LocalMediaAudioTrack {
27
30
  * @param {LocalTrackOptions} [options] - {@link LocalTrack} options
28
31
  */
29
32
  constructor(mediaStreamTrack, options) {
33
+ const noiseCancellation = options?.noiseCancellation || null;
30
34
  super(mediaStreamTrack, options);
35
+
36
+ Object.defineProperties(this, {
37
+ noiseCancellation: {
38
+ enumerable: true,
39
+ value: noiseCancellation,
40
+ writable: false
41
+ },
42
+ });
31
43
  }
32
44
 
33
45
  toString() {
@@ -47,6 +59,20 @@ class LocalAudioTrack extends LocalMediaAudioTrack {
47
59
  return super._end.apply(this, arguments);
48
60
  }
49
61
 
62
+ /**
63
+ * @private
64
+ */
65
+ _reacquireTrack(constraints) {
66
+ this._log.debug('_reacquireTrack: ', constraints);
67
+ if (this.noiseCancellation) {
68
+ return this.noiseCancellation.reacquireTrack(() => {
69
+ return super._reacquireTrack.call(this, constraints);
70
+ });
71
+ }
72
+
73
+ return super._reacquireTrack.call(this, constraints);
74
+ }
75
+
50
76
  /**
51
77
  * Disable the {@link LocalAudioTrack}. This is effectively "mute".
52
78
  * @returns {this}
@@ -118,6 +144,9 @@ class LocalAudioTrack extends LocalMediaAudioTrack {
118
144
  * @fires LocalAudioTrack#stopped
119
145
  */
120
146
  stop() {
147
+ if (this.noiseCancellation) {
148
+ this.noiseCancellation.stop();
149
+ }
121
150
  return super.stop.apply(this, arguments);
122
151
  }
123
152
  }
@@ -151,3 +180,4 @@ class LocalAudioTrack extends LocalMediaAudioTrack {
151
180
  */
152
181
 
153
182
  module.exports = LocalAudioTrack;
183
+
@@ -312,7 +312,7 @@ function workaroundSilentLocalVideo(localVideoTrack, doc) {
312
312
  }).finally(() => {
313
313
  // If silent frames were not detected, then pause the dummy element again.
314
314
  el = localVideoTrack._dummyEl;
315
- if (!el.paused) {
315
+ if (el && !el.paused) {
316
316
  el.pause();
317
317
  }
318
318
 
@@ -0,0 +1,176 @@
1
+ 'use strict';
2
+
3
+ import { NoiseCancellation, NoiseCancellationOptions, NoiseCancellationVendor } from '../../../tsdef/types';
4
+ import { AudioProcessor } from '../../../tsdef/AudioProcessor';
5
+ import { createNoiseCancellationAudioProcessor } from '../../noisecancellationadapter';
6
+ const Log = require('../../util/log');
7
+
8
+ /**
9
+ * {@link NoiseCancellation} interface provides methods to control noise cancellation at runtime. This interface is exposed
10
+ * on {@link LocalAudioTrack} property `noiseCancellation`. It is available only when {@link NoiseCancellationOptions} are
11
+ * specified when creating a {@link LocalAudioTrack}, and the plugin is successfully loaded.
12
+ * @alias NoiseCancellation
13
+ * @interface
14
+ *
15
+ * @example
16
+ * const { connect, createLocalAudioTrack } = require('twilio-video');
17
+ *
18
+ * // Create a LocalAudioTrack with Krisp noise cancellation enabled.
19
+ * const localAudioTrack = await createLocalAudioTrack({
20
+ * noiseCancellationOptions: {
21
+ * sdkAssetsPath: 'path/to/hosted/twilio/krisp/audio/plugin/1.0.0/dist',
22
+ * vendor: 'krisp'
23
+ * }
24
+ * });
25
+ *
26
+ * if (!localAudioTrack.noiseCancellation) {
27
+ * // If the Krisp audio plugin fails to load, then a warning message will be logged
28
+ * // in the browser console, and the "noiseCancellation" property will be set to null.
29
+ * // You can still use the LocalAudioTrack to join a Room. However, it will use the
30
+ * // browser's noise suppression instead of the Krisp noise cancellation. Make sure
31
+ * // the "sdkAssetsPath" provided in "noiseCancellationOptions" points to the correct
32
+ * // hosted path of the plugin assets.
33
+ * } else {
34
+ * // Join a Room with the LocalAudioTrack.
35
+ * const room = await connect('token', {
36
+ * name: 'my-cool-room',
37
+ * tracks: [localAudioTrack]
38
+ * });
39
+ *
40
+ * if (!localAudioTrack.noiseCancellation.isEnabled) {
41
+ * // Krisp noise cancellation is permanently disabled in Peer-to-Peer and Go Rooms.
42
+ * }
43
+ * }
44
+ *
45
+ * //
46
+ * // Enable/disable noise cancellation.
47
+ * // @param {boolean} enable - whether noise cancellation should be enabled
48
+ * //
49
+ * function setNoiseCancellation(enable) {
50
+ * const { noiseCancellation } = localAudioTrack;
51
+ * if (noiseCancellation) {
52
+ * if (enable) {
53
+ * // If enabled, then the LocalAudioTrack will use the Krisp noise
54
+ * // cancellation instead of the browser's noise suppression.
55
+ * noiseCancellation.enable();
56
+ * } else {
57
+ * // If disabled, then the LocalAudioTrack will use the browser's
58
+ * // noise suppression instead of the Krisp noise cancellation.
59
+ * noiseCancellation.disable();
60
+ * }
61
+ * }
62
+ * }
63
+ */
64
+ export class NoiseCancellationImpl implements NoiseCancellation {
65
+ private _processor: AudioProcessor;
66
+ private _sourceTrack: MediaStreamTrack;
67
+ private _disabledPermanent: boolean;
68
+
69
+ constructor(processor: AudioProcessor, originalTrack: MediaStreamTrack) {
70
+ this._processor = processor;
71
+ this._sourceTrack = originalTrack;
72
+ this._disabledPermanent = false;
73
+ }
74
+
75
+ /**
76
+ * Name of the noise cancellation vendor.
77
+ * @type {NoiseCancellationVendor}
78
+ */
79
+ get vendor(): NoiseCancellationVendor {
80
+ return this._processor.vendor;
81
+ }
82
+
83
+ /**
84
+ * The underlying MediaStreamTrack of the {@link LocalAudioTrack}.
85
+ * @type {MediaStreamTrack}
86
+ */
87
+ get sourceTrack(): MediaStreamTrack {
88
+ return this._sourceTrack;
89
+ }
90
+
91
+ /**
92
+ * Whether noise cancellation is enabled.
93
+ * @type {boolean}
94
+ */
95
+ get isEnabled(): boolean {
96
+ return this._processor.isEnabled();
97
+ }
98
+
99
+ /**
100
+ * Enable noise cancellation.
101
+ * @returns {Promise<void>} Promise that resolves when the operation is complete
102
+ * @throws {Error} Throws an error if noise cancellation is disabled permanently
103
+ * for the {@link LocalAudioTrack}
104
+ */
105
+ enable() : Promise<void> {
106
+ if (this._disabledPermanent) {
107
+ throw new Error(`${this.vendor} noise cancellation is disabled permanently for this track`);
108
+ }
109
+
110
+ this._processor.enable();
111
+ return Promise.resolve();
112
+ }
113
+
114
+ /**
115
+ * Disable noise cancellation.
116
+ * @returns {Promise<void>} Promise that resolves when the operation is complete
117
+ */
118
+ disable() : Promise<void> {
119
+ this._processor.disable();
120
+ return Promise.resolve();
121
+ }
122
+
123
+ /**
124
+ * @private
125
+ */
126
+ async reacquireTrack(reacquire: () => Promise<MediaStreamTrack>) : Promise<MediaStreamTrack> {
127
+ const processorWasEnabled = this._processor.isEnabled();
128
+ this._processor.disconnect();
129
+
130
+ const track = await reacquire();
131
+ this._sourceTrack = track;
132
+
133
+ const processedTrack = await this._processor.connect(track);
134
+ if (processorWasEnabled) {
135
+ this._processor.enable();
136
+ } else {
137
+ this._processor.disable();
138
+ }
139
+ return processedTrack;
140
+ }
141
+
142
+ /**
143
+ * @private
144
+ */
145
+ disablePermanently(): Promise<void> {
146
+ this._disabledPermanent = true;
147
+ return this.disable();
148
+ }
149
+
150
+
151
+ /**
152
+ * @private
153
+ */
154
+ stop(): void {
155
+ this._processor.disconnect();
156
+ this._sourceTrack.stop();
157
+ }
158
+ }
159
+
160
+
161
+ export async function applyNoiseCancellation(
162
+ mediaStreamTrack: MediaStreamTrack,
163
+ noiseCancellationOptions: NoiseCancellationOptions,
164
+ log: typeof Log
165
+ ) : Promise<{ cleanTrack: MediaStreamTrack, noiseCancellation?: NoiseCancellation }> {
166
+ try {
167
+ const processor = await createNoiseCancellationAudioProcessor(noiseCancellationOptions, log);
168
+ const cleanTrack = processor.connect(mediaStreamTrack);
169
+ const noiseCancellation = new NoiseCancellationImpl(processor, mediaStreamTrack);
170
+ return { cleanTrack, noiseCancellation };
171
+ } catch (ex) {
172
+ // in case of failures to load noise cancellation library just return original media stream.
173
+ log.warn(`Failed to create noise cancellation. Returning normal audio track: ${ex}`);
174
+ return { cleanTrack: mediaStreamTrack };
175
+ }
176
+ }
@@ -0,0 +1,134 @@
1
+ /* eslint-disable no-console */
2
+ 'use strict';
3
+ import { AudioProcessor } from '../tsdef/AudioProcessor';
4
+ import { NoiseCancellationOptions } from '../tsdef/types';
5
+ const Log = require('./util/log');
6
+
7
+ const dynamicImport = require('./vendor/dynamicimport');
8
+
9
+ const PLUGIN_CONFIG = {
10
+ krisp: {
11
+ supportedVersion: '1.0.0',
12
+ pluginFile: 'krispsdk.mjs'
13
+ },
14
+ rnnoise: {
15
+ supportedVersion: '0.6.0',
16
+ pluginFile: 'rnnoise_sdk.mjs'
17
+ }
18
+ };
19
+ // AudioProcessor assumes following interface from the Plugin
20
+ interface NoiseCancellationPlugin {
21
+ init(options: { rootDir: string }): Promise<void>;
22
+ isInitialized(): boolean;
23
+ isConnected(): boolean;
24
+ isEnabled(): boolean
25
+ connect(input: MediaStream): MediaStream;
26
+ disconnect(): void;
27
+ enable(): void;
28
+ disable(): void;
29
+ destroy(): void;
30
+ setLogging(enable: boolean):void;
31
+ isSupported(audioContext: AudioContext):boolean;
32
+ getVersion(): string;
33
+ }
34
+
35
+ const ensureVersionSupported = ({ supportedVersion, plugin, log }: {supportedVersion: string, plugin: NoiseCancellationPlugin, log: typeof Log}) : void => {
36
+ if (!plugin.getVersion || !plugin.isSupported) {
37
+ throw new Error('Plugin does not export getVersion/isSupported api. Are you using old version of the plugin ?');
38
+ }
39
+
40
+ const pluginVersion = plugin.getVersion();
41
+ log.debug(`Plugin Version = ${pluginVersion}`);
42
+ const supportedVersions = supportedVersion.split('.').map(version => Number(version));
43
+ const pluginVersions = pluginVersion.split('.').map(version => Number(version));
44
+ if (supportedVersions.length !== 3 || pluginVersions.length !== 3) {
45
+ throw new Error(`Unsupported Plugin version format: ${supportedVersion}, ${pluginVersion}`);
46
+ }
47
+
48
+ if (supportedVersions[0] !== pluginVersions[0]) {
49
+ throw new Error(`Major version mismatch: [Plugin version ${pluginVersion}], [Supported Version ${supportedVersion}]`);
50
+ }
51
+
52
+ if (pluginVersions[1] < supportedVersions[1]) {
53
+ throw new Error(`Minor version mismatch: [Plugin version ${pluginVersion}] < [Supported Version ${supportedVersion}]`);
54
+ }
55
+
56
+ const tempContext = new AudioContext();
57
+ const isSupported = plugin.isSupported(tempContext);
58
+ tempContext.close();
59
+ if (!isSupported) {
60
+ throw new Error('Noise Cancellation plugin is not supported on your browser');
61
+ }
62
+ };
63
+
64
+ let audioProcessors = new Map<string, AudioProcessor>();
65
+ export async function createNoiseCancellationAudioProcessor(
66
+ noiseCancellationOptions: NoiseCancellationOptions,
67
+ log: typeof Log
68
+ ) : Promise<AudioProcessor> {
69
+ let audioProcessor = audioProcessors.get(noiseCancellationOptions.vendor);
70
+ if (!audioProcessor) {
71
+ let pluginConfig = PLUGIN_CONFIG[noiseCancellationOptions.vendor];
72
+ if (!pluginConfig) {
73
+ throw new Error(`Unsupported NoiseCancellationOptions.vendor: ${noiseCancellationOptions.vendor}`);
74
+ }
75
+
76
+ const { supportedVersion, pluginFile } = pluginConfig;
77
+ const rootDir = noiseCancellationOptions.sdkAssetsPath;
78
+ const sdkFilePath = `${rootDir}/${pluginFile}`;
79
+
80
+ try {
81
+ log.debug('loading noise cancellation sdk: ', sdkFilePath);
82
+ const dynamicModule = await dynamicImport(sdkFilePath);
83
+ log.debug('Loaded noise cancellation sdk:', dynamicModule);
84
+
85
+ const plugin = dynamicModule.default as NoiseCancellationPlugin;
86
+ ensureVersionSupported({
87
+ supportedVersion,
88
+ plugin,
89
+ log
90
+ });
91
+
92
+ if (!plugin.isInitialized()) {
93
+ log.debug('initializing noise cancellation sdk: ', rootDir);
94
+ await plugin.init({ rootDir });
95
+ log.debug('noise cancellation sdk initialized!');
96
+ }
97
+
98
+ audioProcessor = {
99
+ vendor: noiseCancellationOptions.vendor,
100
+ isInitialized: () => plugin.isInitialized(),
101
+ isConnected: () => plugin.isConnected(),
102
+ isEnabled: () => plugin.isEnabled(),
103
+ disconnect: () => plugin.disconnect(),
104
+ enable: () => plugin.enable(),
105
+ disable: () => plugin.disable(),
106
+ destroy: () => plugin.destroy(),
107
+ setLogging: (enable: boolean) => plugin.setLogging(enable),
108
+ connect: (sourceTrack: MediaStreamTrack) => {
109
+ log.debug('connect: ', sourceTrack.id);
110
+ if (plugin.isConnected()) {
111
+ plugin.disconnect();
112
+ }
113
+
114
+ const mediaStream = plugin.connect(new MediaStream([sourceTrack]));
115
+ if (!mediaStream) {
116
+ throw new Error('Error connecting with noise cancellation sdk');
117
+ }
118
+ const cleanTrack = mediaStream.getAudioTracks()[0];
119
+ if (!cleanTrack) {
120
+ throw new Error('Error getting clean track from noise cancellation sdk');
121
+ }
122
+ plugin.enable();
123
+ return cleanTrack;
124
+ },
125
+ };
126
+ audioProcessors.set(noiseCancellationOptions.vendor, audioProcessor);
127
+
128
+ } catch (er) {
129
+ log.error(`Error loading noise cancellation sdk:${sdkFilePath}`, er);
130
+ throw er;
131
+ }
132
+ }
133
+ return audioProcessor;
134
+ }
@@ -9,7 +9,7 @@ import { getTurnCredentials } from './getturncredentials';
9
9
  import { makeStat } from './makestat';
10
10
  import { syntheticAudio } from './syntheticaudio';
11
11
  import { syntheticVideo } from './syntheticvideo';
12
- import { waitForSometime } from '../util';
12
+ import { waitForSometime } from '../util/index';
13
13
 
14
14
  const { WS_SERVER } = require('../util/constants');
15
15
  const Log = require('../util/log');
package/lib/room.js CHANGED
@@ -130,6 +130,7 @@ class Room extends EventEmitter {
130
130
  handleLocalParticipantEvents(this, localParticipant);
131
131
  handleRecordingEvents(this, signaling.recording);
132
132
  handleSignalingEvents(this, signaling);
133
+ verifyNoiseCancellation(this);
133
134
 
134
135
  log.info('Created a new Room:', this.name);
135
136
  log.debug('Initial RemoteParticipants:', Array.from(this._participants.values()));
@@ -139,6 +140,7 @@ class Room extends EventEmitter {
139
140
  return `[Room #${this._instanceId}: ${this.sid}]`;
140
141
  }
141
142
 
143
+
142
144
  /**
143
145
  * Disconnect from the {@link Room}.
144
146
  * @returns {this}
@@ -171,6 +173,17 @@ class Room extends EventEmitter {
171
173
  }
172
174
  }
173
175
 
176
+ function verifyNoiseCancellation(room) {
177
+ const allowedAudioProcessors = room.localParticipant._signaling.audioProcessors;
178
+ room.localParticipant.audioTracks.forEach(({ track }) => {
179
+ const noiseCancellation = track.noiseCancellation;
180
+ if (noiseCancellation && !allowedAudioProcessors.includes(noiseCancellation.vendor)) {
181
+ room._log.warn(`${noiseCancellation.vendor} is not supported in this room. disabling it permanently`);
182
+ noiseCancellation.disablePermanently();
183
+ }
184
+ });
185
+ }
186
+
174
187
  function rewriteLocalTrackIds(room, trackStats) {
175
188
  const localParticipantSignaling = room.localParticipant._signaling;
176
189
  return trackStats.reduce((trackStats, trackStat) => {
@@ -19,10 +19,11 @@ class LocalParticipantSignaling extends ParticipantSignaling {
19
19
  * @param {DataTrackSender|MediaTrackSender} trackSender
20
20
  * @param {string} name
21
21
  * @param {Track.Priority} priority
22
+ * @param {?NoiseCancellationVendor} noiseCancellationVendor
22
23
  * @returns {LocalTrackPublicationSignaling} publication
23
24
  */
24
- addTrack(trackSender, name, priority) {
25
- const publication = this._createLocalTrackPublicationSignaling(trackSender, name, priority);
25
+ addTrack(trackSender, name, priority, noiseCancellationVendor = null) {
26
+ const publication = this._createLocalTrackPublicationSignaling(trackSender, name, priority, noiseCancellationVendor);
26
27
  this._trackSendersToPublications.set(trackSender, publication);
27
28
  this._publicationsToTrackSenders.set(publication, trackSender);
28
29
  super.addTrack(publication);
@@ -124,9 +124,6 @@ function createCancelableRoomSignalingPromise(token, wsServer, localParticipant,
124
124
  reject(new SignalingIncomingMessageInvalidError());
125
125
  return;
126
126
  }
127
-
128
- const { options: { signaling_region: signalingRegion } } = initialState;
129
- localParticipant.setSignalingRegion(signalingRegion);
130
127
  resolve(new RoomV2(localParticipant, initialState, transport, peerConnectionManager, options));
131
128
  });
132
129
 
@@ -65,6 +65,10 @@ class LocalParticipantV2 extends LocalParticipantSignaling {
65
65
  value: null,
66
66
  writable: true
67
67
  },
68
+ audioProcessors: {
69
+ value: [],
70
+ writable: true
71
+ },
68
72
  bandwidthProfile: {
69
73
  enumerable: true,
70
74
  get() {
@@ -125,6 +129,14 @@ class LocalParticipantV2 extends LocalParticipantSignaling {
125
129
  }
126
130
  }
127
131
 
132
+ /**
133
+ * Sets the AudioProcessors enabled for this room.
134
+ * @param {string[]} audioProcessors
135
+ */
136
+ setAudioProcessors(audioProcessors) {
137
+ this.audioProcessors = audioProcessors;
138
+ }
139
+
128
140
  /**
129
141
  * returns current {@link EncodingParametersImpl}.
130
142
  * @returns {EncodingParametersImpl}
@@ -184,10 +196,11 @@ class LocalParticipantV2 extends LocalParticipantSignaling {
184
196
  * @param {DataTrackSender|MediaTrackSender} trackSender
185
197
  * @param {string} name
186
198
  * @param {Track.Priority} priority
199
+ * @param {?NoiseCancellationVendor} noiseCancellationVendor
187
200
  * @returns {LocalTrackPublicationV2}
188
201
  */
189
- _createLocalTrackPublicationSignaling(trackSender, name, priority) {
190
- return new this._LocalTrackPublicationV2(trackSender, name, priority, { log: this._log });
202
+ _createLocalTrackPublicationSignaling(trackSender, name, priority, noiseCancellationVendor) {
203
+ return new this._LocalTrackPublicationV2(trackSender, name, priority, noiseCancellationVendor, { log: this._log });
191
204
  }
192
205
 
193
206
  /**
@@ -198,8 +211,8 @@ class LocalParticipantV2 extends LocalParticipantSignaling {
198
211
  * @param {Track.Priority} priority
199
212
  * @returns {this}
200
213
  */
201
- addTrack(trackSender, name, priority) {
202
- super.addTrack(trackSender, name, priority);
214
+ addTrack(trackSender, name, priority, noiseCancellationVendor) {
215
+ super.addTrack(trackSender, name, priority, noiseCancellationVendor);
203
216
  const publication = this.getPublication(trackSender);
204
217
 
205
218
  let {
@@ -13,10 +13,12 @@ class LocalTrackPublicationV2 extends LocalTrackPublicationSignaling {
13
13
  * @param {DataTrackSender|MediaTrackSender} trackSender
14
14
  * @param {string} name
15
15
  * @param {Track.Priority} priority
16
+ * @param {?NoiseCancellationVendor} noiseCancellationVendor
16
17
  * @param {object} [options]
17
18
  */
18
- constructor(trackSender, name, priority, options) {
19
+ constructor(trackSender, name, priority, noiseCancellationVendor, options) {
19
20
  super(trackSender, name, priority);
21
+
20
22
  Object.defineProperties(this, {
21
23
  _log: {
22
24
  value: options.log.createLog('default', this)
@@ -24,6 +26,9 @@ class LocalTrackPublicationV2 extends LocalTrackPublicationSignaling {
24
26
  _mediaStates: {
25
27
  value: { recordings: null },
26
28
  writable: true
29
+ },
30
+ _noiseCancellationVendor: {
31
+ value: noiseCancellationVendor,
27
32
  }
28
33
  });
29
34
  }
@@ -33,13 +38,19 @@ class LocalTrackPublicationV2 extends LocalTrackPublicationSignaling {
33
38
  * @returns {LocalTrackPublicationV2#Representation} - without the SID
34
39
  */
35
40
  getState() {
36
- return {
41
+ const state = {
37
42
  enabled: this.isEnabled,
38
43
  id: this.id,
39
44
  kind: this.kind,
40
45
  name: this.name,
41
- priority: this.updatedPriority
46
+ priority: this.updatedPriority,
42
47
  };
48
+
49
+ if (this._noiseCancellationVendor) {
50
+ // eslint-disable-next-line camelcase
51
+ state.audio_processor = this._noiseCancellationVendor;
52
+ }
53
+ return state;
43
54
  }
44
55
 
45
56
  toString() {
@@ -52,6 +52,18 @@ class RoomV2 extends RoomSignaling {
52
52
  }, options);
53
53
 
54
54
  localParticipant.setBandwidthProfile(options.bandwidthProfile);
55
+
56
+ const { options: { signaling_region: signalingRegion, audio_processors: audioProcessors = [] } } = initialState;
57
+ localParticipant.setSignalingRegion(signalingRegion);
58
+
59
+
60
+ if (audioProcessors.includes('krisp')) {
61
+ // Note(mpatwardhan): we add rnnoise as allowed_processor to enable testing our pipeline e2e.
62
+ audioProcessors.push('rnnoise');
63
+ }
64
+
65
+ localParticipant.setAudioProcessors(audioProcessors);
66
+
55
67
  peerConnectionManager.setIceReconnectTimeout(options.sessionTimeout);
56
68
 
57
69
  super(localParticipant, initialState.sid, initialState.name, options);
@@ -154,7 +166,7 @@ class RoomV2 extends RoomSignaling {
154
166
  this._update(initialState);
155
167
 
156
168
  // NOTE(mpatwardhan) after initial state we know if publisher_hints are enabled or not
157
- // if they are not enabled. we need to undo simulcast that if it was enabled with initial offer.
169
+ // if they are not enabled. we need to undo simulcast that was enabled with initial offer.
158
170
  this._peerConnectionManager.setEffectiveAdaptiveSimulcast(this._publisherHintsSignaling.isSetup);
159
171
  }
160
172
 
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Copyright (c) 2018 uupaa and 2019 Google LLC
3
+ * Licensed under the MIT license.
4
+ *
5
+ * Copied from https://github.com/GoogleChromeLabs/dynamic-import-polyfill
6
+ */
7
+
8
+ module.exports = (function(scope) {
9
+ const { document, location, Blob, URL } = scope;
10
+ if ([document, location, Blob, URL].some(api => !api)) {
11
+ return function dynamicImportNotSupported(module) {
12
+ return Promise.reject(new Error(`Failed to import: ${module}: dynamicImport is not supported`));
13
+ };
14
+ }
15
+ const cleanupScript = script => {
16
+ URL.revokeObjectURL(script.src);
17
+ script.remove();
18
+ };
19
+ scope.__twilioImportedModules = {
20
+ // Imported module map.
21
+ };
22
+ return function dynamicImport(module) {
23
+ return new Promise((resolve, reject) => {
24
+ const absURL = new URL(module, location);
25
+ const moduleBlob = new Blob([
26
+ `import * as m from '${absURL}';`,
27
+ `window.__twilioImportedModules['${absURL}']=m;`
28
+ ], { type: 'text/javascript' });
29
+ const script = Object.assign(document.createElement('script'), {
30
+ type: 'module',
31
+ src: URL.createObjectURL(moduleBlob),
32
+ onerror() {
33
+ cleanupScript(script);
34
+ reject(new Error(`Failed to import: ${absURL}`));
35
+ },
36
+ onload() {
37
+ cleanupScript(script);
38
+ resolve(scope.__twilioImportedModules[absURL]);
39
+ },
40
+ });
41
+ document.head.appendChild(script);
42
+ });
43
+ };
44
+ }(globalThis));
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.22.2",
5
+ "version": "2.24.1",
6
6
  "homepage": "https://twilio.com",
7
7
  "author": "Mark Andrus Roberts <mroberts@twilio.com>",
8
8
  "contributors": [
@@ -135,7 +135,7 @@
135
135
  "test:framework:install": "npm install chromedriver && npm install selenium-webdriver && npm install geckodriver && npm install puppeteer",
136
136
  "test:framework": "npm-run-all test:framework:install test:framework:no-framework test:framework:react",
137
137
  "test": "npm-run-all test:unit test:integration",
138
- "build:es5": "rimraf ./es5 && tsc tsdef/twilio-video-tests.ts --noEmit --lib es2018,dom && tsc ",
138
+ "build:es5": "rimraf ./es5 && mkdir -p es5 && tsc tsdef/twilio-video-tests.ts --noEmit --lib es2018,dom && tsc",
139
139
  "build:js": "node ./scripts/build.js ./src/twilio-video.js ./LICENSE.md ./dist/twilio-video.js",
140
140
  "build:min.js": "uglifyjs ./dist/twilio-video.js -o ./dist/twilio-video.min.js --comments \"/^! twilio-video.js/\" -b beautify=false,ascii_only=true",
141
141
  "build": "npm-run-all clean lint docs test:unit test:integration build:es5 build:js build:min.js test:umd",
package/tsconfig.json CHANGED
@@ -7,6 +7,7 @@
7
7
  "lib": ["es2019", "dom"],
8
8
  "downlevelIteration": true,
9
9
  "module": "commonjs",
10
+ "moduleResolution": "node",
10
11
  "noImplicitAny": true,
11
12
  "noImplicitThis": true,
12
13
  "outDir": "./es5",