@mentra/bluetooth-sdk 3.2.0-dev.203 → 3.2.0-dev.206
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/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +0 -8
- package/android/src/main/java/com/mentra/bluetoothsdk/GeneratedReleaseMetadata.kt +5 -5
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +13 -152
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.kt +14 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/streaming/StreamControllerProbe.kt +14 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/streaming/StreamModels.kt +16 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/streaming/StreamSessionState.kt +32 -0
- package/android/src/test/java/com/mentra/bluetoothsdk/streaming/StreamControllerProbeTest.kt +24 -0
- package/android/src/test/java/com/mentra/bluetoothsdk/streaming/StreamSessionStateTest.kt +43 -0
- package/build/BluetoothSdk.types.d.ts +6 -1
- package/build/BluetoothSdk.types.d.ts.map +1 -1
- package/build/BluetoothSdk.types.js.map +1 -1
- package/build/_private/BluetoothSdkModule.d.ts +1 -3
- package/build/_private/BluetoothSdkModule.d.ts.map +1 -1
- package/build/_private/BluetoothSdkModule.js.map +1 -1
- package/build/generated/releaseMetadata.js +5 -5
- package/build/generated/releaseMetadata.js.map +1 -1
- package/ios/BluetoothSdkModule.swift +0 -11
- package/ios/Source/BluetoothSdkDefaults.swift +1 -1
- package/ios/Source/GeneratedReleaseMetadata.swift +5 -5
- package/ios/Source/MentraBluetoothSDK.swift +10 -130
- package/ios/Source/sgcs/MentraLive.swift +46 -35
- package/ios/Source/streaming/StreamControllerProbe.swift +18 -0
- package/ios/Source/streaming/StreamModels.swift +12 -0
- package/ios/Source/streaming/StreamSessionState.swift +29 -0
- package/ios/Tests/StreamControllerProbeTests.swift +27 -0
- package/ios/Tests/StreamSessionStateTests.swift +38 -0
- package/package.json +1 -1
- package/src/BluetoothSdk.types.ts +6 -1
- package/src/_private/BluetoothSdkModule.ts +0 -3
- package/src/generated/releaseMetadata.ts +5 -5
|
@@ -629,6 +629,10 @@ public enum StreamStatus: CustomStringConvertible, Equatable {
|
|
|
629
629
|
public struct StreamStatusEvent: CustomStringConvertible {
|
|
630
630
|
public let status: StreamStatus
|
|
631
631
|
public let stats: StreamLiveStats?
|
|
632
|
+
public private(set) var processSessionId: String?
|
|
633
|
+
public private(set) var revision: Int?
|
|
634
|
+
public private(set) var terminal: Bool?
|
|
635
|
+
public private(set) var errorDetails: String?
|
|
632
636
|
/// True when the glasses will retry the failed publisher themselves
|
|
633
637
|
/// (emitting side lands in PR #3488); absent on older firmware and on
|
|
634
638
|
/// events not parsed from a glasses status map. Carried here instead of
|
|
@@ -644,6 +648,10 @@ public struct StreamStatusEvent: CustomStringConvertible {
|
|
|
644
648
|
status = StreamStatus(values: values)
|
|
645
649
|
stats = StreamLiveStats(values: values["stats"] as? [String: Any])
|
|
646
650
|
willRetry = boolValue(values, "willRetry")
|
|
651
|
+
processSessionId = stringValue(values, "sid")
|
|
652
|
+
revision = optionalIntValue(values, "revision")
|
|
653
|
+
terminal = boolValue(values, "terminal")
|
|
654
|
+
errorDetails = stringValue(values, "errorDetails")
|
|
647
655
|
}
|
|
648
656
|
|
|
649
657
|
public var state: StreamState {
|
|
@@ -661,6 +669,10 @@ public struct StreamStatusEvent: CustomStringConvertible {
|
|
|
661
669
|
public var values: [String: Any] {
|
|
662
670
|
var values = status.values
|
|
663
671
|
values["type"] = "stream_status"
|
|
672
|
+
if let processSessionId { values["sid"] = processSessionId }
|
|
673
|
+
if let revision { values["revision"] = revision }
|
|
674
|
+
if let terminal { values["terminal"] = terminal }
|
|
675
|
+
if let errorDetails { values["errorDetails"] = errorDetails }
|
|
664
676
|
if let stats {
|
|
665
677
|
values["stats"] = stats.values
|
|
666
678
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
/// Observes glasses-owned streaming; delivery gaps never imply publisher failure.
|
|
4
|
+
final class StreamSessionState {
|
|
5
|
+
private(set) var processSessionId: String?
|
|
6
|
+
private(set) var currentStreamId: String?
|
|
7
|
+
private(set) var supported = false
|
|
8
|
+
private var revision: Int = -1
|
|
9
|
+
|
|
10
|
+
func ready(sessionId: String?, controlVersion: Int?) {
|
|
11
|
+
supported = controlVersion == 1 && !(sessionId ?? "").isEmpty
|
|
12
|
+
if processSessionId != sessionId {
|
|
13
|
+
currentStreamId = nil
|
|
14
|
+
revision = -1
|
|
15
|
+
}
|
|
16
|
+
processSessionId = sessionId
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
func accept(_ values: [String: Any]) -> Bool {
|
|
20
|
+
guard supported,
|
|
21
|
+
let sid = values["sid"] as? String, sid == processSessionId,
|
|
22
|
+
let incomingRevision = values["revision"] as? Int,
|
|
23
|
+
incomingRevision >= revision
|
|
24
|
+
else { return false }
|
|
25
|
+
revision = incomingRevision
|
|
26
|
+
currentStreamId = values["terminal"] as? Bool == true ? nil : values["streamId"] as? String
|
|
27
|
+
return true
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
@testable import MentraBluetoothSDK
|
|
2
|
+
import XCTest
|
|
3
|
+
|
|
4
|
+
final class StreamControllerProbeTests: XCTestCase {
|
|
5
|
+
private func probe() -> [String: Any] {
|
|
6
|
+
["protocolVersion": 1, "controllerId": StreamControllerProbe.controllerId,
|
|
7
|
+
"streamId": "stream", "probeId": "nonce"]
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
func testAnswersCurrentProcessChallengeWithoutJsOrTimer() {
|
|
11
|
+
let response = StreamControllerProbe.response(probe())
|
|
12
|
+
XCTAssertEqual(response?["type"] as? String, "stream_controller_response")
|
|
13
|
+
XCTAssertEqual(response?["probeId"] as? String, "nonce")
|
|
14
|
+
XCTAssertEqual(response?["streamId"] as? String, "stream")
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
func testRejectsPreviousProcessAndMalformedChallenges() {
|
|
18
|
+
for (key, value) in [("controllerId", "previous-process" as Any),
|
|
19
|
+
("protocolVersion", 2), ("protocolVersion", true),
|
|
20
|
+
("probeId", ""), ("streamId", "")]
|
|
21
|
+
{
|
|
22
|
+
var input = probe()
|
|
23
|
+
input[key] = value
|
|
24
|
+
XCTAssertNil(StreamControllerProbe.response(input))
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
@testable import MentraBluetoothSDK
|
|
2
|
+
import XCTest
|
|
3
|
+
|
|
4
|
+
final class StreamSessionStateTests: XCTestCase {
|
|
5
|
+
func testReadinessRequiresKnownProtocolAndProcessIdentity() {
|
|
6
|
+
let state = StreamSessionState()
|
|
7
|
+
state.ready(sessionId: "asg", controlVersion: nil)
|
|
8
|
+
XCTAssertFalse(state.supported)
|
|
9
|
+
state.ready(sessionId: "asg", controlVersion: 2)
|
|
10
|
+
XCTAssertFalse(state.supported)
|
|
11
|
+
state.ready(sessionId: "", controlVersion: 1)
|
|
12
|
+
XCTAssertFalse(state.supported)
|
|
13
|
+
state.ready(sessionId: "asg", controlVersion: 1)
|
|
14
|
+
XCTAssertTrue(state.supported)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
func testReconnectionReconcilesTerminalStateWithoutHeartbeatTimeouts() {
|
|
18
|
+
let state = StreamSessionState()
|
|
19
|
+
state.ready(sessionId: "asg", controlVersion: 1)
|
|
20
|
+
XCTAssertTrue(state.accept(["sid": "asg", "revision": 1, "streamId": "stream", "terminal": false]))
|
|
21
|
+
state.ready(sessionId: "asg", controlVersion: 1)
|
|
22
|
+
XCTAssertEqual(state.currentStreamId, "stream")
|
|
23
|
+
XCTAssertTrue(state.accept(["sid": "asg", "revision": 3, "streamId": "stream", "terminal": true]))
|
|
24
|
+
XCTAssertNil(state.currentStreamId)
|
|
25
|
+
XCTAssertFalse(state.accept(["sid": "asg", "revision": 2, "streamId": "stream", "terminal": false]))
|
|
26
|
+
XCTAssertNil(state.currentStreamId)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
func testProcessRestartRejectsOldStatusAndAcceptsNewStoppedSnapshot() {
|
|
30
|
+
let state = StreamSessionState()
|
|
31
|
+
state.ready(sessionId: "old", controlVersion: 1)
|
|
32
|
+
XCTAssertTrue(state.accept(["sid": "old", "revision": 8, "streamId": "stream", "terminal": false]))
|
|
33
|
+
state.ready(sessionId: "new", controlVersion: 1)
|
|
34
|
+
XCTAssertFalse(state.accept(["sid": "old", "revision": 9, "streamId": "stream", "terminal": false]))
|
|
35
|
+
XCTAssertTrue(state.accept(["sid": "new", "revision": 0, "terminal": true]))
|
|
36
|
+
XCTAssertNil(state.currentStreamId)
|
|
37
|
+
}
|
|
38
|
+
}
|
package/package.json
CHANGED
|
@@ -864,6 +864,11 @@ export type StreamLiveStats = {
|
|
|
864
864
|
type StreamStatusCommon = {
|
|
865
865
|
type: "stream_status"
|
|
866
866
|
streamId?: string
|
|
867
|
+
/** ASG process identity and monotonic revision for reconnect reconciliation. */
|
|
868
|
+
sid?: string
|
|
869
|
+
revision?: number
|
|
870
|
+
terminal?: boolean
|
|
871
|
+
errorDetails?: string
|
|
867
872
|
timestamp?: number
|
|
868
873
|
resolvedConfig?: StreamResolvedConfig
|
|
869
874
|
stats?: StreamLiveStats
|
|
@@ -898,7 +903,7 @@ export type StreamStatusEvent =
|
|
|
898
903
|
})
|
|
899
904
|
| (StreamStatusCommon & {
|
|
900
905
|
kind: "snapshot"
|
|
901
|
-
status:
|
|
906
|
+
status: StreamStatusState
|
|
902
907
|
streaming: boolean
|
|
903
908
|
reconnecting: boolean
|
|
904
909
|
attempt?: number
|
|
@@ -46,7 +46,6 @@ import {
|
|
|
46
46
|
ScanModelOptions,
|
|
47
47
|
ScanOptions,
|
|
48
48
|
SettingsAckSuccessEvent,
|
|
49
|
-
StreamKeepAliveRequest,
|
|
50
49
|
StreamStartRequest,
|
|
51
50
|
StreamStatusEvent,
|
|
52
51
|
VideoRecordingStartedStatusEvent,
|
|
@@ -205,9 +204,7 @@ declare class BluetoothSdkNativeModule extends NativeModule<BluetoothSdkModuleEv
|
|
|
205
204
|
|
|
206
205
|
// Stream Commands
|
|
207
206
|
startStream(params: StreamStartRequest): Promise<StreamStatusEvent>
|
|
208
|
-
startExternallyManagedStream(params: StreamStartRequest): Promise<StreamStatusEvent>
|
|
209
207
|
stopStream(): Promise<StreamStatusEvent>
|
|
210
|
-
sendExternallyManagedStreamKeepAlive(params: StreamKeepAliveRequest): Promise<void>
|
|
211
208
|
|
|
212
209
|
// Microphone Commands
|
|
213
210
|
setMicState(enabled: boolean, useGlassesMic?: boolean, sendTranscript?: boolean, sendLc3Data?: boolean): Promise<void>
|
|
@@ -12,9 +12,9 @@ export interface BluetoothSdkReleaseMetadata {
|
|
|
12
12
|
export const BLUETOOTH_SDK_RELEASE_METADATA: Readonly<BluetoothSdkReleaseMetadata> = Object.freeze({
|
|
13
13
|
"schemaVersion": 1,
|
|
14
14
|
"familyBaseVersion": "3.2.0",
|
|
15
|
-
"releaseIdentity": "3.2.0-dev.
|
|
16
|
-
"releaseSetId": "mentra-3.2.0-dev.
|
|
17
|
-
"sourceCommit": "
|
|
18
|
-
"otaManifestUrl": "https://github.com/Mentra-Community/MentraOS/releases/download/mentra-builds-v3.2.0/mentra-live-ota-3.2.0-dev.
|
|
19
|
-
"otaManifestSha256": "
|
|
15
|
+
"releaseIdentity": "3.2.0-dev.206",
|
|
16
|
+
"releaseSetId": "mentra-3.2.0-dev.206",
|
|
17
|
+
"sourceCommit": "3c22b92a5a53ce608c087503417ca5b3d16cc926",
|
|
18
|
+
"otaManifestUrl": "https://github.com/Mentra-Community/MentraOS/releases/download/mentra-builds-v3.2.0/mentra-live-ota-3.2.0-dev.206.json",
|
|
19
|
+
"otaManifestSha256": "7bc5e09f2757b2c11da58c93459bb0a554f406dd0ae5b50b58db28b64b92c838"
|
|
20
20
|
})
|