speaker-calibration 2.2.218 → 2.2.220

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.
@@ -1,6 +1,7 @@
1
1
  import AudioPeer from './audioPeer';
2
2
  import {UnsupportedDeviceError, MissingSpeakerIdError} from './peerErrors';
3
3
  import axios from 'axios';
4
+ import Peer from 'peerjs';
4
5
 
5
6
  /**
6
7
  * @class Handles the listener's side of the connection. Responsible for getting access to user's microphone,
@@ -16,6 +17,7 @@ class Listener extends AudioPeer {
16
17
  */
17
18
  constructor(params) {
18
19
  super(params);
20
+ console.log('Listener constructor', this.peer);
19
21
  this.microphoneFromAPI = params.microphoneFromAPI ? params.microphoneFromAPI : '';
20
22
  this.microphoneDeviceId = params.microphoneDeviceId ? params.microphoneDeviceId : '';
21
23
  // this.deviceInfoFromUser = params.deviceInfoFromUser
@@ -32,16 +34,92 @@ class Listener extends AudioPeer {
32
34
  // previous calibrateSoundSamplingDesiredBits
33
35
  urlParameters.bits !== null && urlParameters.bits !== undefined ? urlParameters.bits : 24;
34
36
  this.speakerPeerId = urlParameters.speakerPeerId;
35
-
36
- this.peer.on('open', this.onPeerOpen);
37
- this.peer.on('connection', this.onPeerConnection);
38
- this.peer.on('disconnected', this.onPeerDisconnected);
39
- this.peer.on('close', this.onPeerClose);
40
- this.peer.on('error', this.onPeerError);
37
+ this.lastPeerId = this.speakerPeerId;
38
+ this.connOpen = false;
41
39
  }
40
+ generateTimeBasedPeerID = async () => {
41
+ const now = new Date().getTime();
42
+ const randomBuffer = new Uint8Array(10);
43
+ crypto.getRandomValues(randomBuffer);
44
+ const randomPart = Array.from(randomBuffer)
45
+ .map(b => b.toString(36))
46
+ .join('');
47
+ const toHash = `${now}-${randomPart}`;
48
+ const encoder = new TextEncoder();
49
+ const data = encoder.encode(toHash);
50
+ const hash = await crypto.subtle.digest('SHA-256', data);
51
+ const hashArray = Array.from(new Uint8Array(hash));
52
+ const hashString = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
53
+ const shortHash = hashString.substring(0, 12);
54
+ return this.encodeBase62(parseInt(shortHash, 16));
55
+ };
56
+
57
+ encodeBase62 = num => {
58
+ const base = 26;
59
+ const characters = 'abcdefghijklmnopqrstuvwxyz';
60
+ let result = '';
61
+ while (num > 0) {
62
+ result = characters[num % base] + result;
63
+ num = Math.floor(num / base);
64
+ }
65
+ return result || 'a';
66
+ };
67
+
68
+ initializePeer = async () => {
69
+ console.log('Initializing PeerJS connection...');
70
+ const id = await this.generateTimeBasedPeerID();
71
+ console.log('Generated Peer ID:', id);
72
+
73
+ try {
74
+ this.peer = new Peer(id, {
75
+ debug: 2,
76
+ host: 'easyeyes-peer-server.herokuapp.com',
77
+ port: 443,
78
+ secure: true,
79
+ config: {
80
+ iceServers: [
81
+ {
82
+ urls: 'stun:stun.relay.metered.ca:80',
83
+ },
84
+ {
85
+ urls: 'turn:global.relay.metered.ca:80',
86
+ username: 'de884cfc34189cdf1a5dd616',
87
+ credential: 'IcOpouU9/TYBmpHU',
88
+ },
89
+ {
90
+ urls: 'turn:global.relay.metered.ca:80?transport=tcp',
91
+ username: 'de884cfc34189cdf1a5dd616',
92
+ credential: 'IcOpouU9/TYBmpHU',
93
+ },
94
+ {
95
+ urls: 'turn:global.relay.metered.ca:443',
96
+ username: 'de884cfc34189cdf1a5dd616',
97
+ credential: 'IcOpouU9/TYBmpHU',
98
+ },
99
+ {
100
+ urls: 'turns:global.relay.metered.ca:443?transport=tcp',
101
+ username: 'de884cfc34189cdf1a5dd616',
102
+ credential: 'IcOpouU9/TYBmpHU',
103
+ },
104
+ ],
105
+ },
106
+ });
107
+
108
+ this.peer.on('open', this.onPeerOpen);
109
+ this.peer.on('connection', this.onPeerConnection);
110
+ this.peer.on('disconnected', this.onPeerDisconnected);
111
+ this.peer.on('close', this.onPeerClose);
112
+ this.peer.on('error', this.onPeerError);
113
+
114
+ console.log('Peer object created:', this.peer);
115
+ } catch (error) {
116
+ console.error('Failed to initialize PeerJS:', error);
117
+ }
118
+ };
42
119
 
43
120
  onPeerOpen = id => {
44
121
  this.displayUpdate('Listener - onPeerOpen');
122
+ console.log('onPeerOpen: ', id);
45
123
  // Workaround for peer.reconnect deleting previous id
46
124
  try {
47
125
  if (id === null) {
@@ -53,12 +131,12 @@ class Listener extends AudioPeer {
53
131
  } catch (error) {
54
132
  console.error('Error in onPeerOpen: ', error);
55
133
  }
56
-
57
134
  this.join();
58
135
  };
59
136
 
60
137
  onPeerConnection = connection => {
61
138
  this.displayUpdate('Listener - onPeerConnection');
139
+ console.log('onPeerConnection: ', connection);
62
140
  // Disallow incoming connections
63
141
  connection.on('open', () => {
64
142
  connection.send('Sender does not accept incoming connections');
@@ -71,26 +149,27 @@ class Listener extends AudioPeer {
71
149
  onConnData = data => {
72
150
  this.displayUpdate('Listener - onConnData');
73
151
  const hasSpeakerID = Object.prototype.hasOwnProperty.call(data, 'speakerPeerId');
74
- if (!hasSpeakerID) {
75
- this.displayUpdate('Error in parsing data received! Must set "speakerPeerId" property');
76
- throw new MissingSpeakerIdError('Must set "speakerPeerId" property');
77
- } else {
78
- // this.conn.close();
79
- this.displayUpdate(this.speakerPeerId);
80
- this.speakerPeerId = data.speakerPeerId;
81
- const newParams = {
82
- speakerPeerId: this.speakerPeerId,
83
- };
84
- /*
85
- FUTURE does this limit usable environments?
86
- ie does this work if internet is lost after initial page load?
87
- */
88
- window.location.search = this.queryStringFromObject(newParams); // Redirect to correctly constructed keypad page
89
- }
152
+ // if (!hasSpeakerID) {
153
+ // this.displayUpdate('Error in parsing data received! Must set "speakerPeerId" property');
154
+ // throw new MissingSpeakerIdError('Must set "speakerPeerId" property');
155
+ // } else {
156
+ // // this.conn.close();
157
+ // this.displayUpdate(this.speakerPeerId);
158
+ // this.speakerPeerId = data.speakerPeerId;
159
+ // const newParams = {
160
+ // speakerPeerId: this.speakerPeerId,
161
+ // };
162
+ // /*
163
+ // FUTURE does this limit usable environments?
164
+ // ie does this work if internet is lost after initial page load?
165
+ // */
166
+ // window.location.search = this.queryStringFromObject(newParams); // Redirect to correctly constructed keypad page
167
+ // }
90
168
  };
91
169
 
92
170
  join = async () => {
93
171
  this.displayUpdate('Listener - join');
172
+ console.log(' Creating connection to: ', this.speakerPeerId);
94
173
  /**
95
174
  * Create the connection between the two Peers.
96
175
  *
@@ -112,18 +191,23 @@ class Listener extends AudioPeer {
112
191
  this.displayUpdate('Created connection');
113
192
  this.conn.on('open', async () => {
114
193
  this.displayUpdate('Listener - conn open');
115
- await this.getDeviceInfo();
194
+ this.connOpen = true;
116
195
  // this.sendSamplingRate();
117
- await this.openAudioStream();
118
196
  });
119
197
 
120
198
  // Handle incoming data (messages only since this is the signal sender)
121
199
  this.conn.on('data', this.onConnData);
122
200
  this.conn.on('close', () => {
123
201
  console.log('Connection closed');
202
+ this.connOpen = false;
124
203
  });
125
204
  };
126
205
 
206
+ startCalibration = async () => {
207
+ await this.getDeviceInfo();
208
+ await this.openAudioStream();
209
+ };
210
+
127
211
  getMobileOS = () => {
128
212
  const ua = navigator.userAgent;
129
213
  if (/android/i.test(ua)) {
@@ -163,6 +247,14 @@ class Listener extends AudioPeer {
163
247
  });
164
248
  };
165
249
 
250
+ sendPermissionStatus = status => {
251
+ // this.displayUpdate('Listener - sendPermissionStatus');
252
+ this.conn.send({
253
+ name: 'permissionStatus',
254
+ payload: status,
255
+ });
256
+ };
257
+
166
258
  getDeviceInfo = async () => {
167
259
  const deviceInfo = {};
168
260
  try {
@@ -271,6 +363,12 @@ class Listener extends AudioPeer {
271
363
 
272
364
  return contraints;
273
365
  };
366
+ setMicrophoneFromAPI = microphoneFromAPI => {
367
+ this.microphoneFromAPI = microphoneFromAPI;
368
+ };
369
+ setMicrophoneDeviceId = microphoneDeviceId => {
370
+ this.microphoneDeviceId = microphoneDeviceId;
371
+ };
274
372
  getDeviceIdByLabel = async targetLabel => {
275
373
  try {
276
374
  //get permission to use audio first. (Returns empty labels on some computers if not done first)
@@ -45,6 +45,7 @@ class Speaker extends AudioPeer {
45
45
  this.deviceId = params?.micrpohoneIdFromWebAudioApi ?? '';
46
46
  this.buttonsContainer = params?.buttonsContainer ?? document.createElement('div');
47
47
  this.phrases = params?.phrases ?? {};
48
+ this.permissionStatus = 'pending';
48
49
 
49
50
  /* Set up callbacks that handle any events related to our peer object. */
50
51
  }
@@ -138,10 +139,19 @@ class Speaker extends AudioPeer {
138
139
  await speaker.initPeer();
139
140
  // wrap the calibration process in a promise so we can await it
140
141
  return new Promise((resolve, reject) => {
142
+ // Add a permission check handler
143
+ const permissionCheckInterval = setInterval(() => {
144
+ if (speaker.permissionStatus === 'error' || speaker.permissionStatus === 'denied') {
145
+ clearInterval(permissionCheckInterval);
146
+ speaker.#removeUIElems();
147
+ resolve('permission denied');
148
+ }
149
+ }, 100);
150
+
141
151
  // when a call is received
142
152
  speaker.peer.on('call', async call => {
143
- // Answer the call (one way)
144
-
153
+ clearInterval(permissionCheckInterval); // Clear interval when call is received
154
+ // Rest of the existing call handling code...
145
155
  call.answer();
146
156
  speaker.#removeUIElems();
147
157
  speaker.#showSpinner();
@@ -218,6 +228,7 @@ class Speaker extends AudioPeer {
218
228
  });
219
229
  // if we do not receive a result within the timeout, reject
220
230
  setTimeout(() => {
231
+ clearInterval(permissionCheckInterval);
221
232
  reject(
222
233
  new CalibrationTimedOutError(
223
234
  `Calibration failed to produce a result after ${
@@ -657,6 +668,20 @@ class Speaker extends AudioPeer {
657
668
  this.ac.setDeviceInfo(data.payload);
658
669
  console.log('Received device info from listener: ', data.payload);
659
670
  break;
671
+ case 'permissionStatus':
672
+ console.log('Received permission status from listener: ', data.payload);
673
+ if (data.payload.type === 'error') {
674
+ this.permissionStatus = 'error';
675
+ this.ac.setPermissionStatus('error');
676
+ } else if (data.payload.type === 'denied') {
677
+ this.permissionStatus = 'denied';
678
+ this.ac.setPermissionStatus('denied');
679
+ } else if (data.payload.type === 'granted') {
680
+ this.permissionStatus = 'granted';
681
+ this.ac.setPermissionStatus('granted');
682
+ console.log('Permission granted');
683
+ }
684
+ break;
660
685
  case UnsupportedDeviceError.name:
661
686
  case MissingSpeakerIdError.name:
662
687
  throw data.payload;
@@ -700,59 +725,77 @@ class Speaker extends AudioPeer {
700
725
 
701
726
  console.log('This is a repeat');
702
727
  // wrap the calibration process in a promise so we can await it
703
- return new Promise(async (resolve, reject) => {
704
- const result = await this.ac.startCalibration(
705
- stream,
706
- params.gainValues,
707
- params.ICalib,
708
- params.knownIR,
709
- params.microphoneName,
710
- params.calibrateSoundCheck,
711
- params.isSmartPhone,
712
- params.calibrateSoundBurstDb,
713
- params.calibrateSoundBurstFilteredExtraDb,
714
- params.calibrateSoundBurstLevelReTBool,
715
- params.calibrateSoundBurstUses1000HzGainBool,
716
- params.calibrateSoundBurstRepeats,
717
- params.calibrateSoundBurstSec,
718
- params._calibrateSoundBurstPreSec,
719
- params._calibrateSoundBurstPostSec,
720
- params.calibrateSoundHz,
721
- params.calibrateSoundIRSec,
722
- params.calibrateSoundIIRSec,
723
- params.calibrateSoundIIRPhase,
724
- params.calibrateSound1000HzPreSec,
725
- params.calibrateSound1000HzSec,
726
- params.calibrateSound1000HzPostSec,
727
- params.calibrateSoundBackgroundSecs,
728
- params.calibrateSoundSmoothOctaves,
729
- params.calibrateSoundSmoothMinBandwidthHz,
730
- params.calibrateSoundPowerBinDesiredSec,
731
- params.calibrateSoundPowerDbSDToleratedDb,
732
- params.calibrateSoundTaperSec,
733
- params.micManufacturer,
734
- params.micSerialNumber,
735
- params.micModelNumber,
736
- params.micModelName,
737
- params.calibrateMicrophonesBool,
738
- params.authorEmails,
739
- params.webAudioDeviceNames,
740
- params.IDsToSaveInSoundProfileLibrary,
741
- params.restartButton,
742
- params.reminder,
743
- params.calibrateSoundLimit,
744
- params.calibrateSoundBurstNormalizeBy1000HzGainBool,
745
- params.calibrateSoundBurstScalarDB,
746
- params.calibrateSound1000HzMaxSD_dB,
747
- params._calibrateSoundBurstMaxSD_dB,
748
- params.calibrateSoundSamplingDesiredBits,
749
- params.language,
750
- params.loudspeakerModelName,
751
- params.phrases,
752
- params.soundSubtitleId
753
- );
754
- this.#removeUIElems();
755
- resolve(result);
728
+ return new Promise((resolve, reject) => {
729
+ // Add a permission check handler
730
+ const permissionCheckInterval = setInterval(() => {
731
+ if (this.permissionStatus === 'error' || this.permissionStatus === 'denied') {
732
+ clearInterval(permissionCheckInterval);
733
+ this.#removeUIElems();
734
+ resolve('permission denied');
735
+ }
736
+ }, 100);
737
+
738
+ // Start calibration process
739
+ (async () => {
740
+ try {
741
+ const result = await this.ac.startCalibration(
742
+ stream,
743
+ params.gainValues,
744
+ params.ICalib,
745
+ params.knownIR,
746
+ params.microphoneName,
747
+ params.calibrateSoundCheck,
748
+ params.isSmartPhone,
749
+ params.calibrateSoundBurstDb,
750
+ params.calibrateSoundBurstFilteredExtraDb,
751
+ params.calibrateSoundBurstLevelReTBool,
752
+ params.calibrateSoundBurstUses1000HzGainBool,
753
+ params.calibrateSoundBurstRepeats,
754
+ params.calibrateSoundBurstSec,
755
+ params._calibrateSoundBurstPreSec,
756
+ params._calibrateSoundBurstPostSec,
757
+ params.calibrateSoundHz,
758
+ params.calibrateSoundIRSec,
759
+ params.calibrateSoundIIRSec,
760
+ params.calibrateSoundIIRPhase,
761
+ params.calibrateSound1000HzPreSec,
762
+ params.calibrateSound1000HzSec,
763
+ params.calibrateSound1000HzPostSec,
764
+ params.calibrateSoundBackgroundSecs,
765
+ params.calibrateSoundSmoothOctaves,
766
+ params.calibrateSoundSmoothMinBandwidthHz,
767
+ params.calibrateSoundPowerBinDesiredSec,
768
+ params.calibrateSoundPowerDbSDToleratedDb,
769
+ params.calibrateSoundTaperSec,
770
+ params.micManufacturer,
771
+ params.micSerialNumber,
772
+ params.micModelNumber,
773
+ params.micModelName,
774
+ params.calibrateMicrophonesBool,
775
+ params.authorEmails,
776
+ params.webAudioDeviceNames,
777
+ params.IDsToSaveInSoundProfileLibrary,
778
+ params.restartButton,
779
+ params.reminder,
780
+ params.calibrateSoundLimit,
781
+ params.calibrateSoundBurstNormalizeBy1000HzGainBool,
782
+ params.calibrateSoundBurstScalarDB,
783
+ params.calibrateSound1000HzMaxSD_dB,
784
+ params._calibrateSoundBurstMaxSD_dB,
785
+ params.calibrateSoundSamplingDesiredBits,
786
+ params.language,
787
+ params.loudspeakerModelName,
788
+ params.phrases,
789
+ params.soundSubtitleId
790
+ );
791
+ clearInterval(permissionCheckInterval);
792
+ this.#removeUIElems();
793
+ resolve(result);
794
+ } catch (error) {
795
+ clearInterval(permissionCheckInterval);
796
+ reject(error);
797
+ }
798
+ })();
756
799
  });
757
800
  };
758
801
  }
@@ -296,6 +296,8 @@ class Combination extends AudioCalibrator {
296
296
  fs2;
297
297
  icapture = 0;
298
298
 
299
+ permissionStatus = null;
300
+
299
301
  /**generate string template that gets reevaluated as variable increases */
300
302
  generateTemplate = status => {
301
303
  if (this.isCalibrating) {
@@ -362,6 +364,10 @@ class Combination extends AudioCalibrator {
362
364
  this.deviceInfo = deviceInfo;
363
365
  };
364
366
 
367
+ setPermissionStatus = permissionStatus => {
368
+ this.permissionStatus = permissionStatus;
369
+ };
370
+
365
371
  /** .
366
372
  * .
367
373
  * .
@@ -3147,6 +3153,7 @@ class Combination extends AudioCalibrator {
3147
3153
  total_results['system']['phase'] = this.systemIRPhase;
3148
3154
  total_results['qualityMetrics'] = this.SDofFilteredRange;
3149
3155
  total_results['flags'] = this.flags;
3156
+ total_results['permissionStatus'] = this.permissionStatus;
3150
3157
  console.log('total results');
3151
3158
  console.log(total_results);
3152
3159
  console.log('Time Stamps');