easyproctor 0.0.15 → 0.0.19
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 +155 -51
- package/dtos/StartProctoringResponse.d.ts +2 -0
- package/esm/index.js +72 -73
- package/index.d.ts +8 -1
- package/index.js +72 -74
- package/interfaces/Devices.d.ts +9 -0
- package/modules/checkPermissions.d.ts +1 -0
- package/modules/enumarateDevices.d.ts +2 -0
- package/modules/http.d.ts +1 -1
- package/modules/startCameraCapture.d.ts +7 -1
- package/modules/startScreenCapture.d.ts +4 -1
- package/package.json +1 -1
- package/unpkg/easyproctor.min.js +8 -8
package/README.md
CHANGED
|
@@ -11,6 +11,7 @@ npm install --save easyproctor
|
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
Via CDN
|
|
14
|
+
|
|
14
15
|
```html
|
|
15
16
|
<script src="https://cdn.jsdelivr.net/npm/easyproctor/unpkg/easyproctor.min.js"></script>
|
|
16
17
|
```
|
|
@@ -18,6 +19,7 @@ Via CDN
|
|
|
18
19
|
## Utilização
|
|
19
20
|
|
|
20
21
|
Para utilizar o componente será necessário utilizar os seguintes parâmetros:
|
|
22
|
+
|
|
21
23
|
- examId: identificador do exame
|
|
22
24
|
- clientId: identificador do parceiro
|
|
23
25
|
- token: token de autenticação biométrica (utilizar SDK biométrico do EasyProctor)
|
|
@@ -28,27 +30,42 @@ Após finalizar a sessão de proctoring através do método finish você poderá
|
|
|
28
30
|
|
|
29
31
|
https://iaris.easyproctor.tech/index.html
|
|
30
32
|
|
|
31
|
-
|
|
32
33
|
Em um bundler
|
|
34
|
+
|
|
33
35
|
```javascript
|
|
34
36
|
import { useProctoring } from "easyproctor";
|
|
35
37
|
|
|
36
|
-
const {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
const {
|
|
39
|
+
start,
|
|
40
|
+
finish,
|
|
41
|
+
onFocus,
|
|
42
|
+
onLostFocus,
|
|
43
|
+
enumarateDevices,
|
|
44
|
+
checkPermissions,
|
|
45
|
+
} = useProctoring({
|
|
46
|
+
examId: "00001",
|
|
47
|
+
clientId: "000001",
|
|
48
|
+
token: "...",
|
|
40
49
|
});
|
|
41
50
|
```
|
|
42
51
|
|
|
43
52
|
Via CDN: A função "useProctoring" é injetada para ser utilizada globalmente
|
|
53
|
+
|
|
44
54
|
```html
|
|
45
55
|
<script src="https://cdn.jsdelivr.net/npm/easyproctor/unpkg/easyproctor.min.js"></script>
|
|
46
56
|
<script>
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
57
|
+
const {
|
|
58
|
+
start,
|
|
59
|
+
finish,
|
|
60
|
+
onFocus,
|
|
61
|
+
onLostFocus,
|
|
62
|
+
enumarateDevices,
|
|
63
|
+
checkPermissions,
|
|
64
|
+
} = useProctoring({
|
|
65
|
+
examId: "00001",
|
|
66
|
+
clientId: "000001",
|
|
67
|
+
token: "...",
|
|
68
|
+
});
|
|
52
69
|
</script>
|
|
53
70
|
```
|
|
54
71
|
|
|
@@ -57,64 +74,151 @@ Via CDN: A função "useProctoring" é injetada para ser utilizada globalmente
|
|
|
57
74
|
```html
|
|
58
75
|
<!DOCTYPE html>
|
|
59
76
|
<html lang="en">
|
|
60
|
-
|
|
61
|
-
<
|
|
62
|
-
<meta
|
|
63
|
-
<meta
|
|
64
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
77
|
+
<head>
|
|
78
|
+
<meta charset="UTF-8" />
|
|
79
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
80
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
65
81
|
<title>Document</title>
|
|
66
82
|
<script src="dist/unpkg/easyproctor.min.js"></script>
|
|
67
83
|
<script>
|
|
84
|
+
const {
|
|
85
|
+
start,
|
|
86
|
+
finish,
|
|
87
|
+
onFocus,
|
|
88
|
+
onLostFocus,
|
|
89
|
+
enumarateDevices,
|
|
90
|
+
checkPermissions,
|
|
91
|
+
} = useProctoring({
|
|
92
|
+
examId: "00001",
|
|
93
|
+
clientId: "000001",
|
|
94
|
+
token: "...",
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
async function startExam() {
|
|
98
|
+
try {
|
|
99
|
+
// Verificar se existem dispositívos disponíveis
|
|
100
|
+
if (devices.cameras.length == 0 || devices.microphones.length == 0) {
|
|
101
|
+
throw "Você precisa possuir ao menos uma câmera e um microfone";
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Verificar se foram setados
|
|
105
|
+
const selectedCamera = cameras.value;
|
|
106
|
+
const selectedMicrophone = microphones.value;
|
|
107
|
+
|
|
108
|
+
if (!selectedCamera || !selectedMicrophone) {
|
|
109
|
+
throw "Você precisa selecionar uma camera e um microfone";
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
startButton.innerHTML = "Carregando";
|
|
113
|
+
|
|
114
|
+
onFocus(() => generateAlert(false));
|
|
115
|
+
onLostFocus(() => generateAlert(true));
|
|
116
|
+
// Adicionar o dispositivo selecionado é opcional
|
|
117
|
+
const { cameraStream } = await start({
|
|
118
|
+
cameraId: selectedCamera,
|
|
119
|
+
microphoneId: selectedMicrophone,
|
|
120
|
+
});
|
|
121
|
+
} catch (error) {
|
|
122
|
+
alert(error);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async function finishExam() {
|
|
127
|
+
try {
|
|
128
|
+
await finish({ onProgress: (percentage) => console.log(percentage) });
|
|
129
|
+
console.log("EXAME FINALIZADO");
|
|
130
|
+
} catch (error) {
|
|
131
|
+
alert(error);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
68
134
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
135
|
+
// Verificar permissões
|
|
136
|
+
let devices = { cameras: [], microphones: [] };
|
|
137
|
+
async function verifyPermissions() {
|
|
138
|
+
// Checar permissões
|
|
139
|
+
var hasPermissions = await checkPermissions();
|
|
74
140
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
} catch (error) {
|
|
79
|
-
alert(error);
|
|
80
|
-
}
|
|
141
|
+
if (!hasPermissions) {
|
|
142
|
+
window.alert("Para continuar você precisa conceder as permissões");
|
|
143
|
+
return;
|
|
81
144
|
}
|
|
82
145
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
146
|
+
// Listar os dispositivos
|
|
147
|
+
devices = await enumarateDevices();
|
|
148
|
+
|
|
149
|
+
const generateOption = (text, value) => {
|
|
150
|
+
const el = document.createElement("option");
|
|
151
|
+
el.setAttribute("value", value);
|
|
152
|
+
el.innerHTML = text;
|
|
153
|
+
return el;
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
devices.cameras.forEach((camera) => {
|
|
157
|
+
const option = generateOption(camera.label, camera.id);
|
|
158
|
+
cameras.appendChild(option);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
devices.microphones.forEach((microphone) => {
|
|
162
|
+
const option = generateOption(microphone.label, microphone.id);
|
|
163
|
+
microphones.appendChild(option);
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Gerar alerta
|
|
168
|
+
function generateAlert(lostFocus) {
|
|
169
|
+
const p = document.createElement("p");
|
|
170
|
+
if (lostFocus) {
|
|
171
|
+
p.classList.add("text-red-500");
|
|
172
|
+
p.innerHTML = `Perdeu o foco em: ${new Date().toLocaleTimeString()}`;
|
|
173
|
+
} else {
|
|
174
|
+
p.classList.add("text-green-500");
|
|
175
|
+
p.innerHTML = `Retomou o foco em: ${new Date().toLocaleTimeString()}`;
|
|
90
176
|
}
|
|
177
|
+
alerts.appendChild(p);
|
|
178
|
+
}
|
|
91
179
|
</script>
|
|
92
|
-
</head>
|
|
93
|
-
|
|
94
|
-
<body>
|
|
95
|
-
<div
|
|
96
|
-
|
|
97
|
-
|
|
180
|
+
</head>
|
|
181
|
+
|
|
182
|
+
<body>
|
|
183
|
+
<div
|
|
184
|
+
style="height: 100vh; display: flex; align-items: center; justify-content: center;"
|
|
185
|
+
>
|
|
186
|
+
<button onclick="startExam()">Iniciar</button>
|
|
187
|
+
<button onclick="finishExam()">Finalizar</button>
|
|
188
|
+
<button onclick="verifyPermissions()">Verificar permissões</button>
|
|
98
189
|
</div>
|
|
99
|
-
</body>
|
|
100
|
-
|
|
190
|
+
</body>
|
|
101
191
|
</html>
|
|
102
192
|
```
|
|
103
193
|
|
|
104
194
|
## API
|
|
195
|
+
|
|
105
196
|
```javascript
|
|
106
|
-
const {
|
|
107
|
-
|
|
108
|
-
|
|
197
|
+
const {
|
|
198
|
+
// Inicia a gravação da prova
|
|
199
|
+
start,
|
|
200
|
+
|
|
201
|
+
// Finaliza a gravação da prova retornando os arquivos gerados
|
|
202
|
+
finish,
|
|
203
|
+
|
|
204
|
+
// Adiciona uma função callback para ser executada quando o usuário recupera o foco da tela
|
|
205
|
+
onFocus,
|
|
206
|
+
|
|
207
|
+
// Adiciona uma função callback para ser executada quando o usuário perde o foco da tela
|
|
208
|
+
onLostFocus,
|
|
109
209
|
|
|
110
|
-
|
|
111
|
-
|
|
210
|
+
// Enumera os dispositivos de camera e microfone
|
|
211
|
+
enumarateDevices,
|
|
112
212
|
|
|
213
|
+
// Checa as permissões de camera e microfone
|
|
214
|
+
checkPermissions,
|
|
113
215
|
} = useProctoring({
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
216
|
+
examId: "00001",
|
|
217
|
+
clientId: "000001",
|
|
218
|
+
token: "...",
|
|
219
|
+
});
|
|
118
220
|
```
|
|
221
|
+
|
|
119
222
|
## License
|
|
120
|
-
|
|
223
|
+
|
|
224
|
+
[MIT](https://choosealicense.com/licenses/mit/)
|
package/esm/index.js
CHANGED
|
@@ -1,46 +1,3 @@
|
|
|
1
|
-
// src/modules/database.ts
|
|
2
|
-
var databaseName = "EasyProctorPlugin";
|
|
3
|
-
var databaseVersion = 1;
|
|
4
|
-
function initializeDatabase(table) {
|
|
5
|
-
return new Promise((resolve, reject) => {
|
|
6
|
-
const request = indexedDB.open(databaseName, databaseVersion);
|
|
7
|
-
request.onupgradeneeded = () => {
|
|
8
|
-
request.result.createObjectStore("cameraBuffers", { keyPath: "id", autoIncrement: true });
|
|
9
|
-
request.result.createObjectStore("screenBuffers", { keyPath: "id", autoIncrement: true });
|
|
10
|
-
};
|
|
11
|
-
request.onerror = (e) => {
|
|
12
|
-
console.log(e);
|
|
13
|
-
reject("N\xE3o foi poss\xEDvel inicializar a biblioteca, por favor, entre em contato com o suporte e informe o erro acima");
|
|
14
|
-
};
|
|
15
|
-
request.onsuccess = () => {
|
|
16
|
-
const db = request.result;
|
|
17
|
-
const tableRef = db.transaction(table, "readwrite");
|
|
18
|
-
const store = tableRef.objectStore(table);
|
|
19
|
-
resolve(store);
|
|
20
|
-
};
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
async function getBuffers(table) {
|
|
24
|
-
const store = await initializeDatabase(table);
|
|
25
|
-
return new Promise((resolve, reject) => {
|
|
26
|
-
const request = store.getAll();
|
|
27
|
-
request.onsuccess = () => {
|
|
28
|
-
const data = request.result;
|
|
29
|
-
const blobs = data.reduce((acc, el) => [...acc, ...el.data], []);
|
|
30
|
-
resolve(blobs);
|
|
31
|
-
};
|
|
32
|
-
request.onerror = (e) => reject(e);
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
async function clearBuffers(table) {
|
|
36
|
-
const store = await initializeDatabase(table);
|
|
37
|
-
return new Promise((resolve, reject) => {
|
|
38
|
-
const request = store.clear();
|
|
39
|
-
request.onsuccess = () => resolve();
|
|
40
|
-
request.onerror = (e) => reject(e);
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
|
|
44
1
|
// src/modules/recorder.ts
|
|
45
2
|
function recorder(stream, buffer) {
|
|
46
3
|
let resolvePromise;
|
|
@@ -70,18 +27,20 @@ function recorder(stream, buffer) {
|
|
|
70
27
|
}
|
|
71
28
|
|
|
72
29
|
// src/modules/startCameraCapture.ts
|
|
73
|
-
async function startCameraCapture(buffer) {
|
|
30
|
+
async function startCameraCapture(buffer, options = { cameraId: void 0, microphoneId: void 0 }) {
|
|
31
|
+
const { cameraId, microphoneId } = options;
|
|
74
32
|
const constraints = {
|
|
75
|
-
audio:
|
|
33
|
+
audio: { deviceId: microphoneId },
|
|
76
34
|
video: {
|
|
35
|
+
deviceId: cameraId,
|
|
77
36
|
width: { max: 1280, ideal: 640 },
|
|
78
37
|
height: { max: 720, ideal: 480 },
|
|
79
38
|
frameRate: 15
|
|
80
39
|
}
|
|
81
40
|
};
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
return
|
|
41
|
+
const cameraStream = await navigator.mediaDevices.getUserMedia(constraints);
|
|
42
|
+
const stopCameraRecording = recorder(cameraStream, buffer);
|
|
43
|
+
return { cameraStream, stopCameraRecording };
|
|
85
44
|
}
|
|
86
45
|
|
|
87
46
|
// src/modules/startScreenCapture.ts
|
|
@@ -92,9 +51,9 @@ async function startScreenCapture(buffer) {
|
|
|
92
51
|
},
|
|
93
52
|
audio: false
|
|
94
53
|
};
|
|
95
|
-
const
|
|
96
|
-
const
|
|
97
|
-
return
|
|
54
|
+
const screenStream = await navigator.mediaDevices.getDisplayMedia(displayMediaStreamConstraints);
|
|
55
|
+
const stopScreenRecorder = recorder(screenStream, buffer);
|
|
56
|
+
return { screenStream, stopScreenRecorder };
|
|
98
57
|
}
|
|
99
58
|
|
|
100
59
|
// src/modules/upload.ts
|
|
@@ -130,13 +89,45 @@ async function makeRequest(data) {
|
|
|
130
89
|
if (resp.status >= 400) {
|
|
131
90
|
throw "N\xE3o foi poss\xEDvel realizar a requisi\xE7\xE3o, tente novamente mais tarde";
|
|
132
91
|
}
|
|
133
|
-
const
|
|
92
|
+
const content = resp.headers.get("content-type");
|
|
93
|
+
const isJson = content ? content.includes("application/json") : false;
|
|
134
94
|
const responseData = isJson ? await resp.json() : null;
|
|
135
95
|
return responseData;
|
|
136
96
|
}
|
|
137
97
|
|
|
98
|
+
// src/modules/enumarateDevices.ts
|
|
99
|
+
async function enumarateDevices() {
|
|
100
|
+
const mediaDevices = await navigator.mediaDevices.enumerateDevices();
|
|
101
|
+
const devices = {
|
|
102
|
+
cameras: mediaDevices.filter((el) => el.kind == "videoinput" && el.deviceId && el.label).map((e) => {
|
|
103
|
+
return { label: e.label, id: e.deviceId };
|
|
104
|
+
}),
|
|
105
|
+
microphones: mediaDevices.filter((el) => el.kind == "audioinput" && el.deviceId && el.label).map((e) => {
|
|
106
|
+
return { label: e.label, id: e.deviceId };
|
|
107
|
+
})
|
|
108
|
+
};
|
|
109
|
+
return devices;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// src/modules/checkPermissions.ts
|
|
113
|
+
async function checkPermissions() {
|
|
114
|
+
try {
|
|
115
|
+
const constraints = {
|
|
116
|
+
audio: true,
|
|
117
|
+
video: true
|
|
118
|
+
};
|
|
119
|
+
const stream = await navigator.mediaDevices.getUserMedia(constraints);
|
|
120
|
+
stream.getTracks().forEach((el) => {
|
|
121
|
+
el.stop();
|
|
122
|
+
});
|
|
123
|
+
return true;
|
|
124
|
+
} catch (error) {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
138
129
|
// src/index.ts
|
|
139
|
-
var azureBlobUrl = "https://iarisprod.
|
|
130
|
+
var azureBlobUrl = "https://iarisprod.blob.core.windows.net/iaris";
|
|
140
131
|
function useProctoring(proctoringOptions) {
|
|
141
132
|
["examId", "clientId", "token"].forEach((el) => {
|
|
142
133
|
const key = el;
|
|
@@ -165,8 +156,11 @@ function useProctoring(proctoringOptions) {
|
|
|
165
156
|
let proctoringId = "";
|
|
166
157
|
let startTime = 0;
|
|
167
158
|
let alerts = [];
|
|
159
|
+
let onLostFocusCallback;
|
|
160
|
+
let onFocusCallback;
|
|
168
161
|
let cancelCallback = null;
|
|
169
|
-
async function _startCapture() {
|
|
162
|
+
async function _startCapture(options) {
|
|
163
|
+
console.log(cancelCallback);
|
|
170
164
|
if (!document.body) {
|
|
171
165
|
throw "A execu\xE7\xE3o do script deve ser feita por algum elemento dentro do <body> da p\xE1gina html";
|
|
172
166
|
}
|
|
@@ -176,11 +170,15 @@ function useProctoring(proctoringOptions) {
|
|
|
176
170
|
let cancelCameraCapture = null;
|
|
177
171
|
let cancelScreenCapture = null;
|
|
178
172
|
try {
|
|
179
|
-
|
|
180
|
-
|
|
173
|
+
const { screenStream, stopScreenRecorder } = await startScreenCapture(screenBuffer);
|
|
174
|
+
const { cameraId, microphoneId } = options;
|
|
175
|
+
const { cameraStream, stopCameraRecording } = await startCameraCapture(cameraBuffer, { cameraId, microphoneId });
|
|
176
|
+
cancelScreenCapture = stopScreenRecorder;
|
|
177
|
+
cancelCameraCapture = stopCameraRecording;
|
|
181
178
|
cancelCallback = async function() {
|
|
182
179
|
await Promise.all([cancelCameraCapture(), cancelScreenCapture()]);
|
|
183
180
|
};
|
|
181
|
+
return { screenStream, cameraStream };
|
|
184
182
|
} catch (error) {
|
|
185
183
|
cancelCallback = null;
|
|
186
184
|
cancelScreenCapture && await cancelScreenCapture();
|
|
@@ -191,6 +189,7 @@ function useProctoring(proctoringOptions) {
|
|
|
191
189
|
}
|
|
192
190
|
}
|
|
193
191
|
const _onLostFocus = () => {
|
|
192
|
+
onLostFocusCallback && onLostFocusCallback();
|
|
194
193
|
alerts.push({
|
|
195
194
|
begin: Date.now() - startTime,
|
|
196
195
|
alert: 25,
|
|
@@ -200,6 +199,7 @@ function useProctoring(proctoringOptions) {
|
|
|
200
199
|
const _onReturnFocus = () => {
|
|
201
200
|
const lastAlert = alerts[alerts.length - 1];
|
|
202
201
|
if (lastAlert) {
|
|
202
|
+
onFocusCallback && onFocusCallback();
|
|
203
203
|
lastAlert.end = Date.now() - startTime;
|
|
204
204
|
}
|
|
205
205
|
};
|
|
@@ -211,17 +211,9 @@ function useProctoring(proctoringOptions) {
|
|
|
211
211
|
window.removeEventListener("blur", _onLostFocus);
|
|
212
212
|
window.removeEventListener("focus", _onReturnFocus);
|
|
213
213
|
};
|
|
214
|
-
async function start(options = {
|
|
215
|
-
const {
|
|
216
|
-
|
|
217
|
-
await Promise.all([clearBuffers("cameraBuffers"), clearBuffers("screenBuffers")]);
|
|
218
|
-
} else {
|
|
219
|
-
const [storedCameraBuffers, storedScreenBuffers] = await Promise.all([getBuffers("cameraBuffers"), getBuffers("screenBuffers")]);
|
|
220
|
-
if (storedCameraBuffers.length > 0 || storedScreenBuffers.length > 0) {
|
|
221
|
-
throw "Existe uma grava\xE7\xE3o iniciada, por favor, execute o m\xE9todo resume() para retomar, ou utilize o parametro start({ override: true }) para limpar os dados";
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
await _startCapture();
|
|
214
|
+
async function start(options = { microphoneId: void 0, cameraId: void 0 }) {
|
|
215
|
+
const { cameraId, microphoneId } = options;
|
|
216
|
+
const { cameraStream, screenStream } = await _startCapture({ cameraId, microphoneId });
|
|
225
217
|
startTime = Date.now();
|
|
226
218
|
try {
|
|
227
219
|
const resp = await makeRequest({
|
|
@@ -230,6 +222,8 @@ function useProctoring(proctoringOptions) {
|
|
|
230
222
|
body: { clientId: proctoringOptions.clientId },
|
|
231
223
|
jwt: proctoringOptions.token
|
|
232
224
|
});
|
|
225
|
+
resp.cameraStream = cameraStream;
|
|
226
|
+
resp.screenStream = screenStream;
|
|
233
227
|
proctoringId = resp.id;
|
|
234
228
|
_addListeners();
|
|
235
229
|
return resp;
|
|
@@ -249,12 +243,12 @@ function useProctoring(proctoringOptions) {
|
|
|
249
243
|
if (finalCameraBuffer.length == 0 || finalScreenBuffer.length == 0) {
|
|
250
244
|
throw "N\xE3o existe nenhuma grava\xE7\xE3o iniciada";
|
|
251
245
|
}
|
|
252
|
-
const cameraFileName = `EP_${proctoringId}
|
|
253
|
-
const screenFIleName = `EP_${proctoringId}
|
|
246
|
+
const cameraFileName = `EP_${proctoringId}_camera_0.webm`;
|
|
247
|
+
const screenFIleName = `EP_${proctoringId}_screen_0.webm`;
|
|
254
248
|
const cameraFile = new File(finalCameraBuffer, cameraFileName, { type: "video/webm" });
|
|
255
249
|
const screenFile = new File(finalScreenBuffer, screenFIleName, { type: "video/webm" });
|
|
256
250
|
let cameraProgress = 0;
|
|
257
|
-
|
|
251
|
+
let screenProgress = 0;
|
|
258
252
|
const handleOnProgress = () => {
|
|
259
253
|
onProgress && onProgress((cameraProgress + screenProgress) / 2);
|
|
260
254
|
};
|
|
@@ -264,7 +258,7 @@ function useProctoring(proctoringOptions) {
|
|
|
264
258
|
handleOnProgress();
|
|
265
259
|
} }),
|
|
266
260
|
upload_default({ file: screenFile, onProgress: (progress) => {
|
|
267
|
-
|
|
261
|
+
screenProgress = progress;
|
|
268
262
|
handleOnProgress();
|
|
269
263
|
} })
|
|
270
264
|
]);
|
|
@@ -288,13 +282,18 @@ function useProctoring(proctoringOptions) {
|
|
|
288
282
|
},
|
|
289
283
|
jwt: proctoringOptions.token
|
|
290
284
|
});
|
|
291
|
-
await Promise.all([clearBuffers("cameraBuffers"), clearBuffers("screenBuffers")]);
|
|
292
285
|
cameraBuffer = [];
|
|
293
286
|
screenBuffer = [];
|
|
294
287
|
alerts = [];
|
|
295
288
|
cancelCallback = null;
|
|
296
289
|
}
|
|
297
|
-
|
|
290
|
+
function onFocus(cb) {
|
|
291
|
+
onFocusCallback = cb;
|
|
292
|
+
}
|
|
293
|
+
function onLostFocus(cb) {
|
|
294
|
+
onLostFocusCallback = cb;
|
|
295
|
+
}
|
|
296
|
+
return { start, finish, download, onFocus, onLostFocus, enumarateDevices, checkPermissions };
|
|
298
297
|
}
|
|
299
298
|
if (typeof window !== "undefined") {
|
|
300
299
|
window.useProctoring = useProctoring;
|
package/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import enumarateDevices from "./modules/enumarateDevices";
|
|
2
|
+
import checkPermissions from "./modules/checkPermissions";
|
|
1
3
|
import StartProctoringResponse from "./dtos/StartProctoringResponse";
|
|
2
4
|
export declare function useProctoring(proctoringOptions: {
|
|
3
5
|
examId: string;
|
|
@@ -5,10 +7,15 @@ export declare function useProctoring(proctoringOptions: {
|
|
|
5
7
|
token: string;
|
|
6
8
|
}): {
|
|
7
9
|
start: (options?: {
|
|
8
|
-
|
|
10
|
+
cameraId?: string;
|
|
11
|
+
microphoneId?: string;
|
|
9
12
|
}) => Promise<StartProctoringResponse>;
|
|
10
13
|
finish: (options?: {
|
|
11
14
|
onProgress?: ((percentage: number) => void) | undefined;
|
|
12
15
|
}) => Promise<void>;
|
|
13
16
|
download: (file: File) => void;
|
|
17
|
+
onFocus: (cb: () => void) => void;
|
|
18
|
+
onLostFocus: (cb: () => void) => void;
|
|
19
|
+
enumarateDevices: typeof enumarateDevices;
|
|
20
|
+
checkPermissions: typeof checkPermissions;
|
|
14
21
|
};
|