@mentra/bluetooth-sdk 0.1.5 → 0.1.7

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 (92) hide show
  1. package/README.md +45 -27
  2. package/android/build.gradle +2 -9
  3. package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +53 -36
  4. package/android/src/main/java/com/mentra/bluetoothsdk/Bridge.kt +22 -9
  5. package/android/src/main/java/com/mentra/bluetoothsdk/DeviceManager.kt +25 -36
  6. package/android/src/main/java/com/mentra/bluetoothsdk/DeviceStore.kt +9 -4
  7. package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +68 -56
  8. package/android/src/main/java/com/mentra/bluetoothsdk/audio/AudioModels.kt +125 -0
  9. package/android/src/main/java/com/mentra/bluetoothsdk/camera/CameraModels.kt +209 -0
  10. package/android/src/main/java/com/mentra/bluetoothsdk/connection/ConnectionModels.kt +78 -0
  11. package/android/src/main/java/com/mentra/bluetoothsdk/controllers/ControllerManager.kt +4 -3
  12. package/android/src/main/java/com/mentra/bluetoothsdk/controllers/R1.kt +2 -1
  13. package/android/src/main/java/com/mentra/bluetoothsdk/events/BluetoothEvents.kt +72 -0
  14. package/android/src/main/java/com/mentra/bluetoothsdk/internal/MapParsing.kt +132 -0
  15. package/android/src/main/java/com/mentra/bluetoothsdk/requests/DisplayRequests.kt +39 -0
  16. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G1.java +1 -1
  17. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G2.kt +2 -1
  18. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Mach1.java +1 -1
  19. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.java +168 -10
  20. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraNex.kt +1 -1
  21. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/SGCManager.kt +7 -3
  22. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Simulated.kt +3 -1
  23. package/android/src/main/java/com/mentra/bluetoothsdk/status/DeviceStatus.kt +607 -0
  24. package/android/src/main/java/com/mentra/bluetoothsdk/status/RuntimeState.kt +201 -0
  25. package/android/src/main/java/com/mentra/bluetoothsdk/status/WifiHotspotStatus.kt +173 -0
  26. package/android/src/main/java/com/mentra/bluetoothsdk/streaming/StreamModels.kt +348 -0
  27. package/android/src/main/java/com/mentra/bluetoothsdk/stt/SherpaOnnxTranscriber.kt +1 -3
  28. package/android/src/main/java/com/mentra/bluetoothsdk/types/DeviceModels.kt +75 -0
  29. package/build/BluetoothSdk.types.d.ts +46 -20
  30. package/build/BluetoothSdk.types.d.ts.map +1 -1
  31. package/build/BluetoothSdk.types.js +1 -0
  32. package/build/BluetoothSdk.types.js.map +1 -1
  33. package/build/_private/BluetoothSdkModule.d.ts +6 -5
  34. package/build/_private/BluetoothSdkModule.d.ts.map +1 -1
  35. package/build/_private/BluetoothSdkModule.js +40 -5
  36. package/build/_private/BluetoothSdkModule.js.map +1 -1
  37. package/build/index.d.ts +1 -1
  38. package/build/index.d.ts.map +1 -1
  39. package/build/index.js +4 -2
  40. package/build/index.js.map +1 -1
  41. package/build/react/useMentraBluetooth.d.ts +5 -3
  42. package/build/react/useMentraBluetooth.d.ts.map +1 -1
  43. package/build/react/useMentraBluetooth.js +15 -4
  44. package/build/react/useMentraBluetooth.js.map +1 -1
  45. package/ios/BluetoothSdkModule.swift +45 -28
  46. package/ios/MentraBluetoothSDK.podspec +0 -3
  47. package/ios/Source/Audio/AudioModels.swift +159 -0
  48. package/ios/Source/Bridge.swift +22 -11
  49. package/ios/Source/Camera/CameraModels.swift +248 -0
  50. package/ios/Source/Connection/ScanSession.swift +27 -0
  51. package/ios/Source/DeviceManager.swift +20 -97
  52. package/ios/Source/DeviceStore.swift +13 -4
  53. package/ios/Source/Errors/BluetoothError.swift +19 -0
  54. package/ios/Source/Events/BluetoothEvents.swift +149 -0
  55. package/ios/Source/Internal/BluetoothAvailability.swift +58 -0
  56. package/ios/Source/Internal/ValueParsing.swift +90 -0
  57. package/ios/Source/MentraBluetoothSDK.swift +50 -2150
  58. package/ios/Source/Requests/DisplayRequests.swift +58 -0
  59. package/ios/Source/Status/DeviceStatus.swift +471 -0
  60. package/ios/Source/Status/RuntimeState.swift +359 -0
  61. package/ios/Source/Status/WifiHotspotStatus.swift +326 -0
  62. package/ios/Source/Streaming/StreamModels.swift +436 -0
  63. package/ios/Source/Types/DeviceModels.swift +134 -0
  64. package/ios/Source/controllers/ControllerManager.swift +3 -3
  65. package/ios/Source/controllers/R1.swift +1 -1
  66. package/ios/Source/sgcs/G1.swift +1 -1
  67. package/ios/Source/sgcs/G2.swift +99 -39
  68. package/ios/Source/sgcs/Mach1.swift +1 -1
  69. package/ios/Source/sgcs/MentraLive.swift +109 -12
  70. package/ios/Source/sgcs/MentraNex.swift +1 -1
  71. package/ios/Source/sgcs/SGCManager.swift +11 -3
  72. package/ios/Source/sgcs/Simulated.swift +2 -2
  73. package/ios/Source/stt/SherpaOnnxTranscriber.swift +1 -4
  74. package/package.json +1 -1
  75. package/src/BluetoothSdk.types.ts +48 -28
  76. package/src/_private/BluetoothSdkModule.ts +47 -21
  77. package/src/index.ts +6 -4
  78. package/src/react/useMentraBluetooth.ts +19 -7
  79. package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothModels.kt +0 -1810
  80. package/android/src/main/java/com/mentra/bluetoothsdk/stt/VadGateSpeechPolicy.kt +0 -221
  81. package/ios/Packages/VAD/Common/VAD/VADQuality.swift +0 -41
  82. package/ios/Packages/VAD/Common/VAD/VADState.swift +0 -26
  83. package/ios/Packages/VAD/Common/VAD/VADStrategy.swift +0 -29
  84. package/ios/Packages/VAD/Common/VAD/VADType.swift +0 -14
  85. package/ios/Packages/VAD/Data/Configuration.swift +0 -68
  86. package/ios/Packages/VAD/Data/FrameSize.swift +0 -39
  87. package/ios/Packages/VAD/Data/Record.swift +0 -13
  88. package/ios/Packages/VAD/Data/Result.swift +0 -22
  89. package/ios/Packages/VAD/Data/SampleRate.swift +0 -48
  90. package/ios/Packages/VAD/Silero/Model/silero_vad.onnx +0 -0
  91. package/ios/Packages/VAD/Silero/SileroVAD.swift +0 -284
  92. package/ios/Packages/VAD/Silero/SileroVADStrategy.swift +0 -64
