twilio-video 2.22.2 → 2.23.0

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 (61) hide show
  1. package/CHANGELOG.md +45 -1
  2. package/README.md +1 -1
  3. package/assets/noisecancellation/rnnoise/rnnoise-processor.wasm +0 -0
  4. package/assets/noisecancellation/rnnoise/rnnoise_processor.js +103 -0
  5. package/assets/noisecancellation/rnnoise/rnnoise_sdk.mjs +150 -0
  6. package/dist/twilio-video.js +675 -212
  7. package/dist/twilio-video.min.js +21 -20
  8. package/es5/connect.js +1 -1
  9. package/es5/connect.js.map +1 -1
  10. package/es5/createlocaltrack.js +38 -8
  11. package/es5/createlocaltrack.js.map +1 -1
  12. package/es5/createlocaltracks.js +36 -11
  13. package/es5/createlocaltracks.js.map +1 -1
  14. package/es5/dynamicImport.js +9 -0
  15. package/es5/index.js +1 -1
  16. package/es5/index.js.map +1 -1
  17. package/es5/localparticipant.js +10 -1
  18. package/es5/localparticipant.js.map +1 -1
  19. package/es5/media/track/localaudiotrack.js +27 -1
  20. package/es5/media/track/localaudiotrack.js.map +1 -1
  21. package/es5/media/track/noisecancellationimpl.js +198 -0
  22. package/es5/media/track/noisecancellationimpl.js.map +1 -0
  23. package/es5/noisecancellationadapter.js +122 -0
  24. package/es5/noisecancellationadapter.js.map +1 -0
  25. package/es5/preflight/preflighttest.js +2 -2
  26. package/es5/preflight/preflighttest.js.map +1 -1
  27. package/es5/room.js +12 -0
  28. package/es5/room.js.map +1 -1
  29. package/es5/signaling/localparticipant.js +4 -2
  30. package/es5/signaling/localparticipant.js.map +1 -1
  31. package/es5/signaling/v2/cancelableroomsignalingpromise.js +0 -2
  32. package/es5/signaling/v2/cancelableroomsignalingpromise.js.map +1 -1
  33. package/es5/signaling/v2/localparticipant.js +16 -4
  34. package/es5/signaling/v2/localparticipant.js.map +1 -1
  35. package/es5/signaling/v2/localtrackpublication.js +12 -3
  36. package/es5/signaling/v2/localtrackpublication.js.map +1 -1
  37. package/es5/signaling/v2/room.js +8 -1
  38. package/es5/signaling/v2/room.js.map +1 -1
  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/dynamicImport.js +9 -0
  44. package/lib/index.ts +5 -3
  45. package/lib/localparticipant.js +10 -1
  46. package/lib/media/track/localaudiotrack.js +27 -0
  47. package/lib/media/track/noisecancellationimpl.ts +143 -0
  48. package/lib/noisecancellationadapter.ts +93 -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/package.json +2 -2
  57. package/tsconfig.json +4 -0
  58. package/tsdef/AudioProcessor.d.ts +65 -0
  59. package/tsdef/LocalAudioTrack.d.ts +2 -0
  60. package/tsdef/index.d.ts +7 -2
  61. package/tsdef/types.d.ts +23 -2
