@mentra/sdk 2.1.4 → 2.1.5
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/app/session/modules/audio.d.ts +2 -2
- package/dist/app/session/modules/audio.d.ts.map +1 -1
- package/dist/app/session/modules/audio.js +17 -21
- package/dist/app/session/modules/camera.d.ts +4 -4
- package/dist/app/session/modules/camera.d.ts.map +1 -1
- package/dist/app/session/modules/camera.js +22 -28
- package/dist/app/session/modules/location.d.ts +3 -3
- package/dist/app/session/modules/location.d.ts.map +1 -1
- package/dist/app/session/modules/location.js +5 -8
- package/package.json +1 -1
@@ -4,8 +4,8 @@
|
|
4
4
|
* Audio functionality for App Sessions.
|
5
5
|
* Handles audio playback on connected glasses.
|
6
6
|
*/
|
7
|
-
import { AudioPlayResponse } from
|
8
|
-
import { Logger } from
|
7
|
+
import { AudioPlayResponse } from '../../../types';
|
8
|
+
import { Logger } from 'pino';
|
9
9
|
/**
|
10
10
|
* Options for audio playback
|
11
11
|
*/
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"audio.d.ts","sourceRoot":"","sources":["../../../../src/app/session/modules/audio.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAEL,iBAAiB,EAGlB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAE9B;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,mFAAmF;IACnF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,cAAc,CAAC,EAAE;QACf,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,iBAAiB,CAAC,EAAE,OAAO,CAAC;QAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,gDAAgD;IAChD,OAAO,EAAE,OAAO,CAAC;IACjB,uCAAuC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,IAAI,CAAyB;IACrC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,OAAO,CAAC,CAAM;IACtB,OAAO,CAAC,MAAM,CAAS;IAEvB,uDAAuD;IACvD,OAAO,CAAC,oBAAoB,
|
1
|
+
{"version":3,"file":"audio.d.ts","sourceRoot":"","sources":["../../../../src/app/session/modules/audio.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAEL,iBAAiB,EAGlB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAE9B;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,mFAAmF;IACnF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,cAAc,CAAC,EAAE;QACf,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,iBAAiB,CAAC,EAAE,OAAO,CAAC;QAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,gDAAgD;IAChD,OAAO,EAAE,OAAO,CAAC;IACjB,uCAAuC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,IAAI,CAAyB;IACrC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,OAAO,CAAC,CAAM;IACtB,OAAO,CAAC,MAAM,CAAS;IAEvB,uDAAuD;IACvD,OAAO,CAAC,oBAAoB,CAGvB;IAEL;;;;;;;;OAQG;gBACS,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,EAAE,MAAM;IAYhH;;;;;;;;;;;;;OAaG;IACG,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;IA0DpE;;;;;;;;OAQG;IACH,SAAS,IAAI,IAAI;IAoBjB;;;;;;;;;;;;;;;;;;;;;OAqBG;IACG,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,eAAe,CAAC;IA4C/E;;;;;;;;OAQG;IACH,uBAAuB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI;IA4B1D;;;;OAIG;IACH,iBAAiB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO;IAO9C;;;OAGG;IACH,sBAAsB,IAAI,MAAM;IAIhC;;;OAGG;IACH,oBAAoB,IAAI,MAAM,EAAE;IAIhC;;;;OAIG;IACH,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAW9C;;;OAGG;IACH,sBAAsB,IAAI,MAAM;IAmBhC;;;;OAIG;IACH,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;IAK3C;;;;OAIG;IACH,iBAAiB,IAAI;QAAE,aAAa,EAAE,MAAM,CAAA;KAAE;CAI/C"}
|
@@ -71,7 +71,7 @@ class AudioManager {
|
|
71
71
|
try {
|
72
72
|
// Validate input
|
73
73
|
if (!options.audioUrl) {
|
74
|
-
reject(
|
74
|
+
reject(new Error('audioUrl must be provided'));
|
75
75
|
return;
|
76
76
|
}
|
77
77
|
// Generate unique request ID
|
@@ -87,7 +87,7 @@ class AudioManager {
|
|
87
87
|
timestamp: new Date(),
|
88
88
|
audioUrl: options.audioUrl,
|
89
89
|
volume: options.volume ?? 1.0,
|
90
|
-
stopOtherAudio: options.stopOtherAudio ?? true
|
90
|
+
stopOtherAudio: options.stopOtherAudio ?? true
|
91
91
|
};
|
92
92
|
// Send request to cloud
|
93
93
|
this.send(message);
|
@@ -97,9 +97,7 @@ class AudioManager {
|
|
97
97
|
// Use session's resource tracker for automatic cleanup
|
98
98
|
this.session.resources.setTimeout(() => {
|
99
99
|
if (this.pendingAudioRequests.has(requestId)) {
|
100
|
-
this.pendingAudioRequests
|
101
|
-
.get(requestId)
|
102
|
-
.reject("Audio play request timed out");
|
100
|
+
this.pendingAudioRequests.get(requestId).reject(new Error('Audio play request timed out'));
|
103
101
|
this.pendingAudioRequests.delete(requestId);
|
104
102
|
this.logger.warn({ requestId }, `🔊 Audio play request timed out`);
|
105
103
|
}
|
@@ -109,9 +107,7 @@ class AudioManager {
|
|
109
107
|
// Fallback to regular setTimeout if session not available
|
110
108
|
setTimeout(() => {
|
111
109
|
if (this.pendingAudioRequests.has(requestId)) {
|
112
|
-
this.pendingAudioRequests
|
113
|
-
.get(requestId)
|
114
|
-
.reject("Audio play request timed out");
|
110
|
+
this.pendingAudioRequests.get(requestId).reject(new Error('Audio play request timed out'));
|
115
111
|
this.pendingAudioRequests.delete(requestId);
|
116
112
|
this.logger.warn({ requestId }, `🔊 Audio play request timed out`);
|
117
113
|
}
|
@@ -120,7 +116,7 @@ class AudioManager {
|
|
120
116
|
}
|
121
117
|
catch (error) {
|
122
118
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
123
|
-
reject(`Failed to play audio: ${errorMessage}`);
|
119
|
+
reject(new Error(`Failed to play audio: ${errorMessage}`));
|
124
120
|
}
|
125
121
|
});
|
126
122
|
}
|
@@ -140,7 +136,7 @@ class AudioManager {
|
|
140
136
|
type: types_1.AppToCloudMessageType.AUDIO_STOP_REQUEST,
|
141
137
|
packageName: this.packageName,
|
142
138
|
sessionId: this.sessionId,
|
143
|
-
timestamp: new Date()
|
139
|
+
timestamp: new Date()
|
144
140
|
};
|
145
141
|
// Send request to cloud (one-way, no response expected)
|
146
142
|
this.send(message);
|
@@ -176,24 +172,24 @@ class AudioManager {
|
|
176
172
|
async speak(text, options = {}) {
|
177
173
|
// Validate input
|
178
174
|
if (!text) {
|
179
|
-
throw new Error(
|
175
|
+
throw new Error('text must be provided');
|
180
176
|
}
|
181
177
|
// Get the HTTPS server URL from the session
|
182
178
|
const baseUrl = this.session?.getHttpsServerUrl?.();
|
183
179
|
if (!baseUrl) {
|
184
|
-
throw new Error(
|
180
|
+
throw new Error('Cannot determine server URL for TTS endpoint');
|
185
181
|
}
|
186
182
|
// Build query parameters for the TTS endpoint
|
187
183
|
const queryParams = new URLSearchParams();
|
188
|
-
queryParams.append(
|
184
|
+
queryParams.append('text', text);
|
189
185
|
if (options.voice_id) {
|
190
|
-
queryParams.append(
|
186
|
+
queryParams.append('voice_id', options.voice_id);
|
191
187
|
}
|
192
188
|
if (options.model_id) {
|
193
|
-
queryParams.append(
|
189
|
+
queryParams.append('model_id', options.model_id);
|
194
190
|
}
|
195
191
|
if (options.voice_settings) {
|
196
|
-
queryParams.append(
|
192
|
+
queryParams.append('voice_settings', JSON.stringify(options.voice_settings));
|
197
193
|
}
|
198
194
|
// Construct the TTS URL
|
199
195
|
const ttsUrl = `${baseUrl}/api/tts?${queryParams.toString()}`;
|
@@ -201,7 +197,7 @@ class AudioManager {
|
|
201
197
|
// Use the existing playAudio method to play the TTS audio
|
202
198
|
return this.playAudio({
|
203
199
|
audioUrl: ttsUrl,
|
204
|
-
volume: options.volume
|
200
|
+
volume: options.volume
|
205
201
|
});
|
206
202
|
}
|
207
203
|
// =====================================
|
@@ -223,14 +219,14 @@ class AudioManager {
|
|
223
219
|
pendingRequest.resolve({
|
224
220
|
success: response.success,
|
225
221
|
error: response.error,
|
226
|
-
duration: response.duration
|
222
|
+
duration: response.duration
|
227
223
|
});
|
228
224
|
// Clean up
|
229
225
|
this.pendingAudioRequests.delete(response.requestId);
|
230
226
|
this.logger.info({
|
231
227
|
requestId: response.requestId,
|
232
228
|
success: response.success,
|
233
|
-
duration: response.duration
|
229
|
+
duration: response.duration
|
234
230
|
}, `🔊 Audio play response received`);
|
235
231
|
}
|
236
232
|
else {
|
@@ -273,7 +269,7 @@ class AudioManager {
|
|
273
269
|
cancelAudioRequest(requestId) {
|
274
270
|
const pendingRequest = this.pendingAudioRequests.get(requestId);
|
275
271
|
if (pendingRequest) {
|
276
|
-
pendingRequest.reject(
|
272
|
+
pendingRequest.reject(new Error('Audio request cancelled'));
|
277
273
|
this.pendingAudioRequests.delete(requestId);
|
278
274
|
this.logger.info({ requestId }, `🔊 Audio request cancelled`);
|
279
275
|
return true;
|
@@ -287,7 +283,7 @@ class AudioManager {
|
|
287
283
|
cancelAllAudioRequests() {
|
288
284
|
const count = this.pendingAudioRequests.size;
|
289
285
|
this.pendingAudioRequests.forEach((request, requestId) => {
|
290
|
-
request.reject(
|
286
|
+
request.reject(new Error('Audio request cancelled due to cleanup'));
|
291
287
|
this.logger.debug({ requestId }, `🔊 Audio request cancelled during cleanup`);
|
292
288
|
});
|
293
289
|
this.pendingAudioRequests.clear();
|
@@ -4,10 +4,10 @@
|
|
4
4
|
* Unified camera functionality for App Sessions.
|
5
5
|
* Handles both photo requests and RTMP streaming from connected glasses.
|
6
6
|
*/
|
7
|
-
import { PhotoData, RtmpStreamStatus, ManagedStreamStatus } from
|
8
|
-
import { VideoConfig, AudioConfig, StreamConfig, StreamStatusHandler } from
|
9
|
-
import { Logger } from
|
10
|
-
import { ManagedStreamOptions, ManagedStreamResult } from
|
7
|
+
import { PhotoData, RtmpStreamStatus, ManagedStreamStatus } from '../../../types';
|
8
|
+
import { VideoConfig, AudioConfig, StreamConfig, StreamStatusHandler } from '../../../types/rtmp-stream';
|
9
|
+
import { Logger } from 'pino';
|
10
|
+
import { ManagedStreamOptions, ManagedStreamResult } from './camera-managed-extension';
|
11
11
|
/**
|
12
12
|
* Options for photo requests
|
13
13
|
*/
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"camera.d.ts","sourceRoot":"","sources":["../../../../src/app/session/modules/camera.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAEL,SAAS,EAIT,gBAAgB,EAEhB,mBAAmB,EAEpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,WAAW,EACX,WAAW,EACX,YAAY,EACZ,mBAAmB,EACpB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAC9B,OAAO,
|
1
|
+
{"version":3,"file":"camera.d.ts","sourceRoot":"","sources":["../../../../src/app/session/modules/camera.ts"],"names":[],"mappings":"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"}
|
@@ -90,7 +90,7 @@ class CameraModule {
|
|
90
90
|
sessionId: this.sessionId,
|
91
91
|
requestId,
|
92
92
|
timestamp: new Date(),
|
93
|
-
saveToGallery: options?.saveToGallery || false
|
93
|
+
saveToGallery: options?.saveToGallery || false
|
94
94
|
};
|
95
95
|
// Send request to cloud
|
96
96
|
this.send(message);
|
@@ -101,9 +101,7 @@ class CameraModule {
|
|
101
101
|
// Use session's resource tracker for automatic cleanup
|
102
102
|
this.session.resources.setTimeout(() => {
|
103
103
|
if (this.pendingPhotoRequests.has(requestId)) {
|
104
|
-
this.pendingPhotoRequests
|
105
|
-
.get(requestId)
|
106
|
-
.reject("Photo request timed out");
|
104
|
+
this.pendingPhotoRequests.get(requestId).reject(new Error('Photo request timed out'));
|
107
105
|
this.pendingPhotoRequests.delete(requestId);
|
108
106
|
this.logger.warn({ requestId }, `📸 Photo request timed out`);
|
109
107
|
}
|
@@ -113,9 +111,7 @@ class CameraModule {
|
|
113
111
|
// Fallback to regular setTimeout if session not available
|
114
112
|
setTimeout(() => {
|
115
113
|
if (this.pendingPhotoRequests.has(requestId)) {
|
116
|
-
this.pendingPhotoRequests
|
117
|
-
.get(requestId)
|
118
|
-
.reject("Photo request timed out");
|
114
|
+
this.pendingPhotoRequests.get(requestId).reject(new Error('Photo request timed out'));
|
119
115
|
this.pendingPhotoRequests.delete(requestId);
|
120
116
|
this.logger.warn({ requestId }, `📸 Photo request timed out`);
|
121
117
|
}
|
@@ -124,7 +120,7 @@ class CameraModule {
|
|
124
120
|
}
|
125
121
|
catch (error) {
|
126
122
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
127
|
-
reject(`Failed to request photo: ${errorMessage}`);
|
123
|
+
reject(new Error(`Failed to request photo: ${errorMessage}`));
|
128
124
|
}
|
129
125
|
});
|
130
126
|
}
|
@@ -185,7 +181,7 @@ class CameraModule {
|
|
185
181
|
cancelPhotoRequest(requestId) {
|
186
182
|
const pendingRequest = this.pendingPhotoRequests.get(requestId);
|
187
183
|
if (pendingRequest) {
|
188
|
-
pendingRequest.reject(
|
184
|
+
pendingRequest.reject(new Error('Photo request cancelled'));
|
189
185
|
this.pendingPhotoRequests.delete(requestId);
|
190
186
|
this.logger.info({ requestId }, `📸 Photo request cancelled`);
|
191
187
|
return true;
|
@@ -200,7 +196,7 @@ class CameraModule {
|
|
200
196
|
cancelAllPhotoRequests() {
|
201
197
|
const count = this.pendingPhotoRequests.size;
|
202
198
|
for (const [requestId, { reject }] of this.pendingPhotoRequests) {
|
203
|
-
reject(
|
199
|
+
reject(new Error('Photo request cancelled - session cleanup'));
|
204
200
|
this.logger.info({ requestId }, `📸 Photo request cancelled during cleanup`);
|
205
201
|
}
|
206
202
|
this.pendingPhotoRequests.clear();
|
@@ -227,14 +223,14 @@ class CameraModule {
|
|
227
223
|
async startStream(options) {
|
228
224
|
this.logger.info({ rtmpUrl: options.rtmpUrl }, `📹 RTMP stream request starting`);
|
229
225
|
if (!options.rtmpUrl) {
|
230
|
-
throw new Error(
|
226
|
+
throw new Error('rtmpUrl is required');
|
231
227
|
}
|
232
228
|
if (this.isStreaming) {
|
233
229
|
this.logger.error({
|
234
230
|
currentStreamUrl: this.currentStreamUrl,
|
235
|
-
requestedUrl: options.rtmpUrl
|
231
|
+
requestedUrl: options.rtmpUrl
|
236
232
|
}, `📹 Already streaming error`);
|
237
|
-
throw new Error(
|
233
|
+
throw new Error('Already streaming. Stop the current stream before starting a new one.');
|
238
234
|
}
|
239
235
|
// Create stream request message
|
240
236
|
const message = {
|
@@ -245,7 +241,7 @@ class CameraModule {
|
|
245
241
|
video: options.video,
|
246
242
|
audio: options.audio,
|
247
243
|
stream: options.stream,
|
248
|
-
timestamp: new Date()
|
244
|
+
timestamp: new Date()
|
249
245
|
};
|
250
246
|
// Save stream URL for reference
|
251
247
|
this.currentStreamUrl = options.rtmpUrl;
|
@@ -259,7 +255,7 @@ class CameraModule {
|
|
259
255
|
catch (error) {
|
260
256
|
this.logger.error({ error, rtmpUrl: options.rtmpUrl }, `📹 Failed to send RTMP stream request`);
|
261
257
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
262
|
-
return Promise.reject(`Failed to request RTMP stream: ${errorMessage}`);
|
258
|
+
return Promise.reject(new Error(`Failed to request RTMP stream: ${errorMessage}`));
|
263
259
|
}
|
264
260
|
}
|
265
261
|
/**
|
@@ -275,7 +271,7 @@ class CameraModule {
|
|
275
271
|
async stopStream() {
|
276
272
|
this.logger.info({
|
277
273
|
isCurrentlyStreaming: this.isStreaming,
|
278
|
-
currentStreamUrl: this.currentStreamUrl
|
274
|
+
currentStreamUrl: this.currentStreamUrl
|
279
275
|
}, `📹 RTMP stream stop request`);
|
280
276
|
if (!this.isStreaming) {
|
281
277
|
this.logger.info(`📹 Not streaming - no-op`);
|
@@ -288,7 +284,7 @@ class CameraModule {
|
|
288
284
|
packageName: this.packageName,
|
289
285
|
sessionId: this.sessionId,
|
290
286
|
streamId: this.currentStreamState?.streamId, // Include streamId if available
|
291
|
-
timestamp: new Date()
|
287
|
+
timestamp: new Date()
|
292
288
|
};
|
293
289
|
// Send the request
|
294
290
|
try {
|
@@ -297,7 +293,7 @@ class CameraModule {
|
|
297
293
|
}
|
298
294
|
catch (error) {
|
299
295
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
300
|
-
return Promise.reject(`Failed to stop RTMP stream: ${errorMessage}`);
|
296
|
+
return Promise.reject(new Error(`Failed to stop RTMP stream: ${errorMessage}`));
|
301
297
|
}
|
302
298
|
}
|
303
299
|
/**
|
@@ -333,7 +329,7 @@ class CameraModule {
|
|
333
329
|
this.session.subscribe(streams_1.StreamType.RTMP_STREAM_STATUS);
|
334
330
|
}
|
335
331
|
else {
|
336
|
-
this.logger.error(
|
332
|
+
this.logger.error('Cannot subscribe to status updates: session reference not available');
|
337
333
|
}
|
338
334
|
}
|
339
335
|
/**
|
@@ -364,7 +360,7 @@ class CameraModule {
|
|
364
360
|
*/
|
365
361
|
onStreamStatus(handler) {
|
366
362
|
if (!this.session) {
|
367
|
-
this.logger.error(
|
363
|
+
this.logger.error('Cannot listen for status updates: session reference not available');
|
368
364
|
return () => { };
|
369
365
|
}
|
370
366
|
this.subscribeToStreamStatusUpdates();
|
@@ -380,7 +376,7 @@ class CameraModule {
|
|
380
376
|
this.logger.debug({
|
381
377
|
messageType: message?.type,
|
382
378
|
messageStatus: message?.status,
|
383
|
-
currentIsStreaming: this.isStreaming
|
379
|
+
currentIsStreaming: this.isStreaming
|
384
380
|
}, `📹 Stream state update`);
|
385
381
|
// Verify this is a valid stream response
|
386
382
|
if (!(0, types_1.isRtmpStreamStatus)(message)) {
|
@@ -395,21 +391,19 @@ class CameraModule {
|
|
395
391
|
errorDetails: message.errorDetails,
|
396
392
|
appId: message.appId,
|
397
393
|
stats: message.stats,
|
398
|
-
timestamp: message.timestamp || new Date()
|
394
|
+
timestamp: message.timestamp || new Date()
|
399
395
|
};
|
400
396
|
this.logger.info({
|
401
397
|
streamId: status.streamId,
|
402
398
|
oldStatus: this.currentStreamState?.status,
|
403
399
|
newStatus: status.status,
|
404
|
-
wasStreaming: this.isStreaming
|
400
|
+
wasStreaming: this.isStreaming
|
405
401
|
}, `📹 Stream status processed`);
|
406
402
|
// Update local state based on status
|
407
|
-
if (status.status ===
|
408
|
-
status.status === "error" ||
|
409
|
-
status.status === "timeout") {
|
403
|
+
if (status.status === 'stopped' || status.status === 'error' || status.status === 'timeout') {
|
410
404
|
this.logger.info({
|
411
405
|
status: status.status,
|
412
|
-
wasStreaming: this.isStreaming
|
406
|
+
wasStreaming: this.isStreaming
|
413
407
|
}, `📹 Stream stopped - updating local state`);
|
414
408
|
this.isStreaming = false;
|
415
409
|
this.currentStreamUrl = undefined;
|
@@ -506,7 +500,7 @@ class CameraModule {
|
|
506
500
|
// Stop streaming if active
|
507
501
|
if (this.isStreaming) {
|
508
502
|
this.stopStream().catch((error) => {
|
509
|
-
this.logger.error({ error },
|
503
|
+
this.logger.error({ error }, 'Error stopping stream during cleanup');
|
510
504
|
});
|
511
505
|
}
|
512
506
|
// Clean up managed extension
|
@@ -1,12 +1,12 @@
|
|
1
|
-
import { AppSession } from
|
2
|
-
import { LocationUpdate } from
|
1
|
+
import { AppSession } from '..';
|
2
|
+
import { LocationUpdate } from '../../../types';
|
3
3
|
export declare class LocationManager {
|
4
4
|
private session;
|
5
5
|
private send;
|
6
6
|
private lastLocationCleanupHandler;
|
7
7
|
constructor(session: AppSession, send: (message: any) => void);
|
8
8
|
subscribeToStream(options: {
|
9
|
-
accuracy:
|
9
|
+
accuracy: 'standard' | 'high' | 'realtime' | 'tenMeters' | 'hundredMeters' | 'kilometer' | 'threeKilometers' | 'reduced';
|
10
10
|
}, handler: (data: LocationUpdate) => void): () => void;
|
11
11
|
unsubscribeFromStream(): void;
|
12
12
|
getLatestLocation(options: {
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"location.d.ts","sourceRoot":"","sources":["../../../../src/app/session/modules/location.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,
|
1
|
+
{"version":3,"file":"location.d.ts","sourceRoot":"","sources":["../../../../src/app/session/modules/location.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,EAAqC,cAAc,EAAyB,MAAM,gBAAgB,CAAC;AAE1G,qBAAa,eAAe;IAGd,OAAO,CAAC,OAAO;IAAc,OAAO,CAAC,IAAI;IAFrD,OAAO,CAAC,0BAA0B,CAAwB;gBAEtC,OAAO,EAAE,UAAU,EAAU,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI;IAGtE,iBAAiB,CAAC,OAAO,EAAE;QAAE,QAAQ,EAAE,UAAU,GAAG,MAAM,GAAG,UAAU,GAAG,WAAW,GAAG,eAAe,GAAG,WAAW,GAAG,iBAAiB,GAAG,SAAS,CAAA;KAAE,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,GAAG,MAAM,IAAI;IAQ7M,qBAAqB,IAAI,IAAI;IAUvB,iBAAiB,CAAC,OAAO,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,CAAC;CA4BvF"}
|
@@ -10,10 +10,7 @@ class LocationManager {
|
|
10
10
|
}
|
11
11
|
// subscribes to the continuous location stream with a specified accuracy tier
|
12
12
|
subscribeToStream(options, handler) {
|
13
|
-
const subscription = {
|
14
|
-
stream: "location_stream",
|
15
|
-
rate: options.accuracy,
|
16
|
-
};
|
13
|
+
const subscription = { stream: 'location_stream', rate: options.accuracy };
|
17
14
|
this.session.subscribe(subscription);
|
18
15
|
this.lastLocationCleanupHandler = this.session.events.onLocation(handler);
|
19
16
|
return this.lastLocationCleanupHandler;
|
@@ -25,7 +22,7 @@ class LocationManager {
|
|
25
22
|
this.lastLocationCleanupHandler = () => { };
|
26
23
|
}
|
27
24
|
else {
|
28
|
-
this.session.unsubscribe(
|
25
|
+
this.session.unsubscribe('location_stream');
|
29
26
|
}
|
30
27
|
}
|
31
28
|
// performs a one-time, intelligent poll for a location fix
|
@@ -33,7 +30,7 @@ class LocationManager {
|
|
33
30
|
return new Promise((resolve, reject) => {
|
34
31
|
const requestId = `poll_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
35
32
|
// listens for a location update with a matching correlationId
|
36
|
-
const unsubscribe = this.session.events.on(
|
33
|
+
const unsubscribe = this.session.events.on('location_update', (data) => {
|
37
34
|
if (data.correlationId === requestId) {
|
38
35
|
unsubscribe(); // clean up the listener
|
39
36
|
resolve(data);
|
@@ -45,12 +42,12 @@ class LocationManager {
|
|
45
42
|
correlationId: requestId,
|
46
43
|
packageName: this.session.getPackageName(),
|
47
44
|
sessionId: this.session.getSessionId(),
|
48
|
-
accuracy: options.accuracy
|
45
|
+
accuracy: options.accuracy
|
49
46
|
});
|
50
47
|
// sets a timeout to prevent the promise from hanging indefinitely
|
51
48
|
setTimeout(() => {
|
52
49
|
unsubscribe();
|
53
|
-
reject(
|
50
|
+
reject(new Error('Location poll request timed out'));
|
54
51
|
}, 15000); // 15 second timeout
|
55
52
|
});
|
56
53
|
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@mentra/sdk",
|
3
|
-
"version": "2.1.
|
3
|
+
"version": "2.1.5",
|
4
4
|
"description": "Build apps for MentraOS smartglasses. This SDK provides everything you need to create real-time smartglasses applications.",
|
5
5
|
"source": "src/index.ts",
|
6
6
|
"main": "dist/index.js",
|