@mentra/acs-meeting 3.3.0-dev.408 → 3.3.0-dev.414

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 CHANGED
@@ -1064,8 +1064,9 @@ Same contract, fewer knobs. `AcsMeetingModule.swift` exposes the same Expo surfa
1064
1064
  `WhepVideoSource` and `LocalWhipIngestSource.swift` deliver `CVPixelBuffer`;
1065
1065
  `AcsFrameSender.swift` sends on the virtual stream behind a `VideoSendGate` with a simple fps
1066
1066
  throttle. `GlassesHotspotNetwork` uses the same persistent `NEHotspotConfiguration` join as
1067
- gallery transfers, verifies the joined SSID and `en0` address, and waits for DHCP against the
1068
- gateway the glasses advertised before resolving. Audio policy logic is shared through the
1067
+ gallery transfers, verifies the joined SSID and the address of the one interface Network framework
1068
+ reports as Wi-Fi (never a fixed `en0`), and waits for DHCP against the gateway the glasses
1069
+ advertised before resolving. Join and SoftAP rebind use that same verified interface and address. Audio policy logic is shared through the
1069
1070
  `PolicyKit` Swift package.
1070
1071
 
1071
1072
  Screen-off and background operation already work in the Mentra App through its existing
@@ -55,21 +55,30 @@ public class AcsMeetingModule: Module {
55
55
  let token = try requireString(options, "token")
56
56
  let meetingUrl = try requireString(options, "meetingUrl")
57
57
  let source = try parseMediaSource(options)
58
- if source.kind == .softap, source.bindAddress != GlassesHotspotNetwork.wifiAddress() {
59
- throw AcsMeetingError("The glasses hotspot address changed before join")
60
- }
61
58
  let video = try parseAcsOutgoingVideo(options["video"])
62
- self.meetingSession().join(
63
- token: token, identityMode: options["identityMode"] as? String ?? "guest", meetingUrl: meetingUrl, sourceConfig: source,
64
- displayName: options["displayName"] as? String,
65
- dumpWav: options["dumpPcmWav"] as? Bool ?? false,
66
- audioSource: options["audioSource"] as? String ?? "glasses", video: video
67
- ) { result in
68
- switch result {
69
- case let .success(state): promise.resolve(state)
70
- case let .failure(error): promise.reject(error)
59
+ let session = self.meetingSession()
60
+ let join = {
61
+ session.join(
62
+ token: token, identityMode: options["identityMode"] as? String ?? "guest", meetingUrl: meetingUrl, sourceConfig: source,
63
+ displayName: options["displayName"] as? String,
64
+ dumpWav: options["dumpPcmWav"] as? Bool ?? false,
65
+ audioSource: options["audioSource"] as? String ?? "glasses", video: video
66
+ ) { result in
67
+ switch result {
68
+ case let .success(state): promise.resolve(state)
69
+ case let .failure(error): promise.reject(error)
70
+ }
71
71
  }
72
72
  }
73
+ guard source.kind == .softap else { join(); return }
74
+ // Bind only to the address this module's hotspot session verified on its Wi-Fi interface.
75
+ self.hotspot.verifiedAddress { address in
76
+ guard let address, source.bindAddress == address else {
77
+ promise.reject(AcsMeetingError("The glasses hotspot address changed before join"))
78
+ return
79
+ }
80
+ join()
81
+ }
73
82
  }
74
83
 
75
84
  AsyncFunction("joinScopedNetwork") { (ssid: String, passphrase: String, promise: Promise) in
@@ -197,10 +206,13 @@ public class AcsMeetingModule: Module {
197
206
  promise.reject(AcsMeetingError("No active meeting to rebind"))
198
207
  return
199
208
  }
200
- session.rebindSoftApIngest { result in
201
- switch result {
202
- case let .success(url): promise.resolve(url)
203
- case let .failure(error): promise.reject(error)
209
+ // The caller rejoins first; that session's verified Wi-Fi binding is the only valid address.
210
+ self.hotspot.verifiedAddress { address in
211
+ session.rebindSoftApIngest(address: address) { result in
212
+ switch result {
213
+ case let .success(url): promise.resolve(url)
214
+ case let .failure(error): promise.reject(error)
215
+ }
204
216
  }
205
217
  }
206
218
  }
@@ -675,8 +687,8 @@ final class AcsMeetingSession {
675
687
  }
676
688
 
677
689
  /// Destroy the current SoftAP listener generation and bind a new one on the
678
- /// address the hotspot reports *now*. The caller rejoins first, then asks for this.
679
- func rebindSoftApIngest(completion: @escaping (Result<String, Error>) -> Void) {
690
+ /// address the hotspot verified *now*. The caller rejoins first, then asks for this.
691
+ func rebindSoftApIngest(address: String?, completion: @escaping (Result<String, Error>) -> Void) {
680
692
  queue.async {
681
693
  guard MediaDiagnostics.softapRecoveryEnabled else {
682
694
  completion(.failure(AcsMeetingError("SoftAP ingest rebind is disabled")))
@@ -686,7 +698,7 @@ final class AcsMeetingSession {
686
698
  completion(.failure(AcsMeetingError("rebindSoftApIngest is only valid for a SoftAP call")))
687
699
  return
688
700
  }
689
- guard let address = GlassesHotspotNetwork.wifiAddress() else {
701
+ guard let address else {
690
702
  completion(.failure(AcsMeetingError("scoped network has no IPv4 address after rejoin")))
691
703
  return
692
704
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mentra/acs-meeting",
3
- "version": "3.3.0-dev.408",
3
+ "version": "3.3.0-dev.414",
4
4
  "description": "MentraOS native ACS Teams meeting module (WHEP decode → ACS raw media)",
5
5
  "main": "build/index.js",
6
6
  "react-native": "src/index.ts",
@@ -32,7 +32,7 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "@expo/config-plugins": "~55.0.10",
35
- "@mentra/glasses-media": "3.3.0-dev.408"
35
+ "@mentra/glasses-media": "3.3.0-dev.414"
36
36
  },
37
37
  "devDependencies": {
38
38
  "expo-module-scripts": "^55.0.2",