@mentra/sdk 2.1.26 โ 2.1.28
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/api-client.d.ts.map +1 -1
- package/dist/app/session/dashboard.d.ts +5 -8
- package/dist/app/session/dashboard.d.ts.map +1 -1
- package/dist/app/session/events.d.ts +5 -2
- package/dist/app/session/events.d.ts.map +1 -1
- package/dist/app/session/index.d.ts +62 -3
- package/dist/app/session/index.d.ts.map +1 -1
- package/dist/app/session/modules/audio.d.ts +33 -4
- package/dist/app/session/modules/audio.d.ts.map +1 -1
- package/dist/app/session/modules/camera-managed-extension.d.ts +2 -3
- package/dist/app/session/modules/camera-managed-extension.d.ts.map +1 -1
- package/dist/app/session/modules/camera.d.ts +5 -5
- package/dist/app/session/modules/camera.d.ts.map +1 -1
- package/dist/app/session/modules/led.d.ts +141 -0
- package/dist/app/session/modules/led.d.ts.map +1 -0
- package/dist/app/session/modules/location.d.ts +1 -2
- package/dist/app/session/modules/location.d.ts.map +1 -1
- package/dist/app/session/modules/simple-storage.d.ts.map +1 -1
- package/dist/constants/log-messages/color.d.ts +5 -0
- package/dist/constants/log-messages/color.d.ts.map +1 -0
- package/dist/constants/log-messages/logos.d.ts +4 -0
- package/dist/constants/log-messages/logos.d.ts.map +1 -0
- package/dist/constants/{messages.d.ts โ log-messages/updates.d.ts} +2 -3
- package/dist/constants/log-messages/updates.d.ts.map +1 -0
- package/dist/constants/log-messages/warning.d.ts +8 -0
- package/dist/constants/log-messages/warning.d.ts.map +1 -0
- package/dist/index.d.ts +7 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5347 -112
- package/dist/index.js.map +45 -0
- package/dist/logging/logger.d.ts +2 -1
- package/dist/logging/logger.d.ts.map +1 -1
- package/dist/types/capabilities.d.ts +3 -0
- package/dist/types/capabilities.d.ts.map +1 -1
- package/dist/types/index.d.ts +4 -14
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/message-types.d.ts +12 -3
- package/dist/types/message-types.d.ts.map +1 -1
- package/dist/types/messages/app-to-cloud.d.ts +48 -2
- package/dist/types/messages/app-to-cloud.d.ts.map +1 -1
- package/dist/types/messages/cloud-to-app.d.ts +25 -6
- package/dist/types/messages/cloud-to-app.d.ts.map +1 -1
- package/dist/types/messages/cloud-to-glasses.d.ts +43 -1
- package/dist/types/messages/cloud-to-glasses.d.ts.map +1 -1
- package/dist/types/messages/glasses-to-cloud.d.ts +32 -1
- package/dist/types/messages/glasses-to-cloud.d.ts.map +1 -1
- package/dist/types/rtmp-stream.d.ts +1 -1
- package/dist/types/rtmp-stream.d.ts.map +1 -1
- package/dist/types/streams.d.ts +28 -1
- package/dist/types/streams.d.ts.map +1 -1
- package/dist/utils/permissions-utils.d.ts +8 -0
- package/dist/utils/permissions-utils.d.ts.map +1 -0
- package/package.json +12 -3
- package/dist/app/index.js +0 -24
- package/dist/app/server/index.js +0 -658
- package/dist/app/session/api-client.js +0 -101
- package/dist/app/session/dashboard.js +0 -149
- package/dist/app/session/events.js +0 -305
- package/dist/app/session/index.js +0 -1571
- package/dist/app/session/layouts.js +0 -372
- package/dist/app/session/modules/audio.js +0 -321
- package/dist/app/session/modules/camera-managed-extension.js +0 -310
- package/dist/app/session/modules/camera.js +0 -603
- package/dist/app/session/modules/index.js +0 -19
- package/dist/app/session/modules/location.js +0 -58
- package/dist/app/session/modules/simple-storage.js +0 -232
- package/dist/app/session/settings.js +0 -358
- package/dist/app/token/index.js +0 -22
- package/dist/app/token/utils.js +0 -144
- package/dist/app/webview/index.js +0 -382
- package/dist/constants/index.js +0 -16
- package/dist/constants/messages.d.ts.map +0 -1
- package/dist/constants/messages.js +0 -57
- package/dist/examples/managed-rtmp-streaming-example.js +0 -158
- package/dist/examples/managed-rtmp-streaming-with-restream-example.js +0 -124
- package/dist/examples/rtmp-streaming-example.js +0 -102
- package/dist/logging/logger.js +0 -79
- package/dist/types/capabilities.js +0 -9
- package/dist/types/dashboard/index.js +0 -12
- package/dist/types/enums.js +0 -75
- package/dist/types/index.js +0 -101
- package/dist/types/layouts.js +0 -3
- package/dist/types/message-types.js +0 -207
- package/dist/types/messages/app-to-cloud.js +0 -95
- package/dist/types/messages/base.js +0 -3
- package/dist/types/messages/cloud-to-app.js +0 -78
- package/dist/types/messages/cloud-to-glasses.js +0 -68
- package/dist/types/messages/glasses-to-cloud.js +0 -139
- package/dist/types/models.js +0 -101
- package/dist/types/photo-data.js +0 -2
- package/dist/types/rtmp-stream.js +0 -3
- package/dist/types/streams.js +0 -306
- package/dist/types/token.js +0 -7
- package/dist/types/webhooks.js +0 -28
- package/dist/utils/animation-utils.js +0 -340
- package/dist/utils/bitmap-utils.js +0 -475
- package/dist/utils/resource-tracker.js +0 -153
|
@@ -1,603 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* ๐ท Camera Module
|
|
4
|
-
*
|
|
5
|
-
* Unified camera functionality for App Sessions.
|
|
6
|
-
* Handles both photo requests and RTMP streaming from connected glasses.
|
|
7
|
-
*/
|
|
8
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.CameraModule = void 0;
|
|
10
|
-
const types_1 = require("../../../types");
|
|
11
|
-
const streams_1 = require("../../../types/streams");
|
|
12
|
-
const camera_managed_extension_1 = require("./camera-managed-extension");
|
|
13
|
-
/**
|
|
14
|
-
* ๐ท Camera Module Implementation
|
|
15
|
-
*
|
|
16
|
-
* Unified camera management for App Sessions.
|
|
17
|
-
* Provides methods for:
|
|
18
|
-
* - ๐ธ Requesting photos from glasses
|
|
19
|
-
* - ๐น Starting/stopping RTMP streams
|
|
20
|
-
* - ๐ Monitoring photo and stream status
|
|
21
|
-
* - ๐งน Cleanup and cancellation
|
|
22
|
-
*
|
|
23
|
-
* @example
|
|
24
|
-
* ```typescript
|
|
25
|
-
* // Request a photo
|
|
26
|
-
* const photoData = await session.camera.requestPhoto({ saveToGallery: true });
|
|
27
|
-
*
|
|
28
|
-
* // Start streaming
|
|
29
|
-
* await session.camera.startStream({ rtmpUrl: 'rtmp://example.com/live/key' });
|
|
30
|
-
*
|
|
31
|
-
* // Monitor stream status
|
|
32
|
-
* session.camera.onStreamStatus((status) => {
|
|
33
|
-
* console.log('Stream status:', status.status);
|
|
34
|
-
* });
|
|
35
|
-
*
|
|
36
|
-
* // Stop streaming
|
|
37
|
-
* await session.camera.stopStream();
|
|
38
|
-
* ```
|
|
39
|
-
*/
|
|
40
|
-
class CameraModule {
|
|
41
|
-
/**
|
|
42
|
-
* Create a new CameraModule
|
|
43
|
-
*
|
|
44
|
-
* @param packageName - The App package name
|
|
45
|
-
* @param sessionId - The current session ID
|
|
46
|
-
* @param send - Function to send messages to the cloud
|
|
47
|
-
* @param session - Reference to the parent AppSession (optional)
|
|
48
|
-
* @param logger - Logger instance for debugging
|
|
49
|
-
*/
|
|
50
|
-
constructor(packageName, sessionId, send, session, logger) {
|
|
51
|
-
// Photo functionality
|
|
52
|
-
/** Map to store pending photo request promises */
|
|
53
|
-
this.pendingPhotoRequests = new Map();
|
|
54
|
-
// Streaming functionality
|
|
55
|
-
this.isStreaming = false;
|
|
56
|
-
this.packageName = packageName;
|
|
57
|
-
this.sessionId = sessionId;
|
|
58
|
-
this.send = send;
|
|
59
|
-
this.session = session;
|
|
60
|
-
this.logger = logger || console;
|
|
61
|
-
// Initialize managed extension
|
|
62
|
-
this.managedExtension = new camera_managed_extension_1.CameraManagedExtension(packageName, sessionId, send, this.logger, session);
|
|
63
|
-
}
|
|
64
|
-
// =====================================
|
|
65
|
-
// ๐ธ Photo Functionality
|
|
66
|
-
// =====================================
|
|
67
|
-
/**
|
|
68
|
-
* ๐ธ Request a photo from the connected glasses
|
|
69
|
-
*
|
|
70
|
-
* @param options - Optional configuration for the photo request
|
|
71
|
-
* @returns Promise that resolves with the actual photo data
|
|
72
|
-
*
|
|
73
|
-
* @example
|
|
74
|
-
* ```typescript
|
|
75
|
-
* // Request a photo
|
|
76
|
-
* const photo = await session.camera.requestPhoto();
|
|
77
|
-
*
|
|
78
|
-
* // Request a photo with custom webhook URL and authentication
|
|
79
|
-
* const photo = await session.camera.requestPhoto({
|
|
80
|
-
* customWebhookUrl: 'https://my-custom-endpoint.com/photo-upload',
|
|
81
|
-
* authToken: 'your-auth-token-here'
|
|
82
|
-
* });
|
|
83
|
-
* ```
|
|
84
|
-
*/
|
|
85
|
-
async requestPhoto(options) {
|
|
86
|
-
return new Promise((resolve, reject) => {
|
|
87
|
-
try {
|
|
88
|
-
console.log("DEBUG: requestPhoto options:", options);
|
|
89
|
-
// Generate unique request ID
|
|
90
|
-
const requestId = `photo_req_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
91
|
-
// Store promise resolvers for when we get the response
|
|
92
|
-
this.pendingPhotoRequests.set(requestId, { resolve, reject });
|
|
93
|
-
// Create photo request message
|
|
94
|
-
const message = {
|
|
95
|
-
type: types_1.AppToCloudMessageType.PHOTO_REQUEST,
|
|
96
|
-
packageName: this.packageName,
|
|
97
|
-
sessionId: this.sessionId,
|
|
98
|
-
requestId,
|
|
99
|
-
timestamp: new Date(),
|
|
100
|
-
saveToGallery: options?.saveToGallery || false,
|
|
101
|
-
customWebhookUrl: options?.customWebhookUrl,
|
|
102
|
-
authToken: options?.authToken,
|
|
103
|
-
size: options?.size || "medium",
|
|
104
|
-
};
|
|
105
|
-
// Send request to cloud
|
|
106
|
-
this.send(message);
|
|
107
|
-
this.logger.info({
|
|
108
|
-
requestId,
|
|
109
|
-
saveToGallery: options?.saveToGallery,
|
|
110
|
-
hasCustomWebhook: !!options?.customWebhookUrl,
|
|
111
|
-
hasAuthToken: !!options?.authToken,
|
|
112
|
-
}, `๐ธ Photo request sent`);
|
|
113
|
-
// If using custom webhook URL, resolve immediately since photo will be uploaded directly to custom endpoint
|
|
114
|
-
if (options?.customWebhookUrl) {
|
|
115
|
-
this.logger.info({ requestId, customWebhookUrl: options.customWebhookUrl }, `๐ธ Using custom webhook URL - resolving promise immediately since photo will be uploaded directly to custom endpoint`);
|
|
116
|
-
// Create a mock PhotoData object for custom webhook URLs
|
|
117
|
-
const mockPhotoData = {
|
|
118
|
-
buffer: Buffer.from([]), // Empty buffer since we don't have the actual photo
|
|
119
|
-
mimeType: "image/jpeg",
|
|
120
|
-
filename: "photo.jpg",
|
|
121
|
-
requestId,
|
|
122
|
-
size: 0,
|
|
123
|
-
timestamp: new Date(),
|
|
124
|
-
};
|
|
125
|
-
// Resolve immediately and clean up
|
|
126
|
-
this.pendingPhotoRequests.delete(requestId);
|
|
127
|
-
resolve(mockPhotoData);
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
// Set timeout to avoid hanging promises (only for non-custom webhook requests)
|
|
131
|
-
const timeoutMs = 30000; // 30 seconds
|
|
132
|
-
if (this.session && this.session.resources) {
|
|
133
|
-
// Use session's resource tracker for automatic cleanup
|
|
134
|
-
this.session.resources.setTimeout(() => {
|
|
135
|
-
if (this.pendingPhotoRequests.has(requestId)) {
|
|
136
|
-
this.pendingPhotoRequests
|
|
137
|
-
.get(requestId)
|
|
138
|
-
.reject("Photo request timed out");
|
|
139
|
-
this.pendingPhotoRequests.delete(requestId);
|
|
140
|
-
this.logger.warn({ requestId }, `๐ธ Photo request timed out`);
|
|
141
|
-
}
|
|
142
|
-
}, timeoutMs);
|
|
143
|
-
}
|
|
144
|
-
else {
|
|
145
|
-
// Fallback to regular setTimeout if session not available
|
|
146
|
-
setTimeout(() => {
|
|
147
|
-
if (this.pendingPhotoRequests.has(requestId)) {
|
|
148
|
-
this.pendingPhotoRequests
|
|
149
|
-
.get(requestId)
|
|
150
|
-
.reject("Photo request timed out");
|
|
151
|
-
this.pendingPhotoRequests.delete(requestId);
|
|
152
|
-
this.logger.warn({ requestId }, `๐ธ Photo request timed out`);
|
|
153
|
-
}
|
|
154
|
-
}, timeoutMs);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
catch (error) {
|
|
158
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
159
|
-
reject(`Failed to request photo: ${errorMessage}`);
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* ๐ฅ Handle photo received from /photo-upload endpoint
|
|
165
|
-
*
|
|
166
|
-
* This method is called internally when a photo response is received.
|
|
167
|
-
* It resolves the corresponding pending promise with the photo data.
|
|
168
|
-
*
|
|
169
|
-
* @param photoData - The photo data received
|
|
170
|
-
* @internal This method is used internally by AppSession
|
|
171
|
-
*/
|
|
172
|
-
handlePhotoReceived(photoData) {
|
|
173
|
-
const { requestId } = photoData;
|
|
174
|
-
const pendingRequest = this.pendingPhotoRequests.get(requestId);
|
|
175
|
-
if (pendingRequest) {
|
|
176
|
-
this.logger.info({ requestId }, `๐ธ Photo received for request ${requestId}`);
|
|
177
|
-
// Resolve the promise with the photo data
|
|
178
|
-
pendingRequest.resolve(photoData);
|
|
179
|
-
// Clean up
|
|
180
|
-
this.pendingPhotoRequests.delete(requestId);
|
|
181
|
-
}
|
|
182
|
-
else {
|
|
183
|
-
this.logger.warn({ requestId }, `๐ธ Received photo for unknown request ID: ${requestId}`);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
/**
|
|
187
|
-
* โ Handle photo error from /photo-upload endpoint
|
|
188
|
-
*
|
|
189
|
-
* This method is called internally when a photo error response is received.
|
|
190
|
-
* It rejects the corresponding pending promise with the error information.
|
|
191
|
-
*
|
|
192
|
-
* @param errorResponse - The error response received
|
|
193
|
-
* @internal This method is used internally by AppSession
|
|
194
|
-
*/
|
|
195
|
-
handlePhotoError(errorResponse) {
|
|
196
|
-
const { requestId, error } = errorResponse;
|
|
197
|
-
const pendingRequest = this.pendingPhotoRequests.get(requestId);
|
|
198
|
-
if (pendingRequest) {
|
|
199
|
-
this.logger.error({ requestId, errorCode: error.code, errorMessage: error.message }, `๐ธ Photo capture failed: ${error.code} - ${error.message}`);
|
|
200
|
-
// Reject the promise with the error information
|
|
201
|
-
pendingRequest.reject(`${error.code}: ${error.message}`);
|
|
202
|
-
// Clean up
|
|
203
|
-
this.pendingPhotoRequests.delete(requestId);
|
|
204
|
-
}
|
|
205
|
-
else {
|
|
206
|
-
this.logger.warn({ requestId, errorCode: error.code, errorMessage: error.message }, `๐ธ Received photo error for unknown request ID: ${requestId}`);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
/**
|
|
210
|
-
* ๐ Check if there's a pending photo request for the given request ID
|
|
211
|
-
*
|
|
212
|
-
* @param requestId - The request ID to check
|
|
213
|
-
* @returns true if there's a pending request
|
|
214
|
-
*/
|
|
215
|
-
hasPhotoPendingRequest(requestId) {
|
|
216
|
-
return this.pendingPhotoRequests.has(requestId);
|
|
217
|
-
}
|
|
218
|
-
/**
|
|
219
|
-
* ๐ Get the number of pending photo requests
|
|
220
|
-
*
|
|
221
|
-
* @returns Number of pending photo requests
|
|
222
|
-
*/
|
|
223
|
-
getPhotoPendingRequestCount() {
|
|
224
|
-
return this.pendingPhotoRequests.size;
|
|
225
|
-
}
|
|
226
|
-
/**
|
|
227
|
-
* ๐ Get all pending photo request IDs
|
|
228
|
-
*
|
|
229
|
-
* @returns Array of pending request IDs
|
|
230
|
-
*/
|
|
231
|
-
getPhotoPendingRequestIds() {
|
|
232
|
-
return Array.from(this.pendingPhotoRequests.keys());
|
|
233
|
-
}
|
|
234
|
-
/**
|
|
235
|
-
* โ Cancel a pending photo request
|
|
236
|
-
*
|
|
237
|
-
* @param requestId - The request ID to cancel
|
|
238
|
-
* @returns true if the request was cancelled, false if it wasn't found
|
|
239
|
-
*/
|
|
240
|
-
cancelPhotoRequest(requestId) {
|
|
241
|
-
const pendingRequest = this.pendingPhotoRequests.get(requestId);
|
|
242
|
-
if (pendingRequest) {
|
|
243
|
-
pendingRequest.reject("Photo request cancelled");
|
|
244
|
-
this.pendingPhotoRequests.delete(requestId);
|
|
245
|
-
this.logger.info({ requestId }, `๐ธ Photo request cancelled`);
|
|
246
|
-
return true;
|
|
247
|
-
}
|
|
248
|
-
return false;
|
|
249
|
-
}
|
|
250
|
-
/**
|
|
251
|
-
* ๐งน Cancel all pending photo requests
|
|
252
|
-
*
|
|
253
|
-
* @returns Number of requests that were cancelled
|
|
254
|
-
*/
|
|
255
|
-
cancelAllPhotoRequests() {
|
|
256
|
-
const count = this.pendingPhotoRequests.size;
|
|
257
|
-
for (const [requestId, { reject }] of this.pendingPhotoRequests) {
|
|
258
|
-
reject("Photo request cancelled - session cleanup");
|
|
259
|
-
this.logger.info({ requestId }, `๐ธ Photo request cancelled during cleanup`);
|
|
260
|
-
}
|
|
261
|
-
this.pendingPhotoRequests.clear();
|
|
262
|
-
return count;
|
|
263
|
-
}
|
|
264
|
-
// =====================================
|
|
265
|
-
// ๐น Streaming Functionality
|
|
266
|
-
// =====================================
|
|
267
|
-
/**
|
|
268
|
-
* ๐น Start an RTMP stream to the specified URL
|
|
269
|
-
*
|
|
270
|
-
* @param options - Configuration options for the stream
|
|
271
|
-
* @returns Promise that resolves when the stream request is sent (not when streaming begins)
|
|
272
|
-
*
|
|
273
|
-
* @example
|
|
274
|
-
* ```typescript
|
|
275
|
-
* await session.camera.startStream({
|
|
276
|
-
* rtmpUrl: 'rtmp://live.example.com/stream/key',
|
|
277
|
-
* video: { resolution: '1920x1080', bitrate: 5000 },
|
|
278
|
-
* audio: { bitrate: 128 }
|
|
279
|
-
* });
|
|
280
|
-
* ```
|
|
281
|
-
*/
|
|
282
|
-
async startStream(options) {
|
|
283
|
-
this.logger.info({ rtmpUrl: options.rtmpUrl }, `๐น RTMP stream request starting`);
|
|
284
|
-
if (!options.rtmpUrl) {
|
|
285
|
-
throw new Error("rtmpUrl is required");
|
|
286
|
-
}
|
|
287
|
-
if (this.isStreaming) {
|
|
288
|
-
this.logger.error({
|
|
289
|
-
currentStreamUrl: this.currentStreamUrl,
|
|
290
|
-
requestedUrl: options.rtmpUrl,
|
|
291
|
-
}, `๐น Already streaming error`);
|
|
292
|
-
throw new Error("Already streaming. Stop the current stream before starting a new one.");
|
|
293
|
-
}
|
|
294
|
-
// Create stream request message
|
|
295
|
-
const message = {
|
|
296
|
-
type: types_1.AppToCloudMessageType.RTMP_STREAM_REQUEST,
|
|
297
|
-
packageName: this.packageName,
|
|
298
|
-
sessionId: this.sessionId,
|
|
299
|
-
rtmpUrl: options.rtmpUrl,
|
|
300
|
-
video: options.video,
|
|
301
|
-
audio: options.audio,
|
|
302
|
-
stream: options.stream,
|
|
303
|
-
timestamp: new Date(),
|
|
304
|
-
};
|
|
305
|
-
// Save stream URL for reference
|
|
306
|
-
this.currentStreamUrl = options.rtmpUrl;
|
|
307
|
-
// Send the request
|
|
308
|
-
try {
|
|
309
|
-
this.send(message);
|
|
310
|
-
this.isStreaming = true;
|
|
311
|
-
this.logger.info({ rtmpUrl: options.rtmpUrl }, `๐น RTMP stream request sent successfully`);
|
|
312
|
-
return Promise.resolve();
|
|
313
|
-
}
|
|
314
|
-
catch (error) {
|
|
315
|
-
this.logger.error({ error, rtmpUrl: options.rtmpUrl }, `๐น Failed to send RTMP stream request`);
|
|
316
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
317
|
-
return Promise.reject(`Failed to request RTMP stream: ${errorMessage}`);
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
/**
|
|
321
|
-
* ๐ Stop the current RTMP stream
|
|
322
|
-
*
|
|
323
|
-
* @returns Promise that resolves when the stop request is sent
|
|
324
|
-
*
|
|
325
|
-
* @example
|
|
326
|
-
* ```typescript
|
|
327
|
-
* await session.camera.stopStream();
|
|
328
|
-
* ```
|
|
329
|
-
*/
|
|
330
|
-
async stopStream() {
|
|
331
|
-
this.logger.info({
|
|
332
|
-
isCurrentlyStreaming: this.isStreaming,
|
|
333
|
-
currentStreamUrl: this.currentStreamUrl,
|
|
334
|
-
}, `๐น RTMP stream stop request`);
|
|
335
|
-
if (!this.isStreaming) {
|
|
336
|
-
this.logger.info(`๐น Not streaming - no-op`);
|
|
337
|
-
// Not an error - just a no-op if not streaming
|
|
338
|
-
return Promise.resolve();
|
|
339
|
-
}
|
|
340
|
-
// Create stop request message
|
|
341
|
-
const message = {
|
|
342
|
-
type: types_1.AppToCloudMessageType.RTMP_STREAM_STOP,
|
|
343
|
-
packageName: this.packageName,
|
|
344
|
-
sessionId: this.sessionId,
|
|
345
|
-
streamId: this.currentStreamState?.streamId, // Include streamId if available
|
|
346
|
-
timestamp: new Date(),
|
|
347
|
-
};
|
|
348
|
-
// Send the request
|
|
349
|
-
try {
|
|
350
|
-
this.send(message);
|
|
351
|
-
return Promise.resolve();
|
|
352
|
-
}
|
|
353
|
-
catch (error) {
|
|
354
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
355
|
-
return Promise.reject(`Failed to stop RTMP stream: ${errorMessage}`);
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
/**
|
|
359
|
-
* ๐ Check if currently streaming
|
|
360
|
-
*
|
|
361
|
-
* @returns True if a stream is active or initializing
|
|
362
|
-
*/
|
|
363
|
-
isCurrentlyStreaming() {
|
|
364
|
-
return this.isStreaming;
|
|
365
|
-
}
|
|
366
|
-
/**
|
|
367
|
-
* ๐ Get the URL of the current stream (if any)
|
|
368
|
-
*
|
|
369
|
-
* @returns The RTMP URL of the current stream, or undefined if not streaming
|
|
370
|
-
*/
|
|
371
|
-
getCurrentStreamUrl() {
|
|
372
|
-
return this.currentStreamUrl;
|
|
373
|
-
}
|
|
374
|
-
/**
|
|
375
|
-
* ๐ Get the current stream status
|
|
376
|
-
*
|
|
377
|
-
* @returns The current stream status, or undefined if not available
|
|
378
|
-
*/
|
|
379
|
-
getStreamStatus() {
|
|
380
|
-
return this.currentStreamState;
|
|
381
|
-
}
|
|
382
|
-
/**
|
|
383
|
-
* ๐บ Subscribe to RTMP stream status updates
|
|
384
|
-
* This uses the standard stream subscription mechanism
|
|
385
|
-
*/
|
|
386
|
-
subscribeToStreamStatusUpdates() {
|
|
387
|
-
if (this.session) {
|
|
388
|
-
this.session.subscribe(streams_1.StreamType.RTMP_STREAM_STATUS);
|
|
389
|
-
}
|
|
390
|
-
else {
|
|
391
|
-
this.logger.error("Cannot subscribe to status updates: session reference not available");
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
/**
|
|
395
|
-
* ๐บ Unsubscribe from RTMP stream status updates
|
|
396
|
-
*/
|
|
397
|
-
unsubscribeFromStreamStatusUpdates() {
|
|
398
|
-
if (this.session) {
|
|
399
|
-
this.session.unsubscribe(streams_1.StreamType.RTMP_STREAM_STATUS);
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
/**
|
|
403
|
-
* ๐ Listen for stream status updates using the standard event system
|
|
404
|
-
* @param handler - Function to call when stream status changes
|
|
405
|
-
* @returns Cleanup function to remove the handler
|
|
406
|
-
*
|
|
407
|
-
* @example
|
|
408
|
-
* ```typescript
|
|
409
|
-
* const cleanup = session.camera.onStreamStatus((status) => {
|
|
410
|
-
* console.log('Stream status:', status.status);
|
|
411
|
-
* if (status.status === 'error') {
|
|
412
|
-
* console.error('Stream error:', status.errorDetails);
|
|
413
|
-
* }
|
|
414
|
-
* });
|
|
415
|
-
*
|
|
416
|
-
* // Later, cleanup the listener
|
|
417
|
-
* cleanup();
|
|
418
|
-
* ```
|
|
419
|
-
*/
|
|
420
|
-
onStreamStatus(handler) {
|
|
421
|
-
if (!this.session) {
|
|
422
|
-
this.logger.error("Cannot listen for status updates: session reference not available");
|
|
423
|
-
return () => { };
|
|
424
|
-
}
|
|
425
|
-
this.subscribeToStreamStatusUpdates();
|
|
426
|
-
return this.session.on(streams_1.StreamType.RTMP_STREAM_STATUS, handler);
|
|
427
|
-
}
|
|
428
|
-
/**
|
|
429
|
-
* ๐ Update internal stream state based on a status message
|
|
430
|
-
* For internal use by AppSession
|
|
431
|
-
* @param message - The status message from the cloud
|
|
432
|
-
* @internal This method is used internally by AppSession
|
|
433
|
-
*/
|
|
434
|
-
updateStreamState(message) {
|
|
435
|
-
this.logger.debug({
|
|
436
|
-
messageType: message?.type,
|
|
437
|
-
messageStatus: message?.status,
|
|
438
|
-
currentIsStreaming: this.isStreaming,
|
|
439
|
-
}, `๐น Stream state update`);
|
|
440
|
-
// Verify this is a valid stream response
|
|
441
|
-
if (!(0, types_1.isRtmpStreamStatus)(message)) {
|
|
442
|
-
this.logger.warn({ message }, `๐น Received invalid stream status message`);
|
|
443
|
-
return;
|
|
444
|
-
}
|
|
445
|
-
// Convert to StreamStatus format
|
|
446
|
-
const status = {
|
|
447
|
-
type: message.type,
|
|
448
|
-
streamId: message.streamId,
|
|
449
|
-
status: message.status,
|
|
450
|
-
errorDetails: message.errorDetails,
|
|
451
|
-
appId: message.appId,
|
|
452
|
-
stats: message.stats,
|
|
453
|
-
timestamp: message.timestamp || new Date(),
|
|
454
|
-
};
|
|
455
|
-
this.logger.info({
|
|
456
|
-
streamId: status.streamId,
|
|
457
|
-
oldStatus: this.currentStreamState?.status,
|
|
458
|
-
newStatus: status.status,
|
|
459
|
-
wasStreaming: this.isStreaming,
|
|
460
|
-
}, `๐น Stream status processed`);
|
|
461
|
-
// Update local state based on status
|
|
462
|
-
if (status.status === "stopped" ||
|
|
463
|
-
status.status === "error" ||
|
|
464
|
-
status.status === "timeout") {
|
|
465
|
-
this.logger.info({
|
|
466
|
-
status: status.status,
|
|
467
|
-
wasStreaming: this.isStreaming,
|
|
468
|
-
}, `๐น Stream stopped - updating local state`);
|
|
469
|
-
this.isStreaming = false;
|
|
470
|
-
this.currentStreamUrl = undefined;
|
|
471
|
-
}
|
|
472
|
-
// Save the latest status
|
|
473
|
-
this.currentStreamState = status;
|
|
474
|
-
}
|
|
475
|
-
// =====================================
|
|
476
|
-
// ๐น Managed Streaming Functionality
|
|
477
|
-
// =====================================
|
|
478
|
-
/**
|
|
479
|
-
* ๐น Start a managed stream
|
|
480
|
-
*
|
|
481
|
-
* The cloud handles the RTMP endpoint and returns HLS/DASH URLs for viewing.
|
|
482
|
-
* Multiple apps can consume the same managed stream simultaneously.
|
|
483
|
-
*
|
|
484
|
-
* @param options - Configuration options for the managed stream
|
|
485
|
-
* @returns Promise that resolves with viewing URLs when the stream is ready
|
|
486
|
-
*
|
|
487
|
-
* @example
|
|
488
|
-
* ```typescript
|
|
489
|
-
* const urls = await session.camera.startManagedStream({
|
|
490
|
-
* quality: '720p',
|
|
491
|
-
* enableWebRTC: true
|
|
492
|
-
* });
|
|
493
|
-
* console.log('HLS URL:', urls.hlsUrl);
|
|
494
|
-
* ```
|
|
495
|
-
*/
|
|
496
|
-
async startManagedStream(options) {
|
|
497
|
-
return this.managedExtension.startManagedStream(options);
|
|
498
|
-
}
|
|
499
|
-
/**
|
|
500
|
-
* ๐ Stop the current managed stream
|
|
501
|
-
*
|
|
502
|
-
* This will stop streaming for this app only. If other apps are consuming
|
|
503
|
-
* the same managed stream, it will continue for them.
|
|
504
|
-
*
|
|
505
|
-
* @returns Promise that resolves when the stop request is sent
|
|
506
|
-
*/
|
|
507
|
-
async stopManagedStream() {
|
|
508
|
-
return this.managedExtension.stopManagedStream();
|
|
509
|
-
}
|
|
510
|
-
/**
|
|
511
|
-
* ๐ Register a handler for managed stream status updates
|
|
512
|
-
*
|
|
513
|
-
* @param handler - Function to call when stream status changes
|
|
514
|
-
* @returns Cleanup function to unregister the handler
|
|
515
|
-
*/
|
|
516
|
-
onManagedStreamStatus(handler) {
|
|
517
|
-
return this.managedExtension.onManagedStreamStatus(handler);
|
|
518
|
-
}
|
|
519
|
-
/**
|
|
520
|
-
* ๐ Check if currently managed streaming
|
|
521
|
-
*
|
|
522
|
-
* @returns true if a managed stream is active
|
|
523
|
-
*/
|
|
524
|
-
isManagedStreamActive() {
|
|
525
|
-
return this.managedExtension.isManagedStreamActive();
|
|
526
|
-
}
|
|
527
|
-
/**
|
|
528
|
-
* ๐ Get current managed stream URLs
|
|
529
|
-
*
|
|
530
|
-
* @returns Current stream URLs or undefined if not streaming
|
|
531
|
-
*/
|
|
532
|
-
getManagedStreamUrls() {
|
|
533
|
-
return this.managedExtension.getManagedStreamUrls();
|
|
534
|
-
}
|
|
535
|
-
/**
|
|
536
|
-
* ๐ Check for any existing streams (managed or unmanaged) for the current user
|
|
537
|
-
*
|
|
538
|
-
* This method checks if there's already an active stream for the current user,
|
|
539
|
-
* which is useful to avoid conflicts and to reconnect to existing streams.
|
|
540
|
-
*
|
|
541
|
-
* @returns Promise that resolves with stream information if a stream exists
|
|
542
|
-
*
|
|
543
|
-
* @example
|
|
544
|
-
* ```typescript
|
|
545
|
-
* const streamInfo = await session.camera.checkExistingStream();
|
|
546
|
-
* if (streamInfo.hasActiveStream) {
|
|
547
|
-
* console.log('Stream type:', streamInfo.streamInfo?.type);
|
|
548
|
-
* if (streamInfo.streamInfo?.type === 'managed') {
|
|
549
|
-
* console.log('HLS URL:', streamInfo.streamInfo.hlsUrl);
|
|
550
|
-
* } else {
|
|
551
|
-
* console.log('RTMP URL:', streamInfo.streamInfo.rtmpUrl);
|
|
552
|
-
* }
|
|
553
|
-
* }
|
|
554
|
-
* ```
|
|
555
|
-
*/
|
|
556
|
-
async checkExistingStream() {
|
|
557
|
-
return this.managedExtension.checkExistingStream();
|
|
558
|
-
}
|
|
559
|
-
/**
|
|
560
|
-
* Handle incoming stream status check response
|
|
561
|
-
* @internal
|
|
562
|
-
*/
|
|
563
|
-
handleStreamCheckResponse(response) {
|
|
564
|
-
this.managedExtension.handleStreamCheckResponse(response);
|
|
565
|
-
}
|
|
566
|
-
/**
|
|
567
|
-
* Handle incoming managed stream status messages
|
|
568
|
-
* @internal
|
|
569
|
-
*/
|
|
570
|
-
handleManagedStreamStatus(message) {
|
|
571
|
-
this.managedExtension.handleManagedStreamStatus(message);
|
|
572
|
-
}
|
|
573
|
-
// =====================================
|
|
574
|
-
// ๐ง General Utilities
|
|
575
|
-
// =====================================
|
|
576
|
-
/**
|
|
577
|
-
* ๐ง Update the session ID (used when reconnecting)
|
|
578
|
-
*
|
|
579
|
-
* @param newSessionId - The new session ID
|
|
580
|
-
* @internal This method is used internally by AppSession
|
|
581
|
-
*/
|
|
582
|
-
updateSessionId(newSessionId) {
|
|
583
|
-
this.sessionId = newSessionId;
|
|
584
|
-
}
|
|
585
|
-
/**
|
|
586
|
-
* ๐งน Cancel all pending requests and clean up resources
|
|
587
|
-
*
|
|
588
|
-
* @returns Object with counts of cancelled requests
|
|
589
|
-
*/
|
|
590
|
-
cancelAllRequests() {
|
|
591
|
-
const photoRequests = this.cancelAllPhotoRequests();
|
|
592
|
-
// Stop streaming if active
|
|
593
|
-
if (this.isStreaming) {
|
|
594
|
-
this.stopStream().catch((error) => {
|
|
595
|
-
this.logger.error({ error }, "Error stopping stream during cleanup");
|
|
596
|
-
});
|
|
597
|
-
}
|
|
598
|
-
// Clean up managed extension
|
|
599
|
-
this.managedExtension.cleanup();
|
|
600
|
-
return { photoRequests };
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
exports.CameraModule = CameraModule;
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./audio"), exports);
|
|
18
|
-
__exportStar(require("./camera"), exports);
|
|
19
|
-
__exportStar(require("./camera-managed-extension"), exports);
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.LocationManager = void 0;
|
|
4
|
-
const types_1 = require("../../../types");
|
|
5
|
-
class LocationManager {
|
|
6
|
-
constructor(session, send) {
|
|
7
|
-
this.session = session;
|
|
8
|
-
this.send = send;
|
|
9
|
-
this.lastLocationCleanupHandler = () => { };
|
|
10
|
-
}
|
|
11
|
-
// subscribes to the continuous location stream with a specified accuracy tier
|
|
12
|
-
subscribeToStream(options, handler) {
|
|
13
|
-
const subscription = {
|
|
14
|
-
stream: "location_stream",
|
|
15
|
-
rate: options.accuracy,
|
|
16
|
-
};
|
|
17
|
-
this.session.subscribe(subscription);
|
|
18
|
-
this.lastLocationCleanupHandler = this.session.events.onLocation(handler);
|
|
19
|
-
return this.lastLocationCleanupHandler;
|
|
20
|
-
}
|
|
21
|
-
// unsubscribes from the continuous location stream
|
|
22
|
-
unsubscribeFromStream() {
|
|
23
|
-
if (this.lastLocationCleanupHandler) {
|
|
24
|
-
this.lastLocationCleanupHandler();
|
|
25
|
-
this.lastLocationCleanupHandler = () => { };
|
|
26
|
-
}
|
|
27
|
-
else {
|
|
28
|
-
this.session.unsubscribe("location_stream");
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
// performs a one-time, intelligent poll for a location fix
|
|
32
|
-
async getLatestLocation(options) {
|
|
33
|
-
return new Promise((resolve, reject) => {
|
|
34
|
-
const requestId = `poll_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
35
|
-
// listens for a location update with a matching correlationId
|
|
36
|
-
const unsubscribe = this.session.events.on("location_update", (data) => {
|
|
37
|
-
if (data.correlationId === requestId) {
|
|
38
|
-
unsubscribe(); // clean up the listener
|
|
39
|
-
resolve(data);
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
// sends the poll request message to the cloud
|
|
43
|
-
this.send({
|
|
44
|
-
type: types_1.AppToCloudMessageType.LOCATION_POLL_REQUEST,
|
|
45
|
-
correlationId: requestId,
|
|
46
|
-
packageName: this.session.getPackageName(),
|
|
47
|
-
sessionId: this.session.getSessionId(),
|
|
48
|
-
accuracy: options.accuracy,
|
|
49
|
-
});
|
|
50
|
-
// sets a timeout to prevent the promise from hanging indefinitely
|
|
51
|
-
setTimeout(() => {
|
|
52
|
-
unsubscribe();
|
|
53
|
-
reject("Location poll request timed out");
|
|
54
|
-
}, 15000); // 15 second timeout
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
exports.LocationManager = LocationManager;
|