@mentra/bluetooth-sdk 3.3.0-dev.786 → 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.
@@ -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.786"
7
- const val RELEASE_SET_ID: String = "mentra-3.3.0-dev.786"
8
- const val SOURCE_COMMIT: String = "3cd6a06166070cc31ec01dda0d1347d4a6d1e1e8"
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.786.json"
10
- const val OTA_MANIFEST_SHA256: String = "4175bdf8b1897844662b11a4c9035698d916834d642a67fce9d3a0b197b5dcdf"
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.786",
5
- "releaseSetId": "mentra-3.3.0-dev.786",
6
- "sourceCommit": "3cd6a06166070cc31ec01dda0d1347d4a6d1e1e8",
7
- "otaManifestUrl": "https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.3.0/mentra-live-ota-3.3.0-dev.786.json",
8
- "otaManifestSha256": "4175bdf8b1897844662b11a4c9035698d916834d642a67fce9d3a0b197b5dcdf"
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.786\",\n \"releaseSetId\": \"mentra-3.3.0-dev.786\",\n \"sourceCommit\": \"3cd6a06166070cc31ec01dda0d1347d4a6d1e1e8\",\n \"otaManifestUrl\": \"https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.3.0/mentra-live-ota-3.3.0-dev.786.json\",\n \"otaManifestSha256\": \"4175bdf8b1897844662b11a4c9035698d916834d642a67fce9d3a0b197b5dcdf\"\n})\n"]}
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.786"
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.786"
7
- static let releaseSetId = "mentra-3.3.0-dev.786"
8
- static let sourceCommit = "3cd6a06166070cc31ec01dda0d1347d4a6d1e1e8"
9
- static let otaManifestUrl = "https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.3.0/mentra-live-ota-3.3.0-dev.786.json"
10
- static let otaManifestSha256 = "4175bdf8b1897844662b11a4c9035698d916834d642a67fce9d3a0b197b5dcdf"
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 isAudioDeviceConnected(devicePattern: devicePattern) {
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 = session.availableInputs else {
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
- guard !target.isEmpty, name.localizedCaseInsensitiveContains(target) else { return false }
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.786",
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.786"
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.786",
16
- "releaseSetId": "mentra-3.3.0-dev.786",
17
- "sourceCommit": "3cd6a06166070cc31ec01dda0d1347d4a6d1e1e8",
18
- "otaManifestUrl": "https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.3.0/mentra-live-ota-3.3.0-dev.786.json",
19
- "otaManifestSha256": "4175bdf8b1897844662b11a4c9035698d916834d642a67fce9d3a0b197b5dcdf"
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
  })