@mentra/bluetooth-sdk 0.1.21-beta.0 → 0.1.21-beta.2

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.
Files changed (89) hide show
  1. package/README.md +22 -11
  2. package/android/build.gradle +3 -0
  3. package/android/src/main/AndroidManifest.xml +3 -1
  4. package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkAnalytics.kt +34 -0
  5. package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkDefaults.kt +1 -0
  6. package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +43 -3
  7. package/android/src/main/java/com/mentra/bluetoothsdk/Bridge.kt +7 -2
  8. package/android/src/main/java/com/mentra/bluetoothsdk/DeviceManager.kt +82 -6
  9. package/android/src/main/java/com/mentra/bluetoothsdk/DeviceStore.kt +5 -1
  10. package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +32 -3
  11. package/android/src/main/java/com/mentra/bluetoothsdk/OtaManifest.kt +43 -3
  12. package/android/src/main/java/com/mentra/bluetoothsdk/camera/CameraModels.kt +17 -4
  13. package/android/src/main/java/com/mentra/bluetoothsdk/debug/BleTraceLogger.kt +1 -1
  14. package/android/src/main/java/com/mentra/bluetoothsdk/services/Foreground.kt +53 -0
  15. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Ar99.java +2653 -0
  16. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.kt +161 -14
  17. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/SGCManager.kt +3 -0
  18. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/ar99/ota/Ar99OtaManager.java +566 -0
  19. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/ar99/ota/OtaByteUtils.java +18 -0
  20. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/ar99/ota/OtaCommandConstants.java +35 -0
  21. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/ar99/ota/OtaCrc32Util.java +13 -0
  22. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/ar99/ota/OtaGattTransport.java +11 -0
  23. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/ar99/ota/OtaProtocol.java +92 -0
  24. package/android/src/main/java/com/mentra/bluetoothsdk/streaming/StreamModels.kt +41 -1
  25. package/android/src/main/java/com/mentra/bluetoothsdk/types/DeviceModels.kt +7 -0
  26. package/android/src/main/java/com/mentra/bluetoothsdk/utils/BleJsonCompact.java +8 -0
  27. package/android/src/main/java/com/mentra/bluetoothsdk/utils/Constants.kt +2 -1
  28. package/android/src/main/java/com/mentra/bluetoothsdk/utils/PhoneAudioMonitor.kt +45 -0
  29. package/android/src/main/java/com/mentra/bluetoothsdk/utils/audio/Ar99OpusPcmDecoder.java +398 -0
  30. package/android/src/test/java/com/mentra/bluetoothsdk/OtaManifestDowngradeTest.kt +86 -0
  31. package/android/src/test/java/com/mentra/bluetoothsdk/StreamStatusEventTest.kt +29 -0
  32. package/android/src/test/java/com/mentra/bluetoothsdk/camera/PhotoRequestTest.kt +30 -0
  33. package/android/src/test/java/com/mentra/bluetoothsdk/sgcs/Ar99AdvertisementMatcherTest.java +22 -0
  34. package/android/src/test/java/com/mentra/bluetoothsdk/utils/BleJsonCompactTest.java +20 -0
  35. package/android/src/test/java/com/mentra/bluetoothsdk/utils/PhoneAudioMonitorTest.kt +45 -0
  36. package/build/BluetoothSdk.types.d.ts +58 -25
  37. package/build/BluetoothSdk.types.d.ts.map +1 -1
  38. package/build/BluetoothSdk.types.js +2 -1
  39. package/build/BluetoothSdk.types.js.map +1 -1
  40. package/build/_internal.d.ts +1 -0
  41. package/build/_internal.d.ts.map +1 -1
  42. package/build/_internal.js +1 -0
  43. package/build/_internal.js.map +1 -1
  44. package/build/_private/BluetoothSdkModule.d.ts +8 -2
  45. package/build/_private/BluetoothSdkModule.d.ts.map +1 -1
  46. package/build/_private/BluetoothSdkModule.js +6 -3
  47. package/build/_private/BluetoothSdkModule.js.map +1 -1
  48. package/build/_private/cameraRequestPayload.d.ts +1 -1
  49. package/build/_private/cameraRequestPayload.d.ts.map +1 -1
  50. package/build/_private/cameraRequestPayload.js +6 -0
  51. package/build/_private/cameraRequestPayload.js.map +1 -1
  52. package/build/_private/photoRequestPayload.d.ts.map +1 -1
  53. package/build/_private/photoRequestPayload.js +10 -1
  54. package/build/_private/photoRequestPayload.js.map +1 -1
  55. package/build/_private/sdkOtaManifest.d.ts +20 -0
  56. package/build/_private/sdkOtaManifest.d.ts.map +1 -0
  57. package/build/_private/sdkOtaManifest.js +28 -0
  58. package/build/_private/sdkOtaManifest.js.map +1 -0
  59. package/build/index.d.ts +1 -1
  60. package/build/index.d.ts.map +1 -1
  61. package/build/index.js +7 -1
  62. package/build/index.js.map +1 -1
  63. package/ios/BluetoothSdkModule.swift +41 -2
  64. package/ios/Source/BluetoothSdkDefaults.swift +2 -1
  65. package/ios/Source/Bridge.swift +15 -3
  66. package/ios/Source/DeviceManager.swift +67 -17
  67. package/ios/Source/DeviceStore.swift +5 -1
  68. package/ios/Source/MentraBluetoothSDK.swift +37 -8
  69. package/ios/Source/OtaManifest.swift +47 -4
  70. package/ios/Source/camera/CameraModels.swift +20 -5
  71. package/ios/Source/internal/BleTraceLogger.swift +1 -1
  72. package/ios/Source/internal/BluetoothSdkAnalytics.swift +39 -0
  73. package/ios/Source/sgcs/Ar99.swift +2451 -0
  74. package/ios/Source/sgcs/MentraLive.swift +174 -38
  75. package/ios/Source/sgcs/SGCManager.swift +8 -0
  76. package/ios/Source/sgcs/ar99/ota/Ar99OtaManager.swift +637 -0
  77. package/ios/Source/streaming/StreamModels.swift +71 -7
  78. package/ios/Source/types/DeviceModels.swift +13 -0
  79. package/ios/Source/utils/BleJsonCompact.swift +8 -0
  80. package/ios/Source/utils/Constants.swift +2 -0
  81. package/ios/Source/utils/PhoneAudioMonitor.swift +4 -0
  82. package/package.json +1 -1
  83. package/src/BluetoothSdk.types.ts +61 -28
  84. package/src/_internal.ts +1 -0
  85. package/src/_private/BluetoothSdkModule.ts +20 -6
  86. package/src/_private/cameraRequestPayload.ts +8 -2
  87. package/src/_private/photoRequestPayload.ts +12 -2
  88. package/src/_private/sdkOtaManifest.ts +31 -0
  89. package/src/index.ts +9 -1
@@ -1,3 +1,12 @@
1
+ const PHOTO_TRANSFER_METHODS = new Set(["auto", "direct", "ble"]);
2
+ function photoTransferMethodForNative(value) {
3
+ if (value === undefined)
4
+ return "auto";
5
+ if (typeof value === "string" && PHOTO_TRANSFER_METHODS.has(value)) {
6
+ return value;
7
+ }
8
+ throw new TypeError(`Invalid transferMethod ${JSON.stringify(value)}. Expected "auto", "direct", or "ble".`);
9
+ }
1
10
  /** Maps unknown/legacy size strings to the current wire format. */
