@mentra/bluetooth-sdk 3.3.0-dev.785 → 3.3.0-dev.788
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/GeneratedReleaseMetadata.kt +5 -5
- package/build/generated/releaseMetadata.js +5 -5
- package/build/generated/releaseMetadata.js.map +1 -1
- package/ios/Source/BluetoothSdkDefaults.swift +1 -1
- package/ios/Source/GeneratedReleaseMetadata.swift +5 -5
- package/ios/Source/utils/AudioSessionMonitor.swift +44 -8
- package/ios/Tests/BluetoothAudioRouteTests.swift +26 -0
- package/package.json +2 -2
- package/src/generated/releaseMetadata.ts +5 -5
|
@@ -3,9 +3,9 @@ package com.mentra.bluetoothsdk
|
|
|
3
3
|
/** Generated by release CI. Do not edit in a release checkout. */
|
|
4
4
|
internal object GeneratedReleaseMetadata {
|
|
5
5
|
const val FAMILY_BASE_VERSION: String = "3.3.0"
|
|
6
|
-
const val RELEASE_IDENTITY: String = "3.3.0-dev.
|
|
7
|
-
const val RELEASE_SET_ID: String = "mentra-3.3.0-dev.
|
|
8
|
-
const val SOURCE_COMMIT: String = "
|
|
9
|
-
const val OTA_MANIFEST_URL: String = "https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.3.0/mentra-live-ota-3.3.0-dev.
|
|
10
|
-
const val OTA_MANIFEST_SHA256: String = "
|
|
6
|
+
const val RELEASE_IDENTITY: String = "3.3.0-dev.788"
|
|
7
|
+
const val RELEASE_SET_ID: String = "mentra-3.3.0-dev.788"
|
|
8
|
+
const val SOURCE_COMMIT: String = "557a9faa3f9c43bee85ab7cc3509e4770a000c22"
|
|
9
|
+
const val OTA_MANIFEST_URL: String = "https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.3.0/mentra-live-ota-3.3.0-dev.788.json"
|
|
10
|
+
const val OTA_MANIFEST_SHA256: String = "a7fe57f5a3cb130c5615133b733fd46b880e6367ce07a283750cc7bf83d2415a"
|
|
11
11
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
export const BLUETOOTH_SDK_RELEASE_METADATA = Object.freeze({
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"familyBaseVersion": "3.3.0",
|
|
4
|
-
"releaseIdentity": "3.3.0-dev.
|
|
5
|
-
"releaseSetId": "mentra-3.3.0-dev.
|
|
6
|
-
"sourceCommit": "
|
|
7
|
-
"otaManifestUrl": "https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.3.0/mentra-live-ota-3.3.0-dev.
|
|
8
|
-
"otaManifestSha256": "
|
|
4
|
+
"releaseIdentity": "3.3.0-dev.788",
|
|
5
|
+
"releaseSetId": "mentra-3.3.0-dev.788",
|
|
6
|
+
"sourceCommit": "557a9faa3f9c43bee85ab7cc3509e4770a000c22",
|
|
7
|
+
"otaManifestUrl": "https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.3.0/mentra-live-ota-3.3.0-dev.788.json",
|
|
8
|
+
"otaManifestSha256": "a7fe57f5a3cb130c5615133b733fd46b880e6367ce07a283750cc7bf83d2415a"
|
|
9
9
|
});
|
|
10
10
|
//# sourceMappingURL=releaseMetadata.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"releaseMetadata.js","sourceRoot":"","sources":["../../src/generated/releaseMetadata.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,8BAA8B,GAA0C,MAAM,CAAC,MAAM,CAAC;IACjG,eAAe,EAAE,CAAC;IAClB,mBAAmB,EAAE,OAAO;IAC5B,iBAAiB,EAAE,eAAe;IAClC,cAAc,EAAE,sBAAsB;IACtC,cAAc,EAAE,0CAA0C;IAC1D,gBAAgB,EAAE,iIAAiI;IACnJ,mBAAmB,EAAE,kEAAkE;CACxF,CAAC,CAAA","sourcesContent":["/** Generated by release CI. Do not edit in a release checkout. */\nexport interface BluetoothSdkReleaseMetadata {\n schemaVersion: 1\n familyBaseVersion: string | null\n releaseIdentity: string | null\n releaseSetId: string | null\n sourceCommit: string | null\n otaManifestUrl: string | null\n otaManifestSha256: string | null\n}\n\nexport const BLUETOOTH_SDK_RELEASE_METADATA: Readonly<BluetoothSdkReleaseMetadata> = Object.freeze({\n \"schemaVersion\": 1,\n \"familyBaseVersion\": \"3.3.0\",\n \"releaseIdentity\": \"3.3.0-dev.
|
|
1
|
+
{"version":3,"file":"releaseMetadata.js","sourceRoot":"","sources":["../../src/generated/releaseMetadata.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,8BAA8B,GAA0C,MAAM,CAAC,MAAM,CAAC;IACjG,eAAe,EAAE,CAAC;IAClB,mBAAmB,EAAE,OAAO;IAC5B,iBAAiB,EAAE,eAAe;IAClC,cAAc,EAAE,sBAAsB;IACtC,cAAc,EAAE,0CAA0C;IAC1D,gBAAgB,EAAE,iIAAiI;IACnJ,mBAAmB,EAAE,kEAAkE;CACxF,CAAC,CAAA","sourcesContent":["/** Generated by release CI. Do not edit in a release checkout. */\nexport interface BluetoothSdkReleaseMetadata {\n schemaVersion: 1\n familyBaseVersion: string | null\n releaseIdentity: string | null\n releaseSetId: string | null\n sourceCommit: string | null\n otaManifestUrl: string | null\n otaManifestSha256: string | null\n}\n\nexport const BLUETOOTH_SDK_RELEASE_METADATA: Readonly<BluetoothSdkReleaseMetadata> = Object.freeze({\n \"schemaVersion\": 1,\n \"familyBaseVersion\": \"3.3.0\",\n \"releaseIdentity\": \"3.3.0-dev.788\",\n \"releaseSetId\": \"mentra-3.3.0-dev.788\",\n \"sourceCommit\": \"557a9faa3f9c43bee85ab7cc3509e4770a000c22\",\n \"otaManifestUrl\": \"https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.3.0/mentra-live-ota-3.3.0-dev.788.json\",\n \"otaManifestSha256\": \"a7fe57f5a3cb130c5615133b733fd46b880e6367ce07a283750cc7bf83d2415a\"\n})\n"]}
|
|
@@ -16,7 +16,7 @@ enum BluetoothSdkDefaults {
|
|
|
16
16
|
/// silently disable it on every pair the app touches.
|
|
17
17
|
static let autoPowerOffEnabled = false
|
|
18
18
|
private static let infoSdkVersionKey = "MentraBluetoothSdkVersion"
|
|
19
|
-
private static let swiftPackageSdkVersion = "3.3.0-dev.
|
|
19
|
+
private static let swiftPackageSdkVersion = "3.3.0-dev.788"
|
|
20
20
|
private static let swiftPackageSdkVersionPlaceholder = "__MENTRA" + "_BLUETOOTH_SDK_VERSION__"
|
|
21
21
|
|
|
22
22
|
private static func normalizedSdkVersion(_ value: String?) -> String? {
|
|
@@ -3,9 +3,9 @@ import Foundation
|
|
|
3
3
|
/// Generated by release CI. Do not edit in a release checkout.
|
|
4
4
|
enum GeneratedReleaseMetadata {
|
|
5
5
|
static let familyBaseVersion = "3.3.0"
|
|
6
|
-
static let releaseIdentity = "3.3.0-dev.
|
|
7
|
-
static let releaseSetId = "mentra-3.3.0-dev.
|
|
8
|
-
static let sourceCommit = "
|
|
9
|
-
static let otaManifestUrl = "https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.3.0/mentra-live-ota-3.3.0-dev.
|
|
10
|
-
static let otaManifestSha256 = "
|
|
6
|
+
static let releaseIdentity = "3.3.0-dev.788"
|
|
7
|
+
static let releaseSetId = "mentra-3.3.0-dev.788"
|
|
8
|
+
static let sourceCommit = "557a9faa3f9c43bee85ab7cc3509e4770a000c22"
|
|
9
|
+
static let otaManifestUrl = "https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.3.0/mentra-live-ota-3.3.0-dev.788.json"
|
|
10
|
+
static let otaManifestSha256 = "a7fe57f5a3cb130c5615133b733fd46b880e6367ce07a283750cc7bf83d2415a"
|
|
11
11
|
}
|
|
@@ -10,9 +10,11 @@ import Foundation
|
|
|
10
10
|
|
|
11
11
|
#if !os(macOS)
|
|
12
12
|
import AVFoundation
|
|
13
|
+
import OSLog
|
|
13
14
|
import UIKit
|
|
14
15
|
|
|
15
16
|
class AudioSessionMonitor {
|
|
17
|
+
private static let readinessLog = Logger(subsystem: "com.mentra.bluetooth-sdk", category: "AudioReadiness")
|
|
16
18
|
/// Singleton instance
|
|
17
19
|
private static var instance: AudioSessionMonitor?
|
|
18
20
|
|
|
@@ -96,15 +98,31 @@ class AudioSessionMonitor {
|
|
|
96
98
|
/// This avoids switching A2DP music playback to HFP microphone mode
|
|
97
99
|
static func isDevicePaired(devicePattern: String) -> Bool {
|
|
98
100
|
let session = AVAudioSession.sharedInstance()
|
|
101
|
+
let outputs = session.currentRoute.outputs
|
|
102
|
+
let route = BluetoothAudioRoute.observe(
|
|
103
|
+
outputs: outputs.map { (name: $0.portName, portType: $0.portType.rawValue) },
|
|
104
|
+
target: devicePattern, isIOSAppOnMac: ProcessInfo.processInfo.isiOSAppOnMac
|
|
105
|
+
)
|
|
106
|
+
let activeTarget = route.matchingOutputCount > 0
|
|
107
|
+
let availableInputs = session.availableInputs
|
|
108
|
+
let bluetoothInput = availableInputs?.first { input in
|
|
109
|
+
input.portType == .bluetoothHFP
|
|
110
|
+
&& input.portName.localizedCaseInsensitiveContains(devicePattern)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// NSLog messages redact the native route checks in retained Mac logs.
|
|
114
|
+
// Keep categorical evidence at notice level without exposing names or
|
|
115
|
+
// selecting an input, activating the session, or changing audio routing.
|
|
116
|
+
readinessLog.notice("Pair audio: iosOnMac=\(ProcessInfo.processInfo.isiOSAppOnMac, privacy: .public) targetPresent=\(!devicePattern.isEmpty, privacy: .public) category=\(session.category.rawValue, privacy: .public) outputs=\(outputs.count, privacy: .public) bluetoothOutputs=\(route.bluetoothOutputCount, privacy: .public) targetNameOutputs=\(route.targetNameOutputCount, privacy: .public) inputs=\(availableInputs?.count ?? -1, privacy: .public) activeTarget=\(activeTarget, privacy: .public) hfpTarget=\(bluetoothInput != nil, privacy: .public)")
|
|
99
117
|
|
|
100
118
|
// Check if already active (using A2DP for music or HFP for calls)
|
|
101
|
-
if
|
|
119
|
+
if activeTarget {
|
|
102
120
|
Bridge.log("AudioMonitor: Device '\(devicePattern)' already active")
|
|
103
121
|
return true
|
|
104
122
|
}
|
|
105
123
|
|
|
106
124
|
// Try to find in availableInputs (includes paired devices)
|
|
107
|
-
guard let availableInputs
|
|
125
|
+
guard let availableInputs else {
|
|
108
126
|
Bridge.log("AudioMonitor: ❌ availableInputs is nil")
|
|
109
127
|
return false
|
|
110
128
|
}
|
|
@@ -114,11 +132,6 @@ class AudioSessionMonitor {
|
|
|
114
132
|
Bridge.log("AudioMonitor: - \(input.portName) (type: \(input.portType.rawValue))")
|
|
115
133
|
}
|
|
116
134
|
|
|
117
|
-
let bluetoothInput = availableInputs.first { input in
|
|
118
|
-
input.portType == .bluetoothHFP
|
|
119
|
-
&& input.portName.localizedCaseInsensitiveContains(devicePattern)
|
|
120
|
-
}
|
|
121
|
-
|
|
122
135
|
if let btInput = bluetoothInput {
|
|
123
136
|
Bridge.log(
|
|
124
137
|
"AudioMonitor: ✅ Found paired device '\(btInput.portName)' (not activating to preserve A2DP)"
|
|
@@ -291,8 +304,31 @@ class AudioSessionMonitor {
|
|
|
291
304
|
/// AVAudioSession preserves the route name on iOS-on-Mac but reports the
|
|
292
305
|
/// CoreAudio transport "Bluetooth" instead of iPhone's profile-specific port.
|
|
293
306
|
enum BluetoothAudioRoute {
|
|
307
|
+
struct Observation: Equatable {
|
|
308
|
+
let bluetoothOutputCount: Int
|
|
309
|
+
let targetNameOutputCount: Int
|
|
310
|
+
let matchingOutputCount: Int
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
static func observe(outputs: [(name: String, portType: String)], target: String, isIOSAppOnMac: Bool) -> Observation {
|
|
314
|
+
Observation(
|
|
315
|
+
bluetoothOutputCount: outputs.filter { isBluetoothTransport($0.portType, isIOSAppOnMac: isIOSAppOnMac) }.count,
|
|
316
|
+
targetNameOutputCount: outputs.filter { matchesName($0.name, target: target) }.count,
|
|
317
|
+
matchingOutputCount: outputs.filter {
|
|
318
|
+
matches(name: $0.name, portType: $0.portType, target: target, isIOSAppOnMac: isIOSAppOnMac)
|
|
319
|
+
}.count
|
|
320
|
+
)
|
|
321
|
+
}
|
|
322
|
+
|
|
294
323
|
static func matches(name: String, portType: String, target: String, isIOSAppOnMac: Bool) -> Bool {
|
|
295
|
-
|
|
324
|
+
matchesName(name, target: target) && isBluetoothTransport(portType, isIOSAppOnMac: isIOSAppOnMac)
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
private static func matchesName(_ name: String, target: String) -> Bool {
|
|
328
|
+
!target.isEmpty && name.localizedCaseInsensitiveContains(target)
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
private static func isBluetoothTransport(_ portType: String, isIOSAppOnMac: Bool) -> Bool {
|
|
296
332
|
return portType == "BluetoothHFP" || portType == "BluetoothA2DPOutput"
|
|
297
333
|
|| (isIOSAppOnMac && portType == "Bluetooth")
|
|
298
334
|
}
|
|
@@ -2,6 +2,32 @@
|
|
|
2
2
|
import XCTest
|
|
3
3
|
|
|
4
4
|
final class BluetoothAudioRouteTests: XCTestCase {
|
|
5
|
+
func testObservationSeparatesAbsentBluetoothFromWrongTarget() {
|
|
6
|
+
let builtIn = BluetoothAudioRoute.observe(
|
|
7
|
+
outputs: [(name: "MacBook Speakers", portType: "Speaker")], target: "03BE", isIOSAppOnMac: true
|
|
8
|
+
)
|
|
9
|
+
let wrongTarget = BluetoothAudioRoute.observe(
|
|
10
|
+
outputs: [(name: "Mentra_Live_023B", portType: "Bluetooth")], target: "03BE", isIOSAppOnMac: true
|
|
11
|
+
)
|
|
12
|
+
XCTAssertEqual(builtIn, .init(bluetoothOutputCount: 0, targetNameOutputCount: 0, matchingOutputCount: 0))
|
|
13
|
+
XCTAssertEqual(wrongTarget, .init(bluetoothOutputCount: 1, targetNameOutputCount: 0, matchingOutputCount: 0))
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
func testObservationKeepsIdentityAndTransportSeparate() {
|
|
17
|
+
let matching = BluetoothAudioRoute.observe(
|
|
18
|
+
outputs: [(name: "Mentra_Live_03BE", portType: "Bluetooth")], target: "03BE", isIOSAppOnMac: true
|
|
19
|
+
)
|
|
20
|
+
let usb = BluetoothAudioRoute.observe(
|
|
21
|
+
outputs: [(name: "Mentra_Live_03BE", portType: "USBAudio")], target: "03BE", isIOSAppOnMac: true
|
|
22
|
+
)
|
|
23
|
+
let missingTarget = BluetoothAudioRoute.observe(
|
|
24
|
+
outputs: [(name: "Mentra_Live_03BE", portType: "Bluetooth")], target: "", isIOSAppOnMac: true
|
|
25
|
+
)
|
|
26
|
+
XCTAssertEqual(matching, .init(bluetoothOutputCount: 1, targetNameOutputCount: 1, matchingOutputCount: 1))
|
|
27
|
+
XCTAssertEqual(usb, .init(bluetoothOutputCount: 0, targetNameOutputCount: 1, matchingOutputCount: 0))
|
|
28
|
+
XCTAssertEqual(missingTarget, .init(bluetoothOutputCount: 1, targetNameOutputCount: 0, matchingOutputCount: 0))
|
|
29
|
+
}
|
|
30
|
+
|
|
5
31
|
func testRecognizesIPhoneProfiles() {
|
|
6
32
|
for port in ["BluetoothHFP", "BluetoothA2DPOutput"] {
|
|
7
33
|
XCTAssertTrue(BluetoothAudioRoute.matches(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mentra/bluetooth-sdk",
|
|
3
|
-
"version": "3.3.0-dev.
|
|
3
|
+
"version": "3.3.0-dev.788",
|
|
4
4
|
"description": "SDK for communicating with smart glasses",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"react-native": "src/index.ts",
|
|
@@ -114,7 +114,7 @@
|
|
|
114
114
|
"registry": "https://registry.npmjs.org/"
|
|
115
115
|
},
|
|
116
116
|
"dependencies": {
|
|
117
|
-
"@mentra/cloud-protocol": "3.3.0-dev.
|
|
117
|
+
"@mentra/cloud-protocol": "3.3.0-dev.788"
|
|
118
118
|
},
|
|
119
119
|
"devDependencies": {
|
|
120
120
|
"@types/node": "^25.9.3",
|
|
@@ -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.3.0",
|
|
15
|
-
"releaseIdentity": "3.3.0-dev.
|
|
16
|
-
"releaseSetId": "mentra-3.3.0-dev.
|
|
17
|
-
"sourceCommit": "
|
|
18
|
-
"otaManifestUrl": "https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.3.0/mentra-live-ota-3.3.0-dev.
|
|
19
|
-
"otaManifestSha256": "
|
|
15
|
+
"releaseIdentity": "3.3.0-dev.788",
|
|
16
|
+
"releaseSetId": "mentra-3.3.0-dev.788",
|
|
17
|
+
"sourceCommit": "557a9faa3f9c43bee85ab7cc3509e4770a000c22",
|
|
18
|
+
"otaManifestUrl": "https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.3.0/mentra-live-ota-3.3.0-dev.788.json",
|
|
19
|
+
"otaManifestSha256": "a7fe57f5a3cb130c5615133b733fd46b880e6367ce07a283750cc7bf83d2415a"
|
|
20
20
|
})
|