@blockcast/mmt-transport 0.3.0 → 0.4.0-main.404c51bd317c

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.
Files changed (91) hide show
  1. package/README.md +4 -0
  2. package/dist/index.d.ts +3 -2
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +3 -2
  5. package/dist/index.js.map +1 -1
  6. package/dist/mmt-transport.no-modules.js +163 -23
  7. package/dist/mmt-transport.no-modules.js.map +4 -4
  8. package/dist/multicast-catalog-policy.d.ts +34 -2
  9. package/dist/multicast-catalog-policy.d.ts.map +1 -1
  10. package/dist/multicast-catalog-policy.js +126 -22
  11. package/dist/multicast-catalog-policy.js.map +1 -1
  12. package/dist/multicast-orchestrator.d.ts +11 -0
  13. package/dist/multicast-orchestrator.d.ts.map +1 -1
  14. package/dist/multicast-orchestrator.js +26 -1
  15. package/dist/multicast-orchestrator.js.map +1 -1
  16. package/dist/multicast-signaling-reconciler.js +1 -1
  17. package/dist/multicast-signaling-reconciler.js.map +1 -1
  18. package/dist/multicast-tier-executor.d.ts +81 -0
  19. package/dist/multicast-tier-executor.d.ts.map +1 -0
  20. package/dist/multicast-tier-executor.js +167 -0
  21. package/dist/multicast-tier-executor.js.map +1 -0
  22. package/dist/multicast-tiers.d.ts +4 -0
  23. package/dist/multicast-tiers.d.ts.map +1 -0
  24. package/dist/multicast-tiers.js +6 -0
  25. package/dist/multicast-tiers.js.map +1 -0
  26. package/dist/no-modules.d.ts +2 -1
  27. package/dist/no-modules.d.ts.map +1 -1
  28. package/dist/no-modules.js +2 -1
  29. package/dist/no-modules.js.map +1 -1
  30. package/dist/transport-manager.d.ts +2 -0
  31. package/dist/transport-manager.d.ts.map +1 -1
  32. package/dist/transport-manager.js +4 -0
  33. package/dist/transport-manager.js.map +1 -1
  34. package/package.json +13 -6
  35. package/src/index.ts +12 -0
  36. package/src/multicast-catalog-policy.ts +145 -25
  37. package/src/multicast-orchestrator.ts +24 -1
  38. package/src/multicast-signaling-reconciler.ts +1 -1
  39. package/src/multicast-tier-executor.ts +226 -0
  40. package/src/multicast-tiers.ts +30 -0
  41. package/src/no-modules.ts +2 -0
  42. package/src/transport-manager.ts +5 -0
  43. package/vectors/multicast-tier-switch/README.md +18 -0
  44. package/vectors/multicast-tier-switch/cases.json +646 -0
  45. package/vectors/pim-cast/ladder-catalog-v1.json +388 -0
  46. package/node_modules/@blockcast/mmt-alta-parse/README.md +0 -181
  47. package/node_modules/@blockcast/mmt-alta-parse/dist/.build-stamp +0 -0
  48. package/node_modules/@blockcast/mmt-alta-parse/dist/index.d.ts +0 -57
  49. package/node_modules/@blockcast/mmt-alta-parse/dist/index.d.ts.map +0 -1
  50. package/node_modules/@blockcast/mmt-alta-parse/dist/index.js +0 -115
  51. package/node_modules/@blockcast/mmt-alta-parse/dist/index.js.map +0 -1
  52. package/node_modules/@blockcast/mmt-alta-parse/package.json +0 -50
  53. package/node_modules/@blockcast/mmt-alta-parse/src/index.ts +0 -136
  54. package/node_modules/@blockcast/mmt-base/README.md +0 -134
  55. package/node_modules/@blockcast/mmt-base/dist/.build-stamp +0 -0
  56. package/node_modules/@blockcast/mmt-base/dist/fec-block-profile.d.ts +0 -55
  57. package/node_modules/@blockcast/mmt-base/dist/fec-block-profile.d.ts.map +0 -1
  58. package/node_modules/@blockcast/mmt-base/dist/fec-block-profile.js +0 -128
  59. package/node_modules/@blockcast/mmt-base/dist/fec-block-profile.js.map +0 -1
  60. package/node_modules/@blockcast/mmt-base/dist/index.d.ts +0 -7
  61. package/node_modules/@blockcast/mmt-base/dist/index.d.ts.map +0 -1
  62. package/node_modules/@blockcast/mmt-base/dist/index.js +0 -7
  63. package/node_modules/@blockcast/mmt-base/dist/index.js.map +0 -1
  64. package/node_modules/@blockcast/mmt-base/dist/mmtp.d.ts +0 -292
  65. package/node_modules/@blockcast/mmt-base/dist/mmtp.d.ts.map +0 -1
  66. package/node_modules/@blockcast/mmt-base/dist/mmtp.js +0 -612
  67. package/node_modules/@blockcast/mmt-base/dist/mmtp.js.map +0 -1
  68. package/node_modules/@blockcast/mmt-base/dist/net-constants.d.ts +0 -18
  69. package/node_modules/@blockcast/mmt-base/dist/net-constants.d.ts.map +0 -1
  70. package/node_modules/@blockcast/mmt-base/dist/net-constants.js +0 -18
  71. package/node_modules/@blockcast/mmt-base/dist/net-constants.js.map +0 -1
  72. package/node_modules/@blockcast/mmt-base/dist/ntp-short.d.ts +0 -47
  73. package/node_modules/@blockcast/mmt-base/dist/ntp-short.d.ts.map +0 -1
  74. package/node_modules/@blockcast/mmt-base/dist/ntp-short.js +0 -54
  75. package/node_modules/@blockcast/mmt-base/dist/ntp-short.js.map +0 -1
  76. package/node_modules/@blockcast/mmt-base/dist/serial-number.d.ts +0 -57
  77. package/node_modules/@blockcast/mmt-base/dist/serial-number.d.ts.map +0 -1
  78. package/node_modules/@blockcast/mmt-base/dist/serial-number.js +0 -98
  79. package/node_modules/@blockcast/mmt-base/dist/serial-number.js.map +0 -1
  80. package/node_modules/@blockcast/mmt-base/dist/signalling.d.ts +0 -312
  81. package/node_modules/@blockcast/mmt-base/dist/signalling.d.ts.map +0 -1
  82. package/node_modules/@blockcast/mmt-base/dist/signalling.js +0 -637
  83. package/node_modules/@blockcast/mmt-base/dist/signalling.js.map +0 -1
  84. package/node_modules/@blockcast/mmt-base/package.json +0 -49
  85. package/node_modules/@blockcast/mmt-base/src/fec-block-profile.ts +0 -145
  86. package/node_modules/@blockcast/mmt-base/src/index.ts +0 -6
  87. package/node_modules/@blockcast/mmt-base/src/mmtp.ts +0 -892
  88. package/node_modules/@blockcast/mmt-base/src/net-constants.ts +0 -17
  89. package/node_modules/@blockcast/mmt-base/src/ntp-short.ts +0 -67
  90. package/node_modules/@blockcast/mmt-base/src/serial-number.ts +0 -107
  91. package/node_modules/@blockcast/mmt-base/src/signalling.ts +0 -862
