@defcomm/meetingsdk 0.3.1 → 0.3.3

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
@@ -512,6 +512,9 @@ var SFUClient = class {
512
512
  getScreenStream() {
513
513
  return this.screenStream;
514
514
  }
515
+ getRemoteScreenStream(participantId) {
516
+ return this.remoteScreenStreams.get(participantId) || null;
517
+ }
515
518
  setLocalStream(stream) {
516
519
  this.localStream = stream;
517
520
  }
@@ -931,19 +934,7 @@ var SFUClient = class {
931
934
  }
932
935
  case "screen_share_stopped": {
933
936
  const participantId = payload.participant_id;
934
- const screenStream = participantId ? this.remoteScreenStreams.get(participantId) : null;
935
937
  const trackId = payload.track_id;
936
- if (screenStream) {
937
- for (const track of screenStream.getVideoTracks()) {
938
- if (!trackId || this.normalizeRemoteTrackId(track.id) === String(trackId)) {
939
- screenStream.removeTrack(track);
940
- track.stop();
941
- }
942
- }
943
- if (screenStream.getTracks().length === 0 && participantId) {
944
- this.remoteScreenStreams.delete(participantId);
945
- }
946
- }
947
938
  this.onScreenShareStopped(participantId, trackId);
948
939
  break;
949
940
  }
@@ -1326,11 +1317,14 @@ var SFUClient = class {
1326
1317
  sdp: answer.sdp
1327
1318
  }
1328
1319
  });
