@mentra/bluetooth-sdk 0.1.20 → 0.1.21-beta.1
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/README.md +27 -12
- package/android/build.gradle +3 -0
- package/android/src/main/AndroidManifest.xml +3 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkAnalytics.kt +34 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkDefaults.kt +1 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +169 -26
- package/android/src/main/java/com/mentra/bluetoothsdk/Bridge.kt +72 -16
- package/android/src/main/java/com/mentra/bluetoothsdk/DeviceManager.kt +127 -8
- package/android/src/main/java/com/mentra/bluetoothsdk/DeviceStore.kt +4 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +400 -99
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraLocalNetworkModule.kt +333 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/OtaManifest.kt +43 -3
- package/android/src/main/java/com/mentra/bluetoothsdk/camera/CameraModels.kt +18 -2
- package/android/src/main/java/com/mentra/bluetoothsdk/debug/BleTraceLogger.kt +1 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/services/Foreground.kt +53 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Ar99.java +2653 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G1.kt +1 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G2.kt +16 -9
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Mach1.kt +1 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.kt +342 -42
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraNex.kt +1 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Nimo.kt +1 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/SGCManager.kt +7 -2
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Simulated.kt +1 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/ar99/ota/Ar99OtaManager.java +566 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/ar99/ota/OtaByteUtils.java +18 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/ar99/ota/OtaCommandConstants.java +35 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/ar99/ota/OtaCrc32Util.java +13 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/ar99/ota/OtaGattTransport.java +11 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/ar99/ota/OtaProtocol.java +92 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/status/WifiHotspotStatus.kt +19 -3
- package/android/src/main/java/com/mentra/bluetoothsdk/streaming/StreamModels.kt +52 -2
- package/android/src/main/java/com/mentra/bluetoothsdk/tts/TTSTools.kt +115 -47
- package/android/src/main/java/com/mentra/bluetoothsdk/types/DeviceModels.kt +7 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/BleJsonCompact.java +8 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/Constants.kt +2 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/PhoneAudioMonitor.kt +45 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/audio/Ar99OpusPcmDecoder.java +398 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/audio/PcmStreamPlayer.kt +328 -0
- package/android/src/test/java/com/mentra/bluetoothsdk/OtaManifestDowngradeTest.kt +86 -0
- package/android/src/test/java/com/mentra/bluetoothsdk/StreamStatusEventTest.kt +29 -0
- package/android/src/test/java/com/mentra/bluetoothsdk/camera/PhotoRequestTest.kt +45 -0
- package/android/src/test/java/com/mentra/bluetoothsdk/sgcs/Ar99AdvertisementMatcherTest.java +22 -0
- package/android/src/test/java/com/mentra/bluetoothsdk/utils/BleJsonCompactTest.java +20 -0
- package/android/src/test/java/com/mentra/bluetoothsdk/utils/PhoneAudioMonitorTest.kt +45 -0
- package/build/BluetoothSdk.types.d.ts +100 -22
- package/build/BluetoothSdk.types.d.ts.map +1 -1
- package/build/BluetoothSdk.types.js +2 -1
- package/build/BluetoothSdk.types.js.map +1 -1
- package/build/_internal.d.ts +3 -0
- package/build/_internal.d.ts.map +1 -1
- package/build/_internal.js +3 -0
- package/build/_internal.js.map +1 -1
- package/build/_private/BluetoothSdkModule.d.ts +31 -4
- package/build/_private/BluetoothSdkModule.d.ts.map +1 -1
- package/build/_private/BluetoothSdkModule.js +26 -3
- package/build/_private/BluetoothSdkModule.js.map +1 -1
- package/build/_private/MentraLocalNetworkModule.d.ts +37 -0
- package/build/_private/MentraLocalNetworkModule.d.ts.map +1 -0
- package/build/_private/MentraLocalNetworkModule.js +3 -0
- package/build/_private/MentraLocalNetworkModule.js.map +1 -0
- package/build/_private/cameraRequestPayload.d.ts +1 -1
- package/build/_private/cameraRequestPayload.d.ts.map +1 -1
- package/build/_private/cameraRequestPayload.js +7 -0
- package/build/_private/cameraRequestPayload.js.map +1 -1
- package/build/_private/photoRequestPayload.d.ts.map +1 -1
- package/build/_private/photoRequestPayload.js +10 -0
- package/build/_private/photoRequestPayload.js.map +1 -1
- package/build/_private/sdkOtaManifest.d.ts +20 -0
- package/build/_private/sdkOtaManifest.d.ts.map +1 -0
- package/build/_private/sdkOtaManifest.js +28 -0
- package/build/_private/sdkOtaManifest.js.map +1 -0
- package/build/index.d.ts +1 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +11 -1
- package/build/index.js.map +1 -1
- package/expo-module.config.json +1 -0
- package/ios/BluetoothSdkModule.swift +113 -2
- package/ios/Source/BluetoothSdkDefaults.swift +2 -1
- package/ios/Source/Bridge.swift +87 -21
- package/ios/Source/DeviceManager.swift +118 -20
- package/ios/Source/DeviceStore.swift +4 -0
- package/ios/Source/MentraBluetoothSDK.swift +326 -33
- package/ios/Source/OtaManifest.swift +47 -4
- package/ios/Source/audio/PcmStreamPlayer.swift +410 -0
- package/ios/Source/camera/CameraModels.swift +26 -6
- package/ios/Source/internal/BleTraceLogger.swift +1 -1
- package/ios/Source/internal/BluetoothSdkAnalytics.swift +39 -0
- package/ios/Source/sgcs/Ar99.swift +2451 -0
- package/ios/Source/sgcs/G1.swift +1 -1
- package/ios/Source/sgcs/G2.swift +19 -7
- package/ios/Source/sgcs/Mach1.swift +1 -1
- package/ios/Source/sgcs/MentraLive.swift +478 -61
- package/ios/Source/sgcs/MentraNex.swift +1 -1
- package/ios/Source/sgcs/Nimo.swift +1 -1
- package/ios/Source/sgcs/SGCManager.swift +13 -2
- package/ios/Source/sgcs/Simulated.swift +1 -1
- package/ios/Source/sgcs/ar99/ota/Ar99OtaManager.swift +637 -0
- package/ios/Source/status/WifiHotspotStatus.swift +21 -2
- package/ios/Source/streaming/StreamModels.swift +68 -2
- package/ios/Source/tts/TTSTools.swift +1 -1
- package/ios/Source/types/DeviceModels.swift +13 -0
- package/ios/Source/utils/BleJsonCompact.swift +8 -0
- package/ios/Source/utils/Constants.swift +2 -0
- package/ios/Source/utils/PhoneAudioMonitor.swift +4 -0
- package/package.json +1 -2
- package/src/BluetoothSdk.types.ts +106 -24
- package/src/_internal.ts +3 -0
- package/src/_private/BluetoothSdkModule.ts +83 -18
- package/src/_private/MentraLocalNetworkModule.ts +50 -0
- package/src/_private/cameraRequestPayload.ts +9 -2
- package/src/_private/photoRequestPayload.ts +13 -4
- package/src/_private/sdkOtaManifest.ts +31 -0
- package/src/index.ts +13 -1
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
CAMERA_FOV_MIN,
|
|
12
12
|
CameraFovPreset,
|
|
13
13
|
CameraFovRequest,
|
|
14
|
+
CameraFovOverrideRequest,
|
|
14
15
|
CameraFovResult,
|
|
15
16
|
CameraFovSetting,
|
|
16
17
|
CameraRoiPosition,
|
|
@@ -116,7 +117,7 @@ declare class BluetoothSdkNativeModule extends NativeModule<BluetoothSdkModuleEv
|
|
|
116
117
|
sendWifiCredentials(ssid: string, password: string): Promise<WifiStatusChangeEvent>
|
|
117
118
|
forgetWifiNetwork(ssid: string): Promise<WifiStatusChangeEvent>
|
|
118
119
|
setHotspotState(enabled: boolean): Promise<HotspotStatusChangeEvent>
|
|
119
|
-
/** Set glasses system clock
|
|
120
|
+
/** Set the glasses system clock when phone detects clock skew (Mentra Live and G2). */
|
|
120
121
|
setSystemTime(timestampMs: number): Promise<void>
|
|
121
122
|
/** Logs current WiFi frequency (MHz) and 5 GHz band to Android logcat. */
|
|
122
123
|
logCurrentWifiFrequency(): Promise<void>
|
|
@@ -124,14 +125,20 @@ declare class BluetoothSdkNativeModule extends NativeModule<BluetoothSdkModuleEv
|
|
|
124
125
|
// Gallery Commands
|
|
125
126
|
setGalleryModeEnabled(enabled: boolean): Promise<SettingsAckSuccessEvent>
|
|
126
127
|
setVoiceActivityDetectionEnabled(enabled: boolean): Promise<void>
|
|
128
|
+
/** Mentra Live center-mic loudness / Barrier gate (cs_swit type 10). */
|
|
129
|
+
setLoudnessGateEnabled(enabled: boolean): Promise<void>
|
|
127
130
|
/**
|
|
128
131
|
* @deprecated Sticky action-button photo presets are deprecated. Prefer per-request
|
|
129
|
-
* `requestPhoto(...)` options (e.g. `mode: "text"` for
|
|
132
|
+
* `requestPhoto(...)` options (e.g. `mode: "text"` for text sensor size/crop).
|
|
130
133
|
*/
|
|
131
134
|
setPhotoCaptureDefaults(settings: PhotoCaptureDefaults): Promise<SettingsAckSuccessEvent>
|
|
132
135
|
setVideoRecordingDefaults(width: number, height: number, fps: number): Promise<SettingsAckSuccessEvent>
|
|
133
136
|
setMaxVideoRecordingDuration(minutes: number): Promise<SettingsAckSuccessEvent>
|
|
134
137
|
setCameraFov(request: CameraFovRequest): Promise<CameraFovResult>
|
|
138
|
+
setLegacyCameraFov(request: CameraFovRequest): Promise<CameraFovResult>
|
|
139
|
+
restoreLegacyCameraFov(): Promise<void>
|
|
140
|
+
setCameraFovOverride(request: CameraFovOverrideRequest): Promise<CameraFovResult>
|
|
141
|
+
releaseCameraFovOverride(leaseId: string): Promise<SettingsAckSuccessEvent>
|
|
135
142
|
/**
|
|
136
143
|
* Configure camera HAL tuning (ANR / gain) on Mentra Live glasses.
|
|
137
144
|
* Sends a {@code camera_tuning_config} BLE message; the ASG client relays it as a
|
|
@@ -144,6 +151,7 @@ declare class BluetoothSdkNativeModule extends NativeModule<BluetoothSdkModuleEv
|
|
|
144
151
|
queryGalleryStatus(): Promise<GalleryStatusEvent>
|
|
145
152
|
requestPhoto(params: PhotoRequestParams): Promise<PhotoSuccessResponseEvent>
|
|
146
153
|
warmUpCamera(params: WarmUpCameraParams): Promise<CameraStatusEvent>
|
|
154
|
+
stopCameraWarmUp(requestId: string): Promise<void>
|
|
147
155
|
|
|
148
156
|
// OTA Commands
|
|
149
157
|
setOtaVersionUrl(otaVersionUrl: string): void
|
|
@@ -151,6 +159,10 @@ declare class BluetoothSdkNativeModule extends NativeModule<BluetoothSdkModuleEv
|
|
|
151
159
|
checkForOtaUpdate(): Promise<boolean>
|
|
152
160
|
startOtaUpdate(otaVersionUrl?: string | null): Promise<OtaStartAckEvent>
|
|
153
161
|
sendOtaQueryStatus(): Promise<OtaQueryResult>
|
|
162
|
+
startAr99OtaFromFile(path: string): Promise<boolean>
|
|
163
|
+
cancelAr99Ota(): Promise<void>
|
|
164
|
+
sendAr99FactoryReset(): Promise<void>
|
|
165
|
+
buildAr99OtaSignature(secret: string, appName: string, currentVersion: string, serialNumber: string, nonce: string): string
|
|
154
166
|
|
|
155
167
|
// Version Info Commands
|
|
156
168
|
requestVersionInfo(): Promise<VersionInfoResult>
|
|
@@ -184,9 +196,26 @@ declare class BluetoothSdkNativeModule extends NativeModule<BluetoothSdkModuleEv
|
|
|
184
196
|
// Used to suspend LC3 mic during audio playback to avoid MCU overload
|
|
185
197
|
setOwnAppAudioPlaying(playing: boolean): Promise<void>
|
|
186
198
|
|
|
199
|
+
// Live PCM output stream (miniapp speaker.createStream). MentraOS-internal
|
|
200
|
+
// ? 16-bit LE PCM chunks into a streaming AudioTrack (USAGE_MEDIA, so it
|
|
201
|
+
// follows the phone's media route, e.g. A2DP to glasses). Implemented with
|
|
202
|
+
// AudioTrack on Android and AVAudioEngine on iOS.
|
|
203
|
+
/** Open a PCM stream session. One AudioTrack per id; caller manages ids. */
|
|
204
|
+
pcmStreamOpen(streamId: string, sampleRate: number, channels: number, volume: number): Promise<void>
|
|
205
|
+
/**
|
|
206
|
+
* Append base64 PCM. Resolves with the queued-but-unplayed backlog in ms;
|
|
207
|
+
* blocks (on a background dispatcher) while the backlog is above the
|
|
208
|
+
* backpressure ceiling, so awaited writes self-throttle to realtime.
|
|
209
|
+
*/
|
|
210
|
+
pcmStreamWrite(streamId: string, base64: string): Promise<{bufferedMs: number}>
|
|
211
|
+
/** Drain the backlog, then stop. Resolves with the total played duration. */
|
|
212
|
+
pcmStreamClose(streamId: string): Promise<{durationMs: number}>
|
|
213
|
+
/** Stop immediately, dropping any backlog. Idempotent. */
|
|
214
|
+
pcmStreamAbort(streamId: string): Promise<void>
|
|
215
|
+
|
|
187
216
|
/** Mentra Live only: K900 `cs_getvol` / `sr_getvol`. */
|
|
188
217
|
getGlassesMediaVolume(): Promise<GlassesMediaVolumeGetResult>
|
|
189
|
-
/** Mentra Live only: K900 `cs_vol` / `sr_vol`; level clamped 0
|
|
218
|
+
/** Mentra Live only: K900 `cs_vol` / `sr_vol`; level clamped 0??5 on native. */
|
|
190
219
|
setGlassesMediaVolume(level: number): Promise<GlassesMediaVolumeSetResult>
|
|
191
220
|
|
|
192
221
|
// RGB LED Control
|
|
@@ -244,13 +273,10 @@ const DEFAULT_CONNECT_OPTIONS: Required<ConnectOptions> = {
|
|
|
244
273
|
|
|
245
274
|
const DEFAULT_SCAN_TIMEOUT_MS = 15_000
|
|
246
275
|
|
|
247
|
-
function bindNativeMethod<T extends (...args: never[]) => unknown>(
|
|
248
|
-
module: Record<string, unknown>,
|
|
249
|
-
name: string,
|
|
250
|
-
): T {
|
|
276
|
+
function bindNativeMethod<T extends (...args: never[]) => unknown>(module: Record<string, unknown>, name: string): T {
|
|
251
277
|
const method = module[name]
|
|
252
278
|
if (typeof method !== "function") {
|
|
253
|
-
console.warn(`[BluetoothSdk] Native method "${name}" is unavailable
|
|
279
|
+
console.warn(`[BluetoothSdk] Native method "${name}" is unavailable ??rebuild the app (bun android / bun ios)`)
|
|
254
280
|
return (async () => {
|
|
255
281
|
throw new Error(`BluetoothSdk.${name} is not available in this native build. Rebuild the app.`)
|
|
256
282
|
}) as T
|
|
@@ -267,10 +293,10 @@ const CAMERA_ROI_POSITION_VALUES: Record<CameraRoiPosition, CameraFovSetting["ro
|
|
|
267
293
|
}
|
|
268
294
|
|
|
269
295
|
// Named presets are a convenience layer over the numeric {fov, roiPosition} API.
|
|
270
|
-
//
|
|
296
|
+
// The default is the full sensor; "standard" preserves the historical 102� crop.
|
|
271
297
|
const CAMERA_FOV_PRESETS: Record<CameraFovPreset, CameraFovSetting> = {
|
|
272
298
|
narrow: {fov: 82, roiPosition: 0},
|
|
273
|
-
standard: {fov:
|
|
299
|
+
standard: {fov: 102, roiPosition: 0},
|
|
274
300
|
wide: {fov: CAMERA_FOV_MAX, roiPosition: 0},
|
|
275
301
|
}
|
|
276
302
|
|
|
@@ -286,11 +312,7 @@ function normalizeCameraFov(request: CameraFovRequest): CameraFovSetting {
|
|
|
286
312
|
const roiPosition = request.roiPosition ?? "center"
|
|
287
313
|
|
|
288
314
|
return {
|
|
289
|
-
fov: clampInteger(
|
|
290
|
-
Number.isFinite(request.fov) ? request.fov : CAMERA_FOV_DEFAULT,
|
|
291
|
-
CAMERA_FOV_MIN,
|
|
292
|
-
CAMERA_FOV_MAX,
|
|
293
|
-
),
|
|
315
|
+
fov: clampInteger(Number.isFinite(request.fov) ? request.fov : CAMERA_FOV_DEFAULT, CAMERA_FOV_MIN, CAMERA_FOV_MAX),
|
|
294
316
|
roiPosition: clampInteger(CAMERA_ROI_POSITION_VALUES[roiPosition] ?? 0, CAMERA_ROI_MIN, CAMERA_ROI_MAX) as
|
|
295
317
|
| 0
|
|
296
318
|
| 1
|
|
@@ -470,14 +492,53 @@ NativeBluetoothSdkModule.setVoiceActivityDetectionEnabled = function (enabled: b
|
|
|
470
492
|
return this.updateBluetoothSettings({voice_activity_detection_enabled: enabled})
|
|
471
493
|
}
|
|
472
494
|
|
|
473
|
-
|
|
474
|
-
(
|
|
475
|
-
|
|
495
|
+
NativeBluetoothSdkModule.setLoudnessGateEnabled = function (enabled: boolean) {
|
|
496
|
+
return this.updateBluetoothSettings({loudness_gate_enabled: enabled})
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
const nativeSetCameraFov = bindNativeMethod<(fov: CameraFovSetting) => MaybePromise<CameraFovResult>>(
|
|
500
|
+
NativeBluetoothSdkModule as unknown as Record<string, unknown>,
|
|
501
|
+
"setCameraFov",
|
|
502
|
+
)
|
|
476
503
|
NativeBluetoothSdkModule.setCameraFov = function (request: CameraFovRequest) {
|
|
477
504
|
const setting = normalizeCameraFov(request)
|
|
478
505
|
return Promise.resolve(nativeSetCameraFov(setting))
|
|
479
506
|
}
|
|
480
507
|
|
|
508
|
+
const nativeSetLegacyCameraFov = bindNativeMethod<(fov: CameraFovSetting) => MaybePromise<CameraFovResult>>(
|
|
509
|
+
NativeBluetoothSdkModule as unknown as Record<string, unknown>,
|
|
510
|
+
"setLegacyCameraFov",
|
|
511
|
+
)
|
|
512
|
+
NativeBluetoothSdkModule.setLegacyCameraFov = function (request: CameraFovRequest) {
|
|
513
|
+
return Promise.resolve(nativeSetLegacyCameraFov(normalizeCameraFov(request)))
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
const nativeRestoreLegacyCameraFov = bindNativeMethod<() => MaybePromise<void>>(
|
|
517
|
+
NativeBluetoothSdkModule as unknown as Record<string, unknown>,
|
|
518
|
+
"restoreLegacyCameraFov",
|
|
519
|
+
)
|
|
520
|
+
NativeBluetoothSdkModule.restoreLegacyCameraFov = function () {
|
|
521
|
+
return Promise.resolve(nativeRestoreLegacyCameraFov())
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
const nativeSetCameraFovOverride = bindNativeMethod<
|
|
525
|
+
(request: CameraFovSetting & {leaseId: string; ttlMs: number}) => MaybePromise<CameraFovResult>
|
|
526
|
+
>(NativeBluetoothSdkModule as unknown as Record<string, unknown>, "setCameraFovOverride")
|
|
527
|
+
NativeBluetoothSdkModule.setCameraFovOverride = function (request: CameraFovOverrideRequest) {
|
|
528
|
+
const setting = normalizeCameraFov(request)
|
|
529
|
+
const requestedTtl =
|
|
530
|
+
typeof request.ttlMs === "number" && Number.isFinite(request.ttlMs) && request.ttlMs > 0
|
|
531
|
+
? Math.round(request.ttlMs)
|
|
532
|
+
: 300_000
|
|
533
|
+
return Promise.resolve(
|
|
534
|
+
nativeSetCameraFovOverride({
|
|
535
|
+
...setting,
|
|
536
|
+
leaseId: request.leaseId,
|
|
537
|
+
ttlMs: Math.min(requestedTtl, 600_000),
|
|
538
|
+
}),
|
|
539
|
+
)
|
|
540
|
+
}
|
|
541
|
+
|
|
481
542
|
NativeBluetoothSdkModule.setMicState = function (
|
|
482
543
|
enabled: boolean,
|
|
483
544
|
useGlassesMic?: boolean,
|
|
@@ -588,3 +649,7 @@ NativeBluetoothSdkModule.warmUpCamera = function (params: WarmUpCameraParams) {
|
|
|
588
649
|
|
|
589
650
|
export default NativeBluetoothSdkModule
|
|
590
651
|
export const BluetoothSdk = NativeBluetoothSdkModule as BluetoothSdkInternalModule
|
|
652
|
+
|
|
653
|
+
|
|
654
|
+
|
|
655
|
+
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {NativeModule, requireOptionalNativeModule} from "expo"
|
|
2
|
+
|
|
3
|
+
export type LocalNetworkResponse = {
|
|
4
|
+
status: number
|
|
5
|
+
headers: Record<string, string>
|
|
6
|
+
bodyBase64: string
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type LocalNetworkDownloadResult = {
|
|
10
|
+
statusCode: number
|
|
11
|
+
bytesWritten: number
|
|
12
|
+
headers: Record<string, string>
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type LocalNetworkDownloadProgress = {
|
|
16
|
+
requestId: string
|
|
17
|
+
bytesWritten: number
|
|
18
|
+
contentLength: number
|
|
19
|
+
statusCode?: number
|
|
20
|
+
headers?: Record<string, string>
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
type LocalNetworkEvents = {
|
|
24
|
+
downloadProgress: (event: LocalNetworkDownloadProgress) => void
|
|
25
|
+
networkLost: (event: {ssid: string}) => void
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
declare class MentraLocalNetworkNativeModule extends NativeModule<LocalNetworkEvents> {
|
|
29
|
+
connect(ssid: string, password: string): Promise<{connected: boolean; ssid: string}>
|
|
30
|
+
request(
|
|
31
|
+
requestId: string,
|
|
32
|
+
url: string,
|
|
33
|
+
method: string,
|
|
34
|
+
headers: Record<string, string>,
|
|
35
|
+
body: string | null,
|
|
36
|
+
timeoutMs: number,
|
|
37
|
+
): Promise<LocalNetworkResponse>
|
|
38
|
+
download(
|
|
39
|
+
requestId: string,
|
|
40
|
+
url: string,
|
|
41
|
+
destination: string,
|
|
42
|
+
headers: Record<string, string>,
|
|
43
|
+
connectionTimeoutMs: number,
|
|
44
|
+
readTimeoutMs: number,
|
|
45
|
+
): Promise<LocalNetworkDownloadResult>
|
|
46
|
+
cancel(requestId: string): Promise<void>
|
|
47
|
+
disconnect(): Promise<void>
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export default requireOptionalNativeModule<MentraLocalNetworkNativeModule>("MentraLocalNetwork")
|
|
@@ -9,9 +9,10 @@ function nonBlankString(value?: string | null): string | undefined {
|
|
|
9
9
|
/** Expo Android bridge rejects null values in Map<String, Any> — omit optional nullish fields. */
|
|
10
10
|
export function warmUpCameraParamsForNative(
|
|
11
11
|
params: WarmUpCameraParams,
|
|
12
|
-
): Record<string, string | number> {
|
|
13
|
-
const payload: Record<string, string | number> = {
|
|
12
|
+
): Record<string, string | number | boolean> {
|
|
13
|
+
const payload: Record<string, string | number | boolean> = {
|
|
14
14
|
size: normalizePhotoSizeTier(params.size),
|
|
15
|
+
mode: params.mode ?? "photo",
|
|
15
16
|
}
|
|
16
17
|
const requestId = nonBlankString(params.requestId)
|
|
17
18
|
if (requestId != null) {
|
|
@@ -25,5 +26,11 @@ export function warmUpCameraParamsForNative(
|
|
|
25
26
|
if (durationMs != null && Number.isFinite(durationMs) && durationMs > 0) {
|
|
26
27
|
payload.durationMs = Math.round(durationMs)
|
|
27
28
|
}
|
|
29
|
+
if (params.mfnr != null) {
|
|
30
|
+
payload.mfnr = params.mfnr
|
|
31
|
+
}
|
|
32
|
+
if (params.zsl != null) {
|
|
33
|
+
payload.zsl = params.zsl
|
|
34
|
+
}
|
|
28
35
|
return payload
|
|
29
36
|
}
|
|
@@ -1,4 +1,14 @@
|
|
|
1
|
-
import type {PhotoRequestParams, PhotoSize} from "../BluetoothSdk.types"
|
|
1
|
+
import type {PhotoRequestParams, PhotoSize, PhotoTransferMethod} from "../BluetoothSdk.types"
|
|
2
|
+
|
|
3
|
+
const PHOTO_TRANSFER_METHODS = new Set<PhotoTransferMethod>(["auto", "direct", "ble"])
|
|
4
|
+
|
|
5
|
+
function photoTransferMethodForNative(value: unknown): PhotoTransferMethod {
|
|
6
|
+
if (value === undefined) return "auto"
|
|
7
|
+
if (typeof value === "string" && PHOTO_TRANSFER_METHODS.has(value as PhotoTransferMethod)) {
|
|
8
|
+
return value as PhotoTransferMethod
|
|
9
|
+
}
|
|
10
|
+
throw new TypeError(`Invalid transferMethod ${JSON.stringify(value)}. Expected "auto", "direct", or "ble".`)
|
|
11
|
+
}
|
|
2
12
|
|
|
3
13
|
/** Maps unknown/legacy size strings to the current wire format. */
|
|
4
14
|
export function normalizePhotoSizeTier(size: string | undefined): PhotoSize {
|
|
@@ -25,12 +35,11 @@ function nonBlankString(value?: string | null): string | undefined {
|
|
|
25
35
|
}
|
|
26
36
|
|
|
27
37
|
/** Expo Android bridge rejects null values in Map<String, Any> — omit optional nullish fields. */
|
|
28
|
-
export function photoRequestParamsForNative(
|
|
29
|
-
params: PhotoRequestParams,
|
|
30
|
-
): Record<string, string | number | boolean> {
|
|
38
|
+
export function photoRequestParamsForNative(params: PhotoRequestParams): Record<string, string | number | boolean> {
|
|
31
39
|
const payload: Record<string, string | number | boolean> = {
|
|
32
40
|
size: normalizePhotoSizeTier(params.size),
|
|
33
41
|
mode: params.mode ?? "photo",
|
|
42
|
+
transferMethod: photoTransferMethodForNative(params.transferMethod),
|
|
34
43
|
webhookUrl: params.webhookUrl ?? "",
|
|
35
44
|
compress: params.compress,
|
|
36
45
|
sound: params.sound,
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SDK-pinned OTA manifest URL derivation.
|
|
3
|
+
*
|
|
4
|
+
* Each Bluetooth SDK release publishes an immutable manifest
|
|
5
|
+
* (`bluetooth-sdk-<version>-version.json`) pinning the exact ASG artifact paired with that SDK
|
|
6
|
+
* version. The URL is derived from this package's own version — the version is frozen into the
|
|
7
|
+
* published artifact, so this is equivalent to baking the URL at release time while keeping the
|
|
8
|
+
* manifest itself replaceable as an operational escape hatch (asset moves, CDN migration).
|
|
9
|
+
*
|
|
10
|
+
* Mirrors the native derivation in `OtaManifestDefaults.defaultOtaVersionUrl()` (Kotlin) /
|
|
11
|
+
* `BluetoothSdkDefaults` (Swift).
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const SDK_OTA_RELEASE_BASE_URL = "https://github.com/Mentra-Community/MentraOS/releases/download/bluetooth-sdk-ota"
|
|
15
|
+
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
17
|
+
const packageJson = require("../../package.json") as {version?: string}
|
|
18
|
+
|
|
19
|
+
/** This Bluetooth SDK package's own version, as published. */
|
|
20
|
+
export const BLUETOOTH_SDK_VERSION: string = (packageJson.version ?? "").trim()
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The immutable manifest URL pinning the ASG artifact paired with this SDK version, or null when
|
|
24
|
+
* the package version is unavailable (malformed workspace state).
|
|
25
|
+
*/
|
|
26
|
+
export function sdkPinnedOtaManifestUrl(): string | null {
|
|
27
|
+
if (!BLUETOOTH_SDK_VERSION) {
|
|
28
|
+
return null
|
|
29
|
+
}
|
|
30
|
+
return `${SDK_OTA_RELEASE_BASE_URL}/bluetooth-sdk-${BLUETOOTH_SDK_VERSION}-version.json`
|
|
31
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -44,6 +44,7 @@ const PUBLIC_EVENT_NAMES = new Set<BluetoothSdkEventName>([
|
|
|
44
44
|
"stream_status",
|
|
45
45
|
"ota_start_ack",
|
|
46
46
|
"ota_status",
|
|
47
|
+
"ar99_ota_status",
|
|
47
48
|
"version_info",
|
|
48
49
|
"extraction_progress",
|
|
49
50
|
])
|
|
@@ -96,9 +97,10 @@ export const BluetoothSdk: BluetoothSdkPublicModule = Object.freeze({
|
|
|
96
97
|
setHotspotState: bindPublicMethod("setHotspotState"),
|
|
97
98
|
setGalleryModeEnabled: bindPublicMethod("setGalleryModeEnabled"),
|
|
98
99
|
setVoiceActivityDetectionEnabled: bindPublicMethod("setVoiceActivityDetectionEnabled"),
|
|
100
|
+
setLoudnessGateEnabled: bindPublicMethod("setLoudnessGateEnabled"),
|
|
99
101
|
/**
|
|
100
102
|
* @deprecated Sticky action-button photo presets are deprecated. Prefer per-request
|
|
101
|
-
* `requestPhoto(...)` options (e.g. `mode: "text"` for
|
|
103
|
+
* `requestPhoto(...)` options (e.g. `mode: "text"` for text sensor size/crop, or explicit per-shot
|
|
102
104
|
* fields). Still functional until removed in a future release.
|
|
103
105
|
*/
|
|
104
106
|
setPhotoCaptureDefaults: bindPublicMethod("setPhotoCaptureDefaults"),
|
|
@@ -113,10 +115,14 @@ export const BluetoothSdk: BluetoothSdkPublicModule = Object.freeze({
|
|
|
113
115
|
},
|
|
114
116
|
setMaxVideoRecordingDuration: bindPublicMethod("setMaxVideoRecordingDuration"),
|
|
115
117
|
setCameraFov: bindPublicMethod("setCameraFov"),
|
|
118
|
+
setLegacyCameraFov: bindPublicMethod("setLegacyCameraFov"),
|
|
119
|
+
setCameraFovOverride: bindPublicMethod("setCameraFovOverride"),
|
|
120
|
+
releaseCameraFovOverride: bindPublicMethod("releaseCameraFovOverride"),
|
|
116
121
|
setCameraTuningConfig: bindPublicMethod("setCameraTuningConfig"),
|
|
117
122
|
queryGalleryStatus: bindPublicMethod("queryGalleryStatus"),
|
|
118
123
|
requestPhoto: bindPublicMethod("requestPhoto"),
|
|
119
124
|
warmUpCamera: bindPublicMethod("warmUpCamera"),
|
|
125
|
+
stopCameraWarmUp: bindPublicMethod("stopCameraWarmUp"),
|
|
120
126
|
startVideoRecording: bindPublicMethod("startVideoRecording"),
|
|
121
127
|
stopVideoRecording: bindPublicMethod("stopVideoRecording"),
|
|
122
128
|
startStream: bindPublicMethod("startStream"),
|
|
@@ -130,6 +136,10 @@ export const BluetoothSdk: BluetoothSdkPublicModule = Object.freeze({
|
|
|
130
136
|
requestVersionInfo: bindPublicMethod("requestVersionInfo"),
|
|
131
137
|
checkForOtaUpdate: bindPublicMethod("checkForOtaUpdate"),
|
|
132
138
|
startOtaUpdate,
|
|
139
|
+
startAr99OtaFromFile: bindPublicMethod("startAr99OtaFromFile"),
|
|
140
|
+
cancelAr99Ota: bindPublicMethod("cancelAr99Ota"),
|
|
141
|
+
sendAr99FactoryReset: bindPublicMethod("sendAr99FactoryReset"),
|
|
142
|
+
buildAr99OtaSignature: bindPublicMethod("buildAr99OtaSignature"),
|
|
133
143
|
setSttModelDetails: bindPublicMethod("setSttModelDetails"),
|
|
134
144
|
getSttModelPath: bindPublicMethod("getSttModelPath"),
|
|
135
145
|
checkSttModelAvailable: bindPublicMethod("checkSttModelAvailable"),
|
|
@@ -160,6 +170,7 @@ export {
|
|
|
160
170
|
|
|
161
171
|
export type {
|
|
162
172
|
AccelEvent,
|
|
173
|
+
Ar99OtaStatusEvent,
|
|
163
174
|
AudioConnectedEvent,
|
|
164
175
|
AudioDisconnectedEvent,
|
|
165
176
|
AudioPairingNeededEvent,
|
|
@@ -210,6 +221,7 @@ export type {
|
|
|
210
221
|
PhotoFpsRange,
|
|
211
222
|
PhotoMeteredPreview,
|
|
212
223
|
PhotoMode,
|
|
224
|
+
PhotoTransferMethod,
|
|
213
225
|
PhotoResponseEvent,
|
|
214
226
|
PhotoRequestedCaptureConfig,
|
|
215
227
|
PhotoRequestParams,
|