package/README.md CHANGED
@@ -53,9 +53,13 @@ The manager owns capability detection, transport selection, and the bandwidth/lo
53
53
  |------|---------|
54
54
  | `@blockcast/mmt-transport` | `TransportManager`, DRIAD, AMT, ABR, repair-track naming, types |
55
55
  | `@blockcast/mmt-transport/clock` | `SharedClock`, `SYNC_TOLERANCE_US`, `PTS_OFFSET_US` |
56
+ | `@blockcast/mmt-transport/multicast-catalog-policy` | Catalog → endpoint/packet-ID policy (`normalizeCatalogEndpoints`, `selectMulticastCandidateForTracks`, `endpointToMulticastConfig`, `selectEndpointPacketIdsForTracks`, …) |
57
+ | `@blockcast/mmt-transport/multicast-tiers` | Tier switching without `TransportManager` (`MulticastOrchestrator`, `MulticastTierExecutor`, `tierPacketFromRouted`, `endpointKey`, `selectMulticastTier`, …) |
56
58
 
57
59
  The root export also re-emits the clock surface. Use the clock subpath when you want a narrower dependency graph.
58
60
 
61
+ The root export constructs the AMT gateway singleton when it is loaded. A player that only needs the catalog policy imports the `multicast-catalog-policy` subpath, and one that drives tier joins with its own engine imports the `multicast-tiers` subpath. Neither has load-time side effects.
62
+
59
63
  ## Transport matrix
60
64
 
61
65
  | Mode | When it's used | Requirements | Latency profile | Fallback |
package/dist/index.d.ts CHANGED
@@ -27,10 +27,11 @@ export { repairTrackPath, MoqFecAlgorithm, } from "./types.js";
27
27
  export { TransportManager, transportManager } from "./transport-manager.js";
28
28
  export { DRIADDiscovery, driadDiscovery } from "./driad-discovery.js";
29
29
  export { AdaptiveBitrateController, validateQualityLadder, type AdaptiveBitrateControllerOptions, QUALITY_LEVELS, type FecStatsForAbr, } from "./abr-controller.js";
