@defcomm/meetingsdk 0.2.7 → 0.2.9

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/index.mjs CHANGED
@@ -357,6 +357,7 @@ var SFUClient = class {
357
357
  this.iceServers = [];
358
358
  this.requestId = 0;
359
359
  this.publisherRevision = 0;
360
+ this.screenShareGeneration = 0;
360
361
  this.currentParticipantId = null;
361
362
  this.token = null;
362
363
  this.room = null;
@@ -439,6 +440,8 @@ var SFUClient = class {
439
440
  this.onError = options.onError || console.error;
440
441
  this.onChatMessage = options.onChatMessage || (() => {
441
442
  });
443
+ this.onReaction = options.onReaction || (() => {
444
+ });
442
445
  this.onRoomUpdate = options.onRoomUpdate || (() => {
443
446
  });
444
447
  this.onParticipantMediaState = options.onParticipantMediaState || (() => {
@@ -565,8 +568,10 @@ var SFUClient = class {
565
568
  avatarUrl: options.avatarUrl
566
569
  };
567
570
  if (options.participantId) this.participantId = options.participantId;
568
- if (typeof options.audioMuted === "boolean") this.desiredAudioMuted = options.audioMuted;
569
- if (typeof options.videoMuted === "boolean") this.desiredVideoMuted = options.videoMuted;
571
+ if (typeof options.audioMuted === "boolean")
572
+ this.desiredAudioMuted = options.audioMuted;
573
+ if (typeof options.videoMuted === "boolean")
574
+ this.desiredVideoMuted = options.videoMuted;
570
575
  if (!this.resumeToken) {
571
576
  this.resumeToken = this.loadResumeToken(this.room);
572
577
  }
@@ -951,8 +956,15 @@ var SFUClient = class {
951
956
  if (!pid) continue;
952
957
  if (pid !== this.currentParticipantId) {
953
958
  this.participants.set(pid, participant);
954
- this.onParticipantPresence(pid, String(participant.presence || "connected"));
955
- this.onParticipantMediaState(pid, Boolean(participant.audio_muted), Boolean(participant.video_muted));
959
+ this.onParticipantPresence(
960
+ pid,
961
+ String(participant.presence || "connected")
962
+ );
963
+ this.onParticipantMediaState(
964
+ pid,
965
+ Boolean(participant.audio_muted),
966
+ Boolean(participant.video_muted)
967
+ );
956
968
  }
957
969
  }
958
970
  for (const [pid] of this.participants) {
@@ -964,7 +976,8 @@ var SFUClient = class {
964
976
  }
965
977
  for (const track of payload.tracks || []) this.rememberTrack(track);
966
978
  if (Array.isArray(payload.chat_history)) {
967
- for (const message2 of payload.chat_history) this.onChatMessage(message2);
979
+ for (const message2 of payload.chat_history)
980
+ this.onChatMessage(message2);
968
981
  }
969
982
  break;
970
983
  }
@@ -973,6 +986,11 @@ var SFUClient = class {
973
986
  if (msg?.id) this.onChatMessage(msg);
974
987
  break;
975
988
  }
989
+ case "reaction": {
990
+ const reaction = payload.reaction || payload;
991
+ if (reaction?.id && reaction?.emoji) this.onReaction(reaction);
992
+ break;
993
+ }
976
994
  case "error": {
977
995
  const message2 = payload.message || "SFU signaling error";
978
996
  if (this.state === "reconnecting" && message2.includes("participant session is stale")) {
@@ -997,7 +1015,9 @@ var SFUClient = class {
997
1015
  }
998
1016
  onRoomStateReconciled(payload) {
999
1017
  const participants = payload.participants || [];
1000
- const local = participants.find((p) => p?.participant_id === this.currentParticipantId);
1018
+ const local = participants.find(
1019
+ (p) => p?.participant_id === this.currentParticipantId
1020
+ );
1001
1021
  if (local) {
1002
1022
  this.desiredAudioMuted = Boolean(local.audio_muted);
1003
1023
  this.desiredVideoMuted = Boolean(local.video_muted);
@@ -1405,15 +1425,20 @@ var SFUClient = class {
1405
1425
  }
1406
1426
  }
1407
1427
  async shareScreen() {
1408
- if (!this.publisher) {
1428
+ if (!this.publisher)
1409
1429
  throw new Error("Publisher PeerConnection is not initialized");
1410
- }
1411
- if (!this.screenTransceiver || !this.screenSender) {
1430
+ if (!this.screenTransceiver || !this.screenSender)
1412
1431
  throw new Error("Screen transceiver is not initialized");
1432
+ const existing = this.screenStream;
1433
+ const existingTrack = this.screenSender.track;
1434
+ if (existing || existingTrack && existingTrack.readyState === "live") {
1435
+ return existing;
1413
1436
  }
1414
- if (this.screenStream) {
1415
- return this.screenStream;
1437
+ try {
1438
+ await this.screenSender.replaceTrack(null);
1439
+ } catch {
1416
1440
  }
1441
+ this.screenTransceiver.direction = "inactive";
1417
1442
  const screenStream = await navigator.mediaDevices.getDisplayMedia({
1418
1443
  video: true,
1419
1444
  audio: false
@@ -1423,29 +1448,22 @@ var SFUClient = class {
1423
1448
  screenStream.getTracks().forEach((track) => track.stop());
1424
1449
  throw new Error("Screen share returned no video track");
1425
1450
  }
1451
+ const generation = ++this.screenShareGeneration;
1426
1452
  this.screenStream = screenStream;
1427
1453
  try {
1428
1454
  await this.screenSender.replaceTrack(screenTrack);
1429
1455
  this.screenTransceiver.direction = "sendonly";
1456
+ this.send({ type: "start_screen_share" });
1430
1457
  const offer = await this.publisher.createOffer();
1431
1458
  await this.publisher.setLocalDescription(offer);
1432
1459
  this.send({
1433
1460
  type: "publish_offer",
1434
- payload: {
1435
- revision: ++this.publisherRevision,
1436
- sdp: offer.sdp
1437
- }
1461
+ payload: { revision: ++this.publisherRevision, sdp: offer.sdp }
1438
1462
  });
1439
- this.send({ type: "start_screen_share" });
1440
1463
  screenTrack.onended = () => {
1464
+ if (generation !== this.screenShareGeneration) return;
1441
1465
  void this.stopScreenShare();
1442
1466
  };
1443
- console.info("[publisher] Screen track attached", {
1444
- screenTrackId: screenTrack.id,
1445
- cameraTrackId: this.videoSender?.track?.id,
1446
- screenMid: this.screenTransceiver.mid,
1447
- cameraMid: this.cameraTransceiver?.mid
1448
- });
1449
1467
  return this.screenStream;
1450
1468
  } catch (error) {
1451
1469
  try {
@@ -1463,38 +1481,34 @@ var SFUClient = class {
1463
1481
  }
1464
1482
  }
1465
1483
  async stopScreenShare() {
1466
- if (!this.screenStream && !this.screenSender?.track) return;
1467
- const screenTrack = this.screenSender?.track || null;
1468
- if (screenTrack) screenTrack.onended = null;
1484
+ const stream = this.screenStream;
1485
+ const senderTrack = this.screenSender?.track || null;
1486
+ if (!stream && !senderTrack) return;
1487
+ ++this.screenShareGeneration;
1488
+ if (senderTrack) senderTrack.onended = null;
1469
1489
  try {
1470
1490
  await this.screenSender?.replaceTrack(null);
1471
1491
  } catch (error) {
1472
1492
  this.onError(error);
1473
1493
  }
1474
- if (this.screenTransceiver) {
1475
- this.screenTransceiver.direction = "inactive";
1476
- }
1477
- this.send({ type: "stop_screen_share" });
1494
+ if (this.screenTransceiver) this.screenTransceiver.direction = "inactive";
1478
1495
  try {
1479
1496
  const offer = await this.publisher?.createOffer();
1480
1497
  if (offer && this.publisher) {
1481
1498
  await this.publisher.setLocalDescription(offer);
1482
1499
  this.send({
1483
1500
  type: "publish_offer",
1484
- payload: {
1485
- revision: ++this.publisherRevision,
1486
- sdp: offer.sdp
1487
- }
1501
+ payload: { revision: ++this.publisherRevision, sdp: offer.sdp }
1488
1502
  });
1489
1503
  }
1490
1504
  } catch (error) {
1491
1505
  this.onError(error);
1492
1506
  }
1493
- this.screenStream?.getTracks().forEach((track) => track.stop());
1507
+ this.send({ type: "stop_screen_share" });
1508
+ stream?.getTracks().forEach((track) => track.stop());
1494
1509
  this.screenStream = null;
1495
- if (this.currentParticipantId) {
1510
+ if (this.currentParticipantId)
1496
1511
  this.onScreenShareStopped(this.currentParticipantId);
1497
- }
1498
1512
  }
1499
1513
  muteAudio(muted) {
1500
1514
  this.desiredAudioMuted = muted;
@@ -1597,6 +1611,14 @@ var SFUClient = class {
1597
1611
  );
1598
1612
  return true;
1599
1613
  }
1614
+ sendReaction(reaction) {
1615
+ this.send({
1616
+ type: "send_reaction",
1617
+ payload: {
1618
+ reaction
1619
+ }
1620
+ });
1621
+ }
1600
1622
  removeRemoteParticipant(participantId) {
1601
1623
  const stream = this.remoteStreams.get(participantId);
1602
1624
  if (stream) {
@@ -2015,7 +2037,9 @@ var VideoSDKCore = class {
2015
2037
  // ADMISSION CONTROL
2016
2038
  onRoomUpdate: (payload) => {
2017
2039
  const participants = payload?.participants || [];
2018
- const local = participants.find((p) => p?.participant_id === this.myId);
2040
+ const local = participants.find(
2041
+ (p) => p?.participant_id === this.myId
2042
+ );
2019
2043
  if (local) {
2020
2044
  const media = this.state.localParticipant?.media;
2021
2045
  this.state.updateLocalParticipant({
@@ -2038,7 +2062,8 @@ var VideoSDKCore = class {
2038
2062
  });
2039
2063
  }
2040
2064
  if (local.screen_sharing) this.state.setPresenterId(this.myId);
2041
- else if (this.state.presenterId === this.myId) this.state.setPresenterId(null);
2065
+ else if (this.state.presenterId === this.myId)
2066
+ this.state.setPresenterId(null);
2042
2067
  }
2043
2068
  const presenter = participants.find((p) => p?.screen_sharing);
2044
2069
  if (presenter) this.state.setPresenterId(presenter.participant_id);
@@ -2469,7 +2494,7 @@ var VideoSDKCore = class {
2469
2494
  media: {
2470
2495
  isScreenSharing: true,
2471
2496
  screenStream: this.screenStream,
2472
- screenTrack: this.screenStream.getVideoTracks()[0]
2497
+ screenTrack: this.screenStream?.getVideoTracks()[0]
2473
2498
  }
2474
2499
  });
2475
2500
  return this.screenStream;
@@ -2534,6 +2559,13 @@ var VideoSDKCore = class {
2534
2559
  target: payload.target ?? null
2535
2560
  });
2536
2561
  }
2562
+ sendReaction(reaction) {
2563
+ if (!this.sfuClient) {
2564
+ console.warn("SFU Client not connected");
2565
+ return;
2566
+ }
2567
+ this.sfuClient.sendReaction(reaction);
2568
+ }
2537
2569
  // CLEANUP
2538
2570
  cleanupRemoteParticipant(participantId) {
2539
2571
  this.activeSpeakerDetector.removeParticipant(participantId);
@@ -2620,6 +2652,7 @@ var MeetingProvider = ({
2620
2652
  const trackStateListeners = useRef(/* @__PURE__ */ new Set());
2621
2653
  const recordingStartedListeners = useRef(/* @__PURE__ */ new Set());
2622
2654
  const recordingStoppedListeners = useRef(/* @__PURE__ */ new Set());
2655
+ const reactionListeners = useRef(/* @__PURE__ */ new Set());
2623
2656
  const activeSpeakerListeners = useRef(
2624
2657
  /* @__PURE__ */ new Set()
2625
2658
  );
@@ -2649,6 +2682,9 @@ var MeetingProvider = ({
2649
2682
  },
2650
2683
  onRecordingStopped: (recording) => {
2651
2684
  recordingStoppedListeners.current.forEach((fn) => fn(recording));
2685
+ },
2686
+ onReaction: (reaction) => {
2687
+ reactionListeners.current.forEach((fn) => fn(reaction));
2652
2688
  }
2653
2689
  }
2654
2690
  );
@@ -2695,6 +2731,7 @@ var MeetingProvider = ({
2695
2731
  startScreenShare: sdk.startScreenShare.bind(sdk),
2696
2732
  stopScreenShare: sdk.stopScreenShare.bind(sdk),
2697
2733
  sendMessage: sdk.sendChatMessage.bind(sdk),
2734
+ sendReaction: sdk.sendReaction.bind(sdk),
2698
2735
  room: sdk.getMeeting(),
2699
2736
  localParticipant,
2700
2737
  participants,
@@ -2751,6 +2788,10 @@ var MeetingProvider = ({
2751
2788
  recordingStoppedListeners.current.add(cb);
2752
2789
  return () => recordingStoppedListeners.current.delete(cb);
2753
2790
  },
2791
+ onReaction: (cb) => {
2792
+ reactionListeners.current.add(cb);
2793
+ return () => reactionListeners.current.delete(cb);
2794
+ },
2754
2795
  onActiveSpeakersChanged: (cb) => {
2755
2796
  activeSpeakerListeners.current.add(cb);
2756
2797
  return () => {
@@ -2847,6 +2888,10 @@ var useMeeting = (handlers) => {
2847
2888
  if (!handlers?.onRecordingStopped) return;
2848
2889
  return ctx.onRecordingStopped(handlers.onRecordingStopped);
2849
2890
  }, [handlers?.onRecordingStopped]);
2891
+ useEffect3(() => {
2892
+ if (!handlers?.onReaction) return;
2893
+ return ctx.onReaction(handlers.onReaction);
2894
+ }, [handlers?.onReaction]);
2850
2895
  const { sdk: _, ...publicApi } = ctx;
2851
2896
  return publicApi;
2852
2897
  };