2
11
  export function normalizePhotoSizeTier(size) {
3
12
  switch (size) {
@@ -25,7 +34,7 @@ export function photoRequestParamsForNative(params) {
25
34
  const payload = {
26
35
  size: normalizePhotoSizeTier(params.size),
27
36
  mode: params.mode ?? "photo",
28
- transferMethod: params.transferMethod ?? "auto",
37
+ transferMethod: photoTransferMethodForNative(params.transferMethod),
29
38
  webhookUrl: params.webhookUrl ?? "",
30
39
  compress: params.compress,
31
40
  sound: params.sound,
@@ -1 +1 @@
1
- {"version":3,"file":"photoRequestPayload.js","sourceRoot":"","sources":["../../src/_private/photoRequestPayload.ts"],"names":[],"mappings":"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","sourcesContent":["import type {PhotoRequestParams, PhotoSize} from \"../BluetoothSdk.types\"\n\n/** Maps unknown/legacy size strings to the current wire format. */\nexport function normalizePhotoSizeTier(size: string | undefined): PhotoSize {\n switch (size) {\n case \"small\":\n return \"low\"\n case \"large\":\n return \"high\"\n case \"full\":\n return \"max\"\n case \"low\":\n case \"medium\":\n case \"high\":\n case \"max\":\n return size\n default:\n return \"medium\"\n }\n}\n\nfunction nonBlankString(value?: string | null): string | undefined {\n const trimmed = value?.trim()\n return trimmed && trimmed.length > 0 ? trimmed : undefined\n}\n\n/** Expo Android bridge rejects null values in Map<String, Any> — omit optional nullish fields. */\nexport function photoRequestParamsForNative(params: PhotoRequestParams): Record<string, string | number | boolean> {\n const payload: Record<string, string | number | boolean> = {\n size: normalizePhotoSizeTier(params.size),\n mode: params.mode ?? \"photo\",\n transferMethod: params.transferMethod ?? \"auto\",\n webhookUrl: params.webhookUrl ?? \"\",\n compress: params.compress,\n sound: params.sound,\n }\n const requestId = nonBlankString(params.requestId)\n if (requestId != null) {\n payload.requestId = requestId\n }\n if (params.save != null) {\n payload.save = params.save\n }\n if (params.authToken != null && params.authToken.length > 0) {\n payload.authToken = params.authToken\n }\n const exposureTimeNs = params.exposureTimeNs\n const hasManualExposure = exposureTimeNs != null && Number.isFinite(exposureTimeNs) && exposureTimeNs > 0\n if (hasManualExposure) {\n payload.exposureTimeNs = exposureTimeNs\n }\n if (hasManualExposure && params.iso != null && Number.isFinite(params.iso) && params.iso > 0) {\n payload.iso = Math.round(params.iso)\n }\n if (params.aeExposureDivisor != null && params.aeExposureDivisor > 1) {\n payload.aeExposureDivisor = Math.round(params.aeExposureDivisor)\n }\n if (params.isoCap != null && params.isoCap > 0) {\n payload.isoCap = Math.round(params.isoCap)\n }\n if (params.noiseReduction != null) {\n payload.noiseReduction = params.noiseReduction\n }\n if (params.edgeEnhancement != null) {\n payload.edgeEnhancement = params.edgeEnhancement\n }\n if (params.mfnr != null) {\n payload.mfnr = params.mfnr\n }\n if (params.zsl != null) {\n payload.zsl = params.zsl\n }\n if (params.ispDigitalGain != null) {\n payload.ispDigitalGain = Math.round(params.ispDigitalGain)\n }\n if (params.ispAnalogGain != null && params.ispAnalogGain.length > 0) {\n payload.ispAnalogGain = params.ispAnalogGain\n }\n return payload\n}\n"]}
1
+ {"version":3,"file":"photoRequestPayload.js","sourceRoot":"","sources":["../../src/_private/photoRequestPayload.ts"],"names":[],"mappings":"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","sourcesContent":["import type {PhotoRequestParams, PhotoSize, PhotoTransferMethod} from \"../BluetoothSdk.types\"\n\nconst PHOTO_TRANSFER_METHODS = new Set<PhotoTransferMethod>([\"auto\", \"direct\", \"ble\"])\n\nfunction photoTransferMethodForNative(value: unknown): PhotoTransferMethod {\n if (value === undefined) return \"auto\"\n if (typeof value === \"string\" && PHOTO_TRANSFER_METHODS.has(value as PhotoTransferMethod)) {\n return value as PhotoTransferMethod\n }\n throw new TypeError(`Invalid transferMethod ${JSON.stringify(value)}. Expected \"auto\", \"direct\", or \"ble\".`)\n}\n\n/** Maps unknown/legacy size strings to the current wire format. */\nexport function normalizePhotoSizeTier(size: string | undefined): PhotoSize {\n switch (size) {\n case \"small\":\n return \"low\"\n case \"large\":\n return \"high\"\n case \"full\":\n return \"max\"\n case \"low\":\n case \"medium\":\n case \"high\":\n case \"max\":\n return size\n default:\n return \"medium\"\n }\n}\n\nfunction nonBlankString(value?: string | null): string | undefined {\n const trimmed = value?.trim()\n return trimmed && trimmed.length > 0 ? trimmed : undefined\n}\n\n/** Expo Android bridge rejects null values in Map<String, Any> — omit optional nullish fields. */\nexport function photoRequestParamsForNative(params: PhotoRequestParams): Record<string, string | number | boolean> {\n const payload: Record<string, string | number | boolean> = {\n size: normalizePhotoSizeTier(params.size),\n mode: params.mode ?? \"photo\",\n transferMethod: photoTransferMethodForNative(params.transferMethod),\n webhookUrl: params.webhookUrl ?? \"\",\n compress: params.compress,\n sound: params.sound,\n }\n const requestId = nonBlankString(params.requestId)\n if (requestId != null) {\n payload.requestId = requestId\n }\n if (params.save != null) {\n payload.save = params.save\n }\n if (params.authToken != null && params.authToken.length > 0) {\n payload.authToken = params.authToken\n }\n const exposureTimeNs = params.exposureTimeNs\n const hasManualExposure = exposureTimeNs != null && Number.isFinite(exposureTimeNs) && exposureTimeNs > 0\n if (hasManualExposure) {\n payload.exposureTimeNs = exposureTimeNs\n }\n if (hasManualExposure && params.iso != null && Number.isFinite(params.iso) && params.iso > 0) {\n payload.iso = Math.round(params.iso)\n }\n if (params.aeExposureDivisor != null && params.aeExposureDivisor > 1) {\n payload.aeExposureDivisor = Math.round(params.aeExposureDivisor)\n }\n if (params.isoCap != null && params.isoCap > 0) {\n payload.isoCap = Math.round(params.isoCap)\n }\n if (params.noiseReduction != null) {\n payload.noiseReduction = params.noiseReduction\n }\n if (params.edgeEnhancement != null) {\n payload.edgeEnhancement = params.edgeEnhancement\n }\n if (params.mfnr != null) {\n payload.mfnr = params.mfnr\n }\n if (params.zsl != null) {\n payload.zsl = params.zsl\n }\n if (params.ispDigitalGain != null) {\n payload.ispDigitalGain = Math.round(params.ispDigitalGain)\n }\n if (params.ispAnalogGain != null && params.ispAnalogGain.length > 0) {\n payload.ispAnalogGain = params.ispAnalogGain\n }\n return payload\n}\n"]}
@@ -0,0 +1,20 @@
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
+ /** This Bluetooth SDK package's own version, as published. */
14
+ export declare const BLUETOOTH_SDK_VERSION: string;
15
+ /**
16
+ * The immutable manifest URL pinning the ASG artifact paired with this SDK version, or null when
17
+ * the package version is unavailable (malformed workspace state).
18
+ */
19
+ export declare function sdkPinnedOtaManifestUrl(): string | null;
20
+ //# sourceMappingURL=sdkOtaManifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdkOtaManifest.d.ts","sourceRoot":"","sources":["../../src/_private/sdkOtaManifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH,8DAA8D;AAC9D,eAAO,MAAM,qBAAqB,EAAE,MAA2C,CAAA;AAE/E;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,GAAG,IAAI,CAKvD"}
@@ -0,0 +1,28 @@
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
+ const SDK_OTA_RELEASE_BASE_URL = "https://github.com/Mentra-Community/MentraOS/releases/download/bluetooth-sdk-ota";
14
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
15
+ const packageJson = require("../../package.json");
16
+ /** This Bluetooth SDK package's own version, as published. */
17
+ export const BLUETOOTH_SDK_VERSION = (packageJson.version ?? "").trim();
18
+ /**
19
+ * The immutable manifest URL pinning the ASG artifact paired with this SDK version, or null when
20
+ * the package version is unavailable (malformed workspace state).
21
+ */
22
+ export function sdkPinnedOtaManifestUrl() {
23
+ if (!BLUETOOTH_SDK_VERSION) {
24
+ return null;
25
+ }
26
+ return `${SDK_OTA_RELEASE_BASE_URL}/bluetooth-sdk-${BLUETOOTH_SDK_VERSION}-version.json`;
27
+ }
28
+ //# sourceMappingURL=sdkOtaManifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdkOtaManifest.js","sourceRoot":"","sources":["../../src/_private/sdkOtaManifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,wBAAwB,GAAG,kFAAkF,CAAA;AAEnH,8DAA8D;AAC9D,MAAM,WAAW,GAAG,OAAO,CAAC,oBAAoB,CAAuB,CAAA;AAEvE,8DAA8D;AAC9D,MAAM,CAAC,MAAM,qBAAqB,GAAW,CAAC,WAAW,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;AAE/E;;;GAGG;AACH,MAAM,UAAU,uBAAuB;IACrC,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAA;IACb,CAAC;IACD,OAAO,GAAG,wBAAwB,kBAAkB,qBAAqB,eAAe,CAAA;AAC1F,CAAC","sourcesContent":["/**\n * SDK-pinned OTA manifest URL derivation.\n *\n * Each Bluetooth SDK release publishes an immutable manifest\n * (`bluetooth-sdk-<version>-version.json`) pinning the exact ASG artifact paired with that SDK\n * version. The URL is derived from this package's own version — the version is frozen into the\n * published artifact, so this is equivalent to baking the URL at release time while keeping the\n * manifest itself replaceable as an operational escape hatch (asset moves, CDN migration).\n *\n * Mirrors the native derivation in `OtaManifestDefaults.defaultOtaVersionUrl()` (Kotlin) /\n * `BluetoothSdkDefaults` (Swift).\n */\n\nconst SDK_OTA_RELEASE_BASE_URL = \"https://github.com/Mentra-Community/MentraOS/releases/download/bluetooth-sdk-ota\"\n\n// eslint-disable-next-line @typescript-eslint/no-var-requires\nconst packageJson = require(\"../../package.json\") as {version?: string}\n\n/** This Bluetooth SDK package's own version, as published. */\nexport const BLUETOOTH_SDK_VERSION: string = (packageJson.version ?? \"\").trim()\n\n/**\n * The immutable manifest URL pinning the ASG artifact paired with this SDK version, or null when\n * the package version is unavailable (malformed workspace state).\n */\nexport function sdkPinnedOtaManifestUrl(): string | null {\n if (!BLUETOOTH_SDK_VERSION) {\n return null\n }\n return `${SDK_OTA_RELEASE_BASE_URL}/bluetooth-sdk-${BLUETOOTH_SDK_VERSION}-version.json`\n}\n"]}
package/build/index.d.ts CHANGED
@@ -2,5 +2,5 @@ import type { BluetoothSdkPublicModule } from "./BluetoothSdk.types";
2
2
  export declare const BluetoothSdk: BluetoothSdkPublicModule;
3
3
  export default BluetoothSdk;
4
4
  export { CAMERA_FOV_DEFAULT, CAMERA_FOV_MAX, CAMERA_FOV_MIN, DeviceModels, isBusyGlassesConnectionStatus, isConnectedGlassesConnectionStatus, isConnectedWifiStatus, isEnabledHotspotStatus, isReadyGlassesConnectionStatus, } from "./BluetoothSdk.types";
5
- export type { AccelEvent, AudioConnectedEvent, AudioDisconnectedEvent, AudioPairingNeededEvent, BatteryStatusEvent, BluetoothSdkEvent, BluetoothSdkEventListener, BluetoothSdkEventMap, BluetoothSdkEventName, BluetoothSdkPublicModule as BluetoothSdkModule, BluetoothSdkSubscription, ButtonPhotoSize, PhotoCaptureDefaults, ButtonPressEvent, CameraFovPreset, CameraFovRequest, CameraFovResult, CameraRoiPosition, CompatibleGlassesSearchStopEvent, ConnectOptions, ConnectedGlassesConnectionStatus, ConnectedWifiStatus, Device, DeviceModel, EnabledHotspotStatus, GalleryStatusEvent, GlassesConnectionStatus, GlassesMediaVolumeGetResult, GlassesMediaVolumeSetResult, GlassesNotReadyEvent, HeadUpEvent, HotspotErrorEvent, HotspotStatus, HotspotStatusChangeEvent, LocalTranscriptionEvent, LogEvent, MicLc3Event, MicMode, MicPcmEvent, MicPreference, OtaStartAckEvent, OtaStatus, OtaStatusEvent, OtaQueryResult, PairFailureEvent, PhotoCaptureMetadata, PhotoResolvedConfig, PhotoCompression, PhotoFpsRange, PhotoMeteredPreview, PhotoMode, PhotoResponseEvent, PhotoRequestedCaptureConfig, PhotoRequestParams, PhotoSize, PhotoStatusEvent, PhotoStatusState, PhotoSuccessResponseEvent, RgbLedAction, RgbLedColor, RgbLedControlResponseEvent, RgbLedControlSuccessResponseEvent, ScanModelOptions, ScanOptions, ScanResultsCallback, SpeakingStatusEvent, SettingsAckEvent, SettingsAckSetting, SettingsAckSuccessEvent, SettingsAckSuccessStatus, SettingsAckStatus, StreamAudioConfig, StreamResolvedConfig, StreamStartRequest, StreamStatusEvent, StreamStatusLifecycleState, StreamStatusReconnectState, StreamStatusState, StreamVideoConfig, SwipeVolumeStatusEvent, SwitchStatusEvent, TouchEvent, VideoRecordingDefaults, VideoRecordingStartedStatusEvent, VideoRecordingStatusEvent, VideoRecordingStatusState, VideoRecordingStoppedStatusEvent, VideoRecordingSuccessStatusEvent, VersionInfoEvent, VersionInfoResult, WifiScanResultEvent, VoiceActivityDetectionStatusEvent, WifiSearchResult, WifiStatus, WifiStatusChangeEvent, } from "./BluetoothSdk.types";
5
+ export type { AccelEvent, Ar99OtaStatusEvent, AudioConnectedEvent, AudioDisconnectedEvent, AudioPairingNeededEvent, BatteryStatusEvent, BluetoothSdkEvent, BluetoothSdkEventListener, BluetoothSdkEventMap, BluetoothSdkEventName, BluetoothSdkPublicModule as BluetoothSdkModule, BluetoothSdkSubscription, ButtonPhotoSize, PhotoCaptureDefaults, ButtonPressEvent, CameraFovPreset, CameraFovRequest, CameraFovResult, CameraRoiPosition, CompatibleGlassesSearchStopEvent, ConnectOptions, ConnectedGlassesConnectionStatus, ConnectedWifiStatus, Device, DeviceModel, EnabledHotspotStatus, GalleryStatusEvent, GlassesConnectionStatus, GlassesMediaVolumeGetResult, GlassesMediaVolumeSetResult, GlassesNotReadyEvent, HeadUpEvent, HotspotErrorEvent, HotspotStatus, HotspotStatusChangeEvent, LocalTranscriptionEvent, LogEvent, MicLc3Event, MicMode, MicPcmEvent, MicPreference, OtaStartAckEvent, OtaStatus, OtaStatusEvent, OtaQueryResult, PairFailureEvent, PhotoCaptureMetadata, PhotoResolvedConfig, PhotoCompression, PhotoFpsRange, PhotoMeteredPreview, PhotoMode, PhotoTransferMethod, PhotoResponseEvent, PhotoRequestedCaptureConfig, PhotoRequestParams, PhotoSize, PhotoStatusEvent, PhotoStatusState, PhotoSuccessResponseEvent, RgbLedAction, RgbLedColor, RgbLedControlResponseEvent, RgbLedControlSuccessResponseEvent, ScanModelOptions, ScanOptions, ScanResultsCallback, SpeakingStatusEvent, SettingsAckEvent, SettingsAckSetting, SettingsAckSuccessEvent, SettingsAckSuccessStatus, SettingsAckStatus, StreamAudioConfig, StreamResolvedConfig, StreamStartRequest, StreamStatusEvent, StreamStatusLifecycleState, StreamStatusReconnectState, StreamStatusState, StreamVideoConfig, SwipeVolumeStatusEvent, SwitchStatusEvent, TouchEvent, VideoRecordingDefaults, VideoRecordingStartedStatusEvent, VideoRecordingStatusEvent, VideoRecordingStatusState, VideoRecordingStoppedStatusEvent, VideoRecordingSuccessStatusEvent, VersionInfoEvent, VersionInfoResult, WifiScanResultEvent, VoiceActivityDetectionStatusEvent, WifiSearchResult, WifiStatus, WifiStatusChangeEvent, } from "./BluetoothSdk.types";
6
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAGV,wBAAwB,EAEzB,MAAM,sBAAsB,CAAA;AAkE7B,eAAO,MAAM,YAAY,EAAE,wBA4EzB,CAAA;AAEF,eAAe,YAAY,CAAA;AAE3B,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,cAAc,EACd,YAAY,EACZ,6BAA6B,EAC7B,kCAAkC,EAClC,qBAAqB,EACrB,sBAAsB,EACtB,8BAA8B,GAC/B,MAAM,sBAAsB,CAAA;AAE7B,YAAY,EACV,UAAU,EACV,mBAAmB,EACnB,sBAAsB,EACtB,uBAAuB,EACvB,kBAAkB,EAClB,iBAAiB,EACjB,yBAAyB,EACzB,oBAAoB,EACpB,qBAAqB,EACrB,wBAAwB,IAAI,kBAAkB,EAC9C,wBAAwB,EACxB,eAAe,EACf,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,gCAAgC,EAChC,cAAc,EACd,gCAAgC,EAChC,mBAAmB,EACnB,MAAM,EACN,WAAW,EACX,oBAAoB,EACpB,kBAAkB,EAClB,uBAAuB,EACvB,2BAA2B,EAC3B,2BAA2B,EAC3B,oBAAoB,EACpB,WAAW,EACX,iBAAiB,EACjB,aAAa,EACb,wBAAwB,EACxB,uBAAuB,EACvB,QAAQ,EACR,WAAW,EACX,OAAO,EACP,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,SAAS,EACT,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACpB,mBAAmB,EACnB,gBAAgB,EAChB,aAAa,EACb,mBAAmB,EACnB,SAAS,EACT,kBAAkB,EAClB,2BAA2B,EAC3B,kBAAkB,EAClB,SAAS,EACT,gBAAgB,EAChB,gBAAgB,EAChB,yBAAyB,EACzB,YAAY,EACZ,WAAW,EACX,0BAA0B,EAC1B,iCAAiC,EACjC,gBAAgB,EAChB,WAAW,EACX,mBAAmB,EACnB,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,EAClB,uBAAuB,EACvB,wBAAwB,EACxB,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,EACjB,0BAA0B,EAC1B,0BAA0B,EAC1B,iBAAiB,EACjB,iBAAiB,EACjB,sBAAsB,EACtB,iBAAiB,EACjB,UAAU,EACV,sBAAsB,EACtB,gCAAgC,EAChC,yBAAyB,EACzB,yBAAyB,EACzB,gCAAgC,EAChC,gCAAgC,EAChC,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EACnB,iCAAiC,EACjC,gBAAgB,EAChB,UAAU,EACV,qBAAqB,GACtB,MAAM,sBAAsB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAGV,wBAAwB,EAEzB,MAAM,sBAAsB,CAAA;AAmE7B,eAAO,MAAM,YAAY,EAAE,wBAiFzB,CAAA;AAEF,eAAe,YAAY,CAAA;AAE3B,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,cAAc,EACd,YAAY,EACZ,6BAA6B,EAC7B,kCAAkC,EAClC,qBAAqB,EACrB,sBAAsB,EACtB,8BAA8B,GAC/B,MAAM,sBAAsB,CAAA;AAE7B,YAAY,EACV,UAAU,EACV,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,EACtB,uBAAuB,EACvB,kBAAkB,EAClB,iBAAiB,EACjB,yBAAyB,EACzB,oBAAoB,EACpB,qBAAqB,EACrB,wBAAwB,IAAI,kBAAkB,EAC9C,wBAAwB,EACxB,eAAe,EACf,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,gCAAgC,EAChC,cAAc,EACd,gCAAgC,EAChC,mBAAmB,EACnB,MAAM,EACN,WAAW,EACX,oBAAoB,EACpB,kBAAkB,EAClB,uBAAuB,EACvB,2BAA2B,EAC3B,2BAA2B,EAC3B,oBAAoB,EACpB,WAAW,EACX,iBAAiB,EACjB,aAAa,EACb,wBAAwB,EACxB,uBAAuB,EACvB,QAAQ,EACR,WAAW,EACX,OAAO,EACP,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,SAAS,EACT,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACpB,mBAAmB,EACnB,gBAAgB,EAChB,aAAa,EACb,mBAAmB,EACnB,SAAS,EACT,mBAAmB,EACnB,kBAAkB,EAClB,2BAA2B,EAC3B,kBAAkB,EAClB,SAAS,EACT,gBAAgB,EAChB,gBAAgB,EAChB,yBAAyB,EACzB,YAAY,EACZ,WAAW,EACX,0BAA0B,EAC1B,iCAAiC,EACjC,gBAAgB,EAChB,WAAW,EACX,mBAAmB,EACnB,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,EAClB,uBAAuB,EACvB,wBAAwB,EACxB,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,EACjB,0BAA0B,EAC1B,0BAA0B,EAC1B,iBAAiB,EACjB,iBAAiB,EACjB,sBAAsB,EACtB,iBAAiB,EACjB,UAAU,EACV,sBAAsB,EACtB,gCAAgC,EAChC,yBAAyB,EACzB,yBAAyB,EACzB,gCAAgC,EAChC,gCAAgC,EAChC,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EACnB,iCAAiC,EACjC,gBAAgB,EAChB,UAAU,EACV,qBAAqB,GACtB,MAAM,sBAAsB,CAAA"}
package/build/index.js CHANGED
@@ -37,6 +37,7 @@ const PUBLIC_EVENT_NAMES = new Set([
37
37
  "stream_status",
38
38
  "ota_start_ack",
39
39
  "ota_status",
40
+ "ar99_ota_status",
40
41
  "version_info",
41
42
  "extraction_progress",
42
43
  ]);
@@ -84,9 +85,10 @@ export const BluetoothSdk = Object.freeze({
84
85
  setHotspotState: bindPublicMethod("setHotspotState"),
85
86
  setGalleryModeEnabled: bindPublicMethod("setGalleryModeEnabled"),
86
87
  setVoiceActivityDetectionEnabled: bindPublicMethod("setVoiceActivityDetectionEnabled"),
88
+ setLoudnessGateEnabled: bindPublicMethod("setLoudnessGateEnabled"),
87
89
  /**
88
90
  * @deprecated Sticky action-button photo presets are deprecated. Prefer per-request
89
- * `requestPhoto(...)` options (e.g. `mode: "text"` for AE ÷3, or explicit per-shot
91
+ * `requestPhoto(...)` options (e.g. `mode: "text"` for text sensor size/crop, or explicit per-shot
90
92
  * fields). Still functional until removed in a future release.
91
93
  */
92
94
  setPhotoCaptureDefaults: bindPublicMethod("setPhotoCaptureDefaults"),
@@ -120,6 +122,10 @@ export const BluetoothSdk = Object.freeze({
120
122
  requestVersionInfo: bindPublicMethod("requestVersionInfo"),
121
123
  checkForOtaUpdate: bindPublicMethod("checkForOtaUpdate"),
122
124
  startOtaUpdate,
125
+ startAr99OtaFromFile: bindPublicMethod("startAr99OtaFromFile"),
126
+ cancelAr99Ota: bindPublicMethod("cancelAr99Ota"),
127
+ sendAr99FactoryReset: bindPublicMethod("sendAr99FactoryReset"),
128
+ buildAr99OtaSignature: bindPublicMethod("buildAr99OtaSignature"),
123
129
  setSttModelDetails: bindPublicMethod("setSttModelDetails"),
124
130
  getSttModelPath: bindPublicMethod("getSttModelPath"),
125
131
  checkSttModelAvailable: bindPublicMethod("checkSttModelAvailable"),
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import PrivateBluetoothSdkModule from \"./_private/BluetoothSdkModule\"\nimport type {\n BluetoothSdkEventListener,\n BluetoothSdkEventName,\n BluetoothSdkPublicModule,\n VideoRecordingDefaults,\n} from \"./BluetoothSdk.types\"\n\nconst PUBLIC_EVENT_NAMES = new Set<BluetoothSdkEventName>([\n \"log\",\n \"device_discovered\",\n \"default_device_changed\",\n \"glasses_not_ready\",\n \"button_press\",\n \"touch_event\",\n \"accel_event\",\n \"head_up\",\n \"voice_activity_detection_status\",\n \"speaking_status\",\n \"battery_status\",\n \"local_transcription\",\n \"wifi_status_change\",\n \"wifi_scan_result\",\n \"hotspot_status_change\",\n \"hotspot_error\",\n \"photo_response\",\n \"photo_status\",\n \"camera_status\",\n \"video_recording_status\",\n \"media_success\",\n \"media_error\",\n \"gallery_status\",\n \"compatible_glasses_search_stop\",\n \"swipe_volume_status\",\n \"switch_status\",\n \"rgb_led_control_response\",\n \"settings_ack\",\n \"pair_failure\",\n \"audio_pairing_needed\",\n \"audio_connected\",\n \"audio_disconnected\",\n \"mic_pcm\",\n \"mic_lc3\",\n \"stream_status\",\n \"ota_start_ack\",\n \"ota_status\",\n \"version_info\",\n \"extraction_progress\",\n])\n\nconst addListener: BluetoothSdkPublicModule[\"addListener\"] = (eventName, listener) => {\n if (!PUBLIC_EVENT_NAMES.has(eventName)) {\n throw new Error(`Unsupported BluetoothSdk event \"${eventName}\". Use @mentra/bluetooth-sdk/react for status state.`)\n }\n return PrivateBluetoothSdkModule.addListener(eventName, listener as BluetoothSdkEventListener<BluetoothSdkEventName>)\n}\n\nconst startOtaUpdate: BluetoothSdkPublicModule[\"startOtaUpdate\"] = () => {\n return PrivateBluetoothSdkModule.startOtaUpdate()\n}\n\nconst bindPublicMethod = <K extends keyof BluetoothSdkPublicModule>(name: K): BluetoothSdkPublicModule[K] => {\n const method = (PrivateBluetoothSdkModule as unknown as Record<string, unknown>)[name]\n if (typeof method === \"function\") {\n return method.bind(PrivateBluetoothSdkModule) as BluetoothSdkPublicModule[K]\n }\n\n return (async () => {\n throw new Error(`BluetoothSdk.${String(name)} is not available in this native build. Rebuild the app.`)\n }) as unknown as BluetoothSdkPublicModule[K]\n}\n\nexport const BluetoothSdk: BluetoothSdkPublicModule = Object.freeze({\n addListener,\n getDefaultDevice: bindPublicMethod(\"getDefaultDevice\"),\n setDefaultDevice: bindPublicMethod(\"setDefaultDevice\"),\n clearDefaultDevice: bindPublicMethod(\"clearDefaultDevice\"),\n startScan: bindPublicMethod(\"startScan\"),\n stopScan: bindPublicMethod(\"stopScan\"),\n scan: bindPublicMethod(\"scan\") as BluetoothSdkPublicModule[\"scan\"],\n connect: bindPublicMethod(\"connect\"),\n connectDefault: bindPublicMethod(\"connectDefault\"),\n cancelConnectionAttempt: bindPublicMethod(\"cancelConnectionAttempt\"),\n disconnect: bindPublicMethod(\"disconnect\"),\n forget: bindPublicMethod(\"forget\"),\n displayText: bindPublicMethod(\"displayText\"),\n clearDisplay: bindPublicMethod(\"clearDisplay\"),\n showDashboard: bindPublicMethod(\"showDashboard\"),\n setDashboardPosition: bindPublicMethod(\"setDashboardPosition\"),\n setHeadUpAngle: bindPublicMethod(\"setHeadUpAngle\"),\n setImuEnabled: bindPublicMethod(\"setImuEnabled\"),\n setScreenDisabled: bindPublicMethod(\"setScreenDisabled\"),\n requestWifiScan: bindPublicMethod(\"requestWifiScan\"),\n sendWifiCredentials: bindPublicMethod(\"sendWifiCredentials\"),\n forgetWifiNetwork: bindPublicMethod(\"forgetWifiNetwork\"),\n setHotspotState: bindPublicMethod(\"setHotspotState\"),\n setGalleryModeEnabled: bindPublicMethod(\"setGalleryModeEnabled\"),\n setVoiceActivityDetectionEnabled: bindPublicMethod(\"setVoiceActivityDetectionEnabled\"),\n /**\n * @deprecated Sticky action-button photo presets are deprecated. Prefer per-request\n * `requestPhoto(...)` options (e.g. `mode: \"text\"` for AE ÷3, or explicit per-shot\n * fields). Still functional until removed in a future release.\n */\n setPhotoCaptureDefaults: bindPublicMethod(\"setPhotoCaptureDefaults\"),\n setVideoRecordingDefaults: ({width, height, fps}: VideoRecordingDefaults) => {\n const method = (PrivateBluetoothSdkModule as unknown as Record<string, unknown>).setVideoRecordingDefaults\n if (typeof method !== \"function\") {\n return Promise.reject(\n new Error(\"BluetoothSdk.setVideoRecordingDefaults is not available in this native build. Rebuild the app.\"),\n )\n }\n return PrivateBluetoothSdkModule.setVideoRecordingDefaults(width, height, fps)\n },\n setMaxVideoRecordingDuration: bindPublicMethod(\"setMaxVideoRecordingDuration\"),\n setCameraFov: bindPublicMethod(\"setCameraFov\"),\n setLegacyCameraFov: bindPublicMethod(\"setLegacyCameraFov\"),\n setCameraFovOverride: bindPublicMethod(\"setCameraFovOverride\"),\n releaseCameraFovOverride: bindPublicMethod(\"releaseCameraFovOverride\"),\n setCameraTuningConfig: bindPublicMethod(\"setCameraTuningConfig\"),\n queryGalleryStatus: bindPublicMethod(\"queryGalleryStatus\"),\n requestPhoto: bindPublicMethod(\"requestPhoto\"),\n warmUpCamera: bindPublicMethod(\"warmUpCamera\"),\n stopCameraWarmUp: bindPublicMethod(\"stopCameraWarmUp\"),\n startVideoRecording: bindPublicMethod(\"startVideoRecording\"),\n stopVideoRecording: bindPublicMethod(\"stopVideoRecording\"),\n startStream: bindPublicMethod(\"startStream\"),\n stopStream: bindPublicMethod(\"stopStream\"),\n setMicState: bindPublicMethod(\"setMicState\"),\n setPreferredMic: bindPublicMethod(\"setPreferredMic\"),\n setOwnAppAudioPlaying: bindPublicMethod(\"setOwnAppAudioPlaying\"),\n getGlassesMediaVolume: bindPublicMethod(\"getGlassesMediaVolume\"),\n setGlassesMediaVolume: bindPublicMethod(\"setGlassesMediaVolume\"),\n rgbLedControl: bindPublicMethod(\"rgbLedControl\"),\n requestVersionInfo: bindPublicMethod(\"requestVersionInfo\"),\n checkForOtaUpdate: bindPublicMethod(\"checkForOtaUpdate\"),\n startOtaUpdate,\n setSttModelDetails: bindPublicMethod(\"setSttModelDetails\"),\n getSttModelPath: bindPublicMethod(\"getSttModelPath\"),\n checkSttModelAvailable: bindPublicMethod(\"checkSttModelAvailable\"),\n validateSttModel: bindPublicMethod(\"validateSttModel\"),\n extractTarBz2: bindPublicMethod(\"extractTarBz2\"),\n restartTranscriber: bindPublicMethod(\"restartTranscriber\"),\n setTtsModelDetails: bindPublicMethod(\"setTtsModelDetails\"),\n getTtsModelPath: bindPublicMethod(\"getTtsModelPath\"),\n getTtsModelLanguage: bindPublicMethod(\"getTtsModelLanguage\"),\n checkTtsModelAvailable: bindPublicMethod(\"checkTtsModelAvailable\"),\n validateTtsModel: bindPublicMethod(\"validateTtsModel\"),\n generateTtsAudio: bindPublicMethod(\"generateTtsAudio\"),\n})\n\nexport default BluetoothSdk\n\nexport {\n CAMERA_FOV_DEFAULT,\n CAMERA_FOV_MAX,\n CAMERA_FOV_MIN,\n DeviceModels,\n isBusyGlassesConnectionStatus,\n isConnectedGlassesConnectionStatus,\n isConnectedWifiStatus,\n isEnabledHotspotStatus,\n isReadyGlassesConnectionStatus,\n} from \"./BluetoothSdk.types\"\n\nexport type {\n AccelEvent,\n AudioConnectedEvent,\n AudioDisconnectedEvent,\n AudioPairingNeededEvent,\n BatteryStatusEvent,\n BluetoothSdkEvent,\n BluetoothSdkEventListener,\n BluetoothSdkEventMap,\n BluetoothSdkEventName,\n BluetoothSdkPublicModule as BluetoothSdkModule,\n BluetoothSdkSubscription,\n ButtonPhotoSize,\n PhotoCaptureDefaults,\n ButtonPressEvent,\n CameraFovPreset,\n CameraFovRequest,\n CameraFovResult,\n CameraRoiPosition,\n CompatibleGlassesSearchStopEvent,\n ConnectOptions,\n ConnectedGlassesConnectionStatus,\n ConnectedWifiStatus,\n Device,\n DeviceModel,\n EnabledHotspotStatus,\n GalleryStatusEvent,\n GlassesConnectionStatus,\n GlassesMediaVolumeGetResult,\n GlassesMediaVolumeSetResult,\n GlassesNotReadyEvent,\n HeadUpEvent,\n HotspotErrorEvent,\n HotspotStatus,\n HotspotStatusChangeEvent,\n LocalTranscriptionEvent,\n LogEvent,\n MicLc3Event,\n MicMode,\n MicPcmEvent,\n MicPreference,\n OtaStartAckEvent,\n OtaStatus,\n OtaStatusEvent,\n OtaQueryResult,\n PairFailureEvent,\n PhotoCaptureMetadata,\n PhotoResolvedConfig,\n PhotoCompression,\n PhotoFpsRange,\n PhotoMeteredPreview,\n PhotoMode,\n PhotoResponseEvent,\n PhotoRequestedCaptureConfig,\n PhotoRequestParams,\n PhotoSize,\n PhotoStatusEvent,\n PhotoStatusState,\n PhotoSuccessResponseEvent,\n RgbLedAction,\n RgbLedColor,\n RgbLedControlResponseEvent,\n RgbLedControlSuccessResponseEvent,\n ScanModelOptions,\n ScanOptions,\n ScanResultsCallback,\n SpeakingStatusEvent,\n SettingsAckEvent,\n SettingsAckSetting,\n SettingsAckSuccessEvent,\n SettingsAckSuccessStatus,\n SettingsAckStatus,\n StreamAudioConfig,\n StreamResolvedConfig,\n StreamStartRequest,\n StreamStatusEvent,\n StreamStatusLifecycleState,\n StreamStatusReconnectState,\n StreamStatusState,\n StreamVideoConfig,\n SwipeVolumeStatusEvent,\n SwitchStatusEvent,\n TouchEvent,\n VideoRecordingDefaults,\n VideoRecordingStartedStatusEvent,\n VideoRecordingStatusEvent,\n VideoRecordingStatusState,\n VideoRecordingStoppedStatusEvent,\n VideoRecordingSuccessStatusEvent,\n VersionInfoEvent,\n VersionInfoResult,\n WifiScanResultEvent,\n VoiceActivityDetectionStatusEvent,\n WifiSearchResult,\n WifiStatus,\n WifiStatusChangeEvent,\n} from \"./BluetoothSdk.types\"\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,yBAAyB,MAAM,+BAA+B,CAAA;AAQrE,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAwB;IACxD,KAAK;IACL,mBAAmB;IACnB,wBAAwB;IACxB,mBAAmB;IACnB,cAAc;IACd,aAAa;IACb,aAAa;IACb,SAAS;IACT,iCAAiC;IACjC,iBAAiB;IACjB,gBAAgB;IAChB,qBAAqB;IACrB,oBAAoB;IACpB,kBAAkB;IAClB,uBAAuB;IACvB,eAAe;IACf,gBAAgB;IAChB,cAAc;IACd,eAAe;IACf,wBAAwB;IACxB,eAAe;IACf,aAAa;IACb,gBAAgB;IAChB,gCAAgC;IAChC,qBAAqB;IACrB,eAAe;IACf,0BAA0B;IAC1B,cAAc;IACd,cAAc;IACd,sBAAsB;IACtB,iBAAiB;IACjB,oBAAoB;IACpB,SAAS;IACT,SAAS;IACT,eAAe;IACf,eAAe;IACf,YAAY;IACZ,iBAAiB;IACjB,cAAc;IACd,qBAAqB;CACtB,CAAC,CAAA;AAEF,MAAM,WAAW,GAA4C,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE;IACnF,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CAAC,mCAAmC,SAAS,sDAAsD,CAAC,CAAA;IACrH,CAAC;IACD,OAAO,yBAAyB,CAAC,WAAW,CAAC,SAAS,EAAE,QAA4D,CAAC,CAAA;AACvH,CAAC,CAAA;AAED,MAAM,cAAc,GAA+C,GAAG,EAAE;IACtE,OAAO,yBAAyB,CAAC,cAAc,EAAE,CAAA;AACnD,CAAC,CAAA;AAED,MAAM,gBAAgB,GAAG,CAA2C,IAAO,EAA+B,EAAE;IAC1G,MAAM,MAAM,GAAI,yBAAgE,CAAC,IAAI,CAAC,CAAA;IACtF,IAAI,OAAO,MAAM,KAAK,UAAU,EAAE,CAAC;QACjC,OAAO,MAAM,CAAC,IAAI,CAAC,yBAAyB,CAAgC,CAAA;IAC9E,CAAC;IAED,OAAO,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,IAAI,KAAK,CAAC,gBAAgB,MAAM,CAAC,IAAI,CAAC,0DAA0D,CAAC,CAAA;IACzG,CAAC,CAA2C,CAAA;AAC9C,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,YAAY,GAA6B,MAAM,CAAC,MAAM,CAAC;IAClE,WAAW;IACX,gBAAgB,EAAE,gBAAgB,CAAC,kBAAkB,CAAC;IACtD,gBAAgB,EAAE,gBAAgB,CAAC,kBAAkB,CAAC;IACtD,kBAAkB,EAAE,gBAAgB,CAAC,oBAAoB,CAAC;IAC1D,SAAS,EAAE,gBAAgB,CAAC,WAAW,CAAC;IACxC,QAAQ,EAAE,gBAAgB,CAAC,UAAU,CAAC;IACtC,IAAI,EAAE,gBAAgB,CAAC,MAAM,CAAqC;IAClE,OAAO,EAAE,gBAAgB,CAAC,SAAS,CAAC;IACpC,cAAc,EAAE,gBAAgB,CAAC,gBAAgB,CAAC;IAClD,uBAAuB,EAAE,gBAAgB,CAAC,yBAAyB,CAAC;IACpE,UAAU,EAAE,gBAAgB,CAAC,YAAY,CAAC;IAC1C,MAAM,EAAE,gBAAgB,CAAC,QAAQ,CAAC;IAClC,WAAW,EAAE,gBAAgB,CAAC,aAAa,CAAC;IAC5C,YAAY,EAAE,gBAAgB,CAAC,cAAc,CAAC;IAC9C,aAAa,EAAE,gBAAgB,CAAC,eAAe,CAAC;IAChD,oBAAoB,EAAE,gBAAgB,CAAC,sBAAsB,CAAC;IAC9D,cAAc,EAAE,gBAAgB,CAAC,gBAAgB,CAAC;IAClD,aAAa,EAAE,gBAAgB,CAAC,eAAe,CAAC;IAChD,iBAAiB,EAAE,gBAAgB,CAAC,mBAAmB,CAAC;IACxD,eAAe,EAAE,gBAAgB,CAAC,iBAAiB,CAAC;IACpD,mBAAmB,EAAE,gBAAgB,CAAC,qBAAqB,CAAC;IAC5D,iBAAiB,EAAE,gBAAgB,CAAC,mBAAmB,CAAC;IACxD,eAAe,EAAE,gBAAgB,CAAC,iBAAiB,CAAC;IACpD,qBAAqB,EAAE,gBAAgB,CAAC,uBAAuB,CAAC;IAChE,gCAAgC,EAAE,gBAAgB,CAAC,kCAAkC,CAAC;IACtF,sBAAsB,EAAE,gBAAgB,CAAC,wBAAwB,CAAC;IAClE;;;;OAIG;IACH,uBAAuB,EAAE,gBAAgB,CAAC,yBAAyB,CAAC;IACpE,yBAAyB,EAAE,CAAC,EAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAyB,EAAE,EAAE;QAC1E,MAAM,MAAM,GAAI,yBAAgE,CAAC,yBAAyB,CAAA;QAC1G,IAAI,OAAO,MAAM,KAAK,UAAU,EAAE,CAAC;YACjC,OAAO,OAAO,CAAC,MAAM,CACnB,IAAI,KAAK,CAAC,gGAAgG,CAAC,CAC5G,CAAA;QACH,CAAC;QACD,OAAO,yBAAyB,CAAC,yBAAyB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,CAAA;IAChF,CAAC;IACD,4BAA4B,EAAE,gBAAgB,CAAC,8BAA8B,CAAC;IAC9E,YAAY,EAAE,gBAAgB,CAAC,cAAc,CAAC;IAC9C,kBAAkB,EAAE,gBAAgB,CAAC,oBAAoB,CAAC;IAC1D,oBAAoB,EAAE,gBAAgB,CAAC,sBAAsB,CAAC;IAC9D,wBAAwB,EAAE,gBAAgB,CAAC,0BAA0B,CAAC;IACtE,qBAAqB,EAAE,gBAAgB,CAAC,uBAAuB,CAAC;IAChE,kBAAkB,EAAE,gBAAgB,CAAC,oBAAoB,CAAC;IAC1D,YAAY,EAAE,gBAAgB,CAAC,cAAc,CAAC;IAC9C,YAAY,EAAE,gBAAgB,CAAC,cAAc,CAAC;IAC9C,gBAAgB,EAAE,gBAAgB,CAAC,kBAAkB,CAAC;IACtD,mBAAmB,EAAE,gBAAgB,CAAC,qBAAqB,CAAC;IAC5D,kBAAkB,EAAE,gBAAgB,CAAC,oBAAoB,CAAC;IAC1D,WAAW,EAAE,gBAAgB,CAAC,aAAa,CAAC;IAC5C,UAAU,EAAE,gBAAgB,CAAC,YAAY,CAAC;IAC1C,WAAW,EAAE,gBAAgB,CAAC,aAAa,CAAC;IAC5C,eAAe,EAAE,gBAAgB,CAAC,iBAAiB,CAAC;IACpD,qBAAqB,EAAE,gBAAgB,CAAC,uBAAuB,CAAC;IAChE,qBAAqB,EAAE,gBAAgB,CAAC,uBAAuB,CAAC;IAChE,qBAAqB,EAAE,gBAAgB,CAAC,uBAAuB,CAAC;IAChE,aAAa,EAAE,gBAAgB,CAAC,eAAe,CAAC;IAChD,kBAAkB,EAAE,gBAAgB,CAAC,oBAAoB,CAAC;IAC1D,iBAAiB,EAAE,gBAAgB,CAAC,mBAAmB,CAAC;IACxD,cAAc;IACd,oBAAoB,EAAE,gBAAgB,CAAC,sBAAsB,CAAC;IAC9D,aAAa,EAAE,gBAAgB,CAAC,eAAe,CAAC;IAChD,oBAAoB,EAAE,gBAAgB,CAAC,sBAAsB,CAAC;IAC9D,qBAAqB,EAAE,gBAAgB,CAAC,uBAAuB,CAAC;IAChE,kBAAkB,EAAE,gBAAgB,CAAC,oBAAoB,CAAC;IAC1D,eAAe,EAAE,gBAAgB,CAAC,iBAAiB,CAAC;IACpD,sBAAsB,EAAE,gBAAgB,CAAC,wBAAwB,CAAC;IAClE,gBAAgB,EAAE,gBAAgB,CAAC,kBAAkB,CAAC;IACtD,aAAa,EAAE,gBAAgB,CAAC,eAAe,CAAC;IAChD,kBAAkB,EAAE,gBAAgB,CAAC,oBAAoB,CAAC;IAC1D,kBAAkB,EAAE,gBAAgB,CAAC,oBAAoB,CAAC;IAC1D,eAAe,EAAE,gBAAgB,CAAC,iBAAiB,CAAC;IACpD,mBAAmB,EAAE,gBAAgB,CAAC,qBAAqB,CAAC;IAC5D,sBAAsB,EAAE,gBAAgB,CAAC,wBAAwB,CAAC;IAClE,gBAAgB,EAAE,gBAAgB,CAAC,kBAAkB,CAAC;IACtD,gBAAgB,EAAE,gBAAgB,CAAC,kBAAkB,CAAC;CACvD,CAAC,CAAA;AAEF,eAAe,YAAY,CAAA;AAE3B,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,cAAc,EACd,YAAY,EACZ,6BAA6B,EAC7B,kCAAkC,EAClC,qBAAqB,EACrB,sBAAsB,EACtB,8BAA8B,GAC/B,MAAM,sBAAsB,CAAA","sourcesContent":["import PrivateBluetoothSdkModule from \"./_private/BluetoothSdkModule\"\nimport type {\n BluetoothSdkEventListener,\n BluetoothSdkEventName,\n BluetoothSdkPublicModule,\n VideoRecordingDefaults,\n} from \"./BluetoothSdk.types\"\n\nconst PUBLIC_EVENT_NAMES = new Set<BluetoothSdkEventName>([\n \"log\",\n \"device_discovered\",\n \"default_device_changed\",\n \"glasses_not_ready\",\n \"button_press\",\n \"touch_event\",\n \"accel_event\",\n \"head_up\",\n \"voice_activity_detection_status\",\n \"speaking_status\",\n \"battery_status\",\n \"local_transcription\",\n \"wifi_status_change\",\n \"wifi_scan_result\",\n \"hotspot_status_change\",\n \"hotspot_error\",\n \"photo_response\",\n \"photo_status\",\n \"camera_status\",\n \"video_recording_status\",\n \"media_success\",\n \"media_error\",\n \"gallery_status\",\n \"compatible_glasses_search_stop\",\n \"swipe_volume_status\",\n \"switch_status\",\n \"rgb_led_control_response\",\n \"settings_ack\",\n \"pair_failure\",\n \"audio_pairing_needed\",\n \"audio_connected\",\n \"audio_disconnected\",\n \"mic_pcm\",\n \"mic_lc3\",\n \"stream_status\",\n \"ota_start_ack\",\n \"ota_status\",\n \"ar99_ota_status\",\n \"version_info\",\n \"extraction_progress\",\n])\n\nconst addListener: BluetoothSdkPublicModule[\"addListener\"] = (eventName, listener) => {\n if (!PUBLIC_EVENT_NAMES.has(eventName)) {\n throw new Error(`Unsupported BluetoothSdk event \"${eventName}\". Use @mentra/bluetooth-sdk/react for status state.`)\n }\n return PrivateBluetoothSdkModule.addListener(eventName, listener as BluetoothSdkEventListener<BluetoothSdkEventName>)\n}\n\nconst startOtaUpdate: BluetoothSdkPublicModule[\"startOtaUpdate\"] = () => {\n return PrivateBluetoothSdkModule.startOtaUpdate()\n}\n\nconst bindPublicMethod = <K extends keyof BluetoothSdkPublicModule>(name: K): BluetoothSdkPublicModule[K] => {\n const method = (PrivateBluetoothSdkModule as unknown as Record<string, unknown>)[name]\n if (typeof method === \"function\") {\n return method.bind(PrivateBluetoothSdkModule) as BluetoothSdkPublicModule[K]\n }\n\n return (async () => {\n throw new Error(`BluetoothSdk.${String(name)} is not available in this native build. Rebuild the app.`)\n }) as unknown as BluetoothSdkPublicModule[K]\n}\n\nexport const BluetoothSdk: BluetoothSdkPublicModule = Object.freeze({\n addListener,\n getDefaultDevice: bindPublicMethod(\"getDefaultDevice\"),\n setDefaultDevice: bindPublicMethod(\"setDefaultDevice\"),\n clearDefaultDevice: bindPublicMethod(\"clearDefaultDevice\"),\n startScan: bindPublicMethod(\"startScan\"),\n stopScan: bindPublicMethod(\"stopScan\"),\n scan: bindPublicMethod(\"scan\") as BluetoothSdkPublicModule[\"scan\"],\n connect: bindPublicMethod(\"connect\"),\n connectDefault: bindPublicMethod(\"connectDefault\"),\n cancelConnectionAttempt: bindPublicMethod(\"cancelConnectionAttempt\"),\n disconnect: bindPublicMethod(\"disconnect\"),\n forget: bindPublicMethod(\"forget\"),\n displayText: bindPublicMethod(\"displayText\"),\n clearDisplay: bindPublicMethod(\"clearDisplay\"),\n showDashboard: bindPublicMethod(\"showDashboard\"),\n setDashboardPosition: bindPublicMethod(\"setDashboardPosition\"),\n setHeadUpAngle: bindPublicMethod(\"setHeadUpAngle\"),\n setImuEnabled: bindPublicMethod(\"setImuEnabled\"),\n setScreenDisabled: bindPublicMethod(\"setScreenDisabled\"),\n requestWifiScan: bindPublicMethod(\"requestWifiScan\"),\n sendWifiCredentials: bindPublicMethod(\"sendWifiCredentials\"),\n forgetWifiNetwork: bindPublicMethod(\"forgetWifiNetwork\"),\n setHotspotState: bindPublicMethod(\"setHotspotState\"),\n setGalleryModeEnabled: bindPublicMethod(\"setGalleryModeEnabled\"),\n setVoiceActivityDetectionEnabled: bindPublicMethod(\"setVoiceActivityDetectionEnabled\"),\n setLoudnessGateEnabled: bindPublicMethod(\"setLoudnessGateEnabled\"),\n /**\n * @deprecated Sticky action-button photo presets are deprecated. Prefer per-request\n * `requestPhoto(...)` options (e.g. `mode: \"text\"` for text sensor size/crop, or explicit per-shot\n * fields). Still functional until removed in a future release.\n */\n setPhotoCaptureDefaults: bindPublicMethod(\"setPhotoCaptureDefaults\"),\n setVideoRecordingDefaults: ({width, height, fps}: VideoRecordingDefaults) => {\n const method = (PrivateBluetoothSdkModule as unknown as Record<string, unknown>).setVideoRecordingDefaults\n if (typeof method !== \"function\") {\n return Promise.reject(\n new Error(\"BluetoothSdk.setVideoRecordingDefaults is not available in this native build. Rebuild the app.\"),\n )\n }\n return PrivateBluetoothSdkModule.setVideoRecordingDefaults(width, height, fps)\n },\n setMaxVideoRecordingDuration: bindPublicMethod(\"setMaxVideoRecordingDuration\"),\n setCameraFov: bindPublicMethod(\"setCameraFov\"),\n setLegacyCameraFov: bindPublicMethod(\"setLegacyCameraFov\"),\n setCameraFovOverride: bindPublicMethod(\"setCameraFovOverride\"),\n releaseCameraFovOverride: bindPublicMethod(\"releaseCameraFovOverride\"),\n setCameraTuningConfig: bindPublicMethod(\"setCameraTuningConfig\"),\n queryGalleryStatus: bindPublicMethod(\"queryGalleryStatus\"),\n requestPhoto: bindPublicMethod(\"requestPhoto\"),\n warmUpCamera: bindPublicMethod(\"warmUpCamera\"),\n stopCameraWarmUp: bindPublicMethod(\"stopCameraWarmUp\"),\n startVideoRecording: bindPublicMethod(\"startVideoRecording\"),\n stopVideoRecording: bindPublicMethod(\"stopVideoRecording\"),\n startStream: bindPublicMethod(\"startStream\"),\n stopStream: bindPublicMethod(\"stopStream\"),\n setMicState: bindPublicMethod(\"setMicState\"),\n setPreferredMic: bindPublicMethod(\"setPreferredMic\"),\n setOwnAppAudioPlaying: bindPublicMethod(\"setOwnAppAudioPlaying\"),\n getGlassesMediaVolume: bindPublicMethod(\"getGlassesMediaVolume\"),\n setGlassesMediaVolume: bindPublicMethod(\"setGlassesMediaVolume\"),\n rgbLedControl: bindPublicMethod(\"rgbLedControl\"),\n requestVersionInfo: bindPublicMethod(\"requestVersionInfo\"),\n checkForOtaUpdate: bindPublicMethod(\"checkForOtaUpdate\"),\n startOtaUpdate,\n startAr99OtaFromFile: bindPublicMethod(\"startAr99OtaFromFile\"),\n cancelAr99Ota: bindPublicMethod(\"cancelAr99Ota\"),\n sendAr99FactoryReset: bindPublicMethod(\"sendAr99FactoryReset\"),\n buildAr99OtaSignature: bindPublicMethod(\"buildAr99OtaSignature\"),\n setSttModelDetails: bindPublicMethod(\"setSttModelDetails\"),\n getSttModelPath: bindPublicMethod(\"getSttModelPath\"),\n checkSttModelAvailable: bindPublicMethod(\"checkSttModelAvailable\"),\n validateSttModel: bindPublicMethod(\"validateSttModel\"),\n extractTarBz2: bindPublicMethod(\"extractTarBz2\"),\n restartTranscriber: bindPublicMethod(\"restartTranscriber\"),\n setTtsModelDetails: bindPublicMethod(\"setTtsModelDetails\"),\n getTtsModelPath: bindPublicMethod(\"getTtsModelPath\"),\n getTtsModelLanguage: bindPublicMethod(\"getTtsModelLanguage\"),\n checkTtsModelAvailable: bindPublicMethod(\"checkTtsModelAvailable\"),\n validateTtsModel: bindPublicMethod(\"validateTtsModel\"),\n generateTtsAudio: bindPublicMethod(\"generateTtsAudio\"),\n})\n\nexport default BluetoothSdk\n\nexport {\n CAMERA_FOV_DEFAULT,\n CAMERA_FOV_MAX,\n CAMERA_FOV_MIN,\n DeviceModels,\n isBusyGlassesConnectionStatus,\n isConnectedGlassesConnectionStatus,\n isConnectedWifiStatus,\n isEnabledHotspotStatus,\n isReadyGlassesConnectionStatus,\n} from \"./BluetoothSdk.types\"\n\nexport type {\n AccelEvent,\n Ar99OtaStatusEvent,\n AudioConnectedEvent,\n AudioDisconnectedEvent,\n AudioPairingNeededEvent,\n BatteryStatusEvent,\n BluetoothSdkEvent,\n BluetoothSdkEventListener,\n BluetoothSdkEventMap,\n BluetoothSdkEventName,\n BluetoothSdkPublicModule as BluetoothSdkModule,\n BluetoothSdkSubscription,\n ButtonPhotoSize,\n PhotoCaptureDefaults,\n ButtonPressEvent,\n CameraFovPreset,\n CameraFovRequest,\n CameraFovResult,\n CameraRoiPosition,\n CompatibleGlassesSearchStopEvent,\n ConnectOptions,\n ConnectedGlassesConnectionStatus,\n ConnectedWifiStatus,\n Device,\n DeviceModel,\n EnabledHotspotStatus,\n GalleryStatusEvent,\n GlassesConnectionStatus,\n GlassesMediaVolumeGetResult,\n GlassesMediaVolumeSetResult,\n GlassesNotReadyEvent,\n HeadUpEvent,\n HotspotErrorEvent,\n HotspotStatus,\n HotspotStatusChangeEvent,\n LocalTranscriptionEvent,\n LogEvent,\n MicLc3Event,\n MicMode,\n MicPcmEvent,\n MicPreference,\n OtaStartAckEvent,\n OtaStatus,\n OtaStatusEvent,\n OtaQueryResult,\n PairFailureEvent,\n PhotoCaptureMetadata,\n PhotoResolvedConfig,\n PhotoCompression,\n PhotoFpsRange,\n PhotoMeteredPreview,\n PhotoMode,\n PhotoTransferMethod,\n PhotoResponseEvent,\n PhotoRequestedCaptureConfig,\n PhotoRequestParams,\n PhotoSize,\n PhotoStatusEvent,\n PhotoStatusState,\n PhotoSuccessResponseEvent,\n RgbLedAction,\n RgbLedColor,\n RgbLedControlResponseEvent,\n RgbLedControlSuccessResponseEvent,\n ScanModelOptions,\n ScanOptions,\n ScanResultsCallback,\n SpeakingStatusEvent,\n SettingsAckEvent,\n SettingsAckSetting,\n SettingsAckSuccessEvent,\n SettingsAckSuccessStatus,\n SettingsAckStatus,\n StreamAudioConfig,\n StreamResolvedConfig,\n StreamStartRequest,\n StreamStatusEvent,\n StreamStatusLifecycleState,\n StreamStatusReconnectState,\n StreamStatusState,\n StreamVideoConfig,\n SwipeVolumeStatusEvent,\n SwitchStatusEvent,\n TouchEvent,\n VideoRecordingDefaults,\n VideoRecordingStartedStatusEvent,\n VideoRecordingStatusEvent,\n VideoRecordingStatusState,\n VideoRecordingStoppedStatusEvent,\n VideoRecordingSuccessStatusEvent,\n VersionInfoEvent,\n VersionInfoResult,\n WifiScanResultEvent,\n VoiceActivityDetectionStatusEvent,\n WifiSearchResult,\n WifiStatus,\n WifiStatusChangeEvent,\n} from \"./BluetoothSdk.types\"\n"]}
@@ -1,3 +1,4 @@
1
+ import CryptoKit
1
2
  import ExpoModulesCore
2
3
  import Foundation
3
4
 
@@ -59,9 +60,11 @@ public class BluetoothSdkModule: Module, MentraBluetoothSDKDelegate {
59
60
  "stream_status",
60
61
  "keep_alive_ack",
61
62
  "mtk_update_complete",
63
+ "glasses_session_changed",
62
64
  "ota_progress",
63
65
  "ota_start_ack",
64
66
  "ota_status",
67
+ "ar99_ota_status",
65
68
  "send_command_to_ble",
66
69
  "receive_command_from_ble",
67
70
  "miniapp_selected",
@@ -329,6 +332,11 @@ public class BluetoothSdkModule: Module, MentraBluetoothSDKDelegate {
329
332
  try await sdk.setVoiceActivityDetectionEnabled(enabled)
330
333
  }
331
334
 
335
+ AsyncFunction("setLoudnessGateEnabled") { (enabled: Bool) in
336
+ let sdk = await MainActor.run { self.bluetoothSdk() }
337
+ try await sdk.setLoudnessGateEnabled(enabled)
338
+ }
339
+
332
340
  AsyncFunction("setPhotoCaptureDefaults") { (params: [String: Any]) in
333
341
  let sdk = await MainActor.run { self.bluetoothSdk() }
334
342
  return try await sdk.setPhotoCaptureDefaults(PhotoCaptureDefaults.from(params: params)).values
@@ -400,7 +408,7 @@ public class BluetoothSdkModule: Module, MentraBluetoothSDKDelegate {
400
408
  }
401
409
 
402
410
  AsyncFunction("requestPhoto") { (params: [String: Any]) in
403
- let req = PhotoRequest.from(params: params)
411
+ let req = try PhotoRequest.from(params: params)
404
412
  Bridge.log(
405
413
  "NATIVE: PHOTO PIPELINE [3/6] BluetoothSdk.requestPhoto requestId=\(req.requestId) size=\(req.size.rawValue) compress=\(req.compress?.rawValue ?? "none") aeDivisor=\(req.aeExposureDivisor.map { String($0) } ?? "nil")"
406
414
  )
@@ -428,6 +436,8 @@ public class BluetoothSdkModule: Module, MentraBluetoothSDKDelegate {
428
436
  }
429
437
  let durationRaw = intValue(params["durationMs"]) ?? 0
430
438
  let durationMs = durationRaw > 0 ? durationRaw : 15000
439
+ let zsl = params["zsl"] as? Bool
440
+ let mfnr = params["mfnr"] as? Bool
431
441
 
432
442
  let sdk = await MainActor.run { self.bluetoothSdk() }
433
443
  return try await sdk.warmUpCamera(
@@ -435,7 +445,9 @@ public class BluetoothSdkModule: Module, MentraBluetoothSDKDelegate {
435
445
  size: size,
436
446
  mode: mode,
437
447
  exposureTimeNs: exposureTimeNs,
438
- durationMs: durationMs
448
+ durationMs: durationMs,
449
+ zsl: zsl,
450
+ mfnr: mfnr
439
451
  ).values
440
452
  }
441
453
 
@@ -478,6 +490,27 @@ public class BluetoothSdkModule: Module, MentraBluetoothSDKDelegate {
478
490
  return try await sdk.sendOtaQueryStatus().values
479
491
  }
480
492
 
493
+ AsyncFunction("startAr99OtaFromFile") { (path: String) in
494
+ let sdk = await MainActor.run { self.bluetoothSdk() }
495
+ return try await MainActor.run { try sdk.startAr99OtaFromFile(path) }
496
+ }
497
+
498
+ AsyncFunction("cancelAr99Ota") {
499
+ let sdk = await MainActor.run { self.bluetoothSdk() }
500
+ await MainActor.run { sdk.cancelAr99Ota() }
501
+ }
502
+
503
+ AsyncFunction("sendAr99FactoryReset") {
504
+ let sdk = await MainActor.run { self.bluetoothSdk() }
505
+ try await MainActor.run { try sdk.sendAr99FactoryReset() }
506
+ }
507
+
508
+
509
+ Function("buildAr99OtaSignature") { (secret: String, appName: String, currentVersion: String, serialNumber: String, nonce: String) in
510
+ let raw = secret + appName + "juxinOTA" + currentVersion + serialNumber.trimmingCharacters(in: .whitespacesAndNewlines) + nonce
511
+ let digest = Insecure.MD5.hash(data: Data(raw.utf8))
512
+ return digest.map { String(format: "%02x", $0) }.joined()
513
+ }
481
514
  // MARK: - Version Info Commands
482
515
 
483
516
  AsyncFunction("requestVersionInfo") {
@@ -884,3 +917,9 @@ private extension ConnectOptions {
884
917
  )
885
918
  }
886
919
  }
920
+
921
+
922
+
923
+
924
+
925
+
@@ -7,7 +7,8 @@ enum BluetoothSdkDefaults {
7
7
  }
8
8
 
9
9
  static let voiceActivityDetectionEnabled = false
10
- private static let swiftPackageSdkVersion = "0.1.21-beta.0"
10
+ static let loudnessGateEnabled = true
11
+ private static let swiftPackageSdkVersion = "0.1.21-beta.2"
11
12
  private static let swiftPackageSdkVersionPlaceholder = "__MENTRA" + "_BLUETOOTH_SDK_VERSION__"
12
13
 
13
14
  private static func normalizedSdkVersion(_ value: String?) -> String? {
@@ -177,12 +177,15 @@ class Bridge {
177
177
  _ deviceModel: String,
178
178
  _ deviceName: String,
179
179
  deviceAddress: String = "",
180
- rssi: Int? = nil
180
+ rssi: Int? = nil,
181
+ projectName: String? = nil
181
182
  ) {
182
183
  Task {
183
184
  await MainActor.run {
184
185
  let searchResults = DeviceStore.shared.get("bluetooth", "searchResults") as? [[String: Any]] ?? []
185
- let id = "\(deviceModel):\(deviceName)"
186
+ let id = [deviceModel, projectName?.isEmpty == false ? projectName! : nil, deviceName]
187
+ .compactMap { $0 }
188
+ .joined(separator: ":")
186
189
  var newResult: [String: Any] = [
187
190
  "id": id,
188
191
  "model": deviceModel,
@@ -191,6 +194,9 @@ class Bridge {
191
194
  if !deviceAddress.isEmpty {
192
195
  newResult["address"] = deviceAddress
193
196
  }
197
+ if let projectName, !projectName.isEmpty {
198
+ newResult["projectName"] = projectName
199
+ }
194
200
  if let rssi {
195
201
  newResult["rssi"] = rssi
196
202
  }
@@ -495,7 +501,7 @@ class Bridge {
495
501
  Bridge.sendTypedMessage("mtk_update_complete", body: eventBody)
496
502
  }
497
503
 
498
- /// Send ota_start_ack — glasses confirmed receipt of ota_start command
504
+ /// Send ota_start_ack —glasses confirmed receipt of ota_start command
499
505
  static func sendOtaStartAck() {
500
506
  let eventBody: [String: Any] = [
501
507
  "timestamp": Int64(Date().timeIntervalSince1970 * 1000),
@@ -607,3 +613,9 @@ class Bridge {
607
613
  return payload
608
614
  }
609
615
  }
616
+
617
+
618
+
619
+
620
+
621
+
@@ -22,7 +22,7 @@ struct ViewState {
22
22
  var text: String
23
23
  var data: String?
24
24
  var animationData: [String: Any]?
25
- // Optional container position/size used by bitmap_view and positioned_text (G2; ignored by others)
25
+ // Optional container position/size - used by bitmap_view and positioned_text (G2; ignored by others)
26
26
  var bmpX: Int32? = nil
27
27
  var bmpY: Int32? = nil
28
28
  var bmpWidth: Int32? = nil
@@ -76,7 +76,7 @@ struct ViewState {
76
76
 
77
77
  if isPaired {
78
78
  // Device is paired! Don't activate it - let PhoneMic.swift activate when recording starts
79
- Bridge.log("Audio: Mentra Live is paired (preserving A2DP for music)")
79
+ Bridge.log("Audio: Mentra Live is paired (preserving A2DP for music)")
80
80
  glassesBluetoothClassicConnected = true
81
81
  } else {
82
82
  glassesBluetoothClassicConnected = false
@@ -88,7 +88,7 @@ struct ViewState {
88
88
  guard let self = self else { return }
89
89
 
90
90
  if connected {
91
- Bridge.log("Audio: Device paired and connected")
91
+ Bridge.log("Audio: Device paired and connected")
92
92
  // Don't activate - let PhoneMic.swift handle that when recording starts
93
93
  self.glassesBluetoothClassicConnected = true
94
94
  } else {
@@ -320,7 +320,7 @@ struct ViewState {
320
320
  ),
321
321
  ]
322
322
 
323
- // Scene slots one whole SceneFrame per view (main/dashboard), parallel to
323
+ // Scene slots - one whole SceneFrame per view (main/dashboard), parallel to
324
324
  // viewStates. When a slot holds a scene, viewStates carries a "scene"
325
325
  // sentinel so sendCurrentState routes here. Holding the WHOLE frame keeps
326
326
  // native re-dispatch coherent (dashboard exit re-applies a complete scene).
@@ -417,6 +417,10 @@ struct ViewState {
417
417
  handlePcm(pcmData)
418
418
  }
419
419
 
420
+ func reportGlassesAudioActivity() {
421
+ lastLc3Event = Date()
422
+ }
423
+
420
424
  func handlePcm(_ pcmData: Data) {
421
425
  handleSendingPcm(pcmData)
422
426
 
@@ -626,6 +630,8 @@ struct ViewState {
626
630
  sgc = MentraLive()
627
631
  } else if wearable.contains(DeviceTypes.NIMO) {
628
632
  sgc = Nimo()
633
+ } else if wearable.contains(DeviceTypes.AR99) {
634
+ sgc = Ar99()
629
635
  } else if wearable.contains(DeviceTypes.FRAME) {
630
636
  // sgc = FrameManager()
631
637
  }
@@ -722,7 +728,7 @@ struct ViewState {
722
728
  )
723
729
  case "positioned_text":
724
730
  Bridge.log(
725
- "MAN: positioned_text text='\(currentViewState.text)' rect=\(currentViewState.bmpX ?? 0),\(currentViewState.bmpY ?? 0) \(currentViewState.bmpWidth ?? 576)x\(currentViewState.bmpHeight ?? 288)"
731
+ "MAN: positioned_text -> text='\(currentViewState.text)' rect=\(currentViewState.bmpX ?? 0),\(currentViewState.bmpY ?? 0) \(currentViewState.bmpWidth ?? 576)x\(currentViewState.bmpHeight ?? 288)"
726
732
  )
727
733
  await sgc?.sendPositionedText(
728
734
  currentViewState.text,
@@ -804,6 +810,11 @@ struct ViewState {
804
810
  return
805
811
  }
806
812
 
813
+ if PhoneAudioMonitor.getInstance().isOwnAppAudioPlaying() {
814
+ Bridge.log("MAN: Mentra audio is playing; skipping glasses mic recovery")
815
+ return
816
+ }
817
+
807
818
  let timeSinceLastLc3Event = Date().timeIntervalSince(lastLc3Event ?? Date())
808
819
  if timeSinceLastLc3Event > 5 {
809
820
  Bridge.log("MAN: No audio activity in the last 5 seconds from glasses, reinitializing glasses mic")
@@ -861,7 +872,7 @@ struct ViewState {
861
872
  let deviceName = session.availableInputs?.first(where: {
862
873
  $0.portName.localizedCaseInsensitiveContains(audioDevicePattern)
863
874
  })?.portName
864
- Bridge.log("MAN: Successfully detected newly paired device '\(deviceName)'")
875
+ Bridge.log("MAN: Successfully detected newly paired device '\(deviceName)'")
865
876
  glassesBluetoothClassicConnected = true
866
877
  } else {
867
878
  glassesBluetoothClassicConnected = false
@@ -928,7 +939,7 @@ struct ViewState {
928
939
  // stale/torn-down connection.
929
940
  guard let sgc = self?.sgc else { return }
930
941
  let h = DeviceStore.shared.get("bluetooth", "dashboard_height") as? Int ?? 4
931
- // Fall back to the canonical default (2), matching DeviceStore not 1.
942
+ // Fall back to the canonical default (2), matching DeviceStore, not 1.
932
943
  let rawDepth = DeviceStore.shared.get("bluetooth", "dashboard_depth") as? Int ?? 2
933
944
  let d = min(max(rawDepth, 1), 4)
934
945
  sgc.setDashboardPosition(h, d)
@@ -962,6 +973,10 @@ struct ViewState {
962
973
  Bridge.saveSetting("default_wearable", defaultWearable)
963
974
  Bridge.saveSetting("device_name", deviceName)
964
975
  Bridge.saveSetting("device_address", deviceAddress)
976
+ if defaultWearable.contains(DeviceTypes.AR99) {
977
+ let projectName = (DeviceStore.shared.get("bluetooth", "project_name") as? String)?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
978
+ Bridge.saveSetting("project_name", projectName)
979
+ }
965
980
 
966
981
  }
967
982
 
@@ -1168,7 +1183,7 @@ struct ViewState {
1168
1183
  // Legacy→scene handoff: stale legacy content (e.g. a cloud app's
1169
1184
  // text wall) must not linger under the scene's elements.
1170
1185
  // clearDisplay is the per-device "wipe what's there" (blank-in-place
1171
- // on G2 no page rebuild).
1186
+ // on G2 - no page rebuild).
1172
1187
  let prevLegacyType = viewStates[stateIndex].layoutType
1173
1188
  if !prevLegacyType.isEmpty, prevLegacyType != "clear_view", prevLegacyType != "scene" {
1174
1189
  sgc?.clearDisplay()
@@ -1187,7 +1202,7 @@ struct ViewState {
1187
1202
  }
1188
1203
 
1189
1204
  // Store the REDISPATCH form: any later sendCurrentState (dashboard
1190
- // exit, head-up return) must repaint the whole frame the original
1205
+ // exit, head-up return) must repaint the whole frame - the original
1191
1206
  // annotations are only valid for the first dispatch right now.
1192
1207
  sceneStates[stateIndex] = frame.asReplay()
1193
1208
  viewStates[stateIndex] = ViewState(
@@ -1201,7 +1216,7 @@ struct ViewState {
1201
1216
  }
1202
1217
  }
1203
1218
 
1204
- /// Guarded scene dispatch mirrors sendCurrentState's send conditions.
1219
+ /// Guarded scene dispatch - mirrors sendCurrentState's send conditions.
1205
1220
  private func dispatchSceneFrame(_ frame: SceneFrame) {
1206
1221
  if screenDisabled { return }
1207
1222
  if sgc?.type.contains(DeviceTypes.SIMULATED) ?? true { return }
@@ -1330,6 +1345,24 @@ struct ViewState {
1330
1345
  (sgc as? MentraLive)?.sendOtaQueryStatus()
1331
1346
  }
1332
1347
 
1348
+ func startAr99OtaFromFile(_ path: String) throws -> Bool {
1349
+ guard let ar99 = sgc as? Ar99 else {
1350
+ throw BluetoothSdkError(code: "unsupported_device", message: "This command requires AR99 glasses.")
1351
+ }
1352
+ return ar99.startOtaFromFile(path)
1353
+ }
1354
+
1355
+ func cancelAr99Ota() {
1356
+ (sgc as? Ar99)?.cancelAr99Ota()
1357
+ }
1358
+
1359
+ func sendAr99FactoryReset() throws {
1360
+ guard let ar99 = sgc as? Ar99 else {
1361
+ throw BluetoothSdkError(code: "unsupported_device", message: "This command requires AR99 glasses.")
1362
+ }
1363
+ ar99.sendFactoryReset()
1364
+ }
1365
+
1333
1366
  private func liveSgc() throws -> MentraLive {
1334
1367
  guard let live = sgc as? MentraLive else {
1335
1368
  throw BluetoothSdkError(code: "unsupported_device", message: "This command requires Mentra Live glasses.")
@@ -1409,7 +1442,9 @@ struct ViewState {
1409
1442
  size: PhotoSize,
1410
1443
  mode: PhotoMode = .photo,
1411
1444
  exposureTimeNs: Double?,
1412
- durationMs: Int
1445
+ durationMs: Int,
1446
+ zsl: Bool? = nil,
1447
+ mfnr: Bool? = nil
1413
1448
  ) throws {
1414
1449
  guard let live = sgc as? MentraLive else {
1415
1450
  // Fail fast like other camera commands so the SDK promise rejects immediately instead
@@ -1422,7 +1457,9 @@ struct ViewState {
1422
1457
  size: size,
1423
1458
  mode: mode,
1424
1459
  exposureTimeNs: exposureTimeNs,
1425
- durationMs: durationMs
1460
+ durationMs: durationMs,
1461
+ zsl: zsl,
1462
+ mfnr: mfnr
1426
1463
  )
1427
1464
  }
1428
1465
 
@@ -1498,7 +1535,7 @@ struct ViewState {
1498
1535
  )
1499
1536
  }
1500
1537
 
1501
- /// Mentra Live only: K900 `cs_getvol` / `sr_getvol` (step volume 0–15).
1538
+ /// Mentra Live only: K900 `cs_getvol` / `sr_getvol` (step volume 0-5).
1502
1539
  func getGlassesMediaVolume() async throws -> [String: Any] {
1503
1540
  guard let live = sgc as? MentraLive else {
1504
1541
  throw NSError(
@@ -1561,7 +1598,7 @@ struct ViewState {
1561
1598
  )
1562
1599
  guard let sgc else {
1563
1600
  Bridge.log(
1564
- "MAN: PHOTO PIPELINE sgc is null (glasses not connected); dropping requestId=\(routed.requestId)"
1601
+ "MAN: PHOTO PIPELINE - sgc is null (glasses not connected); dropping requestId=\(routed.requestId)"
1565
1602
  )
1566
1603
  return
1567
1604
  }
@@ -1573,13 +1610,19 @@ struct ViewState {
1573
1610
  Bridge.log("MAN: No default wearable, returning")
1574
1611
  return
1575
1612
  }
1576
- if deviceName.isEmpty {
1577
- Bridge.log("MAN: No device name, returning")
1613
+ let reconnectTarget =
1614
+ if defaultWearable.contains(DeviceTypes.AR99), !deviceAddress.isEmpty {
1615
+ deviceAddress
1616
+ } else {
1617
+ deviceName
1618
+ }
1619
+ if reconnectTarget.isEmpty {
1620
+ Bridge.log("MAN: No reconnect target, returning")
1578
1621
  return
1579
1622
  }
1580
1623
  initSGC(defaultWearable)
1581
1624
  searching = true
1582
- sgc?.connectById(deviceName)
1625
+ sgc?.connectById(reconnectTarget)
1583
1626
  connectDefaultController()
1584
1627
  }
1585
1628
 
@@ -1669,6 +1712,11 @@ struct ViewState {
1669
1712
  shouldSendBootingMessage = true // Reset for next first connect
1670
1713
  // clear glasses properties:
1671
1714
  DeviceStore.shared.apply("glasses", "deviceModel", "")
1715
+ // A manufacturing serial is session-bound. Clear it on every disconnect so a
1716
+ // previously connected pair's serial can never be reported for the next
1717
+ // connection (e.g. switching from G1/Ar99, which populate it from the
1718
+ // advertisement, to a model that never writes it, like G2).
1719
+ DeviceStore.shared.apply("glasses", "serialNumber", "")
1672
1720
  DeviceStore.shared.apply("glasses", "fullyBooted", false)
1673
1721
  DeviceStore.shared.apply("glasses", "connected", false)
1674
1722
  DeviceStore.shared.apply("glasses", "connectionState", ConnTypes.DISCONNECTED)
@@ -1700,6 +1748,7 @@ struct ViewState {
1700
1748
  Bridge.saveSetting("default_wearable", "")
1701
1749
  Bridge.saveSetting("device_name", "")
1702
1750
  Bridge.saveSetting("device_address", "")
1751
+ Bridge.saveSetting("project_name", "")
1703
1752
  }
1704
1753
 
1705
1754
  func forgetController() {
@@ -1758,3 +1807,4 @@ struct ViewState {
1758
1807
  cancellables.removeAll()
1759
1808
  }
1760
1809
  }
1810
+