package/CHANGELOG.md CHANGED
@@ -2,6 +2,50 @@ The Twilio Programmable Video SDKs use [Semantic Versioning](http://www.semver.o
2
2
 
3
3
  **Version 1.x reached End of Life on September 8th, 2021.** See the changelog entry [here](https://www.twilio.com/changelog/end-of-life-complete-for-unsupported-versions-of-the-programmable-video-sdk). Support for the 1.x version ended on December 4th, 2020.
4
4
 
5
+ 2.23.0 (July 28, 2022)
6
+ ======================
7
+
8
+ New Features
9
+ ------------
10
+
11
+ - This release adds private beta support for 3rd party noise cancellation solution. You need to host twilio approved 3rd party plugin on your web server to enable noise cancellation. Please fill out [this form](https://forms.gle/eeFyoGJj1mgMrxN88) to request access to the 3rd party plugin.
12
+
13
+ Once you get the access to the plugin, You can install it from npm with:
14
+ ```
15
+ npm install <noise_cancellation_plugin>
16
+ ```
17
+
18
+ Once installed, you need to host the contents of `./node_modules/<noise_cancellation_plugin>/dist/` from your web server. We recommend that you add plugin version number to the hosted path to ensure that browser does not use [stale version](https://www.keycdn.com/support/what-is-cache-busting) when its updated. You need to pass the path to the hosted files to `twilio-video` sdk when creating audio track as shown in the example below. The example below assumes that you have hosted the files at `/noise_cancellation_plugin/1.0.0/dist` on your web server.
19
+
20
+ ```ts
21
+ const { connect, createLocalAudioTrack } = require('twilio-video');
22
+
23
+ // create a local audio track and have it use
24
+ // @twilio/krisp-audio-plugin for noise cancellation processing.
25
+ const localAudioTrack = await Video.createLocalAudioTrack({
26
+ noiseCancellationOptions: {
27
+ vendor: 'krisp',
28
+ sdkAssetsPath: '/noise_cancellation_plugin/1.0.0/dist'
29
+ }
30
+ });
31
+
32
+ // publish the track to a room
33
+ const room = await connect( token, {
34
+ tracks: [localAudioTrack]
35
+ // ... any other connect options
36
+ });
37
+
38
+ // you can enable/disable noise cancellation at runtime
39
+ // using noiseCancellation interface exposed by localAudioTrack
40
+ function updateNoiseCancellation(enable: boolean) {
41
+ const noiseCancellation = localAudioTrack.noiseCancellation;
42
+
43
+ if (noiseCancellation) {
44
+ enable ? noiseCancellation.enable() : noiseCancellation.disable();
45
+ }
46
+ }
47
+
48
+ ```
5
49
  2.22.2 (July 25, 2022)
6
50
  ======================
7
51
 
@@ -9,7 +53,7 @@ Changes
9
53
  -------
10
54
 
11
55
  - `isSupported` flag now returns `false` if the browser does not support the Unified Plan SDP format. (VIDEO-10307)
12
-
56
+
13
57
  The following is a list of browsers with Unified Plan as the default SDP format.
14
58
  - Chrome 72+
15
59
  - Safari 12.1+
package/README.md CHANGED
@@ -74,7 +74,7 @@ Releases of twilio-video.js are hosted on a CDN, and you can include these
74
74
  directly in your web app using a &lt;script&gt; tag.
75
75
 
76
76
  ```html
77
- <script src="//sdk.twilio.com/js/video/releases/2.22.2/twilio-video.min.js"></script>
77
+ <script src="//sdk.twilio.com/js/video/releases/2.23.0/twilio-video.min.js"></script>
78
78
 
79
79
  ```
80
80
 
@@ -0,0 +1,103 @@
1
+ 'use strict';
2
+ let rnnoiseExports = null;
3
+ let heapFloat32;
4
+ let processCount = 0;
5
+ class RNNNoiseProcessor extends AudioWorkletProcessor {
6
+ constructor(options) {
7
+ super(Object.assign(Object.assign({}, options), { numberOfInputs: 1, numberOfOutputs: 1, outputChannelCount: [1] }));
8
+ if (!rnnoiseExports) {
9
+ rnnoiseExports = new WebAssembly.Instance(options.processorOptions.module).exports;
10
+ heapFloat32 = new Float32Array(rnnoiseExports.memory.buffer);
11
+ }
12
+ // enable
13
+ // disable
14
+ // destroy
15
+ // enableLogging
16
+ // disableLogging
17
+ this.logging = true;
18
+ this.keepAlive = true;
19
+ if (options.processorOptions.activeInitially) {
20
+ this.log('activeInitially');
21
+ this.state = rnnoiseExports.newState();
22
+ } else {
23
+ this.log('NOT activeInitially');
24
+ this.state = null;
25
+ }
26
+
27
+ this.port.onmessage = ({ data: command }) => {
28
+ let vadProb = 0;
29
+ this.log('handling command: ', command);
30
+ switch (command) {
31
+ case 'enable':
32
+ if (!this.state) {
33
+ this.state = rnnoiseExports.newState();
34
+ }
35
+ vadProb = rnnoiseExports.getVadProb(this.state);
36
+ break;
37
+ case 'disable':
38
+ if (this.state) {
39
+ rnnoiseExports.deleteState(this.state);
40
+ this.state = null;
41
+ }
42
+ break;
43
+ case 'destroy':
44
+ if (this.state) {
45
+ rnnoiseExports.deleteState(this.state);
46
+ this.state = null;
47
+ }
48
+ this.keepAlive = false;
49
+ break;
50
+ case 'enableLogging':
51
+ this.logging = true;
52
+ this.log('logging Enabled');
53
+ break;
54
+ case 'disableLogging':
55
+ this.log('Will disable logging');
56
+ this.logging = false;
57
+ break;
58
+ default:
59
+ // eslint-disable-next-line no-console
60
+ console.warn('unknown command: ', command);
61
+ }
62
+ if (command === 'enable' && this.state === null) {
63
+ this.log('processor creating state again');
64
+ this.state = rnnoiseExports.newState();
65
+ }
66
+ this.port.postMessage({
67
+ vadProb,
68
+ isEnabled: this.state !== null,
69
+ isAlive: this.keepAlive
70
+ });
71
+ };
72
+ }
73
+
74
+ log(...messages) {
75
+ if (this.logging) {
76
+ // eslint-disable-next-line no-console
77
+ console.log('rnnoise_processor:', ...messages);
78
+ }
79
+ }
80
+
81
+ process(inputs, outputs, parameters) {
82
+ if (this.state && inputs && inputs.length > 0 && inputs[0].length > 0) {
83
+ heapFloat32.set(inputs[0][0], rnnoiseExports.getInput(this.state) / 4);
84
+ const o = outputs[0][0];
85
+ const ptr4 = rnnoiseExports.pipe(this.state, o.length) / 4;
86
+ if (ptr4) {
87
+ o.set(heapFloat32.subarray(ptr4, ptr4 + o.length));
88
+ }
89
+ } else {
90
+ // rnnoise is turned off.
91
+ // eslint-disable-next-line no-lonely-if
92
+ if (inputs && inputs.length > 0 && inputs[0].length > 0) {
93
+ outputs[0][0].set(inputs[0][0]);
94
+ }
95
+ }
96
+ processCount++;
97
+ if (processCount % 1111 === 0) {
98
+ this.log(`${processCount}: RNNoise ${this.state ? 'enabled' : 'disabled'}`);
99
+ }
100
+ return this.keepAlive;
101
+ }
102
+ }
103
+ registerProcessor('rnnoise', RNNNoiseProcessor);
@@ -0,0 +1,150 @@
1
+ // Author: Makarand Patwardhan
2
+ // Implements interface to interact with twilio-video SDK
3
+
4
+ /* eslint-disable no-console */
5
+ async function fetchAndCompileWebAssemblyModule(moduleUrl) {
6
+ const response = await fetch(moduleUrl);
7
+ const buffer = await response.arrayBuffer();
8
+ const mod = await WebAssembly.compile(buffer);
9
+ return mod;
10
+ }
11
+ class RNNoiseNode extends AudioWorkletNode {
12
+ constructor(context) {
13
+ super(context, 'rnnoise', {
14
+ channelCountMode: 'explicit',
15
+ channelCount: 1,
16
+ channelInterpretation: 'speakers',
17
+ numberOfInputs: 1,
18
+ numberOfOutputs: 1,
19
+ outputChannelCount: [1],
20
+ processorOptions: {
21
+ module: RNNoiseNode.webModule,
22
+ activeInitially: false,
23
+ },
24
+ });
25
+ this._vadProb = 0;
26
+ this._isEnabled = false; // match what we sent in processorOptions.activeInitially.
27
+ this._isAlive = false;
28
+ console.log('RNNoiseNode constructor');
29
+ this.port.onmessage = ({ data }) => {
30
+ this._isEnabled = data.isEnabled;
31
+ this._isAlive = data.isAlive;
32
+ if (data.vadProb) {
33
+ this._vadProb = data.vadProb;
34
+ if (this._onUpdate) {
35
+ this._onUpdate();
36
+ }
37
+ }
38
+ };
39
+ }
40
+ static async register(context, webAssemblyUrl, processorUrl) {
41
+ RNNoiseNode.webModule = await fetchAndCompileWebAssemblyModule(webAssemblyUrl);
42
+ await context.audioWorklet.addModule(processorUrl);
43
+ }
44
+ onUpdate(onupdate) {
45
+ this._onUpdate = onupdate;
46
+ }
47
+ getVadProb() {
48
+ return this._vadProb;
49
+ }
50
+ getIsEnabled() {
51
+ return this._isEnabled;
52
+ }
53
+ enable() {
54
+ this.port.postMessage('enable');
55
+ this._isEnabled = true;
56
+ }
57
+ disable() {
58
+ this.port.postMessage('disable');
59
+ this._isEnabled = false;
60
+ }
61
+ destroy() {
62
+ this.port.postMessage('destroy');
63
+ }
64
+ setLogging(enabled) {
65
+ this.port.postMessage(enabled ? 'enableLogging' : 'disableLogging');
66
+ }
67
+ }
68
+ RNNoiseNode.webModule = null;
69
+ let initialized = false;
70
+ let audioContext = null;
71
+ let connected = false;
72
+ let rnnoiseNode = null;
73
+ let sourceNode = null;
74
+ let destinationNode = null;
75
+ let inputStream = null;
76
+
77
+ const init = async ({ rootDir }) => {
78
+ console.log('rnnoise.init, was initialized = ', initialized);
79
+ audioContext = new AudioContext();
80
+ const wasmPath = rootDir + '/rnnoise-processor.wasm';
81
+ const processorJSPath = rootDir + '/rnnoise_processor.js';
82
+ console.log({ wasmPath, processorJSPath });
83
+ await RNNoiseNode.register(audioContext, wasmPath, processorJSPath);
84
+ initialized = true;
85
+ };
86
+
87
+ const isInitialized = () => initialized;
88
+
89
+ const connect = stream => {
90
+ if (!isInitialized()) {
91
+ throw new Error('you must call init before connect');
92
+ }
93
+ sourceNode = audioContext.createMediaStreamSource(stream);
94
+ if (!rnnoiseNode) {
95
+ rnnoiseNode = new RNNoiseNode(audioContext);
96
+ }
97
+ destinationNode = audioContext.createMediaStreamDestination();
98
+ sourceNode.connect(rnnoiseNode);
99
+ rnnoiseNode.connect(destinationNode);
100
+ const outputStream = destinationNode.stream;
101
+ connected = true;
102
+ inputStream = stream;
103
+ rnnoiseNode.enable();
104
+ return outputStream;
105
+ };
106
+
107
+ const isConnected = () => connected;
108
+
109
+ const disconnect = () => {
110
+ if (connected) {
111
+ connected = false;
112
+ rnnoiseNode.disable();
113
+ rnnoiseNode.disconnect();
114
+ sourceNode.disconnect();
115
+ destinationNode.disconnect();
116
+ inputStream.getTracks().forEach(track => track.stop());
117
+ }
118
+ };
119
+
120
+ const enable = () => connected && rnnoiseNode.enable();
121
+ const isEnabled = () => connected && rnnoiseNode.getIsEnabled();
122
+ const disable = () => connected && rnnoiseNode.disable();
123
+ const destroy = () => {
124
+ initialized = false;
125
+ disconnect();
126
+ if (rnnoiseNode) {
127
+ rnnoiseNode.destroy();
128
+ rnnoiseNode = null;
129
+ }
130
+ };
131
+
132
+ const setLogging = enable => {
133
+ if (rnnoiseNode) {
134
+ rnnoiseNode.setLogging(enable);
135
+ }
136
+ };
137
+
138
+ export default {
139
+ init,
140
+ isInitialized,
141
+ connect,
142
+ isConnected,
143
+ disconnect,
144
+ enable,
145
+ isEnabled,
146
+ disable,
147
+ destroy,
148
+ setLogging,
149
+ };
150
+