@defcomm/meetingsdk 0.2.7 → 0.2.8
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.d.mts +19 -1
- package/dist/index.d.ts +19 -1
- package/dist/index.js +124 -44
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +124 -44
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
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")
|
|
569
|
-
|
|
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(
|
|
955
|
-
|
|
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)
|
|
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(
|
|
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);
|
|
@@ -1411,9 +1431,27 @@ var SFUClient = class {
|
|
|
1411
1431
|
if (!this.screenTransceiver || !this.screenSender) {
|
|
1412
1432
|
throw new Error("Screen transceiver is not initialized");
|
|
1413
1433
|
}
|
|
1414
|
-
|
|
1434
|
+
const existingTrack = this.screenSender.track;
|
|
1435
|
+
if (this.screenStream && existingTrack && existingTrack.readyState === "live") {
|
|
1415
1436
|
return this.screenStream;
|
|
1416
1437
|
}
|
|
1438
|
+
const generation = ++this.screenShareGeneration;
|
|
1439
|
+
try {
|
|
1440
|
+
await this.screenSender.replaceTrack(null);
|
|
1441
|
+
} catch (err) {
|
|
1442
|
+
console.warn("[SFU] Failed to clear previous screen track", err);
|
|
1443
|
+
}
|
|
1444
|
+
if (this.screenStream) {
|
|
1445
|
+
for (const track of this.screenStream.getTracks()) {
|
|
1446
|
+
try {
|
|
1447
|
+
track.onended = null;
|
|
1448
|
+
track.stop();
|
|
1449
|
+
} catch {
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
this.screenStream = null;
|
|
1454
|
+
this.screenTransceiver.direction = "inactive";
|
|
1417
1455
|
const screenStream = await navigator.mediaDevices.getDisplayMedia({
|
|
1418
1456
|
video: true,
|
|
1419
1457
|
audio: false
|
|
@@ -1427,74 +1465,87 @@ var SFUClient = class {
|
|
|
1427
1465
|
try {
|
|
1428
1466
|
await this.screenSender.replaceTrack(screenTrack);
|
|
1429
1467
|
this.screenTransceiver.direction = "sendonly";
|
|
1468
|
+
this.send({
|
|
1469
|
+
type: "start_screen_share"
|
|
1470
|
+
});
|
|
1471
|
+
await new Promise((resolve) => {
|
|
1472
|
+
queueMicrotask(resolve);
|
|
1473
|
+
});
|
|
1430
1474
|
const offer = await this.publisher.createOffer();
|
|
1431
1475
|
await this.publisher.setLocalDescription(offer);
|
|
1476
|
+
const localDescription = this.publisher.localDescription;
|
|
1477
|
+
if (!localDescription?.sdp) {
|
|
1478
|
+
throw new Error("Publisher did not produce a valid screen-share SDP");
|
|
1479
|
+
}
|
|
1480
|
+
const revision = ++this.publisherRevision;
|
|
1432
1481
|
this.send({
|
|
1433
1482
|
type: "publish_offer",
|
|
1434
1483
|
payload: {
|
|
1435
|
-
revision
|
|
1436
|
-
sdp:
|
|
1484
|
+
revision,
|
|
1485
|
+
sdp: localDescription.sdp
|
|
1437
1486
|
}
|
|
1438
1487
|
});
|
|
1439
|
-
this.send({ type: "start_screen_share" });
|
|
1440
1488
|
screenTrack.onended = () => {
|
|
1489
|
+
if (generation !== this.screenShareGeneration) {
|
|
1490
|
+
return;
|
|
1491
|
+
}
|
|
1441
1492
|
void this.stopScreenShare();
|
|
1442
1493
|
};
|
|
1443
|
-
|
|
1444
|
-
screenTrackId: screenTrack.id,
|
|
1445
|
-
cameraTrackId: this.videoSender?.track?.id,
|
|
1446
|
-
screenMid: this.screenTransceiver.mid,
|
|
1447
|
-
cameraMid: this.cameraTransceiver?.mid
|
|
1448
|
-
});
|
|
1449
|
-
return this.screenStream;
|
|
1494
|
+
return screenStream;
|
|
1450
1495
|
} catch (error) {
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1496
|
+
if (generation === this.screenShareGeneration) {
|
|
1497
|
+
try {
|
|
1498
|
+
await this.screenSender.replaceTrack(null);
|
|
1499
|
+
} catch {
|
|
1500
|
+
}
|
|
1501
|
+
this.screenTransceiver.direction = "inactive";
|
|
1502
|
+
screenTrack.onended = null;
|
|
1503
|
+
screenStream.getTracks().forEach((track) => {
|
|
1504
|
+
try {
|
|
1505
|
+
track.stop();
|
|
1506
|
+
} catch {
|
|
1507
|
+
}
|
|
1508
|
+
});
|
|
1509
|
+
this.screenStream = null;
|
|
1510
|
+
try {
|
|
1511
|
+
this.send({
|
|
1512
|
+
type: "stop_screen_share"
|
|
1513
|
+
});
|
|
1514
|
+
} catch {
|
|
1515
|
+
}
|
|
1461
1516
|
}
|
|
1462
1517
|
throw error;
|
|
1463
1518
|
}
|
|
1464
1519
|
}
|
|
1465
1520
|
async stopScreenShare() {
|
|
1466
|
-
|
|
1467
|
-
const
|
|
1468
|
-
if (
|
|
1521
|
+
const stream = this.screenStream;
|
|
1522
|
+
const senderTrack = this.screenSender?.track || null;
|
|
1523
|
+
if (!stream && !senderTrack) return;
|
|
1524
|
+
++this.screenShareGeneration;
|
|
1525
|
+
if (senderTrack) senderTrack.onended = null;
|
|
1469
1526
|
try {
|
|
1470
1527
|
await this.screenSender?.replaceTrack(null);
|
|
1471
1528
|
} catch (error) {
|
|
1472
1529
|
this.onError(error);
|
|
1473
1530
|
}
|
|
1474
|
-
if (this.screenTransceiver)
|
|
1475
|
-
this.screenTransceiver.direction = "inactive";
|
|
1476
|
-
}
|
|
1477
|
-
this.send({ type: "stop_screen_share" });
|
|
1531
|
+
if (this.screenTransceiver) this.screenTransceiver.direction = "inactive";
|
|
1478
1532
|
try {
|
|
1479
1533
|
const offer = await this.publisher?.createOffer();
|
|
1480
1534
|
if (offer && this.publisher) {
|
|
1481
1535
|
await this.publisher.setLocalDescription(offer);
|
|
1482
1536
|
this.send({
|
|
1483
1537
|
type: "publish_offer",
|
|
1484
|
-
payload: {
|
|
1485
|
-
revision: ++this.publisherRevision,
|
|
1486
|
-
sdp: offer.sdp
|
|
1487
|
-
}
|
|
1538
|
+
payload: { revision: ++this.publisherRevision, sdp: offer.sdp }
|
|
1488
1539
|
});
|
|
1489
1540
|
}
|
|
1490
1541
|
} catch (error) {
|
|
1491
1542
|
this.onError(error);
|
|
1492
1543
|
}
|
|
1493
|
-
this.
|
|
1544
|
+
this.send({ type: "stop_screen_share" });
|
|
1545
|
+
stream?.getTracks().forEach((track) => track.stop());
|
|
1494
1546
|
this.screenStream = null;
|
|
1495
|
-
if (this.currentParticipantId)
|
|
1547
|
+
if (this.currentParticipantId)
|
|
1496
1548
|
this.onScreenShareStopped(this.currentParticipantId);
|
|
1497
|
-
}
|
|
1498
1549
|
}
|
|
1499
1550
|
muteAudio(muted) {
|
|
1500
1551
|
this.desiredAudioMuted = muted;
|
|
@@ -1597,6 +1648,12 @@ var SFUClient = class {
|
|
|
1597
1648
|
);
|
|
1598
1649
|
return true;
|
|
1599
1650
|
}
|
|
1651
|
+
sendReaction(reaction) {
|
|
1652
|
+
this.send({
|
|
1653
|
+
type: "send_reaction",
|
|
1654
|
+
reaction
|
|
1655
|
+
});
|
|
1656
|
+
}
|
|
1600
1657
|
removeRemoteParticipant(participantId) {
|
|
1601
1658
|
const stream = this.remoteStreams.get(participantId);
|
|
1602
1659
|
if (stream) {
|
|
@@ -2015,7 +2072,9 @@ var VideoSDKCore = class {
|
|
|
2015
2072
|
// ADMISSION CONTROL
|
|
2016
2073
|
onRoomUpdate: (payload) => {
|
|
2017
2074
|
const participants = payload?.participants || [];
|
|
2018
|
-
const local = participants.find(
|
|
2075
|
+
const local = participants.find(
|
|
2076
|
+
(p) => p?.participant_id === this.myId
|
|
2077
|
+
);
|
|
2019
2078
|
if (local) {
|
|
2020
2079
|
const media = this.state.localParticipant?.media;
|
|
2021
2080
|
this.state.updateLocalParticipant({
|
|
@@ -2038,7 +2097,8 @@ var VideoSDKCore = class {
|
|
|
2038
2097
|
});
|
|
2039
2098
|
}
|
|
2040
2099
|
if (local.screen_sharing) this.state.setPresenterId(this.myId);
|
|
2041
|
-
else if (this.state.presenterId === this.myId)
|
|
2100
|
+
else if (this.state.presenterId === this.myId)
|
|
2101
|
+
this.state.setPresenterId(null);
|
|
2042
2102
|
}
|
|
2043
2103
|
const presenter = participants.find((p) => p?.screen_sharing);
|
|
2044
2104
|
if (presenter) this.state.setPresenterId(presenter.participant_id);
|
|
@@ -2469,7 +2529,7 @@ var VideoSDKCore = class {
|
|
|
2469
2529
|
media: {
|
|
2470
2530
|
isScreenSharing: true,
|
|
2471
2531
|
screenStream: this.screenStream,
|
|
2472
|
-
screenTrack: this.screenStream
|
|
2532
|
+
screenTrack: this.screenStream?.getVideoTracks()[0]
|
|
2473
2533
|
}
|
|
2474
2534
|
});
|
|
2475
2535
|
return this.screenStream;
|
|
@@ -2534,6 +2594,13 @@ var VideoSDKCore = class {
|
|
|
2534
2594
|
target: payload.target ?? null
|
|
2535
2595
|
});
|
|
2536
2596
|
}
|
|
2597
|
+
sendReaction(reaction) {
|
|
2598
|
+
if (!this.sfuClient) {
|
|
2599
|
+
console.warn("SFU Client not connected");
|
|
2600
|
+
return;
|
|
2601
|
+
}
|
|
2602
|
+
this.sfuClient.sendReaction(reaction);
|
|
2603
|
+
}
|
|
2537
2604
|
// CLEANUP
|
|
2538
2605
|
cleanupRemoteParticipant(participantId) {
|
|
2539
2606
|
this.activeSpeakerDetector.removeParticipant(participantId);
|
|
@@ -2620,6 +2687,7 @@ var MeetingProvider = ({
|
|
|
2620
2687
|
const trackStateListeners = useRef(/* @__PURE__ */ new Set());
|
|
2621
2688
|
const recordingStartedListeners = useRef(/* @__PURE__ */ new Set());
|
|
2622
2689
|
const recordingStoppedListeners = useRef(/* @__PURE__ */ new Set());
|
|
2690
|
+
const reactionListeners = useRef(/* @__PURE__ */ new Set());
|
|
2623
2691
|
const activeSpeakerListeners = useRef(
|
|
2624
2692
|
/* @__PURE__ */ new Set()
|
|
2625
2693
|
);
|
|
@@ -2649,6 +2717,9 @@ var MeetingProvider = ({
|
|
|
2649
2717
|
},
|
|
2650
2718
|
onRecordingStopped: (recording) => {
|
|
2651
2719
|
recordingStoppedListeners.current.forEach((fn) => fn(recording));
|
|
2720
|
+
},
|
|
2721
|
+
onReaction: (reaction) => {
|
|
2722
|
+
reactionListeners.current.forEach((fn) => fn(reaction));
|
|
2652
2723
|
}
|
|
2653
2724
|
}
|
|
2654
2725
|
);
|
|
@@ -2695,6 +2766,7 @@ var MeetingProvider = ({
|
|
|
2695
2766
|
startScreenShare: sdk.startScreenShare.bind(sdk),
|
|
2696
2767
|
stopScreenShare: sdk.stopScreenShare.bind(sdk),
|
|
2697
2768
|
sendMessage: sdk.sendChatMessage.bind(sdk),
|
|
2769
|
+
sendReaction: sdk.sendReaction.bind(sdk),
|
|
2698
2770
|
room: sdk.getMeeting(),
|
|
2699
2771
|
localParticipant,
|
|
2700
2772
|
participants,
|
|
@@ -2751,6 +2823,10 @@ var MeetingProvider = ({
|
|
|
2751
2823
|
recordingStoppedListeners.current.add(cb);
|
|
2752
2824
|
return () => recordingStoppedListeners.current.delete(cb);
|
|
2753
2825
|
},
|
|
2826
|
+
onReaction: (cb) => {
|
|
2827
|
+
reactionListeners.current.add(cb);
|
|
2828
|
+
return () => reactionListeners.current.delete(cb);
|
|
2829
|
+
},
|
|
2754
2830
|
onActiveSpeakersChanged: (cb) => {
|
|
2755
2831
|
activeSpeakerListeners.current.add(cb);
|
|
2756
2832
|
return () => {
|
|
@@ -2847,6 +2923,10 @@ var useMeeting = (handlers) => {
|
|
|
2847
2923
|
if (!handlers?.onRecordingStopped) return;
|
|
2848
2924
|
return ctx.onRecordingStopped(handlers.onRecordingStopped);
|
|
2849
2925
|
}, [handlers?.onRecordingStopped]);
|
|
2926
|
+
useEffect3(() => {
|
|
2927
|
+
if (!handlers?.onReaction) return;
|
|
2928
|
+
return ctx.onReaction(handlers.onReaction);
|
|
2929
|
+
}, [handlers?.onReaction]);
|
|
2850
2930
|
const { sdk: _, ...publicApi } = ctx;
|
|
2851
2931
|
return publicApi;
|
|
2852
2932
|
};
|