30
- export { endpointKey, selectMulticastTier, type MulticastTierEndpoint, } from "./multicast-tier.js";
30
+ export { carriesMedia, endpointKey, selectMulticastTier, type MulticastTierEndpoint, } from "./multicast-tier.js";
31
31
  export { MulticastOrchestrator, DEFAULT_DWELL_MS, DEFAULT_JOIN_DEADLINE_MS, goodputFromStats, type GoodputSample, type HeadroomSample, type MulticastTierPacket, type OrchestratorCommand, type OrchestratorOptions, type OrchestratorState, } from "./multicast-orchestrator.js";
32
+ export { MulticastTierExecutor, tierPacketFromRouted, type MulticastTierDriver, type MulticastTierHost, type MulticastTierPacketReport, type MulticastTierSession, } from "./multicast-tier-executor.js";
32
33
  export { createMulticastSignalingReconciler, normalizeCatalogEndpoints, type MulticastSignalingEndpoint, } from "./multicast-signaling-reconciler.js";
33
- export { catalogTierEndpoints, endpointCarriesMedia, endpointToMulticastConfig, hasMulticastCatalogBaseline, hasUnicastMediaRenditions, isMulticastOnlyCatalog, isRecoverableMulticastSignalReadError, mergeUrlMulticastPolicy, normalizeMulticastConfig, readPlayerMulticastConfig, requiresMulticastCapability, sameMulticastConfig, selectEndpointPacketIds, selectEndpointPacketIdsForTracks, selectMulticastCandidate, selectMulticastCandidateForTracks, urlOverrideBlocksMulticastCandidate, withMulticastEndpoints, catalogQualityLadder, type PlayerMulticastConfig, type MulticastTrackSelection, } from "./multicast-catalog-policy.js";
34
+ export { catalogTierEndpoints, endpointCarriesMedia, endpointToMulticastConfig, hasMulticastCatalogBaseline, hasUnicastMediaRenditions, isMulticastOnlyCatalog, isRecoverableMulticastSignalReadError, mergeUrlMulticastPolicy, normalizeMulticastConfig, readPlayerMulticastConfig, requiresMulticastCapability, sameMulticastConfig, selectEndpointPacketIds, selectEndpointPacketIdsForTracks, selectRepairEndpointsForTracks, selectMulticastCandidate, selectMulticastCandidateForTracks, urlOverrideBlocksMulticastCandidate, withMulticastEndpoints, catalogQualityLadder, type PlayerMulticastConfig, type MulticastTrackSelection, type MulticastRepairCompanion, } from "./multicast-catalog-policy.js";
34
35
  export { isMulticastExplicitlyDisabled, isMulticastTrackPacketId, isUsableMulticastEndpoint, isValidMulticastGroupAddress, multicastEndpointKey, normalizeMulticastEndpoint, readUrlMulticastConfig, toWindowMulticastSubscribeConfig, type MulticastEndpointConfig, type MulticastTransportPreference, type WindowMulticastEndpointInput, } from "./endpoint-config.js";
35
36
  export { subscriptionDeliversPacketBatches } from "./packet-batch.js";
36
37
  export { MulticastSubscriptionPool, multicastSubscriptionPool, type MulticastSubscriptionConsumer, type MulticastSubscriptionLease, } from "./multicast-subscription-pool.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -29,10 +29,11 @@ export { TransportManager, transportManager } from "./transport-manager.js";
29
29
  export { DRIADDiscovery, driadDiscovery } from "./driad-discovery.js";
30
30
  // Adaptive Bitrate Controller
31
31
  export { AdaptiveBitrateController, validateQualityLadder, QUALITY_LEVELS, } from "./abr-controller.js";
32
- export { endpointKey, selectMulticastTier, } from "./multicast-tier.js";
32
+ export { carriesMedia, endpointKey, selectMulticastTier, } from "./multicast-tier.js";
33
33
  export { MulticastOrchestrator, DEFAULT_DWELL_MS, DEFAULT_JOIN_DEADLINE_MS, goodputFromStats, } from "./multicast-orchestrator.js";
34
+ export { MulticastTierExecutor, tierPacketFromRouted, } from "./multicast-tier-executor.js";
34
35
  export { createMulticastSignalingReconciler, normalizeCatalogEndpoints, } from "./multicast-signaling-reconciler.js";
