@mentra/bluetooth-sdk 3.2.0-dev.227 → 3.2.0-dev.233

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.2.0"
6
- const val RELEASE_IDENTITY: String = "3.2.0-dev.227"
7
- const val RELEASE_SET_ID: String = "mentra-3.2.0-dev.227"
8
- const val SOURCE_COMMIT: String = "fc86f650fdae5bcf974c9d4816b3e9c490f54150"
9
- const val OTA_MANIFEST_URL: String = "https://github.com/Mentra-Community/MentraOS/releases/download/mentra-builds-v3.2.0/mentra-live-ota-3.2.0-dev.227.json"
10
- const val OTA_MANIFEST_SHA256: String = "547fa2ddccc9d1ec1679a770077312f238e5bb623d758c41e61dd9e55f591f06"
6
+ const val RELEASE_IDENTITY: String = "3.2.0-dev.233"
7
+ const val RELEASE_SET_ID: String = "mentra-3.2.0-dev.233"
8
+ const val SOURCE_COMMIT: String = "626082d1f9ddc939fc90eefc7af897878a79cbb0"
9
+ const val OTA_MANIFEST_URL: String = "https://github.com/Mentra-Community/MentraOS/releases/download/mentra-builds-v3.2.0/mentra-live-ota-3.2.0-dev.233.json"
10
+ const val OTA_MANIFEST_SHA256: String = "70fce776c2f8653db65522606340c0b1d7246398c205cf2da45c2f3177909f99"
11
11
  }
@@ -241,6 +241,12 @@ class PhoneMic private constructor(private val context: Context) {
241
241
  return true
242
242
  }
243
243
 
244
+ // Reject unavailable candidates before disturbing the active recorder. DeviceManager
245
+ // tries these in one ranked pass, so an unsupported HQ profile must not stop HFP.
246
+ if (mode == MicTypes.BLUETOOTH && !isHighQualityBluetoothAvailable()) return false
247
+ if (mode == MicTypes.BLUETOOTH_CLASSIC && !audioManager.isBluetoothScoAvailableOffCall) return false
248
+ if (mode !in listOf(MicTypes.PHONE_INTERNAL, MicTypes.BLUETOOTH_CLASSIC, MicTypes.BLUETOOTH)) return false
249
+
244
250
  // recording with a different mode, so stop recording and start recording with the new mode:
