twilio-video 2.22.0 → 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.
- package/CHANGELOG.md +67 -1
- package/README.md +1 -1
- package/assets/noisecancellation/rnnoise/rnnoise-processor.wasm +0 -0
- package/assets/noisecancellation/rnnoise/rnnoise_processor.js +103 -0
- package/assets/noisecancellation/rnnoise/rnnoise_sdk.mjs +150 -0
- package/dist/twilio-video.js +710 -220
- package/dist/twilio-video.min.js +21 -20
- package/es5/connect.js +1 -1
- package/es5/connect.js.map +1 -1
- package/es5/createlocaltrack.js +38 -8
- package/es5/createlocaltrack.js.map +1 -1
- package/es5/createlocaltracks.js +36 -11
- package/es5/createlocaltracks.js.map +1 -1
- package/es5/dynamicImport.js +9 -0
- package/es5/index.js +1 -1
- package/es5/index.js.map +1 -1
- package/es5/localparticipant.js +10 -1
- package/es5/localparticipant.js.map +1 -1
- package/es5/media/track/localaudiotrack.js +27 -1
- package/es5/media/track/localaudiotrack.js.map +1 -1
- package/es5/media/track/noisecancellationimpl.js +198 -0
- package/es5/media/track/noisecancellationimpl.js.map +1 -0
- package/es5/noisecancellationadapter.js +122 -0
- package/es5/noisecancellationadapter.js.map +1 -0
- package/es5/preflight/preflighttest.js +2 -2
- package/es5/preflight/preflighttest.js.map +1 -1
- package/es5/room.js +12 -0
- package/es5/room.js.map +1 -1
- package/es5/signaling/localparticipant.js +4 -2
- package/es5/signaling/localparticipant.js.map +1 -1
- package/es5/signaling/v2/cancelableroomsignalingpromise.js +0 -2
- package/es5/signaling/v2/cancelableroomsignalingpromise.js.map +1 -1
- package/es5/signaling/v2/localparticipant.js +16 -4
- package/es5/signaling/v2/localparticipant.js.map +1 -1
- package/es5/signaling/v2/localtrackpublication.js +12 -3
- package/es5/signaling/v2/localtrackpublication.js.map +1 -1
- package/es5/signaling/v2/peerconnection.js +23 -7
- package/es5/signaling/v2/peerconnection.js.map +1 -1
- package/es5/signaling/v2/room.js +8 -1
- package/es5/signaling/v2/room.js.map +1 -1
- package/es5/util/support.js +2 -0
- package/es5/util/support.js.map +1 -1
- package/es5/webrtc/util/sdp.js +10 -1
- package/es5/webrtc/util/sdp.js.map +1 -1
- package/karma/makeconf.js +11 -1
- package/lib/connect.js +2 -1
- package/lib/createlocaltrack.js +41 -8
- package/lib/createlocaltracks.ts +35 -11
- package/lib/dynamicImport.js +9 -0
- package/lib/index.ts +5 -3
- package/lib/localparticipant.js +10 -1
- package/lib/media/track/localaudiotrack.js +27 -0
- package/lib/media/track/noisecancellationimpl.ts +143 -0
- package/lib/noisecancellationadapter.ts +93 -0
- package/lib/preflight/preflighttest.ts +1 -1
- package/lib/room.js +13 -0
- package/lib/signaling/localparticipant.js +3 -2
- package/lib/signaling/v2/cancelableroomsignalingpromise.js +0 -3
- package/lib/signaling/v2/localparticipant.js +17 -4
- package/lib/signaling/v2/localtrackpublication.js +14 -3
- package/lib/signaling/v2/peerconnection.js +22 -7
- package/lib/signaling/v2/room.js +13 -1
- package/lib/util/support.js +2 -0
- package/lib/webrtc/util/sdp.js +11 -1
- package/package.json +2 -2
- package/tsconfig.json +4 -0
- package/tsdef/AudioProcessor.d.ts +65 -0
- package/tsdef/LocalAudioTrack.d.ts +2 -0
- package/tsdef/index.d.ts +7 -2
- package/tsdef/types.d.ts +23 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,72 @@ 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
|
+
```
|
|
49
|
+
2.22.2 (July 25, 2022)
|
|
50
|
+
======================
|
|
51
|
+
|
|
52
|
+
Changes
|
|
53
|
+
-------
|
|
54
|
+
|
|
55
|
+
- `isSupported` flag now returns `false` if the browser does not support the Unified Plan SDP format. (VIDEO-10307)
|
|
56
|
+
|
|
57
|
+
The following is a list of browsers with Unified Plan as the default SDP format.
|
|
58
|
+
- Chrome 72+
|
|
59
|
+
- Safari 12.1+
|
|
60
|
+
- Firefox 38+
|
|
61
|
+
|
|
62
|
+
2.22.1 (July 11, 2022)
|
|
63
|
+
======================
|
|
64
|
+
|
|
65
|
+
Bug Fixes
|
|
66
|
+
---------
|
|
67
|
+
|
|
68
|
+
- The encoding of audio and screen share Tracks are prioritized in Chrome and Safari, thereby more gracefully degrading
|
|
69
|
+
their quality in limited network conditions. (VIDEO-10212)
|
|
70
|
+
|
|
5
71
|
2.22.0 (July 5, 2022)
|
|
6
72
|
====================
|
|
7
73
|
|
|
@@ -76,7 +142,7 @@ Bug Fixes
|
|
|
76
142
|
Bug Fixes
|
|
77
143
|
---------
|
|
78
144
|
|
|
79
|
-
- Fixed an issue where
|
|
145
|
+
- Fixed an issue where publishing a video track sometimes caused a failure with "Unhandled exception: Client is unable to create or apply a local media description". (VIDEO-9511)
|
|
80
146
|
- Fixed an issue where the `dimensionsChanged` event was not firing when the track dimensions first became available. (VIDEO-3576)
|
|
81
147
|
- Removed references to node dependencies that causes build errors on Angular and Vue. (VIDEO-9282)
|
|
82
148
|
- Fixed an issue where incorrect device was detected when using iPad in Desktop Website mode. (VIDEO-8282)
|
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 <script> tag.
|
|
75
75
|
|
|
76
76
|
```html
|
|
77
|
-
<script src="//sdk.twilio.com/js/video/releases/2.
|
|
77
|
+
<script src="//sdk.twilio.com/js/video/releases/2.23.0/twilio-video.min.js"></script>
|
|
78
78
|
|
|
79
79
|
```
|
|
80
80
|
|
|
Binary file
|
|
@@ -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
|
+
|