speaker-calibration 2.2.204 → 2.2.206

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "speaker-calibration",
3
- "version": "2.2.204",
3
+ "version": "2.2.206",
4
4
  "description": "Speaker calibration library for auditory testing",
5
5
  "main": "dist/main.js",
6
6
  "directories": {
@@ -26,16 +26,11 @@ class Listener extends AudioPeer {
26
26
 
27
27
  const urlParameters = this.parseURLSearchParams();
28
28
  this.calibrateSoundHz =
29
- // previous calibrateSoundHz
30
- urlParameters.hz !== null && urlParameters.hz !== undefined
31
- ? urlParameters.hz
32
- : 48000;
29
+ // previous calibrateSoundHz
30
+ urlParameters.hz !== null && urlParameters.hz !== undefined ? urlParameters.hz : 48000;
33
31
  this.calibrateSoundSamplingDesiredBits =
34
- // previous calibrateSoundSamplingDesiredBits
35
- urlParameters.bits !== null &&
36
- urlParameters.bits !== undefined
37
- ? urlParameters.bits
38
- : 24;
32
+ // previous calibrateSoundSamplingDesiredBits
33
+ urlParameters.bits !== null && urlParameters.bits !== undefined ? urlParameters.bits : 24;
39
34
  this.speakerPeerId = urlParameters.speakerPeerId;
40
35
 
41
36
  this.peer.on('open', this.onPeerOpen);
@@ -161,9 +156,9 @@ class Listener extends AudioPeer {
161
156
  this.displayUpdate('Listener - sendFlags');
162
157
  this.conn.send({
163
158
  name: 'flags',
164
- payload: flags
159
+ payload: flags,
165
160
  });
166
- }
161
+ };
167
162
 
168
163
  getDeviceInfo = async () => {
169
164
  try {
@@ -200,7 +195,9 @@ class Listener extends AudioPeer {
200
195
 
201
196
  applyHQTrackConstraints = async stream => {
202
197
  // Contraint the incoming audio to the sampling rate we want
203
- stream.getAudioTracks().forEach(track => {console.log(track, track.enabled)});
198
+ stream.getAudioTracks().forEach(track => {
199
+ console.log(track, track.enabled);
200
+ });
204
201
  const track = stream.getAudioTracks()[0];
205
202
  console.log(track);
206
203
  const capabilities = track.getCapabilities();
@@ -242,47 +239,54 @@ class Listener extends AudioPeer {
242
239
  return settings;
243
240
  };
244
241
 
245
- getMediaDevicesAudioContraints = () => {
242
+ getMediaDevicesAudioContraints = async () => {
246
243
  const availableConstraints = navigator.mediaDevices.getSupportedConstraints();
247
244
 
248
- this.displayUpdate(
249
- `Listener MediaDevices Available Contraints - ${JSON.stringify(
250
- availableConstraints,
251
- undefined,
252
- 2
253
- )}`
254
- );
255
-
256
245
  const contraints = {
257
246
  // ...(availableConstraints.echoCancellation && availableConstraints.echoCancellation == true
258
247
  // ? {echoCancellation: {exact: false}}
259
248
  // : {}),
260
- ...(availableConstraints.sampleRate && availableConstraints.sampleRate == true
261
- ? {sampleRate: {ideal: this.calibrateSoundHz}}
262
- : {}),
263
- ...(availableConstraints.sampleSize && availableConstraints.sampleSize == true
264
- ? {sampleSize: {ideal: this.calibrateSoundSamplingDesiredBits}}
265
- : {}),
266
- ...(availableConstraints.channelCount && availableConstraints.channelCount == true
267
- ? {channelCount: {exact: 1}}
268
- : {}),
249
+ // ...(availableConstraints.sampleRate && availableConstraints.sampleRate == true
250
+ // ? {sampleRate: {ideal: this.calibrateSoundHz}}
251
+ // : {}),
252
+ // ...(availableConstraints.sampleSize && availableConstraints.sampleSize == true
253
+ // ? {sampleSize: {ideal: this.calibrateSoundSamplingDesiredBits}}
254
+ // : {}),
255
+ // ...(availableConstraints.channelCount && availableConstraints.channelCount == true
256
+ // ? {channelCount: {exact: 1}}
257
+ // : {}),
269
258
  echoCancellation: false,
270
- noiseSuppression: false,
271
- autoGainControl: false,
259
+ channelCount: 1,
272
260
  };
273
261
 
274
262
  if (this.microphoneDeviceId !== '') {
275
- contraints.deviceId = {exact: this.microphoneDeviceId};
263
+ contraints.deviceId = {exact: await this.getDeviceIdByLabel(this.microphoneDeviceId)};
276
264
  }
277
265
 
278
266
  console.log(contraints);
279
267
 
280
- this.displayUpdate(
281
- `Listener MediaDevices Contraints - ${JSON.stringify(contraints, undefined, 2)}`
282
- );
283
-
284
268
  return contraints;
285
269
  };
270
+ getDeviceIdByLabel = async targetLabel => {
271
+ try {
272
+ // Enumerate available media devices
273
+ const devices = await navigator.mediaDevices.enumerateDevices();
274
+
275
+ // Find the device with the matching label
276
+ const matchingDevice = devices.find(
277
+ device => device.kind === 'audioinput' && device.label === targetLabel
278
+ );
279
+
280
+ if (matchingDevice) {
281
+ return matchingDevice.deviceId; // Return the deviceId if found
282
+ } else {
283
+ throw new Error(`No audio input device found with label: "${targetLabel}"`);
284
+ }
285
+ } catch (error) {
286
+ console.error('Error finding device ID:', error);
287
+ return null;
288
+ }
289
+ };
286
290
 
287
291
  openAudioStream = async () => {
288
292
  this.displayUpdate('Listener - openAudioStream');
@@ -295,28 +299,35 @@ class Listener extends AudioPeer {
295
299
  });
296
300
  return;
297
301
  }
298
-
302
+ const constraints = await this.getMediaDevicesAudioContraints();
303
+ console.log('Constraints right before getUserMedia:', constraints);
299
304
  navigator.mediaDevices
300
305
  .getUserMedia({
301
- // audio: this.getMediaDevicesAudioContraints(),
302
- audio: {echoCancellation: false, channelCount: 1},
306
+ audio: constraints,
303
307
  video: false,
308
+ //audio: {echoCancellation: false, noiseSuppression: false, autoGainControl: false, deviceId: {exact: await this.getDeviceIdByLabel(this.microphoneDeviceId) }},
304
309
  })
305
310
  .then(stream => {
306
- this.displayUpdate(`Listener Track settings before applied constraints - ${JSON.stringify(stream.getAudioTracks()[0].getSettings(), undefined, 2)}`);
311
+ this.displayUpdate(
312
+ `Listener Track settings before applied constraints - ${JSON.stringify(
313
+ stream.getAudioTracks()[0].getSettings(),
314
+ undefined,
315
+ 2
316
+ )}`
317
+ );
307
318
  this.applyHQTrackConstraints(stream)
308
319
  .then(settings => {
309
320
  console.log(settings);
310
321
  this.sendSamplingRate(settings.sampleRate);
311
322
  let sampleSize = settings.sampleSize;
312
- if (!sampleSize){
323
+ if (!sampleSize) {
313
324
  sampleSize = this.calibrateSoundSamplingDesiredBits;
314
325
  }
315
326
  this.sendSampleSize(sampleSize);
316
327
  this.sendFlags({
317
- 'autoGainControl':settings.autoGainControl,
318
- 'noiseSuppression':settings.noiseSuppression,
319
- 'echoCancellation':settings.echoCancellation
328
+ autoGainControl: settings.autoGainControl,
329
+ noiseSuppression: settings.noiseSuppression,
330
+ echoCancellation: settings.echoCancellation,
320
331
  });
321
332
  this.peer.call(this.speakerPeerId, stream); // one-way call
322
333
  this.displayUpdate('Listener - openAudioStream');
@@ -330,6 +341,15 @@ class Listener extends AudioPeer {
330
341
  })
331
342
  .catch(err => {
332
343
  console.error(err);
344
+ if (err.name === 'OverconstrainedError') {
345
+ const constraint = err.constraint;
346
+ const message = `The constraint "${constraint}" cannot be satisfied by the selected microphone. Please adjust your calibration settings or choose a different microphone.`;
347
+
348
+ this.displayUpdate(`Listener - OverconstrainedError: ${message}`);
349
+ console.error(message);
350
+
351
+ alert(`Overconstrained Error: ${message}`);
352
+ }
333
353
  this.displayUpdate(
334
354
  `Listener - Error in getUserMedia - ${JSON.stringify(err, undefined, 2)}`
335
355
  );
@@ -7,7 +7,7 @@ import {
7
7
  CalibrationTimedOutError,
8
8
  } from './peerErrors';
9
9
 
10
- import {phrases} from '../../dist/example/i18n';
10
+ //import {phrases} from '../../dist/example/i18n';
11
11
 
12
12
  /**
13
13
  * @class Handles the speaker's side of the connection. Responsible for initiating the connection,
@@ -41,7 +41,9 @@ class Speaker extends AudioPeer {
41
41
  this.timeToCalibrate = params?.timeToCalibrate ?? 10;
42
42
  this.isParticipant = params?.isParticipant ?? false;
43
43
  this.isLoudspeakerCalibration = params?.isLoudspeakerCalibration ?? false;
44
+ this.deviceId = params?.micrpohoneIdFromWebAudioApi ?? '';
44
45
  this.buttonsContainer = params?.buttonsContainer ?? document.createElement('div');
46
+ this.phrases = params?. phrases ?? {};
45
47
 
46
48
  /* Set up callbacks that handle any events related to our peer object. */
47
49
  }
@@ -207,6 +209,7 @@ class Speaker extends AudioPeer {
207
209
  params.calibrateSoundSamplingDesiredBits,
208
210
  params.language,
209
211
  params.loudspeakerModelName,
212
+ params.phrases,
210
213
  );
211
214
  speaker.#removeUIElems();
212
215
  resolve(speaker.result);
@@ -284,6 +287,7 @@ class Speaker extends AudioPeer {
284
287
  hz: this.calibrateSoundHz,
285
288
  bits: this.calibrateSoundSamplingDesiredBits,
286
289
  lang: this.language,
290
+ deviceId: this.deviceId
287
291
  };
288
292
  const queryString = this.queryStringFromObject(queryStringParameters);
289
293
  this.uri = this.siteUrl + queryString;
@@ -327,10 +331,10 @@ class Speaker extends AudioPeer {
327
331
  })
328
332
  .then(data => {
329
333
  explanation.innerHTML = formatLineBreak(
330
- phrases.RC_skipQR_ExplanationWithoutPreferNot[this.language]
334
+ this.phrases.RC_skipQR_ExplanationWithoutPreferNot[this.language]
331
335
  .replace('xxx', `<b style="user-select: text">${data.shortURL}</b>`)
332
336
  .replace('XXX', `<b style="user-select: text">${data.shortURL}</b>`),
333
- phrases.RC_checkInternetConnection[this.language]
337
+ this.phrases.RC_checkInternetConnection[this.language]
334
338
  );
335
339
  const checkConnection = document.createElement('a');
336
340
  checkConnection.id = 'check-connection';
@@ -340,7 +344,7 @@ class Speaker extends AudioPeer {
340
344
  checkConnection.addEventListener('click', function (event) {
341
345
  console.log('clicked');
342
346
  event.preventDefault(); // Prevent the default link action
343
- createAndShowPopup(lang);
347
+ createAndShowPopup(lang, this.phrases);
344
348
  });
345
349
  explanation.querySelector('a#check-connection').replaceWith(checkConnection);
346
350
  })
@@ -386,7 +390,7 @@ class Speaker extends AudioPeer {
386
390
  const proceedButton = document.createElement('button');
387
391
  proceedButton.setAttribute('id', 'calibrationProceedButton');
388
392
  proceedButton.setAttribute('class', 'btn btn-success');
389
- proceedButton.innerHTML = phrases.T_proceed[this.language];
393
+ proceedButton.innerHTML = this.phrases.T_proceed[this.language];
390
394
  proceedButton.onclick = () => {
391
395
  // open the link in a new tab
392
396
  window.open(this.uri, '_blank');
@@ -423,7 +427,7 @@ class Speaker extends AudioPeer {
423
427
  instructionDisplay.style.whiteSpace = 'nowrap';
424
428
  instructionDisplay.style.fontWeight = 'bold';
425
429
  instructionDisplay.style.width = 'fit-content';
426
- instructionDisplay.innerHTML = phrases.RC_soundRecording[this.language];
430
+ instructionDisplay.innerHTML = this.phrases.RC_soundRecording[this.language];
427
431
  let fontSize = 100;
428
432
  instructionDisplay.style.fontSize = fontSize + 'px';
429
433
  while (instructionDisplay.scrollWidth > background.scrollWidth * 0.9 && fontSize > 10) {
@@ -442,7 +446,7 @@ class Speaker extends AudioPeer {
442
446
 
443
447
  const timeToCalibrateDisplay = document.getElementById(this.timeToCalibrateDisplay);
444
448
  if (timeToCalibrateDisplay) {
445
- const timeToCalibrateText = phrases.RC_howLongToCalibrate[this.language];
449
+ const timeToCalibrateText = this.phrases.RC_howLongToCalibrate[this.language];
446
450
  timeToCalibrateDisplay.innerHTML = timeToCalibrateText.replace('111', this.timeToCalibrate);
447
451
  timeToCalibrateDisplay.style.fontWeight = 'normal';
448
452
  timeToCalibrateDisplay.style.fontSize = '1rem';
@@ -469,13 +473,13 @@ class Speaker extends AudioPeer {
469
473
  } else if (this.isSmartPhone) {
470
474
  titleDisplay.innerHTML = titleDisplay.innerHTML.replace('6', '7');
471
475
  } else {
472
- titleDisplay.innerHTML = titleDisplay.innerHTML.replace('5', '6');
476
+ titleDisplay.innerHTML = titleDisplay.innerHTML.replace('4', '5');
473
477
  }
474
478
  } else {
475
479
  if (this.isSmartPhone) {
476
480
  titleDisplay.innerHTML = titleDisplay.innerHTML.replace('5', '6');
477
481
  } else {
478
- titleDisplay.innerHTML = titleDisplay.innerHTML.replace('4', '5');
482
+ titleDisplay.innerHTML = titleDisplay.innerHTML.replace('3', '4');
479
483
  }
480
484
  }
481
485
  }
@@ -714,6 +718,7 @@ class Speaker extends AudioPeer {
714
718
  params.calibrateSoundSamplingDesiredBits,
715
719
  params.language,
716
720
  params.loudspeakerModelName,
721
+ params.phrases,
717
722
  );
718
723
  this.#removeUIElems();
719
724
  resolve(result);
@@ -32,7 +32,7 @@ import {
32
32
  where,
33
33
  Timestamp,
34
34
  } from 'firebase/firestore';
35
- import { phrases } from '../../../dist/example/i18n';
35
+ //import { phrases } from '../../../dist/example/i18n';
36
36
 
37
37
  /**
38
38
  *
@@ -312,7 +312,7 @@ class Combination extends AudioCalibrator {
312
312
  let systemSD = '';
313
313
  let flags = '';
314
314
  const reportWebAudioNames = `<strong>${this.webAudioDeviceNames.loudspeakerText} </strong> <strong>${this.webAudioDeviceNames.microphoneText} </strong>`;
315
- const samplingParamText = phrases.RC_SamplingHzBits[this.language].replace('111', this.sourceSamplingRate).replace('222',this.sinkSamplingRate).replace('333', this.calibrateSoundSamplingDesiredBits);
315
+ const samplingParamText = this.phrases.RC_SamplingHzBits[this.language].replace('111', this.sourceSamplingRate).replace('222',this.sinkSamplingRate).replace('333', this.calibrateSoundSamplingDesiredBits);
316
316
  const reportParameters = `${samplingParamText}`;
317
317
  if (this.flags) {
318
318
  flags = `<br> autoGainControl: ${this.flags.autoGainControl};
@@ -2735,6 +2735,7 @@ class Combination extends AudioCalibrator {
2735
2735
  calibrateSoundSamplingDesiredBits = 24,
2736
2736
  language,
2737
2737
  loudspeakerModelName='',
2738
+ phrases,
2738
2739
 
2739
2740
  ) => {
2740
2741
  this._calibrateSoundBurstPreSec = _calibrateSoundBurstPreSec;
@@ -2772,7 +2773,17 @@ class Combination extends AudioCalibrator {
2772
2773
  this._calibrateSoundBurstScalarDB = _calibrateSoundBurstScalarDB;
2773
2774
  this.webAudioDeviceNames = webAudioDeviceNames;
2774
2775
  this.calibrateSoundSamplingDesiredBits = calibrateSoundSamplingDesiredBits;
2775
- if (isSmartPhone) this.webAudioDeviceNames.microphone = this.deviceInfo.microphoneFromAPI;
2776
+ this.phrases = phrases;
2777
+ if (isSmartPhone) {
2778
+ const leftQuote = "\u201C"; // “
2779
+ const rightQuote = "\u201D"; // ”
2780
+ this.webAudioDeviceNames.microphone = this.deviceInfo.microphoneFromAPI;
2781
+ const quotedWebAudioMic = leftQuote + this.webAudioDeviceNames.microphone + rightQuote;
2782
+ const combinedMicText = this.micModelName + " " + quotedWebAudioMic;
2783
+ webAudioDeviceNames.microphoneText = this.phrases.RC_nameMicrophone[this.language]
2784
+ .replace("“xxx”", combinedMicText)
2785
+ .replace("“XXX”", combinedMicText);
2786
+ }
2776
2787
  // this.webAudioDeviceNames.microphoneText = this.webAudioDeviceNames.microphoneText
2777
2788
  // .replace('xxx', this.webAudioDeviceNames.microphone)
2778
2789
  // .replace('XXX', this.webAudioDeviceNames.microphone);
package/src/utils.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import Swal from "sweetalert2";
2
- import {phrases} from '../dist/example/i18n.js';
2
+ //import {phrases} from '../dist/example/i18n.js';
3
3
  /** .
4
4
  * .
5
5
  * .
@@ -147,7 +147,7 @@ export const formatLineBreak =(inputStr,checkInternetConnection) => {
147
147
 
148
148
 
149
149
 
150
- export const createAndShowPopup = (lang) => {
150
+ export const createAndShowPopup = (lang, phrases) => {
151
151
  console.log(`
152
152
  <div style="text-align: left;">
153
153
  ${convertAsterisksToList(phrases.RC_NeedInternetConnectedPhone[lang].replace(/\n/g, '<br>'))}