videomail-client 16.0.2 → 16.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -19
- package/dist/cjs/index.cjs +340 -55
- package/dist/esm/client.d.ts +2 -0
- package/dist/esm/index.js +269 -53
- package/dist/esm/types/events/index.d.ts +3 -1
- package/dist/esm/types/events/params.d.ts +4 -0
- package/dist/esm/util/Despot.d.ts +2 -0
- package/dist/esm/util/html/media/AudioRecorder.d.ts +3 -0
- package/dist/esm/wrappers/container.d.ts +2 -0
- package/dist/esm/wrappers/form.d.ts +9 -2
- package/dist/esm/wrappers/visuals/recorder.d.ts +9 -0
- package/dist/esm/wrappers/visuals/userMedia.d.ts +8 -3
- package/dist/esm/wrappers/visuals.d.ts +3 -0
- package/dist/umd/index.js +280 -51
- package/package.json +3 -3
package/dist/esm/index.js
CHANGED
|
@@ -3620,7 +3620,7 @@ const constants = {
|
|
|
3620
3620
|
}
|
|
3621
3621
|
};
|
|
3622
3622
|
var package_namespaceObject = {
|
|
3623
|
-
rE: "16.0
|
|
3623
|
+
rE: "16.1.0"
|
|
3624
3624
|
};
|
|
3625
3625
|
function isAudioEnabled(options) {
|
|
3626
3626
|
return Boolean(options.audio.enabled);
|
|
@@ -4368,19 +4368,42 @@ class Form extends util_Despot {
|
|
|
4368
4368
|
if (type?.toLowerCase() === "hidden") inputElement.value = "";
|
|
4369
4369
|
}
|
|
4370
4370
|
}
|
|
4371
|
-
|
|
4371
|
+
connectSubmitButton() {
|
|
4372
4372
|
const submitButton = this.container.getSubmitButton();
|
|
4373
|
-
if (submitButton)
|
|
4373
|
+
if (!submitButton) return;
|
|
4374
|
+
if (submitButton.form === this.formElement) return;
|
|
4375
|
+
if (!this.formElement.id) {
|
|
4376
|
+
let formId;
|
|
4377
|
+
do formId = `videomail-form-${Form.nextFormId++}`;
|
|
4378
|
+
while (document.getElementById(formId))
|
|
4379
|
+
this.formElement.id = formId;
|
|
4380
|
+
this.generatedFormId = formId;
|
|
4381
|
+
}
|
|
4382
|
+
this.submitButton = submitButton;
|
|
4383
|
+
this.submitButtonFormAttribute = submitButton.getAttribute("form");
|
|
4384
|
+
submitButton.setAttribute("form", this.formElement.id);
|
|
4385
|
+
}
|
|
4386
|
+
startListeningToSubmitEvents() {
|
|
4387
|
+
this.connectSubmitButton();
|
|
4388
|
+
this.formElement.addEventListener("submit", this.handleSubmit);
|
|
4374
4389
|
}
|
|
4375
4390
|
stopListeningToSubmitEvents() {
|
|
4376
|
-
|
|
4377
|
-
if (submitButton)
|
|
4391
|
+
this.formElement.removeEventListener("submit", this.handleSubmit);
|
|
4392
|
+
if (this.submitButton) {
|
|
4393
|
+
if (null === this.submitButtonFormAttribute) this.submitButton.removeAttribute("form");
|
|
4394
|
+
else this.submitButton.setAttribute("form", this.submitButtonFormAttribute);
|
|
4395
|
+
this.submitButton = void 0;
|
|
4396
|
+
this.submitButtonFormAttribute = null;
|
|
4397
|
+
}
|
|
4398
|
+
if (this.generatedFormId === this.formElement.id) this.formElement.removeAttribute("id");
|
|
4399
|
+
this.generatedFormId = void 0;
|
|
4378
4400
|
}
|
|
4379
4401
|
async doTheSubmit(e) {
|
|
4380
4402
|
if (e) {
|
|
4381
4403
|
this.options.logger.debug(`Form: doTheSubmit(${string_pretty(e)})`);
|
|
4382
4404
|
e.preventDefault();
|
|
4383
4405
|
} else this.options.logger.debug("Form: doTheSubmit()");
|
|
4406
|
+
if (this.isSubmitting) return false;
|
|
4384
4407
|
const hasHostAction = this.formElement.hasAttribute("action");
|
|
4385
4408
|
const url = this.formElement.getAttribute("action") ?? this.options.apiUrl;
|
|
4386
4409
|
const method = this.formElement.getAttribute("method");
|
|
@@ -4395,7 +4418,14 @@ class Form extends util_Despot {
|
|
|
4395
4418
|
default:
|
|
4396
4419
|
chosenMethod = FormMethod.POST;
|
|
4397
4420
|
}
|
|
4398
|
-
if (this.container.hasElement())
|
|
4421
|
+
if (this.container.hasElement()) {
|
|
4422
|
+
this.isSubmitting = true;
|
|
4423
|
+
try {
|
|
4424
|
+
await this.container.submitAll(this.getData(), chosenMethod, url, hasHostAction);
|
|
4425
|
+
} finally{
|
|
4426
|
+
this.isSubmitting = false;
|
|
4427
|
+
}
|
|
4428
|
+
}
|
|
4399
4429
|
return false;
|
|
4400
4430
|
}
|
|
4401
4431
|
getInvalidElement() {
|
|
@@ -4416,9 +4446,11 @@ class Form extends util_Despot {
|
|
|
4416
4446
|
html_showElement(this.formElement);
|
|
4417
4447
|
}
|
|
4418
4448
|
constructor(container, formElement, options){
|
|
4419
|
-
super("Form", options), form_define_property(this, "container", void 0), form_define_property(this, "formElement", void 0), form_define_property(this, "validate", (event)=>{
|
|
4449
|
+
super("Form", options), form_define_property(this, "container", void 0), form_define_property(this, "formElement", void 0), form_define_property(this, "keyInput", void 0), form_define_property(this, "submitButton", void 0), form_define_property(this, "submitButtonFormAttribute", null), form_define_property(this, "generatedFormId", void 0), form_define_property(this, "isSubmitting", false), form_define_property(this, "FORM_FIELDS", {}), form_define_property(this, "validate", (event)=>{
|
|
4420
4450
|
this.container.validate(event);
|
|
4421
|
-
}), form_define_property(this, "
|
|
4451
|
+
}), form_define_property(this, "handleSubmit", (event)=>{
|
|
4452
|
+
if (!event.defaultPrevented) this.doTheSubmit(event);
|
|
4453
|
+
});
|
|
4422
4454
|
this.container = container;
|
|
4423
4455
|
this.formElement = formElement;
|
|
4424
4456
|
this.FORM_FIELDS = {
|
|
@@ -4434,6 +4466,7 @@ class Form extends util_Despot {
|
|
|
4434
4466
|
};
|
|
4435
4467
|
}
|
|
4436
4468
|
}
|
|
4469
|
+
form_define_property(Form, "nextFormId", 0);
|
|
4437
4470
|
const wrappers_form = Form;
|
|
4438
4471
|
function resource_define_property(obj, key, value) {
|
|
4439
4472
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
@@ -4970,7 +5003,7 @@ class Buttons extends util_Despot {
|
|
|
4970
5003
|
html_disableElement(radioButtonElement);
|
|
4971
5004
|
return radioButtonElement;
|
|
4972
5005
|
}
|
|
4973
|
-
makeButton(buttonClass, text, clickHandler, show, id, type, selector, disabled = true) {
|
|
5006
|
+
makeButton(buttonClass, text, clickHandler, show, id, type = "button", selector, disabled = true) {
|
|
4974
5007
|
let buttonElement;
|
|
4975
5008
|
buttonElement = id ? document.querySelector(`#${id}`) : selector ? document.querySelector(selector) : this.buttonsElement?.querySelector(`.${buttonClass}`);
|
|
4976
5009
|
if (buttonElement) buttonElement = html_adjustButton(buttonElement, show, type, disabled);
|
|
@@ -5727,10 +5760,14 @@ class RecorderInsides extends util_Despot {
|
|
|
5727
5760
|
this.on("USER_MEDIA_READY", ()=>{
|
|
5728
5761
|
this.facingMode?.show();
|
|
5729
5762
|
});
|
|
5763
|
+
this.on("CAMERA_RECOVERING", ()=>{
|
|
5764
|
+
this.facingMode?.hide();
|
|
5765
|
+
});
|
|
5730
5766
|
this.on("RECORDING", ()=>{
|
|
5731
5767
|
this.startRecording();
|
|
5732
5768
|
});
|
|
5733
5769
|
this.on("RESUMING", ()=>{
|
|
5770
|
+
this.hidePause();
|
|
5734
5771
|
this.resumeRecording();
|
|
5735
5772
|
});
|
|
5736
5773
|
this.on("STOPPING", ()=>{
|
|
@@ -6300,9 +6337,19 @@ class AudioRecorder {
|
|
|
6300
6337
|
const float32Array = e.inputBuffer.getChannelData(0);
|
|
6301
6338
|
cb(new audio_sample(float32Array));
|
|
6302
6339
|
}
|
|
6340
|
+
disconnect() {
|
|
6341
|
+
if (this.scriptProcessor) {
|
|
6342
|
+
this.scriptProcessor.onaudioprocess = null;
|
|
6343
|
+
this.scriptProcessor.disconnect();
|
|
6344
|
+
}
|
|
6345
|
+
this.audioInput?.disconnect();
|
|
6346
|
+
this.volume?.disconnect();
|
|
6347
|
+
}
|
|
6303
6348
|
init(localMediaStream) {
|
|
6304
6349
|
this.options.logger.debug("AudioRecorder: init()");
|
|
6350
|
+
this.disconnect();
|
|
6305
6351
|
const volume = this.getAudioContext().createGain();
|
|
6352
|
+
this.volume = volume;
|
|
6306
6353
|
try {
|
|
6307
6354
|
this.audioInput = this.getAudioContext().createMediaStreamSource(localMediaStream);
|
|
6308
6355
|
} catch (exc) {
|
|
@@ -6334,10 +6381,13 @@ class AudioRecorder {
|
|
|
6334
6381
|
this.onAudioProcess(e, cb);
|
|
6335
6382
|
};
|
|
6336
6383
|
}
|
|
6384
|
+
async resume() {
|
|
6385
|
+
const context = this.getAudioContext();
|
|
6386
|
+
if ("running" !== context.state) await context.resume();
|
|
6387
|
+
}
|
|
6337
6388
|
stop() {
|
|
6338
6389
|
this.options.logger.debug("AudioRecorder: stop()");
|
|
6339
|
-
|
|
6340
|
-
if (this.audioInput) this.audioInput.disconnect();
|
|
6390
|
+
this.disconnect();
|
|
6341
6391
|
if (this.hasAudioContext()) this.getAudioContext().close().then(()=>{
|
|
6342
6392
|
this.options.logger.debug("AudioRecorder: audio context is closed");
|
|
6343
6393
|
this.vcAudioContext = void 0;
|
|
@@ -6356,6 +6406,7 @@ class AudioRecorder {
|
|
|
6356
6406
|
constructor(userMedia, options){
|
|
6357
6407
|
AudioRecorder_define_property(this, "scriptProcessor", void 0);
|
|
6358
6408
|
AudioRecorder_define_property(this, "audioInput", void 0);
|
|
6409
|
+
AudioRecorder_define_property(this, "volume", void 0);
|
|
6359
6410
|
AudioRecorder_define_property(this, "vcAudioContext", void 0);
|
|
6360
6411
|
AudioRecorder_define_property(this, "userMedia", void 0);
|
|
6361
6412
|
AudioRecorder_define_property(this, "options", void 0);
|
|
@@ -6415,6 +6466,16 @@ class UserMedia extends util_Despot {
|
|
|
6415
6466
|
this.currentVisualStream = void 0;
|
|
6416
6467
|
}
|
|
6417
6468
|
}
|
|
6469
|
+
async restorePlayback() {
|
|
6470
|
+
if (!this.rawVisualUserMedia) throw new Error("No camera preview is available.");
|
|
6471
|
+
await this.rawVisualUserMedia.play();
|
|
6472
|
+
await this.audioRecorder?.resume();
|
|
6473
|
+
}
|
|
6474
|
+
hasLiveStream() {
|
|
6475
|
+
const videoReady = this.currentVisualStream?.getVideoTracks().some((track)=>"live" === track.readyState && track.enabled && !track.muted);
|
|
6476
|
+
const audioReady = !isAudioEnabled(this.options) || this.currentVisualStream?.getAudioTracks().some((track)=>"live" === track.readyState && track.enabled && !track.muted);
|
|
6477
|
+
return Boolean(this.currentVisualStream?.active && videoReady && audioReady);
|
|
6478
|
+
}
|
|
6418
6479
|
hasEnded() {
|
|
6419
6480
|
if (this.rawVisualUserMedia?.ended) return this.rawVisualUserMedia.ended;
|
|
6420
6481
|
return !this.currentVisualStream?.active;
|
|
@@ -6429,6 +6490,7 @@ class UserMedia extends util_Despot {
|
|
|
6429
6490
|
}
|
|
6430
6491
|
unloadRemainingEventListeners() {
|
|
6431
6492
|
this.options.logger.debug("UserMedia: unloadRemainingEventListeners()");
|
|
6493
|
+
this.clearInitializationListeners?.();
|
|
6432
6494
|
mediaEvents.forEach((eventName)=>{
|
|
6433
6495
|
this.rawVisualUserMedia?.removeEventListener(eventName, this.outputEvent);
|
|
6434
6496
|
});
|
|
@@ -6438,11 +6500,13 @@ class UserMedia extends util_Despot {
|
|
|
6438
6500
|
this.removeListener("SENDING_FIRST_FRAME");
|
|
6439
6501
|
this.audioRecorder?.record(audioCallback);
|
|
6440
6502
|
}
|
|
6441
|
-
init(localMediaStream, videoCallback, audioCallback, endedEarlyCallback,
|
|
6503
|
+
init(localMediaStream, videoCallback, audioCallback, endedEarlyCallback, params) {
|
|
6504
|
+
this.clearInitializationListeners?.();
|
|
6442
6505
|
this.stop(localMediaStream, {
|
|
6443
6506
|
aboutToInitialize: true,
|
|
6444
|
-
switchingFacingMode
|
|
6507
|
+
preserveRecordingState: Boolean(params?.switchingFacingMode || params?.recovering)
|
|
6445
6508
|
});
|
|
6509
|
+
const initializationId = ++this.initializationId;
|
|
6446
6510
|
this.onPlayReached = false;
|
|
6447
6511
|
this.onLoadedMetaDataReached = false;
|
|
6448
6512
|
this.playingPromiseReached = false;
|
|
@@ -6455,18 +6519,25 @@ class UserMedia extends util_Despot {
|
|
|
6455
6519
|
this.rawVisualUserMedia?.removeEventListener("play", onPlay);
|
|
6456
6520
|
this.rawVisualUserMedia?.removeEventListener("loadedmetadata", onLoadedMetaData);
|
|
6457
6521
|
};
|
|
6522
|
+
this.clearInitializationListeners = ()=>{
|
|
6523
|
+
this.rawVisualUserMedia?.removeEventListener("play", onPlay);
|
|
6524
|
+
this.rawVisualUserMedia?.removeEventListener("loadedmetadata", onLoadedMetaData);
|
|
6525
|
+
this.clearInitializationListeners = void 0;
|
|
6526
|
+
};
|
|
6458
6527
|
const play = ()=>{
|
|
6459
6528
|
try {
|
|
6460
6529
|
this.rawVisualUserMedia?.load();
|
|
6461
6530
|
if (this.rawVisualUserMedia?.paused) {
|
|
6462
6531
|
this.options.logger.debug(`UserMedia: play(): media.readyState=${this.rawVisualUserMedia.readyState}, media.paused=${this.rawVisualUserMedia.paused}, media.ended=${this.rawVisualUserMedia.ended}, media.played=${string_pretty(this.rawVisualUserMedia.played)}`);
|
|
6463
6532
|
this.rawVisualUserMedia.play().then(()=>{
|
|
6533
|
+
if (initializationId !== this.initializationId) return;
|
|
6464
6534
|
if (!this.playingPromiseReached) {
|
|
6465
6535
|
this.options.logger.debug("UserMedia: play promise successful. Playing now.");
|
|
6466
6536
|
this.playingPromiseReached = true;
|
|
6467
6537
|
}
|
|
6468
6538
|
}).catch((exc)=>{
|
|
6469
|
-
if (
|
|
6539
|
+
if (initializationId !== this.initializationId) return;
|
|
6540
|
+
if (exc instanceof Error && !params?.recovering) this.options.logger.warn(`Caught pending user media promise exception: ${exc.toString()}`);
|
|
6470
6541
|
else {
|
|
6471
6542
|
unloadAllEventListeners();
|
|
6472
6543
|
endedEarlyCallback(error_createError({
|
|
@@ -6487,16 +6558,28 @@ class UserMedia extends util_Despot {
|
|
|
6487
6558
|
this.options.logger.debug(`UserMedia: fireCallbacks(readyState=${readyState}, onPlayReached=${this.onPlayReached}, onLoadedMetaDataReached=${this.onLoadedMetaDataReached})`);
|
|
6488
6559
|
if (this.onPlayReached && this.onLoadedMetaDataReached) if (this.audioRecorder) try {
|
|
6489
6560
|
this.audioRecorder.init(localMediaStream);
|
|
6490
|
-
|
|
6491
|
-
this.
|
|
6492
|
-
|
|
6493
|
-
|
|
6561
|
+
const onAudioReady = ()=>{
|
|
6562
|
+
if (initializationId !== this.initializationId || this.currentVisualStream !== localMediaStream) return;
|
|
6563
|
+
if (this.recording) this.audioRecord(audioCallback);
|
|
6564
|
+
else this.on("SENDING_FIRST_FRAME", ()=>{
|
|
6565
|
+
this.audioRecord(audioCallback);
|
|
6566
|
+
});
|
|
6567
|
+
this.clearInitializationListeners?.();
|
|
6568
|
+
videoCallback();
|
|
6569
|
+
};
|
|
6570
|
+
if (params?.recovering) this.audioRecorder.resume().then(onAudioReady).catch(endedEarlyCallback);
|
|
6571
|
+
else onAudioReady();
|
|
6494
6572
|
} catch (exc) {
|
|
6495
6573
|
unloadAllEventListeners();
|
|
6496
|
-
this.stop(
|
|
6574
|
+
this.stop(void 0, {
|
|
6575
|
+
preserveRecordingState: Boolean(params?.recovering)
|
|
6576
|
+
});
|
|
6497
6577
|
endedEarlyCallback(exc);
|
|
6498
6578
|
}
|
|
6499
|
-
else
|
|
6579
|
+
else {
|
|
6580
|
+
this.clearInitializationListeners?.();
|
|
6581
|
+
videoCallback();
|
|
6582
|
+
}
|
|
6500
6583
|
};
|
|
6501
6584
|
const onPlay = ()=>{
|
|
6502
6585
|
try {
|
|
@@ -6566,9 +6649,8 @@ class UserMedia extends util_Despot {
|
|
|
6566
6649
|
this.setVisualStream(localMediaStream);
|
|
6567
6650
|
play();
|
|
6568
6651
|
} catch (exc) {
|
|
6569
|
-
|
|
6570
|
-
|
|
6571
|
-
});
|
|
6652
|
+
unloadAllEventListeners();
|
|
6653
|
+
endedEarlyCallback(exc);
|
|
6572
6654
|
}
|
|
6573
6655
|
}
|
|
6574
6656
|
getVideoTrackLabel() {
|
|
@@ -6581,6 +6663,8 @@ class UserMedia extends util_Despot {
|
|
|
6581
6663
|
try {
|
|
6582
6664
|
let chosenStream = visualStream;
|
|
6583
6665
|
if (!params?.aboutToInitialize) {
|
|
6666
|
+
this.initializationId++;
|
|
6667
|
+
this.clearInitializationListeners?.();
|
|
6584
6668
|
chosenStream ??= this.currentVisualStream;
|
|
6585
6669
|
const tracks = chosenStream?.getTracks();
|
|
6586
6670
|
if (tracks) tracks.forEach((track)=>{
|
|
@@ -6590,7 +6674,7 @@ class UserMedia extends util_Despot {
|
|
|
6590
6674
|
this.audioRecorder?.stop();
|
|
6591
6675
|
this.audioRecorder = void 0;
|
|
6592
6676
|
}
|
|
6593
|
-
if (!params?.
|
|
6677
|
+
if (!params?.preserveRecordingState) this.paused = this.recording = false;
|
|
6594
6678
|
} catch (exc) {
|
|
6595
6679
|
this.emit("ERROR", {
|
|
6596
6680
|
exc
|
|
@@ -6677,7 +6761,7 @@ class UserMedia extends util_Despot {
|
|
|
6677
6761
|
};
|
|
6678
6762
|
}
|
|
6679
6763
|
constructor(recorder, options){
|
|
6680
|
-
super("UserMedia", options), userMedia_define_property(this, "recorder", void 0), userMedia_define_property(this, "rawVisualUserMedia", void 0), userMedia_define_property(this, "paused", false), userMedia_define_property(this, "recording", false), userMedia_define_property(this, "audioRecorder", void 0), userMedia_define_property(this, "currentVisualStream", void 0), userMedia_define_property(this, "onPlayReached", false), userMedia_define_property(this, "onLoadedMetaDataReached", false), userMedia_define_property(this, "playingPromiseReached", false), userMedia_define_property(this, "videoTrackLabel", void 0), userMedia_define_property(this, "outputEvent", (e)=>{
|
|
6764
|
+
super("UserMedia", options), userMedia_define_property(this, "recorder", void 0), userMedia_define_property(this, "rawVisualUserMedia", void 0), userMedia_define_property(this, "paused", false), userMedia_define_property(this, "recording", false), userMedia_define_property(this, "audioRecorder", void 0), userMedia_define_property(this, "currentVisualStream", void 0), userMedia_define_property(this, "onPlayReached", false), userMedia_define_property(this, "onLoadedMetaDataReached", false), userMedia_define_property(this, "playingPromiseReached", false), userMedia_define_property(this, "videoTrackLabel", void 0), userMedia_define_property(this, "clearInitializationListeners", void 0), userMedia_define_property(this, "initializationId", 0), userMedia_define_property(this, "outputEvent", (e)=>{
|
|
6681
6765
|
this.logEvent(e.type, {
|
|
6682
6766
|
readyState: this.rawVisualUserMedia?.readyState
|
|
6683
6767
|
});
|
|
@@ -6938,7 +7022,9 @@ class Recorder extends util_Despot {
|
|
|
6938
7022
|
this.pingInterval = void 0;
|
|
6939
7023
|
}
|
|
6940
7024
|
onAudioSample(audioSample) {
|
|
6941
|
-
if (this.recordingTransportFailed) return;
|
|
7025
|
+
if (this.recordingTransportFailed || this.cameraRecovery) return;
|
|
7026
|
+
const sampleRate = this.userMedia?.getAudioSampleRate();
|
|
7027
|
+
if (sampleRate && sampleRate > 0) this.recordingAudioSampleRate ??= sampleRate;
|
|
6942
7028
|
this.samplesCount++;
|
|
6943
7029
|
this.mediaTransmissionStarted = true;
|
|
6944
7030
|
const audioBuffer = audioSample.toBuffer();
|
|
@@ -6951,19 +7037,26 @@ class Recorder extends util_Despot {
|
|
|
6951
7037
|
try {
|
|
6952
7038
|
this.options.logger.debug(`Recorder: onUserMediaReady(${params ? string_pretty(params) : ""})`);
|
|
6953
7039
|
const switchingFacingMode = params?.switchingFacingMode;
|
|
7040
|
+
if (params?.recovering) {
|
|
7041
|
+
if (!this.userMedia?.hasLiveStream()) return void this.failCameraRecovery(new Error("The restored camera has no live tracks."));
|
|
7042
|
+
if (void 0 !== this.recordingAudioSampleRate && this.userMedia.getAudioSampleRate() !== this.recordingAudioSampleRate) return void this.failCameraRecovery(new Error("The audio sample rate changed during recovery."));
|
|
7043
|
+
}
|
|
6954
7044
|
this.userMediaLoading = this.blocking = this.unloaded = this.submitting = false;
|
|
6955
7045
|
this.userMediaLoaded = true;
|
|
6956
7046
|
this.clearUserMediaTimeout();
|
|
6957
|
-
if (!switchingFacingMode) this.loop = this.createLoop();
|
|
7047
|
+
if (!switchingFacingMode && !params?.recovering) this.loop = this.createLoop();
|
|
6958
7048
|
this.show();
|
|
6959
7049
|
if (params?.recordWhenReady) this.record();
|
|
6960
7050
|
this.emit("USER_MEDIA_READY", {
|
|
6961
7051
|
switchingFacingMode: params?.switchingFacingMode,
|
|
7052
|
+
recovering: params?.recovering,
|
|
6962
7053
|
paused: this.isPaused(),
|
|
6963
7054
|
recordWhenReady: params?.recordWhenReady
|
|
6964
7055
|
});
|
|
7056
|
+
if (params?.recovering) this.finishCameraRecovery(true);
|
|
6965
7057
|
} catch (exc) {
|
|
6966
|
-
this.
|
|
7058
|
+
if (params?.recovering) this.failCameraRecovery(exc);
|
|
7059
|
+
else this.emit("ERROR", {
|
|
6967
7060
|
exc
|
|
6968
7061
|
});
|
|
6969
7062
|
}
|
|
@@ -7334,6 +7427,7 @@ class Recorder extends util_Despot {
|
|
|
7334
7427
|
return this.blocking;
|
|
7335
7428
|
}
|
|
7336
7429
|
userMediaErrorCallback(err, usedConstraints) {
|
|
7430
|
+
if (this.cameraRecovery) return void this.failCameraRecovery(err);
|
|
7337
7431
|
if (this.unloaded) return void this.options.logger.debug(`Recorder: already unloaded. Not going to throw error ${string_pretty(err)}`);
|
|
7338
7432
|
this.userMediaLoading = false;
|
|
7339
7433
|
this.clearUserMediaTimeout();
|
|
@@ -7365,7 +7459,7 @@ class Recorder extends util_Despot {
|
|
|
7365
7459
|
});
|
|
7366
7460
|
}
|
|
7367
7461
|
}
|
|
7368
|
-
getUserMediaCallback(localStream, params) {
|
|
7462
|
+
getUserMediaCallback(localStream, params, requestId = this.mediaRequestId) {
|
|
7369
7463
|
if (!this.userMedia) {
|
|
7370
7464
|
localStream.getTracks().forEach((track)=>{
|
|
7371
7465
|
track.stop();
|
|
@@ -7378,20 +7472,20 @@ class Recorder extends util_Despot {
|
|
|
7378
7472
|
this.options.logger.debug(`Recorder: getUserMediaCallback(${params ? string_pretty(params) : ""})`);
|
|
7379
7473
|
if (this.showUserMedia()) try {
|
|
7380
7474
|
this.userMedia.init(localStream, ()=>{
|
|
7381
|
-
if (!this.unloaded) this.onUserMediaReady(params);
|
|
7475
|
+
if (!this.unloaded && requestId === this.mediaRequestId) this.onUserMediaReady(params);
|
|
7382
7476
|
}, this.onAudioSample.bind(this), (err)=>{
|
|
7383
|
-
if (!this.unloaded) this.userMediaErrorCallback(err, {
|
|
7477
|
+
if (!this.unloaded && requestId === this.mediaRequestId) this.userMediaErrorCallback(err, {
|
|
7384
7478
|
audio: isAudioEnabled(this.options)
|
|
7385
7479
|
});
|
|
7386
|
-
}, params
|
|
7480
|
+
}, params);
|
|
7387
7481
|
} catch (exc) {
|
|
7388
7482
|
localStream.getTracks().forEach((track)=>{
|
|
7389
7483
|
track.stop();
|
|
7390
7484
|
});
|
|
7391
7485
|
this.userMediaLoading = false;
|
|
7392
7486
|
this.clearUserMediaTimeout();
|
|
7393
|
-
this.
|
|
7394
|
-
|
|
7487
|
+
this.userMediaErrorCallback(exc, {
|
|
7488
|
+
audio: isAudioEnabled(this.options)
|
|
7395
7489
|
});
|
|
7396
7490
|
}
|
|
7397
7491
|
else {
|
|
@@ -7400,12 +7494,14 @@ class Recorder extends util_Despot {
|
|
|
7400
7494
|
});
|
|
7401
7495
|
this.userMediaLoading = false;
|
|
7402
7496
|
this.clearUserMediaTimeout();
|
|
7497
|
+
this.cancelCameraRecovery();
|
|
7403
7498
|
}
|
|
7404
7499
|
}
|
|
7405
7500
|
loadGenuineUserMedia(params) {
|
|
7406
7501
|
this.options.logger.debug(`Recorder: loadGenuineUserMedia(${params ? string_pretty(params) : ""})`);
|
|
7407
7502
|
this.emit("ASKING_WEBCAM_PERMISSION");
|
|
7408
7503
|
this.userMediaLoading = true;
|
|
7504
|
+
const requestId = ++this.mediaRequestId;
|
|
7409
7505
|
const constraints = {
|
|
7410
7506
|
video: {
|
|
7411
7507
|
frameRate: {
|
|
@@ -7419,18 +7515,18 @@ class Recorder extends util_Despot {
|
|
|
7419
7515
|
this.options.logger.debug(string_summarize("Recorder: available webcam constraints are:", navigator.mediaDevices.getSupportedConstraints()));
|
|
7420
7516
|
const streamPromise = navigator.mediaDevices.getUserMedia(constraints);
|
|
7421
7517
|
streamPromise.then((localStream)=>{
|
|
7422
|
-
if (this.unloaded) return void localStream.getTracks().forEach((track)=>{
|
|
7518
|
+
if (this.unloaded || requestId !== this.mediaRequestId) return void localStream.getTracks().forEach((track)=>{
|
|
7423
7519
|
track.stop();
|
|
7424
7520
|
});
|
|
7425
|
-
this.getUserMediaCallback(localStream, params);
|
|
7521
|
+
this.getUserMediaCallback(localStream, params, requestId);
|
|
7426
7522
|
}).catch((reason)=>{
|
|
7427
|
-
if (!this.unloaded) this.userMediaErrorCallback(reason, constraints);
|
|
7523
|
+
if (!this.unloaded && requestId === this.mediaRequestId) this.userMediaErrorCallback(reason, constraints);
|
|
7428
7524
|
});
|
|
7429
7525
|
}
|
|
7430
7526
|
configureVideoConstraints(constraints, params) {
|
|
7431
7527
|
const videoConstraints = "object" == typeof constraints.video ? constraints.video : void 0;
|
|
7432
7528
|
if (!videoConstraints) return;
|
|
7433
|
-
if (params?.switchingFacingMode) videoConstraints.facingMode = params.switchingFacingMode;
|
|
7529
|
+
if (params?.switchingFacingMode || params?.recovering) videoConstraints.facingMode = params.switchingFacingMode || this.facingMode;
|
|
7434
7530
|
if (this.options.video.width) videoConstraints.width = {
|
|
7435
7531
|
ideal: this.options.video.width
|
|
7436
7532
|
};
|
|
@@ -7458,8 +7554,8 @@ class Recorder extends util_Despot {
|
|
|
7458
7554
|
if (!this.userMediaLoaded) {
|
|
7459
7555
|
this.userMediaLoading = false;
|
|
7460
7556
|
const err = util_getBrowser(this.options).getNoAccessIssue();
|
|
7461
|
-
this.
|
|
7462
|
-
|
|
7557
|
+
this.userMediaErrorCallback(err, {
|
|
7558
|
+
audio: isAudioEnabled(this.options)
|
|
7463
7559
|
});
|
|
7464
7560
|
}
|
|
7465
7561
|
}, this.options.timeouts.userMedia);
|
|
@@ -7469,6 +7565,7 @@ class Recorder extends util_Despot {
|
|
|
7469
7565
|
this.clearUserMediaTimeout();
|
|
7470
7566
|
this.options.logger.debug("Recorder: failed to load genuine user media");
|
|
7471
7567
|
this.userMediaLoading = false;
|
|
7568
|
+
if (this.cameraRecovery) return void this.failCameraRecovery(exc);
|
|
7472
7569
|
const errorListeners = this.getListeners("ERROR");
|
|
7473
7570
|
if (errorListeners?.length) this.emit("ERROR", {
|
|
7474
7571
|
exc
|
|
@@ -7592,9 +7689,10 @@ class Recorder extends util_Despot {
|
|
|
7592
7689
|
return this.recordingStats;
|
|
7593
7690
|
}
|
|
7594
7691
|
getAudioSampleRate() {
|
|
7595
|
-
return this.userMedia?.getAudioSampleRate();
|
|
7692
|
+
return this.recordingAudioSampleRate ?? this.userMedia?.getAudioSampleRate();
|
|
7596
7693
|
}
|
|
7597
7694
|
stop(params) {
|
|
7695
|
+
this.cancelCameraRecovery();
|
|
7598
7696
|
if (!this.userMedia) throw new Error("No user media defined, unable to stop");
|
|
7599
7697
|
this.options.logger.debug(`Recorder: stop(${params ? string_pretty(params) : ""})`);
|
|
7600
7698
|
this.recordingActive = false;
|
|
@@ -7620,7 +7718,7 @@ class Recorder extends util_Despot {
|
|
|
7620
7718
|
if (this.userMedia) this.recordingStats.videoTrackLabel = this.userMedia.getVideoTrackLabel();
|
|
7621
7719
|
if (isAudioEnabled(this.options) && this.userMedia) {
|
|
7622
7720
|
this.recordingStats.samplesCount = this.samplesCount;
|
|
7623
|
-
this.recordingStats.sampleRate = this.userMedia.getAudioSampleRate();
|
|
7721
|
+
this.recordingStats.sampleRate = this.recordingAudioSampleRate ?? this.userMedia.getAudioSampleRate();
|
|
7624
7722
|
}
|
|
7625
7723
|
this.writeCommand("stop", this.recordingStats, ()=>{
|
|
7626
7724
|
this.emit("STOPPED", {
|
|
@@ -7675,6 +7773,7 @@ class Recorder extends util_Despot {
|
|
|
7675
7773
|
this.built = this.connecting = this.connected = false;
|
|
7676
7774
|
}
|
|
7677
7775
|
reset() {
|
|
7776
|
+
this.cancelCameraRecovery();
|
|
7678
7777
|
if (!this.unloaded) {
|
|
7679
7778
|
this.options.logger.debug("Recorder: reset()");
|
|
7680
7779
|
this.emit("RESETTING");
|
|
@@ -7702,7 +7801,70 @@ class Recorder extends util_Despot {
|
|
|
7702
7801
|
isReady() {
|
|
7703
7802
|
return this.userMedia?.isReady();
|
|
7704
7803
|
}
|
|
7804
|
+
finishCameraRecovery(restored) {
|
|
7805
|
+
this.clearUserMediaTimeout();
|
|
7806
|
+
const resolve = this.resolveCameraRecovery;
|
|
7807
|
+
const resumeRequested = restored && this.resumeAfterCameraRecovery;
|
|
7808
|
+
this.cameraRecovery = void 0;
|
|
7809
|
+
this.resolveCameraRecovery = void 0;
|
|
7810
|
+
this.resumeAfterCameraRecovery = false;
|
|
7811
|
+
resolve?.(restored);
|
|
7812
|
+
if (resumeRequested && this.isPaused()) this.resume();
|
|
7813
|
+
}
|
|
7814
|
+
cancelCameraRecovery() {
|
|
7815
|
+
if (!this.cameraRecovery) return;
|
|
7816
|
+
this.mediaRequestId++;
|
|
7817
|
+
this.userMediaLoading = false;
|
|
7818
|
+
this.userMediaLoaded = false;
|
|
7819
|
+
this.clearUserMediaTimeout();
|
|
7820
|
+
this.userMedia?.stop(void 0, {
|
|
7821
|
+
preserveRecordingState: true
|
|
7822
|
+
});
|
|
7823
|
+
this.finishCameraRecovery(false);
|
|
7824
|
+
}
|
|
7825
|
+
failCameraRecovery(exc) {
|
|
7826
|
+
this.cancelCameraRecovery();
|
|
7827
|
+
const err = error_createError({
|
|
7828
|
+
message: "Camera recovery failed",
|
|
7829
|
+
explanation: "Your recording is still paused. Check camera permissions, then try Resume again or stop to keep the recorded part.",
|
|
7830
|
+
exc,
|
|
7831
|
+
options: this.options
|
|
7832
|
+
});
|
|
7833
|
+
this.emit("CAMERA_RECOVERY_FAILED", {
|
|
7834
|
+
err
|
|
7835
|
+
});
|
|
7836
|
+
}
|
|
7837
|
+
recoverCamera() {
|
|
7838
|
+
if (this.cameraRecovery) return this.cameraRecovery;
|
|
7839
|
+
if (!this.built || this.unloaded || !this.userMedia || this.userMediaLoading || this.submitting || this.key || void 0 !== this.stopTimeout || this.recordingTransportFailed) return Promise.resolve(false);
|
|
7840
|
+
const liveStream = this.userMedia.hasLiveStream();
|
|
7841
|
+
if (liveStream && this.isRecording()) return Promise.resolve(true);
|
|
7842
|
+
if (!liveStream && this.recordingActive && !this.isPaused()) this.pause();
|
|
7843
|
+
const recovery = new Promise((resolve)=>{
|
|
7844
|
+
this.resolveCameraRecovery = resolve;
|
|
7845
|
+
});
|
|
7846
|
+
this.cameraRecovery = recovery;
|
|
7847
|
+
this.emit("CAMERA_RECOVERING");
|
|
7848
|
+
if (liveStream) {
|
|
7849
|
+
this.userMediaTimeout = window.setTimeout(()=>{
|
|
7850
|
+
this.failCameraRecovery(new Error("Camera playback recovery timed out."));
|
|
7851
|
+
}, this.options.timeouts.userMedia);
|
|
7852
|
+
this.userMedia.restorePlayback().then(()=>{
|
|
7853
|
+
if (this.cameraRecovery === recovery) this.finishCameraRecovery(true);
|
|
7854
|
+
}).catch((exc)=>{
|
|
7855
|
+
if (this.cameraRecovery === recovery) this.failCameraRecovery(exc);
|
|
7856
|
+
});
|
|
7857
|
+
} else {
|
|
7858
|
+
this.userMediaLoaded = false;
|
|
7859
|
+
this.loadUserMedia({
|
|
7860
|
+
recovering: true
|
|
7861
|
+
});
|
|
7862
|
+
}
|
|
7863
|
+
return recovery;
|
|
7864
|
+
}
|
|
7705
7865
|
pause(params) {
|
|
7866
|
+
this.cancelCameraRecovery();
|
|
7867
|
+
this.resumeAfterDrain = false;
|
|
7706
7868
|
if (params) this.options.logger.debug(`pause() at frame ${this.framesCount} with ${string_pretty(params)}`);
|
|
7707
7869
|
else this.options.logger.debug(`pause() at frame ${this.framesCount}`);
|
|
7708
7870
|
this.userMedia?.pause();
|
|
@@ -7711,10 +7873,15 @@ class Recorder extends util_Despot {
|
|
|
7711
7873
|
this.sendPings();
|
|
7712
7874
|
}
|
|
7713
7875
|
resume() {
|
|
7876
|
+
if (this.cameraRecovery || !this.userMedia?.hasLiveStream()) {
|
|
7877
|
+
this.recoverCamera();
|
|
7878
|
+
this.resumeAfterCameraRecovery = Boolean(this.cameraRecovery);
|
|
7879
|
+
return;
|
|
7880
|
+
}
|
|
7714
7881
|
this.options.logger.debug(`Recorder: resume() with frame ${this.framesCount}`);
|
|
7715
7882
|
this.stopPings();
|
|
7716
7883
|
this.emit("RESUMING");
|
|
7717
|
-
this.userMedia
|
|
7884
|
+
this.userMedia.resume();
|
|
7718
7885
|
if (this.streamBackpressured) this.resumeAfterDrain = true;
|
|
7719
7886
|
else this.loop.start();
|
|
7720
7887
|
}
|
|
@@ -7769,7 +7936,7 @@ class Recorder extends util_Despot {
|
|
|
7769
7936
|
return newLoop;
|
|
7770
7937
|
}
|
|
7771
7938
|
record() {
|
|
7772
|
-
if (this.unloaded) return;
|
|
7939
|
+
if (this.unloaded || this.cameraRecovery) return;
|
|
7773
7940
|
if (!this.connected) {
|
|
7774
7941
|
this.options.logger.debug("Recorder: reconnecting before recording …");
|
|
7775
7942
|
this.initSocket(()=>{
|
|
@@ -7842,6 +8009,7 @@ class Recorder extends util_Despot {
|
|
|
7842
8009
|
this.recordingActive = true;
|
|
7843
8010
|
this.recordingTransportFailed = false;
|
|
7844
8011
|
this.mediaTransmissionStarted = false;
|
|
8012
|
+
this.recordingAudioSampleRate = void 0;
|
|
7845
8013
|
this.userMedia.record();
|
|
7846
8014
|
this.emit("RECORDING", {
|
|
7847
8015
|
framesCount: this.framesCount
|
|
@@ -7903,7 +8071,7 @@ class Recorder extends util_Despot {
|
|
|
7903
8071
|
}
|
|
7904
8072
|
}
|
|
7905
8073
|
switchFacingMode() {
|
|
7906
|
-
if (!util_getBrowser(this.options).isMobile()) return;
|
|
8074
|
+
if (this.cameraRecovery || !util_getBrowser(this.options).isMobile()) return;
|
|
7907
8075
|
if ("user" === this.facingMode) this.facingMode = "environment";
|
|
7908
8076
|
else if ("environment" === this.facingMode) this.facingMode = "user";
|
|
7909
8077
|
else this.options.logger.warn(`Recorder: unsupported facing mode ${string_pretty(this.facingMode)}`);
|
|
@@ -7914,12 +8082,14 @@ class Recorder extends util_Despot {
|
|
|
7914
8082
|
initEvents() {
|
|
7915
8083
|
this.options.logger.debug("Recorder: initEvents()");
|
|
7916
8084
|
this.on("SUBMITTING", ()=>{
|
|
8085
|
+
this.cancelCameraRecovery();
|
|
7917
8086
|
this.submitting = true;
|
|
7918
8087
|
});
|
|
7919
8088
|
this.on("SUBMITTED", ()=>{
|
|
7920
8089
|
this.submitting = false;
|
|
7921
8090
|
});
|
|
7922
8091
|
this.on("BLOCKING", ()=>{
|
|
8092
|
+
this.cancelCameraRecovery();
|
|
7923
8093
|
this.blocking = true;
|
|
7924
8094
|
this.clearUserMediaTimeout();
|
|
7925
8095
|
});
|
|
@@ -8093,7 +8263,7 @@ class Recorder extends util_Despot {
|
|
|
8093
8263
|
return this.userMediaLoaded;
|
|
8094
8264
|
}
|
|
8095
8265
|
constructor(visuals, replay, options){
|
|
8096
|
-
super("Recorder", options), recorder_define_property(this, "visuals", void 0), recorder_define_property(this, "replay", void 0), recorder_define_property(this, "pendingWrites", new boundedWriteQueue()), recorder_define_property(this, "loop", void 0), recorder_define_property(this, "originalAnimationFrameObject", void 0), recorder_define_property(this, "samplesCount", 0), recorder_define_property(this, "framesCount", 0), recorder_define_property(this, "recordingStats", void 0), recorder_define_property(this, "confirmedFrameNumber", 0), recorder_define_property(this, "confirmedSampleNumber", 0), recorder_define_property(this, "recorderElement", void 0), recorder_define_property(this, "userMedia", void 0), recorder_define_property(this, "userMediaTimeout", void 0), recorder_define_property(this, "retryTimeout", void 0), recorder_define_property(this, "reconnectTimeout", void 0), recorder_define_property(this, "connectionTimeout", void 0), recorder_define_property(this, "backpressureTimeout", void 0), recorder_define_property(this, "stopTimeout", void 0), recorder_define_property(this, "frameProgress", void 0), recorder_define_property(this, "sampleProgress", void 0), recorder_define_property(this, "canvas", void 0), recorder_define_property(this, "recordingDimensions", void 0), recorder_define_property(this, "ctx", void 0), recorder_define_property(this, "userMediaLoaded", void 0), recorder_define_property(this, "userMediaLoading", false), recorder_define_property(this, "submitting", false), recorder_define_property(this, "unloaded", void 0), recorder_define_property(this, "stopTime", void 0), recorder_define_property(this, "stream", void 0), recorder_define_property(this, "streamBackpressured", false), recorder_define_property(this, "resumeAfterDrain", false), recorder_define_property(this, "mediaTransmissionStarted", false), recorder_define_property(this, "recordingActive", false), recorder_define_property(this, "recordingTransportFailed", false), recorder_define_property(this, "connecting", false), recorder_define_property(this, "connected", false), recorder_define_property(this, "connectionFailed", false), recorder_define_property(this, "reconnecting", false), recorder_define_property(this, "reconnectAttempts", 0), recorder_define_property(this, "blocking", false), recorder_define_property(this, "built", false), recorder_define_property(this, "key", void 0), recorder_define_property(this, "waitingTime", void 0), recorder_define_property(this, "connectingStartedAt", void 0), recorder_define_property(this, "lastCloseEvent", void 0), recorder_define_property(this, "lastSocketError", void 0), recorder_define_property(this, "pingInterval", void 0), recorder_define_property(this, "frame", void 0), recorder_define_property(this, "recordingBuffer", void 0), recorder_define_property(this, "facingMode", void 0);
|
|
8266
|
+
super("Recorder", options), recorder_define_property(this, "visuals", void 0), recorder_define_property(this, "replay", void 0), recorder_define_property(this, "pendingWrites", new boundedWriteQueue()), recorder_define_property(this, "loop", void 0), recorder_define_property(this, "originalAnimationFrameObject", void 0), recorder_define_property(this, "samplesCount", 0), recorder_define_property(this, "framesCount", 0), recorder_define_property(this, "recordingAudioSampleRate", void 0), recorder_define_property(this, "recordingStats", void 0), recorder_define_property(this, "confirmedFrameNumber", 0), recorder_define_property(this, "confirmedSampleNumber", 0), recorder_define_property(this, "recorderElement", void 0), recorder_define_property(this, "userMedia", void 0), recorder_define_property(this, "userMediaTimeout", void 0), recorder_define_property(this, "retryTimeout", void 0), recorder_define_property(this, "reconnectTimeout", void 0), recorder_define_property(this, "connectionTimeout", void 0), recorder_define_property(this, "backpressureTimeout", void 0), recorder_define_property(this, "stopTimeout", void 0), recorder_define_property(this, "frameProgress", void 0), recorder_define_property(this, "sampleProgress", void 0), recorder_define_property(this, "canvas", void 0), recorder_define_property(this, "recordingDimensions", void 0), recorder_define_property(this, "ctx", void 0), recorder_define_property(this, "userMediaLoaded", void 0), recorder_define_property(this, "userMediaLoading", false), recorder_define_property(this, "mediaRequestId", 0), recorder_define_property(this, "cameraRecovery", void 0), recorder_define_property(this, "resolveCameraRecovery", void 0), recorder_define_property(this, "resumeAfterCameraRecovery", false), recorder_define_property(this, "submitting", false), recorder_define_property(this, "unloaded", void 0), recorder_define_property(this, "stopTime", void 0), recorder_define_property(this, "stream", void 0), recorder_define_property(this, "streamBackpressured", false), recorder_define_property(this, "resumeAfterDrain", false), recorder_define_property(this, "mediaTransmissionStarted", false), recorder_define_property(this, "recordingActive", false), recorder_define_property(this, "recordingTransportFailed", false), recorder_define_property(this, "connecting", false), recorder_define_property(this, "connected", false), recorder_define_property(this, "connectionFailed", false), recorder_define_property(this, "reconnecting", false), recorder_define_property(this, "reconnectAttempts", 0), recorder_define_property(this, "blocking", false), recorder_define_property(this, "built", false), recorder_define_property(this, "key", void 0), recorder_define_property(this, "waitingTime", void 0), recorder_define_property(this, "connectingStartedAt", void 0), recorder_define_property(this, "lastCloseEvent", void 0), recorder_define_property(this, "lastSocketError", void 0), recorder_define_property(this, "pingInterval", void 0), recorder_define_property(this, "frame", void 0), recorder_define_property(this, "recordingBuffer", void 0), recorder_define_property(this, "facingMode", void 0);
|
|
8097
8267
|
this.visuals = visuals;
|
|
8098
8268
|
this.replay = replay;
|
|
8099
8269
|
this.facingMode = options.video.facingMode;
|
|
@@ -8386,6 +8556,17 @@ class Visuals extends util_Despot {
|
|
|
8386
8556
|
this.endWaiting();
|
|
8387
8557
|
this.container.enableForm(false);
|
|
8388
8558
|
});
|
|
8559
|
+
this.on("CAMERA_RECOVERING", ()=>{
|
|
8560
|
+
this.clearCameraRecoveryNotice();
|
|
8561
|
+
});
|
|
8562
|
+
this.on("CAMERA_RECOVERY_FAILED", ({ err })=>{
|
|
8563
|
+
this.cameraRecoveryFailed = true;
|
|
8564
|
+
this.options.logger.warn(err);
|
|
8565
|
+
if (this.options.displayErrors) this.notifier.notify(err.message, err.explanation, {
|
|
8566
|
+
problem: true
|
|
8567
|
+
});
|
|
8568
|
+
this.endWaiting();
|
|
8569
|
+
});
|
|
8389
8570
|
this.on("PREVIEW", ()=>{
|
|
8390
8571
|
this.endWaiting();
|
|
8391
8572
|
});
|
|
@@ -8464,6 +8645,7 @@ class Visuals extends util_Despot {
|
|
|
8464
8645
|
child.remove();
|
|
8465
8646
|
}
|
|
8466
8647
|
reset() {
|
|
8648
|
+
this.clearCameraRecoveryNotice();
|
|
8467
8649
|
this.endWaiting();
|
|
8468
8650
|
this.recorder.reset();
|
|
8469
8651
|
}
|
|
@@ -8474,11 +8656,13 @@ class Visuals extends util_Despot {
|
|
|
8474
8656
|
this.container.endWaiting();
|
|
8475
8657
|
}
|
|
8476
8658
|
stop(params) {
|
|
8659
|
+
this.clearCameraRecoveryNotice();
|
|
8477
8660
|
this.recorder.stop(params);
|
|
8478
8661
|
this.recorderInsides.hidePause();
|
|
8479
8662
|
}
|
|
8480
8663
|
back(keepHidden = false, cb) {
|
|
8481
8664
|
this.options.logger.debug(`Visuals: back(keepHidden = ${keepHidden})`);
|
|
8665
|
+
this.cameraRecoveryFailed = false;
|
|
8482
8666
|
this.replay.hide();
|
|
8483
8667
|
this.notifier.hide();
|
|
8484
8668
|
if (keepHidden) {
|
|
@@ -8500,6 +8684,7 @@ class Visuals extends util_Despot {
|
|
|
8500
8684
|
if (!this.built) return;
|
|
8501
8685
|
const e = params?.e;
|
|
8502
8686
|
this.options.logger.debug(`Visuals: unload(${e ? string_pretty(e) : ""})`);
|
|
8687
|
+
this.cameraRecoveryFailed = false;
|
|
8503
8688
|
this.recorder.unload(params);
|
|
8504
8689
|
this.recorderInsides.unload();
|
|
8505
8690
|
this.replay.unload(params);
|
|
@@ -8513,13 +8698,31 @@ class Visuals extends util_Despot {
|
|
|
8513
8698
|
this.recorder.pause(params);
|
|
8514
8699
|
this.recorderInsides.showPause();
|
|
8515
8700
|
}
|
|
8701
|
+
clearCameraRecoveryNotice() {
|
|
8702
|
+
if (this.cameraRecoveryFailed) {
|
|
8703
|
+
this.notifier.hide();
|
|
8704
|
+
this.recorder.show();
|
|
8705
|
+
this.cameraRecoveryFailed = false;
|
|
8706
|
+
}
|
|
8707
|
+
}
|
|
8708
|
+
recoverCamera() {
|
|
8709
|
+
if (this.replay.isShown() || this.isNotifying() && !this.cameraRecoveryFailed) return Promise.resolve(false);
|
|
8710
|
+
this.clearCameraRecoveryNotice();
|
|
8711
|
+
return this.recorder.recoverCamera();
|
|
8712
|
+
}
|
|
8516
8713
|
resume() {
|
|
8517
|
-
|
|
8518
|
-
|
|
8519
|
-
|
|
8714
|
+
this.clearCameraRecoveryNotice();
|
|
8715
|
+
if (this.recorderInsides.isCountingDown()) {
|
|
8716
|
+
this.recorderInsides.resumeCountdown();
|
|
8717
|
+
this.recorderInsides.hidePause();
|
|
8718
|
+
} else {
|
|
8719
|
+
this.recorder.resume();
|
|
8720
|
+
if (!this.recorder.isPaused()) this.recorderInsides.hidePause();
|
|
8721
|
+
}
|
|
8520
8722
|
}
|
|
8521
8723
|
pauseOrResume() {
|
|
8522
|
-
if (this.
|
|
8724
|
+
if (this.cameraRecoveryFailed && this.recorder.isPaused()) this.resume();
|
|
8725
|
+
else if (this.isRecordable()) {
|
|
8523
8726
|
if (this.isRecording()) this.pause();
|
|
8524
8727
|
else if (this.recorder.isPaused()) this.resume();
|
|
8525
8728
|
else if (this.recorder.isReady()) this.recorder.record();
|
|
@@ -8641,7 +8844,7 @@ class Visuals extends util_Despot {
|
|
|
8641
8844
|
return this.visualsElement;
|
|
8642
8845
|
}
|
|
8643
8846
|
constructor(container, options){
|
|
8644
|
-
super("Visuals", options), visuals_define_property(this, "container", void 0), visuals_define_property(this, "replay", void 0), visuals_define_property(this, "recorder", void 0), visuals_define_property(this, "recorderInsides", void 0), visuals_define_property(this, "notifier", void 0), visuals_define_property(this, "visualsElement", void 0), visuals_define_property(this, "built", false);
|
|
8847
|
+
super("Visuals", options), visuals_define_property(this, "container", void 0), visuals_define_property(this, "replay", void 0), visuals_define_property(this, "recorder", void 0), visuals_define_property(this, "recorderInsides", void 0), visuals_define_property(this, "notifier", void 0), visuals_define_property(this, "visualsElement", void 0), visuals_define_property(this, "built", false), visuals_define_property(this, "cameraRecoveryFailed", false);
|
|
8645
8848
|
this.container = container;
|
|
8646
8849
|
this.replay = new visuals_replay(this, options);
|
|
8647
8850
|
this.recorder = new visuals_recorder(this, this.replay, options);
|
|
@@ -8743,10 +8946,10 @@ class Container extends util_Despot {
|
|
|
8743
8946
|
});
|
|
8744
8947
|
if (!playerOnly) this.stopListeningToVisibility = this.visibility.onChange((visible)=>{
|
|
8745
8948
|
if (this.built) if (visible) {
|
|
8746
|
-
if (isAutoPauseEnabled(this.options)
|
|
8949
|
+
if (isAutoPauseEnabled(this.options)) this.recoverCamera();
|
|
8747
8950
|
this.emit("VISIBLE");
|
|
8748
8951
|
} else {
|
|
8749
|
-
if (isAutoPauseEnabled(this.options)
|
|
8952
|
+
if (isAutoPauseEnabled(this.options)) this.suspend();
|
|
8750
8953
|
this.emit("INVISIBLE");
|
|
8751
8954
|
}
|
|
8752
8955
|
});
|
|
@@ -8934,6 +9137,13 @@ class Container extends util_Despot {
|
|
|
8934
9137
|
pause(params) {
|
|
8935
9138
|
this.visuals.pause(params);
|
|
8936
9139
|
}
|
|
9140
|
+
suspend() {
|
|
9141
|
+
if (this.built && (this.isCountingDown() || this.isRecording() || this.isPaused())) this.pause();
|
|
9142
|
+
}
|
|
9143
|
+
recoverCamera() {
|
|
9144
|
+
if (!this.built || this.hasError || this.submitted) return Promise.resolve(false);
|
|
9145
|
+
return this.visuals.recoverCamera();
|
|
9146
|
+
}
|
|
8937
9147
|
validate(event, force = false) {
|
|
8938
9148
|
let runValidation = true;
|
|
8939
9149
|
let valid = true;
|
|
@@ -9275,6 +9485,12 @@ class VideomailClient extends util_Despot {
|
|
|
9275
9485
|
record() {
|
|
9276
9486
|
this.container.record();
|
|
9277
9487
|
}
|
|
9488
|
+
pause() {
|
|
9489
|
+
this.container.suspend();
|
|
9490
|
+
}
|
|
9491
|
+
recoverCamera() {
|
|
9492
|
+
return this.container.recoverCamera();
|
|
9493
|
+
}
|
|
9278
9494
|
getLogLines() {
|
|
9279
9495
|
if (this.options.logger.getLines) return this.options.logger.getLines();
|
|
9280
9496
|
}
|