@mentra/bluetooth-sdk 0.1.4 → 0.1.6
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 +61 -42
- package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +20 -12
- package/android/src/main/java/com/mentra/bluetoothsdk/Bridge.kt +38 -12
- package/android/src/main/java/com/mentra/bluetoothsdk/DeviceStore.kt +2 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +45 -51
- package/android/src/main/java/com/mentra/bluetoothsdk/audio/AudioModels.kt +125 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/camera/CameraModels.kt +187 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/connection/ConnectionModels.kt +78 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/events/BluetoothEvents.kt +60 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/internal/MapParsing.kt +132 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/requests/DisplayRequests.kt +39 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/status/DeviceStatus.kt +605 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/status/RuntimeState.kt +199 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/status/WifiHotspotStatus.kt +173 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/streaming/StreamModels.kt +348 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/types/DeviceModels.kt +75 -0
- package/build/BluetoothSdk.types.d.ts +24 -7
- package/build/BluetoothSdk.types.d.ts.map +1 -1
- package/build/BluetoothSdk.types.js.map +1 -1
- package/build/_internal.d.ts +1 -1
- package/build/_internal.js +1 -1
- package/build/_internal.js.map +1 -1
- package/build/_private/BluetoothSdkModule.d.ts +5 -4
- package/build/_private/BluetoothSdkModule.d.ts.map +1 -1
- package/build/_private/BluetoothSdkModule.js +4 -1
- package/build/_private/BluetoothSdkModule.js.map +1 -1
- package/build/index.d.ts +4 -3
- package/build/index.d.ts.map +1 -1
- package/build/index.js +81 -2
- package/build/index.js.map +1 -1
- package/build/react/index.d.ts +2 -2
- package/build/react/index.d.ts.map +1 -1
- package/build/react/index.js +1 -2
- package/build/react/index.js.map +1 -1
- package/build/react/useBluetoothStatus.js +1 -1
- package/build/react/useBluetoothStatus.js.map +1 -1
- package/build/react/useGlassesConnection.d.ts.map +1 -1
- package/build/react/useGlassesConnection.js +13 -0
- package/build/react/useGlassesConnection.js.map +1 -1
- package/build/react/useMentraBluetooth.d.ts +98 -0
- package/build/react/useMentraBluetooth.d.ts.map +1 -0
- package/build/react/useMentraBluetooth.js +156 -0
- package/build/react/useMentraBluetooth.js.map +1 -0
- package/ios/BluetoothSdkModule.swift +9 -9
- package/ios/Source/Audio/AudioModels.swift +159 -0
- package/ios/Source/Bridge.swift +42 -8
- package/ios/Source/Camera/CameraModels.swift +246 -0
- package/ios/Source/Connection/ScanSession.swift +27 -0
- package/ios/Source/DeviceManager.swift +0 -1
- package/ios/Source/DeviceStore.swift +2 -1
- package/ios/Source/Errors/BluetoothError.swift +19 -0
- package/ios/Source/Events/BluetoothEvents.swift +115 -0
- package/ios/Source/Internal/BluetoothAvailability.swift +58 -0
- package/ios/Source/Internal/ValueParsing.swift +90 -0
- package/ios/Source/MentraBluetoothSDK.swift +32 -2040
- package/ios/Source/Requests/DisplayRequests.swift +58 -0
- package/ios/Source/Status/DeviceStatus.swift +463 -0
- package/ios/Source/Status/RuntimeState.swift +350 -0
- package/ios/Source/Status/WifiHotspotStatus.swift +326 -0
- package/ios/Source/Streaming/StreamModels.swift +436 -0
- package/ios/Source/Types/DeviceModels.swift +134 -0
- package/ios/Source/sgcs/G2.swift +97 -36
- package/package.json +1 -1
- package/src/BluetoothSdk.types.ts +24 -7
- package/src/_internal.ts +1 -1
- package/src/_private/BluetoothSdkModule.ts +10 -5
- package/src/index.ts +93 -4
- package/src/react/index.ts +13 -11
- package/src/react/useBluetoothStatus.ts +1 -1
- package/src/react/useGlassesConnection.ts +15 -0
- package/src/react/useMentraBluetooth.ts +307 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothModels.kt +0 -1725
package/ios/Source/sgcs/G2.swift
CHANGED
|
@@ -1062,6 +1062,8 @@ class G2: NSObject, SGCManager {
|
|
|
1062
1062
|
private var rightAuthenticated: Bool = false
|
|
1063
1063
|
private var isDisconnecting = false
|
|
1064
1064
|
private var pairingTimeoutTimer: DispatchWorkItem?
|
|
1065
|
+
private var useEvenDashboard = true
|
|
1066
|
+
private var dashboardShowing = 0
|
|
1065
1067
|
|
|
1066
1068
|
/// Device search
|
|
1067
1069
|
var DEVICE_SEARCH_ID = "NOT_SET"
|
|
@@ -1598,11 +1600,11 @@ class G2: NSObject, SGCManager {
|
|
|
1598
1600
|
func sendTextWall(_ text: String) {
|
|
1599
1601
|
// Bridge.log("G2: sendTextWall(\(text.prefix(50))...)")
|
|
1600
1602
|
|
|
1601
|
-
// ignore events while the dashboard is open:
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1603
|
+
// ignore events while the ER dashboard is open:
|
|
1604
|
+
let useNativeDashboard = DeviceStore.shared.get("bluetooth", "use_native_dashboard") as? Bool ?? false
|
|
1605
|
+
if useNativeDashboard && dashboardShowing > 0 {
|
|
1606
|
+
return
|
|
1607
|
+
}
|
|
1606
1608
|
|
|
1607
1609
|
if text.isEmpty {
|
|
1608
1610
|
clearDisplay()
|
|
@@ -2191,8 +2193,24 @@ class G2: NSObject, SGCManager {
|
|
|
2191
2193
|
return bmp
|
|
2192
2194
|
}
|
|
2193
2195
|
|
|
2196
|
+
/// Bring the Even Realities dashboard (the OS-level home/idle screen) to
|
|
2197
|
+
/// the foreground by tearing down whatever EvenHub page we currently own.
|
|
2198
|
+
/// The glasses fall back to the dashboard automatically when no page is up.
|
|
2194
2199
|
func showDashboard() {
|
|
2195
|
-
|
|
2200
|
+
Bridge.log("G2: showDashboard")
|
|
2201
|
+
dashboardShowing += 2
|
|
2202
|
+
let msg = EvenHubProto.shutdownMessage()
|
|
2203
|
+
sendEvenHubCommand(msg)
|
|
2204
|
+
pageCreated = false
|
|
2205
|
+
pageHasTextContainer = false
|
|
2206
|
+
currentTextContent = ""
|
|
2207
|
+
currentBitmapBase64 = ""
|
|
2208
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
|
|
2209
|
+
guard let self = self else { return }
|
|
2210
|
+
// activate the dashboard by setting dept to the current setting:
|
|
2211
|
+
let currentDepth = DeviceStore.shared.get("bluetooth", "dashboard_depth") as? Int ?? 0
|
|
2212
|
+
self.setDashboardDepthOnly(currentDepth)
|
|
2213
|
+
}
|
|
2196
2214
|
}
|
|
2197
2215
|
|
|
2198
2216
|
func setDashboardPosition(_ height: Int, _ depth: Int) {
|
|
@@ -2302,21 +2320,33 @@ class G2: NSObject, SGCManager {
|
|
|
2302
2320
|
sendEvenHubCommand(toSend)
|
|
2303
2321
|
}
|
|
2304
2322
|
|
|
2323
|
+
func restartMic() {
|
|
2324
|
+
// if already enabled, set to disabled, then send enabled after 500ms:
|
|
2325
|
+
DeviceStore.shared.apply("glasses", "micEnabled", true)
|
|
2326
|
+
let msg = EvenHubProto.audioControlMessage(enable: false)
|
|
2327
|
+
sendEvenHubCommand(msg)
|
|
2328
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
|
|
2329
|
+
guard let self = self else { return }
|
|
2330
|
+
let useNativeDashboard = DeviceStore.shared.get("bluetooth", "use_native_dashboard") as? Bool ?? false
|
|
2331
|
+
Bridge.log("G2: setMicEnabled - useNativeDashboard=\(useNativeDashboard), dashboardShowing=\(dashboardShowing)")
|
|
2332
|
+
if useNativeDashboard && dashboardShowing > 0 {
|
|
2333
|
+
return
|
|
2334
|
+
}
|
|
2335
|
+
if (!pageCreated || !pageHasTextContainer) {
|
|
2336
|
+
DeviceManager.shared.sendCurrentState()// should re-create the page if needed
|
|
2337
|
+
}
|
|
2338
|
+
let msg = EvenHubProto.audioControlMessage(enable: true)
|
|
2339
|
+
self.sendEvenHubCommand(msg)
|
|
2340
|
+
}
|
|
2341
|
+
}
|
|
2342
|
+
|
|
2305
2343
|
// MARK: - SGCManager: Audio Control
|
|
2306
2344
|
|
|
2307
2345
|
func setMicEnabled(_ enabled: Bool) {
|
|
2308
2346
|
Bridge.log("G2: setMicEnabled(\(enabled))")
|
|
2309
2347
|
let currentEnabled = DeviceStore.shared.get("glasses", "micEnabled") as? Bool ?? false
|
|
2310
2348
|
if currentEnabled && enabled {
|
|
2311
|
-
|
|
2312
|
-
DeviceStore.shared.apply("glasses", "micEnabled", true)
|
|
2313
|
-
let msg = EvenHubProto.audioControlMessage(enable: false)
|
|
2314
|
-
sendEvenHubCommand(msg)
|
|
2315
|
-
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
|
|
2316
|
-
guard let self = self else { return }
|
|
2317
|
-
let msg = EvenHubProto.audioControlMessage(enable: true)
|
|
2318
|
-
self.sendEvenHubCommand(msg)
|
|
2319
|
-
}
|
|
2349
|
+
restartMic()
|
|
2320
2350
|
return
|
|
2321
2351
|
}
|
|
2322
2352
|
|
|
@@ -2505,7 +2535,8 @@ class G2: NSObject, SGCManager {
|
|
|
2505
2535
|
// }
|
|
2506
2536
|
|
|
2507
2537
|
// connectController("1B:08:26:8E:0E:E6")
|
|
2508
|
-
connectController()
|
|
2538
|
+
// connectController()
|
|
2539
|
+
showDashboard()
|
|
2509
2540
|
}
|
|
2510
2541
|
|
|
2511
2542
|
func dbg2() {
|
|
@@ -2532,6 +2563,8 @@ class G2: NSObject, SGCManager {
|
|
|
2532
2563
|
// // update the text
|
|
2533
2564
|
// Bridge.log("G2: sendTextWall() - updating text container")
|
|
2534
2565
|
// updateText("test2")
|
|
2566
|
+
let currentDepth = DeviceStore.shared.get("bluetooth", "dashboard_depth") as? Int ?? 0
|
|
2567
|
+
setDashboardDepthOnly(currentDepth)
|
|
2535
2568
|
}
|
|
2536
2569
|
|
|
2537
2570
|
// MARK: - SGCManager: Device Control
|
|
@@ -3021,15 +3054,22 @@ class G2: NSObject, SGCManager {
|
|
|
3021
3054
|
if eventType == .doubleClick {
|
|
3022
3055
|
// trigger dashboard:
|
|
3023
3056
|
let isHeadUp = DeviceStore.shared.get("glasses", "headUp") as? Bool ?? false
|
|
3024
|
-
|
|
3025
|
-
DeviceStore.shared.
|
|
3026
|
-
if
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
}
|
|
3057
|
+
|
|
3058
|
+
let useNativeDashboard = DeviceStore.shared.get("bluetooth", "use_native_dashboard") as? Bool ?? false
|
|
3059
|
+
if useNativeDashboard {
|
|
3060
|
+
showDashboard()
|
|
3061
|
+
} else {
|
|
3062
|
+
// toggle head up:
|
|
3063
|
+
DeviceStore.shared.apply("glasses", "headUp", !isHeadUp)
|
|
3032
3064
|
}
|
|
3065
|
+
|
|
3066
|
+
// if isHeadUp {
|
|
3067
|
+
// // Bridge.log("G2: going back to home, clearing display")
|
|
3068
|
+
// // clear the display after a delay:
|
|
3069
|
+
// DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
|
3070
|
+
// self.clearDisplay()
|
|
3071
|
+
// }
|
|
3072
|
+
// }
|
|
3033
3073
|
// sendDashboardCommand(DashboardCommand.trigger)
|
|
3034
3074
|
|
|
3035
3075
|
// toggle head up:
|
|
@@ -3373,18 +3413,39 @@ class G2: NSObject, SGCManager {
|
|
|
3373
3413
|
// if we got 08011A00 that means we closed the dashboard, which means the mic is probably dead,
|
|
3374
3414
|
// so we need to revive it:
|
|
3375
3415
|
if data == Data([0x08, 0x01, 0x1A, 0x00]) {
|
|
3376
|
-
Bridge.log("G2:
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3416
|
+
Bridge.log("G2: dashboard closed / shutdown - dashboardShowing=\(dashboardShowing)")
|
|
3417
|
+
let useNativeDashboard = DeviceStore.shared.get("bluetooth", "use_native_dashboard") as? Bool ?? false
|
|
3418
|
+
if !useNativeDashboard {
|
|
3419
|
+
// make sure the container exists:
|
|
3420
|
+
DeviceManager.shared.sendCurrentState()
|
|
3421
|
+
// re-send mic on / if it's enabled:
|
|
3422
|
+
let micEnabled = DeviceStore.shared.get("glasses", "micEnabled") as? Bool ?? false
|
|
3423
|
+
if micEnabled {
|
|
3424
|
+
restartMic()
|
|
3425
|
+
}
|
|
3426
|
+
// reset the text container (different from clearDisplay())
|
|
3427
|
+
// sendTextWall(" ")
|
|
3428
|
+
// createPageWithText(" ")
|
|
3429
|
+
} else {
|
|
3430
|
+
// if we aren't trying to show the dashboard
|
|
3431
|
+
// then we need to turn the mic back on and display the mentra main page:
|
|
3432
|
+
if dashboardShowing <= 1 {
|
|
3433
|
+
dashboardShowing = 0
|
|
3434
|
+
// make sure the container exists:
|
|
3435
|
+
DeviceManager.shared.sendCurrentState()
|
|
3436
|
+
// set the mic back on if it should be on
|
|
3437
|
+
let micEnabled = DeviceStore.shared.get("glasses", "micEnabled") as? Bool ?? false
|
|
3438
|
+
if micEnabled {
|
|
3439
|
+
restartMic()
|
|
3440
|
+
}
|
|
3441
|
+
return
|
|
3442
|
+
}
|
|
3443
|
+
// do nothing this time since we just closed the dashboard
|
|
3444
|
+
dashboardShowing -= 1
|
|
3445
|
+
if (dashboardShowing < 0) {
|
|
3446
|
+
dashboardShowing = 0
|
|
3447
|
+
}
|
|
3448
|
+
}
|
|
3388
3449
|
}
|
|
3389
3450
|
|
|
3390
3451
|
// if we got 08011097012200 that means we selected a menu item:
|
package/package.json
CHANGED
|
@@ -295,11 +295,24 @@ export type WsBinEvent = {
|
|
|
295
295
|
export type MicPcmEvent = {
|
|
296
296
|
type: "mic_pcm"
|
|
297
297
|
pcm: ArrayBuffer
|
|
298
|
+
sampleRate: 16000
|
|
299
|
+
bitsPerSample: 16
|
|
300
|
+
channels: 1
|
|
301
|
+
encoding: "pcm_s16le"
|
|
302
|
+
vadGated: boolean
|
|
298
303
|
}
|
|
299
304
|
|
|
300
305
|
export type MicLc3Event = {
|
|
301
306
|
type: "mic_lc3"
|
|
302
307
|
lc3: ArrayBuffer
|
|
308
|
+
sampleRate: 16000
|
|
309
|
+
channels: 1
|
|
310
|
+
encoding: "lc3"
|
|
311
|
+
frameDurationMs: 10
|
|
312
|
+
frameSizeBytes: number
|
|
313
|
+
bitrate: number
|
|
314
|
+
packetizedFromGlasses: boolean
|
|
315
|
+
vadGated: boolean
|
|
303
316
|
}
|
|
304
317
|
|
|
305
318
|
export type StreamStatusLifecycleState = "initializing" | "streaming" | "stopping" | "stopped"
|
|
@@ -381,7 +394,7 @@ export type OtaUpdateAvailableEvent = {
|
|
|
381
394
|
cache_ready?: boolean
|
|
382
395
|
}
|
|
383
396
|
|
|
384
|
-
/** @deprecated Glasses no longer emit ota_progress; use {@link OtaStatusEvent} and
|
|
397
|
+
/** @deprecated Glasses no longer emit ota_progress; use {@link OtaStatusEvent} and status-store mapping. */
|
|
385
398
|
export type OtaProgressEvent = {
|
|
386
399
|
type: "ota_progress"
|
|
387
400
|
stage?: OtaStage
|
|
@@ -491,8 +504,6 @@ export type PublicBluetoothStatus = Pick<
|
|
|
491
504
|
>
|
|
492
505
|
|
|
493
506
|
export type BluetoothSdkEventMap = {
|
|
494
|
-
glasses_status: Partial<PublicGlassesStatus>
|
|
495
|
-
bluetooth_status: Partial<PublicBluetoothStatus>
|
|
496
507
|
log: LogEvent
|
|
497
508
|
device_discovered: Device
|
|
498
509
|
default_device_changed: {device?: Device}
|
|
@@ -540,8 +551,6 @@ export interface BluetoothSdkPublicModule {
|
|
|
540
551
|
listener: BluetoothSdkEventListener<EventName>,
|
|
541
552
|
): BluetoothSdkSubscription
|
|
542
553
|
|
|
543
|
-
getGlassesStatus(): Promise<PublicGlassesStatus>
|
|
544
|
-
getBluetoothStatus(): Promise<PublicBluetoothStatus>
|
|
545
554
|
getDefaultDevice(): Promise<Device | null>
|
|
546
555
|
setDefaultDevice(device: Device | null): Promise<void>
|
|
547
556
|
clearDefaultDevice(): Promise<void>
|
|
@@ -614,8 +623,6 @@ export interface BluetoothSdkPublicModule {
|
|
|
614
623
|
): Promise<void>
|
|
615
624
|
|
|
616
625
|
requestVersionInfo(): Promise<void>
|
|
617
|
-
onGlassesStatus(callback: (changed: Partial<PublicGlassesStatus>) => void): () => void
|
|
618
|
-
onBluetoothStatus(callback: (changed: Partial<PublicBluetoothStatus>) => void): () => void
|
|
619
626
|
}
|
|
620
627
|
|
|
621
628
|
// OTA update status types
|
|
@@ -711,10 +718,20 @@ export interface CoreSettings {
|
|
|
711
718
|
}
|
|
712
719
|
|
|
713
720
|
export interface Device {
|
|
721
|
+
/**
|
|
722
|
+
* Stable app-facing key for this scan result, within the limits of the
|
|
723
|
+
* platform identifier available to the SDK. Do not parse this value; use the
|
|
724
|
+
* typed model, name, address, and rssi fields instead.
|
|
725
|
+
*/
|
|
714
726
|
id: string
|
|
715
727
|
model: DeviceModel
|
|
716
728
|
name: string
|
|
729
|
+
/** Platform address/identifier when available: Android Bluetooth address, iOS CoreBluetooth identifier. */
|
|
717
730
|
address?: string
|
|
731
|
+
/**
|
|
732
|
+
* Optional scan signal strength. It may be undefined at first discovery and
|
|
733
|
+
* appear in a later scan update when the platform reports RSSI metadata.
|
|
734
|
+
*/
|
|
718
735
|
rssi?: number
|
|
719
736
|
}
|
|
720
737
|
|
package/src/_internal.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MentraOS-only compatibility entrypoint.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Apps should import from `@mentra/bluetooth-sdk`. This file is not a
|
|
5
5
|
* package export; MentraOS resolves it through its local
|
|
6
6
|
* `@mentra/bluetooth-sdk-internal` alias while the app is migrated onto the
|
|
7
7
|
* public SDK surface.
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
ObservableStoreCategory,
|
|
21
21
|
PhotoCompression,
|
|
22
22
|
PhotoSize,
|
|
23
|
+
PublicBluetoothStatus,
|
|
23
24
|
RgbLedAction,
|
|
24
25
|
RgbLedColor,
|
|
25
26
|
ScanModelOptions,
|
|
@@ -33,17 +34,18 @@ import {
|
|
|
33
34
|
*
|
|
34
35
|
* This file intentionally lives under `_private` so the package root can expose
|
|
35
36
|
* a small SDK surface while MentraOS uses its monorepo-only internal alias
|
|
36
|
-
* during migration.
|
|
37
|
+
* during migration. Raw status getters/listeners stay here so React hooks can
|
|
38
|
+
* shape native store snapshots before app code sees them.
|
|
37
39
|
*/
|
|
38
40
|
|
|
39
41
|
type GlassesListener = (changed: Partial<GlassesStatus>) => void
|
|
40
|
-
type BluetoothStatusListener = (changed: Partial<
|
|
42
|
+
type BluetoothStatusListener = (changed: Partial<PublicBluetoothStatus>) => void
|
|
41
43
|
type MaybePromise<T> = T | Promise<T>
|
|
42
44
|
|
|
43
45
|
declare class BluetoothSdkNativeModule extends NativeModule<BluetoothSdkModuleEvents> {
|
|
44
46
|
// Observable Store Functions (native)
|
|
45
47
|
getGlassesStatus(): Promise<GlassesStatus>
|
|
46
|
-
getBluetoothStatus(): Promise<
|
|
48
|
+
getBluetoothStatus(): Promise<PublicBluetoothStatus>
|
|
47
49
|
getDefaultDevice(): Promise<Device | null>
|
|
48
50
|
update(category: ObservableStoreCategory, values: object): Promise<void>
|
|
49
51
|
|
|
@@ -194,7 +196,7 @@ const CAMERA_FOV_SETTINGS: Record<CameraFov, CameraFovSetting> = {
|
|
|
194
196
|
wide: {fov: 118, roiPosition: 0},
|
|
195
197
|
}
|
|
196
198
|
|
|
197
|
-
function searchResultsForModel(status: Partial<
|
|
199
|
+
function searchResultsForModel(status: Partial<PublicBluetoothStatus>, model: DeviceModel): Device[] {
|
|
198
200
|
return status.searchResults?.filter((device) => device.model === model) ?? []
|
|
199
201
|
}
|
|
200
202
|
|
|
@@ -388,7 +390,7 @@ NativeBluetoothSdkModule.setMicState = function (
|
|
|
388
390
|
nativeSetMicState(
|
|
389
391
|
enabled,
|
|
390
392
|
useGlassesMic ?? true,
|
|
391
|
-
bypassVad ??
|
|
393
|
+
bypassVad ?? true,
|
|
392
394
|
sendTranscript ?? false,
|
|
393
395
|
sendLc3Data ?? false,
|
|
394
396
|
),
|
|
@@ -464,6 +466,9 @@ NativeBluetoothSdkModule.scan = async function (
|
|
|
464
466
|
}
|
|
465
467
|
|
|
466
468
|
const handleBluetoothStatus = (status: Partial<BluetoothStatus>) => {
|
|
469
|
+
if (!Array.isArray(status.searchResults)) {
|
|
470
|
+
return
|
|
471
|
+
}
|
|
467
472
|
emitResults(searchResultsForModel(status, scanOptions.model))
|
|
468
473
|
}
|
|
469
474
|
|
package/src/index.ts
CHANGED
|
@@ -1,10 +1,101 @@
|
|
|
1
|
-
import
|
|
1
|
+
import PrivateBluetoothSdkModule from "./_private/BluetoothSdkModule"
|
|
2
|
+
import type {
|
|
3
|
+
BluetoothSdkEventListener,
|
|
4
|
+
BluetoothSdkEventName,
|
|
5
|
+
BluetoothSdkPublicModule,
|
|
6
|
+
} from "./BluetoothSdk.types"
|
|
7
|
+
|
|
8
|
+
const PUBLIC_EVENT_NAMES = new Set<BluetoothSdkEventName>([
|
|
9
|
+
"log",
|
|
10
|
+
"device_discovered",
|
|
11
|
+
"default_device_changed",
|
|
12
|
+
"glasses_not_ready",
|
|
13
|
+
"button_press",
|
|
14
|
+
"touch_event",
|
|
15
|
+
"head_up",
|
|
16
|
+
"vad_status",
|
|
17
|
+
"battery_status",
|
|
18
|
+
"local_transcription",
|
|
19
|
+
"wifi_status_change",
|
|
20
|
+
"hotspot_status_change",
|
|
21
|
+
"hotspot_error",
|
|
22
|
+
"photo_response",
|
|
23
|
+
"gallery_status",
|
|
24
|
+
"compatible_glasses_search_stop",
|
|
25
|
+
"swipe_volume_status",
|
|
26
|
+
"switch_status",
|
|
27
|
+
"rgb_led_control_response",
|
|
28
|
+
"pair_failure",
|
|
29
|
+
"audio_pairing_needed",
|
|
30
|
+
"audio_connected",
|
|
31
|
+
"audio_disconnected",
|
|
32
|
+
"mic_pcm",
|
|
33
|
+
"mic_lc3",
|
|
34
|
+
"stream_status",
|
|
35
|
+
"keep_alive_ack",
|
|
36
|
+
])
|
|
37
|
+
|
|
38
|
+
const addListener: BluetoothSdkPublicModule["addListener"] = (eventName, listener) => {
|
|
39
|
+
if (!PUBLIC_EVENT_NAMES.has(eventName)) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
`Unsupported BluetoothSdk event "${eventName}". Use @mentra/bluetooth-sdk/react for status state.`,
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
return PrivateBluetoothSdkModule.addListener(
|
|
45
|
+
eventName,
|
|
46
|
+
listener as BluetoothSdkEventListener<BluetoothSdkEventName>,
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const BluetoothSdk: BluetoothSdkPublicModule = Object.freeze({
|
|
51
|
+
addListener,
|
|
52
|
+
getDefaultDevice: PrivateBluetoothSdkModule.getDefaultDevice.bind(PrivateBluetoothSdkModule),
|
|
53
|
+
setDefaultDevice: PrivateBluetoothSdkModule.setDefaultDevice.bind(PrivateBluetoothSdkModule),
|
|
54
|
+
clearDefaultDevice: PrivateBluetoothSdkModule.clearDefaultDevice.bind(PrivateBluetoothSdkModule),
|
|
55
|
+
startScan: PrivateBluetoothSdkModule.startScan.bind(PrivateBluetoothSdkModule),
|
|
56
|
+
stopScan: PrivateBluetoothSdkModule.stopScan.bind(PrivateBluetoothSdkModule),
|
|
57
|
+
scan: PrivateBluetoothSdkModule.scan.bind(PrivateBluetoothSdkModule) as BluetoothSdkPublicModule["scan"],
|
|
58
|
+
connect: PrivateBluetoothSdkModule.connect.bind(PrivateBluetoothSdkModule),
|
|
59
|
+
connectDefault: PrivateBluetoothSdkModule.connectDefault.bind(PrivateBluetoothSdkModule),
|
|
60
|
+
cancelConnectionAttempt: PrivateBluetoothSdkModule.cancelConnectionAttempt.bind(PrivateBluetoothSdkModule),
|
|
61
|
+
disconnect: PrivateBluetoothSdkModule.disconnect.bind(PrivateBluetoothSdkModule),
|
|
62
|
+
forget: PrivateBluetoothSdkModule.forget.bind(PrivateBluetoothSdkModule),
|
|
63
|
+
displayText: PrivateBluetoothSdkModule.displayText.bind(PrivateBluetoothSdkModule),
|
|
64
|
+
clearDisplay: PrivateBluetoothSdkModule.clearDisplay.bind(PrivateBluetoothSdkModule),
|
|
65
|
+
showDashboard: PrivateBluetoothSdkModule.showDashboard.bind(PrivateBluetoothSdkModule),
|
|
66
|
+
setDashboardPosition: PrivateBluetoothSdkModule.setDashboardPosition.bind(PrivateBluetoothSdkModule),
|
|
67
|
+
setHeadUpAngle: PrivateBluetoothSdkModule.setHeadUpAngle.bind(PrivateBluetoothSdkModule),
|
|
68
|
+
setScreenDisabled: PrivateBluetoothSdkModule.setScreenDisabled.bind(PrivateBluetoothSdkModule),
|
|
69
|
+
requestWifiScan: PrivateBluetoothSdkModule.requestWifiScan.bind(PrivateBluetoothSdkModule),
|
|
70
|
+
sendWifiCredentials: PrivateBluetoothSdkModule.sendWifiCredentials.bind(PrivateBluetoothSdkModule),
|
|
71
|
+
forgetWifiNetwork: PrivateBluetoothSdkModule.forgetWifiNetwork.bind(PrivateBluetoothSdkModule),
|
|
72
|
+
setHotspotState: PrivateBluetoothSdkModule.setHotspotState.bind(PrivateBluetoothSdkModule),
|
|
73
|
+
setGalleryMode: PrivateBluetoothSdkModule.setGalleryMode.bind(PrivateBluetoothSdkModule),
|
|
74
|
+
setButtonPhotoSettings: PrivateBluetoothSdkModule.setButtonPhotoSettings.bind(PrivateBluetoothSdkModule),
|
|
75
|
+
setButtonVideoRecordingSettings: PrivateBluetoothSdkModule.setButtonVideoRecordingSettings.bind(PrivateBluetoothSdkModule),
|
|
76
|
+
setButtonCameraLed: PrivateBluetoothSdkModule.setButtonCameraLed.bind(PrivateBluetoothSdkModule),
|
|
77
|
+
setButtonMaxRecordingTime: PrivateBluetoothSdkModule.setButtonMaxRecordingTime.bind(PrivateBluetoothSdkModule),
|
|
78
|
+
setCameraFov: PrivateBluetoothSdkModule.setCameraFov.bind(PrivateBluetoothSdkModule),
|
|
79
|
+
queryGalleryStatus: PrivateBluetoothSdkModule.queryGalleryStatus.bind(PrivateBluetoothSdkModule),
|
|
80
|
+
requestPhoto: PrivateBluetoothSdkModule.requestPhoto.bind(PrivateBluetoothSdkModule),
|
|
81
|
+
startVideoRecording: PrivateBluetoothSdkModule.startVideoRecording.bind(PrivateBluetoothSdkModule),
|
|
82
|
+
stopVideoRecording: PrivateBluetoothSdkModule.stopVideoRecording.bind(PrivateBluetoothSdkModule),
|
|
83
|
+
startStream: PrivateBluetoothSdkModule.startStream.bind(PrivateBluetoothSdkModule),
|
|
84
|
+
stopStream: PrivateBluetoothSdkModule.stopStream.bind(PrivateBluetoothSdkModule),
|
|
85
|
+
keepStreamAlive: PrivateBluetoothSdkModule.keepStreamAlive.bind(PrivateBluetoothSdkModule),
|
|
86
|
+
setMicState: PrivateBluetoothSdkModule.setMicState.bind(PrivateBluetoothSdkModule),
|
|
87
|
+
setPreferredMic: PrivateBluetoothSdkModule.setPreferredMic.bind(PrivateBluetoothSdkModule),
|
|
88
|
+
setOwnAppAudioPlaying: PrivateBluetoothSdkModule.setOwnAppAudioPlaying.bind(PrivateBluetoothSdkModule),
|
|
89
|
+
getGlassesMediaVolume: PrivateBluetoothSdkModule.getGlassesMediaVolume.bind(PrivateBluetoothSdkModule),
|
|
90
|
+
setGlassesMediaVolume: PrivateBluetoothSdkModule.setGlassesMediaVolume.bind(PrivateBluetoothSdkModule),
|
|
91
|
+
rgbLedControl: PrivateBluetoothSdkModule.rgbLedControl.bind(PrivateBluetoothSdkModule),
|
|
92
|
+
requestVersionInfo: PrivateBluetoothSdkModule.requestVersionInfo.bind(PrivateBluetoothSdkModule),
|
|
93
|
+
})
|
|
2
94
|
|
|
3
95
|
export default BluetoothSdk
|
|
4
96
|
|
|
5
97
|
export {
|
|
6
98
|
DeviceModels,
|
|
7
|
-
createDisconnectedGlassesStatus,
|
|
8
99
|
isBusyGlassesConnectionStatus,
|
|
9
100
|
isConnectedGlassesConnectionStatus,
|
|
10
101
|
isConnectedWifiStatus,
|
|
@@ -54,8 +145,6 @@ export type {
|
|
|
54
145
|
PhotoCompression,
|
|
55
146
|
PhotoResponseEvent,
|
|
56
147
|
PhotoSize,
|
|
57
|
-
PublicBluetoothStatus as BluetoothStatus,
|
|
58
|
-
PublicGlassesStatus as GlassesStatus,
|
|
59
148
|
RgbLedAction,
|
|
60
149
|
RgbLedColor,
|
|
61
150
|
RgbLedControlResponseEvent,
|
package/src/react/index.ts
CHANGED
|
@@ -8,15 +8,17 @@ export {
|
|
|
8
8
|
type BluetoothScanHookResult,
|
|
9
9
|
type UseBluetoothScanOptions,
|
|
10
10
|
} from "./useBluetoothScan"
|
|
11
|
+
export type {DefaultDeviceStorage} from "./useGlassesConnection"
|
|
11
12
|
export {
|
|
12
|
-
|
|
13
|
-
type
|
|
14
|
-
type
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
type
|
|
19
|
-
type
|
|
20
|
-
type
|
|
21
|
-
type
|
|
22
|
-
|
|
13
|
+
useMentraBluetooth,
|
|
14
|
+
type BatteryState,
|
|
15
|
+
type ConnectedGlassesInfo,
|
|
16
|
+
type FirmwareInfo,
|
|
17
|
+
type GalleryModeState,
|
|
18
|
+
type GlassesRuntimeState,
|
|
19
|
+
type MentraBluetoothSession,
|
|
20
|
+
type PhoneSdkRuntimeState,
|
|
21
|
+
type ScanController,
|
|
22
|
+
type SignalState,
|
|
23
|
+
type UseMentraBluetoothOptions,
|
|
24
|
+
} from "./useMentraBluetooth"
|
|
@@ -96,6 +96,21 @@ export function useGlassesConnection(
|
|
|
96
96
|
}
|
|
97
97
|
}, [])
|
|
98
98
|
|
|
99
|
+
useEffect(() => {
|
|
100
|
+
const subscription = BluetoothSdk.addListener("default_device_changed", (event) => {
|
|
101
|
+
const nextDefaultDevice = event.device ?? null
|
|
102
|
+
setDefaultDeviceState(nextDefaultDevice)
|
|
103
|
+
void defaultDeviceStorageRef.current?.save(nextDefaultDevice).catch((nextError) => {
|
|
104
|
+
setOperationError(nextError)
|
|
105
|
+
onErrorRef.current?.(nextError)
|
|
106
|
+
})
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
return () => {
|
|
110
|
+
subscription.remove()
|
|
111
|
+
}
|
|
112
|
+
}, [])
|
|
113
|
+
|
|
99
114
|
useEffect(() => {
|
|
100
115
|
if (!options.autoConnectDefault || autoConnectAttemptedRef.current || status.connected || !defaultDevice) {
|
|
101
116
|
return
|