245
251
  if (isRecording.get()) {
246
252
  Bridge.log(
@@ -256,14 +262,10 @@ class PhoneMic private constructor(private val context: Context) {
256
262
  return false
257
263
  }
258
264
 
259
- // Smart debouncing
260
- val now = System.currentTimeMillis()
261
- if (now - lastModeChangeTime < MODE_CHANGE_DEBOUNCE_MS) {
262
- Bridge.log("MIC: Debouncing rapid recording request")
263
- return false
264
- }
265
-
266
- lastModeChangeTime = System.currentTimeMillis()
265
+ // Do not debounce ranked candidates: failure must allow the next source to
266
+ // start immediately. isRecordingWithMode above already makes repeated starts
267
+ // of the selected source idempotent. The legacy startRecording entry retains
268
+ // its own debounce for independent recording requests.
267
269
 
268
270
  // Check for conflicts
269
271
  if (isPhoneCallActive) {
@@ -291,20 +293,10 @@ class PhoneMic private constructor(private val context: Context) {
291
293
  }
292
294
  MicTypes.BLUETOOTH_CLASSIC -> {
293
295
  Bridge.log("MIC: Starting Bluetooth Classic (SCO)")
294
- if (!audioManager.isBluetoothScoAvailableOffCall) {
295
- Bridge.log("MIC: Bluetooth SCO not available")
296
- notifyDeviceManager("bt_classic_unavailable", emptyList())
297
- return false
298
- }
299
296
  return startRecordingBtClassic()
300
297
  }
301
298
  MicTypes.BLUETOOTH -> {
302
299
  Bridge.log("MIC: Starting high-quality Bluetooth mic")
303
- if (!isHighQualityBluetoothAvailable()) {
304
- Bridge.log("MIC: High-quality Bluetooth not available")
305
- notifyDeviceManager("bt_hq_unavailable", emptyList())
306
- return false
307
- }
308
300
  return startRecordingBtHighQuality()
309
301
  }
310
302
  else -> {
@@ -0,0 +1,73 @@
1
+ package com.mentra.bluetoothsdk.services
2
+
3
+ import android.Manifest
4
+ import android.content.Context
5
+ import android.media.AudioManager
6
+ import com.mentra.bluetoothsdk.Bridge
7
+ import com.mentra.bluetoothsdk.utils.MicTypes
8
+ import org.assertj.core.api.Assertions.assertThat
9
+ import org.junit.After
10
+ import org.junit.Before
11
+ import org.junit.Test
12
+ import org.junit.runner.RunWith
13
+ import org.robolectric.RobolectricTestRunner
14
+ import org.robolectric.RuntimeEnvironment
15
+ import org.robolectric.Shadows.shadowOf
16
+ import org.robolectric.annotation.Config
17
+ import org.robolectric.annotation.LooperMode
18
+ import org.robolectric.shadows.ShadowAudioRecord
19
+
20
+ @RunWith(RobolectricTestRunner::class)
21
+ @Config(sdk = [28], manifest = Config.NONE)
22
+ @LooperMode(LooperMode.Mode.PAUSED)
23
+ class PhoneMicFallbackTest {
24
+ private lateinit var mic: PhoneMic
25
+
26
+ @Before
27
+ fun setUp() {
28
+ val context = RuntimeEnvironment.getApplication()
29
+ shadowOf(context).grantPermissions(Manifest.permission.RECORD_AUDIO)
30
+ Bridge.initialize(context)
31
+ val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
32
+ shadowOf(audioManager).setIsBluetoothScoAvailableOffCall(true)
33
+ // Keep the test recorder alive without forwarding synthetic audio to DeviceManager.
34
+ ShadowAudioRecord.setSource(object : ShadowAudioRecord.AudioRecordSource {
35
+ override fun readInShortArray(buffer: ShortArray, offset: Int, size: Int, blocking: Boolean): Int {
36
+ try { Thread.sleep(1) } catch (_: InterruptedException) {}
37
+ return 0
38
+ }
39
+ })
40
+ val constructor = PhoneMic::class.java.getDeclaredConstructor(Context::class.java)
41
+ constructor.isAccessible = true
42
+ mic = constructor.newInstance(context)
43
+ }
44
+
45
+ @After
46
+ fun tearDown() {
47
+ mic.cleanup()
48
+ ShadowAudioRecord.clearSource()
49
+ }
50
+
51
+ @Test
52
+ fun unavailableHighQualityProfileDoesNotBlockImmediateHfpFallback() {
53
+ assertThat(mic.startMode(MicTypes.BLUETOOTH)).isFalse()
54
+ assertThat(mic.startMode(MicTypes.BLUETOOTH_CLASSIC)).isTrue()
55
+ assertThat(mic.isRecordingWithMode(MicTypes.BLUETOOTH_CLASSIC)).isTrue()
56
+ }
57
+
58
+ @Test
59
+ fun reevaluatingUnavailableProfileDoesNotStopActiveHfpRecorder() {
60
+ assertThat(mic.startMode(MicTypes.BLUETOOTH_CLASSIC)).isTrue()
61
+ assertThat(mic.startMode(MicTypes.BLUETOOTH)).isFalse()
62
+ assertThat(mic.isRecordingWithMode(MicTypes.BLUETOOTH_CLASSIC)).isTrue()
63
+ }
64
+
65
+ @Test
66
+ fun switchingFromPhoneToHfpDoesNotRequireWaitingForDebounce() {
67
+ assertThat(mic.startMode(MicTypes.PHONE_INTERNAL)).isTrue()
68
+ assertThat(mic.startMode(MicTypes.BLUETOOTH)).isFalse()
69
+ assertThat(mic.isRecordingWithMode(MicTypes.PHONE_INTERNAL)).isTrue()
70
+ assertThat(mic.startMode(MicTypes.BLUETOOTH_CLASSIC)).isTrue()
71
+ assertThat(mic.isRecordingWithMode(MicTypes.BLUETOOTH_CLASSIC)).isTrue()
72
+ }
73
+ }
@@ -1,10 +1,10 @@
1
1
  export const BLUETOOTH_SDK_RELEASE_METADATA = Object.freeze({
2
2
  "schemaVersion": 1,
3
3
  "familyBaseVersion": "3.2.0",
4
- "releaseIdentity": "3.2.0-dev.227",
5
- "releaseSetId": "mentra-3.2.0-dev.227",
6
- "sourceCommit": "fc86f650fdae5bcf974c9d4816b3e9c490f54150",
7
- "otaManifestUrl": "https://github.com/Mentra-Community/MentraOS/releases/download/mentra-builds-v3.2.0/mentra-live-ota-3.2.0-dev.227.json",
8
- "otaManifestSha256": "547fa2ddccc9d1ec1679a770077312f238e5bb623d758c41e61dd9e55f591f06"
4
+ "releaseIdentity": "3.2.0-dev.233",
5
+ "releaseSetId": "mentra-3.2.0-dev.233",
6
+ "sourceCommit": "626082d1f9ddc939fc90eefc7af897878a79cbb0",
7
+ "otaManifestUrl": "https://github.com/Mentra-Community/MentraOS/releases/download/mentra-builds-v3.2.0/mentra-live-ota-3.2.0-dev.233.json",
8
+ "otaManifestSha256": "70fce776c2f8653db65522606340c0b1d7246398c205cf2da45c2f3177909f99"
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,wHAAwH;IAC1I,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.2.0\",\n \"releaseIdentity\": \"3.2.0-dev.227\",\n \"releaseSetId\": \"mentra-3.2.0-dev.227\",\n \"sourceCommit\": \"fc86f650fdae5bcf974c9d4816b3e9c490f54150\",\n \"otaManifestUrl\": \"https://github.com/Mentra-Community/MentraOS/releases/download/mentra-builds-v3.2.0/mentra-live-ota-3.2.0-dev.227.json\",\n \"otaManifestSha256\": \"547fa2ddccc9d1ec1679a770077312f238e5bb623d758c41e61dd9e55f591f06\"\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,wHAAwH;IAC1I,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.2.0\",\n \"releaseIdentity\": \"3.2.0-dev.233\",\n \"releaseSetId\": \"mentra-3.2.0-dev.233\",\n \"sourceCommit\": \"626082d1f9ddc939fc90eefc7af897878a79cbb0\",\n \"otaManifestUrl\": \"https://github.com/Mentra-Community/MentraOS/releases/download/mentra-builds-v3.2.0/mentra-live-ota-3.2.0-dev.233.json\",\n \"otaManifestSha256\": \"70fce776c2f8653db65522606340c0b1d7246398c205cf2da45c2f3177909f99\"\n})\n"]}
@@ -11,7 +11,7 @@ enum BluetoothSdkDefaults {
11
11
  static let voiceActivityDetectionEnabled = false
12
12
  static let loudnessGateEnabled = false
13
13
  private static let infoSdkVersionKey = "MentraBluetoothSdkVersion"
14
- private static let swiftPackageSdkVersion = "3.2.0-dev.227"
14
+ private static let swiftPackageSdkVersion = "3.2.0-dev.233"
15
15
  private static let swiftPackageSdkVersionPlaceholder = "__MENTRA" + "_BLUETOOTH_SDK_VERSION__"
16
16
 
17
17
  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.2.0"
6
- static let releaseIdentity = "3.2.0-dev.227"
7
- static let releaseSetId = "mentra-3.2.0-dev.227"
8
- static let sourceCommit = "fc86f650fdae5bcf974c9d4816b3e9c490f54150"
9
- static let otaManifestUrl = "https://github.com/Mentra-Community/MentraOS/releases/download/mentra-builds-v3.2.0/mentra-live-ota-3.2.0-dev.227.json"
10
- static let otaManifestSha256 = "547fa2ddccc9d1ec1679a770077312f238e5bb623d758c41e61dd9e55f591f06"
6
+ static let releaseIdentity = "3.2.0-dev.233"
7
+ static let releaseSetId = "mentra-3.2.0-dev.233"
8
+ static let sourceCommit = "626082d1f9ddc939fc90eefc7af897878a79cbb0"
9
+ static let otaManifestUrl = "https://github.com/Mentra-Community/MentraOS/releases/download/mentra-builds-v3.2.0/mentra-live-ota-3.2.0-dev.233.json"
10
+ static let otaManifestSha256 = "70fce776c2f8653db65522606340c0b1d7246398c205cf2da45c2f3177909f99"
11
11
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mentra/bluetooth-sdk",
3
- "version": "3.2.0-dev.227",
3
+ "version": "3.2.0-dev.233",
4
4
  "description": "SDK for communicating with smart glasses",
5
5
  "main": "build/index.js",
6
6
  "react-native": "src/index.ts",
@@ -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.227",
16
- "releaseSetId": "mentra-3.2.0-dev.227",
17
- "sourceCommit": "fc86f650fdae5bcf974c9d4816b3e9c490f54150",
18
- "otaManifestUrl": "https://github.com/Mentra-Community/MentraOS/releases/download/mentra-builds-v3.2.0/mentra-live-ota-3.2.0-dev.227.json",
19
- "otaManifestSha256": "547fa2ddccc9d1ec1679a770077312f238e5bb623d758c41e61dd9e55f591f06"
15
+ "releaseIdentity": "3.2.0-dev.233",
16
+ "releaseSetId": "mentra-3.2.0-dev.233",
17
+ "sourceCommit": "626082d1f9ddc939fc90eefc7af897878a79cbb0",
18
+ "otaManifestUrl": "https://github.com/Mentra-Community/MentraOS/releases/download/mentra-builds-v3.2.0/mentra-live-ota-3.2.0-dev.233.json",
19
+ "otaManifestSha256": "70fce776c2f8653db65522606340c0b1d7246398c205cf2da45c2f3177909f99"
20
20
  })