@mentra/bluetooth-sdk 0.1.2 → 0.1.3

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 (59) hide show
  1. package/README.md +33 -19
  2. package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +13 -13
  3. package/android/src/main/java/com/mentra/bluetoothsdk/Bridge.kt +42 -18
  4. package/android/src/main/java/com/mentra/bluetoothsdk/DeviceManager.kt +19 -21
  5. package/android/src/main/java/com/mentra/bluetoothsdk/DeviceStore.kt +4 -4
  6. package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothModels.kt +118 -103
  7. package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +110 -38
  8. package/android/src/main/java/com/mentra/bluetoothsdk/controllers/ControllerManager.kt +4 -4
  9. package/android/src/main/java/com/mentra/bluetoothsdk/controllers/R1.kt +2 -2
  10. package/android/src/main/java/com/mentra/bluetoothsdk/services/PhoneMic.kt +6 -6
  11. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G1.java +1 -1
  12. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G2.kt +3 -3
  13. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Mach1.java +1 -1
  14. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.java +18 -18
  15. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraNex.kt +1 -1
  16. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/SGCManager.kt +4 -4
  17. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Simulated.kt +2 -2
  18. package/android/src/main/java/com/mentra/bluetoothsdk/utils/Constants.kt +6 -6
  19. package/build/BluetoothSdk.types.d.ts +126 -27
  20. package/build/BluetoothSdk.types.d.ts.map +1 -1
  21. package/build/BluetoothSdk.types.js.map +1 -1
  22. package/build/_internal.d.ts +12 -0
  23. package/build/_internal.d.ts.map +1 -0
  24. package/build/_internal.js +11 -0
  25. package/build/_internal.js.map +1 -0
  26. package/build/{BluetoothSdkModule.d.ts → _private/BluetoothSdkModule.d.ts} +19 -8
  27. package/build/_private/BluetoothSdkModule.d.ts.map +1 -0
  28. package/build/{BluetoothSdkModule.js → _private/BluetoothSdkModule.js} +41 -26
  29. package/build/_private/BluetoothSdkModule.js.map +1 -0
  30. package/build/index.d.ts +4 -2
  31. package/build/index.d.ts.map +1 -1
  32. package/build/index.js +3 -4
  33. package/build/index.js.map +1 -1
  34. package/ios/BluetoothSdkModule.swift +14 -9
  35. package/ios/Source/Bridge.swift +44 -12
  36. package/ios/Source/DeviceManager.swift +27 -26
  37. package/ios/Source/DeviceStore.swift +4 -4
  38. package/ios/Source/MentraBluetoothSDK.swift +250 -132
  39. package/ios/Source/controllers/ControllerManager.swift +5 -5
  40. package/ios/Source/controllers/R1.swift +3 -3
  41. package/ios/Source/services/PhoneMic.swift +5 -5
  42. package/ios/Source/sgcs/Frame.swift +1 -1
  43. package/ios/Source/sgcs/G1.swift +1 -1
  44. package/ios/Source/sgcs/G2.swift +3 -3
  45. package/ios/Source/sgcs/Mach1.swift +1 -1
  46. package/ios/Source/sgcs/MentraLive.swift +31 -33
  47. package/ios/Source/sgcs/MentraNex.swift +2 -2
  48. package/ios/Source/sgcs/SGCManager.swift +5 -5
  49. package/ios/Source/sgcs/Simulated.swift +3 -3
  50. package/ios/Source/utils/Constants.swift +6 -6
  51. package/ios/Source/utils/JSCExperiment.swift +8 -8
  52. package/ios/Source/utils/TarBz2Extractor.swift +2 -2
  53. package/package.json +13 -1
  54. package/src/BluetoothSdk.types.ts +186 -28
  55. package/src/_internal.ts +11 -0
  56. package/src/{BluetoothSdkModule.ts → _private/BluetoothSdkModule.ts} +71 -38
  57. package/src/index.ts +80 -4
  58. package/build/BluetoothSdkModule.d.ts.map +0 -1
  59. package/build/BluetoothSdkModule.js.map +0 -1
