@furious.luke/argus-js 0.5.0 → 0.5.1

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.cts CHANGED
@@ -14,11 +14,23 @@ type TrackType = "camera" | "screen" | "audio";
14
14
  */
15
15
  type VideoTrackType = "camera" | "screen";
16
16
  /**
17
- * Declares the logical type of a single published track, keyed by the browser
18
- * `MediaStreamTrack.id`. The media server reads this to label the track
19
- * explicitly rather than guessing from the SDP msid.
17
+ * Declares the logical type and identity of a single published track.
18
+ *
19
+ * `mid` is the negotiated media-section id — the ROUTING key the server matches a
20
+ * track to its type by. It is used rather than the browser `MediaStreamTrack.id`
21
+ * because it is the only track identifier both peers agree on: Firefox mints an
22
+ * SDP msid track id unrelated to the `MediaStreamTrack.id`, so routing keyed on
23
+ * the latter cannot be matched server-side.
24
+ *
25
+ * `id` is the browser `MediaStreamTrack.id` — the GENERATION identity. The mid is
26
+ * stable across renegotiation and is reused when a track of the same type is
27
+ * republished on the same m-line, so it cannot distinguish a delayed end of a
28
+ * removed track from a failure of its replacement; the id changes with each new
29
+ * capture and can. The server echoes it in `media_track_ended`, and the publisher
30
+ * correlates that against the id it intentionally removed.
20
31
  */
21
32
  interface TrackLabel {
33
+ mid: string;
22
34
  id: string;
23
35
  type: TrackType;
24
36
  }
