speaker-calibration 2.2.218 → 2.2.219
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/dist/example/i18n.js +2748 -2772
- package/dist/example/styles.css +75 -22
- package/dist/listener.js +745 -2621
- package/dist/main.js +3 -14
- package/package.json +1 -1
- package/src/listener-app/listener.js +288 -90
- package/src/main.js +1 -2
- package/src/peer-connection/listener.js +37 -17
- package/src/peer-connection/speaker.js +98 -55
- package/src/tasks/combination/combination.js +7 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// get element with id message
|
|
2
2
|
import {phrases} from '../../dist/example/i18n.js';
|
|
3
|
-
import
|
|
3
|
+
import Listener from '../peer-connection/listener.js';
|
|
4
4
|
// get url query parameters
|
|
5
5
|
const urlParams = new URLSearchParams(window.location.search);
|
|
6
6
|
|
|
@@ -16,117 +16,315 @@ const listenerParameters = {
|
|
|
16
16
|
const container = document.getElementById('listenerContainer');
|
|
17
17
|
const recordingInProgress = phrases.RC_soundRecording['en-US'];
|
|
18
18
|
const backToExperimentWindow = phrases.RC_backToExperimentWindow['en-US'];
|
|
19
|
-
const allowMicrophone = phrases.RC_allowMicrophoneUse['en-US']
|
|
20
|
-
const placeSmartphoneMicrophone = phrases.RC_placeSmartphoneMicrophone['en-US']
|
|
21
|
-
|
|
22
|
-
'<br>'
|
|
23
|
-
);
|
|
24
|
-
const turnMeToReadBelow = phrases.RC_turnMeToReadBelow['en-US'].replace(/\n/g, '<br>');
|
|
19
|
+
const allowMicrophone = phrases.RC_allowMicrophoneUse['en-US'];
|
|
20
|
+
const placeSmartphoneMicrophone = phrases.RC_placeSmartphoneMicrophone['en-US'];
|
|
21
|
+
const turnMeToReadBelow = phrases.RC_turnMeToReadBelow['en-US'];
|
|
25
22
|
const recordingInProgressElement = document.getElementById('recordingInProgress');
|
|
26
23
|
const allowMicrophoneElement = document.getElementById('allowMicrophone');
|
|
27
24
|
const turnMessageElement = document.getElementById('turnMeToReadBelow');
|
|
28
25
|
|
|
29
26
|
switch (isSmartPhone) {
|
|
30
27
|
case 'true':
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const phrasesContainer = document.getElementById('phrases');
|
|
39
|
-
// add class
|
|
40
|
-
phrasesContainer.classList.add('phrases');
|
|
41
|
-
const html = document.querySelector('html');
|
|
42
|
-
html.style.overflow = 'hidden';
|
|
43
|
-
const display = document.getElementById('updateDisplay');
|
|
44
|
-
display.classList.add('updateDisplay');
|
|
45
|
-
container.style.display = 'block';
|
|
46
|
-
// event listener for id calibrationBeginButton
|
|
47
|
-
const calibrationBeginButton = document.getElementById('calibrationBeginButton');
|
|
48
|
-
console.log('Waiting for proceed button click');
|
|
28
|
+
//hide target element
|
|
29
|
+
const targetElement = document.getElementById('display');
|
|
30
|
+
targetElement.style.display = 'none';
|
|
31
|
+
// Initialize Listener early
|
|
32
|
+
const initializeListener = async () => {
|
|
33
|
+
window.listener = new Listener(listenerParameters);
|
|
34
|
+
};
|
|
49
35
|
|
|
50
|
-
|
|
51
|
-
|
|
36
|
+
// Check microphone permission first
|
|
37
|
+
async function checkAndRequestMicrophonePermission() {
|
|
38
|
+
try {
|
|
39
|
+
const permissionStatus = await navigator.permissions.query({name: 'microphone'});
|
|
52
40
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
recordingInProgressElement.innerHTML = recordingInProgress;
|
|
59
|
-
allowMicrophoneElement.innerHTML = allowMicrophone;
|
|
41
|
+
if (permissionStatus.state === 'granted') {
|
|
42
|
+
// Permission already granted, proceed to normal flow
|
|
43
|
+
initializeSmartPhoneDisplay();
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
60
46
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
recordingInProgressElement.style.width = 'fit-content';
|
|
65
|
-
let fontSize = 100;
|
|
66
|
-
recordingInProgressElement.style.fontSize = fontSize + 'px';
|
|
47
|
+
// Show permission request message
|
|
48
|
+
allowMicrophoneElement.innerText = phrases.RC_microphonePermission['en-US'];
|
|
49
|
+
container.style.display = 'block';
|
|
67
50
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
if (
|
|
87
|
-
|
|
88
|
-
|
|
51
|
+
// Function to request microphone access
|
|
52
|
+
async function requestMicAccess(attempt = 1) {
|
|
53
|
+
try {
|
|
54
|
+
await navigator.mediaDevices.getUserMedia({audio: true});
|
|
55
|
+
// Permission granted, proceed to normal flow
|
|
56
|
+
initializeSmartPhoneDisplay();
|
|
57
|
+
} catch (err) {
|
|
58
|
+
if (err.name === 'NotAllowedError') {
|
|
59
|
+
console.log('Permission explicitly denied');
|
|
60
|
+
// Permission explicitly denied
|
|
61
|
+
allowMicrophoneElement.innerText = phrases.RC_microphonePermissionDenied['en-US'];
|
|
62
|
+
// Send denied status and end study
|
|
63
|
+
let error = JSON.stringify(err);
|
|
64
|
+
await window.listener.sendPermissionStatus({type: 'denied', error: error});
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// If 10 seconds passed, try again
|
|
69
|
+
if (attempt < 3) {
|
|
70
|
+
console.log('Retrying microphone access');
|
|
71
|
+
// Limit retries
|
|
72
|
+
setTimeout(() => requestMicAccess(attempt + 1), 10000);
|
|
73
|
+
} else {
|
|
74
|
+
console.log('All retries failed, treating as denied');
|
|
75
|
+
// After all retries failed, treat as denied
|
|
76
|
+
allowMicrophoneElement.innerText = phrases.RC_microphonePermissionDenied['en-US'];
|
|
77
|
+
let error = JSON.stringify(err);
|
|
78
|
+
await window.listener.sendPermissionStatus({type: 'error', error: error});
|
|
89
79
|
}
|
|
90
|
-
});
|
|
91
|
-
if (webAudioDeviceNames.microphone === '') {
|
|
92
|
-
webAudioDeviceNames.microphone = mics[0].label;
|
|
93
|
-
webAudioDeviceNames.deviceID = mics[0].deviceId;
|
|
94
80
|
}
|
|
95
81
|
}
|
|
82
|
+
|
|
83
|
+
requestMicAccess();
|
|
96
84
|
} catch (err) {
|
|
97
|
-
console.
|
|
85
|
+
console.error('Error checking microphone permission:', err);
|
|
86
|
+
allowMicrophoneElement.innerText = phrases.RC_microphonePermissionDenied['en-US'];
|
|
87
|
+
let error = JSON.stringify(err);
|
|
88
|
+
await window.listener.sendPermissionStatus({type: 'error', error: error});
|
|
98
89
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function initializeSmartPhoneDisplay() {
|
|
93
|
+
allowMicrophoneElement.innerText = placeSmartphoneMicrophone;
|
|
94
|
+
allowMicrophoneElement.style.lineHeight = '1.2rem';
|
|
95
|
+
allowMicrophoneElement.style.fontSize = '14px';
|
|
96
|
+
turnMessageElement.innerText = turnMeToReadBelow;
|
|
97
|
+
turnMessageElement.style.lineHeight = '1.2rem';
|
|
98
|
+
turnMessageElement.style.fontSize = '14px';
|
|
99
|
+
|
|
100
|
+
// Show the html upsidedown and adjust layout
|
|
101
|
+
const phrasesContainer = document.getElementById('phrases');
|
|
102
|
+
phrasesContainer.classList.add('phrases');
|
|
103
|
+
|
|
104
|
+
// Hide all elements except what's needed for calibration
|
|
105
|
+
const html = document.querySelector('html');
|
|
106
|
+
html.style.overflow = 'hidden';
|
|
107
|
+
|
|
108
|
+
// Adjust the display container
|
|
109
|
+
const display = document.getElementById('updateDisplay');
|
|
110
|
+
display.classList.add('updateDisplay');
|
|
111
|
+
display.style.position = 'absolute';
|
|
112
|
+
display.style.top = '50%';
|
|
113
|
+
display.style.left = '50%';
|
|
114
|
+
display.style.transform = 'translate(-50%, -50%) rotate(180deg)';
|
|
115
|
+
display.style.width = '100%';
|
|
116
|
+
display.style.textAlign = 'center';
|
|
117
|
+
|
|
118
|
+
container.style.display = 'block';
|
|
119
|
+
|
|
120
|
+
// event listener for id calibrationBeginButton
|
|
121
|
+
const calibrationBeginButton = document.getElementById('calibrationBeginButton');
|
|
122
|
+
console.log('Waiting for proceed button click');
|
|
123
|
+
|
|
124
|
+
calibrationBeginButton.addEventListener('click', async () => {
|
|
125
|
+
console.log('Proceed button clicked');
|
|
126
|
+
|
|
127
|
+
// Clear unnecessary elements
|
|
128
|
+
calibrationBeginButton.remove();
|
|
129
|
+
turnMessageElement.remove();
|
|
130
|
+
|
|
131
|
+
// Create a header container for fixed elements
|
|
132
|
+
const headerContainer = document.createElement('div');
|
|
133
|
+
headerContainer.id = 'headerContainer';
|
|
134
|
+
headerContainer.style.position = 'fixed';
|
|
135
|
+
headerContainer.style.bottom = '0';
|
|
136
|
+
headerContainer.style.left = '0';
|
|
137
|
+
headerContainer.style.width = '100%';
|
|
138
|
+
headerContainer.style.background = 'white';
|
|
139
|
+
headerContainer.style.padding = '10px';
|
|
140
|
+
headerContainer.style.zIndex = '1000';
|
|
141
|
+
headerContainer.style.transform = 'rotate(180deg)';
|
|
142
|
+
container.appendChild(headerContainer);
|
|
143
|
+
|
|
144
|
+
// Set title based on screen width
|
|
145
|
+
const title = document.createElement('h1');
|
|
146
|
+
const titleText =
|
|
147
|
+
window.innerWidth >= 1366
|
|
148
|
+
? phrases.RC_soundRecording['en-US']
|
|
149
|
+
: phrases.RC_soundRecordingSmallScreen['en-US'];
|
|
150
|
+
|
|
151
|
+
// Split small screen title into lines if needed
|
|
152
|
+
if (window.innerWidth < 1366 && titleText.includes('\n')) {
|
|
153
|
+
const lines = titleText.split('\n');
|
|
154
|
+
|
|
155
|
+
// Create container for title lines
|
|
156
|
+
const titleContainer = document.createElement('div');
|
|
157
|
+
titleContainer.style.display = 'flex';
|
|
158
|
+
titleContainer.style.flexDirection = 'column';
|
|
159
|
+
titleContainer.style.alignItems = 'left';
|
|
160
|
+
titleContainer.style.lineHeight = '1.2';
|
|
161
|
+
|
|
162
|
+
// Add each line
|
|
163
|
+
lines.forEach(line => {
|
|
164
|
+
const lineDiv = document.createElement('p');
|
|
165
|
+
lineDiv.textContent = line;
|
|
166
|
+
lineDiv.style.width = 'fit-content';
|
|
167
|
+
titleContainer.appendChild(lineDiv);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
title.appendChild(titleContainer);
|
|
171
|
+
} else {
|
|
172
|
+
title.textContent = titleText;
|
|
173
|
+
title.style.lineHeight = '1.2';
|
|
105
174
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
175
|
+
|
|
176
|
+
title.style.margin = '0';
|
|
177
|
+
title.style.whiteSpace = 'pre-line'; // Preserve line breaks
|
|
178
|
+
headerContainer.appendChild(title);
|
|
179
|
+
|
|
180
|
+
// Function to adjust font size to fill width
|
|
181
|
+
const adjustFontSize = (element, maxWidth) => {
|
|
182
|
+
let fontSize = 20; // Start with a reasonable minimum size
|
|
183
|
+
element.style.fontSize = fontSize + 'px';
|
|
184
|
+
// Increase font size until text fills width (minus margins)
|
|
185
|
+
while (element.scrollWidth < maxWidth - 40 && fontSize < 200) {
|
|
186
|
+
fontSize++;
|
|
187
|
+
element.style.fontSize = fontSize + 'px';
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Step back one to ensure we don't overflow
|
|
191
|
+
fontSize--;
|
|
192
|
+
element.style.fontSize = fontSize + 'px';
|
|
193
|
+
return fontSize;
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
// For small screen, ensure all lines use same font size
|
|
197
|
+
if (window.innerWidth < 1366 && titleText.includes('\n')) {
|
|
198
|
+
const lines = title.querySelectorAll('p');
|
|
199
|
+
let minFontSize = Infinity;
|
|
200
|
+
|
|
201
|
+
// First pass: find the smallest font size that fits for any line
|
|
202
|
+
lines.forEach(line => {
|
|
203
|
+
const fontSize = adjustFontSize(line, window.innerWidth);
|
|
204
|
+
minFontSize = Math.min(minFontSize, fontSize);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// Second pass: apply the smallest font size to all lines
|
|
208
|
+
lines.forEach(line => {
|
|
209
|
+
line.style.fontSize = minFontSize + 'px';
|
|
210
|
+
});
|
|
211
|
+
} else {
|
|
212
|
+
// For single line title, just adjust to fill width
|
|
213
|
+
adjustFontSize(title, window.innerWidth);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Get the header height after text is added and sized
|
|
217
|
+
const headerHeight = headerContainer.getBoundingClientRect().height;
|
|
218
|
+
|
|
219
|
+
// Adjust the display container to start after header
|
|
220
|
+
const display = document.getElementById('updateDisplay');
|
|
221
|
+
display.classList.add('updateDisplay');
|
|
222
|
+
display.style.position = 'fixed';
|
|
223
|
+
display.style.bottom = `${headerHeight}px`; // Start after header
|
|
224
|
+
display.style.left = '0';
|
|
225
|
+
display.style.right = '0';
|
|
226
|
+
display.style.top = '0';
|
|
227
|
+
display.style.transform = 'rotate(180deg)';
|
|
228
|
+
display.style.overflowY = 'auto';
|
|
229
|
+
display.style.padding = '20px';
|
|
230
|
+
display.style.background = 'white';
|
|
231
|
+
|
|
232
|
+
// Position microphone instruction at the top (appears at bottom due to rotation)
|
|
233
|
+
allowMicrophoneElement.innerText = '';
|
|
234
|
+
allowMicrophoneElement.style.position = 'fixed';
|
|
235
|
+
allowMicrophoneElement.style.top = '20px';
|
|
236
|
+
allowMicrophoneElement.style.left = '50%';
|
|
237
|
+
allowMicrophoneElement.style.transform = 'translateX(-50%) rotate(180deg)';
|
|
238
|
+
allowMicrophoneElement.style.width = '90%';
|
|
239
|
+
allowMicrophoneElement.style.textAlign = 'center';
|
|
240
|
+
allowMicrophoneElement.style.zIndex = '1000';
|
|
241
|
+
|
|
242
|
+
let lock = null;
|
|
243
|
+
try {
|
|
244
|
+
if ('wakeLock' in navigator) {
|
|
245
|
+
lock = await navigator.wakeLock.request('screen');
|
|
246
|
+
}
|
|
247
|
+
} catch (err) {
|
|
248
|
+
console.log(err);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const webAudioDeviceNames = {microphone: '', deviceID: ''};
|
|
252
|
+
const externalMicList = ['UMIK', 'Airpods', 'Bluetooth'];
|
|
253
|
+
try {
|
|
254
|
+
const stream = await navigator.mediaDevices.getUserMedia({audio: true});
|
|
255
|
+
if (stream) {
|
|
256
|
+
const devices = await navigator.mediaDevices.enumerateDevices();
|
|
257
|
+
const mics = devices.filter(device => device.kind === 'audioinput');
|
|
258
|
+
mics.forEach(mic => {
|
|
259
|
+
if (externalMicList.some(externalMic => mic.label.includes(externalMic))) {
|
|
260
|
+
webAudioDeviceNames.microphone = mic.label;
|
|
261
|
+
webAudioDeviceNames.deviceID = mic.deviceId;
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
if (webAudioDeviceNames.microphone === '') {
|
|
265
|
+
webAudioDeviceNames.microphone = mics[0].label;
|
|
266
|
+
webAudioDeviceNames.deviceID = mics[0].deviceId;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
} catch (err) {
|
|
270
|
+
console.log(err);
|
|
271
|
+
}
|
|
272
|
+
window.listener.setMicrophoneFromAPI(webAudioDeviceNames.microphone);
|
|
273
|
+
window.listener.setMicrophoneDeviceId(webAudioDeviceNames.microphone);
|
|
274
|
+
// show target element
|
|
275
|
+
targetElement.style.display = 'block';
|
|
276
|
+
await window.listener.startCalibration();
|
|
277
|
+
if (lock) {
|
|
278
|
+
lock.release();
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Wrap the initialization in an IIFE
|
|
284
|
+
(async function initializeSmartPhoneMode() {
|
|
285
|
+
await initializeListener();
|
|
286
|
+
|
|
287
|
+
const timeout = 30000; // 30 seconds timeout
|
|
288
|
+
const startTime = Date.now();
|
|
289
|
+
|
|
290
|
+
// Wait for peer connection setup with timeout
|
|
291
|
+
while (Date.now() - startTime < timeout) {
|
|
292
|
+
if (
|
|
293
|
+
window.listener.peer.id !== null &&
|
|
294
|
+
window.listener.conn !== null &&
|
|
295
|
+
window.listener.connOpen
|
|
296
|
+
) {
|
|
297
|
+
console.log('Connection established successfully');
|
|
298
|
+
await checkAndRequestMicrophonePermission();
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
console.log('Waiting for connection setup...');
|
|
302
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
116
303
|
}
|
|
117
|
-
|
|
304
|
+
|
|
305
|
+
// If we get here, we've timed out
|
|
306
|
+
console.error('Connection setup timed out after 30 seconds');
|
|
307
|
+
allowMicrophoneElement.innerText = phrases.RC_microphonePermissionDenied['en-US'];
|
|
308
|
+
await window.listener.sendPermissionStatus({
|
|
309
|
+
type: 'error',
|
|
310
|
+
error: 'Connection setup timed out after 30 seconds',
|
|
311
|
+
});
|
|
312
|
+
})().catch(console.error);
|
|
118
313
|
break;
|
|
119
314
|
case 'false':
|
|
315
|
+
// Initialize listener immediately
|
|
316
|
+
listenerParameters.microphoneDeviceId = urlParams.get('deviceId');
|
|
317
|
+
window.listener = new Listener(listenerParameters);
|
|
318
|
+
|
|
120
319
|
// remove the button
|
|
121
320
|
const calibrationBeginButton2 = document.getElementById('calibrationBeginButton');
|
|
122
321
|
calibrationBeginButton2.remove();
|
|
123
322
|
container.style.display = 'block';
|
|
124
|
-
// event listener for when the page is loaded
|
|
125
323
|
|
|
126
|
-
window.addEventListener('load', () => {
|
|
324
|
+
window.addEventListener('load', async () => {
|
|
127
325
|
// set the text of the html elements
|
|
128
|
-
recordingInProgressElement.
|
|
129
|
-
allowMicrophoneElement.
|
|
326
|
+
recordingInProgressElement.innerText = recordingInProgress;
|
|
327
|
+
allowMicrophoneElement.innerText = allowMicrophone;
|
|
130
328
|
|
|
131
329
|
recordingInProgressElement.style.whiteSpace = 'nowrap';
|
|
132
330
|
recordingInProgressElement.style.fontWeight = 'bold';
|
|
@@ -143,10 +341,10 @@ switch (isSmartPhone) {
|
|
|
143
341
|
const message = document.getElementById('message');
|
|
144
342
|
message.style.lineHeight = '2.5rem';
|
|
145
343
|
const p = document.createElement('p');
|
|
146
|
-
p.
|
|
344
|
+
p.innerText = backToExperimentWindow;
|
|
147
345
|
message.appendChild(p);
|
|
148
|
-
|
|
149
|
-
window.listener
|
|
346
|
+
|
|
347
|
+
await window.listener.startCalibration();
|
|
150
348
|
console.log(window.listener);
|
|
151
349
|
});
|
|
152
350
|
break;
|
package/src/main.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import Listener from './peer-connection/listener';
|
|
1
|
+
// import Listener from './peer-connection/listener';
|
|
2
2
|
import Speaker from './peer-connection/speaker';
|
|
3
3
|
|
|
4
4
|
import VolumeCalibration from './tasks/volume/volume';
|
|
@@ -12,7 +12,6 @@ import {
|
|
|
12
12
|
} from './peer-connection/peerErrors';
|
|
13
13
|
|
|
14
14
|
export {
|
|
15
|
-
Listener,
|
|
16
15
|
Speaker,
|
|
17
16
|
VolumeCalibration,
|
|
18
17
|
ImpulseResponseCalibration,
|
|
@@ -32,6 +32,7 @@ class Listener extends AudioPeer {
|
|
|
32
32
|
// previous calibrateSoundSamplingDesiredBits
|
|
33
33
|
urlParameters.bits !== null && urlParameters.bits !== undefined ? urlParameters.bits : 24;
|
|
34
34
|
this.speakerPeerId = urlParameters.speakerPeerId;
|
|
35
|
+
this.connOpen = false;
|
|
35
36
|
|
|
36
37
|
this.peer.on('open', this.onPeerOpen);
|
|
37
38
|
this.peer.on('connection', this.onPeerConnection);
|
|
@@ -71,22 +72,22 @@ class Listener extends AudioPeer {
|
|
|
71
72
|
onConnData = data => {
|
|
72
73
|
this.displayUpdate('Listener - onConnData');
|
|
73
74
|
const hasSpeakerID = Object.prototype.hasOwnProperty.call(data, 'speakerPeerId');
|
|
74
|
-
if (!hasSpeakerID) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
} else {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
75
|
+
// if (!hasSpeakerID) {
|
|
76
|
+
// this.displayUpdate('Error in parsing data received! Must set "speakerPeerId" property');
|
|
77
|
+
// throw new MissingSpeakerIdError('Must set "speakerPeerId" property');
|
|
78
|
+
// } else {
|
|
79
|
+
// // this.conn.close();
|
|
80
|
+
// this.displayUpdate(this.speakerPeerId);
|
|
81
|
+
// this.speakerPeerId = data.speakerPeerId;
|
|
82
|
+
// const newParams = {
|
|
83
|
+
// speakerPeerId: this.speakerPeerId,
|
|
84
|
+
// };
|
|
85
|
+
// /*
|
|
86
|
+
// FUTURE does this limit usable environments?
|
|
87
|
+
// ie does this work if internet is lost after initial page load?
|
|
88
|
+
// */
|
|
89
|
+
// window.location.search = this.queryStringFromObject(newParams); // Redirect to correctly constructed keypad page
|
|
90
|
+
// }
|
|
90
91
|
};
|
|
91
92
|
|
|
92
93
|
join = async () => {
|
|
@@ -112,18 +113,23 @@ class Listener extends AudioPeer {
|
|
|
112
113
|
this.displayUpdate('Created connection');
|
|
113
114
|
this.conn.on('open', async () => {
|
|
114
115
|
this.displayUpdate('Listener - conn open');
|
|
116
|
+
this.connOpen = true;
|
|
115
117
|
await this.getDeviceInfo();
|
|
116
118
|
// this.sendSamplingRate();
|
|
117
|
-
await this.openAudioStream();
|
|
118
119
|
});
|
|
119
120
|
|
|
120
121
|
// Handle incoming data (messages only since this is the signal sender)
|
|
121
122
|
this.conn.on('data', this.onConnData);
|
|
122
123
|
this.conn.on('close', () => {
|
|
123
124
|
console.log('Connection closed');
|
|
125
|
+
this.connOpen = false;
|
|
124
126
|
});
|
|
125
127
|
};
|
|
126
128
|
|
|
129
|
+
startCalibration = async () => {
|
|
130
|
+
await this.openAudioStream();
|
|
131
|
+
};
|
|
132
|
+
|
|
127
133
|
getMobileOS = () => {
|
|
128
134
|
const ua = navigator.userAgent;
|
|
129
135
|
if (/android/i.test(ua)) {
|
|
@@ -163,6 +169,14 @@ class Listener extends AudioPeer {
|
|
|
163
169
|
});
|
|
164
170
|
};
|
|
165
171
|
|
|
172
|
+
sendPermissionStatus = status => {
|
|
173
|
+
// this.displayUpdate('Listener - sendPermissionStatus');
|
|
174
|
+
this.conn.send({
|
|
175
|
+
name: 'permissionStatus',
|
|
176
|
+
payload: status,
|
|
177
|
+
});
|
|
178
|
+
};
|
|
179
|
+
|
|
166
180
|
getDeviceInfo = async () => {
|
|
167
181
|
const deviceInfo = {};
|
|
168
182
|
try {
|
|
@@ -271,6 +285,12 @@ class Listener extends AudioPeer {
|
|
|
271
285
|
|
|
272
286
|
return contraints;
|
|
273
287
|
};
|
|
288
|
+
setMicrophoneFromAPI = microphoneFromAPI => {
|
|
289
|
+
this.microphoneFromAPI = microphoneFromAPI;
|
|
290
|
+
};
|
|
291
|
+
setMicrophoneDeviceId = microphoneDeviceId => {
|
|
292
|
+
this.microphoneDeviceId = microphoneDeviceId;
|
|
293
|
+
};
|
|
274
294
|
getDeviceIdByLabel = async targetLabel => {
|
|
275
295
|
try {
|
|
276
296
|
//get permission to use audio first. (Returns empty labels on some computers if not done first)
|