@mentra/bluetooth-sdk 0.1.12 → 0.1.14
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 +30 -11
- package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +47 -12
- package/android/src/main/java/com/mentra/bluetoothsdk/DeviceManager.kt +75 -29
- package/android/src/main/java/com/mentra/bluetoothsdk/DeviceStore.kt +1 -5
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +208 -45
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdkDebug.kt +14 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/ObservableStore.kt +20 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/OtaManifest.kt +153 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/camera/CameraModels.kt +80 -14
- package/android/src/main/java/com/mentra/bluetoothsdk/controllers/ControllerManager.kt +4 -16
- package/android/src/main/java/com/mentra/bluetoothsdk/controllers/R1.kt +4 -8
- package/android/src/main/java/com/mentra/bluetoothsdk/services/PhoneMic.kt +90 -4
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G1.kt +3831 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G2.kt +20 -28
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/{Mach1.java → Mach1.kt} +514 -561
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.kt +8674 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraNex.kt +12 -3
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/SGCManager.kt +5 -17
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Simulated.kt +9 -20
- package/android/src/main/java/com/mentra/bluetoothsdk/status/DeviceStatus.kt +0 -6
- package/android/src/main/java/com/mentra/bluetoothsdk/streaming/StreamModels.kt +16 -33
- package/build/BluetoothSdk.types.d.ts +48 -17
- package/build/BluetoothSdk.types.d.ts.map +1 -1
- package/build/BluetoothSdk.types.js.map +1 -1
- package/build/_private/BluetoothSdkModule.d.ts +9 -9
- package/build/_private/BluetoothSdkModule.d.ts.map +1 -1
- package/build/_private/BluetoothSdkModule.js +0 -6
- package/build/_private/BluetoothSdkModule.js.map +1 -1
- package/build/_private/photoRequestPayload.d.ts +3 -1
- package/build/_private/photoRequestPayload.d.ts.map +1 -1
- package/build/_private/photoRequestPayload.js +46 -2
- package/build/_private/photoRequestPayload.js.map +1 -1
- package/build/debug.d.ts +3 -0
- package/build/debug.d.ts.map +1 -0
- package/build/debug.js +8 -0
- package/build/debug.js.map +1 -0
- package/build/index.d.ts +1 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +8 -8
- package/build/index.js.map +1 -1
- package/ios/BluetoothSdkModule.swift +44 -68
- package/ios/Source/BluetoothSdkDefaults.swift +23 -3
- package/ios/Source/DeviceManager.swift +38 -33
- package/ios/Source/DeviceStore.swift +5 -5
- package/ios/Source/MentraBluetoothSDK.swift +217 -50
- package/ios/Source/MentraBluetoothSDKDebug.swift +12 -0
- package/ios/Source/ObservableStore.swift +11 -0
- package/ios/Source/OtaManifest.swift +170 -0
- package/ios/Source/camera/CameraModels.swift +219 -13
- package/ios/Source/controllers/ControllerManager.swift +3 -7
- package/ios/Source/controllers/R1.swift +3 -7
- package/ios/Source/sgcs/Frame.swift +0 -2
- package/ios/Source/sgcs/G1.swift +7 -8
- package/ios/Source/sgcs/G2.swift +21 -20
- package/ios/Source/sgcs/Mach1.swift +7 -8
- package/ios/Source/sgcs/MentraLive.swift +132 -63
- package/ios/Source/sgcs/MentraNex.swift +7 -8
- package/ios/Source/sgcs/SGCManager.swift +7 -10
- package/ios/Source/sgcs/Simulated.swift +8 -8
- package/ios/Source/status/DeviceStatus.swift +1 -9
- package/ios/Source/streaming/StreamModels.swift +7 -32
- package/package.json +6 -1
- package/src/BluetoothSdk.types.ts +49 -17
- package/src/_private/BluetoothSdkModule.ts +9 -17
- package/src/_private/photoRequestPayload.ts +48 -3
- package/src/debug.ts +9 -0
- package/src/index.ts +19 -10
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G1.java +0 -3974
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.java +0 -7434
|
@@ -1234,6 +1234,9 @@ class MentraLive: NSObject, SGCManager {
|
|
|
1234
1234
|
func getBatteryStatus() {}
|
|
1235
1235
|
func setBrightness(_: Int, autoMode _: Bool) {}
|
|
1236
1236
|
func clearDisplay() {}
|
|
1237
|
+
func sendText(_ text: String) async {
|
|
1238
|
+
await sendTextWall(text)
|
|
1239
|
+
}
|
|
1237
1240
|
func sendTextWall(_: String) async {}
|
|
1238
1241
|
func ping() {
|
|
1239
1242
|
Bridge.log("LIVE: ping()")
|
|
@@ -1611,18 +1614,15 @@ class MentraLive: NSObject, SGCManager {
|
|
|
1611
1614
|
}
|
|
1612
1615
|
}
|
|
1613
1616
|
|
|
1614
|
-
func requestPhoto(
|
|
1615
|
-
_ requestId: String, appId: String, size: String?, webhookUrl: String?, authToken: String?,
|
|
1616
|
-
compress: String?, flash: Bool, save: Bool, sound: Bool, exposureTimeNs: Double?, iso: Int?
|
|
1617
|
-
) {
|
|
1617
|
+
func requestPhoto(_ request: PhotoRequest) {
|
|
1618
1618
|
Bridge.log(
|
|
1619
|
-
"LIVE: PHOTO PIPELINE [5/6] requestPhoto() entry requestId=\(requestId) appId=\(appId)
|
|
1619
|
+
"LIVE: PHOTO PIPELINE [5/6] requestPhoto() entry requestId=\(request.requestId) appId=\(request.appId) save=\(request.save) sound=\(request.sound) iso=\(request.iso.map { String($0) } ?? "auto") aeDivisor=\(request.aeExposureDivisor.map { String($0) } ?? "nil")"
|
|
1620
1620
|
)
|
|
1621
1621
|
|
|
1622
1622
|
var json: [String: Any] = [
|
|
1623
1623
|
"type": "take_photo",
|
|
1624
|
-
"requestId": requestId,
|
|
1625
|
-
"appId": appId,
|
|
1624
|
+
"requestId": request.requestId,
|
|
1625
|
+
"appId": request.appId,
|
|
1626
1626
|
]
|
|
1627
1627
|
|
|
1628
1628
|
// Always generate BLE ID for potential fallback
|
|
@@ -1631,15 +1631,15 @@ class MentraLive: NSObject, SGCManager {
|
|
|
1631
1631
|
json["bleImgId"] = bleImgId
|
|
1632
1632
|
json["transferMethod"] = "auto"
|
|
1633
1633
|
|
|
1634
|
-
if let webhookUrl, !webhookUrl.isEmpty {
|
|
1634
|
+
if let webhookUrl = request.webhookUrl, !webhookUrl.isEmpty {
|
|
1635
1635
|
json["webhookUrl"] = webhookUrl
|
|
1636
1636
|
|
|
1637
1637
|
var transfer = BlePhotoTransfer(
|
|
1638
|
-
bleImgId: bleImgId, requestId: requestId, webhookUrl: webhookUrl
|
|
1638
|
+
bleImgId: bleImgId, requestId: request.requestId, webhookUrl: webhookUrl
|
|
1639
1639
|
)
|
|
1640
1640
|
|
|
1641
1641
|
// Store authToken for BLE transfer if provided
|
|
1642
|
-
if let authToken, !authToken.isEmpty {
|
|
1642
|
+
if let authToken = request.authToken, !authToken.isEmpty {
|
|
1643
1643
|
transfer.authToken = authToken
|
|
1644
1644
|
}
|
|
1645
1645
|
|
|
@@ -1647,32 +1647,27 @@ class MentraLive: NSObject, SGCManager {
|
|
|
1647
1647
|
}
|
|
1648
1648
|
|
|
1649
1649
|
// Add authToken to JSON if provided
|
|
1650
|
-
if let authToken, !authToken.isEmpty {
|
|
1650
|
+
if let authToken = request.authToken, !authToken.isEmpty {
|
|
1651
1651
|
json["authToken"] = authToken
|
|
1652
1652
|
}
|
|
1653
1653
|
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
} else {
|
|
1658
|
-
json["size"] = "medium"
|
|
1659
|
-
}
|
|
1660
|
-
|
|
1661
|
-
// Add compress parameter
|
|
1662
|
-
json["compress"] = compress ?? "none"
|
|
1654
|
+
let allowedSizes = ["low", "medium", "high", "max"]
|
|
1655
|
+
let size = request.size.rawValue
|
|
1656
|
+
json["size"] = allowedSizes.contains(size) ? size : "medium"
|
|
1663
1657
|
|
|
1664
|
-
json["
|
|
1665
|
-
json["save"] = save
|
|
1666
|
-
json["sound"] = sound
|
|
1658
|
+
json["compress"] = request.compress?.rawValue ?? "none"
|
|
1659
|
+
json["save"] = request.save
|
|
1660
|
+
json["sound"] = request.sound
|
|
1667
1661
|
|
|
1668
|
-
if let e = exposureTimeNs, e.isFinite, e > 0, e <= Double(Int64.max) {
|
|
1669
|
-
Bridge.log("LIVE: Using manual exposure time for photo request \(requestId): \(Int64(e)) ns")
|
|
1662
|
+
if let e = request.exposureTimeNs, e.isFinite, e > 0, e <= Double(Int64.max) {
|
|
1663
|
+
Bridge.log("LIVE: Using manual exposure time for photo request \(request.requestId): \(Int64(e)) ns")
|
|
1670
1664
|
json["exposureTimeNs"] = Int64(e)
|
|
1671
1665
|
}
|
|
1672
|
-
if let iso, iso > 0 {
|
|
1673
|
-
Bridge.log("LIVE: Using manual ISO for photo request \(requestId): ISO \(iso)")
|
|
1666
|
+
if let iso = request.iso, iso > 0 {
|
|
1667
|
+
Bridge.log("LIVE: Using manual ISO for photo request \(request.requestId): ISO \(iso)")
|
|
1674
1668
|
json["iso"] = iso
|
|
1675
1669
|
}
|
|
1670
|
+
request.appendScanFields(to: &json)
|
|
1676
1671
|
|
|
1677
1672
|
Bridge.log("LIVE: PHOTO PIPELINE [5b/6] take_photo JSON ready bleImgId=\(bleImgId) transferMethod=auto")
|
|
1678
1673
|
Bridge.log("LIVE: PHOTO PIPELINE [6/6] Dispatching take_photo to sendJson()")
|
|
@@ -2883,13 +2878,17 @@ class MentraLive: NSObject, SGCManager {
|
|
|
2883
2878
|
/// Send OTA start command to glasses.
|
|
2884
2879
|
/// Called when user approves an update (onboarding or background mode).
|
|
2885
2880
|
/// Triggers glasses to begin download and installation.
|
|
2886
|
-
func sendOtaStart() {
|
|
2881
|
+
func sendOtaStart(otaVersionUrl: String?) {
|
|
2887
2882
|
Bridge.log("LIVE: 📱 Sending ota_start command to glasses")
|
|
2888
2883
|
|
|
2889
|
-
|
|
2884
|
+
var json: [String: Any] = [
|
|
2890
2885
|
"type": "ota_start",
|
|
2891
2886
|
"timestamp": Int(Date().timeIntervalSince1970 * 1000),
|
|
2892
2887
|
]
|
|
2888
|
+
if let otaVersionUrl = otaVersionUrl?.trimmingCharacters(in: .whitespacesAndNewlines),
|
|
2889
|
+
!otaVersionUrl.isEmpty {
|
|
2890
|
+
json["ota_version_url"] = otaVersionUrl
|
|
2891
|
+
}
|
|
2893
2892
|
|
|
2894
2893
|
sendJson(json, wakeUp: true)
|
|
2895
2894
|
}
|
|
@@ -5085,9 +5084,6 @@ extension MentraLive {
|
|
|
5085
5084
|
// Send button photo settings
|
|
5086
5085
|
sendButtonPhotoSettings()
|
|
5087
5086
|
|
|
5088
|
-
// Send button camera LED setting
|
|
5089
|
-
sendButtonCameraLedSetting()
|
|
5090
|
-
|
|
5091
5087
|
// Send camera FOV setting (K900 / Mentra Live)
|
|
5092
5088
|
sendCameraFovSetting()
|
|
5093
5089
|
|
|
@@ -5197,12 +5193,75 @@ extension MentraLive {
|
|
|
5197
5193
|
}
|
|
5198
5194
|
|
|
5199
5195
|
func sendButtonPhotoSettings() {
|
|
5200
|
-
let size = DeviceStore.shared.get("bluetooth", "button_photo_size") as
|
|
5201
|
-
|
|
5196
|
+
let size = (DeviceStore.shared.get("bluetooth", "button_photo_size") as? String).flatMap { rawSize in
|
|
5197
|
+
rawSize.isEmpty ? nil : PhotoSize(normalizedRawValue: rawSize)
|
|
5198
|
+
}
|
|
5199
|
+
let mfnr = DeviceStore.shared.get("bluetooth", "button_photo_mfnr") as? Bool
|
|
5200
|
+
let zsl = DeviceStore.shared.get("bluetooth", "button_photo_zsl") as? Bool
|
|
5201
|
+
let noiseReduction = DeviceStore.shared.get("bluetooth", "button_photo_noise_reduction") as? Bool
|
|
5202
|
+
let edgeEnhancement = DeviceStore.shared.get("bluetooth", "button_photo_edge_enhancement") as? Bool
|
|
5203
|
+
let ispDigitalGain = DeviceStore.shared.get("bluetooth", "button_photo_isp_digital_gain") as? Int
|
|
5204
|
+
let ispAnalogGain = DeviceStore.shared.get("bluetooth", "button_photo_isp_analog_gain") as? String
|
|
5205
|
+
let aeExposureDivisor = DeviceStore.shared.get("bluetooth", "button_photo_ae_exposure_divisor") as? Int
|
|
5206
|
+
let isoCap = DeviceStore.shared.get("bluetooth", "button_photo_iso_cap") as? Int
|
|
5207
|
+
let compressStr = DeviceStore.shared.get("bluetooth", "button_photo_compress") as? String
|
|
5208
|
+
let sound = DeviceStore.shared.get("bluetooth", "button_photo_sound") as? Bool
|
|
5209
|
+
|
|
5210
|
+
let settings = PhotoCaptureDefaults(
|
|
5211
|
+
size: size,
|
|
5212
|
+
mfnr: mfnr,
|
|
5213
|
+
zsl: zsl,
|
|
5214
|
+
noiseReduction: noiseReduction,
|
|
5215
|
+
edgeEnhancement: edgeEnhancement,
|
|
5216
|
+
ispDigitalGain: ispDigitalGain,
|
|
5217
|
+
ispAnalogGain: ispAnalogGain,
|
|
5218
|
+
aeExposureDivisor: aeExposureDivisor,
|
|
5219
|
+
isoCap: isoCap,
|
|
5220
|
+
compress: compressStr,
|
|
5221
|
+
sound: sound,
|
|
5222
|
+
resetCaptureTuning: false
|
|
5223
|
+
)
|
|
5224
|
+
|
|
5225
|
+
sendButtonPhotoSettings(requestId: nil, settings: settings)
|
|
5202
5226
|
}
|
|
5203
5227
|
|
|
5204
5228
|
func sendButtonPhotoSettings(requestId: String?, size: String) {
|
|
5205
|
-
|
|
5229
|
+
sendButtonPhotoSettings(requestId: requestId, settings: PhotoCaptureDefaults(size: PhotoSize(normalizedRawValue: size)))
|
|
5230
|
+
}
|
|
5231
|
+
|
|
5232
|
+
func sendButtonPhotoSettings(requestId: String?, settings: PhotoCaptureDefaults) {
|
|
5233
|
+
var details = settings.size.map { "size=\($0.rawValue)" } ?? "size=unchanged"
|
|
5234
|
+
if let mfnr = settings.mfnr {
|
|
5235
|
+
details += ", mfnr=\(mfnr)"
|
|
5236
|
+
}
|
|
5237
|
+
if let zsl = settings.zsl {
|
|
5238
|
+
details += ", zsl=\(zsl)"
|
|
5239
|
+
}
|
|
5240
|
+
if let noiseReduction = settings.noiseReduction {
|
|
5241
|
+
details += ", noiseReduction=\(noiseReduction)"
|
|
5242
|
+
}
|
|
5243
|
+
if let edgeEnhancement = settings.edgeEnhancement {
|
|
5244
|
+
details += ", edgeEnhancement=\(edgeEnhancement)"
|
|
5245
|
+
}
|
|
5246
|
+
if let ispDigitalGain = settings.ispDigitalGain {
|
|
5247
|
+
details += ", ispDigitalGain=\(ispDigitalGain)"
|
|
5248
|
+
}
|
|
5249
|
+
if let ispAnalogGain = settings.ispAnalogGain {
|
|
5250
|
+
details += ", ispAnalogGain=\(ispAnalogGain)"
|
|
5251
|
+
}
|
|
5252
|
+
if let aeExposureDivisor = settings.aeExposureDivisor {
|
|
5253
|
+
details += ", aeExposureDivisor=\(aeExposureDivisor)"
|
|
5254
|
+
}
|
|
5255
|
+
if let isoCap = settings.isoCap {
|
|
5256
|
+
details += ", isoCap=\(isoCap)"
|
|
5257
|
+
}
|
|
5258
|
+
if let compress = settings.compress {
|
|
5259
|
+
details += ", compress=\(compress)"
|
|
5260
|
+
}
|
|
5261
|
+
if let sound = settings.sound {
|
|
5262
|
+
details += ", sound=\(sound)"
|
|
5263
|
+
}
|
|
5264
|
+
Bridge.log("Sending button photo setting: \(details)")
|
|
5206
5265
|
|
|
5207
5266
|
guard connectionState == ConnTypes.CONNECTED else {
|
|
5208
5267
|
Bridge.log("Cannot send button photo settings - not connected")
|
|
@@ -5211,33 +5270,45 @@ extension MentraLive {
|
|
|
5211
5270
|
|
|
5212
5271
|
var json: [String: Any] = [
|
|
5213
5272
|
"type": "button_photo_setting",
|
|
5214
|
-
"size": size,
|
|
5215
5273
|
]
|
|
5274
|
+
if let size = settings.size {
|
|
5275
|
+
json["size"] = size.rawValue
|
|
5276
|
+
}
|
|
5216
5277
|
if let requestId, !requestId.isEmpty {
|
|
5217
5278
|
json["request_id"] = requestId
|
|
5218
5279
|
}
|
|
5219
|
-
|
|
5220
|
-
|
|
5221
|
-
|
|
5222
|
-
func sendButtonCameraLedSetting() {
|
|
5223
|
-
let enabled = DeviceStore.shared.get("bluetooth", "button_camera_led") as! Bool
|
|
5224
|
-
sendButtonCameraLedSetting(requestId: nil, enabled: enabled)
|
|
5225
|
-
}
|
|
5226
|
-
|
|
5227
|
-
func sendButtonCameraLedSetting(requestId: String?, enabled: Bool) {
|
|
5228
|
-
Bridge.log("Sending button camera LED setting: \(enabled)")
|
|
5229
|
-
|
|
5230
|
-
guard connectionState == ConnTypes.CONNECTED else {
|
|
5231
|
-
Bridge.log("Cannot send button camera LED setting - not connected")
|
|
5232
|
-
return
|
|
5280
|
+
if let mfnr = settings.mfnr {
|
|
5281
|
+
json["mfnr"] = mfnr
|
|
5233
5282
|
}
|
|
5234
|
-
|
|
5235
|
-
|
|
5236
|
-
|
|
5237
|
-
|
|
5238
|
-
|
|
5239
|
-
|
|
5240
|
-
|
|
5283
|
+
if let zsl = settings.zsl {
|
|
5284
|
+
json["zsl"] = zsl
|
|
5285
|
+
}
|
|
5286
|
+
if let noiseReduction = settings.noiseReduction {
|
|
5287
|
+
json["noiseReduction"] = noiseReduction
|
|
5288
|
+
}
|
|
5289
|
+
if let edgeEnhancement = settings.edgeEnhancement {
|
|
5290
|
+
json["edgeEnhancement"] = edgeEnhancement
|
|
5291
|
+
}
|
|
5292
|
+
if let ispDigitalGain = settings.ispDigitalGain {
|
|
5293
|
+
json["ispDigitalGain"] = ispDigitalGain
|
|
5294
|
+
}
|
|
5295
|
+
if let ispAnalogGain = settings.ispAnalogGain, !ispAnalogGain.isEmpty {
|
|
5296
|
+
json["ispAnalogGain"] = ispAnalogGain
|
|
5297
|
+
}
|
|
5298
|
+
if let aeExposureDivisor = settings.aeExposureDivisor, aeExposureDivisor > 1 {
|
|
5299
|
+
json["aeExposureDivisor"] = aeExposureDivisor
|
|
5300
|
+
}
|
|
5301
|
+
if let isoCap = settings.isoCap, isoCap > 0 {
|
|
5302
|
+
json["isoCap"] = isoCap
|
|
5303
|
+
}
|
|
5304
|
+
if let compress = settings.compress, !compress.isEmpty {
|
|
5305
|
+
json["compress"] = compress
|
|
5306
|
+
}
|
|
5307
|
+
if let sound = settings.sound {
|
|
5308
|
+
json["sound"] = sound
|
|
5309
|
+
}
|
|
5310
|
+
if settings.resetCaptureTuning == true {
|
|
5311
|
+
json["resetCaptureTuning"] = true
|
|
5241
5312
|
}
|
|
5242
5313
|
sendJson(json, wakeUp: true)
|
|
5243
5314
|
}
|
|
@@ -5270,9 +5341,9 @@ extension MentraLive {
|
|
|
5270
5341
|
sendJson(json, wakeUp: true)
|
|
5271
5342
|
}
|
|
5272
5343
|
|
|
5273
|
-
func startVideoRecording(requestId: String, save: Bool,
|
|
5344
|
+
func startVideoRecording(requestId: String, save: Bool, sound: Bool) {
|
|
5274
5345
|
startVideoRecording(
|
|
5275
|
-
requestId: requestId, save: save,
|
|
5346
|
+
requestId: requestId, save: save, sound: sound, width: 0, height: 0, fps: 0,
|
|
5276
5347
|
maxRecordingTimeMinutes: 0
|
|
5277
5348
|
)
|
|
5278
5349
|
}
|
|
@@ -5284,11 +5355,11 @@ extension MentraLive {
|
|
|
5284
5355
|
}
|
|
5285
5356
|
|
|
5286
5357
|
func startVideoRecording(
|
|
5287
|
-
requestId: String, save: Bool,
|
|
5358
|
+
requestId: String, save: Bool, sound: Bool, width: Int, height: Int, fps: Int,
|
|
5288
5359
|
maxRecordingTimeMinutes: Int
|
|
5289
5360
|
) {
|
|
5290
5361
|
Bridge.log(
|
|
5291
|
-
"Starting video recording on glasses: requestId=\(requestId), save=\(save),
|
|
5362
|
+
"Starting video recording on glasses: requestId=\(requestId), save=\(save), sound=\(sound), resolution=\(width)x\(height)@\(fps)fps, maxRecordingTimeMinutes=\(maxRecordingTimeMinutes)"
|
|
5292
5363
|
)
|
|
5293
5364
|
|
|
5294
5365
|
guard connectionState == ConnTypes.CONNECTED else {
|
|
@@ -5300,10 +5371,8 @@ extension MentraLive {
|
|
|
5300
5371
|
"type": "start_video_recording",
|
|
5301
5372
|
"requestId": requestId,
|
|
5302
5373
|
"save": save,
|
|
5303
|
-
"flash": flash,
|
|
5304
5374
|
"sound": sound,
|
|
5305
5375
|
]
|
|
5306
|
-
|
|
5307
5376
|
// Auto-stop timer; only sent when set (> 0). 0 = record until stopped.
|
|
5308
5377
|
if maxRecordingTimeMinutes > 0 {
|
|
5309
5378
|
json["maxRecordingTimeMinutes"] = maxRecordingTimeMinutes
|
|
@@ -51,10 +51,7 @@ class MentraNexSGC: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate, SG
|
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
func requestPhoto(
|
|
55
|
-
_: String, appId _: String, size _: String?, webhookUrl _: String?, authToken _: String?,
|
|
56
|
-
compress _: String?, flash _: Bool, save _: Bool, sound _: Bool, exposureTimeNs _: Double?, iso _: Int?
|
|
57
|
-
) {}
|
|
54
|
+
func requestPhoto(_: PhotoRequest) {}
|
|
58
55
|
|
|
59
56
|
func startStream(_: [String: Any]) {}
|
|
60
57
|
|
|
@@ -62,7 +59,7 @@ class MentraNexSGC: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate, SG
|
|
|
62
59
|
|
|
63
60
|
func sendStreamKeepAlive(_: [String: Any]) {}
|
|
64
61
|
|
|
65
|
-
func startVideoRecording(requestId _: String, save _: Bool,
|
|
62
|
+
func startVideoRecording(requestId _: String, save _: Bool, sound _: Bool) {}
|
|
66
63
|
|
|
67
64
|
func stopVideoRecording(requestId _: String) {}
|
|
68
65
|
|
|
@@ -72,8 +69,6 @@ class MentraNexSGC: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate, SG
|
|
|
72
69
|
|
|
73
70
|
func sendButtonMaxRecordingTime() {}
|
|
74
71
|
|
|
75
|
-
func sendButtonCameraLedSetting() {}
|
|
76
|
-
|
|
77
72
|
func sendCameraFovSetting() {}
|
|
78
73
|
|
|
79
74
|
func setBrightness(_ level: Int, autoMode: Bool) {
|
|
@@ -81,6 +76,10 @@ class MentraNexSGC: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate, SG
|
|
|
81
76
|
updateGlassesAutoBrightness(autoMode)
|
|
82
77
|
}
|
|
83
78
|
|
|
79
|
+
func sendText(_ text: String) async {
|
|
80
|
+
await sendTextWall(text)
|
|
81
|
+
}
|
|
82
|
+
|
|
84
83
|
func sendDoubleTextWall(_ top: String, _ bottom: String) async {
|
|
85
84
|
await sendTextWall("\(top)\n\(bottom)")
|
|
86
85
|
}
|
|
@@ -178,7 +177,7 @@ class MentraNexSGC: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate, SG
|
|
|
178
177
|
|
|
179
178
|
func sendHotspotState(_: Bool) {}
|
|
180
179
|
|
|
181
|
-
func sendOtaStart() {}
|
|
180
|
+
func sendOtaStart(otaVersionUrl: String?) {}
|
|
182
181
|
func sendOtaQueryStatus() {}
|
|
183
182
|
|
|
184
183
|
func sendUserEmailToGlasses(_: String) {}
|
|
@@ -18,20 +18,17 @@ protocol SGCManager {
|
|
|
18
18
|
|
|
19
19
|
// MARK: - Camera & Media
|
|
20
20
|
|
|
21
|
-
func requestPhoto(
|
|
22
|
-
_ requestId: String, appId: String, size: String?, webhookUrl: String?, authToken: String?,
|
|
23
|
-
compress: String?, flash: Bool, save: Bool, sound: Bool, exposureTimeNs: Double?, iso: Int?
|
|
24
|
-
)
|
|
21
|
+
func requestPhoto(_ request: PhotoRequest)
|
|
25
22
|
func startStream(_ message: [String: Any])
|
|
26
23
|
func stopStream()
|
|
27
24
|
func sendStreamKeepAlive(_ message: [String: Any])
|
|
28
|
-
func startVideoRecording(requestId: String, save: Bool,
|
|
25
|
+
func startVideoRecording(requestId: String, save: Bool, sound: Bool)
|
|
29
26
|
/// Start video recording with optional per-recording resolution/fps. A width,
|
|
30
27
|
/// height, or fps of 0 means "use the device's saved button-video default".
|
|
31
28
|
/// Defaulted in an extension to delegate to the basic recording path; devices
|
|
32
29
|
/// that support custom settings (e.g. Mentra Live) override this.
|
|
33
30
|
func startVideoRecording(
|
|
34
|
-
requestId: String, save: Bool,
|
|
31
|
+
requestId: String, save: Bool, sound: Bool, width: Int, height: Int, fps: Int,
|
|
35
32
|
maxRecordingTimeMinutes: Int
|
|
36
33
|
)
|
|
37
34
|
func stopVideoRecording(requestId: String)
|
|
@@ -47,13 +44,13 @@ protocol SGCManager {
|
|
|
47
44
|
func sendButtonPhotoSettings()
|
|
48
45
|
func sendButtonVideoRecordingSettings()
|
|
49
46
|
func sendButtonMaxRecordingTime()
|
|
50
|
-
func sendButtonCameraLedSetting()
|
|
51
47
|
func sendCameraFovSetting()
|
|
52
48
|
|
|
53
49
|
// MARK: - Display Control
|
|
54
50
|
|
|
55
51
|
func setBrightness(_ level: Int, autoMode: Bool)
|
|
56
52
|
func clearDisplay()
|
|
53
|
+
func sendText(_ text: String) async
|
|
57
54
|
func sendTextWall(_ text: String) async
|
|
58
55
|
func sendDoubleTextWall(_ top: String, _ bottom: String) async
|
|
59
56
|
/// Display a bitmap. Optional `x`/`y`/`width`/`height` position and size the target
|
|
@@ -118,7 +115,7 @@ protocol SGCManager {
|
|
|
118
115
|
func sendWifiCredentials(_ ssid: String, _ password: String)
|
|
119
116
|
func forgetWifiNetwork(_ ssid: String)
|
|
120
117
|
func sendHotspotState(_ enabled: Bool)
|
|
121
|
-
func sendOtaStart()
|
|
118
|
+
func sendOtaStart(otaVersionUrl: String?)
|
|
122
119
|
func sendOtaQueryStatus()
|
|
123
120
|
func sendSetSystemTime(_ timestampMs: Int64)
|
|
124
121
|
func sendOtaRetryVersionCheck()
|
|
@@ -151,10 +148,10 @@ extension SGCManager {
|
|
|
151
148
|
// MARK: - Video recording (default: ignore custom settings, use saved defaults)
|
|
152
149
|
|
|
153
150
|
func startVideoRecording(
|
|
154
|
-
requestId: String, save: Bool,
|
|
151
|
+
requestId: String, save: Bool, sound: Bool, width _: Int, height _: Int,
|
|
155
152
|
fps _: Int, maxRecordingTimeMinutes _: Int
|
|
156
153
|
) {
|
|
157
|
-
startVideoRecording(requestId: requestId, save: save,
|
|
154
|
+
startVideoRecording(requestId: requestId, save: save, sound: sound)
|
|
158
155
|
}
|
|
159
156
|
|
|
160
157
|
func stopVideoRecording(requestId: String, webhookUrl _: String?, authToken _: String?) {
|
|
@@ -79,8 +79,8 @@ class Simulated: SGCManager {
|
|
|
79
79
|
|
|
80
80
|
// MARK: - Camera & Media
|
|
81
81
|
|
|
82
|
-
func requestPhoto(_
|
|
83
|
-
Bridge.log("requestPhoto")
|
|
82
|
+
func requestPhoto(_ request: PhotoRequest) {
|
|
83
|
+
Bridge.log("requestPhoto save=\(request.save) sound=\(request.sound)")
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
func startStream(_: [String: Any]) {
|
|
@@ -95,7 +95,7 @@ class Simulated: SGCManager {
|
|
|
95
95
|
Bridge.log("sendStreamKeepAlive")
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
func startVideoRecording(requestId _: String, save _: Bool,
|
|
98
|
+
func startVideoRecording(requestId _: String, save _: Bool, sound _: Bool) {
|
|
99
99
|
Bridge.log("startVideoRecording")
|
|
100
100
|
}
|
|
101
101
|
|
|
@@ -113,10 +113,6 @@ class Simulated: SGCManager {
|
|
|
113
113
|
Bridge.log("sendButtonVideoRecordingSettings")
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
func sendButtonCameraLedSetting() {
|
|
117
|
-
Bridge.log("sendButtonCameraLedSetting")
|
|
118
|
-
}
|
|
119
|
-
|
|
120
116
|
func sendCameraFovSetting() {
|
|
121
117
|
Bridge.log("sendCameraFovSetting")
|
|
122
118
|
}
|
|
@@ -133,6 +129,10 @@ class Simulated: SGCManager {
|
|
|
133
129
|
Bridge.log("clearDisplay")
|
|
134
130
|
}
|
|
135
131
|
|
|
132
|
+
func sendText(_ text: String) async {
|
|
133
|
+
await sendTextWall(text)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
136
|
func sendTextWall(_: String) async {
|
|
137
137
|
Bridge.log("sendTextWall")
|
|
138
138
|
}
|
|
@@ -246,7 +246,7 @@ class Simulated: SGCManager {
|
|
|
246
246
|
Bridge.log("sendUserEmailToGlasses: \(email)")
|
|
247
247
|
}
|
|
248
248
|
|
|
249
|
-
func sendOtaStart() {
|
|
249
|
+
func sendOtaStart(otaVersionUrl: String?) {
|
|
250
250
|
Bridge.log("sendOtaStart")
|
|
251
251
|
}
|
|
252
252
|
|
|
@@ -552,10 +552,6 @@ struct BluetoothStatus: CustomStringConvertible {
|
|
|
552
552
|
ButtonPhotoSize(rawValue: stringValue(values, "button_photo_size") ?? "") ?? .medium
|
|
553
553
|
}
|
|
554
554
|
|
|
555
|
-
var buttonCameraLed: Bool {
|
|
556
|
-
boolValue(values, "button_camera_led") ?? true
|
|
557
|
-
}
|
|
558
|
-
|
|
559
555
|
var buttonMaxRecordingTime: Int {
|
|
560
556
|
intValue(values["button_max_recording_time"]) ?? 10
|
|
561
557
|
}
|
|
@@ -921,11 +917,7 @@ struct BluetoothStatusUpdate: CustomStringConvertible {
|
|
|
921
917
|
}
|
|
922
918
|
|
|
923
919
|
var buttonPhotoSize: ButtonPhotoSize? {
|
|
924
|
-
optionalStringValue(values, "button_photo_size").
|
|
925
|
-
}
|
|
926
|
-
|
|
927
|
-
var buttonCameraLed: Bool? {
|
|
928
|
-
optionalBoolValue(values, "button_camera_led")
|
|
920
|
+
optionalStringValue(values, "button_photo_size").map { ButtonPhotoSize(normalizedRawValue: $0) }
|
|
929
921
|
}
|
|
930
922
|
|
|
931
923
|
var buttonMaxRecordingTime: Int? {
|
|
@@ -23,6 +23,7 @@ public struct StreamVideoConfig {
|
|
|
23
23
|
if let width { values["width"] = width }
|
|
24
24
|
if let height { values["height"] = height }
|
|
25
25
|
if let bitrate { values["bitrate"] = bitrate }
|
|
26
|
+
// ASG stream parsers shipped with the BLE key named "frameRate".
|
|
26
27
|
if let fps { values["frameRate"] = fps }
|
|
27
28
|
return values
|
|
28
29
|
}
|
|
@@ -219,31 +220,22 @@ public struct StreamResolvedConfig: Equatable {
|
|
|
219
220
|
public struct StreamRequest {
|
|
220
221
|
public let streamUrl: String
|
|
221
222
|
public let streamId: String
|
|
222
|
-
public let keepAlive: Bool
|
|
223
|
-
public let keepAliveIntervalSeconds: Int
|
|
224
223
|
public let sound: Bool
|
|
225
224
|
public let video: StreamVideoConfig?
|
|
226
225
|
public let audio: StreamAudioConfig?
|
|
227
|
-
public let extraValues: [String: Any]
|
|
228
226
|
|
|
229
227
|
public init(
|
|
230
228
|
streamUrl: String,
|
|
231
229
|
streamId: String = "",
|
|
232
|
-
keepAlive: Bool = true,
|
|
233
|
-
keepAliveIntervalSeconds: Int = 5,
|
|
234
230
|
sound: Bool = true,
|
|
235
231
|
video: StreamVideoConfig? = nil,
|
|
236
|
-
audio: StreamAudioConfig? = nil
|
|
237
|
-
extraValues: [String: Any] = [:]
|
|
232
|
+
audio: StreamAudioConfig? = nil
|
|
238
233
|
) {
|
|
239
234
|
self.streamUrl = streamUrl
|
|
240
235
|
self.streamId = streamId
|
|
241
|
-
self.keepAlive = keepAlive
|
|
242
|
-
self.keepAliveIntervalSeconds = keepAliveIntervalSeconds
|
|
243
236
|
self.sound = sound
|
|
244
237
|
self.video = video
|
|
245
238
|
self.audio = audio
|
|
246
|
-
self.extraValues = extraValues
|
|
247
239
|
}
|
|
248
240
|
|
|
249
241
|
init(values: [String: Any]) {
|
|
@@ -254,25 +246,17 @@ public struct StreamRequest {
|
|
|
254
246
|
?? values["whipUrl"] as? String
|
|
255
247
|
?? "",
|
|
256
248
|
streamId: values["streamId"] as? String ?? "",
|
|
257
|
-
keepAlive: values["keepAlive"] as? Bool ?? true,
|
|
258
|
-
keepAliveIntervalSeconds: intValue(values["keepAliveIntervalSeconds"]) ?? 5,
|
|
259
249
|
sound: values["sound"] as? Bool ?? true,
|
|
260
250
|
video: StreamVideoConfig(values: values["video"] as? [String: Any]),
|
|
261
|
-
audio: StreamAudioConfig(values: values["audio"] as? [String: Any])
|
|
262
|
-
extraValues: values
|
|
251
|
+
audio: StreamAudioConfig(values: values["audio"] as? [String: Any])
|
|
263
252
|
)
|
|
264
253
|
}
|
|
265
254
|
|
|
266
255
|
public var values: [String: Any] {
|
|
267
|
-
var values =
|
|
268
|
-
values.removeValue(forKey: "keepAliveMode")
|
|
256
|
+
var values: [String: Any] = [:]
|
|
269
257
|
values["type"] = "start_stream"
|
|
270
258
|
values["streamUrl"] = streamUrl
|
|
271
259
|
values["streamId"] = streamId
|
|
272
|
-
values["keepAlive"] = keepAlive
|
|
273
|
-
values["keepAliveIntervalSeconds"] = keepAliveIntervalSeconds
|
|
274
|
-
// The camera light is a privacy indicator and cannot be disabled by SDK callers.
|
|
275
|
-
values["flash"] = true
|
|
276
260
|
values["sound"] = sound
|
|
277
261
|
if let videoValues = video?.dictionary, !videoValues.isEmpty {
|
|
278
262
|
values["video"] = videoValues
|
|
@@ -284,33 +268,24 @@ public struct StreamRequest {
|
|
|
284
268
|
}
|
|
285
269
|
}
|
|
286
270
|
|
|
287
|
-
extension StreamRequest {
|
|
288
|
-
var isExternallyManagedKeepAlive: Bool {
|
|
289
|
-
stringValue(extraValues, "keepAliveMode") == "external"
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
271
|
struct StreamKeepAliveRequest {
|
|
294
272
|
let streamId: String
|
|
295
273
|
let ackId: String
|
|
296
|
-
let extraValues: [String: Any]
|
|
297
274
|
|
|
298
|
-
init(streamId: String, ackId: String
|
|
275
|
+
init(streamId: String, ackId: String) {
|
|
299
276
|
self.streamId = streamId
|
|
300
277
|
self.ackId = ackId
|
|
301
|
-
self.extraValues = extraValues
|
|
302
278
|
}
|
|
303
279
|
|
|
304
280
|
init(values: [String: Any]) {
|
|
305
281
|
self.init(
|
|
306
282
|
streamId: values["streamId"] as? String ?? "",
|
|
307
|
-
ackId: values["ackId"] as? String ?? ""
|
|
308
|
-
extraValues: values
|
|
283
|
+
ackId: values["ackId"] as? String ?? ""
|
|
309
284
|
)
|
|
310
285
|
}
|
|
311
286
|
|
|
312
287
|
var values: [String: Any] {
|
|
313
|
-
var values =
|
|
288
|
+
var values: [String: Any] = [:]
|
|
314
289
|
values["type"] = "keep_stream_alive"
|
|
315
290
|
values["streamId"] = streamId
|
|
316
291
|
values["ackId"] = ackId
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mentra/bluetooth-sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.14",
|
|
4
4
|
"description": "SDK for communicating with smart glasses",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"react-native": "src/index.ts",
|
|
@@ -22,6 +22,11 @@
|
|
|
22
22
|
"react-native": "./src/photo-receiver/index.ts",
|
|
23
23
|
"default": "./build/photo-receiver/index.js"
|
|
24
24
|
},
|
|
25
|
+
"./debug": {
|
|
26
|
+
"types": "./build/debug.d.ts",
|
|
27
|
+
"react-native": "./src/debug.ts",
|
|
28
|
+
"default": "./build/debug.js"
|
|
29
|
+
},
|
|
25
30
|
"./_private/*": null,
|
|
26
31
|
"./build/*": null,
|
|
27
32
|
"./src/*": null,
|