@techsee/techsee-media-service 0.1.3
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/README.md +1 -0
- package/lib/constants.js +20 -0
- package/lib/constants.js.map +1 -0
- package/lib/event-emitter.js +39 -0
- package/lib/event-emitter.js.map +1 -0
- package/lib/index.js +64 -0
- package/lib/index.js.map +1 -0
- package/lib/opentok/session.js +304 -0
- package/lib/opentok/session.js.map +1 -0
- package/lib/opentok/stream.js +310 -0
- package/lib/opentok/stream.js.map +1 -0
- package/lib/publisher.js +143 -0
- package/lib/publisher.js.map +1 -0
- package/lib/qos/raw-qos.js +319 -0
- package/lib/qos/raw-qos.js.map +1 -0
- package/lib/service.js +316 -0
- package/lib/service.js.map +1 -0
- package/lib/session.js +104 -0
- package/lib/session.js.map +1 -0
- package/lib/stream.js +195 -0
- package/lib/stream.js.map +1 -0
- package/lib/subscriber.js +90 -0
- package/lib/subscriber.js.map +1 -0
- package/lib/webrtc/constants.js +112 -0
- package/lib/webrtc/constants.js.map +1 -0
- package/lib/webrtc/helper.js +169 -0
- package/lib/webrtc/helper.js.map +1 -0
- package/lib/webrtc/session-kms.js +558 -0
- package/lib/webrtc/session-kms.js.map +1 -0
- package/lib/webrtc/session-loopback.js +340 -0
- package/lib/webrtc/session-loopback.js.map +1 -0
- package/lib/webrtc/session-turn.js +807 -0
- package/lib/webrtc/session-turn.js.map +1 -0
- package/lib/webrtc/session-turn.v2.js +2 -0
- package/lib/webrtc/session-turn.v2.js.map +1 -0
- package/lib/webrtc/session.js +40 -0
- package/lib/webrtc/session.js.map +1 -0
- package/lib/webrtc/stream.js +631 -0
- package/lib/webrtc/stream.js.map +1 -0
- package/lib/webrtc/temasys/adapter-loader.js +12 -0
- package/lib/webrtc/temasys/adapter-loader.js.map +1 -0
- package/lib/webrtc/temasys/adapter.js +5861 -0
- package/lib/webrtc/temasys/adapter.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
|
|
5
|
+
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
6
|
+
|
|
7
|
+
var RawQos = exports.RawQos = function () {
|
|
8
|
+
function RawQos() {
|
|
9
|
+
_classCallCheck(this, RawQos);
|
|
10
|
+
|
|
11
|
+
if (RawQos.instance) {
|
|
12
|
+
return RawQos.instance;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
this.VIDEO_CODECS = ['vp9', 'vp8', 'h264'];
|
|
16
|
+
this.rawQoSEntry = {};
|
|
17
|
+
this.enableRawEntries = true;
|
|
18
|
+
|
|
19
|
+
this.bytesPrev = null;
|
|
20
|
+
this.timestampPrev = null;
|
|
21
|
+
this.startTimestamp = null;
|
|
22
|
+
|
|
23
|
+
RawQos.instance = this;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
RawQos.prototype.parse = function parse(stats) {
|
|
27
|
+
var self = this;
|
|
28
|
+
|
|
29
|
+
self.rawQoSEntry = {};
|
|
30
|
+
self._clearRaw();
|
|
31
|
+
|
|
32
|
+
for (var _iterator = stats.values(), _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) {
|
|
33
|
+
var _ref;
|
|
34
|
+
|
|
35
|
+
if (_isArray) {
|
|
36
|
+
if (_i >= _iterator.length) break;
|
|
37
|
+
_ref = _iterator[_i++];
|
|
38
|
+
} else {
|
|
39
|
+
_i = _iterator.next();
|
|
40
|
+
if (_i.done) break;
|
|
41
|
+
_ref = _i.value;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
var stat = _ref;
|
|
45
|
+
|
|
46
|
+
if (!stat.isRemote) {
|
|
47
|
+
switch (stat.type) {
|
|
48
|
+
case 'outbound-rtp':
|
|
49
|
+
{
|
|
50
|
+
self._addRaw(stat);
|
|
51
|
+
self._parseOutStats(stat, self.rawQoSEntry);
|
|
52
|
+
|
|
53
|
+
var remote = stats.get(stat.remoteId);
|
|
54
|
+
|
|
55
|
+
if (remote) {
|
|
56
|
+
self._addRaw(remote);
|
|
57
|
+
self.rawQoSEntry.remote = {};
|
|
58
|
+
self._parseInStats(remote, self.rawQoSEntry.remote);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
this._parseRelated(stats, stat, self);
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
case 'inbound-rtp':
|
|
65
|
+
{
|
|
66
|
+
self._addRaw(stat);
|
|
67
|
+
self._parseInStats(stat, self.rawQoSEntry);
|
|
68
|
+
|
|
69
|
+
var _remote = stats.get(stat.remoteId);
|
|
70
|
+
|
|
71
|
+
if (_remote) {
|
|
72
|
+
self._addRaw(_remote);
|
|
73
|
+
self.rawQoSEntry.remote = {};
|
|
74
|
+
self._parseOutStats(_remote, self.rawQoSEntry.remote);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
this._parseRelated(stats, stat, self);
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
case 'remote-inbound-rtp':
|
|
81
|
+
{
|
|
82
|
+
self._addRaw(stat);
|
|
83
|
+
self.rawQoSEntry.remote = {};
|
|
84
|
+
self._parseInStats(stat, self.rawQoSEntry.remote);
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
case 'remote-outbound-rtp':
|
|
88
|
+
{
|
|
89
|
+
self._addRaw(stat);
|
|
90
|
+
self.rawQoSEntry.remote = {};
|
|
91
|
+
self._parseOutStats(stat, self.rawQoSEntry.remote);
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
case 'candidate-pair':
|
|
95
|
+
{
|
|
96
|
+
if ((stat.bytesSent > 0 || stat.bytesReceived > 0) && (!self.rawQoSEntry.servers || stat.bytesSent > self.rawQoSEntry.servers.bytesSent || stat.bytesReceived > self.rawQoSEntry.servers.bytesReceived)) {
|
|
97
|
+
self.rawQoSEntry.servers = {};
|
|
98
|
+
self._addRaw(stat);
|
|
99
|
+
self._parseServerStats(stat, self.rawQoSEntry.servers, stats);
|
|
100
|
+
}
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
case 'track':
|
|
104
|
+
{
|
|
105
|
+
self.track = stat;
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (!self.rawQoSEntry.frameWidth && self.track) {
|
|
113
|
+
self._addRaw(self.track);
|
|
114
|
+
self._parseTrack(self.track, self.rawQoSEntry);
|
|
115
|
+
}
|
|
116
|
+
self.track = null;
|
|
117
|
+
|
|
118
|
+
return self.rawQoSEntry;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
RawQos.prototype._parseRelated = function _parseRelated(stats, stat, self) {
|
|
122
|
+
var track = stats.get(stat.trackId);
|
|
123
|
+
|
|
124
|
+
if (track) {
|
|
125
|
+
self._addRaw(track);
|
|
126
|
+
self._parseTrack(track, self.rawQoSEntry);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
var codec = stats.get(stat.codecId);
|
|
130
|
+
|
|
131
|
+
if (codec) {
|
|
132
|
+
self._addRaw(codec);
|
|
133
|
+
self._parseCodec(codec, self.rawQoSEntry);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
RawQos.prototype._clearRaw = function _clearRaw() {
|
|
138
|
+
if (this.enableRawEntries) {
|
|
139
|
+
this.rawQoSEntry.raw = [];
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
RawQos.prototype._addRaw = function _addRaw(item) {
|
|
144
|
+
if (this.enableRawEntries && item) {
|
|
145
|
+
if (!this.rawQoSEntry.raw) {
|
|
146
|
+
this.rawQoSEntry.raw = [];
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
this.rawQoSEntry.raw.push(this._dumpItem(item));
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
RawQos.prototype._parseServerStats = function _parseServerStats(result, parent, stats) {
|
|
154
|
+
parent.bytesSent = result.bytesSent;
|
|
155
|
+
parent.bytesReceived = result.bytesReceived;
|
|
156
|
+
if (typeof result.totalRoundTripTime === 'number') {
|
|
157
|
+
parent.totalRoundTripTime = result.totalRoundTripTime;
|
|
158
|
+
}
|
|
159
|
+
if (typeof result.currentRoundTripTime === 'number') {
|
|
160
|
+
parent.currentRoundTripTime = result.currentRoundTripTime;
|
|
161
|
+
}
|
|
162
|
+
if (typeof result.availableOutgoingBitrate === 'number') {
|
|
163
|
+
parent.availableOutgoingBitrate = result.availableOutgoingBitrate;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
var localCandidate = stats.get(result.localCandidateId);
|
|
167
|
+
|
|
168
|
+
if (localCandidate) {
|
|
169
|
+
this._addRaw(localCandidate);
|
|
170
|
+
this._parseLocal(localCandidate, parent);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
var remoteCandidate = stats.get(result.remoteCandidateId);
|
|
174
|
+
|
|
175
|
+
if (remoteCandidate) {
|
|
176
|
+
this._addRaw(remoteCandidate);
|
|
177
|
+
this._parseRemote(remoteCandidate, parent);
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
RawQos.prototype._parseCodec = function _parseCodec(result, parent) {
|
|
182
|
+
if (result.mimeType) {
|
|
183
|
+
var index = this.VIDEO_CODECS.findIndex(function (codec) {
|
|
184
|
+
return result.mimeType.toLowerCase().includes(codec);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
if (index >= 0) {
|
|
188
|
+
parent.videoCodec = this.VIDEO_CODECS[index];
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
RawQos.prototype._parseLocal = function _parseLocal(result, parent) {
|
|
194
|
+
parent.localIP = result.ip || result.ipAddress;
|
|
195
|
+
parent.localPort = result.port || result.portNumber;
|
|
196
|
+
parent.localProtocol = result.protocol || result.transport;
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
RawQos.prototype._parseRemote = function _parseRemote(result, parent) {
|
|
200
|
+
parent.remoteIP = result.ip || result.ipAddress;
|
|
201
|
+
parent.remotePort = result.port || result.portNumber;
|
|
202
|
+
parent.remoteProtocol = result.protocol || result.transport;
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
RawQos.prototype._parseTrack = function _parseTrack(result, parent) {
|
|
206
|
+
if (typeof result.frameWidth === 'number') {
|
|
207
|
+
parent.frameWidth = result.frameWidth;
|
|
208
|
+
}
|
|
209
|
+
if (typeof result.frameHeight === 'number') {
|
|
210
|
+
parent.frameHeight = result.frameHeight;
|
|
211
|
+
}
|
|
212
|
+
if (typeof result.framesPerSecond === 'number') {
|
|
213
|
+
parent.videoFrameRate = result.framesPerSecond;
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
RawQos.prototype._parseOutStats = function _parseOutStats(result, parent) {
|
|
218
|
+
parent.isPublisher = true;
|
|
219
|
+
parent.videoSentPackets = result.packetsSent;
|
|
220
|
+
parent.videoSentPacketsLost = result.packetsLost;
|
|
221
|
+
parent.videoSentBytes = result.bytesSent;
|
|
222
|
+
this._parseBitrate(result, parent, parent.videoSentBytes);
|
|
223
|
+
this._parseFrameRate(result, parent, parent.videoSentBytes);
|
|
224
|
+
this._parseOther(result, parent);
|
|
225
|
+
this._saveSomeMetrics(parent, result);
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
RawQos.prototype._parseVideoDuration = function _parseVideoDuration(result, parent) {
|
|
229
|
+
if (!this.startTimestamp) {
|
|
230
|
+
this.startTimestamp = result.timestamp;
|
|
231
|
+
}
|
|
232
|
+
parent.videoDuration = ((result.timestamp - this.startTimestamp) / 1000).toFixed(2);
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
RawQos.prototype._parseInStats = function _parseInStats(result, parent) {
|
|
236
|
+
parent.isSubscriber = true;
|
|
237
|
+
parent.videoReceivedPackets = result.packetsReceived;
|
|
238
|
+
parent.videoReceivedPacketsLost = result.packetsLost;
|
|
239
|
+
parent.videoReceivedBytes = result.bytesReceived;
|
|
240
|
+
this._parseBitrate(result, parent, parent.videoReceivedBytes);
|
|
241
|
+
this._parseFrameRate(result, parent, parent.videoReceivedBytes);
|
|
242
|
+
this._parseOther(result, parent);
|
|
243
|
+
this._saveSomeMetrics(parent, result);
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
RawQos.prototype._saveSomeMetrics = function _saveSomeMetrics(parent, result) {
|
|
247
|
+
if (parent === this.rawQoSEntry) {
|
|
248
|
+
this.bytesPrev = parent.videoReceivedBytes;
|
|
249
|
+
this.timestampPrev = result.timestamp;
|
|
250
|
+
this.ssrcPrev = result.ssrc;
|
|
251
|
+
this.framesDecodedPrev = result.framesDecoded;
|
|
252
|
+
this._parseVideoDuration(result, parent);
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
RawQos.prototype._parseOther = function _parseOther(result, parent) {
|
|
257
|
+
parent.timestamp = result.timestamp;
|
|
258
|
+
parent.ssrc = result.ssrc;
|
|
259
|
+
if (typeof result.discardedPackets === 'number') {
|
|
260
|
+
parent.discardedPackets = result.discardedPackets;
|
|
261
|
+
}
|
|
262
|
+
if (typeof result.jitter === 'number') {
|
|
263
|
+
parent.jitter = result.jitter;
|
|
264
|
+
}
|
|
265
|
+
if (typeof result.packetsRepaired === 'number') {
|
|
266
|
+
parent.packetsRepaired = result.packetsRepaired;
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
RawQos.prototype._parseBitrate = function _parseBitrate(result, parent, bytes) {
|
|
271
|
+
if (bytes > 0) {
|
|
272
|
+
if (typeof result.bitrateMean === 'number') {
|
|
273
|
+
parent.videoBitRate = result.bitrateMean.toFixed(2);
|
|
274
|
+
} else if (this.bytesPrev && this.timestampPrev) {
|
|
275
|
+
var totalBytes = bytes;
|
|
276
|
+
|
|
277
|
+
if (result.ssrc === this.ssrcPrev && bytes > this.bytesPrev) {
|
|
278
|
+
totalBytes = bytes - this.bytesPrev;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
parent.videoBitRate = Math.floor(8 * totalBytes / ((result.timestamp - this.timestampPrev) / 1000));
|
|
282
|
+
}
|
|
283
|
+
} else {
|
|
284
|
+
parent.videoBitRate = 0;
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
RawQos.prototype._parseFrameRate = function _parseFrameRate(result, parent, bytes) {
|
|
289
|
+
if (bytes > 0) {
|
|
290
|
+
if (typeof result.framerateMean === 'number') {
|
|
291
|
+
parent.videoFrameRate = Number(result.framerateMean).toFixed(2);
|
|
292
|
+
} else if (this.framesDecodedPrev && this.timestampPrev) {
|
|
293
|
+
if (result.framesDecoded >= this.framesDecodedPrev && result.timestamp > this.timestampPrev) {
|
|
294
|
+
parent.videoFrameRate = ((result.framesDecoded - this.framesDecodedPrev) / ((result.timestamp - this.timestampPrev) / 1000)).toFixed(2);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
} else {
|
|
298
|
+
parent.videoFrameRate = 0;
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
RawQos.prototype._dumpItem = function _dumpItem(res) {
|
|
303
|
+
var statsString = '{';
|
|
304
|
+
var index = 0;
|
|
305
|
+
|
|
306
|
+
Object.keys(res).forEach(function (k) {
|
|
307
|
+
statsString += '"' + k + '": "' + res[k] + '"';
|
|
308
|
+
if (++index !== res.length) {
|
|
309
|
+
statsString += ',';
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
statsString += '}';
|
|
313
|
+
|
|
314
|
+
return statsString;
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
return RawQos;
|
|
318
|
+
}();
|
|
319
|
+
//# sourceMappingURL=raw-qos.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["qos/raw-qos.js"],"names":["RawQos","instance","VIDEO_CODECS","rawQoSEntry","enableRawEntries","bytesPrev","timestampPrev","startTimestamp","parse","stats","self","_clearRaw","values","stat","isRemote","type","_addRaw","_parseOutStats","remote","get","remoteId","_parseInStats","_parseRelated","bytesSent","bytesReceived","servers","_parseServerStats","track","frameWidth","_parseTrack","trackId","codec","codecId","_parseCodec","raw","item","push","_dumpItem","result","parent","totalRoundTripTime","currentRoundTripTime","availableOutgoingBitrate","localCandidate","localCandidateId","_parseLocal","remoteCandidate","remoteCandidateId","_parseRemote","mimeType","index","findIndex","toLowerCase","includes","videoCodec","localIP","ip","ipAddress","localPort","port","portNumber","localProtocol","protocol","transport","remoteIP","remotePort","remoteProtocol","frameHeight","framesPerSecond","videoFrameRate","isPublisher","videoSentPackets","packetsSent","videoSentPacketsLost","packetsLost","videoSentBytes","_parseBitrate","_parseFrameRate","_parseOther","_saveSomeMetrics","_parseVideoDuration","timestamp","videoDuration","toFixed","isSubscriber","videoReceivedPackets","packetsReceived","videoReceivedPacketsLost","videoReceivedBytes","ssrcPrev","ssrc","framesDecodedPrev","framesDecoded","discardedPackets","jitter","packetsRepaired","bytes","bitrateMean","videoBitRate","totalBytes","Math","floor","framerateMean","Number","res","statsString","Object","keys","forEach","k","length"],"mappings":"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","file":"raw-qos.js","sourcesContent":["'use strict';\n\nexport class RawQos {\n constructor() {\n if (RawQos.instance) {\n return RawQos.instance;\n }\n\n this.VIDEO_CODECS = ['vp9', 'vp8', 'h264'];\n this.rawQoSEntry = {};\n this.enableRawEntries = true;\n\n this.bytesPrev = null;\n this.timestampPrev = null;\n this.startTimestamp = null;\n\n RawQos.instance = this;\n }\n\n parse(stats) {\n const self = this;\n\n self.rawQoSEntry = {};\n self._clearRaw();\n\n for (const stat of stats.values()) {\n if (!stat.isRemote) {\n switch (stat.type) {\n case 'outbound-rtp': {\n self._addRaw(stat);\n self._parseOutStats(stat, self.rawQoSEntry);\n\n const remote = stats.get(stat.remoteId);\n\n if (remote) {\n self._addRaw(remote);\n self.rawQoSEntry.remote = {};\n self._parseInStats(remote, self.rawQoSEntry.remote);\n }\n\n this._parseRelated(stats, stat, self);\n break;\n }\n case 'inbound-rtp': {\n self._addRaw(stat);\n self._parseInStats(stat, self.rawQoSEntry);\n\n const remote = stats.get(stat.remoteId);\n\n if (remote) {\n self._addRaw(remote);\n self.rawQoSEntry.remote = {};\n self._parseOutStats(remote, self.rawQoSEntry.remote);\n }\n\n this._parseRelated(stats, stat, self);\n break;\n }\n case 'remote-inbound-rtp': {\n self._addRaw(stat);\n self.rawQoSEntry.remote = {};\n self._parseInStats(stat, self.rawQoSEntry.remote);\n break;\n }\n case 'remote-outbound-rtp': {\n self._addRaw(stat);\n self.rawQoSEntry.remote = {};\n self._parseOutStats(stat, self.rawQoSEntry.remote);\n break;\n }\n case 'candidate-pair': {\n if ((stat.bytesSent > 0 || stat.bytesReceived > 0) &&\n (!self.rawQoSEntry.servers || stat.bytesSent > self.rawQoSEntry.servers.bytesSent ||\n stat.bytesReceived > self.rawQoSEntry.servers.bytesReceived)) {\n self.rawQoSEntry.servers = {};\n self._addRaw(stat);\n self._parseServerStats(stat, self.rawQoSEntry.servers, stats);\n }\n break;\n }\n case 'track': {\n self.track = stat;\n break;\n }\n }\n }\n }\n\n if (!self.rawQoSEntry.frameWidth && self.track) {\n self._addRaw(self.track);\n self._parseTrack(self.track, self.rawQoSEntry);\n }\n self.track = null;\n\n return self.rawQoSEntry;\n }\n\n _parseRelated(stats, stat, self) {\n const track = stats.get(stat.trackId);\n\n if (track) {\n self._addRaw(track);\n self._parseTrack(track, self.rawQoSEntry);\n }\n\n const codec = stats.get(stat.codecId);\n\n if (codec) {\n self._addRaw(codec);\n self._parseCodec(codec, self.rawQoSEntry);\n }\n }\n\n _clearRaw() {\n if (this.enableRawEntries) {\n this.rawQoSEntry.raw = [];\n }\n }\n\n _addRaw(item) {\n if (this.enableRawEntries && item) {\n if (!this.rawQoSEntry.raw) {\n this.rawQoSEntry.raw = [];\n }\n\n this.rawQoSEntry.raw.push(this._dumpItem(item));\n }\n }\n\n _parseServerStats(result, parent, stats) {\n parent.bytesSent = result.bytesSent;\n parent.bytesReceived = result.bytesReceived;\n if (typeof result.totalRoundTripTime === 'number') {\n parent.totalRoundTripTime = result.totalRoundTripTime;\n }\n if (typeof result.currentRoundTripTime === 'number') {\n parent.currentRoundTripTime = result.currentRoundTripTime;\n }\n if (typeof result.availableOutgoingBitrate === 'number') {\n parent.availableOutgoingBitrate = result.availableOutgoingBitrate;\n }\n\n const localCandidate = stats.get(result.localCandidateId);\n\n if (localCandidate) {\n this._addRaw(localCandidate);\n this._parseLocal(localCandidate, parent);\n }\n\n const remoteCandidate = stats.get(result.remoteCandidateId);\n\n if (remoteCandidate) {\n this._addRaw(remoteCandidate);\n this._parseRemote(remoteCandidate, parent);\n }\n }\n\n _parseCodec(result, parent) {\n if (result.mimeType) {\n const index = this.VIDEO_CODECS.findIndex((codec) => result.mimeType.toLowerCase().includes(codec));\n\n if (index >= 0) {\n parent.videoCodec = this.VIDEO_CODECS[index];\n }\n }\n }\n\n _parseLocal(result, parent) {\n parent.localIP = result.ip || result.ipAddress;\n parent.localPort = result.port || result.portNumber;\n parent.localProtocol = result.protocol || result.transport;\n }\n\n _parseRemote(result, parent) {\n parent.remoteIP = result.ip || result.ipAddress;\n parent.remotePort = result.port || result.portNumber;\n parent.remoteProtocol = result.protocol || result.transport;\n }\n\n _parseTrack(result, parent) {\n if (typeof result.frameWidth === 'number') {\n parent.frameWidth = result.frameWidth;\n }\n if (typeof result.frameHeight === 'number') {\n parent.frameHeight = result.frameHeight;\n }\n if (typeof result.framesPerSecond === 'number') {\n parent.videoFrameRate = result.framesPerSecond;\n }\n }\n\n _parseOutStats(result, parent) {\n parent.isPublisher = true;\n parent.videoSentPackets = result.packetsSent;\n parent.videoSentPacketsLost = result.packetsLost;\n parent.videoSentBytes = result.bytesSent;\n this._parseBitrate(result, parent, parent.videoSentBytes);\n this._parseFrameRate(result, parent, parent.videoSentBytes);\n this._parseOther(result, parent);\n this._saveSomeMetrics(parent, result);\n }\n\n _parseVideoDuration(result, parent) {\n if (!this.startTimestamp) {\n this.startTimestamp = result.timestamp;\n }\n parent.videoDuration = ((result.timestamp - this.startTimestamp) / 1000).toFixed(2);\n }\n\n _parseInStats(result, parent) {\n parent.isSubscriber = true;\n parent.videoReceivedPackets = result.packetsReceived;\n parent.videoReceivedPacketsLost = result.packetsLost;\n parent.videoReceivedBytes = result.bytesReceived;\n this._parseBitrate(result, parent, parent.videoReceivedBytes);\n this._parseFrameRate(result, parent, parent.videoReceivedBytes);\n this._parseOther(result, parent);\n this._saveSomeMetrics(parent, result);\n }\n\n _saveSomeMetrics(parent, result) {\n if (parent === this.rawQoSEntry) {\n this.bytesPrev = parent.videoReceivedBytes;\n this.timestampPrev = result.timestamp;\n this.ssrcPrev = result.ssrc;\n this.framesDecodedPrev = result.framesDecoded;\n this._parseVideoDuration(result, parent);\n }\n }\n\n _parseOther (result, parent) {\n parent.timestamp = result.timestamp;\n parent.ssrc = result.ssrc;\n if (typeof result.discardedPackets === 'number') {\n parent.discardedPackets = result.discardedPackets;\n }\n if (typeof result.jitter === 'number') {\n parent.jitter = result.jitter;\n }\n if (typeof result.packetsRepaired === 'number') {\n parent.packetsRepaired = result.packetsRepaired;\n }\n }\n\n _parseBitrate (result, parent, bytes) {\n if (bytes > 0) {\n if (typeof result.bitrateMean === 'number') {\n parent.videoBitRate = (result.bitrateMean).toFixed(2);\n\n } else if (this.bytesPrev && this.timestampPrev) {\n let totalBytes = bytes;\n\n if((result.ssrc === this.ssrcPrev) && (bytes > this.bytesPrev)) {\n totalBytes = bytes - this.bytesPrev;\n }\n\n parent.videoBitRate = Math.floor((8 * totalBytes) / ((result.timestamp - this.timestampPrev) / 1000));\n }\n } else {\n parent.videoBitRate = 0;\n }\n }\n\n _parseFrameRate (result, parent, bytes) {\n if (bytes > 0) {\n if (typeof result.framerateMean === 'number') {\n parent.videoFrameRate = Number(result.framerateMean).toFixed(2);\n } else if (this.framesDecodedPrev && this.timestampPrev) {\n if (result.framesDecoded >= this.framesDecodedPrev && result.timestamp > this.timestampPrev) {\n parent.videoFrameRate = ((result.framesDecoded - this.framesDecodedPrev) / ((result.timestamp - this.timestampPrev) / 1000)).toFixed(2);\n }\n }\n } else {\n parent.videoFrameRate = 0;\n }\n }\n\n _dumpItem (res) {\n let statsString = '{';\n let index = 0;\n\n Object.keys(res).forEach((k) => {\n statsString += `\"${k}\": \"${res[k]}\"`;\n if (++index !== res.length) {\n statsString += ',';\n }\n });\n statsString += '}';\n\n return statsString;\n }\n}\n"]}
|
package/lib/service.js
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports.TsMediaService = exports.EVENTS = undefined;
|
|
5
|
+
|
|
6
|
+
var _eventEmitter = require('./event-emitter');
|
|
7
|
+
|
|
8
|
+
var _session = require('./webrtc/session');
|
|
9
|
+
|
|
10
|
+
var _tsEnvironmentDetect = require('techsee-common/lib/helpers/ts-environment-detect');
|
|
11
|
+
|
|
12
|
+
var _session2 = require('./opentok/session');
|
|
13
|
+
|
|
14
|
+
var _helper = require('./webrtc/helper');
|
|
15
|
+
|
|
16
|
+
var _constants = require('./constants');
|
|
17
|
+
|
|
18
|
+
var environmentDetect = new _tsEnvironmentDetect.TsEnvironmentDetect();
|
|
19
|
+
|
|
20
|
+
var waitForTemasysPlugin = false;
|
|
21
|
+
|
|
22
|
+
if (environmentDetect.isIE11()) {
|
|
23
|
+
waitForTemasysPlugin = true;
|
|
24
|
+
|
|
25
|
+
var _AdapterJS = require('./webrtc/temasys/adapter-loader')(); // eslint-disable-line global-require
|
|
26
|
+
|
|
27
|
+
_AdapterJS.webRTCReady(function () {
|
|
28
|
+
waitForTemasysPlugin = false;
|
|
29
|
+
});
|
|
30
|
+
} else if (!(environmentDetect.isChrome() && environmentDetect.majorVersion() < 49)) {
|
|
31
|
+
require('webrtc-adapter/src/js/adapter_core'); // eslint-disable-line global-require
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function _isOTDefined() {
|
|
35
|
+
try {
|
|
36
|
+
return !!OT;
|
|
37
|
+
} catch (e) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function _waitForOT() {
|
|
43
|
+
if (_isOTDefined()) {
|
|
44
|
+
return Promise.resolve();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
var isDefined = false;
|
|
48
|
+
|
|
49
|
+
return Promise.reduce(new Array(_constants.WAIT_FOR_OPENTOK_INITIALIZATION_MAX_ATTEMPTS), function () {
|
|
50
|
+
if (isDefined || _isOTDefined()) {
|
|
51
|
+
isDefined = true;
|
|
52
|
+
|
|
53
|
+
return Promise.resolve();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return Promise.delay(_constants.WAIT_FOR_OPENTOK_INITIALIZATION_INTERVAL);
|
|
57
|
+
}, 0).then(function () {
|
|
58
|
+
return isDefined || Promise.reject('OT is undefined');
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @enum SERVICE_EVENTS
|
|
64
|
+
*/
|
|
65
|
+
var SERVICE_EVENTS = {
|
|
66
|
+
SESSION_CREATED: 'SESSION_CREATED',
|
|
67
|
+
EXCEPTION: 'EXCEPTION'
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
exports.EVENTS = SERVICE_EVENTS;
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
var sessions = [];
|
|
74
|
+
var latestLocalStream = null;
|
|
75
|
+
var userMediaPromise = null;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* The top of hierarchy and the entry point of the TsMedia Service.
|
|
79
|
+
*
|
|
80
|
+
* @static
|
|
81
|
+
* @class
|
|
82
|
+
* @extends EventEmitter
|
|
83
|
+
*/
|
|
84
|
+
var TsMediaService = exports.TsMediaService = _.assign(new _eventEmitter.EventEmitter(), {
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* All created sessoins
|
|
88
|
+
*
|
|
89
|
+
* @member { Object }
|
|
90
|
+
* @memberof TsMediaService
|
|
91
|
+
* @type { Array<TsMediaSession> }
|
|
92
|
+
*/
|
|
93
|
+
get sessions() {
|
|
94
|
+
return sessions;
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
createLocalMediaStream: function createLocalMediaStream(constraints) {
|
|
98
|
+
if (userMediaPromise) {
|
|
99
|
+
return userMediaPromise;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (latestLocalStream) {
|
|
103
|
+
var videoTrack = latestLocalStream.getVideoTracks();
|
|
104
|
+
if (videoTrack.length > 0 && videoTrack[0].readyState === 'live') {
|
|
105
|
+
return Promise.resolve(latestLocalStream);
|
|
106
|
+
} else {
|
|
107
|
+
this.destroyLocalMediaStream();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
userMediaPromise = new Promise(function (resolve, reject) {
|
|
112
|
+
try {
|
|
113
|
+
navigator.mediaDevices.getUserMedia(constraints).then(function (stream) {
|
|
114
|
+
latestLocalStream = stream;
|
|
115
|
+
userMediaPromise = null;
|
|
116
|
+
resolve(stream);
|
|
117
|
+
}).catch(function (err) {
|
|
118
|
+
userMediaPromise = null;
|
|
119
|
+
reject(err);
|
|
120
|
+
});
|
|
121
|
+
} catch (e) {
|
|
122
|
+
userMediaPromise = null;
|
|
123
|
+
reject(e);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
return userMediaPromise;
|
|
128
|
+
},
|
|
129
|
+
destroyLocalMediaStream: function destroyLocalMediaStream() {
|
|
130
|
+
if (latestLocalStream) {
|
|
131
|
+
latestLocalStream.getTracks().forEach(function (track) {
|
|
132
|
+
track.stop();
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
latestLocalStream = null;
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Enumerate available media devices
|
|
142
|
+
*
|
|
143
|
+
* @method
|
|
144
|
+
* @memberof TsMediaService
|
|
145
|
+
* @returns { Promise<Array<MediaDeviceInfo>> } devices list
|
|
146
|
+
*
|
|
147
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/MediaDeviceInfo | MediaDeviceInfo documentation}
|
|
148
|
+
*/
|
|
149
|
+
getDevices: function getDevices() {
|
|
150
|
+
if (typeof OT !== 'undefined' && OT && OT.getDevices) {
|
|
151
|
+
return new Promise(function (resolve, reject) {
|
|
152
|
+
OT.getDevices(function (error, devices) {
|
|
153
|
+
if (error) {
|
|
154
|
+
return reject(error);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return resolve(devices);
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (navigator.mediaDevices && navigator.mediaDevices.enumerateDevices) {
|
|
163
|
+
return navigator.mediaDevices.enumerateDevices();
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return Promise.reject('getDevices is not supported');
|
|
167
|
+
},
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Enumerate available media devices
|
|
172
|
+
*
|
|
173
|
+
* @method
|
|
174
|
+
* @memberof TsMediaService
|
|
175
|
+
* @returns { Promise<Array<MediaDeviceInfo>> } devices list
|
|
176
|
+
*
|
|
177
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/MediaDeviceInfo | MediaDeviceInfo documentation}
|
|
178
|
+
*/
|
|
179
|
+
isTemasysPluginAvailable: function isTemasysPluginAvailable() {
|
|
180
|
+
return new Promise(function (resolve) {
|
|
181
|
+
if (!AdapterJS) {
|
|
182
|
+
return resolve(false);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
var verifyPluginState = function verifyPluginState() {
|
|
186
|
+
if (waitForTemasysPlugin && !AdapterJS.pluginNotInstalled) {
|
|
187
|
+
return setTimeout(verifyPluginState, _constants.TEMASYS_PLUGIN_CHECK_INTERVAL);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
resolve(!AdapterJS.pluginNotInstalled);
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
setTimeout(verifyPluginState, _constants.TEMASYS_PLUGIN_CHECK_INTERVAL);
|
|
194
|
+
});
|
|
195
|
+
},
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Verifies camera access
|
|
200
|
+
*
|
|
201
|
+
* @method
|
|
202
|
+
* @memberof TsMediaService
|
|
203
|
+
* @returns { Promise<Object> } returns {stream,constraints} if successful, or rejected promise if failed
|
|
204
|
+
*
|
|
205
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/MediaDeviceInfo | MediaDeviceInfo documentation}
|
|
206
|
+
*/
|
|
207
|
+
verifyCameraAccess: function verifyCameraAccess(deviceOpts) {
|
|
208
|
+
return (0, _helper.getHighestResolutionStream)(deviceOpts);
|
|
209
|
+
},
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Init WebRTC or OpenTok session depends on required type.
|
|
214
|
+
*
|
|
215
|
+
* Returns an initialized specific implementation of TsMediaSession interface.
|
|
216
|
+
*
|
|
217
|
+
* Assuming mobile will be a publisher and not mobile will be a subscriber.
|
|
218
|
+
*
|
|
219
|
+
* @method
|
|
220
|
+
* @memberof TsMediaService
|
|
221
|
+
*
|
|
222
|
+
* @param { OPENTOK|MEDIASERVER|TURNSERVER } mediaServiceType required implementation
|
|
223
|
+
* @param { Boolean } isMobile Whether techsee-mobile or not calls this method.
|
|
224
|
+
* @param { Object } resolution constraint to use for video stream
|
|
225
|
+
* @param { opentok|tsMediaServer|turnServer } credentials server/service credentials
|
|
226
|
+
* @param { Object } deviceOpts requested devices (mainly audio/video device ids)
|
|
227
|
+
* @param { Boolean } isLoopback Whether to use loopback webrtc
|
|
228
|
+
*
|
|
229
|
+
* @returns { Promise<TsMediaSession> }
|
|
230
|
+
*/
|
|
231
|
+
initSession: function initSession() {
|
|
232
|
+
var _this = this;
|
|
233
|
+
|
|
234
|
+
var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
|
|
235
|
+
isMobile: false,
|
|
236
|
+
resolution: '640x480'
|
|
237
|
+
},
|
|
238
|
+
mediaServiceType = _ref.mediaServiceType,
|
|
239
|
+
isMobile = _ref.isMobile,
|
|
240
|
+
resolution = _ref.resolution,
|
|
241
|
+
credentials = _ref.credentials,
|
|
242
|
+
deviceOpts = _ref.deviceOpts,
|
|
243
|
+
isLoopback = _ref.isLoopback;
|
|
244
|
+
|
|
245
|
+
return Promise.resolve().then(function () {
|
|
246
|
+
if (mediaServiceType === _constants.MEDIA_SERVICE_TYPES.MEDIASERVER) {
|
|
247
|
+
//
|
|
248
|
+
// KMS CONNECTION
|
|
249
|
+
//
|
|
250
|
+
return Promise.resolve().then(function () {
|
|
251
|
+
var sessionOptions = {
|
|
252
|
+
isMobile: isMobile,
|
|
253
|
+
resolution: resolution,
|
|
254
|
+
|
|
255
|
+
credentials: credentials.tsMediaServer,
|
|
256
|
+
deviceOpts: deviceOpts || { audio: true, video: true }
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
return new _session.KMSWebRTCSession(sessionOptions);
|
|
260
|
+
});
|
|
261
|
+
} else if (mediaServiceType === _constants.MEDIA_SERVICE_TYPES.TURNSERVER || isLoopback) {
|
|
262
|
+
//
|
|
263
|
+
// TURN-based connection or loopback (no connection)
|
|
264
|
+
//
|
|
265
|
+
return Promise.resolve().then(function () {
|
|
266
|
+
if (waitForTemasysPlugin) {
|
|
267
|
+
return Promise.delay(_constants.WAIT_FOR_TEMASYS_PLUGIN_INITIALIZATION);
|
|
268
|
+
}
|
|
269
|
+
}).then(function () {
|
|
270
|
+
if (waitForTemasysPlugin) {
|
|
271
|
+
return Promise.reject('Temasys plugin has not yet been initialized, despite waiting a grace period');
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
var creds = null;
|
|
275
|
+
|
|
276
|
+
if (!isLoopback) {
|
|
277
|
+
creds = mediaServiceType === _constants.MEDIA_SERVICE_TYPES.TURNSERVER ? credentials.turnServer : credentials.opentok;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
var sessionOptions = {
|
|
281
|
+
isMobile: isMobile,
|
|
282
|
+
resolution: resolution,
|
|
283
|
+
|
|
284
|
+
credentials: creds,
|
|
285
|
+
deviceOpts: deviceOpts || { audio: true, video: true }
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
return isLoopback ? new _session.LoopbackWebRTCSession(sessionOptions) : new _session.TurnWebRTCSession(sessionOptions, _this.createLocalMediaStream.bind(_this));
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
//
|
|
293
|
+
// OT CONNECTION (default mediaServiceType)
|
|
294
|
+
//
|
|
295
|
+
return Promise.resolve().then(function () {
|
|
296
|
+
return _waitForOT();
|
|
297
|
+
}).then(function () {
|
|
298
|
+
var sessionOptions = {
|
|
299
|
+
isMobile: isMobile,
|
|
300
|
+
resolution: resolution,
|
|
301
|
+
|
|
302
|
+
credentials: credentials.opentok
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
return new _session2.TsOpenTokSession(sessionOptions);
|
|
306
|
+
});
|
|
307
|
+
}).then(function (session) {
|
|
308
|
+
_this.emit(SERVICE_EVENTS.SESSION_CREATED, session);
|
|
309
|
+
|
|
310
|
+
sessions.push(session);
|
|
311
|
+
|
|
312
|
+
return session;
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
//# sourceMappingURL=service.js.map
|