@@ -13,8 +13,8 @@ export type ButtonPressEvent = {
13
13
 
14
14
  export type TouchEvent = {
15
15
  type: "touch_event"
16
- device_model?: string
17
- gesture_name?: string
16
+ deviceModel: DeviceModel
17
+ gestureName: string
18
18
  timestamp: number
19
19
  }
20
20
 
@@ -67,7 +67,7 @@ export function createDisconnectedGlassesStatus(): Partial<GlassesStatus> {
67
67
 
68
68
  /** K900 `sr_getvol` response (Mentra Live glasses media step volume 0–15). */
69
69
  export type GlassesMediaVolumeGetResult = {
70
- vol: number
70
+ level: number
71
71
  statusCode: number
72
72
  }
73
73
 
@@ -112,7 +112,7 @@ export type HotspotStatusChangeEvent = HotspotStatus & {
112
112
 
113
113
  export type HotspotErrorEvent = {
114
114
  type: "hotspot_error"
115
- error_message: string
115
+ errorMessage: string
116
116
  timestamp: number
117
117
  }
118
118
 
@@ -121,7 +121,7 @@ export type PhotoResponseEvent =
121
121
  type: "photo_response"
122
122
  state: "success"
123
123
  requestId: string
124
- photoUrl: string
124
+ uploadUrl: string
125
125
  timestamp: number
126
126
  }
127
127
  | {
@@ -138,13 +138,14 @@ export type GalleryStatusEvent = {
138
138
  photos: number
139
139
  videos: number
140
140
  total: number
141
- has_content: boolean
142
- camera_busy: boolean
141
+ totalSize?: number
142
+ hasContent: boolean
143
+ cameraBusy: boolean
143
144
  }
144
145
 
145
146
  export type CompatibleGlassesSearchStopEvent = {
146
147
  type: "compatible_glasses_search_stop"
147
- device_model: DeviceModel
148
+ deviceModel: DeviceModel
148
149
  }
149
150
 
150
151
  export type HeartbeatSentEvent = {
@@ -169,9 +170,7 @@ export type SwipeVolumeStatusEvent = {
169
170
 
170
171
  export type SwitchStatusEvent = {
171
172
  type: "switch_status"
172
- switch_type?: number
173
173
  switchType?: number
174
- switch_value?: number
175
174
  switchValue?: number
176
175
  timestamp: number
177
176
  }
@@ -221,13 +220,11 @@ export type CameraFov = "standard" | "wide"
221
220
 
222
221
  export type CameraFovSetting = {
223
222
  fov: number
224
- roi_position: number
223
+ roiPosition: number
225
224
  }
226
225
 
227
226
  export type MicPreference = "auto" | "phone" | "glasses" | "bluetooth"
228
- export type MicMode = "phone" | "glasses" | "btclassic" | "bt"
229
- /** @deprecated Use {@link MicMode} for active/ranked mic modes or {@link MicPreference} for preferences. */
230
- export type MicRanking = MicMode
227
+ export type MicMode = "phone" | "glasses" | "bluetoothClassic" | "bluetooth"
231
228
 
232
229
  export type StreamVideoConfig = {
233
230
  width?: number
@@ -249,7 +246,6 @@ export type StreamStartRequest = {
249
246
  streamId?: string
250
247
  keepAlive?: boolean
251
248
  keepAliveIntervalSeconds?: number
252
- flash?: boolean
253
249
  sound?: boolean
254
250
  video?: StreamVideoConfig
255
251
  audio?: StreamAudioConfig
@@ -268,12 +264,12 @@ export type PairFailureEvent = {
268
264
 
269
265
  export type AudioPairingNeededEvent = {
270
266
  type: "audio_pairing_needed"
271
- device_name: string
267
+ deviceName: string
272
268
  }
273
269
 
274
270
  export type AudioConnectedEvent = {
275
271
  type: "audio_connected"
276
- device_name: string
272
+ deviceName: string
277
273
  }
278
274
 
279
275
  export type AudioDisconnectedEvent = {
@@ -427,8 +423,8 @@ export type MiniappSelectedEvent = {
427
423
  packageName: string
428
424
  }
429
425
 
430
- // Union type of all Bluetooth SDK events
431
- export type BluetoothSdkEvent = Parameters<BluetoothSdkModuleEvents[keyof BluetoothSdkModuleEvents]>[0]
426
+ // Union type of all native/internal Bluetooth SDK events.
427
+ export type BluetoothSdkInternalEvent = Parameters<BluetoothSdkModuleEvents[keyof BluetoothSdkModuleEvents]>[0]
432
428
 
433
429
  export type BluetoothSdkModuleEvents = {
434
430
  glasses_status: (changed: Partial<GlassesStatus>) => void
@@ -475,6 +471,153 @@ export type BluetoothSdkModuleEvents = {
475
471
  miniapp_selected: (event: MiniappSelectedEvent) => void
476
472
  }
477
473
 
474
+ export type PublicGlassesStatus = Omit<
475
+ GlassesStatus,
476
+ "otaUpdateAvailable" | "otaProgress" | "otaInProgress" | "otaVersionUrl"
477
+ >
478
+
479
+ export type PublicBluetoothStatus = Pick<
480
+ BluetoothStatus,
481
+ | "searching"
482
+ | "searchingController"
483
+ | "systemMicUnavailable"
484
+ | "micRanking"
485
+ | "currentMic"
486
+ | "searchResults"
487
+ | "wifiScanResults"
488
+ | "lastLog"
489
+ | "otherBtConnected"
490
+ | "galleryModeAuto"
491
+ >
492
+
493
+ export type BluetoothSdkEventMap = {
494
+ glasses_status: Partial<PublicGlassesStatus>
495
+ bluetooth_status: Partial<PublicBluetoothStatus>
496
+ log: LogEvent
497
+ device_discovered: Device
498
+ default_device_changed: {device?: Device}
499
+ glasses_not_ready: GlassesNotReadyEvent
500
+ button_press: ButtonPressEvent
501
+ touch_event: TouchEvent
502
+ head_up: HeadUpEvent
503
+ vad_status: VadStatusEvent
504
+ battery_status: BatteryStatusEvent
505
+ local_transcription: LocalTranscriptionEvent
506
+ wifi_status_change: WifiStatusChangeEvent
507
+ hotspot_status_change: HotspotStatusChangeEvent
508
+ hotspot_error: HotspotErrorEvent
509
+ photo_response: PhotoResponseEvent
510
+ gallery_status: GalleryStatusEvent
511
+ compatible_glasses_search_stop: CompatibleGlassesSearchStopEvent
512
+ swipe_volume_status: SwipeVolumeStatusEvent
513
+ switch_status: SwitchStatusEvent
514
+ rgb_led_control_response: RgbLedControlResponseEvent
515
+ pair_failure: PairFailureEvent
516
+ audio_pairing_needed: AudioPairingNeededEvent
517
+ audio_connected: AudioConnectedEvent
518
+ audio_disconnected: AudioDisconnectedEvent
519
+ mic_pcm: MicPcmEvent
520
+ mic_lc3: MicLc3Event
521
+ stream_status: StreamStatusEvent
522
+ keep_alive_ack: KeepAliveAckEvent
523
+ }
524
+
525
+ export type BluetoothSdkEventName = keyof BluetoothSdkEventMap
526
+
527
+ export type BluetoothSdkEventListener<EventName extends BluetoothSdkEventName> = (
528
+ event: BluetoothSdkEventMap[EventName],
529
+ ) => void
530
+
531
+ export type BluetoothSdkSubscription = {
532
+ remove(): void
533
+ }
534
+
535
+ export type BluetoothSdkEvent = BluetoothSdkEventMap[BluetoothSdkEventName]
536
+
537
+ export interface BluetoothSdkPublicModule {
538
+ addListener<EventName extends BluetoothSdkEventName>(
539
+ eventName: EventName,
540
+ listener: BluetoothSdkEventListener<EventName>,
541
+ ): BluetoothSdkSubscription
542
+
543
+ getGlassesStatus(): Promise<PublicGlassesStatus>
544
+ getBluetoothStatus(): Promise<PublicBluetoothStatus>
545
+ getDefaultDevice(): Promise<Device | null>
546
+ setDefaultDevice(device: Device | null): Promise<void>
547
+ clearDefaultDevice(): Promise<void>
548
+
549
+ startScan(model: DeviceModel): Promise<void>
550
+ stopScan(): Promise<void>
551
+ scan(options: ScanOptions): Promise<Device[]>
552
+ scan(model: DeviceModel, options?: ScanModelOptions): Promise<Device[]>
553
+ connect(device: Device, options?: ConnectOptions): Promise<void>
554
+ connectDefault(options?: ConnectOptions): Promise<void>
555
+ cancelConnectionAttempt(): Promise<void>
556
+ disconnect(): Promise<void>
557
+ forget(): Promise<void>
558
+
559
+ displayText(text: string, x?: number, y?: number, size?: number): Promise<void>
560
+ clearDisplay(): Promise<void>
561
+ showDashboard(): Promise<void>
562
+ setDashboardPosition(height: number, depth: number): Promise<void>
563
+ setHeadUpAngle(angleDegrees: number): Promise<void>
564
+ setScreenDisabled(disabled: boolean): Promise<void>
565
+
566
+ requestWifiScan(): Promise<void>
567
+ sendWifiCredentials(ssid: string, password: string): Promise<void>
568
+ forgetWifiNetwork(ssid: string): Promise<void>
569
+ setHotspotState(enabled: boolean): Promise<void>
570
+
571
+ setGalleryMode(mode: GalleryMode): Promise<void>
572
+ setButtonPhotoSettings(size: ButtonPhotoSize): Promise<void>
573
+ setButtonVideoRecordingSettings(width: number, height: number, frameRate: number): Promise<void>
574
+ setButtonCameraLed(enabled: boolean): Promise<void>
575
+ setButtonMaxRecordingTime(minutes: number): Promise<void>
576
+ setCameraFov(fov: CameraFov): Promise<void>
577
+ queryGalleryStatus(): Promise<void>
578
+ requestPhoto(
579
+ requestId: string,
580
+ appId: string,
581
+ size: PhotoSize,
582
+ webhookUrl: string | null,
583
+ authToken: string | null,
584
+ compress: PhotoCompression,
585
+ sound: boolean,
586
+ ): Promise<void>
587
+ startVideoRecording(requestId: string, save: boolean, sound: boolean): Promise<void>
588
+ stopVideoRecording(requestId: string): Promise<void>
589
+
590
+ startStream(params: StreamStartRequest): Promise<void>
591
+ stopStream(): Promise<void>
592
+ keepStreamAlive(params: StreamKeepAliveRequest): Promise<void>
593
+
594
+ setMicState(
595
+ enabled: boolean,
596
+ useGlassesMic?: boolean,
597
+ bypassVad?: boolean,
598
+ sendTranscript?: boolean,
599
+ sendLc3Data?: boolean,
600
+ ): Promise<void>
601
+ setPreferredMic(preferredMic: MicPreference): Promise<void>
602
+ setOwnAppAudioPlaying(playing: boolean): Promise<void>
603
+ getGlassesMediaVolume(): Promise<GlassesMediaVolumeGetResult>
604
+ setGlassesMediaVolume(level: number): Promise<GlassesMediaVolumeSetResult>
605
+
606
+ rgbLedControl(
607
+ requestId: string,
608
+ packageName: string | null,
609
+ action: RgbLedAction,
610
+ color: RgbLedColor | null,
611
+ onDurationMs: number,
612
+ offDurationMs: number,
613
+ count: number,
614
+ ): Promise<void>
615
+
616
+ requestVersionInfo(): Promise<void>
617
+ onGlassesStatus(callback: (changed: Partial<PublicGlassesStatus>) => void): () => void
618
+ onBluetoothStatus(callback: (changed: Partial<PublicBluetoothStatus>) => void): () => void
619
+ }
620
+
478
621
  // OTA update status types
479
622
  export type OtaStage = "download" | "install"
480
623
  export type OtaProgressStatus = "STARTED" | "PROGRESS" | "FINISHED" | "FAILED"
@@ -514,17 +657,17 @@ export interface GlassesStatus {
514
657
  // state:
515
658
  connection: GlassesConnectionStatus
516
659
  micEnabled: boolean
517
- btcConnected: boolean
660
+ bluetoothClassicConnected: boolean
518
661
  signalStrength: number
519
662
  /** Milliseconds since epoch when signalStrength was last refreshed by the phone BLE stack. */
520
663
  signalStrengthUpdatedAt: number
521
664
  // device info
522
665
  deviceModel: string
523
666
  androidVersion: string
524
- fwVersion: string
525
- besFwVersion: string
526
- mtkFwVersion: string
527
- btMacAddress: string
667
+ firmwareVersion: string
668
+ besFirmwareVersion: string
669
+ mtkFirmwareVersion: string
670
+ bluetoothMacAddress: string
528
671
  leftMacAddress: string
529
672
  rightMacAddress: string
530
673
  buildNumber: string
@@ -580,10 +723,20 @@ export interface ConnectOptions {
580
723
  cancelExistingConnectionAttempt?: boolean
581
724
  }
582
725
 
583
- export interface ConnectFirstOptions extends ConnectOptions {
726
+ export type ScanResultsCallback = (devices: Device[]) => void
727
+
728
+ export interface ScanOptions {
729
+ model: DeviceModel
730
+ /** Defaults to 15000. */
584
731
  timeoutMs?: number
732
+ /** Alias for `timeoutMs`, useful when mirroring native examples. */
733
+ timeout?: number
734
+ /** Called every time the discovered device list changes during the scan. */
735
+ onResults?: ScanResultsCallback
585
736
  }
586
737
 
738
+ export type ScanModelOptions = Omit<ScanOptions, "model">
739
+
587
740
  export interface WifiSearchResult {
588
741
  ssid: string
589
742
  requiresPassword: boolean
@@ -607,12 +760,17 @@ export interface BluetoothStatus {
607
760
  systemMicUnavailable: boolean
608
761
  micRanking: MicMode[]
609
762
  currentMic: MicMode | "" | null
763
+ /**
764
+ * Nearby glasses in stable discovery order.
765
+ * Existing entries keep their array position as details refresh; new glasses append at the end,
766
+ * and removals should not reorder remaining entries.
767
+ */
610
768
  searchResults: Device[]
611
769
  wifiScanResults: WifiSearchResult[]
612
770
  lastLog: string[]
613
771
  otherBtConnected: boolean
614
772
  // desired settings the SDK sends to compatible connected glasses:
615
- gallery_mode: boolean
773
+ galleryModeAuto: boolean
616
774
  }
617
775
 
618
776
  export type BluetoothSettingsUpdate = Partial<{
@@ -630,9 +788,9 @@ export type BluetoothSettingsUpdate = Partial<{
630
788
  dashboard_height: number
631
789
  dashboard_depth: number
632
790
  menu_apps: DashboardMenuItem[] | CoreDashboardMenuItem[] | Array<Record<string, unknown>> | null
633
- gallery_mode: boolean
791
+ galleryModeAuto: boolean
634
792
  button_photo_size: ButtonPhotoSize
635
- button_video_settings: {width: number; height: number; fps: number}
793
+ button_video_settings: {width: number; height: number; frameRate: number}
636
794
  button_video_width: number
637
795
  button_video_height: number
638
796
  button_video_fps: number
@@ -0,0 +1,11 @@
1
+ /**
2
+ * MentraOS-only compatibility entrypoint.
3
+ *
4
+ * Partner apps should import from `@mentra/bluetooth-sdk`. This file is not a
5
+ * package export; MentraOS resolves it through its local
6
+ * `@mentra/bluetooth-sdk-internal` alias while the app is migrated onto the
7
+ * public SDK surface.
8
+ */
9
+ export {default} from "./_private/BluetoothSdkModule"
10
+ export type {BluetoothSdkInternalModule} from "./_private/BluetoothSdkModule"
11
+ export * from "./BluetoothSdk.types"
@@ -2,12 +2,12 @@ import {NativeModule, requireNativeModule} from "expo"
2
2
 
3
3
  import {
4
4
  BluetoothSettingsUpdate,
5
+ BluetoothSdkPublicModule,
5
6
  BluetoothSdkModuleEvents,
6
7
  BluetoothStatus,
7
8
  ButtonPhotoSize,
8
9
  CameraFov,
9
10
  CameraFovSetting,
10
- ConnectFirstOptions,
11
11
  ConnectOptions,
12
12
  DashboardMenuItem,
13
13
  Device,
@@ -22,15 +22,25 @@ import {
22
22
  PhotoSize,
23
23
  RgbLedAction,
24
24
  RgbLedColor,
25
+ ScanModelOptions,
26
+ ScanOptions,
25
27
  StreamKeepAliveRequest,
26
28
  StreamStartRequest,
27
- } from "./BluetoothSdk.types"
29
+ } from "../BluetoothSdk.types"
30
+
31
+ /**
32
+ * Private React Native native-module facade.
33
+ *
34
+ * This file intentionally lives under `_private` so the package root can expose
35
+ * a small SDK surface while MentraOS uses its monorepo-only internal alias
36
+ * during migration.
37
+ */
28
38
 
29
39
  type GlassesListener = (changed: Partial<GlassesStatus>) => void
30
40
  type BluetoothStatusListener = (changed: Partial<BluetoothStatus>) => void
31
41
  type MaybePromise<T> = T | Promise<T>
32
42
 
33
- declare class BluetoothSdkModule extends NativeModule<BluetoothSdkModuleEvents> {
43
+ declare class BluetoothSdkNativeModule extends NativeModule<BluetoothSdkModuleEvents> {
34
44
  // Observable Store Functions (native)
35
45
  getGlassesStatus(): Promise<GlassesStatus>
36
46
  getBluetoothStatus(): Promise<BluetoothStatus>
@@ -49,7 +59,9 @@ declare class BluetoothSdkModule extends NativeModule<BluetoothSdkModuleEvents>
49
59
  setDefaultDevice(device: Device | null): Promise<void>
50
60
  clearDefaultDevice(): Promise<void>
51
61
  startScan(model: DeviceModel): Promise<void>
52
- connectFirst(model: DeviceModel, options?: ConnectFirstOptions): Promise<Device>
62
+ stopScan(): Promise<void>
63
+ scan(options: ScanOptions): Promise<Device[]>
64
+ scan(model: DeviceModel, options?: ScanModelOptions): Promise<Device[]>
53
65
  connect(device: Device, options?: ConnectOptions): Promise<void>
54
66
  connectWithOptions(device: Device, options: Required<ConnectOptions>): Promise<void>
55
67
  cancelConnectionAttempt(): Promise<void>
@@ -84,19 +96,18 @@ declare class BluetoothSdkModule extends NativeModule<BluetoothSdkModuleEvents>
84
96
  // Gallery Commands
85
97
  setGalleryMode(mode: GalleryMode): Promise<void>
86
98
  setButtonPhotoSettings(size: ButtonPhotoSize): Promise<void>
87
- setButtonVideoRecordingSettings(width: number, height: number, fps: number): Promise<void>
99
+ setButtonVideoRecordingSettings(width: number, height: number, frameRate: number): Promise<void>
88
100
  setButtonCameraLed(enabled: boolean): Promise<void>
89
101
  setButtonMaxRecordingTime(minutes: number): Promise<void>
90
102
  setCameraFov(fov: CameraFov): Promise<void>
91
103
  queryGalleryStatus(): Promise<void>
92
- photoRequest(
104
+ requestPhoto(
93
105
  requestId: string,
94
106
  appId: string,
95
107
  size: PhotoSize,
96
108
  webhookUrl: string | null,
97
109
  authToken: string | null,
98
110
  compress: PhotoCompression,
99
- flash: boolean,
100
111
  sound: boolean,
101
112
  ): Promise<void>
102
113
 
@@ -108,7 +119,7 @@ declare class BluetoothSdkModule extends NativeModule<BluetoothSdkModuleEvents>
108
119
  requestVersionInfo(): Promise<void>
109
120
 
110
121
  // Video Recording Commands
111
- startVideoRecording(requestId: string, save: boolean, flash: boolean, sound: boolean): Promise<void>
122
+ startVideoRecording(requestId: string, save: boolean, sound: boolean): Promise<void>
112
123
  stopVideoRecording(requestId: string): Promise<void>
113
124
 
114
125
  // Stream Commands
@@ -143,8 +154,8 @@ declare class BluetoothSdkModule extends NativeModule<BluetoothSdkModuleEvents>
143
154
  packageName: string | null,
144
155
  action: RgbLedAction,
145
156
  color: RgbLedColor | null,
146
- ontime: number,
147
- offtime: number,
157
+ onDurationMs: number,
158
+ offDurationMs: number,
148
159
  count: number,
149
160
  ): Promise<void>
150
161
 
@@ -165,24 +176,37 @@ declare class BluetoothSdkModule extends NativeModule<BluetoothSdkModuleEvents>
165
176
  getMemoryMB(): number
166
177
  }
167
178
 
179
+ export type BluetoothSdkInternalModule = BluetoothSdkNativeModule
180
+
168
181
  // This call loads the native module object from the JSI.
169
182
  // NativeModule<BluetoothSdkModuleEvents> already extends EventEmitter<BluetoothSdkModuleEvents>
170
- const NativeBluetoothSdkModule = requireNativeModule<BluetoothSdkModule>("BluetoothSdk")
183
+ const NativeBluetoothSdkModule = requireNativeModule<BluetoothSdkNativeModule>("BluetoothSdk")
171
184
 
172
185
  const DEFAULT_CONNECT_OPTIONS: Required<ConnectOptions> = {
173
186
  saveAsDefault: true,
174
187
  cancelExistingConnectionAttempt: true,
175
188
  }
176
189
 
177
- const DEFAULT_CONNECT_FIRST_TIMEOUT_MS = 15_000
190
+ const DEFAULT_SCAN_TIMEOUT_MS = 15_000
178
191
 
179
192
  const CAMERA_FOV_SETTINGS: Record<CameraFov, CameraFovSetting> = {
180
- standard: {fov: 118, roi_position: 0},
181
- wide: {fov: 118, roi_position: 0},
193
+ standard: {fov: 118, roiPosition: 0},
194
+ wide: {fov: 118, roiPosition: 0},
195
+ }
196
+
197
+ function searchResultsForModel(status: Partial<BluetoothStatus>, model: DeviceModel): Device[] {
198
+ return status.searchResults?.filter((device) => device.model === model) ?? []
199
+ }
200
+
201
+ function normalizeScanArgs(modelOrOptions: DeviceModel | ScanOptions, options?: ScanModelOptions): ScanOptions {
202
+ if (typeof modelOrOptions === "string") {
203
+ return {model: modelOrOptions, ...options}
204
+ }
205
+ return modelOrOptions
182
206
  }
183
207
 
184
- function findSearchResult(status: Partial<BluetoothStatus>, model: DeviceModel): Device | null {
185
- return status.searchResults?.find((device) => device.model === model) ?? null
208
+ function normalizeTimeoutMs(timeoutMs: number | undefined, defaultTimeoutMs: number): number {
209
+ return typeof timeoutMs === "number" && Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : defaultTimeoutMs
186
210
  }
187
211
 
188
212
  function dashboardMenuItemToNative(item: DashboardMenuItem): Record<string, unknown> {
@@ -333,11 +357,11 @@ NativeBluetoothSdkModule.setButtonPhotoSettings = function (size: ButtonPhotoSiz
333
357
  return this.updateBluetoothSettings({button_photo_size: size})
334
358
  }
335
359
 
336
- NativeBluetoothSdkModule.setButtonVideoRecordingSettings = function (width: number, height: number, fps: number) {
360
+ NativeBluetoothSdkModule.setButtonVideoRecordingSettings = function (width: number, height: number, frameRate: number) {
337
361
  return this.updateBluetoothSettings({
338
362
  button_video_width: width,
339
363
  button_video_height: height,
340
- button_video_fps: fps,
364
+ button_video_fps: frameRate,
341
365
  })
342
366
  }
343
367
 
@@ -397,22 +421,36 @@ NativeBluetoothSdkModule.connect = function (device: Device, options?: ConnectOp
397
421
  return this.connectWithOptions(device, {...DEFAULT_CONNECT_OPTIONS, ...options})
398
422
  }
399
423
 
400
- NativeBluetoothSdkModule.connectFirst = async function (model: DeviceModel, options?: ConnectFirstOptions) {
401
- const {timeoutMs = DEFAULT_CONNECT_FIRST_TIMEOUT_MS, ...connectOptions} = options ?? {}
424
+ NativeBluetoothSdkModule.scan = async function (
425
+ modelOrOptions: DeviceModel | ScanOptions,
426
+ options?: ScanModelOptions,
427
+ ) {
428
+ const scanOptions = normalizeScanArgs(modelOrOptions, options)
429
+ const timeoutMs = normalizeTimeoutMs(scanOptions.timeoutMs ?? scanOptions.timeout, DEFAULT_SCAN_TIMEOUT_MS)
430
+ let latestResults: Device[] = []
402
431
 
403
- const device = await new Promise<Device>((resolve, reject) => {
432
+ return new Promise<Device[]>((resolve, reject) => {
404
433
  let timeout: ReturnType<typeof setTimeout> | null = null
405
434
  let removeBluetoothListener = () => {}
406
435
  let settled = false
436
+ let scanStarted = false
437
+
438
+ const emitResults = (devices: Device[]) => {
439
+ latestResults = devices
440
+ scanOptions.onResults?.([...devices])
441
+ }
407
442
 
408
443
  const cleanup = () => {
409
444
  if (timeout) {
410
445
  clearTimeout(timeout)
411
446
  }
412
447
  removeBluetoothListener()
448
+ if (scanStarted) {
449
+ void Promise.resolve(this.stopScan()).catch(() => undefined)
450
+ }
413
451
  }
414
452
 
415
- const settle = (error: Error | null, result?: Device) => {
453
+ const settle = (error?: Error) => {
416
454
  if (settled) {
417
455
  return
418
456
  }
@@ -420,34 +458,29 @@ NativeBluetoothSdkModule.connectFirst = async function (model: DeviceModel, opti
420
458
  cleanup()
421
459
  if (error) {
422
460
  reject(error)
423
- } else if (result) {
424
- resolve(result)
461
+ } else {
462
+ resolve([...latestResults])
425
463
  }
426
464
  }
427
465
 
428
466
  const handleBluetoothStatus = (status: Partial<BluetoothStatus>) => {
429
- const result = findSearchResult(status, model)
430
- if (result) {
431
- settle(null, result)
432
- }
467
+ emitResults(searchResultsForModel(status, scanOptions.model))
433
468
  }
434
469
 
435
470
  removeBluetoothListener = this.onBluetoothStatus(handleBluetoothStatus)
471
+ emitResults([])
436
472
 
437
- if (Number.isFinite(timeoutMs) && timeoutMs > 0) {
438
- timeout = setTimeout(() => {
439
- settle(new Error(`Timed out after ${timeoutMs}ms while scanning for ${model}.`))
440
- }, timeoutMs)
441
- }
473
+ timeout = setTimeout(() => settle(), timeoutMs)
442
474
 
443
- Promise.resolve(this.startScan(model))
444
- .then(() => this.getBluetoothStatus())
475
+ Promise.resolve(this.startScan(scanOptions.model))
476
+ .then(() => {
477
+ scanStarted = true
478
+ return this.getBluetoothStatus()
479
+ })
445
480
  .then(handleBluetoothStatus)
446
481
  .catch((error) => settle(error instanceof Error ? error : new Error(String(error))))
447
482
  })
448
-
449
- await this.connect(device, connectOptions)
450
- return device
451
483
  }
452
484
 
453
485
  export default NativeBluetoothSdkModule
486
+ export const BluetoothSdk = NativeBluetoothSdkModule as BluetoothSdkPublicModule
package/src/index.ts CHANGED
@@ -1,4 +1,80 @@
1
- // Reexport the native module. On web, it will be resolved to BluetoothSdkModule.web.ts
2
- // and on native platforms to BluetoothSdkModule.ts
3
- export {default} from "./BluetoothSdkModule"
4
- export * from "./BluetoothSdk.types"
1
+ import {BluetoothSdk} from "./_private/BluetoothSdkModule"
2
+
3
+ export default BluetoothSdk
4
+
5
+ export {
6
+ DeviceModels,
7
+ createDisconnectedGlassesStatus,
8
+ isBusyGlassesConnectionStatus,
9
+ isConnectedGlassesConnectionStatus,
10
+ isConnectedWifiStatus,
11
+ isEnabledHotspotStatus,
12
+ isReadyGlassesConnectionStatus,
13
+ } from "./BluetoothSdk.types"
14
+
15
+ export type {
16
+ AudioConnectedEvent,
17
+ AudioDisconnectedEvent,
18
+ AudioPairingNeededEvent,
19
+ BatteryStatusEvent,
20
+ BluetoothSdkEvent,
21
+ BluetoothSdkEventListener,
22
+ BluetoothSdkEventMap,
23
+ BluetoothSdkEventName,
24
+ BluetoothSdkPublicModule as BluetoothSdkModule,
25
+ BluetoothSdkSubscription,
26
+ ButtonPhotoSize,
27
+ ButtonPressEvent,
28
+ CameraFov,
29
+ CompatibleGlassesSearchStopEvent,
30
+ ConnectOptions,
31
+ ConnectedGlassesConnectionStatus,
32
+ ConnectedWifiStatus,
33
+ Device,
34
+ DeviceModel,
35
+ EnabledHotspotStatus,
36
+ GalleryMode,
37
+ GalleryStatusEvent,
38
+ GlassesConnectionStatus,
39
+ GlassesMediaVolumeGetResult,
40
+ GlassesMediaVolumeSetResult,
41
+ GlassesNotReadyEvent,
42
+ HeadUpEvent,
43
+ HotspotErrorEvent,
44
+ HotspotStatus,
45
+ HotspotStatusChangeEvent,
46
+ KeepAliveAckEvent,
47
+ LocalTranscriptionEvent,
48
+ LogEvent,
49
+ MicLc3Event,
50
+ MicMode,
51
+ MicPcmEvent,
52
+ MicPreference,
53
+ PairFailureEvent,
54
+ PhotoCompression,
55
+ PhotoResponseEvent,
56
+ PhotoSize,
57
+ PublicBluetoothStatus as BluetoothStatus,
58
+ PublicGlassesStatus as GlassesStatus,
59
+ RgbLedAction,
60
+ RgbLedColor,
61
+ RgbLedControlResponseEvent,
62
+ ScanModelOptions,
63
+ ScanOptions,
64
+ ScanResultsCallback,
65
+ StreamAudioConfig,
66
+ StreamKeepAliveRequest,
67
+ StreamStartRequest,
68
+ StreamStatusEvent,
69
+ StreamStatusLifecycleState,
70
+ StreamStatusReconnectState,
71
+ StreamStatusState,
72
+ StreamVideoConfig,
73
+ SwipeVolumeStatusEvent,
74
+ SwitchStatusEvent,
75
+ TouchEvent,
76
+ VadStatusEvent,
77
+ WifiSearchResult,
78
+ WifiStatus,
79
+ WifiStatusChangeEvent,
80
+ } from "./BluetoothSdk.types"
@@ -1 +0,0 @@
1
- {"version":3,"file":"BluetoothSdkModule.d.ts","sourceRoot":"","sources":["../src/BluetoothSdkModule.ts"],"names":[],"mappings":"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"}