twilio-video 2.17.0 → 2.18.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.
- package/CHANGELOG.md +39 -2
- package/COMMON_ISSUES.md +130 -0
- package/README.md +24 -15
- package/dist/twilio-video.js +361 -220
- package/dist/twilio-video.min.js +22 -21
- package/es5/connect.js +13 -2
- package/es5/connect.js.map +1 -1
- package/es5/media/track/localmediatrack.js +2 -0
- package/es5/media/track/localmediatrack.js.map +1 -1
- package/es5/media/track/remotevideotrack.js +68 -14
- package/es5/media/track/remotevideotrack.js.map +1 -1
- package/es5/preflight/getCombinedConnectionStats.js +0 -1
- package/es5/preflight/getCombinedConnectionStats.js.map +1 -1
- package/es5/preflight/getturncredentials.js +2 -16
- package/es5/preflight/getturncredentials.js.map +1 -1
- package/es5/preflight/makestat.js +1 -1
- package/es5/preflight/makestat.js.map +1 -1
- package/es5/preflight/preflighttest.js +83 -11
- package/es5/preflight/preflighttest.js.map +1 -1
- package/es5/signaling/v2/cancelableroomsignalingpromise.js +2 -9
- package/es5/signaling/v2/cancelableroomsignalingpromise.js.map +1 -1
- package/es5/signaling/v2/mediasignaling.js +2 -4
- package/es5/signaling/v2/mediasignaling.js.map +1 -1
- package/es5/signaling/v2/peerconnection.js +4 -2
- package/es5/signaling/v2/peerconnection.js.map +1 -1
- package/es5/signaling/v2/twilioconnectiontransport.js +3 -27
- package/es5/signaling/v2/twilioconnectiontransport.js.map +1 -1
- package/es5/util/constants.js +3 -0
- package/es5/util/constants.js.map +1 -1
- package/es5/util/eventobserver.js +9 -19
- package/es5/util/eventobserver.js.map +1 -1
- package/es5/util/index.js +2 -0
- package/es5/util/index.js.map +1 -1
- package/es5/util/sid.js +18 -0
- package/es5/util/sid.js.map +1 -0
- package/es5/util/twilio-video-errors.js +38 -5
- package/es5/util/twilio-video-errors.js.map +1 -1
- package/lib/connect.js +21 -2
- package/lib/media/track/localmediatrack.js +2 -0
- package/lib/media/track/remotevideotrack.js +74 -14
- package/lib/preflight/getCombinedConnectionStats.ts +0 -1
- package/lib/preflight/getturncredentials.ts +2 -12
- package/lib/preflight/makestat.ts +2 -2
- package/lib/preflight/preflighttest.ts +107 -13
- package/lib/signaling/v2/cancelableroomsignalingpromise.js +1 -12
- package/lib/signaling/v2/mediasignaling.js +2 -5
- package/lib/signaling/v2/peerconnection.js +4 -2
- package/lib/signaling/v2/twilioconnectiontransport.js +1 -31
- package/lib/util/constants.js +3 -0
- package/lib/util/eventobserver.js +10 -22
- package/lib/util/index.js +3 -0
- package/lib/util/sid.js +20 -0
- package/lib/util/twilio-video-errors.js +37 -5
- package/package.json +4 -3
- package/tsconfig.json +1 -1
- package/tsdef/PreflightTypes.d.ts +1 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { DEFAULT_LOGGER_NAME, DEFAULT_LOG_LEVEL } from '../util/constants';
|
|
2
|
-
import { PreflightOptions, PreflightTestReport, RTCIceCandidateStats, SelectedIceCandidatePairStats } from '../../tsdef/PreflightTypes';
|
|
1
|
+
import { DEFAULT_ENVIRONMENT, DEFAULT_LOGGER_NAME, DEFAULT_LOG_LEVEL, DEFAULT_REALM, SDK_NAME, SDK_VERSION } from '../util/constants';
|
|
2
|
+
import { PreflightOptions, PreflightTestReport, RTCIceCandidateStats, SelectedIceCandidatePairStats, Stats } from '../../tsdef/PreflightTypes';
|
|
3
3
|
import { StatsReport } from '../../tsdef/types';
|
|
4
4
|
import { Timer } from './timer';
|
|
5
5
|
import { calculateMOS } from './mos';
|
|
@@ -10,9 +10,13 @@ import { syntheticAudio } from './syntheticaudio';
|
|
|
10
10
|
import { syntheticVideo } from './syntheticvideo';
|
|
11
11
|
import { waitForSometime } from '../util';
|
|
12
12
|
|
|
13
|
+
const { WS_SERVER } = require('../util/constants');
|
|
13
14
|
const Log = require('../util/log');
|
|
14
15
|
const EventEmitter = require('../eventemitter');
|
|
15
16
|
const MovingAverageDelta = require('../util/movingaveragedelta');
|
|
17
|
+
const EventObserver = require('../util/eventobserver');
|
|
18
|
+
const InsightsPublisher = require('../util/insightspublisher');
|
|
19
|
+
const { createSID, sessionSID } = require('../util/sid');
|
|
16
20
|
|
|
17
21
|
const SECOND = 1000;
|
|
18
22
|
const DEFAULT_TEST_DURATION = 10 * SECOND;
|
|
@@ -71,6 +75,16 @@ declare interface PreflightStats {
|
|
|
71
75
|
iceCandidateStats: RTCIceCandidateStats[],
|
|
72
76
|
}
|
|
73
77
|
|
|
78
|
+
declare interface PreflightTestReportInternal extends PreflightTestReport {
|
|
79
|
+
error?: string,
|
|
80
|
+
mos?: Stats|null
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
declare interface PreflightOptionsInternal extends PreflightOptions {
|
|
84
|
+
environment?: string;
|
|
85
|
+
wsServer?: string;
|
|
86
|
+
}
|
|
87
|
+
|
|
74
88
|
function notEmpty<TValue>(value: TValue | null | undefined): value is TValue {
|
|
75
89
|
return value !== null && typeof value !== 'undefined';
|
|
76
90
|
}
|
|
@@ -108,12 +122,16 @@ export class PreflightTest extends EventEmitter {
|
|
|
108
122
|
*/
|
|
109
123
|
constructor(token: string, options: PreflightOptions) {
|
|
110
124
|
super();
|
|
125
|
+
const internalOptions = options as PreflightOptionsInternal;
|
|
126
|
+
const { environment = 'prod', region = 'gll', duration = DEFAULT_TEST_DURATION } = internalOptions;
|
|
127
|
+
// eslint-disable-next-line new-cap
|
|
128
|
+
const wsServer = internalOptions.wsServer || WS_SERVER(environment, region);
|
|
129
|
+
|
|
111
130
|
this._log = new Log('default', this, DEFAULT_LOG_LEVEL, DEFAULT_LOGGER_NAME);
|
|
112
|
-
this._testDuration =
|
|
131
|
+
this._testDuration = duration;
|
|
113
132
|
this._instanceId = nInstances++;
|
|
114
|
-
|
|
115
133
|
this._testTiming.start();
|
|
116
|
-
this._runPreflightTest(token,
|
|
134
|
+
this._runPreflightTest(token, environment, wsServer);
|
|
117
135
|
}
|
|
118
136
|
|
|
119
137
|
toString(): string {
|
|
@@ -127,7 +145,7 @@ export class PreflightTest extends EventEmitter {
|
|
|
127
145
|
this._stopped = true;
|
|
128
146
|
}
|
|
129
147
|
|
|
130
|
-
private _generatePreflightReport(collectedStats:
|
|
148
|
+
private _generatePreflightReport(collectedStats?: PreflightStats, error? : Error) : PreflightTestReportInternal {
|
|
131
149
|
this._testTiming.stop();
|
|
132
150
|
return {
|
|
133
151
|
testTiming: this._testTiming.getTimeMeasurement(),
|
|
@@ -139,12 +157,15 @@ export class PreflightTest extends EventEmitter {
|
|
|
139
157
|
media: this._mediaTiming.getTimeMeasurement()
|
|
140
158
|
},
|
|
141
159
|
stats: {
|
|
142
|
-
jitter: makeStat(collectedStats
|
|
143
|
-
rtt: makeStat(collectedStats
|
|
144
|
-
packetLoss: makeStat(collectedStats
|
|
160
|
+
jitter: makeStat(collectedStats?.jitter),
|
|
161
|
+
rtt: makeStat(collectedStats?.rtt),
|
|
162
|
+
packetLoss: makeStat(collectedStats?.packetLoss),
|
|
145
163
|
},
|
|
146
|
-
selectedIceCandidatePairStats: collectedStats.selectedIceCandidatePairStats,
|
|
147
|
-
iceCandidateStats: collectedStats.iceCandidateStats
|
|
164
|
+
selectedIceCandidatePairStats: collectedStats ? collectedStats.selectedIceCandidatePairStats : null,
|
|
165
|
+
iceCandidateStats: collectedStats ? collectedStats.iceCandidateStats : [],
|
|
166
|
+
// NOTE(mpatwardhan): internal properties.
|
|
167
|
+
error: error?.toString(),
|
|
168
|
+
mos: makeStat(collectedStats?.mos),
|
|
148
169
|
};
|
|
149
170
|
}
|
|
150
171
|
|
|
@@ -211,9 +232,79 @@ export class PreflightTest extends EventEmitter {
|
|
|
211
232
|
}
|
|
212
233
|
}
|
|
213
234
|
|
|
214
|
-
private
|
|
235
|
+
private _setupInsights({ token, environment = DEFAULT_ENVIRONMENT, realm = DEFAULT_REALM } : {
|
|
236
|
+
token: string,
|
|
237
|
+
environment?: string,
|
|
238
|
+
realm?: string
|
|
239
|
+
}) {
|
|
240
|
+
const eventPublisherOptions = {};
|
|
241
|
+
const eventPublisher = new InsightsPublisher(
|
|
242
|
+
token,
|
|
243
|
+
SDK_NAME,
|
|
244
|
+
SDK_VERSION,
|
|
245
|
+
environment,
|
|
246
|
+
realm,
|
|
247
|
+
eventPublisherOptions);
|
|
248
|
+
|
|
249
|
+
// event publisher requires room sid/participant sid. supply fake ones.
|
|
250
|
+
eventPublisher.connect('PREFLIGHT_ROOM_SID', 'PREFLIGHT_PARTICIPANT');
|
|
251
|
+
const eventObserver = new EventObserver(eventPublisher, Date.now(), this._log);
|
|
252
|
+
|
|
253
|
+
// eslint-disable-next-line no-undefined
|
|
254
|
+
const undefinedValue = undefined;
|
|
255
|
+
return {
|
|
256
|
+
reportToInsights: ({ report }: { report: PreflightTestReportInternal }) => {
|
|
257
|
+
const jitterStats = report.stats.jitter || undefinedValue;
|
|
258
|
+
const rttStats = report.stats.rtt || undefinedValue;
|
|
259
|
+
const packetLossStats = report.stats.packetLoss || undefinedValue;
|
|
260
|
+
const mosStats = report.mos || undefinedValue;
|
|
261
|
+
|
|
262
|
+
// stringify important info from ice candidates.
|
|
263
|
+
const candidateTypeToProtocols = new Map<string, string[]>();
|
|
264
|
+
report.iceCandidateStats.forEach(candidateStats => {
|
|
265
|
+
if (candidateStats.candidateType && candidateStats.protocol) {
|
|
266
|
+
let protocols = candidateTypeToProtocols.get(candidateStats.candidateType) || [];
|
|
267
|
+
if (protocols.indexOf(candidateStats.protocol) < 0) {
|
|
268
|
+
protocols.push(candidateStats.protocol);
|
|
269
|
+
}
|
|
270
|
+
candidateTypeToProtocols.set(candidateStats.candidateType, protocols);
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
const iceCandidateStats = JSON.stringify(Object.fromEntries(candidateTypeToProtocols));
|
|
274
|
+
|
|
275
|
+
const insightsReport = {
|
|
276
|
+
name: 'report',
|
|
277
|
+
group: 'preflight',
|
|
278
|
+
level: report.error ? 'error' : 'info',
|
|
279
|
+
payload: {
|
|
280
|
+
sessionSID,
|
|
281
|
+
preflightSID: createSID('PF'),
|
|
282
|
+
testTiming: report.testTiming,
|
|
283
|
+
dtlsTiming: report.networkTiming.dtls,
|
|
284
|
+
iceTiming: report.networkTiming.ice,
|
|
285
|
+
peerConnectionTiming: report.networkTiming.peerConnection,
|
|
286
|
+
connectTiming: report.networkTiming.connect,
|
|
287
|
+
mediaTiming: report.networkTiming.media,
|
|
288
|
+
selectedLocalCandidate: report.selectedIceCandidatePairStats?.localCandidate,
|
|
289
|
+
selectedRemoteCandidate: report.selectedIceCandidatePairStats?.remoteCandidate,
|
|
290
|
+
iceCandidateStats,
|
|
291
|
+
jitterStats,
|
|
292
|
+
rttStats,
|
|
293
|
+
packetLossStats,
|
|
294
|
+
mosStats,
|
|
295
|
+
error: report.error
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
eventObserver.emit('event', insightsReport);
|
|
299
|
+
setTimeout(() => eventPublisher.disconnect(), 2000);
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
private async _runPreflightTest(token: string, environment: string, wsServer: string) {
|
|
215
305
|
let localTracks: MediaStreamTrack[] = [];
|
|
216
306
|
let pcs: RTCPeerConnection[] = [];
|
|
307
|
+
const { reportToInsights } = this._setupInsights({ token, environment });
|
|
217
308
|
try {
|
|
218
309
|
let elements = [];
|
|
219
310
|
localTracks = await this._executePreflightStep('Acquire media', () => [syntheticAudio(), syntheticVideo({ width: 640, height: 480 })]);
|
|
@@ -221,7 +312,7 @@ export class PreflightTest extends EventEmitter {
|
|
|
221
312
|
this.emit('debug', { localTracks });
|
|
222
313
|
|
|
223
314
|
this._connectTiming.start();
|
|
224
|
-
let iceServers = await this._executePreflightStep('Get turn credentials', () => getTurnCredentials(token,
|
|
315
|
+
let iceServers = await this._executePreflightStep('Get turn credentials', () => getTurnCredentials(token, wsServer));
|
|
225
316
|
this._connectTiming.stop();
|
|
226
317
|
this.emit('progress', PreflightProgress.connected);
|
|
227
318
|
|
|
@@ -287,9 +378,12 @@ export class PreflightTest extends EventEmitter {
|
|
|
287
378
|
() => this._collectRTCStatsForDuration(this._testDuration, initCollectedStats(), senderPC, receiverPC));
|
|
288
379
|
|
|
289
380
|
const report = await this._executePreflightStep('generate report', () => this._generatePreflightReport(collectedStats));
|
|
381
|
+
reportToInsights({ report });
|
|
290
382
|
this.emit('completed', report);
|
|
291
383
|
|
|
292
384
|
} catch (error) {
|
|
385
|
+
// eslint-disable-next-line no-undefined
|
|
386
|
+
reportToInsights({ report: this._generatePreflightReport(undefined, error) });
|
|
293
387
|
this.emit('failed', error);
|
|
294
388
|
} finally {
|
|
295
389
|
pcs.forEach(pc => pc.close());
|
|
@@ -57,8 +57,6 @@ function createCancelableRoomSignalingPromise(token, wsServer, localParticipant,
|
|
|
57
57
|
};
|
|
58
58
|
|
|
59
59
|
const {
|
|
60
|
-
InsightsPublisher,
|
|
61
|
-
NullInsightsPublisher,
|
|
62
60
|
automaticSubscription,
|
|
63
61
|
bandwidthProfile,
|
|
64
62
|
dominantSpeaker,
|
|
@@ -69,10 +67,8 @@ function createCancelableRoomSignalingPromise(token, wsServer, localParticipant,
|
|
|
69
67
|
name,
|
|
70
68
|
networkMonitor,
|
|
71
69
|
networkQuality,
|
|
72
|
-
insights,
|
|
73
70
|
realm,
|
|
74
71
|
sdpSemantics,
|
|
75
|
-
wsServerInsights
|
|
76
72
|
} = options;
|
|
77
73
|
|
|
78
74
|
// decide which msp channels to request
|
|
@@ -92,20 +88,13 @@ function createCancelableRoomSignalingPromise(token, wsServer, localParticipant,
|
|
|
92
88
|
networkMonitor,
|
|
93
89
|
networkQuality,
|
|
94
90
|
iceServers,
|
|
95
|
-
insights,
|
|
96
91
|
onIced,
|
|
97
92
|
realm,
|
|
98
93
|
renderHints,
|
|
99
94
|
sdpSemantics,
|
|
100
95
|
trackPriority,
|
|
101
96
|
trackSwitchOff
|
|
102
|
-
},
|
|
103
|
-
wsServerInsights
|
|
104
|
-
} : {}, InsightsPublisher ? {
|
|
105
|
-
InsightsPublisher
|
|
106
|
-
} : {}, NullInsightsPublisher ? {
|
|
107
|
-
NullInsightsPublisher
|
|
108
|
-
} : {}, bandwidthProfile ? {
|
|
97
|
+
}, bandwidthProfile ? {
|
|
109
98
|
bandwidthProfile
|
|
110
99
|
} : {});
|
|
111
100
|
|
|
@@ -50,19 +50,16 @@ class MediaSignaling extends EventEmitter {
|
|
|
50
50
|
const receiverPromise = this._getReceiver(id).then(receiver => {
|
|
51
51
|
if (receiver.kind !== 'data') {
|
|
52
52
|
this._log.error('Expected a DataTrackReceiver');
|
|
53
|
-
throw new Error('Expected a DataTrackReceiver');
|
|
54
53
|
} if (this._receiverPromise !== receiverPromise) {
|
|
55
54
|
return;
|
|
56
55
|
}
|
|
57
56
|
|
|
58
57
|
try {
|
|
59
58
|
this._transport = receiver.toDataTransport();
|
|
59
|
+
this.emit('ready', this._transport);
|
|
60
60
|
} catch (ex) {
|
|
61
|
-
this._log.error(
|
|
62
|
-
throw new Error('Failed to toDataTransport');
|
|
61
|
+
this._log.error(`Failed to toDataTransport: ${ex.message}`);
|
|
63
62
|
}
|
|
64
|
-
this.emit('ready', this._transport);
|
|
65
|
-
|
|
66
63
|
receiver.once('close', () => this._teardown());
|
|
67
64
|
});
|
|
68
65
|
this._receiverPromise = receiverPromise;
|
|
@@ -904,7 +904,9 @@ class PeerConnectionV2 extends StateMachine {
|
|
|
904
904
|
log.debug(`Starting ICE reconnect timeout: ${delay}`);
|
|
905
905
|
this._iceReconnectTimeout.start();
|
|
906
906
|
}
|
|
907
|
-
this.offer()
|
|
907
|
+
this.offer().catch(ex => {
|
|
908
|
+
log.error(`offer failed in _initiateIceRestart with: ${ex.message}`);
|
|
909
|
+
});
|
|
908
910
|
}
|
|
909
911
|
|
|
910
912
|
/**
|
|
@@ -1747,7 +1749,7 @@ function updateEncodingParameters(pcv2) {
|
|
|
1747
1749
|
params.encodings[0].networkPriority = 'high';
|
|
1748
1750
|
}
|
|
1749
1751
|
|
|
1750
|
-
if (
|
|
1752
|
+
if (isSafari && sender.track.kind === 'video') {
|
|
1751
1753
|
const { width, height } = sender.track.getSettings();
|
|
1752
1754
|
pcv2._updateEncodings(width, height, params.encodings);
|
|
1753
1755
|
}
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const { getSdpFormat } = require('@twilio/webrtc/lib/util/sdp');
|
|
4
|
-
const packageInfo = require('../../../package.json');
|
|
5
|
-
const InsightsPublisher = require('../../util/insightspublisher');
|
|
6
|
-
const NullInsightsPublisher = require('../../util/insightspublisher/null');
|
|
7
4
|
const StateMachine = require('../../statemachine');
|
|
8
5
|
const TwilioConnection = require('../../twilioconnection');
|
|
9
6
|
const DefaultBackoff = require('backoff');
|
|
10
7
|
const { reconnectBackoffConfig } = require('../../util/constants');
|
|
11
8
|
const Timeout = require('../../util/timeout');
|
|
9
|
+
const { SDK_NAME, SDK_VERSION } = require('../../util/constants');
|
|
12
10
|
|
|
13
11
|
const {
|
|
14
12
|
createBandwidthProfilePayload,
|
|
@@ -27,8 +25,6 @@ const {
|
|
|
27
25
|
|
|
28
26
|
const ICE_VERSION = 1;
|
|
29
27
|
const RSP_VERSION = 2;
|
|
30
|
-
const SDK_NAME = `${packageInfo.name}.js`;
|
|
31
|
-
const SDK_VERSION = packageInfo.version;
|
|
32
28
|
|
|
33
29
|
/*
|
|
34
30
|
TwilioConnectionTransport States
|
|
@@ -90,8 +86,6 @@ class TwilioConnectionTransport extends StateMachine {
|
|
|
90
86
|
constructor(name, accessToken, localParticipant, peerConnectionManager, wsServer, options) {
|
|
91
87
|
options = Object.assign({
|
|
92
88
|
Backoff: DefaultBackoff,
|
|
93
|
-
InsightsPublisher,
|
|
94
|
-
NullInsightsPublisher,
|
|
95
89
|
TwilioConnection,
|
|
96
90
|
iceServers: null,
|
|
97
91
|
sdpFormat: getSdpFormat(options.sdpSemantics),
|
|
@@ -102,19 +96,6 @@ class TwilioConnectionTransport extends StateMachine {
|
|
|
102
96
|
}, options);
|
|
103
97
|
super('connecting', states);
|
|
104
98
|
|
|
105
|
-
const eventPublisherOptions = {};
|
|
106
|
-
if (options.wsServerInsights) {
|
|
107
|
-
eventPublisherOptions.gateway = options.wsServerInsights;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const EventPublisher = options.insights ? options.InsightsPublisher : options.NullInsightsPublisher;
|
|
111
|
-
const eventPublisher = new EventPublisher(
|
|
112
|
-
accessToken,
|
|
113
|
-
SDK_NAME,
|
|
114
|
-
SDK_VERSION,
|
|
115
|
-
options.environment,
|
|
116
|
-
options.realm,
|
|
117
|
-
eventPublisherOptions);
|
|
118
99
|
|
|
119
100
|
Object.defineProperties(this, {
|
|
120
101
|
_accessToken: {
|
|
@@ -126,9 +107,6 @@ class TwilioConnectionTransport extends StateMachine {
|
|
|
126
107
|
_bandwidthProfile: {
|
|
127
108
|
value: options.bandwidthProfile
|
|
128
109
|
},
|
|
129
|
-
_disconnectEventPublisher: {
|
|
130
|
-
value: () => eventPublisher.disconnect()
|
|
131
|
-
},
|
|
132
110
|
_dominantSpeaker: {
|
|
133
111
|
value: options.dominantSpeaker
|
|
134
112
|
},
|
|
@@ -198,16 +176,9 @@ class TwilioConnectionTransport extends StateMachine {
|
|
|
198
176
|
}
|
|
199
177
|
});
|
|
200
178
|
|
|
201
|
-
// eslint-disable-next-line no-warning-comments
|
|
202
|
-
// TODO(mmalavalli): Create and set EventPublisher outside this class, so
|
|
203
|
-
// that the EventPublisher constructor is no longer a dependency.
|
|
204
|
-
this._eventObserver.setPublisher(eventPublisher);
|
|
205
179
|
|
|
206
180
|
setupTransport(this);
|
|
207
181
|
|
|
208
|
-
this.once('connected', ({ sid, participant }) => {
|
|
209
|
-
eventPublisher.connect(sid, participant.sid);
|
|
210
|
-
});
|
|
211
182
|
}
|
|
212
183
|
|
|
213
184
|
/**
|
|
@@ -315,7 +286,6 @@ class TwilioConnectionTransport extends StateMachine {
|
|
|
315
286
|
this.preempt('disconnected', null, [error]);
|
|
316
287
|
this._sendConnectOrSyncOrDisconnectMessage();
|
|
317
288
|
this._twilioConnection.close();
|
|
318
|
-
this._disconnectEventPublisher();
|
|
319
289
|
return true;
|
|
320
290
|
}
|
|
321
291
|
return false;
|
package/lib/util/constants.js
CHANGED
|
@@ -8,7 +8,8 @@ const VALID_GROUPS = [
|
|
|
8
8
|
'room',
|
|
9
9
|
'media',
|
|
10
10
|
'quality',
|
|
11
|
-
'video-processor'
|
|
11
|
+
'video-processor',
|
|
12
|
+
'preflight'
|
|
12
13
|
];
|
|
13
14
|
|
|
14
15
|
const VALID_LEVELS = [
|
|
@@ -27,40 +28,35 @@ const VALID_LEVELS = [
|
|
|
27
28
|
class EventObserver extends EventEmitter {
|
|
28
29
|
/**
|
|
29
30
|
* Constructor.
|
|
31
|
+
* @param {InsightsPublisher} publisher
|
|
30
32
|
* @param {number} connectTimestamp
|
|
31
33
|
* @param {Log} log
|
|
32
34
|
* @param {EventListener} [eventListener]
|
|
33
35
|
*/
|
|
34
|
-
constructor(connectTimestamp, log, eventListener = null) {
|
|
36
|
+
constructor(publisher, connectTimestamp, log, eventListener = null) {
|
|
35
37
|
super();
|
|
36
|
-
|
|
37
|
-
Object.defineProperties(this, {
|
|
38
|
-
_publisher: {
|
|
39
|
-
value: null,
|
|
40
|
-
writable: true
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
|
|
44
38
|
this.on('event', ({ name, group, level, payload }) => {
|
|
45
39
|
if (typeof name !== 'string') {
|
|
40
|
+
log.error('Unexpected name: ', name);
|
|
46
41
|
throw new Error('Unexpected name: ', name);
|
|
47
42
|
}
|
|
48
43
|
|
|
49
44
|
if (!VALID_GROUPS.includes(group)) {
|
|
45
|
+
log.error('Unexpected group: ', group);
|
|
50
46
|
throw new Error('Unexpected group: ', group);
|
|
51
47
|
}
|
|
52
48
|
|
|
53
49
|
if (!VALID_LEVELS.includes(level)) {
|
|
50
|
+
log.error('Unexpected level: ', level);
|
|
54
51
|
throw new Error('Unexpected level: ', level);
|
|
55
52
|
}
|
|
56
53
|
|
|
57
54
|
const timestamp = Date.now();
|
|
58
55
|
const elapsedTime = timestamp - connectTimestamp;
|
|
59
56
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
57
|
+
const publisherPayload = Object.assign({ elapsedTime, level }, payload ? payload : {});
|
|
58
|
+
publisher.publish(group, name, publisherPayload);
|
|
59
|
+
|
|
64
60
|
const event = Object.assign({
|
|
65
61
|
elapsedTime,
|
|
66
62
|
group,
|
|
@@ -82,14 +78,6 @@ class EventObserver extends EventEmitter {
|
|
|
82
78
|
}
|
|
83
79
|
});
|
|
84
80
|
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* sets the publisher object. Once set events will be sent to publisher.
|
|
88
|
-
* @param {InsightsPublisher} publisher
|
|
89
|
-
*/
|
|
90
|
-
setPublisher(publisher) {
|
|
91
|
-
this._publisher = publisher;
|
|
92
|
-
}
|
|
93
81
|
}
|
|
94
82
|
|
|
95
83
|
/**
|
package/lib/util/index.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const constants = require('./constants');
|
|
4
4
|
const { typeErrors: E, trackPriority } = constants;
|
|
5
5
|
const util = require('@twilio/webrtc/lib/util');
|
|
6
|
+
const { sessionSID } = require('./sid');
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Return the given {@link LocalTrack} or a new {@link LocalTrack} for the
|
|
@@ -572,6 +573,8 @@ function createRoomConnectEventPayload(connectOptions) {
|
|
|
572
573
|
return val ? 'true' : 'false';
|
|
573
574
|
}
|
|
574
575
|
const payload = {
|
|
576
|
+
sessionSID,
|
|
577
|
+
|
|
575
578
|
// arrays props converted to lengths.
|
|
576
579
|
iceServers: (connectOptions.iceServers || []).length,
|
|
577
580
|
audioTracks: (connectOptions.tracks || []).filter(track => track.kind === 'audio').length,
|
package/lib/util/sid.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const SID_CHARS = '1234567890abcdef';
|
|
2
|
+
const SID_CHAR_LENGTH = 32;
|
|
3
|
+
// copied from: https://code.hq.twilio.com/flex/monkey/blob/0fdce2b6c52d6be0b17a5cdb92f0c54f119b8ea8/src/client/lib/sid.ts#L39
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Generates a random sid using given prefix.
|
|
7
|
+
* @param {string} prefix
|
|
8
|
+
* @returns string
|
|
9
|
+
*/
|
|
10
|
+
function createSID(prefix) {
|
|
11
|
+
let result = '';
|
|
12
|
+
for (let i = 0; i < SID_CHAR_LENGTH; i++) {
|
|
13
|
+
result += SID_CHARS.charAt(Math.floor(Math.random() * SID_CHARS.length));
|
|
14
|
+
}
|
|
15
|
+
return `${prefix}${result}`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
exports.sessionSID = createSID('SS');
|
|
19
|
+
exports.createSID = createSID;
|
|
20
|
+
|
|
@@ -19,9 +19,6 @@ exports.createTwilioError = function createTwilioError(code, message) {
|
|
|
19
19
|
return TwilioErrorByCode[code] ? new TwilioErrorByCode[code]() : new TwilioError(code, message);
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
-
// Note(mpatwardhan): We derive twilio specific errors here. After typescript compiles to es5 `instanceof` does not work
|
|
23
|
-
// on objects that derive from Error/Array types. To workaround we call setPrototypeOf after calling super()
|
|
24
|
-
// more on this at: https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work
|
|
25
22
|
/**
|
|
26
23
|
* @class AccessTokenInvalidError
|
|
27
24
|
* @classdesc Raised whenever the AccessToken used for connecting to a Room is invalid.
|
|
@@ -239,6 +236,7 @@ class SignalingServerBusyError extends TwilioError {
|
|
|
239
236
|
Object.setPrototypeOf(this, SignalingServerBusyError.prototype);
|
|
240
237
|
}
|
|
241
238
|
}
|
|
239
|
+
|
|
242
240
|
exports.SignalingServerBusyError = SignalingServerBusyError;
|
|
243
241
|
Object.defineProperty(TwilioErrorByCode, 53006, { value: SignalingServerBusyError });
|
|
244
242
|
|
|
@@ -388,7 +386,7 @@ Object.defineProperty(TwilioErrorByCode, 53107, { value: RoomMaxParticipantsOutO
|
|
|
388
386
|
class RoomTypeInvalidError extends TwilioError {
|
|
389
387
|
constructor() {
|
|
390
388
|
super(53108, 'RoomType is not valid');
|
|
391
|
-
Object.setPrototypeOf(this,
|
|
389
|
+
Object.setPrototypeOf(this, RoomTypeInvalidError.prototype);
|
|
392
390
|
}
|
|
393
391
|
}
|
|
394
392
|
|
|
@@ -565,6 +563,40 @@ class RoomCompletedError extends TwilioError {
|
|
|
565
563
|
exports.RoomCompletedError = RoomCompletedError;
|
|
566
564
|
Object.defineProperty(TwilioErrorByCode, 53118, { value: RoomCompletedError });
|
|
567
565
|
|
|
566
|
+
/**
|
|
567
|
+
* @class RoomAudioOnlyFlagNotSupportedError
|
|
568
|
+
* @classdesc Raised whenever a participant tries to set the AudioOnly flag for a Room type other than Group Rooms.
|
|
569
|
+
* @extends TwilioError
|
|
570
|
+
* @property {number} code - 53124
|
|
571
|
+
* @property {string} message - 'The AudioOnly flag is not supported for the Room type'
|
|
572
|
+
*/
|
|
573
|
+
class RoomAudioOnlyFlagNotSupportedError extends TwilioError {
|
|
574
|
+
constructor() {
|
|
575
|
+
super(53124, 'The AudioOnly flag is not supported for the Room type');
|
|
576
|
+
Object.setPrototypeOf(this, RoomAudioOnlyFlagNotSupportedError.prototype);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
exports.RoomAudioOnlyFlagNotSupportedError = RoomAudioOnlyFlagNotSupportedError;
|
|
581
|
+
Object.defineProperty(TwilioErrorByCode, 53124, { value: RoomAudioOnlyFlagNotSupportedError });
|
|
582
|
+
|
|
583
|
+
/**
|
|
584
|
+
* @class RoomTrackKindNotSupportedError
|
|
585
|
+
* @classdesc Raised whenever a participant tries to publish a track or connects with a track that is not supported by the group room.
|
|
586
|
+
* @extends TwilioError
|
|
587
|
+
* @property {number} code - 53125
|
|
588
|
+
* @property {string} message - 'The track kind is not supported by the Room'
|
|
589
|
+
*/
|
|
590
|
+
class RoomTrackKindNotSupportedError extends TwilioError {
|
|
591
|
+
constructor() {
|
|
592
|
+
super(53125, 'The track kind is not supported by the Room');
|
|
593
|
+
Object.setPrototypeOf(this, RoomTrackKindNotSupportedError.prototype);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
exports.RoomTrackKindNotSupportedError = RoomTrackKindNotSupportedError;
|
|
598
|
+
Object.defineProperty(TwilioErrorByCode, 53125, { value: RoomTrackKindNotSupportedError });
|
|
599
|
+
|
|
568
600
|
/**
|
|
569
601
|
* @class ParticipantIdentityInvalidError
|
|
570
602
|
* @classdesc Raised whenever a Participant identity is invalid, and the scenario is not covered by a more specific error code.
|
|
@@ -618,7 +650,7 @@ Object.defineProperty(TwilioErrorByCode, 53202, { value: ParticipantIdentityChar
|
|
|
618
650
|
|
|
619
651
|
/**
|
|
620
652
|
* @class ParticipantMaxTracksExceededError
|
|
621
|
-
* @classdesc Raised
|
|
653
|
+
* @classdesc Raised whenever a Participant tries to publish a Track and the maximum number of published tracks allowed in the Room at the same time has been reached
|
|
622
654
|
* @extends TwilioError
|
|
623
655
|
* @property {number} code - 53203
|
|
624
656
|
* @property {string} message - 'The maximum number of published tracks allowed in the Room at the same time has been reached'
|
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.18.2",
|
|
6
6
|
"homepage": "https://twilio.com",
|
|
7
7
|
"author": "Mark Andrus Roberts <mroberts@twilio.com>",
|
|
8
8
|
"contributors": [
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
"vinyl-fs": "^2.4.4",
|
|
86
86
|
"vinyl-source-stream": "^1.1.0",
|
|
87
87
|
"watchify": "^3.11.1",
|
|
88
|
-
"webrtc-adapter": "^
|
|
88
|
+
"webrtc-adapter": "^7.7.1"
|
|
89
89
|
},
|
|
90
90
|
"engines": {
|
|
91
91
|
"node": ">=0.12"
|
|
@@ -97,7 +97,8 @@
|
|
|
97
97
|
"lint:js": "eslint ./lib ./test/*.js ./docker/**/*.js ./test/framework/*.js ./test/lib/*.js ./test/integration/** ./test/unit/** ",
|
|
98
98
|
"lint:ts": "eslint ./tsdef/*.ts ./lib/**/*.ts",
|
|
99
99
|
"lint": "npm-run-all lint:js lint:ts",
|
|
100
|
-
"
|
|
100
|
+
"printVersion": "node --version && npm --version",
|
|
101
|
+
"test:unit": "npm-run-all printVersion build:es5 test:unit:js test:unit:ts",
|
|
101
102
|
"test:unit:js": "nyc --report-dir=./coverage/js --extension=.js --include=lib/**/* --reporter=html --reporter=lcov --reporter=text mocha ./test/unit/index.js",
|
|
102
103
|
"test:unit:ts": "nyc --report-dir=./coverage/ts --extension=.ts --include=lib/**/* --reporter=html --reporter=lcov --reporter=text mocha -r ts-node/register ./test/unit/index.ts",
|
|
103
104
|
"test:serversiderender": "mocha ./test/serversiderender/index.js",
|
package/tsconfig.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"checkJs": false,
|
|
5
5
|
"declaration": false,
|
|
6
6
|
"target": "es5",
|
|
7
|
-
"lib": ["es5", "es6", "es2016", "
|
|
7
|
+
"lib": ["es5", "es6", "es2016", "es2019", "es2018.promise", "dom"],
|
|
8
8
|
"downlevelIteration": true,
|
|
9
9
|
"module": "commonjs",
|
|
10
10
|
"noImplicitAny": true,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export interface PreflightOptions {
|
|
2
2
|
duration?: number;
|
|
3
|
-
environment?: string;
|
|
4
3
|
region?: string;
|
|
5
4
|
}
|
|
6
5
|
|
|
@@ -26,7 +25,7 @@ export interface RTCIceCandidateStats {
|
|
|
26
25
|
candidateType?: string;
|
|
27
26
|
priority?: number;
|
|
28
27
|
url?: string;
|
|
29
|
-
relayProtocol?:
|
|
28
|
+
relayProtocol?: string;
|
|
30
29
|
}
|
|
31
30
|
|
|
32
31
|
export interface SelectedIceCandidatePairStats {
|