@ai-matrx/meet 0.11.34 → 0.11.36

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/dist/core.d.cts CHANGED
@@ -2020,6 +2020,12 @@ interface MeetRoomDriver {
2020
2020
  * (the gesture is what the browser checks). Optional: a driver without it never blocks.
2021
2021
  */
2022
2022
  startAudio?(): Promise<void>;
2023
+ /**
2024
+ * S7 — a "join here too" companion plays no remote audio (the person's other device does; two
2025
+ * speakers in one room echo). `false` removes every attached remote audio element and keeps new
2026
+ * ones from attaching. Optional: a driver without it always plays.
2027
+ */
2028
+ setRemoteAudioPlayback?(enabled: boolean): void;
2023
2029
  }
2024
2030
  type RoomDriverFactory = (handlers: RoomDriverHandlers) => MeetRoomDriver | Promise<MeetRoomDriver>;
2025
2031
  /** Topics for the in-room control plane. One place, so senders cannot drift. */
@@ -2522,6 +2528,13 @@ interface RoomEngine {
2522
2528
  leave(): Promise<void>;
2523
2529
  /** The person's own "back to the device check" press from `left` / `disconnected`. */
2524
2530
  backToPrejoin(): void;
2531
+ /**
2532
+ * S7: BEFORE Join — is this person already live in `roomName` on another tab of THIS browser
2533
+ * (`TabClaim.presentElsewhere`)? When yes the pre-join offers Switch here / Join here too up
2534
+ * front (the same choice the server would otherwise ask after the press). Returns whether it did.
2535
+ * A guest has no stable person key before the pass, so the server's own answer covers them.
2536
+ */
2537
+ checkElsewhere(roomName: RoomName): Promise<boolean>;
2525
2538
  /** Clear a refused-share notice (the `share` region) the person dismissed. */
2526
2539
  dismissShareNotice(): void;
2527
2540
  setMicrophoneEnabled(enabled: boolean): Promise<void>;
package/dist/core.d.ts CHANGED
@@ -2020,6 +2020,12 @@ interface MeetRoomDriver {
2020
2020
  * (the gesture is what the browser checks). Optional: a driver without it never blocks.
2021
2021
  */
2022
2022
  startAudio?(): Promise<void>;
2023
+ /**
2024
+ * S7 — a "join here too" companion plays no remote audio (the person's other device does; two
2025
+ * speakers in one room echo). `false` removes every attached remote audio element and keeps new
2026
+ * ones from attaching. Optional: a driver without it always plays.
2027
+ */
2028
+ setRemoteAudioPlayback?(enabled: boolean): void;
2023
2029
  }
2024
2030
  type RoomDriverFactory = (handlers: RoomDriverHandlers) => MeetRoomDriver | Promise<MeetRoomDriver>;
2025
2031
  /** Topics for the in-room control plane. One place, so senders cannot drift. */
@@ -2522,6 +2528,13 @@ interface RoomEngine {
2522
2528
  leave(): Promise<void>;
2523
2529
  /** The person's own "back to the device check" press from `left` / `disconnected`. */
2524
2530
  backToPrejoin(): void;
2531
+ /**
2532
+ * S7: BEFORE Join — is this person already live in `roomName` on another tab of THIS browser
2533
+ * (`TabClaim.presentElsewhere`)? When yes the pre-join offers Switch here / Join here too up
2534
+ * front (the same choice the server would otherwise ask after the press). Returns whether it did.
2535
+ * A guest has no stable person key before the pass, so the server's own answer covers them.
2536
+ */
2537
+ checkElsewhere(roomName: RoomName): Promise<boolean>;
2525
2538
  /** Clear a refused-share notice (the `share` region) the person dismissed. */
2526
2539
  dismissShareNotice(): void;
2527
2540
  setMicrophoneEnabled(enabled: boolean): Promise<void>;
package/dist/core.js CHANGED
@@ -4482,6 +4482,7 @@ function createLiveKitDriver(handlers, options = {}) {
4482
4482
  projectRoster = roster;
4483
4483
  created.on(RoomEvent.TrackSubscribed, (track) => {
4484
4484
  if (track.kind !== Track.Kind.Audio || typeof document === "undefined") return;
4485
+ if (!remoteAudioPlayback) return;
4485
4486
  const element = track.attach();
4486
4487
  element.setAttribute("data-mx-meet-audio", "");
4487
4488
  audioSink().appendChild(element);
@@ -4566,6 +4567,7 @@ function createLiveKitDriver(handlers, options = {}) {
4566
4567
  let sources = null;
4567
4568
  let trackEvents = null;
4568
4569
  let audioContainer = null;
4570
+ let remoteAudioPlayback = true;
4569
4571
  function audioSink() {
4570
4572
  if (audioContainer !== null && audioContainer.isConnected) return audioContainer;
4571
4573
  const container = document.createElement("div");
@@ -4724,6 +4726,14 @@ function createLiveKitDriver(handlers, options = {}) {
4724
4726
  throw normalizeDeviceError(error, "meet.switchDevice");
4725
4727
  }
4726
4728
  },
4729
+ setRemoteAudioPlayback(enabled) {
4730
+ remoteAudioPlayback = enabled;
4731
+ if (enabled || audioContainer === null) return;
4732
+ for (const element of Array.from(audioContainer.querySelectorAll("[data-mx-meet-audio]"))) {
4733
+ if (element instanceof HTMLMediaElement) element.srcObject = null;
4734
+ element.remove();
4735
+ }
4736
+ },
4727
4737
  async startAudio() {
4728
4738
  const target = room;
4729
4739
  if (target === null) return;
@@ -6628,6 +6638,7 @@ function createRoomEngine(options) {
6628
6638
  return;
6629
6639
  }
6630
6640
  driver = created;
6641
+ if (token.connectionKind === "companion") created.setRemoteAudioPlayback?.(false);
6631
6642
  await created.connect(token.serverUrl, token.token);
6632
6643
  store.patch({ failure: null, connection: "stable" });
6633
6644
  store.dispatch({ type: "connected" });
@@ -6889,6 +6900,19 @@ function createRoomEngine(options) {
6889
6900
  }
6890
6901
  },
6891
6902
  leave: leaveRoom,
6903
+ async checkElsewhere(roomName) {
6904
+ const claim = options.tabClaim;
6905
+ const userId = identity.userId;
6906
+ if (claim === void 0 || userId === null) return false;
6907
+ const before = store.snapshot();
6908
+ if (before.phase !== "prejoin" || before.secondDevice !== null) return false;
6909
+ if (!await claim.presentElsewhere(String(roomName), `user:${String(userId)}`)) return false;
6910
+ const now2 = store.snapshot();
6911
+ if (now2.phase !== "prejoin" || now2.secondDevice !== null) return false;
6912
+ store.patch({ secondDevice: { rule: "ask_switch_or_join" } });
6913
+ report("info", "meet: this browser already has you in this meeting \u2014 offering the choice before Join");
6914
+ return true;
6915
+ },
6892
6916
  backToPrejoin() {
6893
6917
  store.dispatch({ type: "back_to_prejoin", click: true });
6894
6918
  },