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.
- package/CHANGELOG.md +45 -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 +675 -212
- 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/room.js +8 -1
- package/es5/signaling/v2/room.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/room.js +13 -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
|
@@ -0,0 +1,143 @@
|
|
|
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.
|
|
10
|
+
* This interface is exposed on {@link LocalAudioTrack} property `noiseCancellation`. It is available only when
|
|
11
|
+
* {@link NoiseCancellationOptions} are specified when creating a {@link LocalAudioTrack}
|
|
12
|
+
* @alias NoiseCancellation
|
|
13
|
+
* @interface
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* const { connect, createLocalAudioTrack } = require('twilio-video');
|
|
17
|
+
*
|
|
18
|
+
* // create a local audio track and have it use
|
|
19
|
+
* // @twilio/krisp-audio-plugin for noise cancellation processing.
|
|
20
|
+
* const localAudioTrack = await Video.createLocalAudioTrack({
|
|
21
|
+
* noiseCancellationOptions: {
|
|
22
|
+
* vendor: 'krisp',
|
|
23
|
+
* sdkAssetsPath: '/twilio-krisp-audio-plugin/1.0.0/dist'
|
|
24
|
+
* }
|
|
25
|
+
* });
|
|
26
|
+
*
|
|
27
|
+
* // publish the track to a room
|
|
28
|
+
* const room = await connect( token, {
|
|
29
|
+
* tracks: [localAudioTrack]
|
|
30
|
+
* // ... any other connect options
|
|
31
|
+
* });
|
|
32
|
+
*
|
|
33
|
+
* // you can enable/disable noise cancellation at runtime
|
|
34
|
+
* // using noiseCancellation interface exposed by localAudioTrack
|
|
35
|
+
* function updateNoiseCancellation(enable: boolean) {
|
|
36
|
+
* const noiseCancellation = localAudioTrack.noiseCancellation;
|
|
37
|
+
*
|
|
38
|
+
* if (noiseCancellation) {
|
|
39
|
+
* enable ? noiseCancellation.enable() : noiseCancellation.disable();
|
|
40
|
+
* }
|
|
41
|
+
* }
|
|
42
|
+
*/
|
|
43
|
+
export class NoiseCancellationImpl implements NoiseCancellation {
|
|
44
|
+
private _processor: AudioProcessor;
|
|
45
|
+
private _sourceTrack: MediaStreamTrack;
|
|
46
|
+
private _disabledPermanent: boolean;
|
|
47
|
+
constructor(processor: AudioProcessor, originalTrack: MediaStreamTrack) {
|
|
48
|
+
this._processor = processor;
|
|
49
|
+
this._sourceTrack = originalTrack;
|
|
50
|
+
this._disabledPermanent = false;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Identifies the vendor
|
|
55
|
+
* @type {NoiseCancellationVendor}
|
|
56
|
+
*/
|
|
57
|
+
get vendor(): NoiseCancellationVendor {
|
|
58
|
+
return this._processor.vendor;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Underlying MediaStreamTrack
|
|
63
|
+
* @type {MediaStreamTrack}
|
|
64
|
+
*/
|
|
65
|
+
get sourceTrack(): MediaStreamTrack {
|
|
66
|
+
return this._sourceTrack;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Set to true if noise cancellation is currently enabled
|
|
71
|
+
* @type {boolean}
|
|
72
|
+
*/
|
|
73
|
+
get isEnabled(): boolean {
|
|
74
|
+
return this._processor.isEnabled();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Enables noise cancellation
|
|
79
|
+
* @returns {Promise<void>} a promise that resolves when operation is complete.
|
|
80
|
+
*/
|
|
81
|
+
enable() : Promise<void> {
|
|
82
|
+
if (this._disabledPermanent) {
|
|
83
|
+
throw new Error(`${this.vendor} noise cancellation is disabled permanently for this track`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
this._processor.enable();
|
|
87
|
+
return Promise.resolve();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Disables noise cancellation
|
|
92
|
+
* @returns {Promise<void>} a promise that resolves when operation is complete.
|
|
93
|
+
*/
|
|
94
|
+
disable() : Promise<void> {
|
|
95
|
+
this._processor.disable();
|
|
96
|
+
return Promise.resolve();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* @private
|
|
101
|
+
*/
|
|
102
|
+
async reacquireTrack(reacquire: () => Promise<MediaStreamTrack>) : Promise<MediaStreamTrack> {
|
|
103
|
+
const processorWasEnabled = this._processor.isEnabled();
|
|
104
|
+
this._processor.disconnect();
|
|
105
|
+
|
|
106
|
+
const track = await reacquire();
|
|
107
|
+
this._sourceTrack = track;
|
|
108
|
+
|
|
109
|
+
const processedTrack = await this._processor.connect(track);
|
|
110
|
+
if (processorWasEnabled) {
|
|
111
|
+
this._processor.enable();
|
|
112
|
+
} else {
|
|
113
|
+
this._processor.disable();
|
|
114
|
+
}
|
|
115
|
+
return processedTrack;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* @private
|
|
120
|
+
*/
|
|
121
|
+
disablePermanently(): Promise<void> {
|
|
122
|
+
this._disabledPermanent = true;
|
|
123
|
+
return this.disable();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
export async function applyNoiseCancellation(
|
|
129
|
+
mediaStreamTrack: MediaStreamTrack,
|
|
130
|
+
noiseCancellationOptions: NoiseCancellationOptions,
|
|
131
|
+
log: typeof Log
|
|
132
|
+
) : Promise<{ cleanTrack: MediaStreamTrack, noiseCancellation?: NoiseCancellation }> {
|
|
133
|
+
try {
|
|
134
|
+
const processor = await createNoiseCancellationAudioProcessor(noiseCancellationOptions, log);
|
|
135
|
+
const cleanTrack = processor.connect(mediaStreamTrack);
|
|
136
|
+
const noiseCancellation = new NoiseCancellationImpl(processor, mediaStreamTrack);
|
|
137
|
+
return { cleanTrack, noiseCancellation };
|
|
138
|
+
} catch (ex) {
|
|
139
|
+
// in case of failures to load noise cancellation library just return original media stream.
|
|
140
|
+
log.warn(`Failed to create noise cancellation. Returning normal audio track: ${ex}`);
|
|
141
|
+
return { cleanTrack: mediaStreamTrack };
|
|
142
|
+
}
|
|
143
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
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('./dynamicImport');
|
|
8
|
+
const KRISP_PLUGIN_FILE = 'krispsdk.mjs';
|
|
9
|
+
const RNNOISE_PLUGIN_FILE = 'rnnoise_sdk.mjs';
|
|
10
|
+
|
|
11
|
+
// AudioProcessor assumes following interface from the Plugin
|
|
12
|
+
interface NoiseCancellationPlugin {
|
|
13
|
+
init(options: { rootDir: string }): Promise<void>;
|
|
14
|
+
isInitialized(): boolean;
|
|
15
|
+
isConnected(): boolean;
|
|
16
|
+
isEnabled(): boolean
|
|
17
|
+
connect(input: MediaStream): MediaStream;
|
|
18
|
+
disconnect(): void;
|
|
19
|
+
enable(): void;
|
|
20
|
+
disable(): void;
|
|
21
|
+
destroy(): void;
|
|
22
|
+
setLogging(enable: boolean):void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let audioProcessors = new Map<string, AudioProcessor>();
|
|
26
|
+
export async function createNoiseCancellationAudioProcessor(
|
|
27
|
+
noiseCancellationOptions: NoiseCancellationOptions,
|
|
28
|
+
log: typeof Log
|
|
29
|
+
) : Promise<AudioProcessor> {
|
|
30
|
+
let audioProcessor = audioProcessors.get(noiseCancellationOptions.vendor);
|
|
31
|
+
if (!audioProcessor) {
|
|
32
|
+
let sdkFilePath: string;
|
|
33
|
+
let rootDir = noiseCancellationOptions.sdkAssetsPath;
|
|
34
|
+
switch (noiseCancellationOptions.vendor) {
|
|
35
|
+
case 'krisp':
|
|
36
|
+
sdkFilePath = `${rootDir}/${KRISP_PLUGIN_FILE}`;
|
|
37
|
+
break;
|
|
38
|
+
case 'rnnoise':
|
|
39
|
+
sdkFilePath = `${rootDir}/${RNNOISE_PLUGIN_FILE}`;
|
|
40
|
+
break;
|
|
41
|
+
default:
|
|
42
|
+
throw new Error(`Unsupported NoiseCancellationOptions.vendor: ${noiseCancellationOptions.vendor}`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
log.debug('loading noise cancellation sdk: ', sdkFilePath);
|
|
47
|
+
const dynamicModule = await dynamicImport(sdkFilePath);
|
|
48
|
+
log.debug('Loaded noise cancellation sdk:', dynamicModule);
|
|
49
|
+
const plugin = dynamicModule.default as NoiseCancellationPlugin;
|
|
50
|
+
|
|
51
|
+
if (!plugin.isInitialized()) {
|
|
52
|
+
log.debug('initializing noise cancellation sdk: ', rootDir);
|
|
53
|
+
await plugin.init({ rootDir });
|
|
54
|
+
log.debug('noise cancellation sdk initialized!');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
audioProcessor = {
|
|
58
|
+
vendor: noiseCancellationOptions.vendor,
|
|
59
|
+
isInitialized: () => plugin.isInitialized(),
|
|
60
|
+
isConnected: () => plugin.isConnected(),
|
|
61
|
+
isEnabled: () => plugin.isEnabled(),
|
|
62
|
+
disconnect: () => plugin.disconnect(),
|
|
63
|
+
enable: () => plugin.enable(),
|
|
64
|
+
disable: () => plugin.disable(),
|
|
65
|
+
destroy: () => plugin.destroy(),
|
|
66
|
+
setLogging: (enable: boolean) => plugin.setLogging(enable),
|
|
67
|
+
connect: (sourceTrack: MediaStreamTrack) => {
|
|
68
|
+
log.debug('connect: ', sourceTrack.id);
|
|
69
|
+
if (plugin.isConnected()) {
|
|
70
|
+
plugin.disconnect();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const mediaStream = plugin.connect(new MediaStream([sourceTrack]));
|
|
74
|
+
if (!mediaStream) {
|
|
75
|
+
throw new Error('Error connecting with noise cancellation sdk');
|
|
76
|
+
}
|
|
77
|
+
const cleanTrack = mediaStream.getAudioTracks()[0];
|
|
78
|
+
if (!cleanTrack) {
|
|
79
|
+
throw new Error('Error getting clean track from noise cancellation sdk');
|
|
80
|
+
}
|
|
81
|
+
plugin.enable();
|
|
82
|
+
return cleanTrack;
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
audioProcessors.set(noiseCancellationOptions.vendor, audioProcessor);
|
|
86
|
+
|
|
87
|
+
} catch (er) {
|
|
88
|
+
log.error(`Error loading noise cancellation sdk:${sdkFilePath}`, er);
|
|
89
|
+
throw er;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return audioProcessor;
|
|
93
|
+
}
|
|
@@ -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
|
-
|
|
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() {
|
package/lib/signaling/v2/room.js
CHANGED
|
@@ -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
|
|
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
|
|
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.
|
|
5
|
+
"version": "2.23.0",
|
|
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 && cp lib/dynamicImport.js es5/dynamicImport.js && 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",
|
|
@@ -16,5 +17,8 @@
|
|
|
16
17
|
"include": [
|
|
17
18
|
"lib/**/*.ts",
|
|
18
19
|
"lib/**/*.js"
|
|
20
|
+
],
|
|
21
|
+
"exclude": [
|
|
22
|
+
"lib/dynamicImport.js"
|
|
19
23
|
]
|
|
20
24
|
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { NoiseCancellationVendor } from './types';
|
|
2
|
+
|
|
3
|
+
export interface AudioProcessor {
|
|
4
|
+
/**
|
|
5
|
+
* @property {NoiseCancellationVendor} vendor
|
|
6
|
+
*/
|
|
7
|
+
vendor: NoiseCancellationVendor;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* connects and cleans given stream
|
|
11
|
+
* @returns {MediaStreamTrack} clean track
|
|
12
|
+
*/
|
|
13
|
+
connect: (sourceTrack: MediaStreamTrack) => MediaStreamTrack
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* checks if AudioProcessor is currently enabled
|
|
17
|
+
* @returns {boolean} true if audio processor is enabled.
|
|
18
|
+
*/
|
|
19
|
+
isEnabled: () => boolean;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* checks if AudioProcessor is initialized (not destroyed)
|
|
23
|
+
* @returns {boolean} true if audio processor is initialized.
|
|
24
|
+
*/
|
|
25
|
+
isInitialized(): boolean;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* checks if AudioProcessor is connected to a stream
|
|
29
|
+
* @returns {boolean} true if a stream is connected.
|
|
30
|
+
*/
|
|
31
|
+
isConnected(): boolean;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* enables noise cancellation.
|
|
35
|
+
* @returns {void}
|
|
36
|
+
*/
|
|
37
|
+
enable: () => void;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* disables noise cancellation.
|
|
41
|
+
* @returns {void}
|
|
42
|
+
*/
|
|
43
|
+
disable: () => void;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* stops processing previously connected stream
|
|
47
|
+
* @returns {void}
|
|
48
|
+
*/
|
|
49
|
+
disconnect: () => void;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* destroys the processor freeing up any resources
|
|
53
|
+
* @returns {void}
|
|
54
|
+
*/
|
|
55
|
+
destroy:() => void;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* enables/disables logging
|
|
59
|
+
* @param {boolean} [enable] - Specify true to enable logging
|
|
60
|
+
* @returns {void}
|
|
61
|
+
*/
|
|
62
|
+
setLogging:(enable: boolean) => void;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AudioTrack } from './AudioTrack';
|
|
2
2
|
import { LocalTrackOptions } from './LocalTrackOptions';
|
|
3
|
+
import { NoiseCancellation } from './types';
|
|
3
4
|
import { Track } from './Track';
|
|
4
5
|
|
|
5
6
|
export class LocalAudioTrack extends AudioTrack {
|
|
@@ -7,6 +8,7 @@ export class LocalAudioTrack extends AudioTrack {
|
|
|
7
8
|
|
|
8
9
|
id: Track.ID;
|
|
9
10
|
isStopped: boolean;
|
|
11
|
+
noiseCancellation?: NoiseCancellation;
|
|
10
12
|
|
|
11
13
|
disable(): this;
|
|
12
14
|
enable(enabled?: boolean): this;
|
package/tsdef/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
2
|
+
import { CancelablePromise, ConnectOptions, CreateLocalAudioTrackOptions, CreateLocalTrackOptions, CreateLocalTracksOptions, LocalTrack } from './types';
|
|
2
3
|
import { PreflightOptions, PreflightTestReport } from './PreflightTypes';
|
|
3
4
|
import { LocalAudioTrack } from './LocalAudioTrack';
|
|
4
5
|
import { LocalVideoTrack } from './LocalVideoTrack';
|
|
@@ -11,7 +12,7 @@ export const isSupported: boolean;
|
|
|
11
12
|
export const version:string;
|
|
12
13
|
export const Logger: Log.RootLogger;
|
|
13
14
|
export function connect(token: string, options?: ConnectOptions): CancelablePromise<Room>;
|
|
14
|
-
export function createLocalAudioTrack(options?:
|
|
15
|
+
export function createLocalAudioTrack(options?: CreateLocalTracksOptions|CreateLocalAudioTrackOptions): Promise<LocalAudioTrack>;
|
|
15
16
|
export function createLocalTracks(options?: CreateLocalTracksOptions): Promise<LocalTrack[]>;
|
|
16
17
|
export function createLocalVideoTrack(options?: CreateLocalTrackOptions): Promise<LocalVideoTrack>;
|
|
17
18
|
export function runPreflight(token: string, options?: PreflightOptions): PreflightTest;
|
|
@@ -55,6 +56,7 @@ export {
|
|
|
55
56
|
DataTrack,
|
|
56
57
|
DataTrackPublication,
|
|
57
58
|
EncodingParameters,
|
|
59
|
+
CreateLocalAudioTrackOptions,
|
|
58
60
|
LocalAudioTrackStats,
|
|
59
61
|
LocalTrack,
|
|
60
62
|
LocalTrackPublishOptions,
|
|
@@ -72,6 +74,9 @@ export {
|
|
|
72
74
|
NetworkQualitySendOrRecvStats,
|
|
73
75
|
NetworkQualityStats,
|
|
74
76
|
NetworkQualityVerbosity,
|
|
77
|
+
NoiseCancellation,
|
|
78
|
+
NoiseCancellationOptions,
|
|
79
|
+
NoiseCancellationVendor,
|
|
75
80
|
OpusCodecSettings,
|
|
76
81
|
RemoteAudioTrackStats,
|
|
77
82
|
RemoteTrack,
|
package/tsdef/types.d.ts
CHANGED
|
@@ -166,8 +166,29 @@ export interface CreateLocalTrackOptions extends MediaTrackConstraints {
|
|
|
166
166
|
workaroundWebKitBug1208516?: boolean;
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
+
|
|
170
|
+
export type NoiseCancellationVendor = 'krisp' | 'rnnoise';
|
|
171
|
+
|
|
172
|
+
export interface NoiseCancellation {
|
|
173
|
+
readonly vendor: NoiseCancellationVendor;
|
|
174
|
+
readonly sourceTrack: MediaStreamTrack;
|
|
175
|
+
readonly isEnabled: boolean;
|
|
176
|
+
|
|
177
|
+
enable: () => Promise<void>;
|
|
178
|
+
disable: () => Promise<void>;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export interface NoiseCancellationOptions {
|
|
182
|
+
sdkAssetsPath: string;
|
|
183
|
+
vendor: NoiseCancellationVendor;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export interface CreateLocalAudioTrackOptions extends CreateLocalTrackOptions {
|
|
187
|
+
noiseCancellationOptions?: NoiseCancellationOptions;
|
|
188
|
+
}
|
|
189
|
+
|
|
169
190
|
export interface ConnectOptions {
|
|
170
|
-
audio?: boolean | CreateLocalTrackOptions;
|
|
191
|
+
audio?: boolean | CreateLocalTrackOptions| CreateLocalAudioTrackOptions;
|
|
171
192
|
automaticSubscription?: boolean;
|
|
172
193
|
bandwidthProfile?: BandwidthProfileOptions;
|
|
173
194
|
dominantSpeaker?: boolean;
|
|
@@ -205,7 +226,7 @@ export interface ConnectOptions {
|
|
|
205
226
|
}
|
|
206
227
|
|
|
207
228
|
export interface CreateLocalTracksOptions {
|
|
208
|
-
audio?: boolean | CreateLocalTrackOptions;
|
|
229
|
+
audio?: boolean | CreateLocalTrackOptions | CreateLocalAudioTrackOptions;
|
|
209
230
|
/**
|
|
210
231
|
* @deprecated
|
|
211
232
|
*/
|