@@ -0,0 +1,201 @@
1
+ package com.mentra.bluetoothsdk
2
+
3
+ data class MentraBluetoothState(
4
+ val glasses: GlassesRuntimeState,
5
+ val sdk: PhoneSdkRuntimeState,
6
+ val scan: BluetoothScanState,
7
+ ) {
8
+ internal companion object {
9
+ fun from(
10
+ glassesStatus: GlassesStatus,
11
+ bluetoothStatus: BluetoothStatus,
12
+ ): MentraBluetoothState =
13
+ MentraBluetoothState(
14
+ glasses = GlassesRuntimeState.from(glassesStatus),
15
+ sdk = PhoneSdkRuntimeState.from(bluetoothStatus),
16
+ scan = BluetoothScanState.from(bluetoothStatus),
17
+ )
18
+ }
19
+ }
20
+
21
+ data class GlassesBatteryState(
22
+ val charging: Boolean,
23
+ val level: Int?,
24
+ )
25
+
26
+ data class ConnectedGlassesInfo(
27
+ val appVersion: String?,
28
+ val bluetoothName: String?,
29
+ val buildNumber: String?,
30
+ val color: String?,
31
+ val deviceModel: DeviceModel?,
32
+ val firmwareVersion: String?,
33
+ val serialNumber: String?,
34
+ val style: String?,
35
+ )
36
+
37
+ enum class FirmwareSource {
38
+ APP,
39
+ BES,
40
+ FIRMWARE,
41
+ MTK,
42
+ UNKNOWN,
43
+ }
44
+
45
+ data class FirmwareInfo(
46
+ val appVersion: String?,
47
+ val buildNumber: String?,
48
+ val source: FirmwareSource,
49
+ val version: String?,
50
+ )
51
+
52
+ data class SignalState(
53
+ val strengthDbm: Int?,
54
+ val updatedAt: Long?,
55
+ )
56
+
57
+ sealed interface GlassesRuntimeState {
58
+ val connected: Boolean
59
+ val connection: GlassesConnectionState
60
+ val ready: Boolean
61
+
62
+ data class Disconnected(
63
+ override val connection: GlassesConnectionState = GlassesConnectionState.DISCONNECTED,
64
+ ) : GlassesRuntimeState {
65
+ override val connected: Boolean = false
66
+ override val ready: Boolean = false
67
+ }
68
+
69
+ data class Connected(
70
+ val battery: GlassesBatteryState,
71
+ override val connection: GlassesConnectionState,
72
+ val device: ConnectedGlassesInfo,
73
+ val firmware: FirmwareInfo,
74
+ val hotspot: HotspotStatus,
75
+ override val ready: Boolean,
76
+ val signal: SignalState,
77
+ val voiceActivityDetectionEnabled: Boolean,
78
+ val wifi: WifiStatus,
79
+ ) : GlassesRuntimeState {
80
+ override val connected: Boolean = true
81
+ }
82
+
83
+ companion object {
84
+ internal fun from(status: GlassesStatus): GlassesRuntimeState {
85
+ if (!status.connected && status.connectionState != GlassesConnectionState.CONNECTED) {
86
+ return Disconnected(connection = status.connectionState)
87
+ }
88
+ return Connected(
89
+ battery = batteryState(status),
90
+ connection = GlassesConnectionState.CONNECTED,
91
+ device = connectedGlassesInfo(status),
92
+ firmware = firmwareInfo(status),
93
+ hotspot = status.hotspot,
94
+ ready = status.fullyBooted,
95
+ signal = SignalState(
96
+ strengthDbm = status.signalStrength.takeUnless { it == -1 },
97
+ updatedAt = status.signalStrengthUpdatedAt.takeUnless { it <= 0L },
98
+ ),
99
+ voiceActivityDetectionEnabled = status.voiceActivityDetectionEnabled,
100
+ wifi = status.wifi,
101
+ )
102
+ }
103
+
104
+ private fun batteryState(status: GlassesStatus): GlassesBatteryState =
105
+ GlassesBatteryState(
106
+ charging = status.charging,
107
+ level = status.batteryLevel.takeUnless { it < 0 },
108
+ )
109
+
110
+ private fun connectedGlassesInfo(status: GlassesStatus): ConnectedGlassesInfo =
111
+ ConnectedGlassesInfo(
112
+ appVersion = status.appVersion.nonBlank(),
113
+ bluetoothName = status.bluetoothName.nonBlank(),
114
+ buildNumber = status.buildNumber.nonBlank(),
115
+ color = status.color.nonBlank(),
116
+ deviceModel = status.deviceModel.takeIf { it.isNotBlank() }?.let(DeviceModel::fromDeviceType),
117
+ firmwareVersion = status.firmwareVersion.nonBlank(),
118
+ serialNumber = status.serialNumber.nonBlank(),
119
+ style = status.style.nonBlank(),
120
+ )
121
+
122
+ private fun firmwareInfo(status: GlassesStatus): FirmwareInfo {
123
+ val sources =
124
+ listOf(
125
+ status.firmwareVersion to FirmwareSource.FIRMWARE,
126
+ status.besFirmwareVersion to FirmwareSource.BES,
127
+ status.mtkFirmwareVersion to FirmwareSource.MTK,
128
+ status.appVersion to FirmwareSource.APP,
129
+ )
130
+ val match = sources.firstOrNull { (version, _) -> version.isNotBlank() }
131
+ return FirmwareInfo(
132
+ appVersion = status.appVersion.nonBlank(),
133
+ buildNumber = status.buildNumber.nonBlank(),
134
+ source = match?.second ?: FirmwareSource.UNKNOWN,
135
+ version = match?.first?.nonBlank(),
136
+ )
137
+ }
138
+ }
139
+ }
140
+
141
+ enum class MicMode(val value: String) {
142
+ PHONE("phone"),
143
+ GLASSES("glasses"),
144
+ BLUETOOTH_CLASSIC("bluetoothClassic"),
145
+ BLUETOOTH("bluetooth");
146
+
147
+ internal companion object {
148
+ fun fromValue(value: String?): MicMode? =
149
+ values().firstOrNull { it.value == value }
150
+ }
151
+ }
152
+
153
+ data class GalleryModeState(
154
+ val enabled: Boolean,
155
+ )
156
+
157
+ data class PhoneSdkRuntimeState(
158
+ val currentMic: MicMode?,
159
+ val defaultDevice: Device?,
160
+ val galleryMode: GalleryModeState,
161
+ val lastLog: List<String>,
162
+ val micRanking: List<MicMode>,
163
+ val otherBluetoothConnected: Boolean,
164
+ val searching: Boolean,
165
+ val searchingController: Boolean,
166
+ val systemMicUnavailable: Boolean,
167
+ val wifiScanResults: List<WifiScanResult>,
168
+ ) {
169
+ internal companion object {
170
+ fun from(status: BluetoothStatus): PhoneSdkRuntimeState =
171
+ PhoneSdkRuntimeState(
172
+ currentMic = MicMode.fromValue(status.currentMic),
173
+ defaultDevice = status.defaultDevice,
174
+ galleryMode = GalleryModeState(enabled = status.galleryModeEnabled),
175
+ lastLog = status.lastLog,
176
+ micRanking = status.micRanking.mapNotNull { MicMode.fromValue(it) },
177
+ otherBluetoothConnected = status.otherBtConnected,
178
+ searching = status.searching,
179
+ searchingController = status.searchingController,
180
+ systemMicUnavailable = status.systemMicUnavailable,
181
+ wifiScanResults = status.wifiScanResults,
182
+ )
183
+ }
184
+ }
185
+
186
+ data class BluetoothScanState(
187
+ val active: Boolean,
188
+ val devices: List<Device>,
189
+ val searchingController: Boolean,
190
+ ) {
191
+ internal companion object {
192
+ fun from(status: BluetoothStatus): BluetoothScanState =
193
+ BluetoothScanState(
194
+ active = status.searching,
195
+ devices = status.searchResults,
196
+ searchingController = status.searchingController,
197
+ )
198
+ }
199
+ }
200
+
201
+ private fun String.nonBlank(): String? = takeIf { it.isNotBlank() }
@@ -0,0 +1,173 @@
1
+ package com.mentra.bluetoothsdk
2
+
3
+ sealed interface WifiStatus {
4
+ val state: String
5
+
6
+ fun toMap(): Map<String, Any> =
7
+ when (this) {
8
+ is Connected -> {
9
+ val values =
10
+ mutableMapOf<String, Any>(
11
+ "state" to state,
12
+ "ssid" to ssid,
13
+ )
14
+ localIp?.let { values["localIp"] = it }
15
+ values
16
+ }
17
+ Disconnected -> mapOf("state" to state)
18
+ }
19
+
20
+ fun toEventMap(): Map<String, Any> =
21
+ toMap() + mapOf("type" to "wifi_status_change")
22
+
23
+ object Disconnected : WifiStatus {
24
+ override val state: String = "disconnected"
25
+ }
26
+
27
+ data class Connected(
28
+ val ssid: String,
29
+ val localIp: String?,
30
+ ) : WifiStatus {
31
+ override val state: String = "connected"
32
+ }
33
+
34
+ companion object {
35
+ internal fun fromMap(values: Map<String, Any>): WifiStatus? {
36
+ val wifiValues = (values["wifi"] as? Map<*, *>)?.stringKeyedMap() ?: values
37
+ return when (stringValue(wifiValues, "state")?.lowercase()) {
38
+ "connected" -> connectedFrom(wifiValues)
39
+ "disconnected" -> Disconnected
40
+ else -> null
41
+ }
42
+ }
43
+
44
+ internal fun fromStoreMap(values: Map<String, Any>): WifiStatus? {
45
+ val connected = boolValue(values, "wifiConnected") ?: return null
46
+ return fromStoreFields(
47
+ connected = connected,
48
+ ssid = stringValue(values, "wifiSsid"),
49
+ localIp = stringValue(values, "wifiLocalIp"),
50
+ )
51
+ }
52
+
53
+ internal fun fromStoreFields(connected: Boolean, ssid: String?, localIp: String?): WifiStatus? {
54
+ if (!connected) return Disconnected
55
+ val nonEmptySsid = ssid?.trim()?.takeIf { it.isNotEmpty() }
56
+ val nonEmptyLocalIp = localIp?.trim()?.takeIf { it.isNotEmpty() }
57
+ return nonEmptySsid?.let { Connected(it, nonEmptyLocalIp) }
58
+ }
59
+
60
+ private fun connectedFrom(values: Map<String, Any>): WifiStatus? =
61
+ fromStoreFields(
62
+ connected = true,
63
+ ssid = stringValue(values, "ssid"),
64
+ localIp = stringValue(values, "localIp"),
65
+ )
66
+ }
67
+ }
68
+
69
+ data class WifiStatusEvent(
70
+ val status: WifiStatus,
71
+ ) {
72
+ internal constructor(values: Map<String, Any>) : this(WifiStatus.fromMap(values) ?: WifiStatus.Disconnected)
73
+ internal constructor(connected: Boolean, ssid: String?, localIp: String?) : this(
74
+ WifiStatus.fromStoreFields(connected, ssid, localIp) ?: WifiStatus.Disconnected
75
+ )
76
+
77
+ val values: Map<String, Any> get() = status.toEventMap()
78
+ }
79
+
80
+ sealed interface HotspotStatus {
81
+ val state: String
82
+
83
+ fun toMap(): Map<String, Any> =
84
+ when (this) {
85
+ is Enabled ->
86
+ mapOf(
87
+ "state" to state,
88
+ "ssid" to ssid,
89
+ "password" to password,
90
+ "localIp" to localIp,
91
+ )
92
+ Disabled -> mapOf("state" to state)
93
+ }
94
+
95
+ fun toEventMap(): Map<String, Any> =
96
+ toMap() + mapOf("type" to "hotspot_status_change")
97
+
98
+ object Disabled : HotspotStatus {
99
+ override val state: String = "disabled"
100
+ }
101
+
102
+ data class Enabled(
103
+ val ssid: String,
104
+ val password: String,
105
+ val localIp: String,
106
+ ) : HotspotStatus {
107
+ override val state: String = "enabled"
108
+ }
109
+
110
+ companion object {
111
+ internal fun fromMap(values: Map<String, Any>): HotspotStatus? {
112
+ val hotspotValues = (values["hotspot"] as? Map<*, *>)?.stringKeyedMap() ?: values
113
+ return when (stringValue(hotspotValues, "state")?.lowercase()) {
114
+ "enabled" -> enabledFrom(hotspotValues)
115
+ "disabled" -> Disabled
116
+ else -> null
117
+ }
118
+ }
119
+
120
+ internal fun fromStoreMap(values: Map<String, Any>): HotspotStatus? {
121
+ val enabled = boolValue(values, "hotspotEnabled") ?: return null
122
+ return fromStoreFields(
123
+ enabled = enabled,
124
+ ssid = stringValue(values, "hotspotSsid"),
125
+ password = stringValue(values, "hotspotPassword"),
126
+ localIp = stringValue(values, "hotspotGatewayIp"),
127
+ )
128
+ }
129
+
130
+ internal fun fromStoreFields(
131
+ enabled: Boolean,
132
+ ssid: String?,
133
+ password: String?,
134
+ localIp: String?,
135
+ ): HotspotStatus? {
136
+ if (!enabled) return Disabled
137
+ val nonEmptySsid = ssid?.trim()?.takeIf { it.isNotEmpty() }
138
+ val nonEmptyPassword = password?.trim()?.takeIf { it.isNotEmpty() }
139
+ val nonEmptyLocalIp = localIp?.trim()?.takeIf { it.isNotEmpty() }
140
+ return if (nonEmptySsid != null && nonEmptyPassword != null && nonEmptyLocalIp != null) {
141
+ Enabled(nonEmptySsid, nonEmptyPassword, nonEmptyLocalIp)
142
+ } else {
143
+ null
144
+ }
145
+ }
146
+
147
+ private fun enabledFrom(values: Map<String, Any>): HotspotStatus? =
148
+ fromStoreFields(
149
+ enabled = true,
150
+ ssid = stringValue(values, "ssid"),
151
+ password = stringValue(values, "password"),
152
+ localIp = stringValue(values, "localIp"),
153
+ )
154
+ }
155
+ }
156
+
157
+ data class HotspotStatusEvent(
158
+ val status: HotspotStatus,
159
+ ) {
160
+ internal constructor(values: Map<String, Any>) : this(HotspotStatus.fromMap(values) ?: HotspotStatus.Disabled)
161
+ internal constructor(enabled: Boolean, ssid: String?, password: String?, localIp: String?) : this(
162
+ HotspotStatus.fromStoreFields(enabled, ssid, password, localIp) ?: HotspotStatus.Disabled
163
+ )
164
+
165
+ val values: Map<String, Any> get() = status.toEventMap()
166
+ }
167
+
168
+ data class HotspotErrorEvent(
169
+ val values: Map<String, Any>,
170
+ ) {
171
+ val message: String? get() = stringValue(values, "errorMessage")
172
+ val timestamp: Long? get() = longValue(values, "timestamp")
173
+ }