35
- export { catalogTierEndpoints, endpointCarriesMedia, endpointToMulticastConfig, hasMulticastCatalogBaseline, hasUnicastMediaRenditions, isMulticastOnlyCatalog, isRecoverableMulticastSignalReadError, mergeUrlMulticastPolicy, normalizeMulticastConfig, readPlayerMulticastConfig, requiresMulticastCapability, sameMulticastConfig, selectEndpointPacketIds, selectEndpointPacketIdsForTracks, selectMulticastCandidate, selectMulticastCandidateForTracks, urlOverrideBlocksMulticastCandidate, withMulticastEndpoints, catalogQualityLadder, } from "./multicast-catalog-policy.js";
36
+ export { catalogTierEndpoints, endpointCarriesMedia, endpointToMulticastConfig, hasMulticastCatalogBaseline, hasUnicastMediaRenditions, isMulticastOnlyCatalog, isRecoverableMulticastSignalReadError, mergeUrlMulticastPolicy, normalizeMulticastConfig, readPlayerMulticastConfig, requiresMulticastCapability, sameMulticastConfig, selectEndpointPacketIds, selectEndpointPacketIdsForTracks, selectRepairEndpointsForTracks, selectMulticastCandidate, selectMulticastCandidateForTracks, urlOverrideBlocksMulticastCandidate, withMulticastEndpoints, catalogQualityLadder, } from "./multicast-catalog-policy.js";
36
37
  export { isMulticastExplicitlyDisabled, isMulticastTrackPacketId, isUsableMulticastEndpoint, isValidMulticastGroupAddress, multicastEndpointKey, normalizeMulticastEndpoint, readUrlMulticastConfig, toWindowMulticastSubscribeConfig, } from "./endpoint-config.js";
37
38
  export { subscriptionDeliversPacketBatches } from "./packet-batch.js";
38
39
  export { MulticastSubscriptionPool, multicastSubscriptionPool, } from "./multicast-subscription-pool.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAuCH,2DAA2D;AAC3D,OAAO,EACN,eAAe,EACf,eAAe,GACf,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE5E,kBAAkB;AAClB,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtE,8BAA8B;AAC9B,OAAO,EACN,yBAAyB,EACzB,qBAAqB,EAErB,cAAc,GAEd,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACN,WAAW,EACX,mBAAmB,GAEnB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACN,qBAAqB,EACrB,gBAAgB,EAChB,wBAAwB,EACxB,gBAAgB,GAOhB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EACN,kCAAkC,EAClC,yBAAyB,GAEzB,MAAM,qCAAqC,CAAC;AAE7C,OAAO,EACN,oBAAoB,EACpB,oBAAoB,EACpB,yBAAyB,EACzB,2BAA2B,EAC3B,yBAAyB,EACzB,sBAAsB,EACtB,qCAAqC,EACrC,uBAAuB,EACvB,wBAAwB,EACxB,yBAAyB,EACzB,2BAA2B,EAC3B,mBAAmB,EACnB,uBAAuB,EACvB,gCAAgC,EAChC,wBAAwB,EACxB,iCAAiC,EACjC,mCAAmC,EACnC,sBAAsB,EACtB,oBAAoB,GAGpB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EACN,6BAA6B,EAC7B,wBAAwB,EACxB,yBAAyB,EACzB,4BAA4B,EAC5B,oBAAoB,EACpB,0BAA0B,EAC1B,sBAAsB,EACtB,gCAAgC,GAIhC,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,iCAAiC,EAAE,MAAM,mBAAmB,CAAC;AAEtE,OAAO,EACN,yBAAyB,EACzB,yBAAyB,GAGzB,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EACN,aAAa,EACb,sBAAsB,GAKtB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACN,uBAAuB,EACvB,iBAAiB,EACjB,sBAAsB,GAMtB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACN,kBAAkB,GAUlB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACN,uBAAuB,EACvB,wBAAwB,EACxB,qBAAqB,EAErB,sBAAsB,GAEtB,MAAM,oBAAoB,CAAC;AAE5B,cAAc;AACd,OAAO,EACN,iBAAiB,EACjB,UAAU,EACV,iBAAiB,GAGjB,MAAM,kBAAkB,CAAC;AAE1B,iBAAiB;AACjB,OAAO,EACN,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,GACb,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAuCH,2DAA2D;AAC3D,OAAO,EACN,eAAe,EACf,eAAe,GACf,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE5E,kBAAkB;AAClB,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtE,8BAA8B;AAC9B,OAAO,EACN,yBAAyB,EACzB,qBAAqB,EAErB,cAAc,GAEd,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACN,YAAY,EACZ,WAAW,EACX,mBAAmB,GAEnB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACN,qBAAqB,EACrB,gBAAgB,EAChB,wBAAwB,EACxB,gBAAgB,GAOhB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EACN,qBAAqB,EACrB,oBAAoB,GAKpB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EACN,kCAAkC,EAClC,yBAAyB,GAEzB,MAAM,qCAAqC,CAAC;AAE7C,OAAO,EACN,oBAAoB,EACpB,oBAAoB,EACpB,yBAAyB,EACzB,2BAA2B,EAC3B,yBAAyB,EACzB,sBAAsB,EACtB,qCAAqC,EACrC,uBAAuB,EACvB,wBAAwB,EACxB,yBAAyB,EACzB,2BAA2B,EAC3B,mBAAmB,EACnB,uBAAuB,EACvB,gCAAgC,EAChC,8BAA8B,EAC9B,wBAAwB,EACxB,iCAAiC,EACjC,mCAAmC,EACnC,sBAAsB,EACtB,oBAAoB,GAIpB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EACN,6BAA6B,EAC7B,wBAAwB,EACxB,yBAAyB,EACzB,4BAA4B,EAC5B,oBAAoB,EACpB,0BAA0B,EAC1B,sBAAsB,EACtB,gCAAgC,GAIhC,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,iCAAiC,EAAE,MAAM,mBAAmB,CAAC;AAEtE,OAAO,EACN,yBAAyB,EACzB,yBAAyB,GAGzB,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EACN,aAAa,EACb,sBAAsB,GAKtB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACN,uBAAuB,EACvB,iBAAiB,EACjB,sBAAsB,GAMtB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACN,kBAAkB,GAUlB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACN,uBAAuB,EACvB,wBAAwB,EACxB,qBAAqB,EAErB,sBAAsB,GAEtB,MAAM,oBAAoB,CAAC;AAE5B,cAAc;AACd,OAAO,EACN,iBAAiB,EACjB,UAAU,EACV,iBAAiB,GAGjB,MAAM,kBAAkB,CAAC;AAE1B,iBAAiB;AACjB,OAAO,EACN,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,GACb,MAAM,YAAY,CAAC"}