1329
- const waiters = this.subscriptionWaiters.splice(0);
1330
- waiters.forEach((w) => w.resolve());
1320
+ const waiter = this.subscriptionWaiters.shift();
1321
+ waiter?.resolve();
1331
1322
  } catch (error) {
1332
- const waiters = this.subscriptionWaiters.splice(0);
1333
- waiters.forEach((w) => w.reject(error));
1323
+ const waiter = this.subscriptionWaiters.shift();
1324
+ if (waiter) {
1325
+ waiter.trackIds.forEach((id) => this.subscribedTracks.delete(id));
1326
+ waiter.reject(error);
1327
+ }
1334
1328
  this.onError(
1335
1329
  new Error(`Failed to process subscriber offer: ${String(error)}`)
1336
1330
  );
@@ -1352,11 +1346,20 @@ var SFUClient = class {
1352
1346
  if (!uniqueIds.length || !this.isSocketOpen()) return;
1353
1347
  uniqueIds.forEach((id) => this.subscribedTracks.add(id));
1354
1348
  return new Promise((resolve, reject) => {
1355
- this.subscriptionWaiters.push({ resolve, reject });
1356
- this.send({
1349
+ const sent = this.send({
1357
1350
  type: "subscribe",
1358
1351
  payload: { track_ids: uniqueIds }
1359
1352
  });
1353
+ if (!sent) {
1354
+ uniqueIds.forEach((id) => this.subscribedTracks.delete(id));
1355
+ reject(new Error("Signaling socket is not open"));
1356
+ return;
1357
+ }
1358
+ this.subscriptionWaiters.push({
1359
+ trackIds: uniqueIds,
1360
+ resolve,
1361
+ reject
1362
+ });
1360
1363
  });
1361
1364
  }
1362
1365
  async processSubscriptionQueue() {
@@ -1369,11 +1372,20 @@ var SFUClient = class {
1369
1372
  continue;
1370
1373
  }
1371
1374
  await new Promise((resolve, reject) => {
1372
- this.subscriptionWaiters.push({ resolve, reject });
1373
- this.send({
1375
+ const sent = this.send({
1374
1376
  type: "subscribe",
1375
1377
  payload: { track_ids: [trackId] }
1376
1378
  });
1379
+ if (!sent) {
1380
+ this.subscribedTracks.delete(trackId);
1381
+ reject(new Error("Signaling socket is not open"));
1382
+ return;
1383
+ }
1384
+ this.subscriptionWaiters.push({
1385
+ trackIds: [trackId],
1386
+ resolve,
1387
+ reject
1388
+ });
1377
1389
  });
1378
1390
  }
1379
1391
  } finally {
@@ -1431,9 +1443,16 @@ var SFUClient = class {
1431
1443
  if (!this.screenTransceiver || !this.screenSender) {
1432
1444
  throw new Error("Screen transceiver is not initialized");
1433
1445
  }
1434
- if (this.screenStream) {
1435
- return this.screenStream;
1446
+ const existing = this.screenStream;
1447
+ const existingTrack = this.screenSender.track;
1448
+ if (existing || existingTrack && existingTrack.readyState === "live") {
1449
+ return existing;
1436
1450
  }
1451
+ try {
1452
+ await this.screenSender.replaceTrack(null);
1453
+ } catch {
1454
+ }
1455
+ this.screenTransceiver.direction = "inactive";
1437
1456
  const screenStream = await navigator.mediaDevices.getDisplayMedia({
1438
1457
  video: true,
1439
1458
  audio: false
@@ -1443,29 +1462,33 @@ var SFUClient = class {
1443
1462
  screenStream.getTracks().forEach((track) => track.stop());
1444
1463
  throw new Error("Screen share returned no video track");
1445
1464
  }
1465
+ const generation = ++this.screenShareGeneration;
1446
1466
  this.screenStream = screenStream;
1447
1467
  try {
1448
1468
  await this.screenSender.replaceTrack(screenTrack);
1449
1469
  this.screenTransceiver.direction = "sendonly";
1470
+ this.send({
1471
+ type: "start_screen_share"
1472
+ });
1450
1473
  const offer = await this.publisher.createOffer();
1451
1474
  await this.publisher.setLocalDescription(offer);
1475
+ const localDescription = this.publisher.localDescription;
1476
+ if (!localDescription?.sdp) {
1477
+ throw new Error("Publisher did not produce a valid screen-share SDP");
1478
+ }
1452
1479
  this.send({
1453
1480
  type: "publish_offer",
1454
1481
  payload: {
1455
1482
  revision: ++this.publisherRevision,
1456
- sdp: offer.sdp
1483
+ sdp: localDescription.sdp
1457
1484
  }
1458
1485
  });
1459
- this.send({ type: "start_screen_share" });
1460
1486
  screenTrack.onended = () => {
1487
+ if (generation !== this.screenShareGeneration) {
1488
+ return;
1489
+ }
1461
1490
  void this.stopScreenShare();
1462
1491
  };
1463
- console.info("[publisher] Screen track attached", {
1464
- screenTrackId: screenTrack.id,
1465
- cameraTrackId: this.videoSender?.track?.id,
1466
- screenMid: this.screenTransceiver.mid,
1467
- cameraMid: this.cameraTransceiver?.mid
1468
- });
1469
1492
  return this.screenStream;
1470
1493
  } catch (error) {
1471
1494
  try {
@@ -1473,19 +1496,33 @@ var SFUClient = class {
1473
1496
  } catch {
1474
1497
  }
1475
1498
  this.screenTransceiver.direction = "inactive";
1476
- screenStream.getTracks().forEach((track) => track.stop());
1499
+ screenTrack.onended = null;
1500
+ screenStream.getTracks().forEach((track) => {
1501
+ try {
1502
+ track.stop();
1503
+ } catch {
1504
+ }
1505
+ });
1477
1506
  this.screenStream = null;
1478
1507
  try {
1479
- this.send({ type: "stop_screen_share" });
1508
+ this.send({
1509
+ type: "stop_screen_share"
1510
+ });
1480
1511
  } catch {
1481
1512
  }
1482
1513
  throw error;
1483
1514
  }
1484
1515
  }
1485
1516
  async stopScreenShare() {
1486
- if (!this.screenStream && !this.screenSender?.track) return;
1487
- const screenTrack = this.screenSender?.track || null;
1488
- if (screenTrack) screenTrack.onended = null;
1517
+ const stream = this.screenStream;
1518
+ const senderTrack = this.screenSender?.track || null;
1519
+ if (!stream && !senderTrack) {
1520
+ return;
1521
+ }
1522
+ ++this.screenShareGeneration;
1523
+ if (senderTrack) {
1524
+ senderTrack.onended = null;
1525
+ }
1489
1526
  try {
1490
1527
  await this.screenSender?.replaceTrack(null);
1491
1528
  } catch (error) {
@@ -1494,23 +1531,33 @@ var SFUClient = class {
1494
1531
  if (this.screenTransceiver) {
1495
1532
  this.screenTransceiver.direction = "inactive";
1496
1533
  }
1497
- this.send({ type: "stop_screen_share" });
1498
1534
  try {
1499
- const offer = await this.publisher?.createOffer();
1500
- if (offer && this.publisher) {
1535
+ if (this.publisher) {
1536
+ const offer = await this.publisher.createOffer();
1501
1537
  await this.publisher.setLocalDescription(offer);
1502
- this.send({
1503
- type: "publish_offer",
1504
- payload: {
1505
- revision: ++this.publisherRevision,
1506
- sdp: offer.sdp
1507
- }
1508
- });
1538
+ const localDescription = this.publisher.localDescription;
1539
+ if (localDescription?.sdp) {
1540
+ this.send({
1541
+ type: "publish_offer",
1542
+ payload: {
1543
+ revision: ++this.publisherRevision,
1544
+ sdp: localDescription.sdp
1545
+ }
1546
+ });
1547
+ }
1509
1548
  }
1510
1549
  } catch (error) {
1511
1550
  this.onError(error);
1512
1551
  }
1513
- this.screenStream?.getTracks().forEach((track) => track.stop());
1552
+ this.send({
1553
+ type: "stop_screen_share"
1554
+ });
1555
+ stream?.getTracks().forEach((track) => {
1556
+ try {
1557
+ track.stop();
1558
+ } catch {
1559
+ }
1560
+ });
1514
1561
  this.screenStream = null;
1515
1562
  if (this.currentParticipantId) {
1516
1563
  this.onScreenShareStopped(this.currentParticipantId);
@@ -2274,11 +2321,11 @@ var VideoSDKCore = class {
2274
2321
  // SCREEN SHARE
2275
2322
  onScreenShareStarted: (participantId, _track) => {
2276
2323
  console.log("[SFU] Screen share started", participantId);
2277
- if (participantId === this.myId && !this.screenStream) {
2278
- this.screenStream = this.sfuClient?.getScreenStream() ?? null;
2279
- }
2280
- this.state.setPresenterId(participantId);
2281
2324
  if (participantId === this.myId) {
2325
+ if (!this.screenStream) {
2326
+ this.screenStream = this.sfuClient?.getScreenStream() ?? null;
2327
+ }
2328
+ this.state.setPresenterId(participantId);
2282
2329
  this.state.updateLocalParticipant({
2283
2330
  media: {
2284
2331
  isScreenSharing: true,
@@ -2288,11 +2335,25 @@ var VideoSDKCore = class {
2288
2335
  });
2289
2336
  return;
2290
2337
  }
2338
+ this.state.setPresenterId(participantId);
2339
+ const existingRemoteScreen = this.sfuClient?.getRemoteScreenStream(participantId) ?? this.remoteScreenStreams.get(participantId) ?? null;
2340
+ if (existingRemoteScreen) {
2341
+ this.remoteScreenStreams.set(participantId, existingRemoteScreen);
2342
+ const screenTrack = existingRemoteScreen.getVideoTracks()[0];
2343
+ this.state.updateParticipantMedia(participantId, {
2344
+ isScreenSharing: true,
2345
+ screenStream: existingRemoteScreen,
2346
+ screenTrack
2347
+ });
2348
+ this.events.onScreenShareStarted?.(participantId, existingRemoteScreen);
2349
+ return;
2350
+ }
2291
2351
  const current = this.state.getParticipant(participantId);
2292
2352
  if (current) {
2293
2353
  this.state.updateParticipantMedia(participantId, {
2294
2354
  isScreenSharing: true,
2295
- screenStream: current.media?.screenStream ?? null
2355
+ screenStream: current.media?.screenStream ?? null,
2356
+ screenTrack: current.media?.screenTrack
2296
2357
  });
2297
2358
  }
2298
2359
  },
@@ -2310,13 +2371,8 @@ var VideoSDKCore = class {
2310
2371
  });
2311
2372
  return;
2312
2373
  }
2313
- const screen = this.remoteScreenStreams.get(participantId);
2314
- screen?.getTracks().forEach((track) => track.stop());
2315
- this.remoteScreenStreams.delete(participantId);
2316
2374
  this.state.updateParticipantMedia(participantId, {
2317
- isScreenSharing: false,
2318
- screenStream: null,
2319
- screenTrack: void 0
2375
+ isScreenSharing: false
2320
2376
  });
2321
2377
  this.events.onScreenShareStopped?.(participantId);
2322
2378
  },