easyproctor 0.0.53 → 0.0.55
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/esm/index.js +4077 -153
- package/index.d.ts +1 -9
- package/index.js +4081 -157
- package/modules/http.d.ts +1 -1
- package/modules/recorder copy.d.ts +1 -0
- package/modules/s3Client.d.ts +0 -0
- package/modules/upload.d.ts +1 -1
- package/modules/video.d.ts +1 -0
- package/package.json +10 -2
- package/unpkg/easyproctor.min.js +313 -19
package/esm/index.js
CHANGED
|
@@ -18,6 +18,3634 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
};
|
|
19
19
|
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod));
|
|
20
20
|
|
|
21
|
+
// node_modules/recordrtc/RecordRTC.js
|
|
22
|
+
var require_RecordRTC = __commonJS({
|
|
23
|
+
"node_modules/recordrtc/RecordRTC.js"(exports, module) {
|
|
24
|
+
"use strict";
|
|
25
|
+
function RecordRTC(mediaStream, config) {
|
|
26
|
+
if (!mediaStream) {
|
|
27
|
+
throw "First parameter is required.";
|
|
28
|
+
}
|
|
29
|
+
config = config || {
|
|
30
|
+
type: "video"
|
|
31
|
+
};
|
|
32
|
+
config = new RecordRTCConfiguration(mediaStream, config);
|
|
33
|
+
var self2 = this;
|
|
34
|
+
function startRecording(config2) {
|
|
35
|
+
if (!config.disableLogs) {
|
|
36
|
+
console.log("RecordRTC version: ", self2.version);
|
|
37
|
+
}
|
|
38
|
+
if (!!config2) {
|
|
39
|
+
config = new RecordRTCConfiguration(mediaStream, config2);
|
|
40
|
+
}
|
|
41
|
+
if (!config.disableLogs) {
|
|
42
|
+
console.log("started recording " + config.type + " stream.");
|
|
43
|
+
}
|
|
44
|
+
if (mediaRecorder) {
|
|
45
|
+
mediaRecorder.clearRecordedData();
|
|
46
|
+
mediaRecorder.record();
|
|
47
|
+
setState("recording");
|
|
48
|
+
if (self2.recordingDuration) {
|
|
49
|
+
handleRecordingDuration();
|
|
50
|
+
}
|
|
51
|
+
return self2;
|
|
52
|
+
}
|
|
53
|
+
initRecorder(function() {
|
|
54
|
+
if (self2.recordingDuration) {
|
|
55
|
+
handleRecordingDuration();
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
return self2;
|
|
59
|
+
}
|
|
60
|
+
function initRecorder(initCallback) {
|
|
61
|
+
if (initCallback) {
|
|
62
|
+
config.initCallback = function() {
|
|
63
|
+
initCallback();
|
|
64
|
+
initCallback = config.initCallback = null;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
var Recorder = new GetRecorderType(mediaStream, config);
|
|
68
|
+
mediaRecorder = new Recorder(mediaStream, config);
|
|
69
|
+
mediaRecorder.record();
|
|
70
|
+
setState("recording");
|
|
71
|
+
if (!config.disableLogs) {
|
|
72
|
+
console.log("Initialized recorderType:", mediaRecorder.constructor.name, "for output-type:", config.type);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function stopRecording(callback) {
|
|
76
|
+
callback = callback || function() {
|
|
77
|
+
};
|
|
78
|
+
if (!mediaRecorder) {
|
|
79
|
+
warningLog();
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (self2.state === "paused") {
|
|
83
|
+
self2.resumeRecording();
|
|
84
|
+
setTimeout(function() {
|
|
85
|
+
stopRecording(callback);
|
|
86
|
+
}, 1);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (self2.state !== "recording" && !config.disableLogs) {
|
|
90
|
+
console.warn('Recording state should be: "recording", however current state is: ', self2.state);
|
|
91
|
+
}
|
|
92
|
+
if (!config.disableLogs) {
|
|
93
|
+
console.log("Stopped recording " + config.type + " stream.");
|
|
94
|
+
}
|
|
95
|
+
if (config.type !== "gif") {
|
|
96
|
+
mediaRecorder.stop(_callback);
|
|
97
|
+
} else {
|
|
98
|
+
mediaRecorder.stop();
|
|
99
|
+
_callback();
|
|
100
|
+
}
|
|
101
|
+
setState("stopped");
|
|
102
|
+
function _callback(__blob) {
|
|
103
|
+
if (!mediaRecorder) {
|
|
104
|
+
if (typeof callback.call === "function") {
|
|
105
|
+
callback.call(self2, "");
|
|
106
|
+
} else {
|
|
107
|
+
callback("");
|
|
108
|
+
}
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
Object.keys(mediaRecorder).forEach(function(key) {
|
|
112
|
+
if (typeof mediaRecorder[key] === "function") {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
self2[key] = mediaRecorder[key];
|
|
116
|
+
});
|
|
117
|
+
var blob = mediaRecorder.blob;
|
|
118
|
+
if (!blob) {
|
|
119
|
+
if (__blob) {
|
|
120
|
+
mediaRecorder.blob = blob = __blob;
|
|
121
|
+
} else {
|
|
122
|
+
throw "Recording failed.";
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (blob && !config.disableLogs) {
|
|
126
|
+
console.log(blob.type, "->", bytesToSize(blob.size));
|
|
127
|
+
}
|
|
128
|
+
if (callback) {
|
|
129
|
+
var url;
|
|
130
|
+
try {
|
|
131
|
+
url = URL2.createObjectURL(blob);
|
|
132
|
+
} catch (e) {
|
|
133
|
+
}
|
|
134
|
+
if (typeof callback.call === "function") {
|
|
135
|
+
callback.call(self2, url);
|
|
136
|
+
} else {
|
|
137
|
+
callback(url);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (!config.autoWriteToDisk) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
getDataURL(function(dataURL) {
|
|
144
|
+
var parameter = {};
|
|
145
|
+
parameter[config.type + "Blob"] = dataURL;
|
|
146
|
+
DiskStorage.Store(parameter);
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
function pauseRecording() {
|
|
151
|
+
if (!mediaRecorder) {
|
|
152
|
+
warningLog();
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
if (self2.state !== "recording") {
|
|
156
|
+
if (!config.disableLogs) {
|
|
157
|
+
console.warn("Unable to pause the recording. Recording state: ", self2.state);
|
|
158
|
+
}
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
setState("paused");
|
|
162
|
+
mediaRecorder.pause();
|
|
163
|
+
if (!config.disableLogs) {
|
|
164
|
+
console.log("Paused recording.");
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function resumeRecording() {
|
|
168
|
+
if (!mediaRecorder) {
|
|
169
|
+
warningLog();
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
if (self2.state !== "paused") {
|
|
173
|
+
if (!config.disableLogs) {
|
|
174
|
+
console.warn("Unable to resume the recording. Recording state: ", self2.state);
|
|
175
|
+
}
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
setState("recording");
|
|
179
|
+
mediaRecorder.resume();
|
|
180
|
+
if (!config.disableLogs) {
|
|
181
|
+
console.log("Resumed recording.");
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
function readFile(_blob) {
|
|
185
|
+
postMessage(new FileReaderSync().readAsDataURL(_blob));
|
|
186
|
+
}
|
|
187
|
+
function getDataURL(callback, _mediaRecorder) {
|
|
188
|
+
if (!callback) {
|
|
189
|
+
throw "Pass a callback function over getDataURL.";
|
|
190
|
+
}
|
|
191
|
+
var blob = _mediaRecorder ? _mediaRecorder.blob : (mediaRecorder || {}).blob;
|
|
192
|
+
if (!blob) {
|
|
193
|
+
if (!config.disableLogs) {
|
|
194
|
+
console.warn("Blob encoder did not finish its job yet.");
|
|
195
|
+
}
|
|
196
|
+
setTimeout(function() {
|
|
197
|
+
getDataURL(callback, _mediaRecorder);
|
|
198
|
+
}, 1e3);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
if (typeof Worker !== "undefined" && !navigator.mozGetUserMedia) {
|
|
202
|
+
var webWorker = processInWebWorker(readFile);
|
|
203
|
+
webWorker.onmessage = function(event) {
|
|
204
|
+
callback(event.data);
|
|
205
|
+
};
|
|
206
|
+
webWorker.postMessage(blob);
|
|
207
|
+
} else {
|
|
208
|
+
var reader = new FileReader();
|
|
209
|
+
reader.readAsDataURL(blob);
|
|
210
|
+
reader.onload = function(event) {
|
|
211
|
+
callback(event.target.result);
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
function processInWebWorker(_function) {
|
|
215
|
+
try {
|
|
216
|
+
var blob2 = URL2.createObjectURL(new Blob([
|
|
217
|
+
_function.toString(),
|
|
218
|
+
"this.onmessage = function (eee) {" + _function.name + "(eee.data);}"
|
|
219
|
+
], {
|
|
220
|
+
type: "application/javascript"
|
|
221
|
+
}));
|
|
222
|
+
var worker = new Worker(blob2);
|
|
223
|
+
URL2.revokeObjectURL(blob2);
|
|
224
|
+
return worker;
|
|
225
|
+
} catch (e) {
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
function handleRecordingDuration(counter) {
|
|
230
|
+
counter = counter || 0;
|
|
231
|
+
if (self2.state === "paused") {
|
|
232
|
+
setTimeout(function() {
|
|
233
|
+
handleRecordingDuration(counter);
|
|
234
|
+
}, 1e3);
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
if (self2.state === "stopped") {
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
if (counter >= self2.recordingDuration) {
|
|
241
|
+
stopRecording(self2.onRecordingStopped);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
counter += 1e3;
|
|
245
|
+
setTimeout(function() {
|
|
246
|
+
handleRecordingDuration(counter);
|
|
247
|
+
}, 1e3);
|
|
248
|
+
}
|
|
249
|
+
function setState(state) {
|
|
250
|
+
if (!self2) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
self2.state = state;
|
|
254
|
+
if (typeof self2.onStateChanged.call === "function") {
|
|
255
|
+
self2.onStateChanged.call(self2, state);
|
|
256
|
+
} else {
|
|
257
|
+
self2.onStateChanged(state);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
var WARNING = 'It seems that recorder is destroyed or "startRecording" is not invoked for ' + config.type + " recorder.";
|
|
261
|
+
function warningLog() {
|
|
262
|
+
if (config.disableLogs === true) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
console.warn(WARNING);
|
|
266
|
+
}
|
|
267
|
+
var mediaRecorder;
|
|
268
|
+
var returnObject = {
|
|
269
|
+
startRecording,
|
|
270
|
+
stopRecording,
|
|
271
|
+
pauseRecording,
|
|
272
|
+
resumeRecording,
|
|
273
|
+
initRecorder,
|
|
274
|
+
setRecordingDuration: function(recordingDuration, callback) {
|
|
275
|
+
if (typeof recordingDuration === "undefined") {
|
|
276
|
+
throw "recordingDuration is required.";
|
|
277
|
+
}
|
|
278
|
+
if (typeof recordingDuration !== "number") {
|
|
279
|
+
throw "recordingDuration must be a number.";
|
|
280
|
+
}
|
|
281
|
+
self2.recordingDuration = recordingDuration;
|
|
282
|
+
self2.onRecordingStopped = callback || function() {
|
|
283
|
+
};
|
|
284
|
+
return {
|
|
285
|
+
onRecordingStopped: function(callback2) {
|
|
286
|
+
self2.onRecordingStopped = callback2;
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
},
|
|
290
|
+
clearRecordedData: function() {
|
|
291
|
+
if (!mediaRecorder) {
|
|
292
|
+
warningLog();
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
mediaRecorder.clearRecordedData();
|
|
296
|
+
if (!config.disableLogs) {
|
|
297
|
+
console.log("Cleared old recorded data.");
|
|
298
|
+
}
|
|
299
|
+
},
|
|
300
|
+
getBlob: function() {
|
|
301
|
+
if (!mediaRecorder) {
|
|
302
|
+
warningLog();
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
return mediaRecorder.blob;
|
|
306
|
+
},
|
|
307
|
+
getDataURL,
|
|
308
|
+
toURL: function() {
|
|
309
|
+
if (!mediaRecorder) {
|
|
310
|
+
warningLog();
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
return URL2.createObjectURL(mediaRecorder.blob);
|
|
314
|
+
},
|
|
315
|
+
getInternalRecorder: function() {
|
|
316
|
+
return mediaRecorder;
|
|
317
|
+
},
|
|
318
|
+
save: function(fileName) {
|
|
319
|
+
if (!mediaRecorder) {
|
|
320
|
+
warningLog();
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
invokeSaveAsDialog2(mediaRecorder.blob, fileName);
|
|
324
|
+
},
|
|
325
|
+
getFromDisk: function(callback) {
|
|
326
|
+
if (!mediaRecorder) {
|
|
327
|
+
warningLog();
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
RecordRTC.getFromDisk(config.type, callback);
|
|
331
|
+
},
|
|
332
|
+
setAdvertisementArray: function(arrayOfWebPImages) {
|
|
333
|
+
config.advertisement = [];
|
|
334
|
+
var length = arrayOfWebPImages.length;
|
|
335
|
+
for (var i = 0; i < length; i++) {
|
|
336
|
+
config.advertisement.push({
|
|
337
|
+
duration: i,
|
|
338
|
+
image: arrayOfWebPImages[i]
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
},
|
|
342
|
+
blob: null,
|
|
343
|
+
bufferSize: 0,
|
|
344
|
+
sampleRate: 0,
|
|
345
|
+
buffer: null,
|
|
346
|
+
reset: function() {
|
|
347
|
+
if (self2.state === "recording" && !config.disableLogs) {
|
|
348
|
+
console.warn("Stop an active recorder.");
|
|
349
|
+
}
|
|
350
|
+
if (mediaRecorder && typeof mediaRecorder.clearRecordedData === "function") {
|
|
351
|
+
mediaRecorder.clearRecordedData();
|
|
352
|
+
}
|
|
353
|
+
mediaRecorder = null;
|
|
354
|
+
setState("inactive");
|
|
355
|
+
self2.blob = null;
|
|
356
|
+
},
|
|
357
|
+
onStateChanged: function(state) {
|
|
358
|
+
if (!config.disableLogs) {
|
|
359
|
+
console.log("Recorder state changed:", state);
|
|
360
|
+
}
|
|
361
|
+
},
|
|
362
|
+
state: "inactive",
|
|
363
|
+
getState: function() {
|
|
364
|
+
return self2.state;
|
|
365
|
+
},
|
|
366
|
+
destroy: function() {
|
|
367
|
+
var disableLogsCache = config.disableLogs;
|
|
368
|
+
config = {
|
|
369
|
+
disableLogs: true
|
|
370
|
+
};
|
|
371
|
+
self2.reset();
|
|
372
|
+
setState("destroyed");
|
|
373
|
+
returnObject = self2 = null;
|
|
374
|
+
if (Storage.AudioContextConstructor) {
|
|
375
|
+
Storage.AudioContextConstructor.close();
|
|
376
|
+
Storage.AudioContextConstructor = null;
|
|
377
|
+
}
|
|
378
|
+
config.disableLogs = disableLogsCache;
|
|
379
|
+
if (!config.disableLogs) {
|
|
380
|
+
console.log("RecordRTC is destroyed.");
|
|
381
|
+
}
|
|
382
|
+
},
|
|
383
|
+
version: "5.6.2"
|
|
384
|
+
};
|
|
385
|
+
if (!this) {
|
|
386
|
+
self2 = returnObject;
|
|
387
|
+
return returnObject;
|
|
388
|
+
}
|
|
389
|
+
for (var prop in returnObject) {
|
|
390
|
+
this[prop] = returnObject[prop];
|
|
391
|
+
}
|
|
392
|
+
self2 = this;
|
|
393
|
+
return returnObject;
|
|
394
|
+
}
|
|
395
|
+
RecordRTC.version = "5.6.2";
|
|
396
|
+
if (typeof module !== "undefined") {
|
|
397
|
+
module.exports = RecordRTC;
|
|
398
|
+
}
|
|
399
|
+
if (typeof define === "function" && define.amd) {
|
|
400
|
+
define("RecordRTC", [], function() {
|
|
401
|
+
return RecordRTC;
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
RecordRTC.getFromDisk = function(type, callback) {
|
|
405
|
+
if (!callback) {
|
|
406
|
+
throw "callback is mandatory.";
|
|
407
|
+
}
|
|
408
|
+
console.log("Getting recorded " + (type === "all" ? "blobs" : type + " blob ") + " from disk!");
|
|
409
|
+
DiskStorage.Fetch(function(dataURL, _type) {
|
|
410
|
+
if (type !== "all" && _type === type + "Blob" && callback) {
|
|
411
|
+
callback(dataURL);
|
|
412
|
+
}
|
|
413
|
+
if (type === "all" && callback) {
|
|
414
|
+
callback(dataURL, _type.replace("Blob", ""));
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
};
|
|
418
|
+
RecordRTC.writeToDisk = function(options) {
|
|
419
|
+
console.log("Writing recorded blob(s) to disk!");
|
|
420
|
+
options = options || {};
|
|
421
|
+
if (options.audio && options.video && options.gif) {
|
|
422
|
+
options.audio.getDataURL(function(audioDataURL) {
|
|
423
|
+
options.video.getDataURL(function(videoDataURL) {
|
|
424
|
+
options.gif.getDataURL(function(gifDataURL) {
|
|
425
|
+
DiskStorage.Store({
|
|
426
|
+
audioBlob: audioDataURL,
|
|
427
|
+
videoBlob: videoDataURL,
|
|
428
|
+
gifBlob: gifDataURL
|
|
429
|
+
});
|
|
430
|
+
});
|
|
431
|
+
});
|
|
432
|
+
});
|
|
433
|
+
} else if (options.audio && options.video) {
|
|
434
|
+
options.audio.getDataURL(function(audioDataURL) {
|
|
435
|
+
options.video.getDataURL(function(videoDataURL) {
|
|
436
|
+
DiskStorage.Store({
|
|
437
|
+
audioBlob: audioDataURL,
|
|
438
|
+
videoBlob: videoDataURL
|
|
439
|
+
});
|
|
440
|
+
});
|
|
441
|
+
});
|
|
442
|
+
} else if (options.audio && options.gif) {
|
|
443
|
+
options.audio.getDataURL(function(audioDataURL) {
|
|
444
|
+
options.gif.getDataURL(function(gifDataURL) {
|
|
445
|
+
DiskStorage.Store({
|
|
446
|
+
audioBlob: audioDataURL,
|
|
447
|
+
gifBlob: gifDataURL
|
|
448
|
+
});
|
|
449
|
+
});
|
|
450
|
+
});
|
|
451
|
+
} else if (options.video && options.gif) {
|
|
452
|
+
options.video.getDataURL(function(videoDataURL) {
|
|
453
|
+
options.gif.getDataURL(function(gifDataURL) {
|
|
454
|
+
DiskStorage.Store({
|
|
455
|
+
videoBlob: videoDataURL,
|
|
456
|
+
gifBlob: gifDataURL
|
|
457
|
+
});
|
|
458
|
+
});
|
|
459
|
+
});
|
|
460
|
+
} else if (options.audio) {
|
|
461
|
+
options.audio.getDataURL(function(audioDataURL) {
|
|
462
|
+
DiskStorage.Store({
|
|
463
|
+
audioBlob: audioDataURL
|
|
464
|
+
});
|
|
465
|
+
});
|
|
466
|
+
} else if (options.video) {
|
|
467
|
+
options.video.getDataURL(function(videoDataURL) {
|
|
468
|
+
DiskStorage.Store({
|
|
469
|
+
videoBlob: videoDataURL
|
|
470
|
+
});
|
|
471
|
+
});
|
|
472
|
+
} else if (options.gif) {
|
|
473
|
+
options.gif.getDataURL(function(gifDataURL) {
|
|
474
|
+
DiskStorage.Store({
|
|
475
|
+
gifBlob: gifDataURL
|
|
476
|
+
});
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
};
|
|
480
|
+
function RecordRTCConfiguration(mediaStream, config) {
|
|
481
|
+
if (!config.recorderType && !config.type) {
|
|
482
|
+
if (!!config.audio && !!config.video) {
|
|
483
|
+
config.type = "video";
|
|
484
|
+
} else if (!!config.audio && !config.video) {
|
|
485
|
+
config.type = "audio";
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
if (config.recorderType && !config.type) {
|
|
489
|
+
if (config.recorderType === WhammyRecorder || config.recorderType === CanvasRecorder || typeof WebAssemblyRecorder !== "undefined" && config.recorderType === WebAssemblyRecorder) {
|
|
490
|
+
config.type = "video";
|
|
491
|
+
} else if (config.recorderType === GifRecorder) {
|
|
492
|
+
config.type = "gif";
|
|
493
|
+
} else if (config.recorderType === StereoAudioRecorder) {
|
|
494
|
+
config.type = "audio";
|
|
495
|
+
} else if (config.recorderType === MediaStreamRecorder) {
|
|
496
|
+
if (getTracks(mediaStream, "audio").length && getTracks(mediaStream, "video").length) {
|
|
497
|
+
config.type = "video";
|
|
498
|
+
} else if (!getTracks(mediaStream, "audio").length && getTracks(mediaStream, "video").length) {
|
|
499
|
+
config.type = "video";
|
|
500
|
+
} else if (getTracks(mediaStream, "audio").length && !getTracks(mediaStream, "video").length) {
|
|
501
|
+
config.type = "audio";
|
|
502
|
+
} else {
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
if (typeof MediaStreamRecorder !== "undefined" && typeof MediaRecorder !== "undefined" && "requestData" in MediaRecorder.prototype) {
|
|
507
|
+
if (!config.mimeType) {
|
|
508
|
+
config.mimeType = "video/webm";
|
|
509
|
+
}
|
|
510
|
+
if (!config.type) {
|
|
511
|
+
config.type = config.mimeType.split("/")[0];
|
|
512
|
+
}
|
|
513
|
+
if (!config.bitsPerSecond) {
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
if (!config.type) {
|
|
517
|
+
if (config.mimeType) {
|
|
518
|
+
config.type = config.mimeType.split("/")[0];
|
|
519
|
+
}
|
|
520
|
+
if (!config.type) {
|
|
521
|
+
config.type = "audio";
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
return config;
|
|
525
|
+
}
|
|
526
|
+
function GetRecorderType(mediaStream, config) {
|
|
527
|
+
var recorder;
|
|
528
|
+
if (isChrome || isEdge || isOpera) {
|
|
529
|
+
recorder = StereoAudioRecorder;
|
|
530
|
+
}
|
|
531
|
+
if (typeof MediaRecorder !== "undefined" && "requestData" in MediaRecorder.prototype && !isChrome) {
|
|
532
|
+
recorder = MediaStreamRecorder;
|
|
533
|
+
}
|
|
534
|
+
if (config.type === "video" && (isChrome || isOpera)) {
|
|
535
|
+
recorder = WhammyRecorder;
|
|
536
|
+
if (typeof WebAssemblyRecorder !== "undefined" && typeof ReadableStream !== "undefined") {
|
|
537
|
+
recorder = WebAssemblyRecorder;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
if (config.type === "gif") {
|
|
541
|
+
recorder = GifRecorder;
|
|
542
|
+
}
|
|
543
|
+
if (config.type === "canvas") {
|
|
544
|
+
recorder = CanvasRecorder;
|
|
545
|
+
}
|
|
546
|
+
if (isMediaRecorderCompatible() && recorder !== CanvasRecorder && recorder !== GifRecorder && typeof MediaRecorder !== "undefined" && "requestData" in MediaRecorder.prototype) {
|
|
547
|
+
if (getTracks(mediaStream, "video").length || getTracks(mediaStream, "audio").length) {
|
|
548
|
+
if (config.type === "audio") {
|
|
549
|
+
if (typeof MediaRecorder.isTypeSupported === "function" && MediaRecorder.isTypeSupported("audio/webm")) {
|
|
550
|
+
recorder = MediaStreamRecorder;
|
|
551
|
+
}
|
|
552
|
+
} else {
|
|
553
|
+
if (typeof MediaRecorder.isTypeSupported === "function" && MediaRecorder.isTypeSupported("video/webm")) {
|
|
554
|
+
recorder = MediaStreamRecorder;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
if (mediaStream instanceof Array && mediaStream.length) {
|
|
560
|
+
recorder = MultiStreamRecorder;
|
|
561
|
+
}
|
|
562
|
+
if (config.recorderType) {
|
|
563
|
+
recorder = config.recorderType;
|
|
564
|
+
}
|
|
565
|
+
if (!config.disableLogs && !!recorder && !!recorder.name) {
|
|
566
|
+
console.log("Using recorderType:", recorder.name || recorder.constructor.name);
|
|
567
|
+
}
|
|
568
|
+
if (!recorder && isSafari2) {
|
|
569
|
+
recorder = MediaStreamRecorder;
|
|
570
|
+
}
|
|
571
|
+
return recorder;
|
|
572
|
+
}
|
|
573
|
+
function MRecordRTC(mediaStream) {
|
|
574
|
+
this.addStream = function(_mediaStream) {
|
|
575
|
+
if (_mediaStream) {
|
|
576
|
+
mediaStream = _mediaStream;
|
|
577
|
+
}
|
|
578
|
+
};
|
|
579
|
+
this.mediaType = {
|
|
580
|
+
audio: true,
|
|
581
|
+
video: true
|
|
582
|
+
};
|
|
583
|
+
this.startRecording = function() {
|
|
584
|
+
var mediaType = this.mediaType;
|
|
585
|
+
var recorderType;
|
|
586
|
+
var mimeType = this.mimeType || {
|
|
587
|
+
audio: null,
|
|
588
|
+
video: null,
|
|
589
|
+
gif: null
|
|
590
|
+
};
|
|
591
|
+
if (typeof mediaType.audio !== "function" && isMediaRecorderCompatible() && !getTracks(mediaStream, "audio").length) {
|
|
592
|
+
mediaType.audio = false;
|
|
593
|
+
}
|
|
594
|
+
if (typeof mediaType.video !== "function" && isMediaRecorderCompatible() && !getTracks(mediaStream, "video").length) {
|
|
595
|
+
mediaType.video = false;
|
|
596
|
+
}
|
|
597
|
+
if (typeof mediaType.gif !== "function" && isMediaRecorderCompatible() && !getTracks(mediaStream, "video").length) {
|
|
598
|
+
mediaType.gif = false;
|
|
599
|
+
}
|
|
600
|
+
if (!mediaType.audio && !mediaType.video && !mediaType.gif) {
|
|
601
|
+
throw "MediaStream must have either audio or video tracks.";
|
|
602
|
+
}
|
|
603
|
+
if (!!mediaType.audio) {
|
|
604
|
+
recorderType = null;
|
|
605
|
+
if (typeof mediaType.audio === "function") {
|
|
606
|
+
recorderType = mediaType.audio;
|
|
607
|
+
}
|
|
608
|
+
this.audioRecorder = new RecordRTC(mediaStream, {
|
|
609
|
+
type: "audio",
|
|
610
|
+
bufferSize: this.bufferSize,
|
|
611
|
+
sampleRate: this.sampleRate,
|
|
612
|
+
numberOfAudioChannels: this.numberOfAudioChannels || 2,
|
|
613
|
+
disableLogs: this.disableLogs,
|
|
614
|
+
recorderType,
|
|
615
|
+
mimeType: mimeType.audio,
|
|
616
|
+
timeSlice: this.timeSlice,
|
|
617
|
+
onTimeStamp: this.onTimeStamp
|
|
618
|
+
});
|
|
619
|
+
if (!mediaType.video) {
|
|
620
|
+
this.audioRecorder.startRecording();
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
if (!!mediaType.video) {
|
|
624
|
+
recorderType = null;
|
|
625
|
+
if (typeof mediaType.video === "function") {
|
|
626
|
+
recorderType = mediaType.video;
|
|
627
|
+
}
|
|
628
|
+
var newStream = mediaStream;
|
|
629
|
+
if (isMediaRecorderCompatible() && !!mediaType.audio && typeof mediaType.audio === "function") {
|
|
630
|
+
var videoTrack = getTracks(mediaStream, "video")[0];
|
|
631
|
+
if (isFirefox) {
|
|
632
|
+
newStream = new MediaStream();
|
|
633
|
+
newStream.addTrack(videoTrack);
|
|
634
|
+
if (recorderType && recorderType === WhammyRecorder) {
|
|
635
|
+
recorderType = MediaStreamRecorder;
|
|
636
|
+
}
|
|
637
|
+
} else {
|
|
638
|
+
newStream = new MediaStream();
|
|
639
|
+
newStream.addTrack(videoTrack);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
this.videoRecorder = new RecordRTC(newStream, {
|
|
643
|
+
type: "video",
|
|
644
|
+
video: this.video,
|
|
645
|
+
canvas: this.canvas,
|
|
646
|
+
frameInterval: this.frameInterval || 10,
|
|
647
|
+
disableLogs: this.disableLogs,
|
|
648
|
+
recorderType,
|
|
649
|
+
mimeType: mimeType.video,
|
|
650
|
+
timeSlice: this.timeSlice,
|
|
651
|
+
onTimeStamp: this.onTimeStamp,
|
|
652
|
+
workerPath: this.workerPath,
|
|
653
|
+
webAssemblyPath: this.webAssemblyPath,
|
|
654
|
+
frameRate: this.frameRate,
|
|
655
|
+
bitrate: this.bitrate
|
|
656
|
+
});
|
|
657
|
+
if (!mediaType.audio) {
|
|
658
|
+
this.videoRecorder.startRecording();
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
if (!!mediaType.audio && !!mediaType.video) {
|
|
662
|
+
var self2 = this;
|
|
663
|
+
var isSingleRecorder = isMediaRecorderCompatible() === true;
|
|
664
|
+
if (mediaType.audio instanceof StereoAudioRecorder && !!mediaType.video) {
|
|
665
|
+
isSingleRecorder = false;
|
|
666
|
+
} else if (mediaType.audio !== true && mediaType.video !== true && mediaType.audio !== mediaType.video) {
|
|
667
|
+
isSingleRecorder = false;
|
|
668
|
+
}
|
|
669
|
+
if (isSingleRecorder === true) {
|
|
670
|
+
self2.audioRecorder = null;
|
|
671
|
+
self2.videoRecorder.startRecording();
|
|
672
|
+
} else {
|
|
673
|
+
self2.videoRecorder.initRecorder(function() {
|
|
674
|
+
self2.audioRecorder.initRecorder(function() {
|
|
675
|
+
self2.videoRecorder.startRecording();
|
|
676
|
+
self2.audioRecorder.startRecording();
|
|
677
|
+
});
|
|
678
|
+
});
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
if (!!mediaType.gif) {
|
|
682
|
+
recorderType = null;
|
|
683
|
+
if (typeof mediaType.gif === "function") {
|
|
684
|
+
recorderType = mediaType.gif;
|
|
685
|
+
}
|
|
686
|
+
this.gifRecorder = new RecordRTC(mediaStream, {
|
|
687
|
+
type: "gif",
|
|
688
|
+
frameRate: this.frameRate || 200,
|
|
689
|
+
quality: this.quality || 10,
|
|
690
|
+
disableLogs: this.disableLogs,
|
|
691
|
+
recorderType,
|
|
692
|
+
mimeType: mimeType.gif
|
|
693
|
+
});
|
|
694
|
+
this.gifRecorder.startRecording();
|
|
695
|
+
}
|
|
696
|
+
};
|
|
697
|
+
this.stopRecording = function(callback) {
|
|
698
|
+
callback = callback || function() {
|
|
699
|
+
};
|
|
700
|
+
if (this.audioRecorder) {
|
|
701
|
+
this.audioRecorder.stopRecording(function(blobURL) {
|
|
702
|
+
callback(blobURL, "audio");
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
if (this.videoRecorder) {
|
|
706
|
+
this.videoRecorder.stopRecording(function(blobURL) {
|
|
707
|
+
callback(blobURL, "video");
|
|
708
|
+
});
|
|
709
|
+
}
|
|
710
|
+
if (this.gifRecorder) {
|
|
711
|
+
this.gifRecorder.stopRecording(function(blobURL) {
|
|
712
|
+
callback(blobURL, "gif");
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
};
|
|
716
|
+
this.pauseRecording = function() {
|
|
717
|
+
if (this.audioRecorder) {
|
|
718
|
+
this.audioRecorder.pauseRecording();
|
|
719
|
+
}
|
|
720
|
+
if (this.videoRecorder) {
|
|
721
|
+
this.videoRecorder.pauseRecording();
|
|
722
|
+
}
|
|
723
|
+
if (this.gifRecorder) {
|
|
724
|
+
this.gifRecorder.pauseRecording();
|
|
725
|
+
}
|
|
726
|
+
};
|
|
727
|
+
this.resumeRecording = function() {
|
|
728
|
+
if (this.audioRecorder) {
|
|
729
|
+
this.audioRecorder.resumeRecording();
|
|
730
|
+
}
|
|
731
|
+
if (this.videoRecorder) {
|
|
732
|
+
this.videoRecorder.resumeRecording();
|
|
733
|
+
}
|
|
734
|
+
if (this.gifRecorder) {
|
|
735
|
+
this.gifRecorder.resumeRecording();
|
|
736
|
+
}
|
|
737
|
+
};
|
|
738
|
+
this.getBlob = function(callback) {
|
|
739
|
+
var output = {};
|
|
740
|
+
if (this.audioRecorder) {
|
|
741
|
+
output.audio = this.audioRecorder.getBlob();
|
|
742
|
+
}
|
|
743
|
+
if (this.videoRecorder) {
|
|
744
|
+
output.video = this.videoRecorder.getBlob();
|
|
745
|
+
}
|
|
746
|
+
if (this.gifRecorder) {
|
|
747
|
+
output.gif = this.gifRecorder.getBlob();
|
|
748
|
+
}
|
|
749
|
+
if (callback) {
|
|
750
|
+
callback(output);
|
|
751
|
+
}
|
|
752
|
+
return output;
|
|
753
|
+
};
|
|
754
|
+
this.destroy = function() {
|
|
755
|
+
if (this.audioRecorder) {
|
|
756
|
+
this.audioRecorder.destroy();
|
|
757
|
+
this.audioRecorder = null;
|
|
758
|
+
}
|
|
759
|
+
if (this.videoRecorder) {
|
|
760
|
+
this.videoRecorder.destroy();
|
|
761
|
+
this.videoRecorder = null;
|
|
762
|
+
}
|
|
763
|
+
if (this.gifRecorder) {
|
|
764
|
+
this.gifRecorder.destroy();
|
|
765
|
+
this.gifRecorder = null;
|
|
766
|
+
}
|
|
767
|
+
};
|
|
768
|
+
this.getDataURL = function(callback) {
|
|
769
|
+
this.getBlob(function(blob) {
|
|
770
|
+
if (blob.audio && blob.video) {
|
|
771
|
+
getDataURL(blob.audio, function(_audioDataURL) {
|
|
772
|
+
getDataURL(blob.video, function(_videoDataURL) {
|
|
773
|
+
callback({
|
|
774
|
+
audio: _audioDataURL,
|
|
775
|
+
video: _videoDataURL
|
|
776
|
+
});
|
|
777
|
+
});
|
|
778
|
+
});
|
|
779
|
+
} else if (blob.audio) {
|
|
780
|
+
getDataURL(blob.audio, function(_audioDataURL) {
|
|
781
|
+
callback({
|
|
782
|
+
audio: _audioDataURL
|
|
783
|
+
});
|
|
784
|
+
});
|
|
785
|
+
} else if (blob.video) {
|
|
786
|
+
getDataURL(blob.video, function(_videoDataURL) {
|
|
787
|
+
callback({
|
|
788
|
+
video: _videoDataURL
|
|
789
|
+
});
|
|
790
|
+
});
|
|
791
|
+
}
|
|
792
|
+
});
|
|
793
|
+
function getDataURL(blob, callback00) {
|
|
794
|
+
if (typeof Worker !== "undefined") {
|
|
795
|
+
var webWorker = processInWebWorker(function readFile(_blob) {
|
|
796
|
+
postMessage(new FileReaderSync().readAsDataURL(_blob));
|
|
797
|
+
});
|
|
798
|
+
webWorker.onmessage = function(event) {
|
|
799
|
+
callback00(event.data);
|
|
800
|
+
};
|
|
801
|
+
webWorker.postMessage(blob);
|
|
802
|
+
} else {
|
|
803
|
+
var reader = new FileReader();
|
|
804
|
+
reader.readAsDataURL(blob);
|
|
805
|
+
reader.onload = function(event) {
|
|
806
|
+
callback00(event.target.result);
|
|
807
|
+
};
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
function processInWebWorker(_function) {
|
|
811
|
+
var blob = URL2.createObjectURL(new Blob([
|
|
812
|
+
_function.toString(),
|
|
813
|
+
"this.onmessage = function (eee) {" + _function.name + "(eee.data);}"
|
|
814
|
+
], {
|
|
815
|
+
type: "application/javascript"
|
|
816
|
+
}));
|
|
817
|
+
var worker = new Worker(blob);
|
|
818
|
+
var url;
|
|
819
|
+
if (typeof URL2 !== "undefined") {
|
|
820
|
+
url = URL2;
|
|
821
|
+
} else if (typeof webkitURL !== "undefined") {
|
|
822
|
+
url = webkitURL;
|
|
823
|
+
} else {
|
|
824
|
+
throw "Neither URL nor webkitURL detected.";
|
|
825
|
+
}
|
|
826
|
+
url.revokeObjectURL(blob);
|
|
827
|
+
return worker;
|
|
828
|
+
}
|
|
829
|
+
};
|
|
830
|
+
this.writeToDisk = function() {
|
|
831
|
+
RecordRTC.writeToDisk({
|
|
832
|
+
audio: this.audioRecorder,
|
|
833
|
+
video: this.videoRecorder,
|
|
834
|
+
gif: this.gifRecorder
|
|
835
|
+
});
|
|
836
|
+
};
|
|
837
|
+
this.save = function(args) {
|
|
838
|
+
args = args || {
|
|
839
|
+
audio: true,
|
|
840
|
+
video: true,
|
|
841
|
+
gif: true
|
|
842
|
+
};
|
|
843
|
+
if (!!args.audio && this.audioRecorder) {
|
|
844
|
+
this.audioRecorder.save(typeof args.audio === "string" ? args.audio : "");
|
|
845
|
+
}
|
|
846
|
+
if (!!args.video && this.videoRecorder) {
|
|
847
|
+
this.videoRecorder.save(typeof args.video === "string" ? args.video : "");
|
|
848
|
+
}
|
|
849
|
+
if (!!args.gif && this.gifRecorder) {
|
|
850
|
+
this.gifRecorder.save(typeof args.gif === "string" ? args.gif : "");
|
|
851
|
+
}
|
|
852
|
+
};
|
|
853
|
+
}
|
|
854
|
+
MRecordRTC.getFromDisk = RecordRTC.getFromDisk;
|
|
855
|
+
MRecordRTC.writeToDisk = RecordRTC.writeToDisk;
|
|
856
|
+
if (typeof RecordRTC !== "undefined") {
|
|
857
|
+
RecordRTC.MRecordRTC = MRecordRTC;
|
|
858
|
+
}
|
|
859
|
+
var browserFakeUserAgent = "Fake/5.0 (FakeOS) AppleWebKit/123 (KHTML, like Gecko) Fake/12.3.4567.89 Fake/123.45";
|
|
860
|
+
(function(that) {
|
|
861
|
+
if (!that) {
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
if (typeof window !== "undefined") {
|
|
865
|
+
return;
|
|
866
|
+
}
|
|
867
|
+
if (typeof global === "undefined") {
|
|
868
|
+
return;
|
|
869
|
+
}
|
|
870
|
+
global.navigator = {
|
|
871
|
+
userAgent: browserFakeUserAgent,
|
|
872
|
+
getUserMedia: function() {
|
|
873
|
+
}
|
|
874
|
+
};
|
|
875
|
+
if (!global.console) {
|
|
876
|
+
global.console = {};
|
|
877
|
+
}
|
|
878
|
+
if (typeof global.console.log === "undefined" || typeof global.console.error === "undefined") {
|
|
879
|
+
global.console.error = global.console.log = global.console.log || function() {
|
|
880
|
+
console.log(arguments);
|
|
881
|
+
};
|
|
882
|
+
}
|
|
883
|
+
if (typeof document === "undefined") {
|
|
884
|
+
that.document = {
|
|
885
|
+
documentElement: {
|
|
886
|
+
appendChild: function() {
|
|
887
|
+
return "";
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
};
|
|
891
|
+
document.createElement = document.captureStream = document.mozCaptureStream = function() {
|
|
892
|
+
var obj = {
|
|
893
|
+
getContext: function() {
|
|
894
|
+
return obj;
|
|
895
|
+
},
|
|
896
|
+
play: function() {
|
|
897
|
+
},
|
|
898
|
+
pause: function() {
|
|
899
|
+
},
|
|
900
|
+
drawImage: function() {
|
|
901
|
+
},
|
|
902
|
+
toDataURL: function() {
|
|
903
|
+
return "";
|
|
904
|
+
},
|
|
905
|
+
style: {}
|
|
906
|
+
};
|
|
907
|
+
return obj;
|
|
908
|
+
};
|
|
909
|
+
that.HTMLVideoElement = function() {
|
|
910
|
+
};
|
|
911
|
+
}
|
|
912
|
+
if (typeof location === "undefined") {
|
|
913
|
+
that.location = {
|
|
914
|
+
protocol: "file:",
|
|
915
|
+
href: "",
|
|
916
|
+
hash: ""
|
|
917
|
+
};
|
|
918
|
+
}
|
|
919
|
+
if (typeof screen === "undefined") {
|
|
920
|
+
that.screen = {
|
|
921
|
+
width: 0,
|
|
922
|
+
height: 0
|
|
923
|
+
};
|
|
924
|
+
}
|
|
925
|
+
if (typeof URL2 === "undefined") {
|
|
926
|
+
that.URL = {
|
|
927
|
+
createObjectURL: function() {
|
|
928
|
+
return "";
|
|
929
|
+
},
|
|
930
|
+
revokeObjectURL: function() {
|
|
931
|
+
return "";
|
|
932
|
+
}
|
|
933
|
+
};
|
|
934
|
+
}
|
|
935
|
+
that.window = global;
|
|
936
|
+
})(typeof global !== "undefined" ? global : null);
|
|
937
|
+
var requestAnimationFrame = window.requestAnimationFrame;
|
|
938
|
+
if (typeof requestAnimationFrame === "undefined") {
|
|
939
|
+
if (typeof webkitRequestAnimationFrame !== "undefined") {
|
|
940
|
+
requestAnimationFrame = webkitRequestAnimationFrame;
|
|
941
|
+
} else if (typeof mozRequestAnimationFrame !== "undefined") {
|
|
942
|
+
requestAnimationFrame = mozRequestAnimationFrame;
|
|
943
|
+
} else if (typeof msRequestAnimationFrame !== "undefined") {
|
|
944
|
+
requestAnimationFrame = msRequestAnimationFrame;
|
|
945
|
+
} else if (typeof requestAnimationFrame === "undefined") {
|
|
946
|
+
lastTime = 0;
|
|
947
|
+
requestAnimationFrame = function(callback, element) {
|
|
948
|
+
var currTime = new Date().getTime();
|
|
949
|
+
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
|
|
950
|
+
var id = setTimeout(function() {
|
|
951
|
+
callback(currTime + timeToCall);
|
|
952
|
+
}, timeToCall);
|
|
953
|
+
lastTime = currTime + timeToCall;
|
|
954
|
+
return id;
|
|
955
|
+
};
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
var lastTime;
|
|
959
|
+
var cancelAnimationFrame = window.cancelAnimationFrame;
|
|
960
|
+
if (typeof cancelAnimationFrame === "undefined") {
|
|
961
|
+
if (typeof webkitCancelAnimationFrame !== "undefined") {
|
|
962
|
+
cancelAnimationFrame = webkitCancelAnimationFrame;
|
|
963
|
+
} else if (typeof mozCancelAnimationFrame !== "undefined") {
|
|
964
|
+
cancelAnimationFrame = mozCancelAnimationFrame;
|
|
965
|
+
} else if (typeof msCancelAnimationFrame !== "undefined") {
|
|
966
|
+
cancelAnimationFrame = msCancelAnimationFrame;
|
|
967
|
+
} else if (typeof cancelAnimationFrame === "undefined") {
|
|
968
|
+
cancelAnimationFrame = function(id) {
|
|
969
|
+
clearTimeout(id);
|
|
970
|
+
};
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
var AudioContext = window.AudioContext;
|
|
974
|
+
if (typeof AudioContext === "undefined") {
|
|
975
|
+
if (typeof webkitAudioContext !== "undefined") {
|
|
976
|
+
AudioContext = webkitAudioContext;
|
|
977
|
+
}
|
|
978
|
+
if (typeof mozAudioContext !== "undefined") {
|
|
979
|
+
AudioContext = mozAudioContext;
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
var URL2 = window.URL;
|
|
983
|
+
if (typeof URL2 === "undefined" && typeof webkitURL !== "undefined") {
|
|
984
|
+
URL2 = webkitURL;
|
|
985
|
+
}
|
|
986
|
+
if (typeof navigator !== "undefined" && typeof navigator.getUserMedia === "undefined") {
|
|
987
|
+
if (typeof navigator.webkitGetUserMedia !== "undefined") {
|
|
988
|
+
navigator.getUserMedia = navigator.webkitGetUserMedia;
|
|
989
|
+
}
|
|
990
|
+
if (typeof navigator.mozGetUserMedia !== "undefined") {
|
|
991
|
+
navigator.getUserMedia = navigator.mozGetUserMedia;
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
var isEdge = navigator.userAgent.indexOf("Edge") !== -1 && (!!navigator.msSaveBlob || !!navigator.msSaveOrOpenBlob);
|
|
995
|
+
var isOpera = !!window.opera || navigator.userAgent.indexOf("OPR/") !== -1;
|
|
996
|
+
var isFirefox = navigator.userAgent.toLowerCase().indexOf("firefox") > -1 && "netscape" in window && / rv:/.test(navigator.userAgent);
|
|
997
|
+
var isChrome = !isOpera && !isEdge && !!navigator.webkitGetUserMedia || isElectron() || navigator.userAgent.toLowerCase().indexOf("chrome/") !== -1;
|
|
998
|
+
var isSafari2 = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
|
999
|
+
if (isSafari2 && !isChrome && navigator.userAgent.indexOf("CriOS") !== -1) {
|
|
1000
|
+
isSafari2 = false;
|
|
1001
|
+
isChrome = true;
|
|
1002
|
+
}
|
|
1003
|
+
var MediaStream = window.MediaStream;
|
|
1004
|
+
if (typeof MediaStream === "undefined" && typeof webkitMediaStream !== "undefined") {
|
|
1005
|
+
MediaStream = webkitMediaStream;
|
|
1006
|
+
}
|
|
1007
|
+
if (typeof MediaStream !== "undefined") {
|
|
1008
|
+
if (typeof MediaStream.prototype.stop === "undefined") {
|
|
1009
|
+
MediaStream.prototype.stop = function() {
|
|
1010
|
+
this.getTracks().forEach(function(track) {
|
|
1011
|
+
track.stop();
|
|
1012
|
+
});
|
|
1013
|
+
};
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
function bytesToSize(bytes) {
|
|
1017
|
+
var k = 1e3;
|
|
1018
|
+
var sizes = ["Bytes", "KB", "MB", "GB", "TB"];
|
|
1019
|
+
if (bytes === 0) {
|
|
1020
|
+
return "0 Bytes";
|
|
1021
|
+
}
|
|
1022
|
+
var i = parseInt(Math.floor(Math.log(bytes) / Math.log(k)), 10);
|
|
1023
|
+
return (bytes / Math.pow(k, i)).toPrecision(3) + " " + sizes[i];
|
|
1024
|
+
}
|
|
1025
|
+
function invokeSaveAsDialog2(file, fileName) {
|
|
1026
|
+
if (!file) {
|
|
1027
|
+
throw "Blob object is required.";
|
|
1028
|
+
}
|
|
1029
|
+
if (!file.type) {
|
|
1030
|
+
try {
|
|
1031
|
+
file.type = "video/webm";
|
|
1032
|
+
} catch (e) {
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
var fileExtension = (file.type || "video/webm").split("/")[1];
|
|
1036
|
+
if (fileExtension.indexOf(";") !== -1) {
|
|
1037
|
+
fileExtension = fileExtension.split(";")[0];
|
|
1038
|
+
}
|
|
1039
|
+
if (fileName && fileName.indexOf(".") !== -1) {
|
|
1040
|
+
var splitted = fileName.split(".");
|
|
1041
|
+
fileName = splitted[0];
|
|
1042
|
+
fileExtension = splitted[1];
|
|
1043
|
+
}
|
|
1044
|
+
var fileFullName = (fileName || Math.round(Math.random() * 9999999999) + 888888888) + "." + fileExtension;
|
|
1045
|
+
if (typeof navigator.msSaveOrOpenBlob !== "undefined") {
|
|
1046
|
+
return navigator.msSaveOrOpenBlob(file, fileFullName);
|
|
1047
|
+
} else if (typeof navigator.msSaveBlob !== "undefined") {
|
|
1048
|
+
return navigator.msSaveBlob(file, fileFullName);
|
|
1049
|
+
}
|
|
1050
|
+
var hyperlink = document.createElement("a");
|
|
1051
|
+
hyperlink.href = URL2.createObjectURL(file);
|
|
1052
|
+
hyperlink.download = fileFullName;
|
|
1053
|
+
hyperlink.style = "display:none;opacity:0;color:transparent;";
|
|
1054
|
+
(document.body || document.documentElement).appendChild(hyperlink);
|
|
1055
|
+
if (typeof hyperlink.click === "function") {
|
|
1056
|
+
hyperlink.click();
|
|
1057
|
+
} else {
|
|
1058
|
+
hyperlink.target = "_blank";
|
|
1059
|
+
hyperlink.dispatchEvent(new MouseEvent("click", {
|
|
1060
|
+
view: window,
|
|
1061
|
+
bubbles: true,
|
|
1062
|
+
cancelable: true
|
|
1063
|
+
}));
|
|
1064
|
+
}
|
|
1065
|
+
URL2.revokeObjectURL(hyperlink.href);
|
|
1066
|
+
}
|
|
1067
|
+
function isElectron() {
|
|
1068
|
+
if (typeof window !== "undefined" && typeof window.process === "object" && window.process.type === "renderer") {
|
|
1069
|
+
return true;
|
|
1070
|
+
}
|
|
1071
|
+
if (typeof process !== "undefined" && typeof process.versions === "object" && !!process.versions.electron) {
|
|
1072
|
+
return true;
|
|
1073
|
+
}
|
|
1074
|
+
if (typeof navigator === "object" && typeof navigator.userAgent === "string" && navigator.userAgent.indexOf("Electron") >= 0) {
|
|
1075
|
+
return true;
|
|
1076
|
+
}
|
|
1077
|
+
return false;
|
|
1078
|
+
}
|
|
1079
|
+
function getTracks(stream, kind) {
|
|
1080
|
+
if (!stream || !stream.getTracks) {
|
|
1081
|
+
return [];
|
|
1082
|
+
}
|
|
1083
|
+
return stream.getTracks().filter(function(t) {
|
|
1084
|
+
return t.kind === (kind || "audio");
|
|
1085
|
+
});
|
|
1086
|
+
}
|
|
1087
|
+
function setSrcObject(stream, element) {
|
|
1088
|
+
if ("srcObject" in element) {
|
|
1089
|
+
element.srcObject = stream;
|
|
1090
|
+
} else if ("mozSrcObject" in element) {
|
|
1091
|
+
element.mozSrcObject = stream;
|
|
1092
|
+
} else {
|
|
1093
|
+
element.srcObject = stream;
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
function getSeekableBlob3(inputBlob, callback) {
|
|
1097
|
+
if (typeof EBML === "undefined") {
|
|
1098
|
+
throw new Error("Please link: https://www.webrtc-experiment.com/EBML.js");
|
|
1099
|
+
}
|
|
1100
|
+
var reader = new EBML.Reader();
|
|
1101
|
+
var decoder = new EBML.Decoder();
|
|
1102
|
+
var tools = EBML.tools;
|
|
1103
|
+
var fileReader = new FileReader();
|
|
1104
|
+
fileReader.onload = function(e) {
|
|
1105
|
+
var ebmlElms = decoder.decode(this.result);
|
|
1106
|
+
ebmlElms.forEach(function(element) {
|
|
1107
|
+
reader.read(element);
|
|
1108
|
+
});
|
|
1109
|
+
reader.stop();
|
|
1110
|
+
var refinedMetadataBuf = tools.makeMetadataSeekable(reader.metadatas, reader.duration, reader.cues);
|
|
1111
|
+
var body = this.result.slice(reader.metadataSize);
|
|
1112
|
+
var newBlob = new Blob([refinedMetadataBuf, body], {
|
|
1113
|
+
type: "video/webm"
|
|
1114
|
+
});
|
|
1115
|
+
callback(newBlob);
|
|
1116
|
+
};
|
|
1117
|
+
fileReader.readAsArrayBuffer(inputBlob);
|
|
1118
|
+
}
|
|
1119
|
+
if (typeof RecordRTC !== "undefined") {
|
|
1120
|
+
RecordRTC.invokeSaveAsDialog = invokeSaveAsDialog2;
|
|
1121
|
+
RecordRTC.getTracks = getTracks;
|
|
1122
|
+
RecordRTC.getSeekableBlob = getSeekableBlob3;
|
|
1123
|
+
RecordRTC.bytesToSize = bytesToSize;
|
|
1124
|
+
RecordRTC.isElectron = isElectron;
|
|
1125
|
+
}
|
|
1126
|
+
var Storage = {};
|
|
1127
|
+
if (typeof AudioContext !== "undefined") {
|
|
1128
|
+
Storage.AudioContext = AudioContext;
|
|
1129
|
+
} else if (typeof webkitAudioContext !== "undefined") {
|
|
1130
|
+
Storage.AudioContext = webkitAudioContext;
|
|
1131
|
+
}
|
|
1132
|
+
if (typeof RecordRTC !== "undefined") {
|
|
1133
|
+
RecordRTC.Storage = Storage;
|
|
1134
|
+
}
|
|
1135
|
+
function isMediaRecorderCompatible() {
|
|
1136
|
+
if (isFirefox || isSafari2 || isEdge) {
|
|
1137
|
+
return true;
|
|
1138
|
+
}
|
|
1139
|
+
var nVer = navigator.appVersion;
|
|
1140
|
+
var nAgt = navigator.userAgent;
|
|
1141
|
+
var fullVersion = "" + parseFloat(navigator.appVersion);
|
|
1142
|
+
var majorVersion = parseInt(navigator.appVersion, 10);
|
|
1143
|
+
var nameOffset, verOffset, ix;
|
|
1144
|
+
if (isChrome || isOpera) {
|
|
1145
|
+
verOffset = nAgt.indexOf("Chrome");
|
|
1146
|
+
fullVersion = nAgt.substring(verOffset + 7);
|
|
1147
|
+
}
|
|
1148
|
+
if ((ix = fullVersion.indexOf(";")) !== -1) {
|
|
1149
|
+
fullVersion = fullVersion.substring(0, ix);
|
|
1150
|
+
}
|
|
1151
|
+
if ((ix = fullVersion.indexOf(" ")) !== -1) {
|
|
1152
|
+
fullVersion = fullVersion.substring(0, ix);
|
|
1153
|
+
}
|
|
1154
|
+
majorVersion = parseInt("" + fullVersion, 10);
|
|
1155
|
+
if (isNaN(majorVersion)) {
|
|
1156
|
+
fullVersion = "" + parseFloat(navigator.appVersion);
|
|
1157
|
+
majorVersion = parseInt(navigator.appVersion, 10);
|
|
1158
|
+
}
|
|
1159
|
+
return majorVersion >= 49;
|
|
1160
|
+
}
|
|
1161
|
+
function MediaStreamRecorder(mediaStream, config) {
|
|
1162
|
+
var self2 = this;
|
|
1163
|
+
if (typeof mediaStream === "undefined") {
|
|
1164
|
+
throw 'First argument "MediaStream" is required.';
|
|
1165
|
+
}
|
|
1166
|
+
if (typeof MediaRecorder === "undefined") {
|
|
1167
|
+
throw "Your browser does not support the Media Recorder API. Please try other modules e.g. WhammyRecorder or StereoAudioRecorder.";
|
|
1168
|
+
}
|
|
1169
|
+
config = config || {
|
|
1170
|
+
mimeType: "video/webm"
|
|
1171
|
+
};
|
|
1172
|
+
if (config.type === "audio") {
|
|
1173
|
+
if (getTracks(mediaStream, "video").length && getTracks(mediaStream, "audio").length) {
|
|
1174
|
+
var stream;
|
|
1175
|
+
if (!!navigator.mozGetUserMedia) {
|
|
1176
|
+
stream = new MediaStream();
|
|
1177
|
+
stream.addTrack(getTracks(mediaStream, "audio")[0]);
|
|
1178
|
+
} else {
|
|
1179
|
+
stream = new MediaStream(getTracks(mediaStream, "audio"));
|
|
1180
|
+
}
|
|
1181
|
+
mediaStream = stream;
|
|
1182
|
+
}
|
|
1183
|
+
if (!config.mimeType || config.mimeType.toString().toLowerCase().indexOf("audio") === -1) {
|
|
1184
|
+
config.mimeType = isChrome ? "audio/webm" : "audio/ogg";
|
|
1185
|
+
}
|
|
1186
|
+
if (config.mimeType && config.mimeType.toString().toLowerCase() !== "audio/ogg" && !!navigator.mozGetUserMedia) {
|
|
1187
|
+
config.mimeType = "audio/ogg";
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
var arrayOfBlobs = [];
|
|
1191
|
+
this.getArrayOfBlobs = function() {
|
|
1192
|
+
return arrayOfBlobs;
|
|
1193
|
+
};
|
|
1194
|
+
this.record = function() {
|
|
1195
|
+
self2.blob = null;
|
|
1196
|
+
self2.clearRecordedData();
|
|
1197
|
+
self2.timestamps = [];
|
|
1198
|
+
allStates = [];
|
|
1199
|
+
arrayOfBlobs = [];
|
|
1200
|
+
var recorderHints = config;
|
|
1201
|
+
if (!config.disableLogs) {
|
|
1202
|
+
console.log("Passing following config over MediaRecorder API.", recorderHints);
|
|
1203
|
+
}
|
|
1204
|
+
if (mediaRecorder) {
|
|
1205
|
+
mediaRecorder = null;
|
|
1206
|
+
}
|
|
1207
|
+
if (isChrome && !isMediaRecorderCompatible()) {
|
|
1208
|
+
recorderHints = "video/vp8";
|
|
1209
|
+
}
|
|
1210
|
+
if (typeof MediaRecorder.isTypeSupported === "function" && recorderHints.mimeType) {
|
|
1211
|
+
if (!MediaRecorder.isTypeSupported(recorderHints.mimeType)) {
|
|
1212
|
+
if (!config.disableLogs) {
|
|
1213
|
+
console.warn("MediaRecorder API seems unable to record mimeType:", recorderHints.mimeType);
|
|
1214
|
+
}
|
|
1215
|
+
recorderHints.mimeType = config.type === "audio" ? "audio/webm" : "video/webm";
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
try {
|
|
1219
|
+
mediaRecorder = new MediaRecorder(mediaStream, recorderHints);
|
|
1220
|
+
config.mimeType = recorderHints.mimeType;
|
|
1221
|
+
} catch (e) {
|
|
1222
|
+
mediaRecorder = new MediaRecorder(mediaStream);
|
|
1223
|
+
}
|
|
1224
|
+
if (recorderHints.mimeType && !MediaRecorder.isTypeSupported && "canRecordMimeType" in mediaRecorder && mediaRecorder.canRecordMimeType(recorderHints.mimeType) === false) {
|
|
1225
|
+
if (!config.disableLogs) {
|
|
1226
|
+
console.warn("MediaRecorder API seems unable to record mimeType:", recorderHints.mimeType);
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
mediaRecorder.ondataavailable = function(e) {
|
|
1230
|
+
if (e.data) {
|
|
1231
|
+
allStates.push("ondataavailable: " + bytesToSize(e.data.size));
|
|
1232
|
+
}
|
|
1233
|
+
if (typeof config.timeSlice === "number") {
|
|
1234
|
+
if (e.data && e.data.size) {
|
|
1235
|
+
arrayOfBlobs.push(e.data);
|
|
1236
|
+
updateTimeStamp();
|
|
1237
|
+
if (typeof config.ondataavailable === "function") {
|
|
1238
|
+
var blob = config.getNativeBlob ? e.data : new Blob([e.data], {
|
|
1239
|
+
type: getMimeType(recorderHints)
|
|
1240
|
+
});
|
|
1241
|
+
config.ondataavailable(blob);
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
return;
|
|
1245
|
+
}
|
|
1246
|
+
if (!e.data || !e.data.size || e.data.size < 100 || self2.blob) {
|
|
1247
|
+
if (self2.recordingCallback) {
|
|
1248
|
+
self2.recordingCallback(new Blob([], {
|
|
1249
|
+
type: getMimeType(recorderHints)
|
|
1250
|
+
}));
|
|
1251
|
+
self2.recordingCallback = null;
|
|
1252
|
+
}
|
|
1253
|
+
return;
|
|
1254
|
+
}
|
|
1255
|
+
self2.blob = config.getNativeBlob ? e.data : new Blob([e.data], {
|
|
1256
|
+
type: getMimeType(recorderHints)
|
|
1257
|
+
});
|
|
1258
|
+
if (self2.recordingCallback) {
|
|
1259
|
+
self2.recordingCallback(self2.blob);
|
|
1260
|
+
self2.recordingCallback = null;
|
|
1261
|
+
}
|
|
1262
|
+
};
|
|
1263
|
+
mediaRecorder.onstart = function() {
|
|
1264
|
+
allStates.push("started");
|
|
1265
|
+
};
|
|
1266
|
+
mediaRecorder.onpause = function() {
|
|
1267
|
+
allStates.push("paused");
|
|
1268
|
+
};
|
|
1269
|
+
mediaRecorder.onresume = function() {
|
|
1270
|
+
allStates.push("resumed");
|
|
1271
|
+
};
|
|
1272
|
+
mediaRecorder.onstop = function() {
|
|
1273
|
+
allStates.push("stopped");
|
|
1274
|
+
};
|
|
1275
|
+
mediaRecorder.onerror = function(error) {
|
|
1276
|
+
if (!error) {
|
|
1277
|
+
return;
|
|
1278
|
+
}
|
|
1279
|
+
if (!error.name) {
|
|
1280
|
+
error.name = "UnknownError";
|
|
1281
|
+
}
|
|
1282
|
+
allStates.push("error: " + error);
|
|
1283
|
+
if (!config.disableLogs) {
|
|
1284
|
+
if (error.name.toString().toLowerCase().indexOf("invalidstate") !== -1) {
|
|
1285
|
+
console.error("The MediaRecorder is not in a state in which the proposed operation is allowed to be executed.", error);
|
|
1286
|
+
} else if (error.name.toString().toLowerCase().indexOf("notsupported") !== -1) {
|
|
1287
|
+
console.error("MIME type (", recorderHints.mimeType, ") is not supported.", error);
|
|
1288
|
+
} else if (error.name.toString().toLowerCase().indexOf("security") !== -1) {
|
|
1289
|
+
console.error("MediaRecorder security error", error);
|
|
1290
|
+
} else if (error.name === "OutOfMemory") {
|
|
1291
|
+
console.error("The UA has exhaused the available memory. User agents SHOULD provide as much additional information as possible in the message attribute.", error);
|
|
1292
|
+
} else if (error.name === "IllegalStreamModification") {
|
|
1293
|
+
console.error("A modification to the stream has occurred that makes it impossible to continue recording. An example would be the addition of a Track while recording is occurring. User agents SHOULD provide as much additional information as possible in the message attribute.", error);
|
|
1294
|
+
} else if (error.name === "OtherRecordingError") {
|
|
1295
|
+
console.error("Used for an fatal error other than those listed above. User agents SHOULD provide as much additional information as possible in the message attribute.", error);
|
|
1296
|
+
} else if (error.name === "GenericError") {
|
|
1297
|
+
console.error("The UA cannot provide the codec or recording option that has been requested.", error);
|
|
1298
|
+
} else {
|
|
1299
|
+
console.error("MediaRecorder Error", error);
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
(function(looper) {
|
|
1303
|
+
if (!self2.manuallyStopped && mediaRecorder && mediaRecorder.state === "inactive") {
|
|
1304
|
+
delete config.timeslice;
|
|
1305
|
+
mediaRecorder.start(10 * 60 * 1e3);
|
|
1306
|
+
return;
|
|
1307
|
+
}
|
|
1308
|
+
setTimeout(looper, 1e3);
|
|
1309
|
+
})();
|
|
1310
|
+
if (mediaRecorder.state !== "inactive" && mediaRecorder.state !== "stopped") {
|
|
1311
|
+
mediaRecorder.stop();
|
|
1312
|
+
}
|
|
1313
|
+
};
|
|
1314
|
+
if (typeof config.timeSlice === "number") {
|
|
1315
|
+
updateTimeStamp();
|
|
1316
|
+
mediaRecorder.start(config.timeSlice);
|
|
1317
|
+
} else {
|
|
1318
|
+
mediaRecorder.start(36e5);
|
|
1319
|
+
}
|
|
1320
|
+
if (config.initCallback) {
|
|
1321
|
+
config.initCallback();
|
|
1322
|
+
}
|
|
1323
|
+
};
|
|
1324
|
+
this.timestamps = [];
|
|
1325
|
+
function updateTimeStamp() {
|
|
1326
|
+
self2.timestamps.push(new Date().getTime());
|
|
1327
|
+
if (typeof config.onTimeStamp === "function") {
|
|
1328
|
+
config.onTimeStamp(self2.timestamps[self2.timestamps.length - 1], self2.timestamps);
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
function getMimeType(secondObject) {
|
|
1332
|
+
if (mediaRecorder && mediaRecorder.mimeType) {
|
|
1333
|
+
return mediaRecorder.mimeType;
|
|
1334
|
+
}
|
|
1335
|
+
return secondObject.mimeType || "video/webm";
|
|
1336
|
+
}
|
|
1337
|
+
this.stop = function(callback) {
|
|
1338
|
+
callback = callback || function() {
|
|
1339
|
+
};
|
|
1340
|
+
self2.manuallyStopped = true;
|
|
1341
|
+
if (!mediaRecorder) {
|
|
1342
|
+
return;
|
|
1343
|
+
}
|
|
1344
|
+
this.recordingCallback = callback;
|
|
1345
|
+
if (mediaRecorder.state === "recording") {
|
|
1346
|
+
mediaRecorder.stop();
|
|
1347
|
+
}
|
|
1348
|
+
if (typeof config.timeSlice === "number") {
|
|
1349
|
+
setTimeout(function() {
|
|
1350
|
+
self2.blob = new Blob(arrayOfBlobs, {
|
|
1351
|
+
type: getMimeType(config)
|
|
1352
|
+
});
|
|
1353
|
+
self2.recordingCallback(self2.blob);
|
|
1354
|
+
}, 100);
|
|
1355
|
+
}
|
|
1356
|
+
};
|
|
1357
|
+
this.pause = function() {
|
|
1358
|
+
if (!mediaRecorder) {
|
|
1359
|
+
return;
|
|
1360
|
+
}
|
|
1361
|
+
if (mediaRecorder.state === "recording") {
|
|
1362
|
+
mediaRecorder.pause();
|
|
1363
|
+
}
|
|
1364
|
+
};
|
|
1365
|
+
this.resume = function() {
|
|
1366
|
+
if (!mediaRecorder) {
|
|
1367
|
+
return;
|
|
1368
|
+
}
|
|
1369
|
+
if (mediaRecorder.state === "paused") {
|
|
1370
|
+
mediaRecorder.resume();
|
|
1371
|
+
}
|
|
1372
|
+
};
|
|
1373
|
+
this.clearRecordedData = function() {
|
|
1374
|
+
if (mediaRecorder && mediaRecorder.state === "recording") {
|
|
1375
|
+
self2.stop(clearRecordedDataCB);
|
|
1376
|
+
}
|
|
1377
|
+
clearRecordedDataCB();
|
|
1378
|
+
};
|
|
1379
|
+
function clearRecordedDataCB() {
|
|
1380
|
+
arrayOfBlobs = [];
|
|
1381
|
+
mediaRecorder = null;
|
|
1382
|
+
self2.timestamps = [];
|
|
1383
|
+
}
|
|
1384
|
+
var mediaRecorder;
|
|
1385
|
+
this.getInternalRecorder = function() {
|
|
1386
|
+
return mediaRecorder;
|
|
1387
|
+
};
|
|
1388
|
+
function isMediaStreamActive() {
|
|
1389
|
+
if ("active" in mediaStream) {
|
|
1390
|
+
if (!mediaStream.active) {
|
|
1391
|
+
return false;
|
|
1392
|
+
}
|
|
1393
|
+
} else if ("ended" in mediaStream) {
|
|
1394
|
+
if (mediaStream.ended) {
|
|
1395
|
+
return false;
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
return true;
|
|
1399
|
+
}
|
|
1400
|
+
this.blob = null;
|
|
1401
|
+
this.getState = function() {
|
|
1402
|
+
if (!mediaRecorder) {
|
|
1403
|
+
return "inactive";
|
|
1404
|
+
}
|
|
1405
|
+
return mediaRecorder.state || "inactive";
|
|
1406
|
+
};
|
|
1407
|
+
var allStates = [];
|
|
1408
|
+
this.getAllStates = function() {
|
|
1409
|
+
return allStates;
|
|
1410
|
+
};
|
|
1411
|
+
if (typeof config.checkForInactiveTracks === "undefined") {
|
|
1412
|
+
config.checkForInactiveTracks = false;
|
|
1413
|
+
}
|
|
1414
|
+
var self2 = this;
|
|
1415
|
+
(function looper() {
|
|
1416
|
+
if (!mediaRecorder || config.checkForInactiveTracks === false) {
|
|
1417
|
+
return;
|
|
1418
|
+
}
|
|
1419
|
+
if (isMediaStreamActive() === false) {
|
|
1420
|
+
if (!config.disableLogs) {
|
|
1421
|
+
console.log("MediaStream seems stopped.");
|
|
1422
|
+
}
|
|
1423
|
+
self2.stop();
|
|
1424
|
+
return;
|
|
1425
|
+
}
|
|
1426
|
+
setTimeout(looper, 1e3);
|
|
1427
|
+
})();
|
|
1428
|
+
this.name = "MediaStreamRecorder";
|
|
1429
|
+
this.toString = function() {
|
|
1430
|
+
return this.name;
|
|
1431
|
+
};
|
|
1432
|
+
}
|
|
1433
|
+
if (typeof RecordRTC !== "undefined") {
|
|
1434
|
+
RecordRTC.MediaStreamRecorder = MediaStreamRecorder;
|
|
1435
|
+
}
|
|
1436
|
+
function StereoAudioRecorder(mediaStream, config) {
|
|
1437
|
+
if (!getTracks(mediaStream, "audio").length) {
|
|
1438
|
+
throw "Your stream has no audio tracks.";
|
|
1439
|
+
}
|
|
1440
|
+
config = config || {};
|
|
1441
|
+
var self2 = this;
|
|
1442
|
+
var leftchannel = [];
|
|
1443
|
+
var rightchannel = [];
|
|
1444
|
+
var recording = false;
|
|
1445
|
+
var recordingLength = 0;
|
|
1446
|
+
var jsAudioNode;
|
|
1447
|
+
var numberOfAudioChannels = 2;
|
|
1448
|
+
var desiredSampRate = config.desiredSampRate;
|
|
1449
|
+
if (config.leftChannel === true) {
|
|
1450
|
+
numberOfAudioChannels = 1;
|
|
1451
|
+
}
|
|
1452
|
+
if (config.numberOfAudioChannels === 1) {
|
|
1453
|
+
numberOfAudioChannels = 1;
|
|
1454
|
+
}
|
|
1455
|
+
if (!numberOfAudioChannels || numberOfAudioChannels < 1) {
|
|
1456
|
+
numberOfAudioChannels = 2;
|
|
1457
|
+
}
|
|
1458
|
+
if (!config.disableLogs) {
|
|
1459
|
+
console.log("StereoAudioRecorder is set to record number of channels: " + numberOfAudioChannels);
|
|
1460
|
+
}
|
|
1461
|
+
if (typeof config.checkForInactiveTracks === "undefined") {
|
|
1462
|
+
config.checkForInactiveTracks = true;
|
|
1463
|
+
}
|
|
1464
|
+
function isMediaStreamActive() {
|
|
1465
|
+
if (config.checkForInactiveTracks === false) {
|
|
1466
|
+
return true;
|
|
1467
|
+
}
|
|
1468
|
+
if ("active" in mediaStream) {
|
|
1469
|
+
if (!mediaStream.active) {
|
|
1470
|
+
return false;
|
|
1471
|
+
}
|
|
1472
|
+
} else if ("ended" in mediaStream) {
|
|
1473
|
+
if (mediaStream.ended) {
|
|
1474
|
+
return false;
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
return true;
|
|
1478
|
+
}
|
|
1479
|
+
this.record = function() {
|
|
1480
|
+
if (isMediaStreamActive() === false) {
|
|
1481
|
+
throw "Please make sure MediaStream is active.";
|
|
1482
|
+
}
|
|
1483
|
+
resetVariables();
|
|
1484
|
+
isAudioProcessStarted = isPaused = false;
|
|
1485
|
+
recording = true;
|
|
1486
|
+
if (typeof config.timeSlice !== "undefined") {
|
|
1487
|
+
looper();
|
|
1488
|
+
}
|
|
1489
|
+
};
|
|
1490
|
+
function mergeLeftRightBuffers(config2, callback) {
|
|
1491
|
+
function mergeAudioBuffers(config3, cb) {
|
|
1492
|
+
var numberOfAudioChannels2 = config3.numberOfAudioChannels;
|
|
1493
|
+
var leftBuffers = config3.leftBuffers.slice(0);
|
|
1494
|
+
var rightBuffers = config3.rightBuffers.slice(0);
|
|
1495
|
+
var sampleRate2 = config3.sampleRate;
|
|
1496
|
+
var internalInterleavedLength = config3.internalInterleavedLength;
|
|
1497
|
+
var desiredSampRate2 = config3.desiredSampRate;
|
|
1498
|
+
if (numberOfAudioChannels2 === 2) {
|
|
1499
|
+
leftBuffers = mergeBuffers(leftBuffers, internalInterleavedLength);
|
|
1500
|
+
rightBuffers = mergeBuffers(rightBuffers, internalInterleavedLength);
|
|
1501
|
+
if (desiredSampRate2) {
|
|
1502
|
+
leftBuffers = interpolateArray(leftBuffers, desiredSampRate2, sampleRate2);
|
|
1503
|
+
rightBuffers = interpolateArray(rightBuffers, desiredSampRate2, sampleRate2);
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
if (numberOfAudioChannels2 === 1) {
|
|
1507
|
+
leftBuffers = mergeBuffers(leftBuffers, internalInterleavedLength);
|
|
1508
|
+
if (desiredSampRate2) {
|
|
1509
|
+
leftBuffers = interpolateArray(leftBuffers, desiredSampRate2, sampleRate2);
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
if (desiredSampRate2) {
|
|
1513
|
+
sampleRate2 = desiredSampRate2;
|
|
1514
|
+
}
|
|
1515
|
+
function interpolateArray(data, newSampleRate, oldSampleRate) {
|
|
1516
|
+
var fitCount = Math.round(data.length * (newSampleRate / oldSampleRate));
|
|
1517
|
+
var newData = [];
|
|
1518
|
+
var springFactor = Number((data.length - 1) / (fitCount - 1));
|
|
1519
|
+
newData[0] = data[0];
|
|
1520
|
+
for (var i2 = 1; i2 < fitCount - 1; i2++) {
|
|
1521
|
+
var tmp = i2 * springFactor;
|
|
1522
|
+
var before = Number(Math.floor(tmp)).toFixed();
|
|
1523
|
+
var after = Number(Math.ceil(tmp)).toFixed();
|
|
1524
|
+
var atPoint = tmp - before;
|
|
1525
|
+
newData[i2] = linearInterpolate(data[before], data[after], atPoint);
|
|
1526
|
+
}
|
|
1527
|
+
newData[fitCount - 1] = data[data.length - 1];
|
|
1528
|
+
return newData;
|
|
1529
|
+
}
|
|
1530
|
+
function linearInterpolate(before, after, atPoint) {
|
|
1531
|
+
return before + (after - before) * atPoint;
|
|
1532
|
+
}
|
|
1533
|
+
function mergeBuffers(channelBuffer, rLength) {
|
|
1534
|
+
var result = new Float64Array(rLength);
|
|
1535
|
+
var offset = 0;
|
|
1536
|
+
var lng2 = channelBuffer.length;
|
|
1537
|
+
for (var i2 = 0; i2 < lng2; i2++) {
|
|
1538
|
+
var buffer2 = channelBuffer[i2];
|
|
1539
|
+
result.set(buffer2, offset);
|
|
1540
|
+
offset += buffer2.length;
|
|
1541
|
+
}
|
|
1542
|
+
return result;
|
|
1543
|
+
}
|
|
1544
|
+
function interleave(leftChannel, rightChannel) {
|
|
1545
|
+
var length = leftChannel.length + rightChannel.length;
|
|
1546
|
+
var result = new Float64Array(length);
|
|
1547
|
+
var inputIndex = 0;
|
|
1548
|
+
for (var index2 = 0; index2 < length; ) {
|
|
1549
|
+
result[index2++] = leftChannel[inputIndex];
|
|
1550
|
+
result[index2++] = rightChannel[inputIndex];
|
|
1551
|
+
inputIndex++;
|
|
1552
|
+
}
|
|
1553
|
+
return result;
|
|
1554
|
+
}
|
|
1555
|
+
function writeUTFBytes(view2, offset, string) {
|
|
1556
|
+
var lng2 = string.length;
|
|
1557
|
+
for (var i2 = 0; i2 < lng2; i2++) {
|
|
1558
|
+
view2.setUint8(offset + i2, string.charCodeAt(i2));
|
|
1559
|
+
}
|
|
1560
|
+
}
|
|
1561
|
+
var interleaved;
|
|
1562
|
+
if (numberOfAudioChannels2 === 2) {
|
|
1563
|
+
interleaved = interleave(leftBuffers, rightBuffers);
|
|
1564
|
+
}
|
|
1565
|
+
if (numberOfAudioChannels2 === 1) {
|
|
1566
|
+
interleaved = leftBuffers;
|
|
1567
|
+
}
|
|
1568
|
+
var interleavedLength = interleaved.length;
|
|
1569
|
+
var resultingBufferLength = 44 + interleavedLength * 2;
|
|
1570
|
+
var buffer = new ArrayBuffer(resultingBufferLength);
|
|
1571
|
+
var view = new DataView(buffer);
|
|
1572
|
+
writeUTFBytes(view, 0, "RIFF");
|
|
1573
|
+
view.setUint32(4, 36 + interleavedLength * 2, true);
|
|
1574
|
+
writeUTFBytes(view, 8, "WAVE");
|
|
1575
|
+
writeUTFBytes(view, 12, "fmt ");
|
|
1576
|
+
view.setUint32(16, 16, true);
|
|
1577
|
+
view.setUint16(20, 1, true);
|
|
1578
|
+
view.setUint16(22, numberOfAudioChannels2, true);
|
|
1579
|
+
view.setUint32(24, sampleRate2, true);
|
|
1580
|
+
view.setUint32(28, sampleRate2 * numberOfAudioChannels2 * 2, true);
|
|
1581
|
+
view.setUint16(32, numberOfAudioChannels2 * 2, true);
|
|
1582
|
+
view.setUint16(34, 16, true);
|
|
1583
|
+
writeUTFBytes(view, 36, "data");
|
|
1584
|
+
view.setUint32(40, interleavedLength * 2, true);
|
|
1585
|
+
var lng = interleavedLength;
|
|
1586
|
+
var index = 44;
|
|
1587
|
+
var volume = 1;
|
|
1588
|
+
for (var i = 0; i < lng; i++) {
|
|
1589
|
+
view.setInt16(index, interleaved[i] * (32767 * volume), true);
|
|
1590
|
+
index += 2;
|
|
1591
|
+
}
|
|
1592
|
+
if (cb) {
|
|
1593
|
+
return cb({
|
|
1594
|
+
buffer,
|
|
1595
|
+
view
|
|
1596
|
+
});
|
|
1597
|
+
}
|
|
1598
|
+
postMessage({
|
|
1599
|
+
buffer,
|
|
1600
|
+
view
|
|
1601
|
+
});
|
|
1602
|
+
}
|
|
1603
|
+
if (config2.noWorker) {
|
|
1604
|
+
mergeAudioBuffers(config2, function(data) {
|
|
1605
|
+
callback(data.buffer, data.view);
|
|
1606
|
+
});
|
|
1607
|
+
return;
|
|
1608
|
+
}
|
|
1609
|
+
var webWorker = processInWebWorker(mergeAudioBuffers);
|
|
1610
|
+
webWorker.onmessage = function(event) {
|
|
1611
|
+
callback(event.data.buffer, event.data.view);
|
|
1612
|
+
URL2.revokeObjectURL(webWorker.workerURL);
|
|
1613
|
+
webWorker.terminate();
|
|
1614
|
+
};
|
|
1615
|
+
webWorker.postMessage(config2);
|
|
1616
|
+
}
|
|
1617
|
+
function processInWebWorker(_function) {
|
|
1618
|
+
var workerURL = URL2.createObjectURL(new Blob([
|
|
1619
|
+
_function.toString(),
|
|
1620
|
+
";this.onmessage = function (eee) {" + _function.name + "(eee.data);}"
|
|
1621
|
+
], {
|
|
1622
|
+
type: "application/javascript"
|
|
1623
|
+
}));
|
|
1624
|
+
var worker = new Worker(workerURL);
|
|
1625
|
+
worker.workerURL = workerURL;
|
|
1626
|
+
return worker;
|
|
1627
|
+
}
|
|
1628
|
+
this.stop = function(callback) {
|
|
1629
|
+
callback = callback || function() {
|
|
1630
|
+
};
|
|
1631
|
+
recording = false;
|
|
1632
|
+
mergeLeftRightBuffers({
|
|
1633
|
+
desiredSampRate,
|
|
1634
|
+
sampleRate,
|
|
1635
|
+
numberOfAudioChannels,
|
|
1636
|
+
internalInterleavedLength: recordingLength,
|
|
1637
|
+
leftBuffers: leftchannel,
|
|
1638
|
+
rightBuffers: numberOfAudioChannels === 1 ? [] : rightchannel,
|
|
1639
|
+
noWorker: config.noWorker
|
|
1640
|
+
}, function(buffer, view) {
|
|
1641
|
+
self2.blob = new Blob([view], {
|
|
1642
|
+
type: "audio/wav"
|
|
1643
|
+
});
|
|
1644
|
+
self2.buffer = new ArrayBuffer(view.buffer.byteLength);
|
|
1645
|
+
self2.view = view;
|
|
1646
|
+
self2.sampleRate = desiredSampRate || sampleRate;
|
|
1647
|
+
self2.bufferSize = bufferSize;
|
|
1648
|
+
self2.length = recordingLength;
|
|
1649
|
+
isAudioProcessStarted = false;
|
|
1650
|
+
if (callback) {
|
|
1651
|
+
callback(self2.blob);
|
|
1652
|
+
}
|
|
1653
|
+
});
|
|
1654
|
+
};
|
|
1655
|
+
if (typeof RecordRTC.Storage === "undefined") {
|
|
1656
|
+
RecordRTC.Storage = {
|
|
1657
|
+
AudioContextConstructor: null,
|
|
1658
|
+
AudioContext: window.AudioContext || window.webkitAudioContext
|
|
1659
|
+
};
|
|
1660
|
+
}
|
|
1661
|
+
if (!RecordRTC.Storage.AudioContextConstructor || RecordRTC.Storage.AudioContextConstructor.state === "closed") {
|
|
1662
|
+
RecordRTC.Storage.AudioContextConstructor = new RecordRTC.Storage.AudioContext();
|
|
1663
|
+
}
|
|
1664
|
+
var context = RecordRTC.Storage.AudioContextConstructor;
|
|
1665
|
+
var audioInput = context.createMediaStreamSource(mediaStream);
|
|
1666
|
+
var legalBufferValues = [0, 256, 512, 1024, 2048, 4096, 8192, 16384];
|
|
1667
|
+
var bufferSize = typeof config.bufferSize === "undefined" ? 4096 : config.bufferSize;
|
|
1668
|
+
if (legalBufferValues.indexOf(bufferSize) === -1) {
|
|
1669
|
+
if (!config.disableLogs) {
|
|
1670
|
+
console.log("Legal values for buffer-size are " + JSON.stringify(legalBufferValues, null, " "));
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1673
|
+
if (context.createJavaScriptNode) {
|
|
1674
|
+
jsAudioNode = context.createJavaScriptNode(bufferSize, numberOfAudioChannels, numberOfAudioChannels);
|
|
1675
|
+
} else if (context.createScriptProcessor) {
|
|
1676
|
+
jsAudioNode = context.createScriptProcessor(bufferSize, numberOfAudioChannels, numberOfAudioChannels);
|
|
1677
|
+
} else {
|
|
1678
|
+
throw "WebAudio API has no support on this browser.";
|
|
1679
|
+
}
|
|
1680
|
+
audioInput.connect(jsAudioNode);
|
|
1681
|
+
if (!config.bufferSize) {
|
|
1682
|
+
bufferSize = jsAudioNode.bufferSize;
|
|
1683
|
+
}
|
|
1684
|
+
var sampleRate = typeof config.sampleRate !== "undefined" ? config.sampleRate : context.sampleRate || 44100;
|
|
1685
|
+
if (sampleRate < 22050 || sampleRate > 96e3) {
|
|
1686
|
+
if (!config.disableLogs) {
|
|
1687
|
+
console.log("sample-rate must be under range 22050 and 96000.");
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
if (!config.disableLogs) {
|
|
1691
|
+
if (config.desiredSampRate) {
|
|
1692
|
+
console.log("Desired sample-rate: " + config.desiredSampRate);
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
var isPaused = false;
|
|
1696
|
+
this.pause = function() {
|
|
1697
|
+
isPaused = true;
|
|
1698
|
+
};
|
|
1699
|
+
this.resume = function() {
|
|
1700
|
+
if (isMediaStreamActive() === false) {
|
|
1701
|
+
throw "Please make sure MediaStream is active.";
|
|
1702
|
+
}
|
|
1703
|
+
if (!recording) {
|
|
1704
|
+
if (!config.disableLogs) {
|
|
1705
|
+
console.log("Seems recording has been restarted.");
|
|
1706
|
+
}
|
|
1707
|
+
this.record();
|
|
1708
|
+
return;
|
|
1709
|
+
}
|
|
1710
|
+
isPaused = false;
|
|
1711
|
+
};
|
|
1712
|
+
this.clearRecordedData = function() {
|
|
1713
|
+
config.checkForInactiveTracks = false;
|
|
1714
|
+
if (recording) {
|
|
1715
|
+
this.stop(clearRecordedDataCB);
|
|
1716
|
+
}
|
|
1717
|
+
clearRecordedDataCB();
|
|
1718
|
+
};
|
|
1719
|
+
function resetVariables() {
|
|
1720
|
+
leftchannel = [];
|
|
1721
|
+
rightchannel = [];
|
|
1722
|
+
recordingLength = 0;
|
|
1723
|
+
isAudioProcessStarted = false;
|
|
1724
|
+
recording = false;
|
|
1725
|
+
isPaused = false;
|
|
1726
|
+
context = null;
|
|
1727
|
+
self2.leftchannel = leftchannel;
|
|
1728
|
+
self2.rightchannel = rightchannel;
|
|
1729
|
+
self2.numberOfAudioChannels = numberOfAudioChannels;
|
|
1730
|
+
self2.desiredSampRate = desiredSampRate;
|
|
1731
|
+
self2.sampleRate = sampleRate;
|
|
1732
|
+
self2.recordingLength = recordingLength;
|
|
1733
|
+
intervalsBasedBuffers = {
|
|
1734
|
+
left: [],
|
|
1735
|
+
right: [],
|
|
1736
|
+
recordingLength: 0
|
|
1737
|
+
};
|
|
1738
|
+
}
|
|
1739
|
+
function clearRecordedDataCB() {
|
|
1740
|
+
if (jsAudioNode) {
|
|
1741
|
+
jsAudioNode.onaudioprocess = null;
|
|
1742
|
+
jsAudioNode.disconnect();
|
|
1743
|
+
jsAudioNode = null;
|
|
1744
|
+
}
|
|
1745
|
+
if (audioInput) {
|
|
1746
|
+
audioInput.disconnect();
|
|
1747
|
+
audioInput = null;
|
|
1748
|
+
}
|
|
1749
|
+
resetVariables();
|
|
1750
|
+
}
|
|
1751
|
+
this.name = "StereoAudioRecorder";
|
|
1752
|
+
this.toString = function() {
|
|
1753
|
+
return this.name;
|
|
1754
|
+
};
|
|
1755
|
+
var isAudioProcessStarted = false;
|
|
1756
|
+
function onAudioProcessDataAvailable(e) {
|
|
1757
|
+
if (isPaused) {
|
|
1758
|
+
return;
|
|
1759
|
+
}
|
|
1760
|
+
if (isMediaStreamActive() === false) {
|
|
1761
|
+
if (!config.disableLogs) {
|
|
1762
|
+
console.log("MediaStream seems stopped.");
|
|
1763
|
+
}
|
|
1764
|
+
jsAudioNode.disconnect();
|
|
1765
|
+
recording = false;
|
|
1766
|
+
}
|
|
1767
|
+
if (!recording) {
|
|
1768
|
+
if (audioInput) {
|
|
1769
|
+
audioInput.disconnect();
|
|
1770
|
+
audioInput = null;
|
|
1771
|
+
}
|
|
1772
|
+
return;
|
|
1773
|
+
}
|
|
1774
|
+
if (!isAudioProcessStarted) {
|
|
1775
|
+
isAudioProcessStarted = true;
|
|
1776
|
+
if (config.onAudioProcessStarted) {
|
|
1777
|
+
config.onAudioProcessStarted();
|
|
1778
|
+
}
|
|
1779
|
+
if (config.initCallback) {
|
|
1780
|
+
config.initCallback();
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1783
|
+
var left = e.inputBuffer.getChannelData(0);
|
|
1784
|
+
var chLeft = new Float32Array(left);
|
|
1785
|
+
leftchannel.push(chLeft);
|
|
1786
|
+
if (numberOfAudioChannels === 2) {
|
|
1787
|
+
var right = e.inputBuffer.getChannelData(1);
|
|
1788
|
+
var chRight = new Float32Array(right);
|
|
1789
|
+
rightchannel.push(chRight);
|
|
1790
|
+
}
|
|
1791
|
+
recordingLength += bufferSize;
|
|
1792
|
+
self2.recordingLength = recordingLength;
|
|
1793
|
+
if (typeof config.timeSlice !== "undefined") {
|
|
1794
|
+
intervalsBasedBuffers.recordingLength += bufferSize;
|
|
1795
|
+
intervalsBasedBuffers.left.push(chLeft);
|
|
1796
|
+
if (numberOfAudioChannels === 2) {
|
|
1797
|
+
intervalsBasedBuffers.right.push(chRight);
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1801
|
+
jsAudioNode.onaudioprocess = onAudioProcessDataAvailable;
|
|
1802
|
+
if (context.createMediaStreamDestination) {
|
|
1803
|
+
jsAudioNode.connect(context.createMediaStreamDestination());
|
|
1804
|
+
} else {
|
|
1805
|
+
jsAudioNode.connect(context.destination);
|
|
1806
|
+
}
|
|
1807
|
+
this.leftchannel = leftchannel;
|
|
1808
|
+
this.rightchannel = rightchannel;
|
|
1809
|
+
this.numberOfAudioChannels = numberOfAudioChannels;
|
|
1810
|
+
this.desiredSampRate = desiredSampRate;
|
|
1811
|
+
this.sampleRate = sampleRate;
|
|
1812
|
+
self2.recordingLength = recordingLength;
|
|
1813
|
+
var intervalsBasedBuffers = {
|
|
1814
|
+
left: [],
|
|
1815
|
+
right: [],
|
|
1816
|
+
recordingLength: 0
|
|
1817
|
+
};
|
|
1818
|
+
function looper() {
|
|
1819
|
+
if (!recording || typeof config.ondataavailable !== "function" || typeof config.timeSlice === "undefined") {
|
|
1820
|
+
return;
|
|
1821
|
+
}
|
|
1822
|
+
if (intervalsBasedBuffers.left.length) {
|
|
1823
|
+
mergeLeftRightBuffers({
|
|
1824
|
+
desiredSampRate,
|
|
1825
|
+
sampleRate,
|
|
1826
|
+
numberOfAudioChannels,
|
|
1827
|
+
internalInterleavedLength: intervalsBasedBuffers.recordingLength,
|
|
1828
|
+
leftBuffers: intervalsBasedBuffers.left,
|
|
1829
|
+
rightBuffers: numberOfAudioChannels === 1 ? [] : intervalsBasedBuffers.right
|
|
1830
|
+
}, function(buffer, view) {
|
|
1831
|
+
var blob = new Blob([view], {
|
|
1832
|
+
type: "audio/wav"
|
|
1833
|
+
});
|
|
1834
|
+
config.ondataavailable(blob);
|
|
1835
|
+
setTimeout(looper, config.timeSlice);
|
|
1836
|
+
});
|
|
1837
|
+
intervalsBasedBuffers = {
|
|
1838
|
+
left: [],
|
|
1839
|
+
right: [],
|
|
1840
|
+
recordingLength: 0
|
|
1841
|
+
};
|
|
1842
|
+
} else {
|
|
1843
|
+
setTimeout(looper, config.timeSlice);
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
if (typeof RecordRTC !== "undefined") {
|
|
1848
|
+
RecordRTC.StereoAudioRecorder = StereoAudioRecorder;
|
|
1849
|
+
}
|
|
1850
|
+
function CanvasRecorder(htmlElement, config) {
|
|
1851
|
+
if (typeof html2canvas === "undefined") {
|
|
1852
|
+
throw "Please link: https://www.webrtc-experiment.com/screenshot.js";
|
|
1853
|
+
}
|
|
1854
|
+
config = config || {};
|
|
1855
|
+
if (!config.frameInterval) {
|
|
1856
|
+
config.frameInterval = 10;
|
|
1857
|
+
}
|
|
1858
|
+
var isCanvasSupportsStreamCapturing = false;
|
|
1859
|
+
["captureStream", "mozCaptureStream", "webkitCaptureStream"].forEach(function(item) {
|
|
1860
|
+
if (item in document.createElement("canvas")) {
|
|
1861
|
+
isCanvasSupportsStreamCapturing = true;
|
|
1862
|
+
}
|
|
1863
|
+
});
|
|
1864
|
+
var _isChrome = (!!window.webkitRTCPeerConnection || !!window.webkitGetUserMedia) && !!window.chrome;
|
|
1865
|
+
var chromeVersion = 50;
|
|
1866
|
+
var matchArray = navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./);
|
|
1867
|
+
if (_isChrome && matchArray && matchArray[2]) {
|
|
1868
|
+
chromeVersion = parseInt(matchArray[2], 10);
|
|
1869
|
+
}
|
|
1870
|
+
if (_isChrome && chromeVersion < 52) {
|
|
1871
|
+
isCanvasSupportsStreamCapturing = false;
|
|
1872
|
+
}
|
|
1873
|
+
if (config.useWhammyRecorder) {
|
|
1874
|
+
isCanvasSupportsStreamCapturing = false;
|
|
1875
|
+
}
|
|
1876
|
+
var globalCanvas, mediaStreamRecorder;
|
|
1877
|
+
if (isCanvasSupportsStreamCapturing) {
|
|
1878
|
+
if (!config.disableLogs) {
|
|
1879
|
+
console.log("Your browser supports both MediRecorder API and canvas.captureStream!");
|
|
1880
|
+
}
|
|
1881
|
+
if (htmlElement instanceof HTMLCanvasElement) {
|
|
1882
|
+
globalCanvas = htmlElement;
|
|
1883
|
+
} else if (htmlElement instanceof CanvasRenderingContext2D) {
|
|
1884
|
+
globalCanvas = htmlElement.canvas;
|
|
1885
|
+
} else {
|
|
1886
|
+
throw "Please pass either HTMLCanvasElement or CanvasRenderingContext2D.";
|
|
1887
|
+
}
|
|
1888
|
+
} else if (!!navigator.mozGetUserMedia) {
|
|
1889
|
+
if (!config.disableLogs) {
|
|
1890
|
+
console.error("Canvas recording is NOT supported in Firefox.");
|
|
1891
|
+
}
|
|
1892
|
+
}
|
|
1893
|
+
var isRecording;
|
|
1894
|
+
this.record = function() {
|
|
1895
|
+
isRecording = true;
|
|
1896
|
+
if (isCanvasSupportsStreamCapturing && !config.useWhammyRecorder) {
|
|
1897
|
+
var canvasMediaStream;
|
|
1898
|
+
if ("captureStream" in globalCanvas) {
|
|
1899
|
+
canvasMediaStream = globalCanvas.captureStream(25);
|
|
1900
|
+
} else if ("mozCaptureStream" in globalCanvas) {
|
|
1901
|
+
canvasMediaStream = globalCanvas.mozCaptureStream(25);
|
|
1902
|
+
} else if ("webkitCaptureStream" in globalCanvas) {
|
|
1903
|
+
canvasMediaStream = globalCanvas.webkitCaptureStream(25);
|
|
1904
|
+
}
|
|
1905
|
+
try {
|
|
1906
|
+
var mdStream = new MediaStream();
|
|
1907
|
+
mdStream.addTrack(getTracks(canvasMediaStream, "video")[0]);
|
|
1908
|
+
canvasMediaStream = mdStream;
|
|
1909
|
+
} catch (e) {
|
|
1910
|
+
}
|
|
1911
|
+
if (!canvasMediaStream) {
|
|
1912
|
+
throw "captureStream API are NOT available.";
|
|
1913
|
+
}
|
|
1914
|
+
mediaStreamRecorder = new MediaStreamRecorder(canvasMediaStream, {
|
|
1915
|
+
mimeType: config.mimeType || "video/webm"
|
|
1916
|
+
});
|
|
1917
|
+
mediaStreamRecorder.record();
|
|
1918
|
+
} else {
|
|
1919
|
+
whammy.frames = [];
|
|
1920
|
+
lastTime2 = new Date().getTime();
|
|
1921
|
+
drawCanvasFrame();
|
|
1922
|
+
}
|
|
1923
|
+
if (config.initCallback) {
|
|
1924
|
+
config.initCallback();
|
|
1925
|
+
}
|
|
1926
|
+
};
|
|
1927
|
+
this.getWebPImages = function(callback) {
|
|
1928
|
+
if (htmlElement.nodeName.toLowerCase() !== "canvas") {
|
|
1929
|
+
callback();
|
|
1930
|
+
return;
|
|
1931
|
+
}
|
|
1932
|
+
var framesLength = whammy.frames.length;
|
|
1933
|
+
whammy.frames.forEach(function(frame, idx) {
|
|
1934
|
+
var framesRemaining = framesLength - idx;
|
|
1935
|
+
if (!config.disableLogs) {
|
|
1936
|
+
console.log(framesRemaining + "/" + framesLength + " frames remaining");
|
|
1937
|
+
}
|
|
1938
|
+
if (config.onEncodingCallback) {
|
|
1939
|
+
config.onEncodingCallback(framesRemaining, framesLength);
|
|
1940
|
+
}
|
|
1941
|
+
var webp = frame.image.toDataURL("image/webp", 1);
|
|
1942
|
+
whammy.frames[idx].image = webp;
|
|
1943
|
+
});
|
|
1944
|
+
if (!config.disableLogs) {
|
|
1945
|
+
console.log("Generating WebM");
|
|
1946
|
+
}
|
|
1947
|
+
callback();
|
|
1948
|
+
};
|
|
1949
|
+
this.stop = function(callback) {
|
|
1950
|
+
isRecording = false;
|
|
1951
|
+
var that = this;
|
|
1952
|
+
if (isCanvasSupportsStreamCapturing && mediaStreamRecorder) {
|
|
1953
|
+
mediaStreamRecorder.stop(callback);
|
|
1954
|
+
return;
|
|
1955
|
+
}
|
|
1956
|
+
this.getWebPImages(function() {
|
|
1957
|
+
whammy.compile(function(blob) {
|
|
1958
|
+
if (!config.disableLogs) {
|
|
1959
|
+
console.log("Recording finished!");
|
|
1960
|
+
}
|
|
1961
|
+
that.blob = blob;
|
|
1962
|
+
if (that.blob.forEach) {
|
|
1963
|
+
that.blob = new Blob([], {
|
|
1964
|
+
type: "video/webm"
|
|
1965
|
+
});
|
|
1966
|
+
}
|
|
1967
|
+
if (callback) {
|
|
1968
|
+
callback(that.blob);
|
|
1969
|
+
}
|
|
1970
|
+
whammy.frames = [];
|
|
1971
|
+
});
|
|
1972
|
+
});
|
|
1973
|
+
};
|
|
1974
|
+
var isPausedRecording = false;
|
|
1975
|
+
this.pause = function() {
|
|
1976
|
+
isPausedRecording = true;
|
|
1977
|
+
if (mediaStreamRecorder instanceof MediaStreamRecorder) {
|
|
1978
|
+
mediaStreamRecorder.pause();
|
|
1979
|
+
return;
|
|
1980
|
+
}
|
|
1981
|
+
};
|
|
1982
|
+
this.resume = function() {
|
|
1983
|
+
isPausedRecording = false;
|
|
1984
|
+
if (mediaStreamRecorder instanceof MediaStreamRecorder) {
|
|
1985
|
+
mediaStreamRecorder.resume();
|
|
1986
|
+
return;
|
|
1987
|
+
}
|
|
1988
|
+
if (!isRecording) {
|
|
1989
|
+
this.record();
|
|
1990
|
+
}
|
|
1991
|
+
};
|
|
1992
|
+
this.clearRecordedData = function() {
|
|
1993
|
+
if (isRecording) {
|
|
1994
|
+
this.stop(clearRecordedDataCB);
|
|
1995
|
+
}
|
|
1996
|
+
clearRecordedDataCB();
|
|
1997
|
+
};
|
|
1998
|
+
function clearRecordedDataCB() {
|
|
1999
|
+
whammy.frames = [];
|
|
2000
|
+
isRecording = false;
|
|
2001
|
+
isPausedRecording = false;
|
|
2002
|
+
}
|
|
2003
|
+
this.name = "CanvasRecorder";
|
|
2004
|
+
this.toString = function() {
|
|
2005
|
+
return this.name;
|
|
2006
|
+
};
|
|
2007
|
+
function cloneCanvas() {
|
|
2008
|
+
var newCanvas = document.createElement("canvas");
|
|
2009
|
+
var context = newCanvas.getContext("2d");
|
|
2010
|
+
newCanvas.width = htmlElement.width;
|
|
2011
|
+
newCanvas.height = htmlElement.height;
|
|
2012
|
+
context.drawImage(htmlElement, 0, 0);
|
|
2013
|
+
return newCanvas;
|
|
2014
|
+
}
|
|
2015
|
+
function drawCanvasFrame() {
|
|
2016
|
+
if (isPausedRecording) {
|
|
2017
|
+
lastTime2 = new Date().getTime();
|
|
2018
|
+
return setTimeout(drawCanvasFrame, 500);
|
|
2019
|
+
}
|
|
2020
|
+
if (htmlElement.nodeName.toLowerCase() === "canvas") {
|
|
2021
|
+
var duration = new Date().getTime() - lastTime2;
|
|
2022
|
+
lastTime2 = new Date().getTime();
|
|
2023
|
+
whammy.frames.push({
|
|
2024
|
+
image: cloneCanvas(),
|
|
2025
|
+
duration
|
|
2026
|
+
});
|
|
2027
|
+
if (isRecording) {
|
|
2028
|
+
setTimeout(drawCanvasFrame, config.frameInterval);
|
|
2029
|
+
}
|
|
2030
|
+
return;
|
|
2031
|
+
}
|
|
2032
|
+
html2canvas(htmlElement, {
|
|
2033
|
+
grabMouse: typeof config.showMousePointer === "undefined" || config.showMousePointer,
|
|
2034
|
+
onrendered: function(canvas) {
|
|
2035
|
+
var duration2 = new Date().getTime() - lastTime2;
|
|
2036
|
+
if (!duration2) {
|
|
2037
|
+
return setTimeout(drawCanvasFrame, config.frameInterval);
|
|
2038
|
+
}
|
|
2039
|
+
lastTime2 = new Date().getTime();
|
|
2040
|
+
whammy.frames.push({
|
|
2041
|
+
image: canvas.toDataURL("image/webp", 1),
|
|
2042
|
+
duration: duration2
|
|
2043
|
+
});
|
|
2044
|
+
if (isRecording) {
|
|
2045
|
+
setTimeout(drawCanvasFrame, config.frameInterval);
|
|
2046
|
+
}
|
|
2047
|
+
}
|
|
2048
|
+
});
|
|
2049
|
+
}
|
|
2050
|
+
var lastTime2 = new Date().getTime();
|
|
2051
|
+
var whammy = new Whammy.Video(100);
|
|
2052
|
+
}
|
|
2053
|
+
if (typeof RecordRTC !== "undefined") {
|
|
2054
|
+
RecordRTC.CanvasRecorder = CanvasRecorder;
|
|
2055
|
+
}
|
|
2056
|
+
function WhammyRecorder(mediaStream, config) {
|
|
2057
|
+
config = config || {};
|
|
2058
|
+
if (!config.frameInterval) {
|
|
2059
|
+
config.frameInterval = 10;
|
|
2060
|
+
}
|
|
2061
|
+
if (!config.disableLogs) {
|
|
2062
|
+
console.log("Using frames-interval:", config.frameInterval);
|
|
2063
|
+
}
|
|
2064
|
+
this.record = function() {
|
|
2065
|
+
if (!config.width) {
|
|
2066
|
+
config.width = 320;
|
|
2067
|
+
}
|
|
2068
|
+
if (!config.height) {
|
|
2069
|
+
config.height = 240;
|
|
2070
|
+
}
|
|
2071
|
+
if (!config.video) {
|
|
2072
|
+
config.video = {
|
|
2073
|
+
width: config.width,
|
|
2074
|
+
height: config.height
|
|
2075
|
+
};
|
|
2076
|
+
}
|
|
2077
|
+
if (!config.canvas) {
|
|
2078
|
+
config.canvas = {
|
|
2079
|
+
width: config.width,
|
|
2080
|
+
height: config.height
|
|
2081
|
+
};
|
|
2082
|
+
}
|
|
2083
|
+
canvas.width = config.canvas.width || 320;
|
|
2084
|
+
canvas.height = config.canvas.height || 240;
|
|
2085
|
+
context = canvas.getContext("2d");
|
|
2086
|
+
if (config.video && config.video instanceof HTMLVideoElement) {
|
|
2087
|
+
video = config.video.cloneNode();
|
|
2088
|
+
if (config.initCallback) {
|
|
2089
|
+
config.initCallback();
|
|
2090
|
+
}
|
|
2091
|
+
} else {
|
|
2092
|
+
video = document.createElement("video");
|
|
2093
|
+
setSrcObject(mediaStream, video);
|
|
2094
|
+
video.onloadedmetadata = function() {
|
|
2095
|
+
if (config.initCallback) {
|
|
2096
|
+
config.initCallback();
|
|
2097
|
+
}
|
|
2098
|
+
};
|
|
2099
|
+
video.width = config.video.width;
|
|
2100
|
+
video.height = config.video.height;
|
|
2101
|
+
}
|
|
2102
|
+
video.muted = true;
|
|
2103
|
+
video.play();
|
|
2104
|
+
lastTime2 = new Date().getTime();
|
|
2105
|
+
whammy = new Whammy.Video();
|
|
2106
|
+
if (!config.disableLogs) {
|
|
2107
|
+
console.log("canvas resolutions", canvas.width, "*", canvas.height);
|
|
2108
|
+
console.log("video width/height", video.width || canvas.width, "*", video.height || canvas.height);
|
|
2109
|
+
}
|
|
2110
|
+
drawFrames(config.frameInterval);
|
|
2111
|
+
};
|
|
2112
|
+
function drawFrames(frameInterval) {
|
|
2113
|
+
frameInterval = typeof frameInterval !== "undefined" ? frameInterval : 10;
|
|
2114
|
+
var duration = new Date().getTime() - lastTime2;
|
|
2115
|
+
if (!duration) {
|
|
2116
|
+
return setTimeout(drawFrames, frameInterval, frameInterval);
|
|
2117
|
+
}
|
|
2118
|
+
if (isPausedRecording) {
|
|
2119
|
+
lastTime2 = new Date().getTime();
|
|
2120
|
+
return setTimeout(drawFrames, 100);
|
|
2121
|
+
}
|
|
2122
|
+
lastTime2 = new Date().getTime();
|
|
2123
|
+
if (video.paused) {
|
|
2124
|
+
video.play();
|
|
2125
|
+
}
|
|
2126
|
+
context.drawImage(video, 0, 0, canvas.width, canvas.height);
|
|
2127
|
+
whammy.frames.push({
|
|
2128
|
+
duration,
|
|
2129
|
+
image: canvas.toDataURL("image/webp")
|
|
2130
|
+
});
|
|
2131
|
+
if (!isStopDrawing) {
|
|
2132
|
+
setTimeout(drawFrames, frameInterval, frameInterval);
|
|
2133
|
+
}
|
|
2134
|
+
}
|
|
2135
|
+
function asyncLoop(o) {
|
|
2136
|
+
var i = -1, length = o.length;
|
|
2137
|
+
(function loop() {
|
|
2138
|
+
i++;
|
|
2139
|
+
if (i === length) {
|
|
2140
|
+
o.callback();
|
|
2141
|
+
return;
|
|
2142
|
+
}
|
|
2143
|
+
setTimeout(function() {
|
|
2144
|
+
o.functionToLoop(loop, i);
|
|
2145
|
+
}, 1);
|
|
2146
|
+
})();
|
|
2147
|
+
}
|
|
2148
|
+
function dropBlackFrames(_frames, _framesToCheck, _pixTolerance, _frameTolerance, callback) {
|
|
2149
|
+
var localCanvas = document.createElement("canvas");
|
|
2150
|
+
localCanvas.width = canvas.width;
|
|
2151
|
+
localCanvas.height = canvas.height;
|
|
2152
|
+
var context2d = localCanvas.getContext("2d");
|
|
2153
|
+
var resultFrames = [];
|
|
2154
|
+
var checkUntilNotBlack = _framesToCheck === -1;
|
|
2155
|
+
var endCheckFrame = _framesToCheck && _framesToCheck > 0 && _framesToCheck <= _frames.length ? _framesToCheck : _frames.length;
|
|
2156
|
+
var sampleColor = {
|
|
2157
|
+
r: 0,
|
|
2158
|
+
g: 0,
|
|
2159
|
+
b: 0
|
|
2160
|
+
};
|
|
2161
|
+
var maxColorDifference = Math.sqrt(Math.pow(255, 2) + Math.pow(255, 2) + Math.pow(255, 2));
|
|
2162
|
+
var pixTolerance = _pixTolerance && _pixTolerance >= 0 && _pixTolerance <= 1 ? _pixTolerance : 0;
|
|
2163
|
+
var frameTolerance = _frameTolerance && _frameTolerance >= 0 && _frameTolerance <= 1 ? _frameTolerance : 0;
|
|
2164
|
+
var doNotCheckNext = false;
|
|
2165
|
+
asyncLoop({
|
|
2166
|
+
length: endCheckFrame,
|
|
2167
|
+
functionToLoop: function(loop, f) {
|
|
2168
|
+
var matchPixCount, endPixCheck, maxPixCount;
|
|
2169
|
+
var finishImage = function() {
|
|
2170
|
+
if (!doNotCheckNext && maxPixCount - matchPixCount <= maxPixCount * frameTolerance) {
|
|
2171
|
+
} else {
|
|
2172
|
+
if (checkUntilNotBlack) {
|
|
2173
|
+
doNotCheckNext = true;
|
|
2174
|
+
}
|
|
2175
|
+
resultFrames.push(_frames[f]);
|
|
2176
|
+
}
|
|
2177
|
+
loop();
|
|
2178
|
+
};
|
|
2179
|
+
if (!doNotCheckNext) {
|
|
2180
|
+
var image = new Image();
|
|
2181
|
+
image.onload = function() {
|
|
2182
|
+
context2d.drawImage(image, 0, 0, canvas.width, canvas.height);
|
|
2183
|
+
var imageData = context2d.getImageData(0, 0, canvas.width, canvas.height);
|
|
2184
|
+
matchPixCount = 0;
|
|
2185
|
+
endPixCheck = imageData.data.length;
|
|
2186
|
+
maxPixCount = imageData.data.length / 4;
|
|
2187
|
+
for (var pix = 0; pix < endPixCheck; pix += 4) {
|
|
2188
|
+
var currentColor = {
|
|
2189
|
+
r: imageData.data[pix],
|
|
2190
|
+
g: imageData.data[pix + 1],
|
|
2191
|
+
b: imageData.data[pix + 2]
|
|
2192
|
+
};
|
|
2193
|
+
var colorDifference = Math.sqrt(Math.pow(currentColor.r - sampleColor.r, 2) + Math.pow(currentColor.g - sampleColor.g, 2) + Math.pow(currentColor.b - sampleColor.b, 2));
|
|
2194
|
+
if (colorDifference <= maxColorDifference * pixTolerance) {
|
|
2195
|
+
matchPixCount++;
|
|
2196
|
+
}
|
|
2197
|
+
}
|
|
2198
|
+
finishImage();
|
|
2199
|
+
};
|
|
2200
|
+
image.src = _frames[f].image;
|
|
2201
|
+
} else {
|
|
2202
|
+
finishImage();
|
|
2203
|
+
}
|
|
2204
|
+
},
|
|
2205
|
+
callback: function() {
|
|
2206
|
+
resultFrames = resultFrames.concat(_frames.slice(endCheckFrame));
|
|
2207
|
+
if (resultFrames.length <= 0) {
|
|
2208
|
+
resultFrames.push(_frames[_frames.length - 1]);
|
|
2209
|
+
}
|
|
2210
|
+
callback(resultFrames);
|
|
2211
|
+
}
|
|
2212
|
+
});
|
|
2213
|
+
}
|
|
2214
|
+
var isStopDrawing = false;
|
|
2215
|
+
this.stop = function(callback) {
|
|
2216
|
+
callback = callback || function() {
|
|
2217
|
+
};
|
|
2218
|
+
isStopDrawing = true;
|
|
2219
|
+
var _this = this;
|
|
2220
|
+
setTimeout(function() {
|
|
2221
|
+
dropBlackFrames(whammy.frames, -1, null, null, function(frames) {
|
|
2222
|
+
whammy.frames = frames;
|
|
2223
|
+
if (config.advertisement && config.advertisement.length) {
|
|
2224
|
+
whammy.frames = config.advertisement.concat(whammy.frames);
|
|
2225
|
+
}
|
|
2226
|
+
whammy.compile(function(blob) {
|
|
2227
|
+
_this.blob = blob;
|
|
2228
|
+
if (_this.blob.forEach) {
|
|
2229
|
+
_this.blob = new Blob([], {
|
|
2230
|
+
type: "video/webm"
|
|
2231
|
+
});
|
|
2232
|
+
}
|
|
2233
|
+
if (callback) {
|
|
2234
|
+
callback(_this.blob);
|
|
2235
|
+
}
|
|
2236
|
+
});
|
|
2237
|
+
});
|
|
2238
|
+
}, 10);
|
|
2239
|
+
};
|
|
2240
|
+
var isPausedRecording = false;
|
|
2241
|
+
this.pause = function() {
|
|
2242
|
+
isPausedRecording = true;
|
|
2243
|
+
};
|
|
2244
|
+
this.resume = function() {
|
|
2245
|
+
isPausedRecording = false;
|
|
2246
|
+
if (isStopDrawing) {
|
|
2247
|
+
this.record();
|
|
2248
|
+
}
|
|
2249
|
+
};
|
|
2250
|
+
this.clearRecordedData = function() {
|
|
2251
|
+
if (!isStopDrawing) {
|
|
2252
|
+
this.stop(clearRecordedDataCB);
|
|
2253
|
+
}
|
|
2254
|
+
clearRecordedDataCB();
|
|
2255
|
+
};
|
|
2256
|
+
function clearRecordedDataCB() {
|
|
2257
|
+
whammy.frames = [];
|
|
2258
|
+
isStopDrawing = true;
|
|
2259
|
+
isPausedRecording = false;
|
|
2260
|
+
}
|
|
2261
|
+
this.name = "WhammyRecorder";
|
|
2262
|
+
this.toString = function() {
|
|
2263
|
+
return this.name;
|
|
2264
|
+
};
|
|
2265
|
+
var canvas = document.createElement("canvas");
|
|
2266
|
+
var context = canvas.getContext("2d");
|
|
2267
|
+
var video;
|
|
2268
|
+
var lastTime2;
|
|
2269
|
+
var whammy;
|
|
2270
|
+
}
|
|
2271
|
+
if (typeof RecordRTC !== "undefined") {
|
|
2272
|
+
RecordRTC.WhammyRecorder = WhammyRecorder;
|
|
2273
|
+
}
|
|
2274
|
+
var Whammy = function() {
|
|
2275
|
+
function WhammyVideo(duration) {
|
|
2276
|
+
this.frames = [];
|
|
2277
|
+
this.duration = duration || 1;
|
|
2278
|
+
this.quality = 0.8;
|
|
2279
|
+
}
|
|
2280
|
+
WhammyVideo.prototype.add = function(frame, duration) {
|
|
2281
|
+
if ("canvas" in frame) {
|
|
2282
|
+
frame = frame.canvas;
|
|
2283
|
+
}
|
|
2284
|
+
if ("toDataURL" in frame) {
|
|
2285
|
+
frame = frame.toDataURL("image/webp", this.quality);
|
|
2286
|
+
}
|
|
2287
|
+
if (!/^data:image\/webp;base64,/ig.test(frame)) {
|
|
2288
|
+
throw "Input must be formatted properly as a base64 encoded DataURI of type image/webp";
|
|
2289
|
+
}
|
|
2290
|
+
this.frames.push({
|
|
2291
|
+
image: frame,
|
|
2292
|
+
duration: duration || this.duration
|
|
2293
|
+
});
|
|
2294
|
+
};
|
|
2295
|
+
function processInWebWorker(_function) {
|
|
2296
|
+
var blob = URL2.createObjectURL(new Blob([
|
|
2297
|
+
_function.toString(),
|
|
2298
|
+
"this.onmessage = function (eee) {" + _function.name + "(eee.data);}"
|
|
2299
|
+
], {
|
|
2300
|
+
type: "application/javascript"
|
|
2301
|
+
}));
|
|
2302
|
+
var worker = new Worker(blob);
|
|
2303
|
+
URL2.revokeObjectURL(blob);
|
|
2304
|
+
return worker;
|
|
2305
|
+
}
|
|
2306
|
+
function whammyInWebWorker(frames) {
|
|
2307
|
+
function ArrayToWebM(frames2) {
|
|
2308
|
+
var info = checkFrames(frames2);
|
|
2309
|
+
if (!info) {
|
|
2310
|
+
return [];
|
|
2311
|
+
}
|
|
2312
|
+
var clusterMaxDuration = 3e4;
|
|
2313
|
+
var EBML2 = [{
|
|
2314
|
+
"id": 440786851,
|
|
2315
|
+
"data": [{
|
|
2316
|
+
"data": 1,
|
|
2317
|
+
"id": 17030
|
|
2318
|
+
}, {
|
|
2319
|
+
"data": 1,
|
|
2320
|
+
"id": 17143
|
|
2321
|
+
}, {
|
|
2322
|
+
"data": 4,
|
|
2323
|
+
"id": 17138
|
|
2324
|
+
}, {
|
|
2325
|
+
"data": 8,
|
|
2326
|
+
"id": 17139
|
|
2327
|
+
}, {
|
|
2328
|
+
"data": "webm",
|
|
2329
|
+
"id": 17026
|
|
2330
|
+
}, {
|
|
2331
|
+
"data": 2,
|
|
2332
|
+
"id": 17031
|
|
2333
|
+
}, {
|
|
2334
|
+
"data": 2,
|
|
2335
|
+
"id": 17029
|
|
2336
|
+
}]
|
|
2337
|
+
}, {
|
|
2338
|
+
"id": 408125543,
|
|
2339
|
+
"data": [{
|
|
2340
|
+
"id": 357149030,
|
|
2341
|
+
"data": [{
|
|
2342
|
+
"data": 1e6,
|
|
2343
|
+
"id": 2807729
|
|
2344
|
+
}, {
|
|
2345
|
+
"data": "whammy",
|
|
2346
|
+
"id": 19840
|
|
2347
|
+
}, {
|
|
2348
|
+
"data": "whammy",
|
|
2349
|
+
"id": 22337
|
|
2350
|
+
}, {
|
|
2351
|
+
"data": doubleToString(info.duration),
|
|
2352
|
+
"id": 17545
|
|
2353
|
+
}]
|
|
2354
|
+
}, {
|
|
2355
|
+
"id": 374648427,
|
|
2356
|
+
"data": [{
|
|
2357
|
+
"id": 174,
|
|
2358
|
+
"data": [{
|
|
2359
|
+
"data": 1,
|
|
2360
|
+
"id": 215
|
|
2361
|
+
}, {
|
|
2362
|
+
"data": 1,
|
|
2363
|
+
"id": 29637
|
|
2364
|
+
}, {
|
|
2365
|
+
"data": 0,
|
|
2366
|
+
"id": 156
|
|
2367
|
+
}, {
|
|
2368
|
+
"data": "und",
|
|
2369
|
+
"id": 2274716
|
|
2370
|
+
}, {
|
|
2371
|
+
"data": "V_VP8",
|
|
2372
|
+
"id": 134
|
|
2373
|
+
}, {
|
|
2374
|
+
"data": "VP8",
|
|
2375
|
+
"id": 2459272
|
|
2376
|
+
}, {
|
|
2377
|
+
"data": 1,
|
|
2378
|
+
"id": 131
|
|
2379
|
+
}, {
|
|
2380
|
+
"id": 224,
|
|
2381
|
+
"data": [{
|
|
2382
|
+
"data": info.width,
|
|
2383
|
+
"id": 176
|
|
2384
|
+
}, {
|
|
2385
|
+
"data": info.height,
|
|
2386
|
+
"id": 186
|
|
2387
|
+
}]
|
|
2388
|
+
}]
|
|
2389
|
+
}]
|
|
2390
|
+
}]
|
|
2391
|
+
}];
|
|
2392
|
+
var frameNumber = 0;
|
|
2393
|
+
var clusterTimecode = 0;
|
|
2394
|
+
while (frameNumber < frames2.length) {
|
|
2395
|
+
var clusterFrames = [];
|
|
2396
|
+
var clusterDuration = 0;
|
|
2397
|
+
do {
|
|
2398
|
+
clusterFrames.push(frames2[frameNumber]);
|
|
2399
|
+
clusterDuration += frames2[frameNumber].duration;
|
|
2400
|
+
frameNumber++;
|
|
2401
|
+
} while (frameNumber < frames2.length && clusterDuration < clusterMaxDuration);
|
|
2402
|
+
var clusterCounter = 0;
|
|
2403
|
+
var cluster = {
|
|
2404
|
+
"id": 524531317,
|
|
2405
|
+
"data": getClusterData(clusterTimecode, clusterCounter, clusterFrames)
|
|
2406
|
+
};
|
|
2407
|
+
EBML2[1].data.push(cluster);
|
|
2408
|
+
clusterTimecode += clusterDuration;
|
|
2409
|
+
}
|
|
2410
|
+
return generateEBML(EBML2);
|
|
2411
|
+
}
|
|
2412
|
+
function getClusterData(clusterTimecode, clusterCounter, clusterFrames) {
|
|
2413
|
+
return [{
|
|
2414
|
+
"data": clusterTimecode,
|
|
2415
|
+
"id": 231
|
|
2416
|
+
}].concat(clusterFrames.map(function(webp) {
|
|
2417
|
+
var block = makeSimpleBlock({
|
|
2418
|
+
discardable: 0,
|
|
2419
|
+
frame: webp.data.slice(4),
|
|
2420
|
+
invisible: 0,
|
|
2421
|
+
keyframe: 1,
|
|
2422
|
+
lacing: 0,
|
|
2423
|
+
trackNum: 1,
|
|
2424
|
+
timecode: Math.round(clusterCounter)
|
|
2425
|
+
});
|
|
2426
|
+
clusterCounter += webp.duration;
|
|
2427
|
+
return {
|
|
2428
|
+
data: block,
|
|
2429
|
+
id: 163
|
|
2430
|
+
};
|
|
2431
|
+
}));
|
|
2432
|
+
}
|
|
2433
|
+
function checkFrames(frames2) {
|
|
2434
|
+
if (!frames2[0]) {
|
|
2435
|
+
postMessage({
|
|
2436
|
+
error: "Something went wrong. Maybe WebP format is not supported in the current browser."
|
|
2437
|
+
});
|
|
2438
|
+
return;
|
|
2439
|
+
}
|
|
2440
|
+
var width = frames2[0].width, height = frames2[0].height, duration = frames2[0].duration;
|
|
2441
|
+
for (var i = 1; i < frames2.length; i++) {
|
|
2442
|
+
duration += frames2[i].duration;
|
|
2443
|
+
}
|
|
2444
|
+
return {
|
|
2445
|
+
duration,
|
|
2446
|
+
width,
|
|
2447
|
+
height
|
|
2448
|
+
};
|
|
2449
|
+
}
|
|
2450
|
+
function numToBuffer(num) {
|
|
2451
|
+
var parts = [];
|
|
2452
|
+
while (num > 0) {
|
|
2453
|
+
parts.push(num & 255);
|
|
2454
|
+
num = num >> 8;
|
|
2455
|
+
}
|
|
2456
|
+
return new Uint8Array(parts.reverse());
|
|
2457
|
+
}
|
|
2458
|
+
function strToBuffer(str) {
|
|
2459
|
+
return new Uint8Array(str.split("").map(function(e) {
|
|
2460
|
+
return e.charCodeAt(0);
|
|
2461
|
+
}));
|
|
2462
|
+
}
|
|
2463
|
+
function bitsToBuffer(bits) {
|
|
2464
|
+
var data = [];
|
|
2465
|
+
var pad = bits.length % 8 ? new Array(1 + 8 - bits.length % 8).join("0") : "";
|
|
2466
|
+
bits = pad + bits;
|
|
2467
|
+
for (var i = 0; i < bits.length; i += 8) {
|
|
2468
|
+
data.push(parseInt(bits.substr(i, 8), 2));
|
|
2469
|
+
}
|
|
2470
|
+
return new Uint8Array(data);
|
|
2471
|
+
}
|
|
2472
|
+
function generateEBML(json) {
|
|
2473
|
+
var ebml = [];
|
|
2474
|
+
for (var i = 0; i < json.length; i++) {
|
|
2475
|
+
var data = json[i].data;
|
|
2476
|
+
if (typeof data === "object") {
|
|
2477
|
+
data = generateEBML(data);
|
|
2478
|
+
}
|
|
2479
|
+
if (typeof data === "number") {
|
|
2480
|
+
data = bitsToBuffer(data.toString(2));
|
|
2481
|
+
}
|
|
2482
|
+
if (typeof data === "string") {
|
|
2483
|
+
data = strToBuffer(data);
|
|
2484
|
+
}
|
|
2485
|
+
var len = data.size || data.byteLength || data.length;
|
|
2486
|
+
var zeroes = Math.ceil(Math.ceil(Math.log(len) / Math.log(2)) / 8);
|
|
2487
|
+
var sizeToString = len.toString(2);
|
|
2488
|
+
var padded = new Array(zeroes * 7 + 7 + 1 - sizeToString.length).join("0") + sizeToString;
|
|
2489
|
+
var size = new Array(zeroes).join("0") + "1" + padded;
|
|
2490
|
+
ebml.push(numToBuffer(json[i].id));
|
|
2491
|
+
ebml.push(bitsToBuffer(size));
|
|
2492
|
+
ebml.push(data);
|
|
2493
|
+
}
|
|
2494
|
+
return new Blob(ebml, {
|
|
2495
|
+
type: "video/webm"
|
|
2496
|
+
});
|
|
2497
|
+
}
|
|
2498
|
+
function toBinStrOld(bits) {
|
|
2499
|
+
var data = "";
|
|
2500
|
+
var pad = bits.length % 8 ? new Array(1 + 8 - bits.length % 8).join("0") : "";
|
|
2501
|
+
bits = pad + bits;
|
|
2502
|
+
for (var i = 0; i < bits.length; i += 8) {
|
|
2503
|
+
data += String.fromCharCode(parseInt(bits.substr(i, 8), 2));
|
|
2504
|
+
}
|
|
2505
|
+
return data;
|
|
2506
|
+
}
|
|
2507
|
+
function makeSimpleBlock(data) {
|
|
2508
|
+
var flags = 0;
|
|
2509
|
+
if (data.keyframe) {
|
|
2510
|
+
flags |= 128;
|
|
2511
|
+
}
|
|
2512
|
+
if (data.invisible) {
|
|
2513
|
+
flags |= 8;
|
|
2514
|
+
}
|
|
2515
|
+
if (data.lacing) {
|
|
2516
|
+
flags |= data.lacing << 1;
|
|
2517
|
+
}
|
|
2518
|
+
if (data.discardable) {
|
|
2519
|
+
flags |= 1;
|
|
2520
|
+
}
|
|
2521
|
+
if (data.trackNum > 127) {
|
|
2522
|
+
throw "TrackNumber > 127 not supported";
|
|
2523
|
+
}
|
|
2524
|
+
var out = [data.trackNum | 128, data.timecode >> 8, data.timecode & 255, flags].map(function(e) {
|
|
2525
|
+
return String.fromCharCode(e);
|
|
2526
|
+
}).join("") + data.frame;
|
|
2527
|
+
return out;
|
|
2528
|
+
}
|
|
2529
|
+
function parseWebP(riff) {
|
|
2530
|
+
var VP8 = riff.RIFF[0].WEBP[0];
|
|
2531
|
+
var frameStart = VP8.indexOf("\x9D*");
|
|
2532
|
+
for (var i = 0, c = []; i < 4; i++) {
|
|
2533
|
+
c[i] = VP8.charCodeAt(frameStart + 3 + i);
|
|
2534
|
+
}
|
|
2535
|
+
var width, height, tmp;
|
|
2536
|
+
tmp = c[1] << 8 | c[0];
|
|
2537
|
+
width = tmp & 16383;
|
|
2538
|
+
tmp = c[3] << 8 | c[2];
|
|
2539
|
+
height = tmp & 16383;
|
|
2540
|
+
return {
|
|
2541
|
+
width,
|
|
2542
|
+
height,
|
|
2543
|
+
data: VP8,
|
|
2544
|
+
riff
|
|
2545
|
+
};
|
|
2546
|
+
}
|
|
2547
|
+
function getStrLength(string, offset) {
|
|
2548
|
+
return parseInt(string.substr(offset + 4, 4).split("").map(function(i) {
|
|
2549
|
+
var unpadded = i.charCodeAt(0).toString(2);
|
|
2550
|
+
return new Array(8 - unpadded.length + 1).join("0") + unpadded;
|
|
2551
|
+
}).join(""), 2);
|
|
2552
|
+
}
|
|
2553
|
+
function parseRIFF(string) {
|
|
2554
|
+
var offset = 0;
|
|
2555
|
+
var chunks = {};
|
|
2556
|
+
while (offset < string.length) {
|
|
2557
|
+
var id = string.substr(offset, 4);
|
|
2558
|
+
var len = getStrLength(string, offset);
|
|
2559
|
+
var data = string.substr(offset + 4 + 4, len);
|
|
2560
|
+
offset += 4 + 4 + len;
|
|
2561
|
+
chunks[id] = chunks[id] || [];
|
|
2562
|
+
if (id === "RIFF" || id === "LIST") {
|
|
2563
|
+
chunks[id].push(parseRIFF(data));
|
|
2564
|
+
} else {
|
|
2565
|
+
chunks[id].push(data);
|
|
2566
|
+
}
|
|
2567
|
+
}
|
|
2568
|
+
return chunks;
|
|
2569
|
+
}
|
|
2570
|
+
function doubleToString(num) {
|
|
2571
|
+
return [].slice.call(new Uint8Array(new Float64Array([num]).buffer), 0).map(function(e) {
|
|
2572
|
+
return String.fromCharCode(e);
|
|
2573
|
+
}).reverse().join("");
|
|
2574
|
+
}
|
|
2575
|
+
var webm = new ArrayToWebM(frames.map(function(frame) {
|
|
2576
|
+
var webp = parseWebP(parseRIFF(atob(frame.image.slice(23))));
|
|
2577
|
+
webp.duration = frame.duration;
|
|
2578
|
+
return webp;
|
|
2579
|
+
}));
|
|
2580
|
+
postMessage(webm);
|
|
2581
|
+
}
|
|
2582
|
+
WhammyVideo.prototype.compile = function(callback) {
|
|
2583
|
+
var webWorker = processInWebWorker(whammyInWebWorker);
|
|
2584
|
+
webWorker.onmessage = function(event) {
|
|
2585
|
+
if (event.data.error) {
|
|
2586
|
+
console.error(event.data.error);
|
|
2587
|
+
return;
|
|
2588
|
+
}
|
|
2589
|
+
callback(event.data);
|
|
2590
|
+
};
|
|
2591
|
+
webWorker.postMessage(this.frames);
|
|
2592
|
+
};
|
|
2593
|
+
return {
|
|
2594
|
+
Video: WhammyVideo
|
|
2595
|
+
};
|
|
2596
|
+
}();
|
|
2597
|
+
if (typeof RecordRTC !== "undefined") {
|
|
2598
|
+
RecordRTC.Whammy = Whammy;
|
|
2599
|
+
}
|
|
2600
|
+
var DiskStorage = {
|
|
2601
|
+
init: function() {
|
|
2602
|
+
var self2 = this;
|
|
2603
|
+
if (typeof indexedDB === "undefined" || typeof indexedDB.open === "undefined") {
|
|
2604
|
+
console.error("IndexedDB API are not available in this browser.");
|
|
2605
|
+
return;
|
|
2606
|
+
}
|
|
2607
|
+
var dbVersion = 1;
|
|
2608
|
+
var dbName = this.dbName || location.href.replace(/\/|:|#|%|\.|\[|\]/g, ""), db;
|
|
2609
|
+
var request = indexedDB.open(dbName, dbVersion);
|
|
2610
|
+
function createObjectStore(dataBase) {
|
|
2611
|
+
dataBase.createObjectStore(self2.dataStoreName);
|
|
2612
|
+
}
|
|
2613
|
+
function putInDB() {
|
|
2614
|
+
var transaction = db.transaction([self2.dataStoreName], "readwrite");
|
|
2615
|
+
if (self2.videoBlob) {
|
|
2616
|
+
transaction.objectStore(self2.dataStoreName).put(self2.videoBlob, "videoBlob");
|
|
2617
|
+
}
|
|
2618
|
+
if (self2.gifBlob) {
|
|
2619
|
+
transaction.objectStore(self2.dataStoreName).put(self2.gifBlob, "gifBlob");
|
|
2620
|
+
}
|
|
2621
|
+
if (self2.audioBlob) {
|
|
2622
|
+
transaction.objectStore(self2.dataStoreName).put(self2.audioBlob, "audioBlob");
|
|
2623
|
+
}
|
|
2624
|
+
function getFromStore(portionName) {
|
|
2625
|
+
transaction.objectStore(self2.dataStoreName).get(portionName).onsuccess = function(event) {
|
|
2626
|
+
if (self2.callback) {
|
|
2627
|
+
self2.callback(event.target.result, portionName);
|
|
2628
|
+
}
|
|
2629
|
+
};
|
|
2630
|
+
}
|
|
2631
|
+
getFromStore("audioBlob");
|
|
2632
|
+
getFromStore("videoBlob");
|
|
2633
|
+
getFromStore("gifBlob");
|
|
2634
|
+
}
|
|
2635
|
+
request.onerror = self2.onError;
|
|
2636
|
+
request.onsuccess = function() {
|
|
2637
|
+
db = request.result;
|
|
2638
|
+
db.onerror = self2.onError;
|
|
2639
|
+
if (db.setVersion) {
|
|
2640
|
+
if (db.version !== dbVersion) {
|
|
2641
|
+
var setVersion = db.setVersion(dbVersion);
|
|
2642
|
+
setVersion.onsuccess = function() {
|
|
2643
|
+
createObjectStore(db);
|
|
2644
|
+
putInDB();
|
|
2645
|
+
};
|
|
2646
|
+
} else {
|
|
2647
|
+
putInDB();
|
|
2648
|
+
}
|
|
2649
|
+
} else {
|
|
2650
|
+
putInDB();
|
|
2651
|
+
}
|
|
2652
|
+
};
|
|
2653
|
+
request.onupgradeneeded = function(event) {
|
|
2654
|
+
createObjectStore(event.target.result);
|
|
2655
|
+
};
|
|
2656
|
+
},
|
|
2657
|
+
Fetch: function(callback) {
|
|
2658
|
+
this.callback = callback;
|
|
2659
|
+
this.init();
|
|
2660
|
+
return this;
|
|
2661
|
+
},
|
|
2662
|
+
Store: function(config) {
|
|
2663
|
+
this.audioBlob = config.audioBlob;
|
|
2664
|
+
this.videoBlob = config.videoBlob;
|
|
2665
|
+
this.gifBlob = config.gifBlob;
|
|
2666
|
+
this.init();
|
|
2667
|
+
return this;
|
|
2668
|
+
},
|
|
2669
|
+
onError: function(error) {
|
|
2670
|
+
console.error(JSON.stringify(error, null, " "));
|
|
2671
|
+
},
|
|
2672
|
+
dataStoreName: "recordRTC",
|
|
2673
|
+
dbName: null
|
|
2674
|
+
};
|
|
2675
|
+
if (typeof RecordRTC !== "undefined") {
|
|
2676
|
+
RecordRTC.DiskStorage = DiskStorage;
|
|
2677
|
+
}
|
|
2678
|
+
function GifRecorder(mediaStream, config) {
|
|
2679
|
+
if (typeof GIFEncoder === "undefined") {
|
|
2680
|
+
var script = document.createElement("script");
|
|
2681
|
+
script.src = "https://www.webrtc-experiment.com/gif-recorder.js";
|
|
2682
|
+
(document.body || document.documentElement).appendChild(script);
|
|
2683
|
+
}
|
|
2684
|
+
config = config || {};
|
|
2685
|
+
var isHTMLObject = mediaStream instanceof CanvasRenderingContext2D || mediaStream instanceof HTMLCanvasElement;
|
|
2686
|
+
this.record = function() {
|
|
2687
|
+
if (typeof GIFEncoder === "undefined") {
|
|
2688
|
+
setTimeout(self2.record, 1e3);
|
|
2689
|
+
return;
|
|
2690
|
+
}
|
|
2691
|
+
if (!isLoadedMetaData) {
|
|
2692
|
+
setTimeout(self2.record, 1e3);
|
|
2693
|
+
return;
|
|
2694
|
+
}
|
|
2695
|
+
if (!isHTMLObject) {
|
|
2696
|
+
if (!config.width) {
|
|
2697
|
+
config.width = video.offsetWidth || 320;
|
|
2698
|
+
}
|
|
2699
|
+
if (!config.height) {
|
|
2700
|
+
config.height = video.offsetHeight || 240;
|
|
2701
|
+
}
|
|
2702
|
+
if (!config.video) {
|
|
2703
|
+
config.video = {
|
|
2704
|
+
width: config.width,
|
|
2705
|
+
height: config.height
|
|
2706
|
+
};
|
|
2707
|
+
}
|
|
2708
|
+
if (!config.canvas) {
|
|
2709
|
+
config.canvas = {
|
|
2710
|
+
width: config.width,
|
|
2711
|
+
height: config.height
|
|
2712
|
+
};
|
|
2713
|
+
}
|
|
2714
|
+
canvas.width = config.canvas.width || 320;
|
|
2715
|
+
canvas.height = config.canvas.height || 240;
|
|
2716
|
+
video.width = config.video.width || 320;
|
|
2717
|
+
video.height = config.video.height || 240;
|
|
2718
|
+
}
|
|
2719
|
+
gifEncoder = new GIFEncoder();
|
|
2720
|
+
gifEncoder.setRepeat(0);
|
|
2721
|
+
gifEncoder.setDelay(config.frameRate || 200);
|
|
2722
|
+
gifEncoder.setQuality(config.quality || 10);
|
|
2723
|
+
gifEncoder.start();
|
|
2724
|
+
if (typeof config.onGifRecordingStarted === "function") {
|
|
2725
|
+
config.onGifRecordingStarted();
|
|
2726
|
+
}
|
|
2727
|
+
startTime = Date.now();
|
|
2728
|
+
function drawVideoFrame(time) {
|
|
2729
|
+
if (self2.clearedRecordedData === true) {
|
|
2730
|
+
return;
|
|
2731
|
+
}
|
|
2732
|
+
if (isPausedRecording) {
|
|
2733
|
+
return setTimeout(function() {
|
|
2734
|
+
drawVideoFrame(time);
|
|
2735
|
+
}, 100);
|
|
2736
|
+
}
|
|
2737
|
+
lastAnimationFrame = requestAnimationFrame(drawVideoFrame);
|
|
2738
|
+
if (typeof lastFrameTime === void 0) {
|
|
2739
|
+
lastFrameTime = time;
|
|
2740
|
+
}
|
|
2741
|
+
if (time - lastFrameTime < 90) {
|
|
2742
|
+
return;
|
|
2743
|
+
}
|
|
2744
|
+
if (!isHTMLObject && video.paused) {
|
|
2745
|
+
video.play();
|
|
2746
|
+
}
|
|
2747
|
+
if (!isHTMLObject) {
|
|
2748
|
+
context.drawImage(video, 0, 0, canvas.width, canvas.height);
|
|
2749
|
+
}
|
|
2750
|
+
if (config.onGifPreview) {
|
|
2751
|
+
config.onGifPreview(canvas.toDataURL("image/png"));
|
|
2752
|
+
}
|
|
2753
|
+
gifEncoder.addFrame(context);
|
|
2754
|
+
lastFrameTime = time;
|
|
2755
|
+
}
|
|
2756
|
+
lastAnimationFrame = requestAnimationFrame(drawVideoFrame);
|
|
2757
|
+
if (config.initCallback) {
|
|
2758
|
+
config.initCallback();
|
|
2759
|
+
}
|
|
2760
|
+
};
|
|
2761
|
+
this.stop = function(callback) {
|
|
2762
|
+
callback = callback || function() {
|
|
2763
|
+
};
|
|
2764
|
+
if (lastAnimationFrame) {
|
|
2765
|
+
cancelAnimationFrame(lastAnimationFrame);
|
|
2766
|
+
}
|
|
2767
|
+
endTime = Date.now();
|
|
2768
|
+
this.blob = new Blob([new Uint8Array(gifEncoder.stream().bin)], {
|
|
2769
|
+
type: "image/gif"
|
|
2770
|
+
});
|
|
2771
|
+
callback(this.blob);
|
|
2772
|
+
gifEncoder.stream().bin = [];
|
|
2773
|
+
};
|
|
2774
|
+
var isPausedRecording = false;
|
|
2775
|
+
this.pause = function() {
|
|
2776
|
+
isPausedRecording = true;
|
|
2777
|
+
};
|
|
2778
|
+
this.resume = function() {
|
|
2779
|
+
isPausedRecording = false;
|
|
2780
|
+
};
|
|
2781
|
+
this.clearRecordedData = function() {
|
|
2782
|
+
self2.clearedRecordedData = true;
|
|
2783
|
+
clearRecordedDataCB();
|
|
2784
|
+
};
|
|
2785
|
+
function clearRecordedDataCB() {
|
|
2786
|
+
if (gifEncoder) {
|
|
2787
|
+
gifEncoder.stream().bin = [];
|
|
2788
|
+
}
|
|
2789
|
+
}
|
|
2790
|
+
this.name = "GifRecorder";
|
|
2791
|
+
this.toString = function() {
|
|
2792
|
+
return this.name;
|
|
2793
|
+
};
|
|
2794
|
+
var canvas = document.createElement("canvas");
|
|
2795
|
+
var context = canvas.getContext("2d");
|
|
2796
|
+
if (isHTMLObject) {
|
|
2797
|
+
if (mediaStream instanceof CanvasRenderingContext2D) {
|
|
2798
|
+
context = mediaStream;
|
|
2799
|
+
canvas = context.canvas;
|
|
2800
|
+
} else if (mediaStream instanceof HTMLCanvasElement) {
|
|
2801
|
+
context = mediaStream.getContext("2d");
|
|
2802
|
+
canvas = mediaStream;
|
|
2803
|
+
}
|
|
2804
|
+
}
|
|
2805
|
+
var isLoadedMetaData = true;
|
|
2806
|
+
if (!isHTMLObject) {
|
|
2807
|
+
var video = document.createElement("video");
|
|
2808
|
+
video.muted = true;
|
|
2809
|
+
video.autoplay = true;
|
|
2810
|
+
video.playsInline = true;
|
|
2811
|
+
isLoadedMetaData = false;
|
|
2812
|
+
video.onloadedmetadata = function() {
|
|
2813
|
+
isLoadedMetaData = true;
|
|
2814
|
+
};
|
|
2815
|
+
setSrcObject(mediaStream, video);
|
|
2816
|
+
video.play();
|
|
2817
|
+
}
|
|
2818
|
+
var lastAnimationFrame = null;
|
|
2819
|
+
var startTime, endTime, lastFrameTime;
|
|
2820
|
+
var gifEncoder;
|
|
2821
|
+
var self2 = this;
|
|
2822
|
+
}
|
|
2823
|
+
if (typeof RecordRTC !== "undefined") {
|
|
2824
|
+
RecordRTC.GifRecorder = GifRecorder;
|
|
2825
|
+
}
|
|
2826
|
+
function MultiStreamsMixer(arrayOfMediaStreams, elementClass) {
|
|
2827
|
+
var browserFakeUserAgent2 = "Fake/5.0 (FakeOS) AppleWebKit/123 (KHTML, like Gecko) Fake/12.3.4567.89 Fake/123.45";
|
|
2828
|
+
(function(that) {
|
|
2829
|
+
if (typeof RecordRTC !== "undefined") {
|
|
2830
|
+
return;
|
|
2831
|
+
}
|
|
2832
|
+
if (!that) {
|
|
2833
|
+
return;
|
|
2834
|
+
}
|
|
2835
|
+
if (typeof window !== "undefined") {
|
|
2836
|
+
return;
|
|
2837
|
+
}
|
|
2838
|
+
if (typeof global === "undefined") {
|
|
2839
|
+
return;
|
|
2840
|
+
}
|
|
2841
|
+
global.navigator = {
|
|
2842
|
+
userAgent: browserFakeUserAgent2,
|
|
2843
|
+
getUserMedia: function() {
|
|
2844
|
+
}
|
|
2845
|
+
};
|
|
2846
|
+
if (!global.console) {
|
|
2847
|
+
global.console = {};
|
|
2848
|
+
}
|
|
2849
|
+
if (typeof global.console.log === "undefined" || typeof global.console.error === "undefined") {
|
|
2850
|
+
global.console.error = global.console.log = global.console.log || function() {
|
|
2851
|
+
console.log(arguments);
|
|
2852
|
+
};
|
|
2853
|
+
}
|
|
2854
|
+
if (typeof document === "undefined") {
|
|
2855
|
+
that.document = {
|
|
2856
|
+
documentElement: {
|
|
2857
|
+
appendChild: function() {
|
|
2858
|
+
return "";
|
|
2859
|
+
}
|
|
2860
|
+
}
|
|
2861
|
+
};
|
|
2862
|
+
document.createElement = document.captureStream = document.mozCaptureStream = function() {
|
|
2863
|
+
var obj = {
|
|
2864
|
+
getContext: function() {
|
|
2865
|
+
return obj;
|
|
2866
|
+
},
|
|
2867
|
+
play: function() {
|
|
2868
|
+
},
|
|
2869
|
+
pause: function() {
|
|
2870
|
+
},
|
|
2871
|
+
drawImage: function() {
|
|
2872
|
+
},
|
|
2873
|
+
toDataURL: function() {
|
|
2874
|
+
return "";
|
|
2875
|
+
},
|
|
2876
|
+
style: {}
|
|
2877
|
+
};
|
|
2878
|
+
return obj;
|
|
2879
|
+
};
|
|
2880
|
+
that.HTMLVideoElement = function() {
|
|
2881
|
+
};
|
|
2882
|
+
}
|
|
2883
|
+
if (typeof location === "undefined") {
|
|
2884
|
+
that.location = {
|
|
2885
|
+
protocol: "file:",
|
|
2886
|
+
href: "",
|
|
2887
|
+
hash: ""
|
|
2888
|
+
};
|
|
2889
|
+
}
|
|
2890
|
+
if (typeof screen === "undefined") {
|
|
2891
|
+
that.screen = {
|
|
2892
|
+
width: 0,
|
|
2893
|
+
height: 0
|
|
2894
|
+
};
|
|
2895
|
+
}
|
|
2896
|
+
if (typeof URL3 === "undefined") {
|
|
2897
|
+
that.URL = {
|
|
2898
|
+
createObjectURL: function() {
|
|
2899
|
+
return "";
|
|
2900
|
+
},
|
|
2901
|
+
revokeObjectURL: function() {
|
|
2902
|
+
return "";
|
|
2903
|
+
}
|
|
2904
|
+
};
|
|
2905
|
+
}
|
|
2906
|
+
that.window = global;
|
|
2907
|
+
})(typeof global !== "undefined" ? global : null);
|
|
2908
|
+
elementClass = elementClass || "multi-streams-mixer";
|
|
2909
|
+
var videos = [];
|
|
2910
|
+
var isStopDrawingFrames = false;
|
|
2911
|
+
var canvas = document.createElement("canvas");
|
|
2912
|
+
var context = canvas.getContext("2d");
|
|
2913
|
+
canvas.style.opacity = 0;
|
|
2914
|
+
canvas.style.position = "absolute";
|
|
2915
|
+
canvas.style.zIndex = -1;
|
|
2916
|
+
canvas.style.top = "-1000em";
|
|
2917
|
+
canvas.style.left = "-1000em";
|
|
2918
|
+
canvas.className = elementClass;
|
|
2919
|
+
(document.body || document.documentElement).appendChild(canvas);
|
|
2920
|
+
this.disableLogs = false;
|
|
2921
|
+
this.frameInterval = 10;
|
|
2922
|
+
this.width = 360;
|
|
2923
|
+
this.height = 240;
|
|
2924
|
+
this.useGainNode = true;
|
|
2925
|
+
var self2 = this;
|
|
2926
|
+
var AudioContext2 = window.AudioContext;
|
|
2927
|
+
if (typeof AudioContext2 === "undefined") {
|
|
2928
|
+
if (typeof webkitAudioContext !== "undefined") {
|
|
2929
|
+
AudioContext2 = webkitAudioContext;
|
|
2930
|
+
}
|
|
2931
|
+
if (typeof mozAudioContext !== "undefined") {
|
|
2932
|
+
AudioContext2 = mozAudioContext;
|
|
2933
|
+
}
|
|
2934
|
+
}
|
|
2935
|
+
var URL3 = window.URL;
|
|
2936
|
+
if (typeof URL3 === "undefined" && typeof webkitURL !== "undefined") {
|
|
2937
|
+
URL3 = webkitURL;
|
|
2938
|
+
}
|
|
2939
|
+
if (typeof navigator !== "undefined" && typeof navigator.getUserMedia === "undefined") {
|
|
2940
|
+
if (typeof navigator.webkitGetUserMedia !== "undefined") {
|
|
2941
|
+
navigator.getUserMedia = navigator.webkitGetUserMedia;
|
|
2942
|
+
}
|
|
2943
|
+
if (typeof navigator.mozGetUserMedia !== "undefined") {
|
|
2944
|
+
navigator.getUserMedia = navigator.mozGetUserMedia;
|
|
2945
|
+
}
|
|
2946
|
+
}
|
|
2947
|
+
var MediaStream2 = window.MediaStream;
|
|
2948
|
+
if (typeof MediaStream2 === "undefined" && typeof webkitMediaStream !== "undefined") {
|
|
2949
|
+
MediaStream2 = webkitMediaStream;
|
|
2950
|
+
}
|
|
2951
|
+
if (typeof MediaStream2 !== "undefined") {
|
|
2952
|
+
if (typeof MediaStream2.prototype.stop === "undefined") {
|
|
2953
|
+
MediaStream2.prototype.stop = function() {
|
|
2954
|
+
this.getTracks().forEach(function(track) {
|
|
2955
|
+
track.stop();
|
|
2956
|
+
});
|
|
2957
|
+
};
|
|
2958
|
+
}
|
|
2959
|
+
}
|
|
2960
|
+
var Storage2 = {};
|
|
2961
|
+
if (typeof AudioContext2 !== "undefined") {
|
|
2962
|
+
Storage2.AudioContext = AudioContext2;
|
|
2963
|
+
} else if (typeof webkitAudioContext !== "undefined") {
|
|
2964
|
+
Storage2.AudioContext = webkitAudioContext;
|
|
2965
|
+
}
|
|
2966
|
+
function setSrcObject2(stream, element) {
|
|
2967
|
+
if ("srcObject" in element) {
|
|
2968
|
+
element.srcObject = stream;
|
|
2969
|
+
} else if ("mozSrcObject" in element) {
|
|
2970
|
+
element.mozSrcObject = stream;
|
|
2971
|
+
} else {
|
|
2972
|
+
element.srcObject = stream;
|
|
2973
|
+
}
|
|
2974
|
+
}
|
|
2975
|
+
this.startDrawingFrames = function() {
|
|
2976
|
+
drawVideosToCanvas();
|
|
2977
|
+
};
|
|
2978
|
+
function drawVideosToCanvas() {
|
|
2979
|
+
if (isStopDrawingFrames) {
|
|
2980
|
+
return;
|
|
2981
|
+
}
|
|
2982
|
+
var videosLength = videos.length;
|
|
2983
|
+
var fullcanvas = false;
|
|
2984
|
+
var remaining = [];
|
|
2985
|
+
videos.forEach(function(video) {
|
|
2986
|
+
if (!video.stream) {
|
|
2987
|
+
video.stream = {};
|
|
2988
|
+
}
|
|
2989
|
+
if (video.stream.fullcanvas) {
|
|
2990
|
+
fullcanvas = video;
|
|
2991
|
+
} else {
|
|
2992
|
+
remaining.push(video);
|
|
2993
|
+
}
|
|
2994
|
+
});
|
|
2995
|
+
if (fullcanvas) {
|
|
2996
|
+
canvas.width = fullcanvas.stream.width;
|
|
2997
|
+
canvas.height = fullcanvas.stream.height;
|
|
2998
|
+
} else if (remaining.length) {
|
|
2999
|
+
canvas.width = videosLength > 1 ? remaining[0].width * 2 : remaining[0].width;
|
|
3000
|
+
var height = 1;
|
|
3001
|
+
if (videosLength === 3 || videosLength === 4) {
|
|
3002
|
+
height = 2;
|
|
3003
|
+
}
|
|
3004
|
+
if (videosLength === 5 || videosLength === 6) {
|
|
3005
|
+
height = 3;
|
|
3006
|
+
}
|
|
3007
|
+
if (videosLength === 7 || videosLength === 8) {
|
|
3008
|
+
height = 4;
|
|
3009
|
+
}
|
|
3010
|
+
if (videosLength === 9 || videosLength === 10) {
|
|
3011
|
+
height = 5;
|
|
3012
|
+
}
|
|
3013
|
+
canvas.height = remaining[0].height * height;
|
|
3014
|
+
} else {
|
|
3015
|
+
canvas.width = self2.width || 360;
|
|
3016
|
+
canvas.height = self2.height || 240;
|
|
3017
|
+
}
|
|
3018
|
+
if (fullcanvas && fullcanvas instanceof HTMLVideoElement) {
|
|
3019
|
+
drawImage(fullcanvas);
|
|
3020
|
+
}
|
|
3021
|
+
remaining.forEach(function(video, idx) {
|
|
3022
|
+
drawImage(video, idx);
|
|
3023
|
+
});
|
|
3024
|
+
setTimeout(drawVideosToCanvas, self2.frameInterval);
|
|
3025
|
+
}
|
|
3026
|
+
function drawImage(video, idx) {
|
|
3027
|
+
if (isStopDrawingFrames) {
|
|
3028
|
+
return;
|
|
3029
|
+
}
|
|
3030
|
+
var x = 0;
|
|
3031
|
+
var y = 0;
|
|
3032
|
+
var width = video.width;
|
|
3033
|
+
var height = video.height;
|
|
3034
|
+
if (idx === 1) {
|
|
3035
|
+
x = video.width;
|
|
3036
|
+
}
|
|
3037
|
+
if (idx === 2) {
|
|
3038
|
+
y = video.height;
|
|
3039
|
+
}
|
|
3040
|
+
if (idx === 3) {
|
|
3041
|
+
x = video.width;
|
|
3042
|
+
y = video.height;
|
|
3043
|
+
}
|
|
3044
|
+
if (idx === 4) {
|
|
3045
|
+
y = video.height * 2;
|
|
3046
|
+
}
|
|
3047
|
+
if (idx === 5) {
|
|
3048
|
+
x = video.width;
|
|
3049
|
+
y = video.height * 2;
|
|
3050
|
+
}
|
|
3051
|
+
if (idx === 6) {
|
|
3052
|
+
y = video.height * 3;
|
|
3053
|
+
}
|
|
3054
|
+
if (idx === 7) {
|
|
3055
|
+
x = video.width;
|
|
3056
|
+
y = video.height * 3;
|
|
3057
|
+
}
|
|
3058
|
+
if (typeof video.stream.left !== "undefined") {
|
|
3059
|
+
x = video.stream.left;
|
|
3060
|
+
}
|
|
3061
|
+
if (typeof video.stream.top !== "undefined") {
|
|
3062
|
+
y = video.stream.top;
|
|
3063
|
+
}
|
|
3064
|
+
if (typeof video.stream.width !== "undefined") {
|
|
3065
|
+
width = video.stream.width;
|
|
3066
|
+
}
|
|
3067
|
+
if (typeof video.stream.height !== "undefined") {
|
|
3068
|
+
height = video.stream.height;
|
|
3069
|
+
}
|
|
3070
|
+
context.drawImage(video, x, y, width, height);
|
|
3071
|
+
if (typeof video.stream.onRender === "function") {
|
|
3072
|
+
video.stream.onRender(context, x, y, width, height, idx);
|
|
3073
|
+
}
|
|
3074
|
+
}
|
|
3075
|
+
function getMixedStream() {
|
|
3076
|
+
isStopDrawingFrames = false;
|
|
3077
|
+
var mixedVideoStream = getMixedVideoStream();
|
|
3078
|
+
var mixedAudioStream = getMixedAudioStream();
|
|
3079
|
+
if (mixedAudioStream) {
|
|
3080
|
+
mixedAudioStream.getTracks().filter(function(t) {
|
|
3081
|
+
return t.kind === "audio";
|
|
3082
|
+
}).forEach(function(track) {
|
|
3083
|
+
mixedVideoStream.addTrack(track);
|
|
3084
|
+
});
|
|
3085
|
+
}
|
|
3086
|
+
var fullcanvas;
|
|
3087
|
+
arrayOfMediaStreams.forEach(function(stream) {
|
|
3088
|
+
if (stream.fullcanvas) {
|
|
3089
|
+
fullcanvas = true;
|
|
3090
|
+
}
|
|
3091
|
+
});
|
|
3092
|
+
return mixedVideoStream;
|
|
3093
|
+
}
|
|
3094
|
+
function getMixedVideoStream() {
|
|
3095
|
+
resetVideoStreams();
|
|
3096
|
+
var capturedStream;
|
|
3097
|
+
if ("captureStream" in canvas) {
|
|
3098
|
+
capturedStream = canvas.captureStream();
|
|
3099
|
+
} else if ("mozCaptureStream" in canvas) {
|
|
3100
|
+
capturedStream = canvas.mozCaptureStream();
|
|
3101
|
+
} else if (!self2.disableLogs) {
|
|
3102
|
+
console.error("Upgrade to latest Chrome or otherwise enable this flag: chrome://flags/#enable-experimental-web-platform-features");
|
|
3103
|
+
}
|
|
3104
|
+
var videoStream = new MediaStream2();
|
|
3105
|
+
capturedStream.getTracks().filter(function(t) {
|
|
3106
|
+
return t.kind === "video";
|
|
3107
|
+
}).forEach(function(track) {
|
|
3108
|
+
videoStream.addTrack(track);
|
|
3109
|
+
});
|
|
3110
|
+
canvas.stream = videoStream;
|
|
3111
|
+
return videoStream;
|
|
3112
|
+
}
|
|
3113
|
+
function getMixedAudioStream() {
|
|
3114
|
+
if (!Storage2.AudioContextConstructor) {
|
|
3115
|
+
Storage2.AudioContextConstructor = new Storage2.AudioContext();
|
|
3116
|
+
}
|
|
3117
|
+
self2.audioContext = Storage2.AudioContextConstructor;
|
|
3118
|
+
self2.audioSources = [];
|
|
3119
|
+
if (self2.useGainNode === true) {
|
|
3120
|
+
self2.gainNode = self2.audioContext.createGain();
|
|
3121
|
+
self2.gainNode.connect(self2.audioContext.destination);
|
|
3122
|
+
self2.gainNode.gain.value = 0;
|
|
3123
|
+
}
|
|
3124
|
+
var audioTracksLength = 0;
|
|
3125
|
+
arrayOfMediaStreams.forEach(function(stream) {
|
|
3126
|
+
if (!stream.getTracks().filter(function(t) {
|
|
3127
|
+
return t.kind === "audio";
|
|
3128
|
+
}).length) {
|
|
3129
|
+
return;
|
|
3130
|
+
}
|
|
3131
|
+
audioTracksLength++;
|
|
3132
|
+
var audioSource = self2.audioContext.createMediaStreamSource(stream);
|
|
3133
|
+
if (self2.useGainNode === true) {
|
|
3134
|
+
audioSource.connect(self2.gainNode);
|
|
3135
|
+
}
|
|
3136
|
+
self2.audioSources.push(audioSource);
|
|
3137
|
+
});
|
|
3138
|
+
if (!audioTracksLength) {
|
|
3139
|
+
return;
|
|
3140
|
+
}
|
|
3141
|
+
self2.audioDestination = self2.audioContext.createMediaStreamDestination();
|
|
3142
|
+
self2.audioSources.forEach(function(audioSource) {
|
|
3143
|
+
audioSource.connect(self2.audioDestination);
|
|
3144
|
+
});
|
|
3145
|
+
return self2.audioDestination.stream;
|
|
3146
|
+
}
|
|
3147
|
+
function getVideo(stream) {
|
|
3148
|
+
var video = document.createElement("video");
|
|
3149
|
+
setSrcObject2(stream, video);
|
|
3150
|
+
video.className = elementClass;
|
|
3151
|
+
video.muted = true;
|
|
3152
|
+
video.volume = 0;
|
|
3153
|
+
video.width = stream.width || self2.width || 360;
|
|
3154
|
+
video.height = stream.height || self2.height || 240;
|
|
3155
|
+
video.play();
|
|
3156
|
+
return video;
|
|
3157
|
+
}
|
|
3158
|
+
this.appendStreams = function(streams) {
|
|
3159
|
+
if (!streams) {
|
|
3160
|
+
throw "First parameter is required.";
|
|
3161
|
+
}
|
|
3162
|
+
if (!(streams instanceof Array)) {
|
|
3163
|
+
streams = [streams];
|
|
3164
|
+
}
|
|
3165
|
+
streams.forEach(function(stream) {
|
|
3166
|
+
var newStream = new MediaStream2();
|
|
3167
|
+
if (stream.getTracks().filter(function(t) {
|
|
3168
|
+
return t.kind === "video";
|
|
3169
|
+
}).length) {
|
|
3170
|
+
var video = getVideo(stream);
|
|
3171
|
+
video.stream = stream;
|
|
3172
|
+
videos.push(video);
|
|
3173
|
+
newStream.addTrack(stream.getTracks().filter(function(t) {
|
|
3174
|
+
return t.kind === "video";
|
|
3175
|
+
})[0]);
|
|
3176
|
+
}
|
|
3177
|
+
if (stream.getTracks().filter(function(t) {
|
|
3178
|
+
return t.kind === "audio";
|
|
3179
|
+
}).length) {
|
|
3180
|
+
var audioSource = self2.audioContext.createMediaStreamSource(stream);
|
|
3181
|
+
self2.audioDestination = self2.audioContext.createMediaStreamDestination();
|
|
3182
|
+
audioSource.connect(self2.audioDestination);
|
|
3183
|
+
newStream.addTrack(self2.audioDestination.stream.getTracks().filter(function(t) {
|
|
3184
|
+
return t.kind === "audio";
|
|
3185
|
+
})[0]);
|
|
3186
|
+
}
|
|
3187
|
+
arrayOfMediaStreams.push(newStream);
|
|
3188
|
+
});
|
|
3189
|
+
};
|
|
3190
|
+
this.releaseStreams = function() {
|
|
3191
|
+
videos = [];
|
|
3192
|
+
isStopDrawingFrames = true;
|
|
3193
|
+
if (self2.gainNode) {
|
|
3194
|
+
self2.gainNode.disconnect();
|
|
3195
|
+
self2.gainNode = null;
|
|
3196
|
+
}
|
|
3197
|
+
if (self2.audioSources.length) {
|
|
3198
|
+
self2.audioSources.forEach(function(source) {
|
|
3199
|
+
source.disconnect();
|
|
3200
|
+
});
|
|
3201
|
+
self2.audioSources = [];
|
|
3202
|
+
}
|
|
3203
|
+
if (self2.audioDestination) {
|
|
3204
|
+
self2.audioDestination.disconnect();
|
|
3205
|
+
self2.audioDestination = null;
|
|
3206
|
+
}
|
|
3207
|
+
if (self2.audioContext) {
|
|
3208
|
+
self2.audioContext.close();
|
|
3209
|
+
}
|
|
3210
|
+
self2.audioContext = null;
|
|
3211
|
+
context.clearRect(0, 0, canvas.width, canvas.height);
|
|
3212
|
+
if (canvas.stream) {
|
|
3213
|
+
canvas.stream.stop();
|
|
3214
|
+
canvas.stream = null;
|
|
3215
|
+
}
|
|
3216
|
+
};
|
|
3217
|
+
this.resetVideoStreams = function(streams) {
|
|
3218
|
+
if (streams && !(streams instanceof Array)) {
|
|
3219
|
+
streams = [streams];
|
|
3220
|
+
}
|
|
3221
|
+
resetVideoStreams(streams);
|
|
3222
|
+
};
|
|
3223
|
+
function resetVideoStreams(streams) {
|
|
3224
|
+
videos = [];
|
|
3225
|
+
streams = streams || arrayOfMediaStreams;
|
|
3226
|
+
streams.forEach(function(stream) {
|
|
3227
|
+
if (!stream.getTracks().filter(function(t) {
|
|
3228
|
+
return t.kind === "video";
|
|
3229
|
+
}).length) {
|
|
3230
|
+
return;
|
|
3231
|
+
}
|
|
3232
|
+
var video = getVideo(stream);
|
|
3233
|
+
video.stream = stream;
|
|
3234
|
+
videos.push(video);
|
|
3235
|
+
});
|
|
3236
|
+
}
|
|
3237
|
+
this.name = "MultiStreamsMixer";
|
|
3238
|
+
this.toString = function() {
|
|
3239
|
+
return this.name;
|
|
3240
|
+
};
|
|
3241
|
+
this.getMixedStream = getMixedStream;
|
|
3242
|
+
}
|
|
3243
|
+
if (typeof RecordRTC === "undefined") {
|
|
3244
|
+
if (typeof module !== "undefined") {
|
|
3245
|
+
module.exports = MultiStreamsMixer;
|
|
3246
|
+
}
|
|
3247
|
+
if (typeof define === "function" && define.amd) {
|
|
3248
|
+
define("MultiStreamsMixer", [], function() {
|
|
3249
|
+
return MultiStreamsMixer;
|
|
3250
|
+
});
|
|
3251
|
+
}
|
|
3252
|
+
}
|
|
3253
|
+
function MultiStreamRecorder(arrayOfMediaStreams, options) {
|
|
3254
|
+
arrayOfMediaStreams = arrayOfMediaStreams || [];
|
|
3255
|
+
var self2 = this;
|
|
3256
|
+
var mixer;
|
|
3257
|
+
var mediaRecorder;
|
|
3258
|
+
options = options || {
|
|
3259
|
+
elementClass: "multi-streams-mixer",
|
|
3260
|
+
mimeType: "video/webm",
|
|
3261
|
+
video: {
|
|
3262
|
+
width: 360,
|
|
3263
|
+
height: 240
|
|
3264
|
+
}
|
|
3265
|
+
};
|
|
3266
|
+
if (!options.frameInterval) {
|
|
3267
|
+
options.frameInterval = 10;
|
|
3268
|
+
}
|
|
3269
|
+
if (!options.video) {
|
|
3270
|
+
options.video = {};
|
|
3271
|
+
}
|
|
3272
|
+
if (!options.video.width) {
|
|
3273
|
+
options.video.width = 360;
|
|
3274
|
+
}
|
|
3275
|
+
if (!options.video.height) {
|
|
3276
|
+
options.video.height = 240;
|
|
3277
|
+
}
|
|
3278
|
+
this.record = function() {
|
|
3279
|
+
mixer = new MultiStreamsMixer(arrayOfMediaStreams, options.elementClass || "multi-streams-mixer");
|
|
3280
|
+
if (getAllVideoTracks().length) {
|
|
3281
|
+
mixer.frameInterval = options.frameInterval || 10;
|
|
3282
|
+
mixer.width = options.video.width || 360;
|
|
3283
|
+
mixer.height = options.video.height || 240;
|
|
3284
|
+
mixer.startDrawingFrames();
|
|
3285
|
+
}
|
|
3286
|
+
if (options.previewStream && typeof options.previewStream === "function") {
|
|
3287
|
+
options.previewStream(mixer.getMixedStream());
|
|
3288
|
+
}
|
|
3289
|
+
mediaRecorder = new MediaStreamRecorder(mixer.getMixedStream(), options);
|
|
3290
|
+
mediaRecorder.record();
|
|
3291
|
+
};
|
|
3292
|
+
function getAllVideoTracks() {
|
|
3293
|
+
var tracks = [];
|
|
3294
|
+
arrayOfMediaStreams.forEach(function(stream) {
|
|
3295
|
+
getTracks(stream, "video").forEach(function(track) {
|
|
3296
|
+
tracks.push(track);
|
|
3297
|
+
});
|
|
3298
|
+
});
|
|
3299
|
+
return tracks;
|
|
3300
|
+
}
|
|
3301
|
+
this.stop = function(callback) {
|
|
3302
|
+
if (!mediaRecorder) {
|
|
3303
|
+
return;
|
|
3304
|
+
}
|
|
3305
|
+
mediaRecorder.stop(function(blob) {
|
|
3306
|
+
self2.blob = blob;
|
|
3307
|
+
callback(blob);
|
|
3308
|
+
self2.clearRecordedData();
|
|
3309
|
+
});
|
|
3310
|
+
};
|
|
3311
|
+
this.pause = function() {
|
|
3312
|
+
if (mediaRecorder) {
|
|
3313
|
+
mediaRecorder.pause();
|
|
3314
|
+
}
|
|
3315
|
+
};
|
|
3316
|
+
this.resume = function() {
|
|
3317
|
+
if (mediaRecorder) {
|
|
3318
|
+
mediaRecorder.resume();
|
|
3319
|
+
}
|
|
3320
|
+
};
|
|
3321
|
+
this.clearRecordedData = function() {
|
|
3322
|
+
if (mediaRecorder) {
|
|
3323
|
+
mediaRecorder.clearRecordedData();
|
|
3324
|
+
mediaRecorder = null;
|
|
3325
|
+
}
|
|
3326
|
+
if (mixer) {
|
|
3327
|
+
mixer.releaseStreams();
|
|
3328
|
+
mixer = null;
|
|
3329
|
+
}
|
|
3330
|
+
};
|
|
3331
|
+
this.addStreams = function(streams) {
|
|
3332
|
+
if (!streams) {
|
|
3333
|
+
throw "First parameter is required.";
|
|
3334
|
+
}
|
|
3335
|
+
if (!(streams instanceof Array)) {
|
|
3336
|
+
streams = [streams];
|
|
3337
|
+
}
|
|
3338
|
+
arrayOfMediaStreams.concat(streams);
|
|
3339
|
+
if (!mediaRecorder || !mixer) {
|
|
3340
|
+
return;
|
|
3341
|
+
}
|
|
3342
|
+
mixer.appendStreams(streams);
|
|
3343
|
+
if (options.previewStream && typeof options.previewStream === "function") {
|
|
3344
|
+
options.previewStream(mixer.getMixedStream());
|
|
3345
|
+
}
|
|
3346
|
+
};
|
|
3347
|
+
this.resetVideoStreams = function(streams) {
|
|
3348
|
+
if (!mixer) {
|
|
3349
|
+
return;
|
|
3350
|
+
}
|
|
3351
|
+
if (streams && !(streams instanceof Array)) {
|
|
3352
|
+
streams = [streams];
|
|
3353
|
+
}
|
|
3354
|
+
mixer.resetVideoStreams(streams);
|
|
3355
|
+
};
|
|
3356
|
+
this.getMixer = function() {
|
|
3357
|
+
return mixer;
|
|
3358
|
+
};
|
|
3359
|
+
this.name = "MultiStreamRecorder";
|
|
3360
|
+
this.toString = function() {
|
|
3361
|
+
return this.name;
|
|
3362
|
+
};
|
|
3363
|
+
}
|
|
3364
|
+
if (typeof RecordRTC !== "undefined") {
|
|
3365
|
+
RecordRTC.MultiStreamRecorder = MultiStreamRecorder;
|
|
3366
|
+
}
|
|
3367
|
+
function RecordRTCPromisesHandler3(mediaStream, options) {
|
|
3368
|
+
if (!this) {
|
|
3369
|
+
throw 'Use "new RecordRTCPromisesHandler()"';
|
|
3370
|
+
}
|
|
3371
|
+
if (typeof mediaStream === "undefined") {
|
|
3372
|
+
throw 'First argument "MediaStream" is required.';
|
|
3373
|
+
}
|
|
3374
|
+
var self2 = this;
|
|
3375
|
+
self2.recordRTC = new RecordRTC(mediaStream, options);
|
|
3376
|
+
this.startRecording = function() {
|
|
3377
|
+
return new Promise(function(resolve, reject) {
|
|
3378
|
+
try {
|
|
3379
|
+
self2.recordRTC.startRecording();
|
|
3380
|
+
resolve();
|
|
3381
|
+
} catch (e) {
|
|
3382
|
+
reject(e);
|
|
3383
|
+
}
|
|
3384
|
+
});
|
|
3385
|
+
};
|
|
3386
|
+
this.stopRecording = function() {
|
|
3387
|
+
return new Promise(function(resolve, reject) {
|
|
3388
|
+
try {
|
|
3389
|
+
self2.recordRTC.stopRecording(function(url) {
|
|
3390
|
+
self2.blob = self2.recordRTC.getBlob();
|
|
3391
|
+
if (!self2.blob || !self2.blob.size) {
|
|
3392
|
+
reject("Empty blob.", self2.blob);
|
|
3393
|
+
return;
|
|
3394
|
+
}
|
|
3395
|
+
resolve(url);
|
|
3396
|
+
});
|
|
3397
|
+
} catch (e) {
|
|
3398
|
+
reject(e);
|
|
3399
|
+
}
|
|
3400
|
+
});
|
|
3401
|
+
};
|
|
3402
|
+
this.pauseRecording = function() {
|
|
3403
|
+
return new Promise(function(resolve, reject) {
|
|
3404
|
+
try {
|
|
3405
|
+
self2.recordRTC.pauseRecording();
|
|
3406
|
+
resolve();
|
|
3407
|
+
} catch (e) {
|
|
3408
|
+
reject(e);
|
|
3409
|
+
}
|
|
3410
|
+
});
|
|
3411
|
+
};
|
|
3412
|
+
this.resumeRecording = function() {
|
|
3413
|
+
return new Promise(function(resolve, reject) {
|
|
3414
|
+
try {
|
|
3415
|
+
self2.recordRTC.resumeRecording();
|
|
3416
|
+
resolve();
|
|
3417
|
+
} catch (e) {
|
|
3418
|
+
reject(e);
|
|
3419
|
+
}
|
|
3420
|
+
});
|
|
3421
|
+
};
|
|
3422
|
+
this.getDataURL = function(callback) {
|
|
3423
|
+
return new Promise(function(resolve, reject) {
|
|
3424
|
+
try {
|
|
3425
|
+
self2.recordRTC.getDataURL(function(dataURL) {
|
|
3426
|
+
resolve(dataURL);
|
|
3427
|
+
});
|
|
3428
|
+
} catch (e) {
|
|
3429
|
+
reject(e);
|
|
3430
|
+
}
|
|
3431
|
+
});
|
|
3432
|
+
};
|
|
3433
|
+
this.getBlob = function() {
|
|
3434
|
+
return new Promise(function(resolve, reject) {
|
|
3435
|
+
try {
|
|
3436
|
+
resolve(self2.recordRTC.getBlob());
|
|
3437
|
+
} catch (e) {
|
|
3438
|
+
reject(e);
|
|
3439
|
+
}
|
|
3440
|
+
});
|
|
3441
|
+
};
|
|
3442
|
+
this.getInternalRecorder = function() {
|
|
3443
|
+
return new Promise(function(resolve, reject) {
|
|
3444
|
+
try {
|
|
3445
|
+
resolve(self2.recordRTC.getInternalRecorder());
|
|
3446
|
+
} catch (e) {
|
|
3447
|
+
reject(e);
|
|
3448
|
+
}
|
|
3449
|
+
});
|
|
3450
|
+
};
|
|
3451
|
+
this.reset = function() {
|
|
3452
|
+
return new Promise(function(resolve, reject) {
|
|
3453
|
+
try {
|
|
3454
|
+
resolve(self2.recordRTC.reset());
|
|
3455
|
+
} catch (e) {
|
|
3456
|
+
reject(e);
|
|
3457
|
+
}
|
|
3458
|
+
});
|
|
3459
|
+
};
|
|
3460
|
+
this.destroy = function() {
|
|
3461
|
+
return new Promise(function(resolve, reject) {
|
|
3462
|
+
try {
|
|
3463
|
+
resolve(self2.recordRTC.destroy());
|
|
3464
|
+
} catch (e) {
|
|
3465
|
+
reject(e);
|
|
3466
|
+
}
|
|
3467
|
+
});
|
|
3468
|
+
};
|
|
3469
|
+
this.getState = function() {
|
|
3470
|
+
return new Promise(function(resolve, reject) {
|
|
3471
|
+
try {
|
|
3472
|
+
resolve(self2.recordRTC.getState());
|
|
3473
|
+
} catch (e) {
|
|
3474
|
+
reject(e);
|
|
3475
|
+
}
|
|
3476
|
+
});
|
|
3477
|
+
};
|
|
3478
|
+
this.blob = null;
|
|
3479
|
+
this.version = "5.6.2";
|
|
3480
|
+
}
|
|
3481
|
+
if (typeof RecordRTC !== "undefined") {
|
|
3482
|
+
RecordRTC.RecordRTCPromisesHandler = RecordRTCPromisesHandler3;
|
|
3483
|
+
}
|
|
3484
|
+
function WebAssemblyRecorder(stream, config) {
|
|
3485
|
+
if (typeof ReadableStream === "undefined" || typeof WritableStream === "undefined") {
|
|
3486
|
+
console.error("Following polyfill is strongly recommended: https://unpkg.com/@mattiasbuelens/web-streams-polyfill/dist/polyfill.min.js");
|
|
3487
|
+
}
|
|
3488
|
+
config = config || {};
|
|
3489
|
+
config.width = config.width || 640;
|
|
3490
|
+
config.height = config.height || 480;
|
|
3491
|
+
config.frameRate = config.frameRate || 30;
|
|
3492
|
+
config.bitrate = config.bitrate || 1200;
|
|
3493
|
+
config.realtime = config.realtime || true;
|
|
3494
|
+
function createBufferURL(buffer, type) {
|
|
3495
|
+
return URL2.createObjectURL(new Blob([buffer], {
|
|
3496
|
+
type: type || ""
|
|
3497
|
+
}));
|
|
3498
|
+
}
|
|
3499
|
+
var finished;
|
|
3500
|
+
function cameraStream() {
|
|
3501
|
+
return new ReadableStream({
|
|
3502
|
+
start: function(controller) {
|
|
3503
|
+
var cvs = document.createElement("canvas");
|
|
3504
|
+
var video = document.createElement("video");
|
|
3505
|
+
var first = true;
|
|
3506
|
+
video.srcObject = stream;
|
|
3507
|
+
video.muted = true;
|
|
3508
|
+
video.height = config.height;
|
|
3509
|
+
video.width = config.width;
|
|
3510
|
+
video.volume = 0;
|
|
3511
|
+
video.onplaying = function() {
|
|
3512
|
+
cvs.width = config.width;
|
|
3513
|
+
cvs.height = config.height;
|
|
3514
|
+
var ctx = cvs.getContext("2d");
|
|
3515
|
+
var frameTimeout = 1e3 / config.frameRate;
|
|
3516
|
+
var cameraTimer = setInterval(function f() {
|
|
3517
|
+
if (finished) {
|
|
3518
|
+
clearInterval(cameraTimer);
|
|
3519
|
+
controller.close();
|
|
3520
|
+
}
|
|
3521
|
+
if (first) {
|
|
3522
|
+
first = false;
|
|
3523
|
+
if (config.onVideoProcessStarted) {
|
|
3524
|
+
config.onVideoProcessStarted();
|
|
3525
|
+
}
|
|
3526
|
+
}
|
|
3527
|
+
ctx.drawImage(video, 0, 0);
|
|
3528
|
+
if (controller._controlledReadableStream.state !== "closed") {
|
|
3529
|
+
try {
|
|
3530
|
+
controller.enqueue(ctx.getImageData(0, 0, config.width, config.height));
|
|
3531
|
+
} catch (e) {
|
|
3532
|
+
}
|
|
3533
|
+
}
|
|
3534
|
+
}, frameTimeout);
|
|
3535
|
+
};
|
|
3536
|
+
video.play();
|
|
3537
|
+
}
|
|
3538
|
+
});
|
|
3539
|
+
}
|
|
3540
|
+
var worker;
|
|
3541
|
+
function startRecording(stream2, buffer) {
|
|
3542
|
+
if (!config.workerPath && !buffer) {
|
|
3543
|
+
finished = false;
|
|
3544
|
+
fetch("https://unpkg.com/webm-wasm@latest/dist/webm-worker.js").then(function(r) {
|
|
3545
|
+
r.arrayBuffer().then(function(buffer2) {
|
|
3546
|
+
startRecording(stream2, buffer2);
|
|
3547
|
+
});
|
|
3548
|
+
});
|
|
3549
|
+
return;
|
|
3550
|
+
}
|
|
3551
|
+
if (!config.workerPath && buffer instanceof ArrayBuffer) {
|
|
3552
|
+
var blob = new Blob([buffer], {
|
|
3553
|
+
type: "text/javascript"
|
|
3554
|
+
});
|
|
3555
|
+
config.workerPath = URL2.createObjectURL(blob);
|
|
3556
|
+
}
|
|
3557
|
+
if (!config.workerPath) {
|
|
3558
|
+
console.error("workerPath parameter is missing.");
|
|
3559
|
+
}
|
|
3560
|
+
worker = new Worker(config.workerPath);
|
|
3561
|
+
worker.postMessage(config.webAssemblyPath || "https://unpkg.com/webm-wasm@latest/dist/webm-wasm.wasm");
|
|
3562
|
+
worker.addEventListener("message", function(event) {
|
|
3563
|
+
if (event.data === "READY") {
|
|
3564
|
+
worker.postMessage({
|
|
3565
|
+
width: config.width,
|
|
3566
|
+
height: config.height,
|
|
3567
|
+
bitrate: config.bitrate || 1200,
|
|
3568
|
+
timebaseDen: config.frameRate || 30,
|
|
3569
|
+
realtime: config.realtime
|
|
3570
|
+
});
|
|
3571
|
+
cameraStream().pipeTo(new WritableStream({
|
|
3572
|
+
write: function(image) {
|
|
3573
|
+
if (finished) {
|
|
3574
|
+
console.error("Got image, but recorder is finished!");
|
|
3575
|
+
return;
|
|
3576
|
+
}
|
|
3577
|
+
worker.postMessage(image.data.buffer, [image.data.buffer]);
|
|
3578
|
+
}
|
|
3579
|
+
}));
|
|
3580
|
+
} else if (!!event.data) {
|
|
3581
|
+
if (!isPaused) {
|
|
3582
|
+
arrayOfBuffers.push(event.data);
|
|
3583
|
+
}
|
|
3584
|
+
}
|
|
3585
|
+
});
|
|
3586
|
+
}
|
|
3587
|
+
this.record = function() {
|
|
3588
|
+
arrayOfBuffers = [];
|
|
3589
|
+
isPaused = false;
|
|
3590
|
+
this.blob = null;
|
|
3591
|
+
startRecording(stream);
|
|
3592
|
+
if (typeof config.initCallback === "function") {
|
|
3593
|
+
config.initCallback();
|
|
3594
|
+
}
|
|
3595
|
+
};
|
|
3596
|
+
var isPaused;
|
|
3597
|
+
this.pause = function() {
|
|
3598
|
+
isPaused = true;
|
|
3599
|
+
};
|
|
3600
|
+
this.resume = function() {
|
|
3601
|
+
isPaused = false;
|
|
3602
|
+
};
|
|
3603
|
+
function terminate(callback) {
|
|
3604
|
+
if (!worker) {
|
|
3605
|
+
if (callback) {
|
|
3606
|
+
callback();
|
|
3607
|
+
}
|
|
3608
|
+
return;
|
|
3609
|
+
}
|
|
3610
|
+
worker.addEventListener("message", function(event) {
|
|
3611
|
+
if (event.data === null) {
|
|
3612
|
+
worker.terminate();
|
|
3613
|
+
worker = null;
|
|
3614
|
+
if (callback) {
|
|
3615
|
+
callback();
|
|
3616
|
+
}
|
|
3617
|
+
}
|
|
3618
|
+
});
|
|
3619
|
+
worker.postMessage(null);
|
|
3620
|
+
}
|
|
3621
|
+
var arrayOfBuffers = [];
|
|
3622
|
+
this.stop = function(callback) {
|
|
3623
|
+
finished = true;
|
|
3624
|
+
var recorder = this;
|
|
3625
|
+
terminate(function() {
|
|
3626
|
+
recorder.blob = new Blob(arrayOfBuffers, {
|
|
3627
|
+
type: "video/webm"
|
|
3628
|
+
});
|
|
3629
|
+
callback(recorder.blob);
|
|
3630
|
+
});
|
|
3631
|
+
};
|
|
3632
|
+
this.name = "WebAssemblyRecorder";
|
|
3633
|
+
this.toString = function() {
|
|
3634
|
+
return this.name;
|
|
3635
|
+
};
|
|
3636
|
+
this.clearRecordedData = function() {
|
|
3637
|
+
arrayOfBuffers = [];
|
|
3638
|
+
isPaused = false;
|
|
3639
|
+
this.blob = null;
|
|
3640
|
+
};
|
|
3641
|
+
this.blob = null;
|
|
3642
|
+
}
|
|
3643
|
+
if (typeof RecordRTC !== "undefined") {
|
|
3644
|
+
RecordRTC.WebAssemblyRecorder = WebAssemblyRecorder;
|
|
3645
|
+
}
|
|
3646
|
+
}
|
|
3647
|
+
});
|
|
3648
|
+
|
|
21
3649
|
// src/plugins/mp3.js
|
|
22
3650
|
var require_mp3 = __commonJS({
|
|
23
3651
|
"src/plugins/mp3.js"(exports, module) {
|
|
@@ -14301,39 +17929,8 @@ var require_mp3 = __commonJS({
|
|
|
14301
17929
|
}
|
|
14302
17930
|
});
|
|
14303
17931
|
|
|
14304
|
-
// src/modules/recorder.ts
|
|
14305
|
-
function recorder(stream, buffer) {
|
|
14306
|
-
let resolvePromise;
|
|
14307
|
-
const options = {
|
|
14308
|
-
mimeType: "video/webm",
|
|
14309
|
-
videoBitsPerSecond: 128e3,
|
|
14310
|
-
audioBitsPerSecond: 64 * 1e3
|
|
14311
|
-
};
|
|
14312
|
-
const mediaRecorder = new MediaRecorder(stream, options);
|
|
14313
|
-
mediaRecorder.ondataavailable = (e) => {
|
|
14314
|
-
if (e.data.size > 0) {
|
|
14315
|
-
buffer.push(e.data);
|
|
14316
|
-
}
|
|
14317
|
-
resolvePromise && resolvePromise();
|
|
14318
|
-
};
|
|
14319
|
-
mediaRecorder.start();
|
|
14320
|
-
function stopRecording() {
|
|
14321
|
-
return new Promise((resolve) => {
|
|
14322
|
-
if (mediaRecorder.state == "recording") {
|
|
14323
|
-
resolvePromise = resolve;
|
|
14324
|
-
mediaRecorder.stop();
|
|
14325
|
-
stream.getTracks().forEach((el) => {
|
|
14326
|
-
el.stop();
|
|
14327
|
-
});
|
|
14328
|
-
} else {
|
|
14329
|
-
resolve();
|
|
14330
|
-
}
|
|
14331
|
-
});
|
|
14332
|
-
}
|
|
14333
|
-
return stopRecording;
|
|
14334
|
-
}
|
|
14335
|
-
|
|
14336
17932
|
// src/modules/startCameraCapture.ts
|
|
17933
|
+
var import_recordrtc = __toESM(require_RecordRTC());
|
|
14337
17934
|
async function startCameraCapture(buffer, options = { cameraId: void 0, microphoneId: void 0 }, videoOptions = { width: 640, height: 480 }) {
|
|
14338
17935
|
const { cameraId, microphoneId } = options;
|
|
14339
17936
|
const constraints = {
|
|
@@ -14346,7 +17943,24 @@ async function startCameraCapture(buffer, options = { cameraId: void 0, micropho
|
|
|
14346
17943
|
}
|
|
14347
17944
|
};
|
|
14348
17945
|
const cameraStream = await navigator.mediaDevices.getUserMedia(constraints);
|
|
14349
|
-
const
|
|
17946
|
+
const recorder = new import_recordrtc.RecordRTCPromisesHandler(cameraStream, {
|
|
17947
|
+
type: "video"
|
|
17948
|
+
});
|
|
17949
|
+
recorder.startRecording();
|
|
17950
|
+
const stopCameraRecording = async () => {
|
|
17951
|
+
await recorder.stopRecording();
|
|
17952
|
+
const blob = await recorder.getBlob();
|
|
17953
|
+
(0, import_recordrtc.getSeekableBlob)(blob, function(seekableBlob) {
|
|
17954
|
+
recorder.destroy();
|
|
17955
|
+
buffer.push(seekableBlob);
|
|
17956
|
+
console.log(buffer);
|
|
17957
|
+
console.log(seekableBlob);
|
|
17958
|
+
(0, import_recordrtc.invokeSaveAsDialog)(seekableBlob, "seekable-recordrtc.webm");
|
|
17959
|
+
cameraStream.getTracks().forEach((el) => {
|
|
17960
|
+
el.stop();
|
|
17961
|
+
});
|
|
17962
|
+
});
|
|
17963
|
+
};
|
|
14350
17964
|
return { cameraStream, stopCameraRecording };
|
|
14351
17965
|
}
|
|
14352
17966
|
|
|
@@ -14354,17 +17968,17 @@ async function startCameraCapture(buffer, options = { cameraId: void 0, micropho
|
|
|
14354
17968
|
var import_mp3 = __toESM(require_mp3());
|
|
14355
17969
|
var stopRecord;
|
|
14356
17970
|
function startAudioCapture() {
|
|
14357
|
-
const
|
|
17971
|
+
const recorder = new import_mp3.default({
|
|
14358
17972
|
bitRate: 128
|
|
14359
17973
|
});
|
|
14360
17974
|
function start() {
|
|
14361
|
-
|
|
17975
|
+
recorder.start().then(() => {
|
|
14362
17976
|
}).catch((e) => {
|
|
14363
17977
|
console.error(e);
|
|
14364
17978
|
});
|
|
14365
17979
|
}
|
|
14366
17980
|
async function stop() {
|
|
14367
|
-
const response = await
|
|
17981
|
+
const response = await recorder.stop().getMp3().then(async ([buffer, blob]) => {
|
|
14368
17982
|
return { buffer, blob };
|
|
14369
17983
|
}).catch((e) => {
|
|
14370
17984
|
alert("We could not retrieve your message");
|
|
@@ -14376,6 +17990,9 @@ function startAudioCapture() {
|
|
|
14376
17990
|
return { start, stop };
|
|
14377
17991
|
}
|
|
14378
17992
|
|
|
17993
|
+
// src/modules/startScreenCapture.ts
|
|
17994
|
+
var import_recordrtc2 = __toESM(require_RecordRTC());
|
|
17995
|
+
|
|
14379
17996
|
// src/errors/errors.ts
|
|
14380
17997
|
var SCRIPT_NOT_CALLED_INSIDE_BODY = "script_not_called_inside_body";
|
|
14381
17998
|
var INCOMPATIBLE_NAVIGATOR = "incompatible_navigator";
|
|
@@ -14415,7 +18032,21 @@ async function startScreenCapture(buffer, options) {
|
|
|
14415
18032
|
});
|
|
14416
18033
|
throw NOT_SHARED_FIRST_SCREEN;
|
|
14417
18034
|
}
|
|
14418
|
-
const
|
|
18035
|
+
const recorder = new import_recordrtc2.RecordRTCPromisesHandler(screenStream, {
|
|
18036
|
+
type: "video"
|
|
18037
|
+
});
|
|
18038
|
+
recorder.startRecording();
|
|
18039
|
+
const stopScreenRecorder = async () => {
|
|
18040
|
+
await recorder.stopRecording();
|
|
18041
|
+
const blob = await recorder.getBlob();
|
|
18042
|
+
(0, import_recordrtc2.getSeekableBlob)(blob, function(seekableBlob) {
|
|
18043
|
+
recorder.destroy();
|
|
18044
|
+
buffer.push(seekableBlob);
|
|
18045
|
+
screenStream.getTracks().forEach((el) => {
|
|
18046
|
+
el.stop();
|
|
18047
|
+
});
|
|
18048
|
+
});
|
|
18049
|
+
};
|
|
14419
18050
|
return { screenStream, stopScreenRecorder };
|
|
14420
18051
|
}
|
|
14421
18052
|
|
|
@@ -14467,8 +18098,8 @@ function getGlobal(useCached) {
|
|
|
14467
18098
|
}
|
|
14468
18099
|
return _cachedGlobal;
|
|
14469
18100
|
}
|
|
14470
|
-
function throwTypeError(
|
|
14471
|
-
throw new TypeError(
|
|
18101
|
+
function throwTypeError(message2) {
|
|
18102
|
+
throw new TypeError(message2);
|
|
14472
18103
|
}
|
|
14473
18104
|
function objCreateFn(obj) {
|
|
14474
18105
|
var func = ObjCreate;
|
|
@@ -14592,8 +18223,8 @@ function _forEachProp(target, func) {
|
|
|
14592
18223
|
function _isDynamicCandidate(target, funcName, skipOwn) {
|
|
14593
18224
|
return funcName !== Constructor && typeof target[funcName] === strFunction && (skipOwn || _hasOwnProperty(target, funcName));
|
|
14594
18225
|
}
|
|
14595
|
-
function _throwTypeError(
|
|
14596
|
-
throw new TypeError("DynamicProto: " +
|
|
18226
|
+
function _throwTypeError(message2) {
|
|
18227
|
+
throw new TypeError("DynamicProto: " + message2);
|
|
14597
18228
|
}
|
|
14598
18229
|
function _getInstanceFuncs(thisTarget) {
|
|
14599
18230
|
var instFuncs = {};
|
|
@@ -15197,8 +18828,8 @@ function isNotTruthy(value) {
|
|
|
15197
18828
|
function isTruthy(value) {
|
|
15198
18829
|
return !!value;
|
|
15199
18830
|
}
|
|
15200
|
-
function throwError(
|
|
15201
|
-
throw new Error(
|
|
18831
|
+
function throwError(message2) {
|
|
18832
|
+
throw new Error(message2);
|
|
15202
18833
|
}
|
|
15203
18834
|
function proxyAssign(target, source, chkSet) {
|
|
15204
18835
|
if (target && source && target !== source && isObject(target) && isObject(source)) {
|
|
@@ -15515,7 +19146,7 @@ function _sanitizeDiagnosticText(text) {
|
|
|
15515
19146
|
}
|
|
15516
19147
|
return "";
|
|
15517
19148
|
}
|
|
15518
|
-
function _logToConsole(func,
|
|
19149
|
+
function _logToConsole(func, message2) {
|
|
15519
19150
|
var theConsole = getConsole();
|
|
15520
19151
|
if (!!theConsole) {
|
|
15521
19152
|
var logFunc = "log";
|
|
@@ -15523,7 +19154,7 @@ function _logToConsole(func, message) {
|
|
|
15523
19154
|
logFunc = func;
|
|
15524
19155
|
}
|
|
15525
19156
|
if (isFunction(theConsole[logFunc])) {
|
|
15526
|
-
theConsole[logFunc](
|
|
19157
|
+
theConsole[logFunc](message2);
|
|
15527
19158
|
}
|
|
15528
19159
|
}
|
|
15529
19160
|
}
|
|
@@ -15574,48 +19205,48 @@ var DiagnosticLogger = function() {
|
|
|
15574
19205
|
if (isUserAct === void 0) {
|
|
15575
19206
|
isUserAct = false;
|
|
15576
19207
|
}
|
|
15577
|
-
var
|
|
19208
|
+
var message2 = new _InternalLogMessage(msgId, msg, isUserAct, properties);
|
|
15578
19209
|
if (_self.enableDebugExceptions()) {
|
|
15579
|
-
throw
|
|
19210
|
+
throw message2;
|
|
15580
19211
|
} else {
|
|
15581
19212
|
var logFunc = severity === LoggingSeverity.CRITICAL ? strErrorToConsole : strWarnToConsole;
|
|
15582
|
-
if (!isUndefined(
|
|
19213
|
+
if (!isUndefined(message2.message)) {
|
|
15583
19214
|
var logLevel = _self.consoleLoggingLevel();
|
|
15584
19215
|
if (isUserAct) {
|
|
15585
|
-
var messageKey = +
|
|
19216
|
+
var messageKey = +message2.messageId;
|
|
15586
19217
|
if (!_messageLogged[messageKey] && logLevel >= severity) {
|
|
15587
|
-
_self[logFunc](
|
|
19218
|
+
_self[logFunc](message2.message);
|
|
15588
19219
|
_messageLogged[messageKey] = true;
|
|
15589
19220
|
}
|
|
15590
19221
|
} else {
|
|
15591
19222
|
if (logLevel >= severity) {
|
|
15592
|
-
_self[logFunc](
|
|
19223
|
+
_self[logFunc](message2.message);
|
|
15593
19224
|
}
|
|
15594
19225
|
}
|
|
15595
|
-
_self.logInternalMessage(severity,
|
|
19226
|
+
_self.logInternalMessage(severity, message2);
|
|
15596
19227
|
} else {
|
|
15597
|
-
_debugExtMsg("throw" + (severity === LoggingSeverity.CRITICAL ? "Critical" : "Warning"),
|
|
19228
|
+
_debugExtMsg("throw" + (severity === LoggingSeverity.CRITICAL ? "Critical" : "Warning"), message2);
|
|
15598
19229
|
}
|
|
15599
19230
|
}
|
|
15600
19231
|
};
|
|
15601
|
-
_self.warnToConsole = function(
|
|
15602
|
-
_logToConsole("warn",
|
|
15603
|
-
_debugExtMsg("warning",
|
|
19232
|
+
_self.warnToConsole = function(message2) {
|
|
19233
|
+
_logToConsole("warn", message2);
|
|
19234
|
+
_debugExtMsg("warning", message2);
|
|
15604
19235
|
};
|
|
15605
|
-
_self.errorToConsole = function(
|
|
15606
|
-
_logToConsole("error",
|
|
15607
|
-
_debugExtMsg("error",
|
|
19236
|
+
_self.errorToConsole = function(message2) {
|
|
19237
|
+
_logToConsole("error", message2);
|
|
19238
|
+
_debugExtMsg("error", message2);
|
|
15608
19239
|
};
|
|
15609
19240
|
_self.resetInternalMessageCount = function() {
|
|
15610
19241
|
_messageCount = 0;
|
|
15611
19242
|
_messageLogged = {};
|
|
15612
19243
|
};
|
|
15613
|
-
_self.logInternalMessage = function(severity,
|
|
19244
|
+
_self.logInternalMessage = function(severity, message2) {
|
|
15614
19245
|
if (_areInternalMessagesThrottled()) {
|
|
15615
19246
|
return;
|
|
15616
19247
|
}
|
|
15617
19248
|
var logMessage = true;
|
|
15618
|
-
var messageKey = AIInternalMessagePrefix +
|
|
19249
|
+
var messageKey = AIInternalMessagePrefix + message2.messageId;
|
|
15619
19250
|
if (_messageLogged[messageKey]) {
|
|
15620
19251
|
logMessage = false;
|
|
15621
19252
|
} else {
|
|
@@ -15623,9 +19254,9 @@ var DiagnosticLogger = function() {
|
|
|
15623
19254
|
}
|
|
15624
19255
|
if (logMessage) {
|
|
15625
19256
|
if (severity <= _self.telemetryLoggingLevel()) {
|
|
15626
|
-
_self.queue.push(
|
|
19257
|
+
_self.queue.push(message2);
|
|
15627
19258
|
_messageCount++;
|
|
15628
|
-
_debugExtMsg(severity === LoggingSeverity.CRITICAL ? "error" : "warn",
|
|
19259
|
+
_debugExtMsg(severity === LoggingSeverity.CRITICAL ? "error" : "warn", message2);
|
|
15629
19260
|
}
|
|
15630
19261
|
if (_messageCount === _self.maxInternalMessageLimit()) {
|
|
15631
19262
|
var throttleLimitMessage = "Internal events throttle limit per PageView reached for this app.";
|
|
@@ -17074,15 +20705,15 @@ function dataSanitizeString(logger, value, maxLength) {
|
|
|
17074
20705
|
function dataSanitizeUrl(logger, url) {
|
|
17075
20706
|
return dataSanitizeInput(logger, url, 2048, _InternalMessageId.UrlTooLong);
|
|
17076
20707
|
}
|
|
17077
|
-
function dataSanitizeMessage(logger,
|
|
20708
|
+
function dataSanitizeMessage(logger, message2) {
|
|
17078
20709
|
var messageTrunc;
|
|
17079
|
-
if (
|
|
17080
|
-
if (
|
|
17081
|
-
messageTrunc =
|
|
17082
|
-
logger && logger.throwInternal(LoggingSeverity.WARNING, _InternalMessageId.MessageTruncated, "message is too long, it has been truncated to " + 32768 + " characters.", { message }, true);
|
|
20710
|
+
if (message2) {
|
|
20711
|
+
if (message2.length > 32768) {
|
|
20712
|
+
messageTrunc = message2.substring(0, 32768);
|
|
20713
|
+
logger && logger.throwInternal(LoggingSeverity.WARNING, _InternalMessageId.MessageTruncated, "message is too long, it has been truncated to " + 32768 + " characters.", { message: message2 }, true);
|
|
17083
20714
|
}
|
|
17084
20715
|
}
|
|
17085
|
-
return messageTrunc ||
|
|
20716
|
+
return messageTrunc || message2;
|
|
17086
20717
|
}
|
|
17087
20718
|
function dataSanitizeException(logger, exception) {
|
|
17088
20719
|
var exceptionTrunc;
|
|
@@ -17195,8 +20826,8 @@ function getExtensionByName(extensions, identifier) {
|
|
|
17195
20826
|
});
|
|
17196
20827
|
return extension;
|
|
17197
20828
|
}
|
|
17198
|
-
function isCrossOriginError(
|
|
17199
|
-
return !error && isString(
|
|
20829
|
+
function isCrossOriginError(message2, url, lineNumber, columnNumber, error) {
|
|
20830
|
+
return !error && isString(message2) && (message2 === "Script error." || message2 === "Script error");
|
|
17200
20831
|
}
|
|
17201
20832
|
|
|
17202
20833
|
// node_modules/@microsoft/applicationinsights-common/dist-esm/Constants.js
|
|
@@ -17933,15 +21564,15 @@ var Exception = function(_super) {
|
|
|
17933
21564
|
}
|
|
17934
21565
|
return _this;
|
|
17935
21566
|
}
|
|
17936
|
-
Exception2.CreateAutoException = function(
|
|
17937
|
-
var errorType = _getErrorType(error || evt ||
|
|
21567
|
+
Exception2.CreateAutoException = function(message2, url, lineNumber, columnNumber, error, evt, stack, errorSrc) {
|
|
21568
|
+
var errorType = _getErrorType(error || evt || message2);
|
|
17938
21569
|
return {
|
|
17939
|
-
message: _formatMessage(
|
|
21570
|
+
message: _formatMessage(message2, errorType),
|
|
17940
21571
|
url,
|
|
17941
21572
|
lineNumber,
|
|
17942
21573
|
columnNumber,
|
|
17943
|
-
error: _formatErrorCode(error || evt ||
|
|
17944
|
-
evt: _formatErrorCode(evt ||
|
|
21574
|
+
error: _formatErrorCode(error || evt || message2),
|
|
21575
|
+
evt: _formatErrorCode(evt || message2),
|
|
17945
21576
|
typeName: errorType,
|
|
17946
21577
|
stackDetails: _getStackFromErrorObj(stack || error || evt),
|
|
17947
21578
|
errorSrc
|
|
@@ -17970,12 +21601,12 @@ var Exception = function(_super) {
|
|
|
17970
21601
|
isManual
|
|
17971
21602
|
};
|
|
17972
21603
|
};
|
|
17973
|
-
Exception2.CreateSimpleException = function(
|
|
21604
|
+
Exception2.CreateSimpleException = function(message2, typeName, assembly, fileName, details, line) {
|
|
17974
21605
|
return {
|
|
17975
21606
|
exceptions: [
|
|
17976
21607
|
{
|
|
17977
21608
|
hasFullStack: true,
|
|
17978
|
-
message,
|
|
21609
|
+
message: message2,
|
|
17979
21610
|
stack: details,
|
|
17980
21611
|
typeName
|
|
17981
21612
|
}
|
|
@@ -18296,7 +21927,7 @@ var MessageData = function() {
|
|
|
18296
21927
|
// node_modules/@microsoft/applicationinsights-common/dist-esm/Telemetry/Trace.js
|
|
18297
21928
|
var Trace = function(_super) {
|
|
18298
21929
|
__extendsFn(Trace2, _super);
|
|
18299
|
-
function Trace2(logger,
|
|
21930
|
+
function Trace2(logger, message2, severityLevel, properties, measurements) {
|
|
18300
21931
|
var _this = _super.call(this) || this;
|
|
18301
21932
|
_this.aiDataContract = {
|
|
18302
21933
|
ver: 1,
|
|
@@ -18304,8 +21935,8 @@ var Trace = function(_super) {
|
|
|
18304
21935
|
severityLevel: 0,
|
|
18305
21936
|
properties: 0
|
|
18306
21937
|
};
|
|
18307
|
-
|
|
18308
|
-
_this.message = dataSanitizeMessage(logger,
|
|
21938
|
+
message2 = message2 || strNotSpecified;
|
|
21939
|
+
_this.message = dataSanitizeMessage(logger, message2);
|
|
18309
21940
|
_this.properties = dataSanitizeProperties(logger, properties);
|
|
18310
21941
|
_this.measurements = dataSanitizeMeasurements(logger, measurements);
|
|
18311
21942
|
if (severityLevel) {
|
|
@@ -19127,11 +22758,11 @@ var ApplicationInsights = function(_super) {
|
|
|
19127
22758
|
if (_self.config.disableExceptionTracking === false && !_self.config.autoExceptionInstrumented && _window) {
|
|
19128
22759
|
var onerror_1 = "onerror";
|
|
19129
22760
|
var originalOnError_1 = _window[onerror_1];
|
|
19130
|
-
_window.onerror = function(
|
|
22761
|
+
_window.onerror = function(message2, url, lineNumber, columnNumber, error) {
|
|
19131
22762
|
var evt = _window[strEvent];
|
|
19132
|
-
var handled = originalOnError_1 && originalOnError_1(
|
|
22763
|
+
var handled = originalOnError_1 && originalOnError_1(message2, url, lineNumber, columnNumber, error);
|
|
19133
22764
|
if (handled !== true) {
|
|
19134
|
-
instance._onerror(Exception.CreateAutoException(
|
|
22765
|
+
instance._onerror(Exception.CreateAutoException(message2, url, lineNumber, columnNumber, error, evt));
|
|
19135
22766
|
}
|
|
19136
22767
|
return handled;
|
|
19137
22768
|
};
|
|
@@ -19695,7 +23326,7 @@ function PageViewPerformanceEnvelopeCreator(logger, telemetryItem, customUndefin
|
|
|
19695
23326
|
}
|
|
19696
23327
|
function TraceEnvelopeCreator(logger, telemetryItem, customUndefinedValue) {
|
|
19697
23328
|
EnvelopeCreatorInit(logger, telemetryItem);
|
|
19698
|
-
var
|
|
23329
|
+
var message2 = telemetryItem[strBaseData].message;
|
|
19699
23330
|
var severityLevel = telemetryItem[strBaseData].severityLevel;
|
|
19700
23331
|
var props = telemetryItem[strBaseData][strProperties] || {};
|
|
19701
23332
|
var measurements = telemetryItem[strBaseData].measurements || {};
|
|
@@ -19703,7 +23334,7 @@ function TraceEnvelopeCreator(logger, telemetryItem, customUndefinedValue) {
|
|
|
19703
23334
|
if (!isNullOrUndefined(customUndefinedValue)) {
|
|
19704
23335
|
_convertPropsUndefinedToCustomDefinedValue(props, customUndefinedValue);
|
|
19705
23336
|
}
|
|
19706
|
-
var baseData = new Trace(logger,
|
|
23337
|
+
var baseData = new Trace(logger, message2, severityLevel, props, measurements);
|
|
19707
23338
|
var data = new Data2(Trace.dataType, baseData);
|
|
19708
23339
|
return _createEnvelope(logger, Trace.envelopeType, telemetryItem, data);
|
|
19709
23340
|
}
|
|
@@ -20255,8 +23886,8 @@ var Sender = function(_super) {
|
|
|
20255
23886
|
}
|
|
20256
23887
|
}
|
|
20257
23888
|
};
|
|
20258
|
-
_self._onError = function(payload,
|
|
20259
|
-
_self.diagLog().throwInternal(LoggingSeverity.WARNING, _InternalMessageId.OnError, "Failed to send telemetry.", { message });
|
|
23889
|
+
_self._onError = function(payload, message2, event) {
|
|
23890
|
+
_self.diagLog().throwInternal(LoggingSeverity.WARNING, _InternalMessageId.OnError, "Failed to send telemetry.", { message: message2 });
|
|
20260
23891
|
_self._buffer.clearSent(payload);
|
|
20261
23892
|
};
|
|
20262
23893
|
_self._onPartialSuccess = function(payload, results) {
|
|
@@ -20574,11 +24205,11 @@ var Sender = function(_super) {
|
|
|
20574
24205
|
function _isRetriable(statusCode) {
|
|
20575
24206
|
return statusCode === 408 || statusCode === 429 || statusCode === 500 || statusCode === 503;
|
|
20576
24207
|
}
|
|
20577
|
-
function _formatErrorMessageXhr(xhr,
|
|
24208
|
+
function _formatErrorMessageXhr(xhr, message2) {
|
|
20578
24209
|
if (xhr) {
|
|
20579
24210
|
return "XMLHttpRequest,Status:" + xhr.status + ",Response:" + _getResponseText(xhr) || xhr.response || "";
|
|
20580
24211
|
}
|
|
20581
|
-
return
|
|
24212
|
+
return message2;
|
|
20582
24213
|
}
|
|
20583
24214
|
function _xdrSender(payload, isAsync) {
|
|
20584
24215
|
var buffer = _self._buffer;
|
|
@@ -20602,11 +24233,11 @@ var Sender = function(_super) {
|
|
|
20602
24233
|
xdr.send(batch);
|
|
20603
24234
|
buffer.markAsSent(payload);
|
|
20604
24235
|
}
|
|
20605
|
-
function _formatErrorMessageXdr(xdr,
|
|
24236
|
+
function _formatErrorMessageXdr(xdr, message2) {
|
|
20606
24237
|
if (xdr) {
|
|
20607
24238
|
return "XDomainRequest,Response:" + _getResponseText(xdr) || "";
|
|
20608
24239
|
}
|
|
20609
|
-
return
|
|
24240
|
+
return message2;
|
|
20610
24241
|
}
|
|
20611
24242
|
function _getNotifyMgr() {
|
|
20612
24243
|
var func = "getNotifyMgr";
|
|
@@ -21110,8 +24741,8 @@ var PropertiesPlugin = function(_super) {
|
|
|
21110
24741
|
_processTelemetryInternal(event, itemCtx);
|
|
21111
24742
|
if (userCtx && userCtx.isNewUser) {
|
|
21112
24743
|
userCtx.isNewUser = false;
|
|
21113
|
-
var
|
|
21114
|
-
itemCtx.diagLog().logInternalMessage(LoggingSeverity.CRITICAL,
|
|
24744
|
+
var message2 = new _InternalLogMessage(_InternalMessageId.SendBrowserInfoOnUserInit, (getNavigator() || {}).userAgent || "");
|
|
24745
|
+
itemCtx.diagLog().logInternalMessage(LoggingSeverity.CRITICAL, message2);
|
|
21115
24746
|
}
|
|
21116
24747
|
_self.processNext(event, itemCtx);
|
|
21117
24748
|
}
|
|
@@ -21477,15 +25108,15 @@ function _getFailedAjaxDiagnosticsMessage(xhr) {
|
|
|
21477
25108
|
}
|
|
21478
25109
|
return result;
|
|
21479
25110
|
}
|
|
21480
|
-
function _throwInternalCritical(ajaxMonitorInstance, msgId,
|
|
21481
|
-
ajaxMonitorInstance[strDiagLog]()[strThrowInternal](LoggingSeverity.CRITICAL, msgId,
|
|
25111
|
+
function _throwInternalCritical(ajaxMonitorInstance, msgId, message2, properties, isUserAct) {
|
|
25112
|
+
ajaxMonitorInstance[strDiagLog]()[strThrowInternal](LoggingSeverity.CRITICAL, msgId, message2, properties, isUserAct);
|
|
21482
25113
|
}
|
|
21483
|
-
function _throwInternalWarning(ajaxMonitorInstance, msgId,
|
|
21484
|
-
ajaxMonitorInstance[strDiagLog]()[strThrowInternal](LoggingSeverity.WARNING, msgId,
|
|
25114
|
+
function _throwInternalWarning(ajaxMonitorInstance, msgId, message2, properties, isUserAct) {
|
|
25115
|
+
ajaxMonitorInstance[strDiagLog]()[strThrowInternal](LoggingSeverity.WARNING, msgId, message2, properties, isUserAct);
|
|
21485
25116
|
}
|
|
21486
|
-
function _createErrorCallbackFunc(ajaxMonitorInstance, internalMessage,
|
|
25117
|
+
function _createErrorCallbackFunc(ajaxMonitorInstance, internalMessage, message2) {
|
|
21487
25118
|
return function(args) {
|
|
21488
|
-
_throwInternalCritical(ajaxMonitorInstance, internalMessage,
|
|
25119
|
+
_throwInternalCritical(ajaxMonitorInstance, internalMessage, message2, {
|
|
21489
25120
|
ajaxDiagnosticsMessage: _getFailedAjaxDiagnosticsMessage(args.inst),
|
|
21490
25121
|
exception: dumpObj(args.err)
|
|
21491
25122
|
});
|
|
@@ -22466,67 +26097,87 @@ var trackers = {
|
|
|
22466
26097
|
registerUploadVideo: (proctoringId, success, description) => registerCustomEvent(eventNames.UPLOAD_VIDEO, { proctoringId, success, description })
|
|
22467
26098
|
};
|
|
22468
26099
|
|
|
22469
|
-
// src/modules/http.ts
|
|
22470
|
-
var baseUrl = "https://proctoring-api.easyproctor.tech/api";
|
|
22471
|
-
async function setBaseUrl(_baseUrl) {
|
|
22472
|
-
baseUrl = _baseUrl;
|
|
22473
|
-
}
|
|
22474
|
-
async function makeRequest(data) {
|
|
22475
|
-
const { url, method, body, jwt } = data;
|
|
22476
|
-
const resp = await fetch(baseUrl + url, {
|
|
22477
|
-
method,
|
|
22478
|
-
body: body != null ? JSON.stringify(body) : void 0,
|
|
22479
|
-
headers: {
|
|
22480
|
-
Authorization: `Bearer ${jwt}`,
|
|
22481
|
-
"Content-Type": "application/json"
|
|
22482
|
-
}
|
|
22483
|
-
});
|
|
22484
|
-
if (resp.status >= 400) {
|
|
22485
|
-
throw "N\xE3o foi poss\xEDvel realizar a requisi\xE7\xE3o, tente novamente mais tarde";
|
|
22486
|
-
}
|
|
22487
|
-
const content = resp.headers.get("content-type");
|
|
22488
|
-
const isJson = content ? content.includes("application/json") : false;
|
|
22489
|
-
const responseData = isJson ? await resp.json() : null;
|
|
22490
|
-
return responseData;
|
|
22491
|
-
}
|
|
22492
|
-
|
|
22493
26100
|
// src/modules/upload.ts
|
|
22494
26101
|
var account = "";
|
|
22495
26102
|
var containerName = "";
|
|
22496
26103
|
var sas = "";
|
|
22497
26104
|
var blobServiceClient;
|
|
26105
|
+
var message = "";
|
|
22498
26106
|
async function setConfiguration(_account, _cointainerName, _sas) {
|
|
22499
26107
|
account = _account;
|
|
22500
26108
|
containerName = _cointainerName;
|
|
22501
26109
|
sas = _sas;
|
|
22502
26110
|
blobServiceClient = new BlobServiceClient(`https://${account}.blob.core.windows.net${sas}`);
|
|
22503
26111
|
}
|
|
22504
|
-
|
|
26112
|
+
function sendError(proctoringId) {
|
|
26113
|
+
console.log(message);
|
|
26114
|
+
trackers.registerError(proctoringId, message);
|
|
26115
|
+
}
|
|
26116
|
+
async function upload(data, proctoringId) {
|
|
22505
26117
|
try {
|
|
22506
26118
|
const { file, onProgress } = data;
|
|
22507
|
-
|
|
26119
|
+
message += `Blob: Step 1 - ${containerName}
|
|
26120
|
+
`;
|
|
22508
26121
|
if (blobServiceClient == void 0) {
|
|
22509
|
-
|
|
26122
|
+
message += `blobServiceClient is undefined
|
|
26123
|
+
`;
|
|
22510
26124
|
}
|
|
22511
26125
|
const containerClient = blobServiceClient.getContainerClient(containerName);
|
|
22512
|
-
|
|
26126
|
+
message += "Blob: Step 2\n";
|
|
26127
|
+
message += " accountName " + blobServiceClient.accountName + "\n";
|
|
26128
|
+
message += " credential " + JSON.stringify(blobServiceClient.credential) + "\n";
|
|
22513
26129
|
const blockBlobClient = containerClient.getBlockBlobClient(file.name);
|
|
22514
|
-
|
|
26130
|
+
message += "Blob: Step 3\n";
|
|
22515
26131
|
const progressCallback = (e) => {
|
|
22516
26132
|
const progress = e.loadedBytes / file.size * 100;
|
|
22517
26133
|
onProgress && onProgress(Math.round(progress));
|
|
22518
26134
|
};
|
|
22519
|
-
|
|
26135
|
+
message += "Blob: Step 4\n";
|
|
22520
26136
|
await blockBlobClient.upload(file, file.size, { onProgress: progressCallback }).catch((error) => {
|
|
22521
|
-
|
|
26137
|
+
message += "\nErro on upload Azure\n";
|
|
26138
|
+
message += `
|
|
26139
|
+
File name: ${file.name}
|
|
26140
|
+
`;
|
|
26141
|
+
message += `File size: ${file.size}
|
|
26142
|
+
`;
|
|
26143
|
+
message += `File type: ${file.type}
|
|
26144
|
+
`;
|
|
22522
26145
|
throw error;
|
|
22523
26146
|
});
|
|
22524
|
-
|
|
26147
|
+
message += "Blob: Step 5\n";
|
|
22525
26148
|
} catch (err) {
|
|
26149
|
+
sendError(proctoringId);
|
|
22526
26150
|
throw err;
|
|
22527
26151
|
}
|
|
22528
26152
|
}
|
|
22529
26153
|
|
|
26154
|
+
// src/modules/http.ts
|
|
26155
|
+
var baseUrl = "https://proctoring-api.easyproctor.tech/api";
|
|
26156
|
+
async function setBaseUrl(homol) {
|
|
26157
|
+
console.log("homol -> ", homol);
|
|
26158
|
+
if (homol)
|
|
26159
|
+
baseUrl = "https://proctoring-api-hml.easyproctor.tech/api";
|
|
26160
|
+
}
|
|
26161
|
+
async function makeRequest(data) {
|
|
26162
|
+
const { url, method, body, jwt } = data;
|
|
26163
|
+
const resp = await fetch(baseUrl + url, {
|
|
26164
|
+
method,
|
|
26165
|
+
body: body != null ? JSON.stringify(body) : void 0,
|
|
26166
|
+
headers: {
|
|
26167
|
+
Authorization: `Bearer ${jwt}`,
|
|
26168
|
+
"Content-Type": "application/json",
|
|
26169
|
+
"Access-Control-Allow-Origin": "*"
|
|
26170
|
+
}
|
|
26171
|
+
});
|
|
26172
|
+
if (resp.status >= 400) {
|
|
26173
|
+
throw "N\xE3o foi poss\xEDvel realizar a requisi\xE7\xE3o, tente novamente mais tarde";
|
|
26174
|
+
}
|
|
26175
|
+
const content = resp.headers.get("content-type");
|
|
26176
|
+
const isJson = content ? content.includes("application/json") : false;
|
|
26177
|
+
const responseData = isJson ? await resp.json() : null;
|
|
26178
|
+
return responseData;
|
|
26179
|
+
}
|
|
26180
|
+
|
|
22530
26181
|
// src/modules/enumarateDevices.ts
|
|
22531
26182
|
async function enumarateDevices() {
|
|
22532
26183
|
const mediaDevices = await navigator.mediaDevices.enumerateDevices();
|
|
@@ -22636,7 +26287,7 @@ var defaultProctoringOptions = {
|
|
|
22636
26287
|
};
|
|
22637
26288
|
var azureBlobUrl = "";
|
|
22638
26289
|
var _captureScreen = true;
|
|
22639
|
-
function useProctoring(proctoringOptions,
|
|
26290
|
+
function useProctoring(proctoringOptions, homolConfig = false) {
|
|
22640
26291
|
["examId", "clientId", "token"].forEach((el) => {
|
|
22641
26292
|
const key = el;
|
|
22642
26293
|
if (!proctoringOptions[key]) {
|
|
@@ -22701,7 +26352,7 @@ function useProctoring(proctoringOptions, proctoringConfig) {
|
|
|
22701
26352
|
}
|
|
22702
26353
|
const { cameraStream, stopCameraRecording } = await startCameraCapture(cameraBuffer, { cameraId, microphoneId }, videoOptions);
|
|
22703
26354
|
startAudio();
|
|
22704
|
-
cancelCameraCapture = stopCameraRecording;
|
|
26355
|
+
cancelCameraCapture = await stopCameraRecording;
|
|
22705
26356
|
if (captureScreen) {
|
|
22706
26357
|
cancelCallback = async function() {
|
|
22707
26358
|
await Promise.all([cancelCameraCapture(), cancelScreenCapture()]);
|
|
@@ -22753,7 +26404,7 @@ function useProctoring(proctoringOptions, proctoringConfig) {
|
|
|
22753
26404
|
const finalCameraBuffer = cameraBuffer;
|
|
22754
26405
|
const finalAudioBuffer = buffer;
|
|
22755
26406
|
const finalScreenBuffer = screenBuffer;
|
|
22756
|
-
if (finalCameraBuffer
|
|
26407
|
+
if (!finalCameraBuffer) {
|
|
22757
26408
|
trackers.registerError(proctoringId, PROCTORING_NOT_STARTED);
|
|
22758
26409
|
throw PROCTORING_NOT_STARTED;
|
|
22759
26410
|
}
|
|
@@ -22772,22 +26423,15 @@ function useProctoring(proctoringOptions, proctoringConfig) {
|
|
|
22772
26423
|
return { cameraFile, audioFile, screenFile };
|
|
22773
26424
|
};
|
|
22774
26425
|
async function initConfig() {
|
|
22775
|
-
|
|
22776
|
-
|
|
22777
|
-
|
|
22778
|
-
|
|
22779
|
-
|
|
22780
|
-
}
|
|
22781
|
-
|
|
22782
|
-
|
|
22783
|
-
|
|
22784
|
-
jwt: proctoringOptions.token
|
|
22785
|
-
});
|
|
22786
|
-
setConfiguration(config.account, config.containerName, config.sas);
|
|
22787
|
-
azureBlobUrl = config.azureBlobUrl;
|
|
22788
|
-
setBaseUrl(config.baseUrl);
|
|
22789
|
-
init(config.insights);
|
|
22790
|
-
}
|
|
26426
|
+
setBaseUrl(homolConfig);
|
|
26427
|
+
const config = await makeRequest({
|
|
26428
|
+
url: `/AzureKey`,
|
|
26429
|
+
method: "GET",
|
|
26430
|
+
jwt: proctoringOptions.token
|
|
26431
|
+
});
|
|
26432
|
+
setConfiguration(config.account, config.containerName, config.sas);
|
|
26433
|
+
azureBlobUrl = config.azureBlobUrl;
|
|
26434
|
+
init(config.insights);
|
|
22791
26435
|
}
|
|
22792
26436
|
async function start(options = defaultProctoringOptions, videoOptions = { width: 640, height: 480 }) {
|
|
22793
26437
|
if (lastClick >= Date.now() - delay)
|
|
@@ -22938,6 +26582,7 @@ function useProctoring(proctoringOptions, proctoringConfig) {
|
|
|
22938
26582
|
}
|
|
22939
26583
|
try {
|
|
22940
26584
|
if (azureBlobUrl == "") {
|
|
26585
|
+
setBaseUrl(homolConfig);
|
|
22941
26586
|
const config = await makeRequest({
|
|
22942
26587
|
url: `/AzureKey`,
|
|
22943
26588
|
method: "GET",
|
|
@@ -22945,7 +26590,6 @@ function useProctoring(proctoringOptions, proctoringConfig) {
|
|
|
22945
26590
|
});
|
|
22946
26591
|
setConfiguration(config.account, config.containerName, config.sas);
|
|
22947
26592
|
azureBlobUrl = config.azureBlobUrl;
|
|
22948
|
-
setBaseUrl(config.baseUrl);
|
|
22949
26593
|
}
|
|
22950
26594
|
} catch (error) {
|
|
22951
26595
|
trackers.registerError(proctoringId, "Erro ao buscar credenciais!");
|
|
@@ -23054,7 +26698,7 @@ function useProctoring(proctoringOptions, proctoringConfig) {
|
|
|
23054
26698
|
uploadProgress[i] = progress;
|
|
23055
26699
|
handleOnProgress();
|
|
23056
26700
|
}
|
|
23057
|
-
}, proctoringId
|
|
26701
|
+
}, proctoringId);
|
|
23058
26702
|
});
|
|
23059
26703
|
await Promise.all(uploadPromises);
|
|
23060
26704
|
trackers.registerUploadVideo(proctoringId, true, "");
|
|
@@ -23088,3 +26732,283 @@ export {
|
|
|
23088
26732
|
* Microsoft Dynamic Proto Utility, 1.1.4
|
|
23089
26733
|
* Copyright (c) Microsoft and contributors. All rights reserved.
|
|
23090
26734
|
*/
|
|
26735
|
+
/**
|
|
26736
|
+
* CanvasRecorder is a standalone class used by {@link RecordRTC} to bring HTML5-Canvas recording into video WebM. It uses HTML2Canvas library and runs top over {@link Whammy}.
|
|
26737
|
+
* @summary HTML2Canvas recording into video WebM.
|
|
26738
|
+
* @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}
|
|
26739
|
+
* @author {@link https://MuazKhan.com|Muaz Khan}
|
|
26740
|
+
* @typedef CanvasRecorder
|
|
26741
|
+
* @class
|
|
26742
|
+
* @example
|
|
26743
|
+
* var recorder = new CanvasRecorder(htmlElement, { disableLogs: true, useWhammyRecorder: true });
|
|
26744
|
+
* recorder.record();
|
|
26745
|
+
* recorder.stop(function(blob) {
|
|
26746
|
+
* video.src = URL.createObjectURL(blob);
|
|
26747
|
+
* });
|
|
26748
|
+
* @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}
|
|
26749
|
+
* @param {HTMLElement} htmlElement - querySelector/getElementById/getElementsByTagName[0]/etc.
|
|
26750
|
+
* @param {object} config - {disableLogs:true, initCallback: function}
|
|
26751
|
+
*/
|
|
26752
|
+
/**
|
|
26753
|
+
* DiskStorage is a standalone object used by {@link RecordRTC} to store recorded blobs in IndexedDB storage.
|
|
26754
|
+
* @summary Writing blobs into IndexedDB.
|
|
26755
|
+
* @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}
|
|
26756
|
+
* @author {@link https://MuazKhan.com|Muaz Khan}
|
|
26757
|
+
* @example
|
|
26758
|
+
* DiskStorage.Store({
|
|
26759
|
+
* audioBlob: yourAudioBlob,
|
|
26760
|
+
* videoBlob: yourVideoBlob,
|
|
26761
|
+
* gifBlob : yourGifBlob
|
|
26762
|
+
* });
|
|
26763
|
+
* DiskStorage.Fetch(function(dataURL, type) {
|
|
26764
|
+
* if(type === 'audioBlob') { }
|
|
26765
|
+
* if(type === 'videoBlob') { }
|
|
26766
|
+
* if(type === 'gifBlob') { }
|
|
26767
|
+
* });
|
|
26768
|
+
* // DiskStorage.dataStoreName = 'recordRTC';
|
|
26769
|
+
* // DiskStorage.onError = function(error) { };
|
|
26770
|
+
* @property {function} init - This method must be called once to initialize IndexedDB ObjectStore. Though, it is auto-used internally.
|
|
26771
|
+
* @property {function} Fetch - This method fetches stored blobs from IndexedDB.
|
|
26772
|
+
* @property {function} Store - This method stores blobs in IndexedDB.
|
|
26773
|
+
* @property {function} onError - This function is invoked for any known/unknown error.
|
|
26774
|
+
* @property {string} dataStoreName - Name of the ObjectStore created in IndexedDB storage.
|
|
26775
|
+
* @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}
|
|
26776
|
+
*/
|
|
26777
|
+
/**
|
|
26778
|
+
* GifRecorder is standalone calss used by {@link RecordRTC} to record video or canvas into animated gif.
|
|
26779
|
+
* @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}
|
|
26780
|
+
* @author {@link https://MuazKhan.com|Muaz Khan}
|
|
26781
|
+
* @typedef GifRecorder
|
|
26782
|
+
* @class
|
|
26783
|
+
* @example
|
|
26784
|
+
* var recorder = new GifRecorder(mediaStream || canvas || context, { onGifPreview: function, onGifRecordingStarted: function, width: 1280, height: 720, frameRate: 200, quality: 10 });
|
|
26785
|
+
* recorder.record();
|
|
26786
|
+
* recorder.stop(function(blob) {
|
|
26787
|
+
* img.src = URL.createObjectURL(blob);
|
|
26788
|
+
* });
|
|
26789
|
+
* @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}
|
|
26790
|
+
* @param {MediaStream} mediaStream - MediaStream object or HTMLCanvasElement or CanvasRenderingContext2D.
|
|
26791
|
+
* @param {object} config - {disableLogs:true, initCallback: function, width: 320, height: 240, frameRate: 200, quality: 10}
|
|
26792
|
+
*/
|
|
26793
|
+
/**
|
|
26794
|
+
* MRecordRTC runs on top of {@link RecordRTC} to bring multiple recordings in a single place, by providing simple API.
|
|
26795
|
+
* @summary MRecordRTC stands for "Multiple-RecordRTC".
|
|
26796
|
+
* @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}
|
|
26797
|
+
* @author {@link https://MuazKhan.com|Muaz Khan}
|
|
26798
|
+
* @typedef MRecordRTC
|
|
26799
|
+
* @class
|
|
26800
|
+
* @example
|
|
26801
|
+
* var recorder = new MRecordRTC();
|
|
26802
|
+
* recorder.addStream(MediaStream);
|
|
26803
|
+
* recorder.mediaType = {
|
|
26804
|
+
* audio: true, // or StereoAudioRecorder or MediaStreamRecorder
|
|
26805
|
+
* video: true, // or WhammyRecorder or MediaStreamRecorder or WebAssemblyRecorder or CanvasRecorder
|
|
26806
|
+
* gif: true // or GifRecorder
|
|
26807
|
+
* };
|
|
26808
|
+
* // mimeType is optional and should be set only in advance cases.
|
|
26809
|
+
* recorder.mimeType = {
|
|
26810
|
+
* audio: 'audio/wav',
|
|
26811
|
+
* video: 'video/webm',
|
|
26812
|
+
* gif: 'image/gif'
|
|
26813
|
+
* };
|
|
26814
|
+
* recorder.startRecording();
|
|
26815
|
+
* @see For further information:
|
|
26816
|
+
* @see {@link https://github.com/muaz-khan/RecordRTC/tree/master/MRecordRTC|MRecordRTC Source Code}
|
|
26817
|
+
* @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API.
|
|
26818
|
+
* @requires {@link RecordRTC}
|
|
26819
|
+
*/
|
|
26820
|
+
/**
|
|
26821
|
+
* MediaStreamRecorder is an abstraction layer for {@link https://w3c.github.io/mediacapture-record/MediaRecorder.html|MediaRecorder API}. It is used by {@link RecordRTC} to record MediaStream(s) in both Chrome and Firefox.
|
|
26822
|
+
* @summary Runs top over {@link https://w3c.github.io/mediacapture-record/MediaRecorder.html|MediaRecorder API}.
|
|
26823
|
+
* @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}
|
|
26824
|
+
* @author {@link https://github.com/muaz-khan|Muaz Khan}
|
|
26825
|
+
* @typedef MediaStreamRecorder
|
|
26826
|
+
* @class
|
|
26827
|
+
* @example
|
|
26828
|
+
* var config = {
|
|
26829
|
+
* mimeType: 'video/webm', // vp8, vp9, h264, mkv, opus/vorbis
|
|
26830
|
+
* audioBitsPerSecond : 256 * 8 * 1024,
|
|
26831
|
+
* videoBitsPerSecond : 256 * 8 * 1024,
|
|
26832
|
+
* bitsPerSecond: 256 * 8 * 1024, // if this is provided, skip above two
|
|
26833
|
+
* checkForInactiveTracks: true,
|
|
26834
|
+
* timeSlice: 1000, // concatenate intervals based blobs
|
|
26835
|
+
* ondataavailable: function() {} // get intervals based blobs
|
|
26836
|
+
* }
|
|
26837
|
+
* var recorder = new MediaStreamRecorder(mediaStream, config);
|
|
26838
|
+
* recorder.record();
|
|
26839
|
+
* recorder.stop(function(blob) {
|
|
26840
|
+
* video.src = URL.createObjectURL(blob);
|
|
26841
|
+
*
|
|
26842
|
+
* // or
|
|
26843
|
+
* var blob = recorder.blob;
|
|
26844
|
+
* });
|
|
26845
|
+
* @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}
|
|
26846
|
+
* @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API.
|
|
26847
|
+
* @param {object} config - {disableLogs:true, initCallback: function, mimeType: "video/webm", timeSlice: 1000}
|
|
26848
|
+
* @throws Will throw an error if first argument "MediaStream" is missing. Also throws error if "MediaRecorder API" are not supported by the browser.
|
|
26849
|
+
*/
|
|
26850
|
+
/**
|
|
26851
|
+
* MultiStreamRecorder can record multiple videos in single container.
|
|
26852
|
+
* @summary Multi-videos recorder.
|
|
26853
|
+
* @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}
|
|
26854
|
+
* @author {@link https://MuazKhan.com|Muaz Khan}
|
|
26855
|
+
* @typedef MultiStreamRecorder
|
|
26856
|
+
* @class
|
|
26857
|
+
* @example
|
|
26858
|
+
* var options = {
|
|
26859
|
+
* mimeType: 'video/webm'
|
|
26860
|
+
* }
|
|
26861
|
+
* var recorder = new MultiStreamRecorder(ArrayOfMediaStreams, options);
|
|
26862
|
+
* recorder.record();
|
|
26863
|
+
* recorder.stop(function(blob) {
|
|
26864
|
+
* video.src = URL.createObjectURL(blob);
|
|
26865
|
+
*
|
|
26866
|
+
* // or
|
|
26867
|
+
* var blob = recorder.blob;
|
|
26868
|
+
* });
|
|
26869
|
+
* @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}
|
|
26870
|
+
* @param {MediaStreams} mediaStreams - Array of MediaStreams.
|
|
26871
|
+
* @param {object} config - {disableLogs:true, frameInterval: 1, mimeType: "video/webm"}
|
|
26872
|
+
*/
|
|
26873
|
+
/**
|
|
26874
|
+
* RecordRTCPromisesHandler adds promises support in {@link RecordRTC}. Try a {@link https://github.com/muaz-khan/RecordRTC/blob/master/simple-demos/RecordRTCPromisesHandler.html|demo here}
|
|
26875
|
+
* @summary Promises for {@link RecordRTC}
|
|
26876
|
+
* @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}
|
|
26877
|
+
* @author {@link https://MuazKhan.com|Muaz Khan}
|
|
26878
|
+
* @typedef RecordRTCPromisesHandler
|
|
26879
|
+
* @class
|
|
26880
|
+
* @example
|
|
26881
|
+
* var recorder = new RecordRTCPromisesHandler(mediaStream, options);
|
|
26882
|
+
* recorder.startRecording()
|
|
26883
|
+
* .then(successCB)
|
|
26884
|
+
* .catch(errorCB);
|
|
26885
|
+
* // Note: You can access all RecordRTC API using "recorder.recordRTC" e.g.
|
|
26886
|
+
* recorder.recordRTC.onStateChanged = function(state) {};
|
|
26887
|
+
* recorder.recordRTC.setRecordingDuration(5000);
|
|
26888
|
+
* @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}
|
|
26889
|
+
* @param {MediaStream} mediaStream - Single media-stream object, array of media-streams, html-canvas-element, etc.
|
|
26890
|
+
* @param {object} config - {type:"video", recorderType: MediaStreamRecorder, disableLogs: true, numberOfAudioChannels: 1, bufferSize: 0, sampleRate: 0, video: HTMLVideoElement, etc.}
|
|
26891
|
+
* @throws Will throw an error if "new" keyword is not used to initiate "RecordRTCPromisesHandler". Also throws error if first argument "MediaStream" is missing.
|
|
26892
|
+
* @requires {@link RecordRTC}
|
|
26893
|
+
*/
|
|
26894
|
+
/**
|
|
26895
|
+
* StereoAudioRecorder is a standalone class used by {@link RecordRTC} to bring "stereo" audio-recording in chrome.
|
|
26896
|
+
* @summary JavaScript standalone object for stereo audio recording.
|
|
26897
|
+
* @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}
|
|
26898
|
+
* @author {@link https://MuazKhan.com|Muaz Khan}
|
|
26899
|
+
* @typedef StereoAudioRecorder
|
|
26900
|
+
* @class
|
|
26901
|
+
* @example
|
|
26902
|
+
* var recorder = new StereoAudioRecorder(MediaStream, {
|
|
26903
|
+
* sampleRate: 44100,
|
|
26904
|
+
* bufferSize: 4096
|
|
26905
|
+
* });
|
|
26906
|
+
* recorder.record();
|
|
26907
|
+
* recorder.stop(function(blob) {
|
|
26908
|
+
* video.src = URL.createObjectURL(blob);
|
|
26909
|
+
* });
|
|
26910
|
+
* @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}
|
|
26911
|
+
* @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API.
|
|
26912
|
+
* @param {object} config - {sampleRate: 44100, bufferSize: 4096, numberOfAudioChannels: 1, etc.}
|
|
26913
|
+
*/
|
|
26914
|
+
/**
|
|
26915
|
+
* Storage is a standalone object used by {@link RecordRTC} to store reusable objects e.g. "new AudioContext".
|
|
26916
|
+
* @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}
|
|
26917
|
+
* @author {@link https://MuazKhan.com|Muaz Khan}
|
|
26918
|
+
* @example
|
|
26919
|
+
* Storage.AudioContext === webkitAudioContext
|
|
26920
|
+
* @property {webkitAudioContext} AudioContext - Keeps a reference to AudioContext object.
|
|
26921
|
+
* @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}
|
|
26922
|
+
*/
|
|
26923
|
+
/**
|
|
26924
|
+
* WebAssemblyRecorder lets you create webm videos in JavaScript via WebAssembly. The library consumes raw RGBA32 buffers (4 bytes per pixel) and turns them into a webm video with the given framerate and quality. This makes it compatible out-of-the-box with ImageData from a CANVAS. With realtime mode you can also use webm-wasm for streaming webm videos.
|
|
26925
|
+
* @summary Video recording feature in Chrome, Firefox and maybe Edge.
|
|
26926
|
+
* @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}
|
|
26927
|
+
* @author {@link https://MuazKhan.com|Muaz Khan}
|
|
26928
|
+
* @typedef WebAssemblyRecorder
|
|
26929
|
+
* @class
|
|
26930
|
+
* @example
|
|
26931
|
+
* var recorder = new WebAssemblyRecorder(mediaStream);
|
|
26932
|
+
* recorder.record();
|
|
26933
|
+
* recorder.stop(function(blob) {
|
|
26934
|
+
* video.src = URL.createObjectURL(blob);
|
|
26935
|
+
* });
|
|
26936
|
+
* @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}
|
|
26937
|
+
* @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API.
|
|
26938
|
+
* @param {object} config - {webAssemblyPath:'webm-wasm.wasm',workerPath: 'webm-worker.js', frameRate: 30, width: 1920, height: 1080, bitrate: 1024, realtime: true}
|
|
26939
|
+
*/
|
|
26940
|
+
/**
|
|
26941
|
+
* Whammy is a standalone class used by {@link RecordRTC} to bring video recording in Chrome. It is written by {@link https://github.com/antimatter15|antimatter15}
|
|
26942
|
+
* @summary A real time javascript webm encoder based on a canvas hack.
|
|
26943
|
+
* @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}
|
|
26944
|
+
* @author {@link https://MuazKhan.com|Muaz Khan}
|
|
26945
|
+
* @typedef Whammy
|
|
26946
|
+
* @class
|
|
26947
|
+
* @example
|
|
26948
|
+
* var recorder = new Whammy().Video(15);
|
|
26949
|
+
* recorder.add(context || canvas || dataURL);
|
|
26950
|
+
* var output = recorder.compile();
|
|
26951
|
+
* @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}
|
|
26952
|
+
*/
|
|
26953
|
+
/**
|
|
26954
|
+
* WhammyRecorder is a standalone class used by {@link RecordRTC} to bring video recording in Chrome. It runs top over {@link Whammy}.
|
|
26955
|
+
* @summary Video recording feature in Chrome.
|
|
26956
|
+
* @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}
|
|
26957
|
+
* @author {@link https://MuazKhan.com|Muaz Khan}
|
|
26958
|
+
* @typedef WhammyRecorder
|
|
26959
|
+
* @class
|
|
26960
|
+
* @example
|
|
26961
|
+
* var recorder = new WhammyRecorder(mediaStream);
|
|
26962
|
+
* recorder.record();
|
|
26963
|
+
* recorder.stop(function(blob) {
|
|
26964
|
+
* video.src = URL.createObjectURL(blob);
|
|
26965
|
+
* });
|
|
26966
|
+
* @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}
|
|
26967
|
+
* @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API.
|
|
26968
|
+
* @param {object} config - {disableLogs: true, initCallback: function, video: HTMLVideoElement, etc.}
|
|
26969
|
+
*/
|
|
26970
|
+
/**
|
|
26971
|
+
* {@link GetRecorderType} is an inner/private helper for {@link RecordRTC}.
|
|
26972
|
+
* @summary It returns best recorder-type available for your browser.
|
|
26973
|
+
* @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}
|
|
26974
|
+
* @author {@link https://MuazKhan.com|Muaz Khan}
|
|
26975
|
+
* @typedef GetRecorderType
|
|
26976
|
+
* @class
|
|
26977
|
+
* @example
|
|
26978
|
+
* var RecorderType = GetRecorderType(options);
|
|
26979
|
+
* var recorder = new RecorderType(options);
|
|
26980
|
+
* @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}
|
|
26981
|
+
* @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API.
|
|
26982
|
+
* @param {object} config - {type:"video", disableLogs: true, numberOfAudioChannels: 1, bufferSize: 0, sampleRate: 0, video: HTMLVideoElement, etc.}
|
|
26983
|
+
*/
|
|
26984
|
+
/**
|
|
26985
|
+
* {@link RecordRTCConfiguration} is an inner/private helper for {@link RecordRTC}.
|
|
26986
|
+
* @summary It configures the 2nd parameter passed over {@link RecordRTC} and returns a valid "config" object.
|
|
26987
|
+
* @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}
|
|
26988
|
+
* @author {@link https://MuazKhan.com|Muaz Khan}
|
|
26989
|
+
* @typedef RecordRTCConfiguration
|
|
26990
|
+
* @class
|
|
26991
|
+
* @example
|
|
26992
|
+
* var options = RecordRTCConfiguration(mediaStream, options);
|
|
26993
|
+
* @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}
|
|
26994
|
+
* @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API.
|
|
26995
|
+
* @param {object} config - {type:"video", disableLogs: true, numberOfAudioChannels: 1, bufferSize: 0, sampleRate: 0, video: HTMLVideoElement, getNativeBlob:true, etc.}
|
|
26996
|
+
*/
|
|
26997
|
+
/**
|
|
26998
|
+
* {@link https://github.com/muaz-khan/RecordRTC|RecordRTC} is a WebRTC JavaScript library for audio/video as well as screen activity recording. It supports Chrome, Firefox, Opera, Android, and Microsoft Edge. Platforms: Linux, Mac and Windows.
|
|
26999
|
+
* @summary Record audio, video or screen inside the browser.
|
|
27000
|
+
* @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}
|
|
27001
|
+
* @author {@link https://MuazKhan.com|Muaz Khan}
|
|
27002
|
+
* @typedef RecordRTC
|
|
27003
|
+
* @class
|
|
27004
|
+
* @example
|
|
27005
|
+
* var recorder = RecordRTC(mediaStream or [arrayOfMediaStream], {
|
|
27006
|
+
* type: 'video', // audio or video or gif or canvas
|
|
27007
|
+
* recorderType: MediaStreamRecorder || CanvasRecorder || StereoAudioRecorder || Etc
|
|
27008
|
+
* });
|
|
27009
|
+
* recorder.startRecording();
|
|
27010
|
+
* @see For further information:
|
|
27011
|
+
* @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}
|
|
27012
|
+
* @param {MediaStream} mediaStream - Single media-stream object, array of media-streams, html-canvas-element, etc.
|
|
27013
|
+
* @param {object} config - {type:"video", recorderType: MediaStreamRecorder, disableLogs: true, numberOfAudioChannels: 1, bufferSize: 0, sampleRate: 0, desiredSampRate: 16000, video: HTMLVideoElement, etc.}
|
|
27014
|
+
*/
|