@mentra/bluetooth-sdk 0.1.0 → 0.1.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.
- package/README.md +7 -22
- package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +16 -17
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +69 -10
- package/build/BluetoothSdk.types.d.ts +86 -12
- package/build/BluetoothSdk.types.d.ts.map +1 -1
- package/build/BluetoothSdk.types.js +11 -0
- package/build/BluetoothSdk.types.js.map +1 -1
- package/build/BluetoothSdkModule.d.ts +20 -7
- package/build/BluetoothSdkModule.d.ts.map +1 -1
- package/build/BluetoothSdkModule.js +114 -0
- package/build/BluetoothSdkModule.js.map +1 -1
- package/ios/BluetoothSdkModule.swift +15 -29
- package/ios/Source/MentraBluetoothSDK.swift +66 -13
- package/package.json +1 -1
- package/src/BluetoothSdk.types.ts +89 -13
- package/src/BluetoothSdkModule.ts +207 -13
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
import {NativeModule, requireNativeModule} from "expo"
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
|
-
|
|
4
|
+
BluetoothSettingsUpdate,
|
|
5
5
|
BluetoothSdkModuleEvents,
|
|
6
6
|
BluetoothStatus,
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
ButtonPhotoSize,
|
|
8
|
+
CameraFov,
|
|
9
|
+
CameraFovSetting,
|
|
10
|
+
ConnectFirstOptions,
|
|
11
|
+
ConnectOptions,
|
|
12
|
+
DashboardMenuItem,
|
|
9
13
|
Device,
|
|
14
|
+
DeviceModel,
|
|
15
|
+
GalleryMode,
|
|
10
16
|
GlassesMediaVolumeGetResult,
|
|
11
17
|
GlassesMediaVolumeSetResult,
|
|
12
18
|
GlassesStatus,
|
|
19
|
+
MicPreference,
|
|
20
|
+
ObservableStoreCategory,
|
|
13
21
|
PhotoCompression,
|
|
14
22
|
PhotoSize,
|
|
15
23
|
RgbLedAction,
|
|
@@ -27,11 +35,11 @@ declare class BluetoothSdkModule extends NativeModule<BluetoothSdkModuleEvents>
|
|
|
27
35
|
getGlassesStatus(): Promise<GlassesStatus>
|
|
28
36
|
getBluetoothStatus(): Promise<BluetoothStatus>
|
|
29
37
|
getDefaultDevice(): Promise<Device | null>
|
|
30
|
-
update(category:
|
|
38
|
+
update(category: ObservableStoreCategory, values: object): Promise<void>
|
|
31
39
|
|
|
32
40
|
// Display Commands
|
|
33
|
-
displayEvent(params: Record<string,
|
|
34
|
-
displayText(
|
|
41
|
+
displayEvent(params: Record<string, unknown>): Promise<void>
|
|
42
|
+
displayText(text: string, x?: number, y?: number, size?: number): Promise<void>
|
|
35
43
|
clearDisplay(): Promise<void>
|
|
36
44
|
|
|
37
45
|
// Connection Commands
|
|
@@ -40,7 +48,8 @@ declare class BluetoothSdkModule extends NativeModule<BluetoothSdkModuleEvents>
|
|
|
40
48
|
connectDefaultWithOptions(options: Required<ConnectOptions>): Promise<void>
|
|
41
49
|
setDefaultDevice(device: Device | null): Promise<void>
|
|
42
50
|
clearDefaultDevice(): Promise<void>
|
|
43
|
-
startScan(
|
|
51
|
+
startScan(model: DeviceModel): Promise<void>
|
|
52
|
+
connectFirst(model: DeviceModel, options?: ConnectFirstOptions): Promise<Device>
|
|
44
53
|
connect(device: Device, options?: ConnectOptions): Promise<void>
|
|
45
54
|
connectWithOptions(device: Device, options: Required<ConnectOptions>): Promise<void>
|
|
46
55
|
cancelConnectionAttempt(): Promise<void>
|
|
@@ -51,6 +60,12 @@ declare class BluetoothSdkModule extends NativeModule<BluetoothSdkModuleEvents>
|
|
|
51
60
|
forget(): Promise<void>
|
|
52
61
|
forgetController(): Promise<void>
|
|
53
62
|
showDashboard(): Promise<void>
|
|
63
|
+
setBrightness(level: number, autoMode?: boolean | null): Promise<void>
|
|
64
|
+
setAutoBrightness(enabled: boolean): Promise<void>
|
|
65
|
+
setDashboardPosition(height: number, depth: number): Promise<void>
|
|
66
|
+
setDashboardMenu(items: DashboardMenuItem[]): Promise<void>
|
|
67
|
+
setHeadUpAngle(angleDegrees: number): Promise<void>
|
|
68
|
+
setScreenDisabled(disabled: boolean): Promise<void>
|
|
54
69
|
ping(): Promise<void>
|
|
55
70
|
dbg1(): Promise<void>
|
|
56
71
|
dbg2(): Promise<void>
|
|
@@ -68,6 +83,11 @@ declare class BluetoothSdkModule extends NativeModule<BluetoothSdkModuleEvents>
|
|
|
68
83
|
|
|
69
84
|
// Gallery Commands
|
|
70
85
|
setGalleryMode(mode: GalleryMode): Promise<void>
|
|
86
|
+
setButtonPhotoSettings(size: ButtonPhotoSize): Promise<void>
|
|
87
|
+
setButtonVideoRecordingSettings(width: number, height: number, fps: number): Promise<void>
|
|
88
|
+
setButtonCameraLed(enabled: boolean): Promise<void>
|
|
89
|
+
setButtonMaxRecordingTime(minutes: number): Promise<void>
|
|
90
|
+
setCameraFov(fov: CameraFov): Promise<void>
|
|
71
91
|
queryGalleryStatus(): Promise<void>
|
|
72
92
|
photoRequest(
|
|
73
93
|
requestId: string,
|
|
@@ -97,7 +117,14 @@ declare class BluetoothSdkModule extends NativeModule<BluetoothSdkModuleEvents>
|
|
|
97
117
|
keepStreamAlive(params: StreamKeepAliveRequest): Promise<void>
|
|
98
118
|
|
|
99
119
|
// Microphone Commands
|
|
100
|
-
setMicState(
|
|
120
|
+
setMicState(
|
|
121
|
+
enabled: boolean,
|
|
122
|
+
useGlassesMic?: boolean,
|
|
123
|
+
bypassVad?: boolean,
|
|
124
|
+
sendTranscript?: boolean,
|
|
125
|
+
sendLc3Data?: boolean,
|
|
126
|
+
): Promise<void>
|
|
127
|
+
setPreferredMic(preferredMic: MicPreference): Promise<void>
|
|
101
128
|
restartTranscriber(): Promise<void>
|
|
102
129
|
|
|
103
130
|
// Audio Playback Monitoring
|
|
@@ -130,7 +157,7 @@ declare class BluetoothSdkModule extends NativeModule<BluetoothSdkModuleEvents>
|
|
|
130
157
|
|
|
131
158
|
// Helper methods for type-safe observable store access
|
|
132
159
|
updateGlasses(values: Partial<GlassesStatus>): Promise<void>
|
|
133
|
-
updateBluetoothSettings(values:
|
|
160
|
+
updateBluetoothSettings(values: BluetoothSettingsUpdate): Promise<void>
|
|
134
161
|
onGlassesStatus(callback: GlassesListener): () => void
|
|
135
162
|
onBluetoothStatus(callback: BluetoothStatusListener): () => void
|
|
136
163
|
|
|
@@ -147,7 +174,26 @@ const DEFAULT_CONNECT_OPTIONS: Required<ConnectOptions> = {
|
|
|
147
174
|
cancelExistingConnectionAttempt: true,
|
|
148
175
|
}
|
|
149
176
|
|
|
150
|
-
|
|
177
|
+
const DEFAULT_CONNECT_FIRST_TIMEOUT_MS = 15_000
|
|
178
|
+
|
|
179
|
+
const CAMERA_FOV_SETTINGS: Record<CameraFov, CameraFovSetting> = {
|
|
180
|
+
standard: {fov: 118, roi_position: 0},
|
|
181
|
+
wide: {fov: 118, roi_position: 0},
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function findSearchResult(status: Partial<BluetoothStatus>, model: DeviceModel): Device | null {
|
|
185
|
+
return status.searchResults?.find((device) => device.model === model) ?? null
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function dashboardMenuItemToNative(item: DashboardMenuItem): Record<string, unknown> {
|
|
189
|
+
return {
|
|
190
|
+
...(item.values ?? {}),
|
|
191
|
+
title: item.title,
|
|
192
|
+
packageName: item.packageName,
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function adaptConnectionStatusToNative(connection: GlassesStatus["connection"]): Record<string, unknown> {
|
|
151
197
|
switch (connection.state) {
|
|
152
198
|
case "connected":
|
|
153
199
|
return {connectionState: "CONNECTED", connected: true, fullyBooted: connection.fullyBooted}
|
|
@@ -162,9 +208,9 @@ function adaptConnectionStatusToNative(connection: GlassesStatus["connection"]):
|
|
|
162
208
|
}
|
|
163
209
|
}
|
|
164
210
|
|
|
165
|
-
function adaptGlassesUpdateToNative(values: Partial<GlassesStatus>): Record<string,
|
|
211
|
+
function adaptGlassesUpdateToNative(values: Partial<GlassesStatus>): Record<string, unknown> {
|
|
166
212
|
const {wifi, hotspot, connection, ...rest} = values
|
|
167
|
-
let update: Record<string,
|
|
213
|
+
let update: Record<string, unknown> = {...rest}
|
|
168
214
|
if (connection) {
|
|
169
215
|
update = {
|
|
170
216
|
...update,
|
|
@@ -226,14 +272,109 @@ NativeBluetoothSdkModule.getDefaultDevice = function () {
|
|
|
226
272
|
return Promise.resolve(nativeGetDefaultDevice())
|
|
227
273
|
}
|
|
228
274
|
|
|
275
|
+
const nativeSetMicState = NativeBluetoothSdkModule.setMicState.bind(NativeBluetoothSdkModule) as (
|
|
276
|
+
enabled: boolean,
|
|
277
|
+
useGlassesMic: boolean,
|
|
278
|
+
bypassVad: boolean,
|
|
279
|
+
sendTranscript: boolean,
|
|
280
|
+
sendLc3Data: boolean,
|
|
281
|
+
) => MaybePromise<void>
|
|
282
|
+
|
|
283
|
+
const nativeDisplayText = NativeBluetoothSdkModule.displayText.bind(NativeBluetoothSdkModule) as (
|
|
284
|
+
text: string,
|
|
285
|
+
x: number,
|
|
286
|
+
y: number,
|
|
287
|
+
size: number,
|
|
288
|
+
) => MaybePromise<void>
|
|
289
|
+
|
|
229
290
|
NativeBluetoothSdkModule.updateGlasses = function (values: Partial<GlassesStatus>) {
|
|
230
291
|
return this.update("glasses", adaptGlassesUpdateToNative(values))
|
|
231
292
|
}
|
|
232
293
|
|
|
233
|
-
NativeBluetoothSdkModule.updateBluetoothSettings = function (values:
|
|
294
|
+
NativeBluetoothSdkModule.updateBluetoothSettings = function (values: BluetoothSettingsUpdate) {
|
|
234
295
|
return this.update("bluetooth", values)
|
|
235
296
|
}
|
|
236
297
|
|
|
298
|
+
NativeBluetoothSdkModule.displayText = function (text: string, x?: number, y?: number, size?: number) {
|
|
299
|
+
return Promise.resolve(nativeDisplayText(text, x ?? 0, y ?? 0, size ?? 24))
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
NativeBluetoothSdkModule.setBrightness = function (level: number, autoMode?: boolean | null) {
|
|
303
|
+
return this.updateBluetoothSettings({
|
|
304
|
+
...(autoMode == null ? {} : {auto_brightness: autoMode}),
|
|
305
|
+
brightness: level,
|
|
306
|
+
})
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
NativeBluetoothSdkModule.setAutoBrightness = function (enabled: boolean) {
|
|
310
|
+
return this.updateBluetoothSettings({auto_brightness: enabled})
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
NativeBluetoothSdkModule.setDashboardPosition = function (height: number, depth: number) {
|
|
314
|
+
return this.updateBluetoothSettings({
|
|
315
|
+
dashboard_height: height,
|
|
316
|
+
dashboard_depth: depth,
|
|
317
|
+
})
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
NativeBluetoothSdkModule.setDashboardMenu = function (items: DashboardMenuItem[]) {
|
|
321
|
+
return this.updateBluetoothSettings({menu_apps: items.map(dashboardMenuItemToNative)})
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
NativeBluetoothSdkModule.setHeadUpAngle = function (angleDegrees: number) {
|
|
325
|
+
return this.updateBluetoothSettings({head_up_angle: angleDegrees})
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
NativeBluetoothSdkModule.setScreenDisabled = function (disabled: boolean) {
|
|
329
|
+
return this.updateBluetoothSettings({screen_disabled: disabled})
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
NativeBluetoothSdkModule.setButtonPhotoSettings = function (size: ButtonPhotoSize) {
|
|
333
|
+
return this.updateBluetoothSettings({button_photo_size: size})
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
NativeBluetoothSdkModule.setButtonVideoRecordingSettings = function (width: number, height: number, fps: number) {
|
|
337
|
+
return this.updateBluetoothSettings({
|
|
338
|
+
button_video_width: width,
|
|
339
|
+
button_video_height: height,
|
|
340
|
+
button_video_fps: fps,
|
|
341
|
+
})
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
NativeBluetoothSdkModule.setButtonCameraLed = function (enabled: boolean) {
|
|
345
|
+
return this.updateBluetoothSettings({button_camera_led: enabled})
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
NativeBluetoothSdkModule.setButtonMaxRecordingTime = function (minutes: number) {
|
|
349
|
+
return this.updateBluetoothSettings({button_max_recording_time: minutes})
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
NativeBluetoothSdkModule.setCameraFov = function (fov: CameraFov) {
|
|
353
|
+
return this.updateBluetoothSettings({camera_fov: CAMERA_FOV_SETTINGS[fov]})
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
NativeBluetoothSdkModule.setMicState = function (
|
|
357
|
+
enabled: boolean,
|
|
358
|
+
useGlassesMic?: boolean,
|
|
359
|
+
bypassVad?: boolean,
|
|
360
|
+
sendTranscript?: boolean,
|
|
361
|
+
sendLc3Data?: boolean,
|
|
362
|
+
) {
|
|
363
|
+
return Promise.resolve(
|
|
364
|
+
nativeSetMicState(
|
|
365
|
+
enabled,
|
|
366
|
+
useGlassesMic ?? true,
|
|
367
|
+
bypassVad ?? false,
|
|
368
|
+
sendTranscript ?? false,
|
|
369
|
+
sendLc3Data ?? false,
|
|
370
|
+
),
|
|
371
|
+
)
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
NativeBluetoothSdkModule.setPreferredMic = function (preferredMic: MicPreference) {
|
|
375
|
+
return this.updateBluetoothSettings({preferred_mic: preferredMic})
|
|
376
|
+
}
|
|
377
|
+
|
|
237
378
|
NativeBluetoothSdkModule.onGlassesStatus = function (callback: GlassesListener) {
|
|
238
379
|
const subscription = this.addListener("glasses_status", callback)
|
|
239
380
|
return () => subscription.remove()
|
|
@@ -256,4 +397,57 @@ NativeBluetoothSdkModule.connect = function (device: Device, options?: ConnectOp
|
|
|
256
397
|
return this.connectWithOptions(device, {...DEFAULT_CONNECT_OPTIONS, ...options})
|
|
257
398
|
}
|
|
258
399
|
|
|
400
|
+
NativeBluetoothSdkModule.connectFirst = async function (model: DeviceModel, options?: ConnectFirstOptions) {
|
|
401
|
+
const {timeoutMs = DEFAULT_CONNECT_FIRST_TIMEOUT_MS, ...connectOptions} = options ?? {}
|
|
402
|
+
|
|
403
|
+
const device = await new Promise<Device>((resolve, reject) => {
|
|
404
|
+
let timeout: ReturnType<typeof setTimeout> | null = null
|
|
405
|
+
let removeBluetoothListener = () => {}
|
|
406
|
+
let settled = false
|
|
407
|
+
|
|
408
|
+
const cleanup = () => {
|
|
409
|
+
if (timeout) {
|
|
410
|
+
clearTimeout(timeout)
|
|
411
|
+
}
|
|
412
|
+
removeBluetoothListener()
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
const settle = (error: Error | null, result?: Device) => {
|
|
416
|
+
if (settled) {
|
|
417
|
+
return
|
|
418
|
+
}
|
|
419
|
+
settled = true
|
|
420
|
+
cleanup()
|
|
421
|
+
if (error) {
|
|
422
|
+
reject(error)
|
|
423
|
+
} else if (result) {
|
|
424
|
+
resolve(result)
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
const handleBluetoothStatus = (status: Partial<BluetoothStatus>) => {
|
|
429
|
+
const result = findSearchResult(status, model)
|
|
430
|
+
if (result) {
|
|
431
|
+
settle(null, result)
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
removeBluetoothListener = this.onBluetoothStatus(handleBluetoothStatus)
|
|
436
|
+
|
|
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
|
+
}
|
|
442
|
+
|
|
443
|
+
Promise.resolve(this.startScan(model))
|
|
444
|
+
.then(() => this.getBluetoothStatus())
|
|
445
|
+
.then(handleBluetoothStatus)
|
|
446
|
+
.catch((error) => settle(error instanceof Error ? error : new Error(String(error))))
|
|
447
|
+
})
|
|
448
|
+
|
|
449
|
+
await this.connect(device, connectOptions)
|
|
450
|
+
return device
|
|
451
|
+
}
|
|
452
|
+
|
|
259
453
|
export default NativeBluetoothSdkModule
|