@mentra/bluetooth-sdk 0.1.6 → 0.1.8
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 +26 -22
- package/android/.project +28 -0
- package/android/build.gradle +5 -9
- package/android/lc3Lib/.project +28 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +54 -33
- package/android/src/main/java/com/mentra/bluetoothsdk/Bridge.kt +48 -10
- package/android/src/main/java/com/mentra/bluetoothsdk/DeviceManager.kt +27 -36
- package/android/src/main/java/com/mentra/bluetoothsdk/DeviceStore.kt +8 -4
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +170 -14
- package/android/src/main/java/com/mentra/bluetoothsdk/audio/AudioModels.kt +6 -6
- package/android/src/main/java/com/mentra/bluetoothsdk/camera/CameraModels.kt +69 -10
- package/android/src/main/java/com/mentra/bluetoothsdk/controllers/ControllerManager.kt +5 -3
- package/android/src/main/java/com/mentra/bluetoothsdk/controllers/R1.kt +2 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/debug/BleTraceLogger.kt +149 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/events/BluetoothEvents.kt +13 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/photoreceiver/LocalPhotoUploadServer.kt +297 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/photoreceiver/MentraPhotoReceiverModule.kt +120 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/services/Foreground.kt +13 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G1.java +1 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G2.kt +3 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Mach1.java +1 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.java +269 -28
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraNex.kt +1 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/SGCManager.kt +8 -3
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Simulated.kt +4 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/status/DeviceStatus.kt +14 -12
- package/android/src/main/java/com/mentra/bluetoothsdk/status/RuntimeState.kt +4 -2
- package/android/src/main/java/com/mentra/bluetoothsdk/streaming/StreamModels.kt +131 -6
- package/android/src/main/java/com/mentra/bluetoothsdk/stt/SherpaOnnxTranscriber.kt +1 -3
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/MessageChunkReassembler.java +105 -0
- package/build/BluetoothSdk.types.d.ts +107 -48
- package/build/BluetoothSdk.types.d.ts.map +1 -1
- package/build/BluetoothSdk.types.js +4 -0
- package/build/BluetoothSdk.types.js.map +1 -1
- package/build/_private/BluetoothSdkModule.d.ts +8 -6
- package/build/_private/BluetoothSdkModule.d.ts.map +1 -1
- package/build/_private/BluetoothSdkModule.js +58 -9
- package/build/_private/BluetoothSdkModule.js.map +1 -1
- package/build/index.d.ts +2 -2
- package/build/index.d.ts.map +1 -1
- package/build/index.js +6 -5
- package/build/index.js.map +1 -1
- package/build/photo-receiver/MentraPhotoReceiver.types.d.ts +18 -0
- package/build/photo-receiver/MentraPhotoReceiver.types.d.ts.map +1 -0
- package/build/photo-receiver/MentraPhotoReceiver.types.js +2 -0
- package/build/photo-receiver/MentraPhotoReceiver.types.js.map +1 -0
- package/build/photo-receiver/MentraPhotoReceiverModule.d.ts +10 -0
- package/build/photo-receiver/MentraPhotoReceiverModule.d.ts.map +1 -0
- package/build/photo-receiver/MentraPhotoReceiverModule.js +3 -0
- package/build/photo-receiver/MentraPhotoReceiverModule.js.map +1 -0
- package/build/photo-receiver/MentraPhotoReceiverModule.web.d.ts +10 -0
- package/build/photo-receiver/MentraPhotoReceiverModule.web.d.ts.map +1 -0
- package/build/photo-receiver/MentraPhotoReceiverModule.web.js +12 -0
- package/build/photo-receiver/MentraPhotoReceiverModule.web.js.map +1 -0
- package/build/photo-receiver/index.d.ts +3 -0
- package/build/photo-receiver/index.d.ts.map +1 -0
- package/build/photo-receiver/index.js +3 -0
- package/build/photo-receiver/index.js.map +1 -0
- package/build/react/useMentraBluetooth.d.ts +5 -3
- package/build/react/useMentraBluetooth.d.ts.map +1 -1
- package/build/react/useMentraBluetooth.js +15 -4
- package/build/react/useMentraBluetooth.js.map +1 -1
- package/expo-module.config.json +5 -2
- package/ios/BluetoothSdkModule.swift +59 -26
- package/ios/LocalPhotoUploadServer.swift +411 -0
- package/ios/MentraBluetoothSDK.podspec +8 -5
- package/ios/MentraPhotoReceiverModule.swift +147 -0
- package/ios/Source/Audio/AudioModels.swift +10 -10
- package/ios/Source/Bridge.swift +42 -12
- package/ios/Source/Camera/CameraModels.swift +74 -19
- package/ios/Source/DeviceManager.swift +23 -98
- package/ios/Source/DeviceStore.swift +12 -4
- package/ios/Source/Events/BluetoothEvents.swift +37 -0
- package/ios/Source/MentraBluetoothSDK.swift +135 -14
- package/ios/Source/Status/DeviceStatus.swift +12 -4
- package/ios/Source/Status/RuntimeState.swift +22 -13
- package/ios/Source/Streaming/StreamModels.swift +239 -45
- package/ios/Source/controllers/ControllerManager.swift +3 -3
- package/ios/Source/controllers/R1.swift +9 -3
- package/ios/Source/sgcs/G1.swift +5 -4
- package/ios/Source/sgcs/G2.swift +5 -6
- package/ios/Source/sgcs/Mach1.swift +1 -1
- package/ios/Source/sgcs/MentraLive.swift +183 -22
- package/ios/Source/sgcs/MentraNex.swift +1 -1
- package/ios/Source/sgcs/SGCManager.swift +11 -3
- package/ios/Source/sgcs/Simulated.swift +2 -2
- package/ios/Source/stt/SherpaOnnxTranscriber.swift +1 -4
- package/ios/Source/utils/MessageChunkReassembler.swift +89 -0
- package/package.json +6 -1
- package/src/BluetoothSdk.types.ts +133 -62
- package/src/_private/BluetoothSdkModule.ts +79 -26
- package/src/index.ts +15 -8
- package/src/photo-receiver/MentraPhotoReceiver.types.ts +20 -0
- package/src/photo-receiver/MentraPhotoReceiverModule.ts +14 -0
- package/src/photo-receiver/MentraPhotoReceiverModule.web.ts +20 -0
- package/src/photo-receiver/index.ts +2 -0
- package/src/react/useMentraBluetooth.ts +19 -7
- package/android/src/main/java/com/mentra/bluetoothsdk/stt/VadGateSpeechPolicy.kt +0 -221
- package/ios/Packages/VAD/Common/VAD/VADQuality.swift +0 -41
- package/ios/Packages/VAD/Common/VAD/VADState.swift +0 -26
- package/ios/Packages/VAD/Common/VAD/VADStrategy.swift +0 -29
- package/ios/Packages/VAD/Common/VAD/VADType.swift +0 -14
- package/ios/Packages/VAD/Data/Configuration.swift +0 -68
- package/ios/Packages/VAD/Data/FrameSize.swift +0 -39
- package/ios/Packages/VAD/Data/Record.swift +0 -13
- package/ios/Packages/VAD/Data/Result.swift +0 -22
- package/ios/Packages/VAD/Data/SampleRate.swift +0 -48
- package/ios/Packages/VAD/Silero/Model/silero_vad.onnx +0 -0
- package/ios/Packages/VAD/Silero/SileroVAD.swift +0 -284
- package/ios/Packages/VAD/Silero/SileroVADStrategy.swift +0 -64
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
import CoreBluetooth
|
|
2
2
|
import Foundation
|
|
3
3
|
|
|
4
|
+
@MainActor
|
|
5
|
+
private final class ActiveStreamKeepAlive {
|
|
6
|
+
let streamId: String
|
|
7
|
+
let intervalSeconds: Int
|
|
8
|
+
var pendingAckId: String?
|
|
9
|
+
var missedAckCount = 0
|
|
10
|
+
var task: Task<Void, Never>?
|
|
11
|
+
|
|
12
|
+
init(streamId: String, intervalSeconds: Int) {
|
|
13
|
+
self.streamId = streamId
|
|
14
|
+
self.intervalSeconds = intervalSeconds
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
4
18
|
@MainActor
|
|
5
19
|
private final class ActiveScanSession {
|
|
6
20
|
let model: DeviceModel
|
|
@@ -33,6 +47,7 @@ public final class MentraBluetoothSDK {
|
|
|
33
47
|
private var suppressDefaultDeviceEvents = false
|
|
34
48
|
private var defaultDeviceApplyGeneration = 0
|
|
35
49
|
private var activeScanSessions: [UUID: ActiveScanSession] = [:]
|
|
50
|
+
private var activeStreamKeepAlive: ActiveStreamKeepAlive?
|
|
36
51
|
|
|
37
52
|
public init(configuration: MentraBluetoothSDKConfiguration = .default) {
|
|
38
53
|
self.configuration = configuration
|
|
@@ -268,8 +283,12 @@ public final class MentraBluetoothSDK {
|
|
|
268
283
|
DeviceStore.shared.apply(ObservableStore.bluetoothCategory, "screen_disabled", disabled)
|
|
269
284
|
}
|
|
270
285
|
|
|
271
|
-
public func
|
|
272
|
-
DeviceStore.shared.apply(ObservableStore.bluetoothCategory, "
|
|
286
|
+
public func setGalleryModeEnabled(_ enabled: Bool) async throws {
|
|
287
|
+
DeviceStore.shared.apply(ObservableStore.bluetoothCategory, "gallery_mode", enabled)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
public func setVoiceActivityDetectionEnabled(_ enabled: Bool) async throws {
|
|
291
|
+
DeviceStore.shared.apply(ObservableStore.bluetoothCategory, "voice_activity_detection_enabled", enabled)
|
|
273
292
|
}
|
|
274
293
|
|
|
275
294
|
public func setButtonPhotoSettings(size: ButtonPhotoSize) async throws {
|
|
@@ -280,14 +299,14 @@ public final class MentraBluetoothSDK {
|
|
|
280
299
|
try await setButtonPhotoSettings(size: settings.size)
|
|
281
300
|
}
|
|
282
301
|
|
|
283
|
-
public func setButtonVideoRecordingSettings(width: Int, height: Int,
|
|
302
|
+
public func setButtonVideoRecordingSettings(width: Int, height: Int, fps: Int) async throws {
|
|
284
303
|
DeviceStore.shared.apply(ObservableStore.bluetoothCategory, "button_video_width", width)
|
|
285
304
|
DeviceStore.shared.apply(ObservableStore.bluetoothCategory, "button_video_height", height)
|
|
286
|
-
DeviceStore.shared.apply(ObservableStore.bluetoothCategory, "button_video_fps",
|
|
305
|
+
DeviceStore.shared.apply(ObservableStore.bluetoothCategory, "button_video_fps", fps)
|
|
287
306
|
}
|
|
288
307
|
|
|
289
308
|
public func setButtonVideoRecordingSettings(_ settings: ButtonVideoRecordingSettings) async throws {
|
|
290
|
-
try await setButtonVideoRecordingSettings(width: settings.width, height: settings.height,
|
|
309
|
+
try await setButtonVideoRecordingSettings(width: settings.width, height: settings.height, fps: settings.fps)
|
|
291
310
|
}
|
|
292
311
|
|
|
293
312
|
public func setButtonCameraLed(enabled: Bool) async throws {
|
|
@@ -305,7 +324,6 @@ public final class MentraBluetoothSDK {
|
|
|
305
324
|
public func setMicState(
|
|
306
325
|
enabled: Bool,
|
|
307
326
|
useGlassesMic: Bool = true,
|
|
308
|
-
bypassVad: Bool = true,
|
|
309
327
|
sendTranscript: Bool = false,
|
|
310
328
|
sendLc3Data: Bool = false
|
|
311
329
|
) {
|
|
@@ -319,7 +337,6 @@ public final class MentraBluetoothSDK {
|
|
|
319
337
|
applyMicState(
|
|
320
338
|
sendPcmData: enabled,
|
|
321
339
|
sendTranscript: enabled && sendTranscript,
|
|
322
|
-
bypassVad: bypassVad,
|
|
323
340
|
sendLc3Data: enabled && sendLc3Data
|
|
324
341
|
)
|
|
325
342
|
}
|
|
@@ -327,13 +344,11 @@ public final class MentraBluetoothSDK {
|
|
|
327
344
|
private func applyMicState(
|
|
328
345
|
sendPcmData: Bool,
|
|
329
346
|
sendTranscript: Bool,
|
|
330
|
-
bypassVad: Bool,
|
|
331
347
|
sendLc3Data: Bool
|
|
332
348
|
) {
|
|
333
349
|
DeviceStore.shared.apply(ObservableStore.bluetoothCategory, "should_send_pcm", sendPcmData)
|
|
334
350
|
DeviceStore.shared.apply(ObservableStore.bluetoothCategory, "should_send_lc3", sendLc3Data)
|
|
335
351
|
DeviceStore.shared.apply(ObservableStore.bluetoothCategory, "should_send_transcript", sendTranscript)
|
|
336
|
-
DeviceStore.shared.apply(ObservableStore.bluetoothCategory, "bypass_vad", bypassVad)
|
|
337
352
|
DeviceManager.shared.setMicState()
|
|
338
353
|
}
|
|
339
354
|
|
|
@@ -376,6 +391,9 @@ public final class MentraBluetoothSDK {
|
|
|
376
391
|
}
|
|
377
392
|
|
|
378
393
|
public func requestPhoto(_ request: PhotoRequest) {
|
|
394
|
+
Bridge.log(
|
|
395
|
+
"NATIVE: PHOTO PIPELINE [3b/6] MentraBluetoothSdk.requestPhoto requestId=\(request.requestId) appId=\(request.appId)"
|
|
396
|
+
)
|
|
379
397
|
DeviceManager.shared.requestPhoto(
|
|
380
398
|
request.requestId,
|
|
381
399
|
request.appId,
|
|
@@ -383,7 +401,10 @@ public final class MentraBluetoothSDK {
|
|
|
383
401
|
request.webhookUrl,
|
|
384
402
|
request.authToken,
|
|
385
403
|
request.compress?.rawValue,
|
|
386
|
-
request.
|
|
404
|
+
request.flash,
|
|
405
|
+
request.sound,
|
|
406
|
+
exposureTimeNs: request.exposureTimeNs,
|
|
407
|
+
iso: request.iso
|
|
387
408
|
)
|
|
388
409
|
}
|
|
389
410
|
|
|
@@ -392,10 +413,17 @@ public final class MentraBluetoothSDK {
|
|
|
392
413
|
}
|
|
393
414
|
|
|
394
415
|
public func startStream(_ request: StreamRequest) {
|
|
395
|
-
|
|
416
|
+
var values = request.values
|
|
417
|
+
let streamId = stringValue(values, "streamId").flatMap { $0.isEmpty ? nil : $0 } ?? "sdk-\(UUID().uuidString)"
|
|
418
|
+
values["streamId"] = streamId
|
|
419
|
+
stopStreamKeepAliveMonitor()
|
|
420
|
+
DeviceManager.shared.startStream(values)
|
|
421
|
+
if request.keepAlive, !request.isExternallyManagedKeepAlive {
|
|
422
|
+
startStreamKeepAliveMonitor(streamId: streamId, intervalSeconds: request.keepAliveIntervalSeconds)
|
|
423
|
+
}
|
|
396
424
|
}
|
|
397
425
|
|
|
398
|
-
|
|
426
|
+
func sendCloudStreamKeepAlive(_ request: StreamKeepAliveRequest) {
|
|
399
427
|
DeviceManager.shared.keepStreamAlive(request.values)
|
|
400
428
|
}
|
|
401
429
|
|
|
@@ -412,6 +440,7 @@ public final class MentraBluetoothSDK {
|
|
|
412
440
|
}
|
|
413
441
|
|
|
414
442
|
public func stopStream() {
|
|
443
|
+
stopStreamKeepAliveMonitor()
|
|
415
444
|
DeviceManager.shared.stopStream()
|
|
416
445
|
}
|
|
417
446
|
|
|
@@ -452,6 +481,7 @@ public final class MentraBluetoothSDK {
|
|
|
452
481
|
}
|
|
453
482
|
|
|
454
483
|
public func invalidate() {
|
|
484
|
+
stopStreamKeepAliveMonitor()
|
|
455
485
|
if let bridgeEventSinkId {
|
|
456
486
|
Bridge.removeEventSink(bridgeEventSinkId)
|
|
457
487
|
self.bridgeEventSinkId = nil
|
|
@@ -463,6 +493,80 @@ public final class MentraBluetoothSDK {
|
|
|
463
493
|
delegate = nil
|
|
464
494
|
}
|
|
465
495
|
|
|
496
|
+
private func startStreamKeepAliveMonitor(streamId: String, intervalSeconds requestedIntervalSeconds: Int) {
|
|
497
|
+
let intervalSeconds = requestedIntervalSeconds > 0 ? requestedIntervalSeconds : 5
|
|
498
|
+
let tracker = ActiveStreamKeepAlive(streamId: streamId, intervalSeconds: intervalSeconds)
|
|
499
|
+
activeStreamKeepAlive = tracker
|
|
500
|
+
sendNextStreamKeepAlive(for: tracker)
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
private func stopStreamKeepAliveMonitor() {
|
|
504
|
+
activeStreamKeepAlive?.task?.cancel()
|
|
505
|
+
activeStreamKeepAlive = nil
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
private func sendNextStreamKeepAlive(for tracker: ActiveStreamKeepAlive) {
|
|
509
|
+
guard activeStreamKeepAlive === tracker else { return }
|
|
510
|
+
|
|
511
|
+
if tracker.pendingAckId != nil {
|
|
512
|
+
tracker.missedAckCount += 1
|
|
513
|
+
if tracker.missedAckCount >= 3 {
|
|
514
|
+
activeStreamKeepAlive = nil
|
|
515
|
+
tracker.task?.cancel()
|
|
516
|
+
let event = StreamStatusEvent(
|
|
517
|
+
status: .error(
|
|
518
|
+
streamId: tracker.streamId,
|
|
519
|
+
errorDetails: "Stream keep-alive timed out after \(tracker.missedAckCount) missed ACKs",
|
|
520
|
+
timestamp: Int(Date().timeIntervalSince1970 * 1000),
|
|
521
|
+
resolvedConfig: nil
|
|
522
|
+
)
|
|
523
|
+
)
|
|
524
|
+
delegate?.mentraBluetoothSDK(self, didReceive: .streamStatus(event))
|
|
525
|
+
return
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
let ackId = "ack-\(Int(Date().timeIntervalSince1970 * 1000))"
|
|
530
|
+
tracker.pendingAckId = ackId
|
|
531
|
+
DeviceManager.shared.keepStreamAlive(
|
|
532
|
+
StreamKeepAliveRequest(streamId: tracker.streamId, ackId: ackId).values
|
|
533
|
+
)
|
|
534
|
+
|
|
535
|
+
tracker.task?.cancel()
|
|
536
|
+
tracker.task = Task { @MainActor [weak self, weak tracker] in
|
|
537
|
+
guard let tracker else { return }
|
|
538
|
+
try? await Task.sleep(nanoseconds: UInt64(tracker.intervalSeconds) * 1_000_000_000)
|
|
539
|
+
self?.sendNextStreamKeepAlive(for: tracker)
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
private func handleStreamKeepAliveAck(_ event: KeepAliveAckEvent) -> Bool {
|
|
544
|
+
guard let tracker = activeStreamKeepAlive,
|
|
545
|
+
event.streamId == tracker.streamId,
|
|
546
|
+
event.ackId == tracker.pendingAckId
|
|
547
|
+
else {
|
|
548
|
+
return false
|
|
549
|
+
}
|
|
550
|
+
tracker.pendingAckId = nil
|
|
551
|
+
tracker.missedAckCount = 0
|
|
552
|
+
return true
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
private func handleStreamStatusForKeepAlive(_ status: StreamStatus) {
|
|
556
|
+
if let streamId = status.streamId,
|
|
557
|
+
activeStreamKeepAlive?.streamId != streamId
|
|
558
|
+
{
|
|
559
|
+
return
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
switch status.state {
|
|
563
|
+
case .stopped, .stopping, .error, .reconnectFailed:
|
|
564
|
+
stopStreamKeepAliveMonitor()
|
|
565
|
+
default:
|
|
566
|
+
break
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
466
570
|
private func dispatchStoreUpdate(_ category: String, _ changes: [String: Any]) {
|
|
467
571
|
switch ObservableStore.normalizeCategory(category) {
|
|
468
572
|
case "glasses":
|
|
@@ -573,6 +677,16 @@ public final class MentraBluetoothSDK {
|
|
|
573
677
|
values: data
|
|
574
678
|
)
|
|
575
679
|
delegate?.mentraBluetoothSDK(self, didReceive: .localTranscription(event))
|
|
680
|
+
case "voice_activity_detection_status":
|
|
681
|
+
delegate?.mentraBluetoothSDK(
|
|
682
|
+
self,
|
|
683
|
+
didReceive: .voiceActivityDetectionStatus(VoiceActivityDetectionStatusEvent(values: data))
|
|
684
|
+
)
|
|
685
|
+
case "speaking_status":
|
|
686
|
+
delegate?.mentraBluetoothSDK(
|
|
687
|
+
self,
|
|
688
|
+
didReceive: .speakingStatus(SpeakingStatusEvent(values: data))
|
|
689
|
+
)
|
|
576
690
|
case "hotspot_status_change":
|
|
577
691
|
delegate?.mentraBluetoothSDK(self, didReceive: .hotspotStatus(HotspotStatusEvent(values: data)))
|
|
578
692
|
case "wifi_status_change":
|
|
@@ -581,10 +695,17 @@ public final class MentraBluetoothSDK {
|
|
|
581
695
|
delegate?.mentraBluetoothSDK(self, didReceive: .hotspotError(HotspotErrorEvent(values: data)))
|
|
582
696
|
case "photo_response":
|
|
583
697
|
delegate?.mentraBluetoothSDK(self, didReceive: .photoResponse(PhotoResponseEvent(values: data)))
|
|
698
|
+
case "photo_status":
|
|
699
|
+
delegate?.mentraBluetoothSDK(self, didReceive: .photoStatus(PhotoStatusEvent(values: data)))
|
|
584
700
|
case "stream_status":
|
|
585
|
-
|
|
701
|
+
let event = StreamStatusEvent(values: data)
|
|
702
|
+
handleStreamStatusForKeepAlive(event.status)
|
|
703
|
+
delegate?.mentraBluetoothSDK(self, didReceive: .streamStatus(event))
|
|
586
704
|
case "keep_alive_ack":
|
|
587
|
-
|
|
705
|
+
let event = KeepAliveAckEvent(values: data)
|
|
706
|
+
if !handleStreamKeepAliveAck(event) {
|
|
707
|
+
delegate?.mentraBluetoothSDK(self, didReceive: .keepAliveAck(event))
|
|
708
|
+
}
|
|
588
709
|
case "compatible_glasses_search_stop":
|
|
589
710
|
delegate?.mentraBluetoothSDK(self, didStopScan: .completed)
|
|
590
711
|
case "pair_failure":
|
|
@@ -133,6 +133,7 @@ struct GlassesStatus: CustomStringConvertible {
|
|
|
133
133
|
var fullyBooted: Bool { boolValue(values, "fullyBooted") ?? false }
|
|
134
134
|
var connected: Bool { boolValue(values, "connected") ?? false }
|
|
135
135
|
var micEnabled: Bool { boolValue(values, "micEnabled") ?? false }
|
|
136
|
+
var voiceActivityDetectionEnabled: Bool { boolValue(values, "voiceActivityDetectionEnabled") ?? true }
|
|
136
137
|
var connectionState: GlassesConnectionState { GlassesConnectionState(stringValue(values, "connectionState")) }
|
|
137
138
|
var bluetoothClassicConnected: Bool { boolValue(values, "bluetoothClassicConnected") ?? false }
|
|
138
139
|
var signalStrength: Int { intValue(values["signalStrength"]) ?? -1 }
|
|
@@ -246,6 +247,10 @@ struct BluetoothStatus: CustomStringConvertible {
|
|
|
246
247
|
if let searchResults = values["searchResults"] as? [[String: Any]] {
|
|
247
248
|
normalizedValues["searchResults"] = searchResults.compactMap { Device(values: $0)?.dictionary }
|
|
248
249
|
}
|
|
250
|
+
if let galleryMode = boolValue(values, "gallery_mode") {
|
|
251
|
+
normalizedValues["galleryModeEnabled"] = galleryMode
|
|
252
|
+
normalizedValues.removeValue(forKey: "gallery_mode")
|
|
253
|
+
}
|
|
249
254
|
return normalizedValues
|
|
250
255
|
}
|
|
251
256
|
|
|
@@ -294,7 +299,7 @@ struct BluetoothStatus: CustomStringConvertible {
|
|
|
294
299
|
var dashboardDepth: Int { intValue(values["dashboard_depth"]) ?? 2 }
|
|
295
300
|
var headUpAngle: Int { intValue(values["head_up_angle"]) ?? 30 }
|
|
296
301
|
var contextualDashboard: Bool { boolValue(values, "contextual_dashboard") ?? true }
|
|
297
|
-
var
|
|
302
|
+
var galleryModeEnabled: Bool { boolValue(values, "gallery_mode") ?? boolValue(values, "galleryModeEnabled") ?? true }
|
|
298
303
|
var buttonPhotoSize: ButtonPhotoSize {
|
|
299
304
|
ButtonPhotoSize(rawValue: stringValue(values, "button_photo_size") ?? "") ?? .medium
|
|
300
305
|
}
|
|
@@ -306,7 +311,6 @@ struct BluetoothStatus: CustomStringConvertible {
|
|
|
306
311
|
var shouldSendPcm: Bool { boolValue(values, "should_send_pcm") ?? false }
|
|
307
312
|
var shouldSendLc3: Bool { boolValue(values, "should_send_lc3") ?? false }
|
|
308
313
|
var shouldSendTranscript: Bool { boolValue(values, "should_send_transcript") ?? false }
|
|
309
|
-
var bypassVad: Bool { boolValue(values, "bypass_vad") ?? true }
|
|
310
314
|
var offlineCaptionsRunning: Bool { boolValue(values, "offline_captions_running") ?? false }
|
|
311
315
|
var localSttFallbackActive: Bool { boolValue(values, "local_stt_fallback_active") ?? false }
|
|
312
316
|
var shouldSendBootingMessage: Bool { boolValue(values, "shouldSendBootingMessage") ?? true }
|
|
@@ -335,6 +339,7 @@ struct GlassesStatusUpdate: CustomStringConvertible {
|
|
|
335
339
|
var fullyBooted: Bool? { optionalBoolValue(values, "fullyBooted") }
|
|
336
340
|
var connected: Bool? { optionalBoolValue(values, "connected") }
|
|
337
341
|
var micEnabled: Bool? { optionalBoolValue(values, "micEnabled") }
|
|
342
|
+
var voiceActivityDetectionEnabled: Bool? { optionalBoolValue(values, "voiceActivityDetectionEnabled") }
|
|
338
343
|
var connectionState: GlassesConnectionState? {
|
|
339
344
|
GlassesConnectionState.fromValue(optionalStringValue(values, "connectionState"))
|
|
340
345
|
}
|
|
@@ -403,6 +408,10 @@ struct BluetoothStatusUpdate: CustomStringConvertible {
|
|
|
403
408
|
if let searchResults = values["searchResults"] as? [[String: Any]] {
|
|
404
409
|
normalizedValues["searchResults"] = searchResults.compactMap { Device(values: $0)?.dictionary }
|
|
405
410
|
}
|
|
411
|
+
if let galleryMode = optionalBoolValue(values, "gallery_mode") {
|
|
412
|
+
normalizedValues["galleryModeEnabled"] = galleryMode
|
|
413
|
+
normalizedValues.removeValue(forKey: "gallery_mode")
|
|
414
|
+
}
|
|
406
415
|
self.values = normalizedValues
|
|
407
416
|
}
|
|
408
417
|
|
|
@@ -440,7 +449,7 @@ struct BluetoothStatusUpdate: CustomStringConvertible {
|
|
|
440
449
|
var dashboardDepth: Int? { optionalIntValue(values, "dashboard_depth") }
|
|
441
450
|
var headUpAngle: Int? { optionalIntValue(values, "head_up_angle") }
|
|
442
451
|
var contextualDashboard: Bool? { optionalBoolValue(values, "contextual_dashboard") }
|
|
443
|
-
var
|
|
452
|
+
var galleryModeEnabled: Bool? { optionalBoolValue(values, "gallery_mode") ?? optionalBoolValue(values, "galleryModeEnabled") }
|
|
444
453
|
var buttonPhotoSize: ButtonPhotoSize? {
|
|
445
454
|
optionalStringValue(values, "button_photo_size").flatMap(ButtonPhotoSize.init(rawValue:))
|
|
446
455
|
}
|
|
@@ -452,7 +461,6 @@ struct BluetoothStatusUpdate: CustomStringConvertible {
|
|
|
452
461
|
var shouldSendPcm: Bool? { optionalBoolValue(values, "should_send_pcm") }
|
|
453
462
|
var shouldSendLc3: Bool? { optionalBoolValue(values, "should_send_lc3") }
|
|
454
463
|
var shouldSendTranscript: Bool? { optionalBoolValue(values, "should_send_transcript") }
|
|
455
|
-
var bypassVad: Bool? { optionalBoolValue(values, "bypass_vad") }
|
|
456
464
|
var offlineCaptionsRunning: Bool? { optionalBoolValue(values, "offline_captions_running") }
|
|
457
465
|
var localSttFallbackActive: Bool? { optionalBoolValue(values, "local_stt_fallback_active") }
|
|
458
466
|
var shouldSendBootingMessage: Bool? { optionalBoolValue(values, "shouldSendBootingMessage") }
|
|
@@ -121,6 +121,7 @@ public enum GlassesRuntimeState: CustomStringConvertible {
|
|
|
121
121
|
hotspot: HotspotStatus,
|
|
122
122
|
ready: Bool,
|
|
123
123
|
signal: SignalState,
|
|
124
|
+
voiceActivityDetectionEnabled: Bool,
|
|
124
125
|
wifi: WifiStatus
|
|
125
126
|
)
|
|
126
127
|
|
|
@@ -153,6 +154,7 @@ public enum GlassesRuntimeState: CustomStringConvertible {
|
|
|
153
154
|
strengthDbm: status.signalStrength == -1 ? nil : status.signalStrength,
|
|
154
155
|
updatedAt: status.signalStrengthUpdatedAt <= 0 ? nil : status.signalStrengthUpdatedAt
|
|
155
156
|
),
|
|
157
|
+
voiceActivityDetectionEnabled: status.voiceActivityDetectionEnabled,
|
|
156
158
|
wifi: status.wifi
|
|
157
159
|
)
|
|
158
160
|
}
|
|
@@ -168,7 +170,7 @@ public enum GlassesRuntimeState: CustomStringConvertible {
|
|
|
168
170
|
switch self {
|
|
169
171
|
case let .disconnected(connection):
|
|
170
172
|
connection
|
|
171
|
-
case let .connected(_, connection, _, _, _, _, _, _):
|
|
173
|
+
case let .connected(_, connection, _, _, _, _, _, _, _):
|
|
172
174
|
connection
|
|
173
175
|
}
|
|
174
176
|
}
|
|
@@ -177,48 +179,55 @@ public enum GlassesRuntimeState: CustomStringConvertible {
|
|
|
177
179
|
switch self {
|
|
178
180
|
case .disconnected:
|
|
179
181
|
false
|
|
180
|
-
case let .connected(_, _, _, _, _, ready, _, _):
|
|
182
|
+
case let .connected(_, _, _, _, _, ready, _, _, _):
|
|
181
183
|
ready
|
|
182
184
|
}
|
|
183
185
|
}
|
|
184
186
|
|
|
185
187
|
public var battery: GlassesBatteryState? {
|
|
186
|
-
guard case let .connected(battery, _, _, _, _, _, _, _) = self else {
|
|
188
|
+
guard case let .connected(battery, _, _, _, _, _, _, _, _) = self else {
|
|
187
189
|
return nil
|
|
188
190
|
}
|
|
189
191
|
return battery
|
|
190
192
|
}
|
|
191
193
|
|
|
192
194
|
public var device: ConnectedGlassesInfo? {
|
|
193
|
-
guard case let .connected(_, _, device, _, _, _, _, _) = self else {
|
|
195
|
+
guard case let .connected(_, _, device, _, _, _, _, _, _) = self else {
|
|
194
196
|
return nil
|
|
195
197
|
}
|
|
196
198
|
return device
|
|
197
199
|
}
|
|
198
200
|
|
|
199
201
|
public var firmware: FirmwareInfo? {
|
|
200
|
-
guard case let .connected(_, _, _, firmware, _, _, _, _) = self else {
|
|
202
|
+
guard case let .connected(_, _, _, firmware, _, _, _, _, _) = self else {
|
|
201
203
|
return nil
|
|
202
204
|
}
|
|
203
205
|
return firmware
|
|
204
206
|
}
|
|
205
207
|
|
|
206
208
|
public var hotspot: HotspotStatus? {
|
|
207
|
-
guard case let .connected(_, _, _, _, hotspot, _, _, _) = self else {
|
|
209
|
+
guard case let .connected(_, _, _, _, hotspot, _, _, _, _) = self else {
|
|
208
210
|
return nil
|
|
209
211
|
}
|
|
210
212
|
return hotspot
|
|
211
213
|
}
|
|
212
214
|
|
|
213
215
|
public var signal: SignalState? {
|
|
214
|
-
guard case let .connected(_, _, _, _, _, _, signal, _) = self else {
|
|
216
|
+
guard case let .connected(_, _, _, _, _, _, signal, _, _) = self else {
|
|
215
217
|
return nil
|
|
216
218
|
}
|
|
217
219
|
return signal
|
|
218
220
|
}
|
|
219
221
|
|
|
222
|
+
public var voiceActivityDetectionEnabled: Bool {
|
|
223
|
+
guard case let .connected(_, _, _, _, _, _, _, voiceActivityDetectionEnabled, _) = self else {
|
|
224
|
+
return false
|
|
225
|
+
}
|
|
226
|
+
return voiceActivityDetectionEnabled
|
|
227
|
+
}
|
|
228
|
+
|
|
220
229
|
public var wifi: WifiStatus? {
|
|
221
|
-
guard case let .connected(_, _, _, _, _, _, _, wifi) = self else {
|
|
230
|
+
guard case let .connected(_, _, _, _, _, _, _, _, wifi) = self else {
|
|
222
231
|
return nil
|
|
223
232
|
}
|
|
224
233
|
return wifi
|
|
@@ -228,17 +237,17 @@ public enum GlassesRuntimeState: CustomStringConvertible {
|
|
|
228
237
|
switch self {
|
|
229
238
|
case let .disconnected(connection):
|
|
230
239
|
"GlassesRuntimeState(\(connection.rawValue))"
|
|
231
|
-
case let .connected(_, _, device, _, _, ready, _, _):
|
|
240
|
+
case let .connected(_, _, device, _, _, ready, _, _, _):
|
|
232
241
|
"GlassesRuntimeState(connected: \(device), ready: \(ready))"
|
|
233
242
|
}
|
|
234
243
|
}
|
|
235
244
|
}
|
|
236
245
|
|
|
237
246
|
public struct GalleryModeState: Equatable {
|
|
238
|
-
public let
|
|
247
|
+
public let enabled: Bool
|
|
239
248
|
|
|
240
|
-
public init(
|
|
241
|
-
self.
|
|
249
|
+
public init(enabled: Bool) {
|
|
250
|
+
self.enabled = enabled
|
|
242
251
|
}
|
|
243
252
|
}
|
|
244
253
|
|
|
@@ -288,7 +297,7 @@ public struct PhoneSdkRuntimeState: CustomStringConvertible {
|
|
|
288
297
|
init(status: BluetoothStatus) {
|
|
289
298
|
currentMic = MicMode(rawValue: status.currentMic)
|
|
290
299
|
defaultDevice = status.defaultDevice
|
|
291
|
-
galleryMode = GalleryModeState(
|
|
300
|
+
galleryMode = GalleryModeState(enabled: status.galleryModeEnabled)
|
|
292
301
|
lastLog = status.lastLog
|
|
293
302
|
micRanking = status.micRanking.compactMap(MicMode.init(rawValue:))
|
|
294
303
|
otherBluetoothConnected = status.otherBtConnected
|