@@ -201,15 +201,10 @@
201
201
  }
202
202
  };
203
203
 
204
- // node_modules/@blockcast/mmt-alta-parse/dist/index.js
204
+ // node_modules/@blockcast/mmt-base/dist/mmtp.js
205
205
  var MPU_HEADER_SIZE = 8;
206
206
  var MPU_LENGTH_FIELD_SIZE = 2;
207
207
  var MPU_HEADER_REMAINDER_SIZE = MPU_HEADER_SIZE - MPU_LENGTH_FIELD_SIZE;
208
-
209
- // node_modules/@blockcast/mmt-base/dist/mmtp.js
210
- var MPU_HEADER_SIZE2 = 8;
211
- var MPU_LENGTH_FIELD_SIZE2 = 2;
212
- var MPU_HEADER_REMAINDER_SIZE2 = MPU_HEADER_SIZE2 - MPU_LENGTH_FIELD_SIZE2;
213
208
  var MMTP_SIGNALING_PACKET_ID = 0;
214
209
  var MMTP_PACKET_ID_MAX = 65535;
215
210
 
@@ -239,9 +234,67 @@
239
234
 
240
235
  // node_modules/@blockcast/mmt-base/dist/fec-block-profile.js
241
236
  var FEC_BLOCK_PROFILES = Object.freeze([
242
- "k-padded-v1",
243
237
  "iso-ssbg1-v1"
244
238
  ]);
239
+ function isFecBlockProfile(value) {
240
+ return value === "iso-ssbg1-v1";
241
+ }
242
+
243
+ // node_modules/@blockcast/mmt-base/dist/catalog-fec-source.js
244
+ var ALL_ROLES = Object.freeze(["video", "audio"]);
245
+ function recordOf(value) {
246
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
247
+ }
248
+ function locateCatalogFecSource(catalog, source, roles = ALL_ROLES) {
249
+ const root = recordOf(catalog);
250
+ if (root === void 0)
251
+ return void 0;
252
+ for (const role of roles) {
253
+ const renditions = recordOf(recordOf(root[role])?.["renditions"]);
254
+ if (renditions === void 0 || !Object.hasOwn(renditions, source))
255
+ continue;
256
+ const entry2 = recordOf(renditions[source]);
257
+ if (entry2 === void 0)
258
+ continue;
259
+ return Object.freeze({
260
+ dialect: "hang",
261
+ role,
262
+ entry: entry2,
263
+ fec: entry2["fec"],
264
+ fecPath: `$.${role}.renditions[${JSON.stringify(source)}].fec`
265
+ });
266
+ }
267
+ const tracks = root["tracks"];
268
+ if (!Array.isArray(tracks))
269
+ return void 0;
270
+ const index = tracks.findIndex((track) => recordOf(track)?.["name"] === source);
271
+ if (index < 0)
272
+ return void 0;
273
+ const entry = recordOf(tracks[index]) ?? {};
274
+ return Object.freeze({
275
+ dialect: "msf",
276
+ index,
277
+ entry,
278
+ fec: entry["fec"],
279
+ fecPath: `$.tracks[${index}].fec`
280
+ });
281
+ }
282
+ function isoBlockSpanUsable(fec) {
283
+ const block = recordOf(fec);
284
+ if (block === void 0 || block["blockProfile"] !== "iso-ssbg1-v1")
285
+ return true;
286
+ const ms = block["interleaveDepthMs"];
287
+ return ms === void 0 || typeof ms === "number" && Number.isSafeInteger(ms) && ms >= 0;
288
+ }
289
+ function catalogFecAvailable(fec) {
290
+ const block = recordOf(fec);
291
+ if (block === void 0)
292
+ return true;
293
+ const declaresFecInstance = block["algorithm"] !== "none";
294
+ const profile = block["blockProfile"];
295
+ const profileOk = isFecBlockProfile(profile) || profile === void 0 && !declaresFecInstance;
296
+ return profileOk && (!declaresFecInstance || isoBlockSpanUsable(block));
297
+ }
245
298
 