@@ -442,6 +454,13 @@ declare class Publisher {
442
454
  /** Builds the id → type label array declared to the server on every offer. */
443
455
  private buildTrackLabels;
444
456
  private labelsReplacingType;
457
+ /**
458
+ * The negotiated mid of the transceiver currently sending `track`, or null if
459
+ * none is found or it has not been negotiated yet. The mid is the identifier
460
+ * both peers agree on; it is assigned once setLocalDescription runs, which the
461
+ * publisher always does before sending an offer's labels.
462
+ */
463
+ private midForTrack;
445
464
  private stagePublish;
446
465
  private stageUnpublish;
447
466
  /** Stops every published local track and clears the published map. */
package/dist/index.d.ts CHANGED
@@ -14,11 +14,23 @@ type TrackType = "camera" | "screen" | "audio";
14
14
  */
15
15
  type VideoTrackType = "camera" | "screen";
16
16
  /**
17
- * Declares the logical type of a single published track, keyed by the browser
18
- * `MediaStreamTrack.id`. The media server reads this to label the track
19
- * explicitly rather than guessing from the SDP msid.
17
+ * Declares the logical type and identity of a single published track.
18
+ *
19
+ * `mid` is the negotiated media-section id — the ROUTING key the server matches a
20
+ * track to its type by. It is used rather than the browser `MediaStreamTrack.id`
21
+ * because it is the only track identifier both peers agree on: Firefox mints an
22
+ * SDP msid track id unrelated to the `MediaStreamTrack.id`, so routing keyed on
23
+ * the latter cannot be matched server-side.
24
+ *
25
+ * `id` is the browser `MediaStreamTrack.id` — the GENERATION identity. The mid is
26
+ * stable across renegotiation and is reused when a track of the same type is
27
+ * republished on the same m-line, so it cannot distinguish a delayed end of a
28
+ * removed track from a failure of its replacement; the id changes with each new
29
+ * capture and can. The server echoes it in `media_track_ended`, and the publisher
30
+ * correlates that against the id it intentionally removed.
20
31
  */
21
32
  interface TrackLabel {
33
+ mid: string;
22
34
  id: string;
23
35
  type: TrackType;
24
36
  }
@@ -442,6 +454,13 @@ declare class Publisher {
442
454
  /** Builds the id → type label array declared to the server on every offer. */
443
455
  private buildTrackLabels;
444
456
  private labelsReplacingType;
457
+ /**
458
+ * The negotiated mid of the transceiver currently sending `track`, or null if
459
+ * none is found or it has not been negotiated yet. The mid is the identifier
460
+ * both peers agree on; it is assigned once setLocalDescription runs, which the
461
+ * publisher always does before sending an offer's labels.
462
+ */
463
+ private midForTrack;
445
464
  private stagePublish;
446
465
  private stageUnpublish;
447
466
  /** Stops every published local track and clears the published map. */
package/dist/index.js CHANGED
@@ -151,10 +151,11 @@ var Publisher = class {
151
151
  // may later reuse any compatible inactive transceiver, not necessarily the one
152
152
  // that previously carried the same logical type.
153
153
  typeSenders = /* @__PURE__ */ new Map();
154
- // intentionalTrackEnds holds physical track ids removed by publish/unpublish
155
- // whose server-side `media_track_ended` has not yet arrived. Correlating by id
156
- // keeps a delayed end for an old screen track from being mistaken for failure
157
- // of a newly-published screen track.
154
+ // intentionalTrackEnds holds the browser track ids removed by publish/unpublish
155
+ // whose server-side `media_track_ended` has not yet arrived. Correlating by the
156
+ // track id (the generation identity the server echoes in track_id) keeps a
157
+ // delayed end for an old screen track from being mistaken for failure of a
158
+ // newly-published screen track.
158
159
  intentionalTrackEnds = /* @__PURE__ */ new Map();
159
160
  // negotiationChain serializes every offer/answer exchange, including recovery.
160
161
  // User operations do not resolve until their answer is applied, so no caller
@@ -1095,7 +1096,7 @@ var Publisher = class {
1095
1096
  sdp: local.sdp,
1096
1097
  sdp_type: "offer",
1097
1098
  negotiation_id: id,
1098
- tracks: change?.labels ?? this.buildTrackLabels(),
1099
+ tracks: change?.labels?.() ?? this.buildTrackLabels(),
1099
1100
  speech_enabled: this.speechEnabled || this.speechPending || void 0
1100
1101
  });
1101
1102
  this.releaseLocalCandidateBatch();
@@ -1504,7 +1505,7 @@ var Publisher = class {
1504
1505
  this.typeSenders.set(type, addedSender);
1505
1506
  }
1506
1507
  return {
1507
- labels: this.labelsReplacingType(type, track),
1508
+ labels: () => this.labelsReplacingType(type, track),
1508
1509
  commit: () => {
1509
1510
  for (const { track: oldTrack } of previous) {
1510
1511
  this.unwatchTrack(oldTrack);
@@ -1568,18 +1569,34 @@ var Publisher = class {
1568
1569
  buildTrackLabels() {
1569
1570
  const labels = [];
1570
1571
  for (const [track, type] of this.published) {
1571
- labels.push({ id: track.id, type });
1572
+ const mid = this.midForTrack(track);
1573
+ if (mid !== null) labels.push({ mid, id: track.id, type });
1572
1574
  }
1573
1575
  return labels;
1574
1576
  }
1575
1577
  labelsReplacingType(type, replacement) {
1576
1578
  const labels = [];
1577
1579
  for (const [track, publishedType] of this.published) {
1578
- if (publishedType !== type) labels.push({ id: track.id, type: publishedType });
1580
+ if (publishedType === type) continue;
1581
+ const mid = this.midForTrack(track);
1582
+ if (mid !== null) labels.push({ mid, id: track.id, type: publishedType });
1583
+ }
1584
+ if (replacement) {
1585
+ const mid = this.midForTrack(replacement);
1586
+ if (mid !== null) labels.push({ mid, id: replacement.id, type });
1579
1587
  }
1580
- if (replacement) labels.push({ id: replacement.id, type });
1581
1588
  return labels;
1582
1589
  }
1590
+ /**
1591
+ * The negotiated mid of the transceiver currently sending `track`, or null if
1592
+ * none is found or it has not been negotiated yet. The mid is the identifier
1593
+ * both peers agree on; it is assigned once setLocalDescription runs, which the
1594
+ * publisher always does before sending an offer's labels.
1595
+ */
1596
+ midForTrack(track) {
1597
+ const transceiver = this.pc?.getTransceivers().find((candidate) => candidate.sender.track === track);
1598
+ return transceiver?.mid ?? null;
1599
+ }
1583
1600
  async stagePublish(track, stream, type) {
1584
1601
  const pc = this.pc;
1585
1602
  if (!pc) throw new Error("publisher not started");
@@ -1610,7 +1627,7 @@ var Publisher = class {
1610
1627
  this.typeSenders.set(type, addedSender);
1611
1628
  }
1612
1629
  return {
1613
- labels: this.labelsReplacingType(type, track),
1630
+ labels: () => this.labelsReplacingType(type, track),
1614
1631
  commit: () => {
1615
1632
  this.cancelMediaRecovery(type);
1616
1633
  this.recoveryState(type).required = false;
@@ -1658,7 +1675,7 @@ var Publisher = class {
1658
1675
  for (const { track } of previous) this.expectIntentionalTrackEnd(track.id, type);
1659
1676
  pc.removeTrack(typeSender);
1660
1677
  return {
1661
- labels: this.labelsReplacingType(type),
1678
+ labels: () => this.labelsReplacingType(type),
1662
1679
  commit: () => {
1663
1680
  this.cancelMediaRecovery(type);
1664
1681
  this.recoveryState(type).required = false;