@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.
- package/README.md +33 -19
- package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +13 -13
- package/android/src/main/java/com/mentra/bluetoothsdk/Bridge.kt +42 -18
- package/android/src/main/java/com/mentra/bluetoothsdk/DeviceManager.kt +19 -21
- package/android/src/main/java/com/mentra/bluetoothsdk/DeviceStore.kt +4 -4
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothModels.kt +118 -103
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +110 -38
- package/android/src/main/java/com/mentra/bluetoothsdk/controllers/ControllerManager.kt +4 -4
- package/android/src/main/java/com/mentra/bluetoothsdk/controllers/R1.kt +2 -2
- package/android/src/main/java/com/mentra/bluetoothsdk/services/PhoneMic.kt +6 -6
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G1.java +1 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G2.kt +3 -3
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Mach1.java +1 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.java +18 -18
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraNex.kt +1 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/SGCManager.kt +4 -4
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Simulated.kt +2 -2
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/Constants.kt +6 -6
- package/build/BluetoothSdk.types.d.ts +126 -27
- package/build/BluetoothSdk.types.d.ts.map +1 -1
- package/build/BluetoothSdk.types.js.map +1 -1
- package/build/_internal.d.ts +12 -0
- package/build/_internal.d.ts.map +1 -0
- package/build/_internal.js +11 -0
- package/build/_internal.js.map +1 -0
- package/build/{BluetoothSdkModule.d.ts → _private/BluetoothSdkModule.d.ts} +19 -8
- package/build/_private/BluetoothSdkModule.d.ts.map +1 -0
- package/build/{BluetoothSdkModule.js → _private/BluetoothSdkModule.js} +41 -26
- package/build/_private/BluetoothSdkModule.js.map +1 -0
- package/build/index.d.ts +4 -2
- package/build/index.d.ts.map +1 -1
- package/build/index.js +3 -4
- package/build/index.js.map +1 -1
- package/ios/BluetoothSdkModule.swift +14 -9
- package/ios/Source/Bridge.swift +44 -12
- package/ios/Source/DeviceManager.swift +27 -26
- package/ios/Source/DeviceStore.swift +4 -4
- package/ios/Source/MentraBluetoothSDK.swift +250 -132
- package/ios/Source/controllers/ControllerManager.swift +5 -5
- package/ios/Source/controllers/R1.swift +3 -3
- package/ios/Source/services/PhoneMic.swift +5 -5
- package/ios/Source/sgcs/Frame.swift +1 -1
- package/ios/Source/sgcs/G1.swift +1 -1
- package/ios/Source/sgcs/G2.swift +3 -3
- package/ios/Source/sgcs/Mach1.swift +1 -1
- package/ios/Source/sgcs/MentraLive.swift +31 -33
- package/ios/Source/sgcs/MentraNex.swift +2 -2
- package/ios/Source/sgcs/SGCManager.swift +5 -5
- package/ios/Source/sgcs/Simulated.swift +3 -3
- package/ios/Source/utils/Constants.swift +6 -6
- package/ios/Source/utils/JSCExperiment.swift +8 -8
- package/ios/Source/utils/TarBz2Extractor.swift +2 -2
- package/package.json +13 -1
- package/src/BluetoothSdk.types.ts +186 -28
- package/src/_internal.ts +11 -0
- package/src/{BluetoothSdkModule.ts → _private/BluetoothSdkModule.ts} +71 -38
- package/src/index.ts +80 -4
- package/build/BluetoothSdkModule.d.ts.map +0 -1
- 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
|
-
|
|
17
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
142
|
-
|
|
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
|
-
|
|
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
|
-
|
|
223
|
+
roiPosition: number
|
|
225
224
|
}
|
|
226
225
|
|
|
227
226
|
export type MicPreference = "auto" | "phone" | "glasses" | "bluetooth"
|
|
228
|
-
export type MicMode = "phone" | "glasses" | "
|
|
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
|
-
|
|
267
|
+
deviceName: string
|
|
272
268
|
}
|
|
273
269
|
|
|
274
270
|
export type AudioConnectedEvent = {
|
|
275
271
|
type: "audio_connected"
|
|
276
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
791
|
+
galleryModeAuto: boolean
|
|
634
792
|
button_photo_size: ButtonPhotoSize
|
|
635
|
-
button_video_settings: {width: number; height: 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
|
package/src/_internal.ts
ADDED
|
@@ -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 "
|
|
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
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
147
|
-
|
|
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<
|
|
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
|
|
190
|
+
const DEFAULT_SCAN_TIMEOUT_MS = 15_000
|
|
178
191
|
|
|
179
192
|
const CAMERA_FOV_SETTINGS: Record<CameraFov, CameraFovSetting> = {
|
|
180
|
-
standard: {fov: 118,
|
|
181
|
-
wide: {fov: 118,
|
|
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
|
|
185
|
-
return
|
|
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,
|
|
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:
|
|
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.
|
|
401
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
424
|
-
resolve(
|
|
461
|
+
} else {
|
|
462
|
+
resolve([...latestResults])
|
|
425
463
|
}
|
|
426
464
|
}
|
|
427
465
|
|
|
428
466
|
const handleBluetoothStatus = (status: Partial<BluetoothStatus>) => {
|
|
429
|
-
|
|
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
|
-
|
|
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(() =>
|
|
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
|
-
|
|
2
|
-
|
|
3
|
-
export
|
|
4
|
-
|
|
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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"}
|