246
299
  // src/endpoint-config.ts
247
300
  function toWindowMulticastSubscribeConfig(input) {
@@ -437,8 +490,9 @@
437
490
  }
438
491
  onGoodput(sample) {
439
492
  const bitrate = sample.bitrate;
440
- if (!this.#current || this.options.adaptive === false) return void 0;
493
+ if (!this.#current) return void 0;
441
494
  if (this.#state === "joining") return this.poll();
495
+ if (this.options.adaptive === false) return void 0;
442
496
  if (bitrate === void 0 || !Number.isFinite(bitrate)) return void 0;
443
497
  this.#estimate = bitrate;
444
498
  const desired = selectMulticastTier(this.options.endpoints, bitrate);
@@ -497,6 +551,25 @@
497
551
  this.#favored = void 0;
498
552
  return { kind: "join-target", current: this.#current, target: desired };
499
553
  }
554
+ /**
555
+ * Join `target` because the viewer selected it, not because goodput or
556
+ * headroom ranked it. It runs whether or not the orchestrator adapts, and
557
+ * takes the path an adaptive join takes: commit on the target's RAP at or
558
+ * beyond the high-water mark, abandon at the join deadline. While it is
559
+ * pending nothing re-ranks the ladder; goodput only advances the deadline.
560
+ *
561
+ * Returns undefined, changing nothing, while another join is pending (cancel
562
+ * it first), when `target` is the current tier, or when it carries no media.
563
+ */
564
+ select(target) {
565
+ if (!this.#current || this.#state === "joining" || !carriesMedia(target)) return void 0;
566
+ if (endpointKey(target) === endpointKey(this.#current)) return void 0;
567
+ this.#state = "joining";
568
+ this.#target = target;
569
+ this.#joinStartedAt = this.#now();
570
+ this.#favored = void 0;
571
+ return { kind: "join-target", current: this.#current, target };
572
+ }
500
573
  /**
501
574
  * Feed a packet from the active tier (to advance the high-water mark) or
502
575
  * from the in-flight target (to find a committable RAP).
@@ -689,7 +762,7 @@
689
762
  if (endpoint.protocol === "ssm" && (typeof endpoint.sourceAddress !== "string" || endpoint.sourceAddress.trim().length === 0)) return false;
690
763
  if (!isValidMulticastGroupAddress(endpoint.groupAddress) || !Number.isInteger(Number(endpoint.port)) || endpoint.port <= 0 || endpoint.port > 65535 || !endpoint.tracks.length) return false;
691
764
  const catalogTracks = /* @__PURE__ */ new Set([...Object.keys(catalog?.video?.renditions ?? {}), ...Object.keys(catalog?.audio?.renditions ?? {})]);
692
- return endpoint.tracks.every((track) => !!track.name && isMulticastTrackPacketId(track.packetId) && (catalogTracks.size === 0 || catalogTracks.has(track.name) || catalogTracks.has(track.name.replace(/\/repair$/, ""))));
765
+ return endpoint.tracks.every((track) => !!track.name && isMulticastTrackPacketId(track.packetId) && (catalogTracks.size === 0 || catalogTracks.has(track.name) || catalogTracks.has(track.name.replace(/\/repair(?:\/\d+)?$/, ""))));
693
766
  }
694
767
  function copyEndpoint(endpoint) {
695
768
  return { ...endpoint, tracks: endpoint.tracks.map((track) => ({ ...track })) };
@@ -754,7 +827,7 @@
754
827
  source: endpoint.sourceAddress || "",
755
828
  port: Number(endpoint.port)
756
829
  };
757
- const networkSource = endpoint.networkSource ?? catalog?.multicast?.networkSource;
830
+ const networkSource = catalog?.multicast?.networkSource;
758
831
  const amt = findAmtRelay(networkSource);
759
832
  if (amt) {
760
833
  config.mode = "tunnel";
@@ -779,11 +852,18 @@
779
852
  function selectEndpointPacketIdsForTracks(endpoint, catalog, selection = {}) {
780
853
  if (!endpoint || !Array.isArray(endpoint.tracks)) return [];
781
854
  if (advertisesInvalidPacketId(endpoint)) return null;
782
- const tracks = endpoint.tracks.map((track) => ({
855
+ const { tracks, selected } = selectedEndpointTracks(endpoint, catalog, selection);
856
+ if (tracks.length === 0) return [];
857
+ if (selected.length === 0) return normalizePacketIds(tracks.map((track) => track.packetId));
858
+ const selectedRepairNames = new Set(selected.flatMap((track) => catalogRepairTracks(catalog, track.name)));
859
+ const selectedRepairTracks = tracks.filter((track) => selectedRepairNames.has(track.name));
860
+ return normalizePacketIds([...selected, ...selectedRepairTracks].map((track) => track.packetId));
861
+ }
862
+ function selectedEndpointTracks(endpoint, catalog, selection) {
863
+ const tracks = (Array.isArray(endpoint.tracks) ? endpoint.tracks : []).map((track) => ({
783
864
  name: typeof track?.name === "string" ? track.name : "",
784
865
  packetId: validPacketId(track?.packetId)
785
866
  })).filter((track) => track.name.length > 0 && track.packetId !== void 0);
786
- if (tracks.length === 0) return [];
787
867
  const packaging = selection.containerKind || "mmtp";
788
868
  const renditionTrack = selection.rendition || "";
789
869
  const videoRenditions = catalogRenditions(catalog, "video");
@@ -794,13 +874,70 @@
794
874
  const preferredAudio = packaging === "mmtp" ? "audio" : `audio.${packaging}`;
795
875
  const video = (renditionTrack ? videoTracks.find((track) => track.name === renditionTrack) : void 0) ?? videoTracks.find((track) => track.name === preferredVideo) ?? [...videoTracks].sort((a, b) => videoRenditionRank(videoRenditions, a.name) - videoRenditionRank(videoRenditions, b.name))[0];
796
876
  const audio = audioTracks.find((track) => track.name === preferredAudio) ?? audioTracks[0];
797
- const selected = [video, audio].filter(
798
- (track) => track !== void 0
799
- );
800
- if (selected.length === 0) return normalizePacketIds(tracks.map((track) => track.packetId));
801
- const selectedRepairNames = new Set(selected.flatMap((track) => catalogRepairTracks(catalog, track.name)));
802
- const selectedRepairTracks = tracks.filter((track) => selectedRepairNames.has(track.name));
803
- return normalizePacketIds([...selected, ...selectedRepairTracks].map((track) => track.packetId));
877
+ const selected = [video, audio].filter((track) => track !== void 0);
878
+ return { tracks, selected };
879
+ }
880
+ function selectRepairEndpointsForTracks(catalog, mediaEndpoint, selection = {}) {
881
+ const mediaConfig = endpointToMulticastConfig(mediaEndpoint, catalog, selection);
882
+ if (!mediaEndpoint || !mediaConfig) return [];
883
+ const { selected } = selectedEndpointTracks(mediaEndpoint, catalog, selection);
884
+ if (selected.length === 0) return [];
885
+ const videoRenditions = catalogRenditions(catalog, "video");
886
+ const sourceNames = /* @__PURE__ */ new Set([...Object.keys(videoRenditions), ...Object.keys(catalogRenditions(catalog, "audio"))]);
887
+ const rungTrack = selected.find((track) => Object.hasOwn(videoRenditions, track.name)) ?? selected[0];
888
+ const rungIsVideo = Object.hasOwn(videoRenditions, rungTrack.name);
889
+ const ownerOf = /* @__PURE__ */ new Map();
890
+ for (const owner of selected) {
891
+ for (const name of catalogRepairTracks(catalog, owner.name)) ownerOf.set(name, owner);
892
+ }
893
+ const repairOwner = (name) => {
894
+ const direct = ownerOf.get(name);
895
+ if (direct) return direct;
896
+ const layer = /^(.*)\/\d+$/.exec(name);
897
+ return layer ? ownerOf.get(layer[1]) : void 0;
898
+ };
899
+ const endpoints = normalizeCatalogEndpoints(catalog);
900
+ const sameEndpoint = (endpoint) => endpoint.groupAddress === mediaEndpoint.groupAddress && (endpoint.sourceAddress || "") === (mediaEndpoint.sourceAddress || "") && Number(endpoint.port) === Number(mediaEndpoint.port);
901
+ const start = endpoints.findIndex(sameEndpoint);
902
+ if (start < 0) return [];
903
+ const { mode, amtRelay, amtRelayPort, amtNetworkSource } = mediaConfig;
904
+ const transport = {
905
+ ...mode === void 0 ? {} : { mode },
906
+ ...amtRelay === void 0 ? {} : { amtRelay },
907
+ ...amtRelayPort === void 0 ? {} : { amtRelayPort },
908
+ ...amtNetworkSource === void 0 ? {} : { amtNetworkSource }
909
+ };
910
+ const companions = [];
911
+ for (const endpoint of endpoints.slice(start + 1)) {
912
+ const names = endpoint.tracks.map((track) => track.name);
913
+ if (names.some((name) => sourceNames.has(name))) {
914
+ if (rungIsVideo && names.includes(rungTrack.name)) continue;
915
+ break;
916
+ }
917
+ if (!isUsableMulticastEndpoint(endpoint) || advertisesInvalidPacketId(endpoint)) continue;
918
+ const repairOwners = [];
919
+ const owners = [];
920
+ const repairs = [];
921
+ for (const track of endpoint.tracks) {
922
+ const owner = repairOwner(track.name);
923
+ const packetId = validPacketId(track.packetId);
924
+ if (!owner || packetId === void 0 || packetId === owner.packetId) continue;
925
+ repairOwners.push({ packetId, ownerPacketId: owner.packetId });
926
+ if (!owners.includes(owner)) owners.push(owner);
927
+ repairs.push({ name: track.name, packetId });
928
+ }
929
+ if (repairOwners.length === 0) continue;
930
+ companions.push({
931
+ group: endpoint.groupAddress,
932
+ source: endpoint.sourceAddress || "",
933
+ port: Number(endpoint.port),
934
+ ...transport,
935
+ packetIds: normalizePacketIds(repairOwners.map((owner) => owner.packetId)),
936
+ repairOwners,
937
+ tracks: [...owners.map((owner) => ({ ...owner })), ...repairs]
938
+ });
939
+ }
940
+ return companions;
804
941
  }
805
942
  function readPlayerMulticastConfig(search = currentSearchParams()) {
806
943
  const params = search instanceof URLSearchParams ? search : new URLSearchParams(search || "");
@@ -954,10 +1091,8 @@
954
1091
  function catalogRepairTracks(catalog, name) {
955
1092
  assertNoRetiredTrackFields(catalog);
956
1093
  const tracks = Array.isArray(catalog?.tracks) ? catalog.tracks : [];
957
- const track = tracks.find((candidate) => candidate?.name === name);
958
- const rendition = catalog?.video?.renditions?.[name] ?? catalog?.audio?.renditions?.[name];
959
- const fec = track?.fec ?? rendition?.fec;
960
- if (!fec || fec.algorithm === "none") return [];
1094
+ const fec = locateCatalogFecSource(catalog, name)?.fec;
1095
+ if (!fec || typeof fec !== "object" || fec.algorithm === "none" || !catalogFecAvailable(fec)) return [];
961
1096
  const names = /* @__PURE__ */ new Set();
962
1097
  if (typeof fec.repairTrack === "string" && fec.repairTrack.length > 0) names.add(fec.repairTrack);
963
1098
  const dependsOn = (entry) => Array.isArray(entry?.depends) && entry.depends.length === 1 && entry.depends[0] === name;
@@ -1832,6 +1967,10 @@
1832
1967
  pollMulticastTierSwitch() {
1833
1968
  return this.dispatchOrchestratorCommand(this.multicastOrchestrator?.poll());
1834
1969
  }
1970
+ /** Abandon the in-flight tier join, e.g. because the host could not join the target. */
1971
+ cancelMulticastTierJoin() {
1972
+ return this.dispatchOrchestratorCommand(this.multicastOrchestrator?.cancel());
1973
+ }
1835
1974
  /**
1836
1975
  * Set packet callback
1837
1976
  */
@@ -1960,6 +2099,7 @@
1960
2099
  selectEndpointPacketIds,
1961
2100
  selectMulticastCandidate,
1962
2101
  selectMulticastTier,
2102
+ selectRepairEndpointsForTracks,
1963
2103
  urlOverrideBlocksMulticastCandidate,
1964
2104
  withMulticastEndpoints,
1965
2105
  wireStarvationDetector