@lookit/record 4.0.0 → 5.0.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 +199 -8
- package/dist/index.browser.js +257 -39
- package/dist/index.browser.js.map +1 -1
- package/dist/index.browser.min.js +16 -16
- package/dist/index.browser.min.js.map +1 -1
- package/dist/index.cjs +256 -38
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +185 -14
- package/dist/index.js +256 -38
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/consentVideo.spec.ts +9 -1
- package/src/consentVideo.ts +10 -2
- package/src/errors.ts +28 -0
- package/src/index.spec.ts +835 -17
- package/src/recorder.spec.ts +677 -73
- package/src/recorder.ts +191 -35
- package/src/start.ts +51 -5
- package/src/stop.ts +56 -5
- package/src/trial.ts +128 -16
- package/src/types.ts +21 -0
- package/src/utils.spec.ts +129 -0
- package/src/utils.ts +45 -0
package/README.md
CHANGED
|
@@ -356,9 +356,28 @@ To use the CHS trial recording extension, you need to:
|
|
|
356
356
|
|
|
357
357
|
### Parameters
|
|
358
358
|
|
|
359
|
-
|
|
359
|
+
**`wait_for_upload_message` [`null` or HTML string | `null` ]**
|
|
360
360
|
|
|
361
|
-
|
|
361
|
+
This parameter determines what content should be displayed while the trial
|
|
362
|
+
recording is uploading. If `null` (the default), then the message 'uploading
|
|
363
|
+
video, please wait...' (or appropriate translation based on `locale`) will be
|
|
364
|
+
displayed. Otherwise this parameter can be set to a custom string and can
|
|
365
|
+
contain HTML markup. If you want to embed images/video/audio in this HTML
|
|
366
|
+
string, be sure to preload the media files with the `preload` plugin and
|
|
367
|
+
[manual preloading](https://www.jspsych.org/latest/overview/media-preloading/#manual-preloading).
|
|
368
|
+
Use a blank string (`""`) for no message/content. If a value is provided then
|
|
369
|
+
the `locale` parameter will be ignored.
|
|
370
|
+
|
|
371
|
+
**`max_upload_seconds` [ Integer | 10 ]**
|
|
372
|
+
|
|
373
|
+
Maximum duration (in seconds) to wait for the trial recording to finish
|
|
374
|
+
uploading before continuing with the experiment. If the maximum upload duration
|
|
375
|
+
is reached and the upload has not finished, then the experiment will move on and
|
|
376
|
+
the trial recording upload will continue in the background.
|
|
377
|
+
|
|
378
|
+
### Examples
|
|
379
|
+
|
|
380
|
+
**Basic usage**
|
|
362
381
|
|
|
363
382
|
To record a single trial, you will have to first load the extension in
|
|
364
383
|
`initJsPsych`.
|
|
@@ -375,7 +394,7 @@ record any trial you design.
|
|
|
375
394
|
|
|
376
395
|
```javascript
|
|
377
396
|
const trialRec = {
|
|
378
|
-
// ... Other trial
|
|
397
|
+
// ... Other trial parameters ...
|
|
379
398
|
extensions: [{ type: chsRecord.TrialRecordExtension }],
|
|
380
399
|
};
|
|
381
400
|
```
|
|
@@ -386,6 +405,81 @@ Finally, insert the trials into the timeline.
|
|
|
386
405
|
jsPsych.run([videoConfig, trialRec]);
|
|
387
406
|
```
|
|
388
407
|
|
|
408
|
+
**Setting parameters**
|
|
409
|
+
|
|
410
|
+
You can set the trial extension parameters when you load the extension with
|
|
411
|
+
`initJsPsych`.
|
|
412
|
+
|
|
413
|
+
In the example below, the default "uploading video, please wait..." message will
|
|
414
|
+
be displayed in French while a trial recording is uploading at the end of the
|
|
415
|
+
trial.
|
|
416
|
+
|
|
417
|
+
```javascript
|
|
418
|
+
const jsPsych = initJsPsych({
|
|
419
|
+
extensions: [
|
|
420
|
+
{
|
|
421
|
+
type: chsRecord.TrialRecordExtension,
|
|
422
|
+
params: { locale: "fr" },
|
|
423
|
+
},
|
|
424
|
+
],
|
|
425
|
+
});
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
And in this example, the custom message "Please wait!" will be displayed while
|
|
429
|
+
the trial recording is uploading. You can include any HTML-formatted content in
|
|
430
|
+
this string, which means you can display images, videos, animations etc.
|
|
431
|
+
|
|
432
|
+
```javascript
|
|
433
|
+
const jsPsych = initJsPsych({
|
|
434
|
+
extensions: [
|
|
435
|
+
{
|
|
436
|
+
type: chsRecord.TrialRecordExtension,
|
|
437
|
+
params: { wait_for_upload_message: "<div>Please wait!</div>" },
|
|
438
|
+
},
|
|
439
|
+
],
|
|
440
|
+
});
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
You can also set the parameters within individual trials. This will override any
|
|
444
|
+
parameters set during the extension initialization (in `initJsPsych`), which can
|
|
445
|
+
be useful if you want to change the parameter values during the experiment. In
|
|
446
|
+
this example, the `wait_for_upload_message` is set to an empty string, which
|
|
447
|
+
will prevent the default "uploading video, please wait..." message from
|
|
448
|
+
appearing after the trial finishes.
|
|
449
|
+
|
|
450
|
+
```javascript
|
|
451
|
+
const trialRec = {
|
|
452
|
+
// ... Other trial parameters ...
|
|
453
|
+
extensions: [
|
|
454
|
+
{
|
|
455
|
+
type: chsRecord.TrialRecordExtension,
|
|
456
|
+
params: { wait_for_upload_message: "" },
|
|
457
|
+
},
|
|
458
|
+
],
|
|
459
|
+
};
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
By default, the trial recording extension will wait up to 10 seconds for the
|
|
463
|
+
recording to finish uploading before moving on to the next trial. If the upload
|
|
464
|
+
does not finish in that time, it will continue to upload in the background. You
|
|
465
|
+
can adjust this duration with the `max_upload_seconds` parameter. You may want
|
|
466
|
+
to increase or decrease this duration depending on the duration of your recorded
|
|
467
|
+
trials, or you expect that some participants may have slow/unreliable internet
|
|
468
|
+
connections. This example decreases the maximum upload duration from 10 to 5
|
|
469
|
+
seconds:
|
|
470
|
+
|
|
471
|
+
```javascript
|
|
472
|
+
const trialRec = {
|
|
473
|
+
// ... Other trial parameters ...
|
|
474
|
+
extensions: [
|
|
475
|
+
{
|
|
476
|
+
type: chsRecord.TrialRecordExtension,
|
|
477
|
+
params: { max_upload_seconds: 5 },
|
|
478
|
+
},
|
|
479
|
+
],
|
|
480
|
+
};
|
|
481
|
+
```
|
|
482
|
+
|
|
389
483
|
## Session Recording
|
|
390
484
|
|
|
391
485
|
You might prefer to record across multiple trials in a study session. This can
|
|
@@ -414,8 +508,18 @@ const startRec = { type: chsRecord.StartRecordPlugin };
|
|
|
414
508
|
|
|
415
509
|
#### Parameters
|
|
416
510
|
|
|
417
|
-
|
|
418
|
-
|
|
511
|
+
**`wait_for_connection_message` [`null` or HTML string | `null` ]**
|
|
512
|
+
|
|
513
|
+
This parameter determines what content should be displayed while the session
|
|
514
|
+
recording is initializing. If `null` (the default), then the message
|
|
515
|
+
'establishing video connection, please wait' (or appropriate translation based
|
|
516
|
+
on `locale`) will be displayed. Otherwise this parameter can be set to a custom
|
|
517
|
+
string and can contain HTML markup. If you want to embed images/video/audio in
|
|
518
|
+
this HTML string, be sure to preload the media files with the `preload` plugin
|
|
519
|
+
and
|
|
520
|
+
[manual preloading](https://www.jspsych.org/latest/overview/media-preloading/#manual-preloading).
|
|
521
|
+
Use a blank string (`""`) for no message/content. If a value is provided then
|
|
522
|
+
the `locale` parameter will be ignored.
|
|
419
523
|
|
|
420
524
|
### Stop Recording Plugin
|
|
421
525
|
|
|
@@ -425,12 +529,44 @@ The plugin to stop session recording is called `chsRecord.StopRecordPlugin`.
|
|
|
425
529
|
const stopRec = { type: chsRecord.StopRecordPlugin };
|
|
426
530
|
```
|
|
427
531
|
|
|
532
|
+
When the trial starts, by default, this plugin will display "uploading video,
|
|
533
|
+
please wait...", or the appropriate translation based on the `locale` parameter.
|
|
534
|
+
This message can be customized using the `wait_for_upload_message` parameter,
|
|
535
|
+
which is the HTML-formatted string to be displayed while the session recording
|
|
536
|
+
is uploading.
|
|
537
|
+
|
|
538
|
+
```javascript
|
|
539
|
+
const stopRec = {
|
|
540
|
+
type: chsRecord.StopRecordPlugin,
|
|
541
|
+
wait_for_upload_message:
|
|
542
|
+
"<p style='color:red;'>Please wait while we upload your video.</p>",
|
|
543
|
+
};
|
|
544
|
+
```
|
|
545
|
+
|
|
428
546
|
#### Parameters
|
|
429
547
|
|
|
430
|
-
|
|
431
|
-
plugins.
|
|
548
|
+
**`wait_for_upload_message` [`null` or HTML string | `null` ]**
|
|
432
549
|
|
|
433
|
-
|
|
550
|
+
This parameter determines what content should be displayed while the session
|
|
551
|
+
recording is uploading. If `null` (the default), then the message 'uploading
|
|
552
|
+
video, please wait...' (or appropriate translation based on `locale`) will be
|
|
553
|
+
displayed. Otherwise this parameter can be set to a custom string and can
|
|
554
|
+
contain HTML markup. If you want to embed images/video/audio in this HTML
|
|
555
|
+
string, be sure to preload the media files with the `preload` plugin and
|
|
556
|
+
[manual preloading](https://www.jspsych.org/latest/overview/media-preloading/#manual-preloading).
|
|
557
|
+
Use a blank string (`""`) for no message/content. If a value is provided then
|
|
558
|
+
the `locale` parameter will be ignored.
|
|
559
|
+
|
|
560
|
+
**`max_upload_seconds` [ Integer | 10 ]**
|
|
561
|
+
|
|
562
|
+
Maximum duration (in seconds) to wait for the session recording to finish
|
|
563
|
+
uploading before continuing with the experiment. If the maximum upload duration
|
|
564
|
+
is reached and the upload has not finished, then the experiment will move on and
|
|
565
|
+
the session recording upload will continue in the background.
|
|
566
|
+
|
|
567
|
+
### Examples
|
|
568
|
+
|
|
569
|
+
**Basic usage**
|
|
434
570
|
|
|
435
571
|
First, make sure that you've added a video config trial to your experiment
|
|
436
572
|
timeline. Then, create your start and stop recording trials:
|
|
@@ -476,3 +612,58 @@ jsPsych.run([
|
|
|
476
612
|
stopRec,
|
|
477
613
|
]);
|
|
478
614
|
```
|
|
615
|
+
|
|
616
|
+
**Setting parameters**
|
|
617
|
+
|
|
618
|
+
By default, the start session recording plugin will display "establishing video
|
|
619
|
+
connection, please wait" while establishing the connection to our video storage,
|
|
620
|
+
and the stop session recording plugin will display "uploading video, please
|
|
621
|
+
wait..." while the session recording is uploading. You can set the `locale`
|
|
622
|
+
parameter value to translate these messages to another language. For example,
|
|
623
|
+
the trial below will display the Brazilian Portuguese translation of these
|
|
624
|
+
messages. If the locale string does not match any of the translation codes that
|
|
625
|
+
we support, then the message will be displayed in English.
|
|
626
|
+
|
|
627
|
+
```javascript
|
|
628
|
+
const startpRec = {
|
|
629
|
+
type: type: chsRecord.StartRecordPlugin,
|
|
630
|
+
locale: "pt-br",
|
|
631
|
+
};
|
|
632
|
+
const stopRec = {
|
|
633
|
+
type: chsRecord.StopRecordPlugin,
|
|
634
|
+
locale: "pt-br",
|
|
635
|
+
};
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
You can also set custom content to be displayed at the start of the session
|
|
639
|
+
recording, while it is initializing, and/or at the end, when the file is
|
|
640
|
+
uploading. The value must be a string. It can include HTML-formatted content,
|
|
641
|
+
which means that you can embed audio, video, images etc. (be sure to preload any
|
|
642
|
+
media files!).
|
|
643
|
+
|
|
644
|
+
```javascript
|
|
645
|
+
const startpRec = {
|
|
646
|
+
type: type: chsRecord.StartRecordPlugin,
|
|
647
|
+
wait_for_connection_message: "<p style='color:green;>Please wait...</p>"
|
|
648
|
+
};
|
|
649
|
+
const stopRec = {
|
|
650
|
+
type: chsRecord.StopRecordPlugin,
|
|
651
|
+
wait_for_upload_message: "<p style='color:red;'>Hang on a sec!</p>",
|
|
652
|
+
};
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
By default, the stop session recording plugin will wait up to 10 seconds for the
|
|
656
|
+
session recording to finish uploading before moving on with the experiment. If
|
|
657
|
+
the upload does not finish in that time, it will continue to upload in the
|
|
658
|
+
background. You can adjust this duration with the `max_upload_seconds`
|
|
659
|
+
parameter. You may want to increase this duration if, for example, your
|
|
660
|
+
experiment creates a very long session recording, or you expect that some
|
|
661
|
+
participants may have slow/unreliable internet connections. This example
|
|
662
|
+
increases the maximum upload duration from 10 to 20 seconds:
|
|
663
|
+
|
|
664
|
+
```javascript
|
|
665
|
+
const stopRec = {
|
|
666
|
+
type: chsRecord.StopRecordPlugin,
|
|
667
|
+
max_upload_seconds: 20,
|
|
668
|
+
};
|
|
669
|
+
```
|
package/dist/index.browser.js
CHANGED
|
@@ -32,7 +32,7 @@ var chsRecord = (function (Data, chsTemplates, jspsych) {
|
|
|
32
32
|
|
|
33
33
|
var _package = {
|
|
34
34
|
name: "@lookit/record",
|
|
35
|
-
version: "
|
|
35
|
+
version: "5.0.0",
|
|
36
36
|
description: "Recording extensions and plugins for CHS studies.",
|
|
37
37
|
homepage: "https://github.com/lookit/lookit-jspsych#readme",
|
|
38
38
|
bugs: {
|
|
@@ -73,8 +73,8 @@ var chsRecord = (function (Data, chsTemplates, jspsych) {
|
|
|
73
73
|
typescript: "^5.6.2"
|
|
74
74
|
},
|
|
75
75
|
peerDependencies: {
|
|
76
|
-
"@lookit/data": "^0.
|
|
77
|
-
"@lookit/templates": "^
|
|
76
|
+
"@lookit/data": "^0.3.0",
|
|
77
|
+
"@lookit/templates": "^3.0.0",
|
|
78
78
|
jspsych: "^8.0.3"
|
|
79
79
|
}
|
|
80
80
|
};
|
|
@@ -149,6 +149,12 @@ var chsRecord = (function (Data, chsTemplates, jspsych) {
|
|
|
149
149
|
this.name = "S3UndefinedError";
|
|
150
150
|
}
|
|
151
151
|
}
|
|
152
|
+
class NoFileNameError extends Error {
|
|
153
|
+
constructor() {
|
|
154
|
+
super("No filename found for recording.");
|
|
155
|
+
this.name = "NoFileNameError";
|
|
156
|
+
}
|
|
157
|
+
}
|
|
152
158
|
class StreamActiveOnResetError extends Error {
|
|
153
159
|
constructor() {
|
|
154
160
|
super("Won't reset recorder. Stream is still active.");
|
|
@@ -173,6 +179,12 @@ var chsRecord = (function (Data, chsTemplates, jspsych) {
|
|
|
173
179
|
this.name = "ElementNotFoundError";
|
|
174
180
|
}
|
|
175
181
|
}
|
|
182
|
+
class TimeoutError extends Error {
|
|
183
|
+
constructor(msg) {
|
|
184
|
+
super(`${msg}`);
|
|
185
|
+
this.name = "TimeoutError";
|
|
186
|
+
}
|
|
187
|
+
}
|
|
176
188
|
|
|
177
189
|
// Gets all non-builtin properties up the prototype chain.
|
|
178
190
|
const getAllProperties = object => {
|
|
@@ -8465,6 +8477,31 @@ var chsRecord = (function (Data, chsTemplates, jspsych) {
|
|
|
8465
8477
|
|
|
8466
8478
|
var img$7 = "data:image/svg+xml,%3c%3fxml version='1.0' encoding='utf-8' %3f%3e%3csvg viewBox='-1 -1 18 18' xmlns='http://www.w3.org/2000/svg'%3e %3ccircle fill='red' stroke='black' stroke-width='0.5' cx='8' cy='8' r='8'%3e%3c/circle%3e%3c/svg%3e";
|
|
8467
8479
|
|
|
8480
|
+
const promiseWithTimeout = (promise, promiseId, timeoutMs, onTimeoutCleanup) => {
|
|
8481
|
+
let timeoutHandle;
|
|
8482
|
+
const timeout = new Promise((resolve) => {
|
|
8483
|
+
timeoutHandle = setTimeout(() => {
|
|
8484
|
+
onTimeoutCleanup?.();
|
|
8485
|
+
resolve("timeout");
|
|
8486
|
+
}, timeoutMs);
|
|
8487
|
+
});
|
|
8488
|
+
return Promise.race([promise, timeout]).then(
|
|
8489
|
+
(value) => {
|
|
8490
|
+
if (value == "timeout") {
|
|
8491
|
+
console.log(`Upload for ${promiseId} timed out.`);
|
|
8492
|
+
} else {
|
|
8493
|
+
console.log(`Upload for ${promiseId} completed.`);
|
|
8494
|
+
clearTimeout(timeoutHandle);
|
|
8495
|
+
}
|
|
8496
|
+
return value;
|
|
8497
|
+
},
|
|
8498
|
+
(err) => {
|
|
8499
|
+
clearTimeout(timeoutHandle);
|
|
8500
|
+
throw err;
|
|
8501
|
+
}
|
|
8502
|
+
);
|
|
8503
|
+
};
|
|
8504
|
+
|
|
8468
8505
|
class Recorder {
|
|
8469
8506
|
constructor(jsPsych) {
|
|
8470
8507
|
this.jsPsych = jsPsych;
|
|
@@ -8569,13 +8606,73 @@ var chsRecord = (function (Data, chsTemplates, jspsych) {
|
|
|
8569
8606
|
this.recorder.stop();
|
|
8570
8607
|
this.stream.getTracks().map((t) => t.stop());
|
|
8571
8608
|
}
|
|
8572
|
-
stop(
|
|
8609
|
+
stop({
|
|
8610
|
+
maintain_container_size = false,
|
|
8611
|
+
stop_timeout_ms = null,
|
|
8612
|
+
upload_timeout_ms = 1e4
|
|
8613
|
+
} = {}) {
|
|
8614
|
+
this.preStopCheck();
|
|
8573
8615
|
this.clearWebcamFeed(maintain_container_size);
|
|
8574
8616
|
this.stopTracks();
|
|
8575
|
-
|
|
8576
|
-
|
|
8577
|
-
|
|
8578
|
-
|
|
8617
|
+
const snapshot = {
|
|
8618
|
+
s3: !this.localDownload ? this.s3 : null,
|
|
8619
|
+
filename: this.filename,
|
|
8620
|
+
localDownload: this.localDownload,
|
|
8621
|
+
url: "null"
|
|
8622
|
+
};
|
|
8623
|
+
const stopped = stop_timeout_ms ? promiseWithTimeout(
|
|
8624
|
+
this.stopPromise,
|
|
8625
|
+
`${snapshot.filename}-stopped`,
|
|
8626
|
+
stop_timeout_ms,
|
|
8627
|
+
this.createTimeoutHandler("stop", snapshot.filename)
|
|
8628
|
+
) : this.stopPromise;
|
|
8629
|
+
stopped.finally(() => {
|
|
8630
|
+
try {
|
|
8631
|
+
this.reset();
|
|
8632
|
+
} catch (err) {
|
|
8633
|
+
console.error("Error while resetting recorder after stop: ", err);
|
|
8634
|
+
}
|
|
8635
|
+
});
|
|
8636
|
+
const uploadPromise = (async () => {
|
|
8637
|
+
let url;
|
|
8638
|
+
try {
|
|
8639
|
+
url = await stopped;
|
|
8640
|
+
if (url == "timeout") {
|
|
8641
|
+
throw new TimeoutError("Recorder stop timed out.");
|
|
8642
|
+
}
|
|
8643
|
+
} catch (err) {
|
|
8644
|
+
console.warn("Upload failed because recorder stop timed out");
|
|
8645
|
+
throw err;
|
|
8646
|
+
}
|
|
8647
|
+
snapshot.url = url;
|
|
8648
|
+
if (snapshot.localDownload) {
|
|
8649
|
+
try {
|
|
8650
|
+
this.download(snapshot.filename, snapshot.url);
|
|
8651
|
+
await Promise.resolve();
|
|
8652
|
+
} catch (err) {
|
|
8653
|
+
console.error("Local download failed: ", err);
|
|
8654
|
+
throw err;
|
|
8655
|
+
}
|
|
8656
|
+
} else {
|
|
8657
|
+
try {
|
|
8658
|
+
await snapshot.s3.completeUpload();
|
|
8659
|
+
} catch (err) {
|
|
8660
|
+
console.error("Upload failed: ", err);
|
|
8661
|
+
throw err;
|
|
8662
|
+
}
|
|
8663
|
+
}
|
|
8664
|
+
})();
|
|
8665
|
+
const uploaded = upload_timeout_ms ? promiseWithTimeout(
|
|
8666
|
+
uploadPromise,
|
|
8667
|
+
`${snapshot.filename}-uploaded`,
|
|
8668
|
+
upload_timeout_ms,
|
|
8669
|
+
this.createTimeoutHandler("upload", snapshot.filename)
|
|
8670
|
+
) : uploadPromise;
|
|
8671
|
+
window.chs.pendingUploads.push({
|
|
8672
|
+
promise: uploadPromise,
|
|
8673
|
+
file: snapshot.filename
|
|
8674
|
+
});
|
|
8675
|
+
return { stopped, uploaded };
|
|
8579
8676
|
}
|
|
8580
8677
|
initializeCheck() {
|
|
8581
8678
|
if (!this.recorder) {
|
|
@@ -8588,18 +8685,27 @@ var chsRecord = (function (Data, chsTemplates, jspsych) {
|
|
|
8588
8685
|
throw new StreamDataInitializeError();
|
|
8589
8686
|
}
|
|
8590
8687
|
}
|
|
8688
|
+
preStopCheck() {
|
|
8689
|
+
if (!this.recorder) {
|
|
8690
|
+
throw new RecorderInitializeError();
|
|
8691
|
+
}
|
|
8692
|
+
if (!this.stream.active) {
|
|
8693
|
+
throw new StreamInactiveInitializeError();
|
|
8694
|
+
}
|
|
8695
|
+
if (!this.stopPromise) {
|
|
8696
|
+
throw new NoStopPromiseError();
|
|
8697
|
+
}
|
|
8698
|
+
if (!this.filename) {
|
|
8699
|
+
throw new NoFileNameError();
|
|
8700
|
+
}
|
|
8701
|
+
}
|
|
8591
8702
|
handleStop(resolve) {
|
|
8592
|
-
return
|
|
8703
|
+
return () => {
|
|
8593
8704
|
if (this.blobs.length === 0) {
|
|
8594
8705
|
throw new CreateURLError();
|
|
8595
8706
|
}
|
|
8596
8707
|
this.url = URL.createObjectURL(new Blob(this.blobs));
|
|
8597
|
-
|
|
8598
|
-
this.download();
|
|
8599
|
-
} else {
|
|
8600
|
-
await this.s3.completeUpload();
|
|
8601
|
-
}
|
|
8602
|
-
resolve();
|
|
8708
|
+
resolve(this.url);
|
|
8603
8709
|
};
|
|
8604
8710
|
}
|
|
8605
8711
|
handleDataAvailable(event) {
|
|
@@ -8608,11 +8714,11 @@ var chsRecord = (function (Data, chsTemplates, jspsych) {
|
|
|
8608
8714
|
this.s3.onDataAvailable(event.data);
|
|
8609
8715
|
}
|
|
8610
8716
|
}
|
|
8611
|
-
download() {
|
|
8612
|
-
if (
|
|
8717
|
+
download(filename, url) {
|
|
8718
|
+
if (filename && url) {
|
|
8613
8719
|
const link = document.createElement("a");
|
|
8614
|
-
link.href =
|
|
8615
|
-
link.download =
|
|
8720
|
+
link.href = url;
|
|
8721
|
+
link.download = filename;
|
|
8616
8722
|
link.click();
|
|
8617
8723
|
}
|
|
8618
8724
|
}
|
|
@@ -8641,6 +8747,18 @@ var chsRecord = (function (Data, chsTemplates, jspsych) {
|
|
|
8641
8747
|
const rand_digits = Math.floor(Math.random() * 1e3);
|
|
8642
8748
|
return `${prefix}_${window.chs.study.id}_${trial_id}_${window.chs.response.id}_${new Date().getTime()}_${rand_digits}.webm`;
|
|
8643
8749
|
}
|
|
8750
|
+
createTimeoutHandler(eventName, id) {
|
|
8751
|
+
return () => {
|
|
8752
|
+
console.warn(`Recorder ${eventName} timed out: ${id}`);
|
|
8753
|
+
if (!this.stream.active) {
|
|
8754
|
+
try {
|
|
8755
|
+
this.reset();
|
|
8756
|
+
} catch (err) {
|
|
8757
|
+
console.error("Error while resetting recorder after timeout: ", err);
|
|
8758
|
+
}
|
|
8759
|
+
}
|
|
8760
|
+
};
|
|
8761
|
+
}
|
|
8644
8762
|
}
|
|
8645
8763
|
|
|
8646
8764
|
const info$3 = {
|
|
@@ -8693,6 +8811,11 @@ var chsRecord = (function (Data, chsTemplates, jspsych) {
|
|
|
8693
8811
|
prompt_only_adults: { type: jspsych.ParameterType.BOOL, default: false },
|
|
8694
8812
|
consent_statement_text: { type: jspsych.ParameterType.STRING, default: "" },
|
|
8695
8813
|
omit_injury_phrase: { type: jspsych.ParameterType.BOOL, default: false }
|
|
8814
|
+
},
|
|
8815
|
+
data: {
|
|
8816
|
+
chs_type: {
|
|
8817
|
+
type: jspsych.ParameterType.STRING
|
|
8818
|
+
}
|
|
8696
8819
|
}
|
|
8697
8820
|
};
|
|
8698
8821
|
class VideoConsentPlugin {
|
|
@@ -8822,8 +8945,10 @@ var chsRecord = (function (Data, chsTemplates, jspsych) {
|
|
|
8822
8945
|
stop.addEventListener("click", async () => {
|
|
8823
8946
|
stop.disabled = true;
|
|
8824
8947
|
this.addMessage(display, this.uploadingMsg);
|
|
8825
|
-
|
|
8826
|
-
|
|
8948
|
+
const { stopped, uploaded } = this.recorder.stop({
|
|
8949
|
+
maintain_container_size: true
|
|
8950
|
+
});
|
|
8951
|
+
await stopped;
|
|
8827
8952
|
this.recordFeed(display);
|
|
8828
8953
|
this.getImg(display, "record-icon").style.visibility = "hidden";
|
|
8829
8954
|
this.addMessage(display, this.notRecordingMsg);
|
|
@@ -8846,7 +8971,21 @@ var chsRecord = (function (Data, chsTemplates, jspsych) {
|
|
|
8846
8971
|
}
|
|
8847
8972
|
}
|
|
8848
8973
|
|
|
8849
|
-
const info$2 = {
|
|
8974
|
+
const info$2 = {
|
|
8975
|
+
name: "start-record-plugin",
|
|
8976
|
+
version: _package.version,
|
|
8977
|
+
parameters: {
|
|
8978
|
+
wait_for_connection_message: {
|
|
8979
|
+
type: jspsych.ParameterType.HTML_STRING,
|
|
8980
|
+
default: null
|
|
8981
|
+
},
|
|
8982
|
+
locale: {
|
|
8983
|
+
type: jspsych.ParameterType.STRING,
|
|
8984
|
+
default: "en-us"
|
|
8985
|
+
}
|
|
8986
|
+
},
|
|
8987
|
+
data: {}
|
|
8988
|
+
};
|
|
8850
8989
|
class StartRecordPlugin {
|
|
8851
8990
|
constructor(jsPsych) {
|
|
8852
8991
|
this.jsPsych = jsPsych;
|
|
@@ -8859,8 +8998,14 @@ var chsRecord = (function (Data, chsTemplates, jspsych) {
|
|
|
8859
8998
|
}
|
|
8860
8999
|
static info = info$2;
|
|
8861
9000
|
recorder;
|
|
8862
|
-
trial() {
|
|
8863
|
-
|
|
9001
|
+
async trial(display_element, trial) {
|
|
9002
|
+
if (trial.wait_for_connection_message == null) {
|
|
9003
|
+
display_element.innerHTML = chsTemplates.establishingConnection(trial);
|
|
9004
|
+
} else {
|
|
9005
|
+
display_element.innerHTML = trial.wait_for_connection_message;
|
|
9006
|
+
}
|
|
9007
|
+
await this.recorder.start(false, `${StartRecordPlugin.info.name}-multiframe`).then(() => {
|
|
9008
|
+
display_element.innerHTML = "";
|
|
8864
9009
|
this.jsPsych.finishTrial();
|
|
8865
9010
|
});
|
|
8866
9011
|
}
|
|
@@ -8868,9 +9013,22 @@ var chsRecord = (function (Data, chsTemplates, jspsych) {
|
|
|
8868
9013
|
|
|
8869
9014
|
const info$1 = {
|
|
8870
9015
|
name: "stop-record-plugin",
|
|
9016
|
+
version: _package.version,
|
|
8871
9017
|
parameters: {
|
|
8872
|
-
|
|
8873
|
-
|
|
9018
|
+
wait_for_upload_message: {
|
|
9019
|
+
type: jspsych.ParameterType.HTML_STRING,
|
|
9020
|
+
default: null
|
|
9021
|
+
},
|
|
9022
|
+
locale: {
|
|
9023
|
+
type: jspsych.ParameterType.STRING,
|
|
9024
|
+
default: "en-us"
|
|
9025
|
+
},
|
|
9026
|
+
max_upload_seconds: {
|
|
9027
|
+
type: jspsych.ParameterType.INT,
|
|
9028
|
+
default: 10
|
|
9029
|
+
}
|
|
9030
|
+
},
|
|
9031
|
+
data: {}
|
|
8874
9032
|
};
|
|
8875
9033
|
class StopRecordPlugin {
|
|
8876
9034
|
constructor(jsPsych) {
|
|
@@ -8883,13 +9041,25 @@ var chsRecord = (function (Data, chsTemplates, jspsych) {
|
|
|
8883
9041
|
}
|
|
8884
9042
|
static info = info$1;
|
|
8885
9043
|
recorder;
|
|
8886
|
-
trial(display_element, trial) {
|
|
8887
|
-
|
|
8888
|
-
|
|
9044
|
+
async trial(display_element, trial) {
|
|
9045
|
+
if (trial.wait_for_upload_message == null) {
|
|
9046
|
+
display_element.innerHTML = chsTemplates.uploadingVideo(trial);
|
|
9047
|
+
} else {
|
|
9048
|
+
display_element.innerHTML = trial.wait_for_upload_message;
|
|
9049
|
+
}
|
|
9050
|
+
const { stopped, uploaded } = this.recorder.stop({
|
|
9051
|
+
upload_timeout_ms: trial.max_upload_seconds !== null ? trial.max_upload_seconds * 1e3 : null
|
|
9052
|
+
});
|
|
9053
|
+
try {
|
|
9054
|
+
await stopped;
|
|
9055
|
+
await uploaded;
|
|
9056
|
+
} catch (err) {
|
|
9057
|
+
console.error("StopRecordPlugin: recorder stop/upload failed.", err);
|
|
9058
|
+
} finally {
|
|
8889
9059
|
window.chs.sessionRecorder = null;
|
|
8890
9060
|
display_element.innerHTML = "";
|
|
8891
9061
|
this.jsPsych.finishTrial();
|
|
8892
|
-
}
|
|
9062
|
+
}
|
|
8893
9063
|
}
|
|
8894
9064
|
}
|
|
8895
9065
|
|
|
@@ -8899,22 +9069,70 @@ var chsRecord = (function (Data, chsTemplates, jspsych) {
|
|
|
8899
9069
|
autoBind(this);
|
|
8900
9070
|
}
|
|
8901
9071
|
static info = {
|
|
8902
|
-
name: "chs-trial-record-extension"
|
|
9072
|
+
name: "chs-trial-record-extension",
|
|
9073
|
+
version: _package.version,
|
|
9074
|
+
data: {}
|
|
8903
9075
|
};
|
|
8904
9076
|
recorder;
|
|
8905
9077
|
pluginName;
|
|
8906
|
-
|
|
9078
|
+
uploadMsg = null;
|
|
9079
|
+
locale = "en-us";
|
|
9080
|
+
maxUploadSeconds = void 0;
|
|
9081
|
+
async initialize(params) {
|
|
9082
|
+
await new Promise((resolve) => {
|
|
9083
|
+
this.uploadMsg = params?.wait_for_upload_message ? params.wait_for_upload_message : null;
|
|
9084
|
+
this.locale = params?.locale ? params.locale : "en-us";
|
|
9085
|
+
this.maxUploadSeconds = params?.max_upload_seconds === void 0 ? 10 : params.max_upload_seconds;
|
|
9086
|
+
resolve();
|
|
9087
|
+
});
|
|
8907
9088
|
}
|
|
8908
|
-
on_start() {
|
|
9089
|
+
on_start(startParams) {
|
|
9090
|
+
if (startParams?.wait_for_upload_message) {
|
|
9091
|
+
this.uploadMsg = startParams.wait_for_upload_message;
|
|
9092
|
+
}
|
|
9093
|
+
if (startParams?.locale) {
|
|
9094
|
+
this.locale = startParams.locale;
|
|
9095
|
+
}
|
|
9096
|
+
if (startParams?.max_upload_seconds !== void 0) {
|
|
9097
|
+
this.maxUploadSeconds = startParams?.max_upload_seconds;
|
|
9098
|
+
}
|
|
8909
9099
|
this.recorder = new Recorder(this.jsPsych);
|
|
9100
|
+
this.pluginName = this.getCurrentPluginName();
|
|
9101
|
+
this.recorder.start(false, `${this.pluginName}`);
|
|
8910
9102
|
}
|
|
8911
9103
|
on_load() {
|
|
8912
|
-
this.pluginName = this.getCurrentPluginName();
|
|
8913
|
-
this.recorder?.start(false, `${this.pluginName}`);
|
|
8914
9104
|
}
|
|
8915
|
-
on_finish() {
|
|
8916
|
-
this.
|
|
8917
|
-
|
|
9105
|
+
async on_finish() {
|
|
9106
|
+
const displayEl = this.jsPsych.getDisplayElement();
|
|
9107
|
+
if (this.uploadMsg == null) {
|
|
9108
|
+
displayEl.innerHTML = chsTemplates.uploadingVideo({
|
|
9109
|
+
type: this.jsPsych.getCurrentTrial().type,
|
|
9110
|
+
locale: this.locale
|
|
9111
|
+
});
|
|
9112
|
+
} else {
|
|
9113
|
+
displayEl.innerHTML = this.uploadMsg;
|
|
9114
|
+
}
|
|
9115
|
+
if (this.recorder) {
|
|
9116
|
+
const { stopped, uploaded } = this.recorder.stop({
|
|
9117
|
+
upload_timeout_ms: this.maxUploadSeconds !== null ? this.maxUploadSeconds * 1e3 : null
|
|
9118
|
+
});
|
|
9119
|
+
try {
|
|
9120
|
+
await stopped;
|
|
9121
|
+
await uploaded;
|
|
9122
|
+
displayEl.innerHTML = "";
|
|
9123
|
+
return {};
|
|
9124
|
+
} catch (err) {
|
|
9125
|
+
console.error(
|
|
9126
|
+
"TrialRecordExtension: recorder stop/upload failed.",
|
|
9127
|
+
err
|
|
9128
|
+
);
|
|
9129
|
+
displayEl.innerHTML = "";
|
|
9130
|
+
return {};
|
|
9131
|
+
}
|
|
9132
|
+
} else {
|
|
9133
|
+
displayEl.innerHTML = "";
|
|
9134
|
+
return {};
|
|
9135
|
+
}
|
|
8918
9136
|
}
|
|
8919
9137
|
getCurrentPluginName() {
|
|
8920
9138
|
const current_plugin_class = this.jsPsych.getCurrentTrial().type;
|
|
@@ -9325,4 +9543,4 @@ var chsRecord = (function (Data, chsTemplates, jspsych) {
|
|
|
9325
9543
|
return index;
|
|
9326
9544
|
|
|
9327
9545
|
})(chsData, chsTemplates, jsPsychModule);
|
|
9328
|
-
//# sourceMappingURL=https://unpkg.com/@lookit/record@
|
|
9546
|
+
//# sourceMappingURL=https://unpkg.com/@lookit/record@5.0.0/dist/index.browser.js.map
|