@norskvideo/moq-net 0.1.0

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 (274) hide show
  1. package/README.md +70 -0
  2. package/announced.d.ts +45 -0
  3. package/announced.d.ts.map +1 -0
  4. package/announced.js +70 -0
  5. package/announced.js.map +1 -0
  6. package/bandwidth.d.ts +11 -0
  7. package/bandwidth.d.ts.map +1 -0
  8. package/bandwidth.js +7 -0
  9. package/bandwidth.js.map +1 -0
  10. package/broadcast.d.ts +39 -0
  11. package/broadcast.d.ts.map +1 -0
  12. package/broadcast.js +76 -0
  13. package/broadcast.js.map +1 -0
  14. package/connection/accept.d.ts +15 -0
  15. package/connection/accept.d.ts.map +1 -0
  16. package/connection/accept.js +137 -0
  17. package/connection/accept.js.map +1 -0
  18. package/connection/cert.test.d.ts +2 -0
  19. package/connection/cert.test.d.ts.map +1 -0
  20. package/connection/cert.test.js +26 -0
  21. package/connection/cert.test.js.map +1 -0
  22. package/connection/connect.d.ts +37 -0
  23. package/connection/connect.d.ts.map +1 -0
  24. package/connection/connect.js +348 -0
  25. package/connection/connect.js.map +1 -0
  26. package/connection/established.d.ts +30 -0
  27. package/connection/established.d.ts.map +1 -0
  28. package/connection/established.js +3 -0
  29. package/connection/established.js.map +1 -0
  30. package/connection/handshake.d.ts +10 -0
  31. package/connection/handshake.d.ts.map +1 -0
  32. package/connection/handshake.js +48 -0
  33. package/connection/handshake.js.map +1 -0
  34. package/connection/index.d.ts +5 -0
  35. package/connection/index.d.ts.map +1 -0
  36. package/connection/index.js +6 -0
  37. package/connection/index.js.map +1 -0
  38. package/connection/reload.d.ts +47 -0
  39. package/connection/reload.d.ts.map +1 -0
  40. package/connection/reload.js +137 -0
  41. package/connection/reload.js.map +1 -0
  42. package/group.d.ts +66 -0
  43. package/group.d.ts.map +1 -0
  44. package/group.js +135 -0
  45. package/group.js.map +1 -0
  46. package/group.test.d.ts +2 -0
  47. package/group.test.d.ts.map +1 -0
  48. package/group.test.js +66 -0
  49. package/group.test.js.map +1 -0
  50. package/ietf/adapter.d.ts +65 -0
  51. package/ietf/adapter.d.ts.map +1 -0
  52. package/ietf/adapter.js +626 -0
  53. package/ietf/adapter.js.map +1 -0
  54. package/ietf/connection.d.ts +65 -0
  55. package/ietf/connection.d.ts.map +1 -0
  56. package/ietf/connection.js +248 -0
  57. package/ietf/connection.js.map +1 -0
  58. package/ietf/control.d.ts +135 -0
  59. package/ietf/control.d.ts.map +1 -0
  60. package/ietf/control.js +242 -0
  61. package/ietf/control.js.map +1 -0
  62. package/ietf/fetch.d.ts +64 -0
  63. package/ietf/fetch.d.ts.map +1 -0
  64. package/ietf/fetch.js +100 -0
  65. package/ietf/fetch.js.map +1 -0
  66. package/ietf/goaway.d.ts +15 -0
  67. package/ietf/goaway.d.ts.map +1 -0
  68. package/ietf/goaway.js +34 -0
  69. package/ietf/goaway.js.map +1 -0
  70. package/ietf/ietf.test.d.ts +2 -0
  71. package/ietf/ietf.test.d.ts.map +1 -0
  72. package/ietf/ietf.test.js +873 -0
  73. package/ietf/ietf.test.js.map +1 -0
  74. package/ietf/index.d.ts +18 -0
  75. package/ietf/index.d.ts.map +1 -0
  76. package/ietf/index.js +19 -0
  77. package/ietf/index.js.map +1 -0
  78. package/ietf/message.d.ts +4 -0
  79. package/ietf/message.d.ts.map +1 -0
  80. package/ietf/message.js +54 -0
  81. package/ietf/message.js.map +1 -0
  82. package/ietf/namespace.d.ts +5 -0
  83. package/ietf/namespace.d.ts.map +1 -0
  84. package/ietf/namespace.js +27 -0
  85. package/ietf/namespace.js.map +1 -0
  86. package/ietf/object.d.ts +40 -0
  87. package/ietf/object.d.ts.map +1 -0
  88. package/ietf/object.js +160 -0
  89. package/ietf/object.js.map +1 -0
  90. package/ietf/parameters.d.ts +56 -0
  91. package/ietf/parameters.d.ts.map +1 -0
  92. package/ietf/parameters.js +337 -0
  93. package/ietf/parameters.js.map +1 -0
  94. package/ietf/properties.d.ts +4 -0
  95. package/ietf/properties.d.ts.map +1 -0
  96. package/ietf/properties.js +33 -0
  97. package/ietf/properties.js.map +1 -0
  98. package/ietf/publish.d.ts +68 -0
  99. package/ietf/publish.d.ts.map +1 -0
  100. package/ietf/publish.js +192 -0
  101. package/ietf/publish.js.map +1 -0
  102. package/ietf/publish_namespace.d.ts +68 -0
  103. package/ietf/publish_namespace.d.ts.map +1 -0
  104. package/ietf/publish_namespace.js +176 -0
  105. package/ietf/publish_namespace.js.map +1 -0
  106. package/ietf/publisher.d.ts +50 -0
  107. package/ietf/publisher.d.ts.map +1 -0
  108. package/ietf/publisher.js +330 -0
  109. package/ietf/publisher.js.map +1 -0
  110. package/ietf/request.d.ts +52 -0
  111. package/ietf/request.d.ts.map +1 -0
  112. package/ietf/request.js +119 -0
  113. package/ietf/request.js.map +1 -0
  114. package/ietf/setup.d.ts +38 -0
  115. package/ietf/setup.d.ts.map +1 -0
  116. package/ietf/setup.js +129 -0
  117. package/ietf/setup.js.map +1 -0
  118. package/ietf/subscribe.d.ts +66 -0
  119. package/ietf/subscribe.d.ts.map +1 -0
  120. package/ietf/subscribe.js +276 -0
  121. package/ietf/subscribe.js.map +1 -0
  122. package/ietf/subscribe_namespace.d.ts +101 -0
  123. package/ietf/subscribe_namespace.d.ts.map +1 -0
  124. package/ietf/subscribe_namespace.js +256 -0
  125. package/ietf/subscribe_namespace.js.map +1 -0
  126. package/ietf/subscriber.d.ts +53 -0
  127. package/ietf/subscriber.d.ts.map +1 -0
  128. package/ietf/subscriber.js +404 -0
  129. package/ietf/subscriber.js.map +1 -0
  130. package/ietf/track.d.ts +40 -0
  131. package/ietf/track.d.ts.map +1 -0
  132. package/ietf/track.js +108 -0
  133. package/ietf/track.js.map +1 -0
  134. package/ietf/version.d.ts +56 -0
  135. package/ietf/version.d.ts.map +1 -0
  136. package/ietf/version.js +63 -0
  137. package/ietf/version.js.map +1 -0
  138. package/index.d.ts +22 -0
  139. package/index.d.ts.map +1 -0
  140. package/index.js +23 -0
  141. package/index.js.map +1 -0
  142. package/integration.test.d.ts +2 -0
  143. package/integration.test.d.ts.map +1 -0
  144. package/integration.test.js +90 -0
  145. package/integration.test.js.map +1 -0
  146. package/lite/announce.d.ts +35 -0
  147. package/lite/announce.d.ts.map +1 -0
  148. package/lite/announce.js +166 -0
  149. package/lite/announce.js.map +1 -0
  150. package/lite/connection.d.ts +47 -0
  151. package/lite/connection.d.ts.map +1 -0
  152. package/lite/connection.js +247 -0
  153. package/lite/connection.js.map +1 -0
  154. package/lite/fetch.d.ts +14 -0
  155. package/lite/fetch.d.ts.map +1 -0
  156. package/lite/fetch.js +47 -0
  157. package/lite/fetch.js.map +1 -0
  158. package/lite/goaway.d.ts +10 -0
  159. package/lite/goaway.d.ts.map +1 -0
  160. package/lite/goaway.js +37 -0
  161. package/lite/goaway.js.map +1 -0
  162. package/lite/group.d.ts +18 -0
  163. package/lite/group.d.ts.map +1 -0
  164. package/lite/group.js +46 -0
  165. package/lite/group.js.map +1 -0
  166. package/lite/index.d.ts +11 -0
  167. package/lite/index.d.ts.map +1 -0
  168. package/lite/index.js +12 -0
  169. package/lite/index.js.map +1 -0
  170. package/lite/message.d.ts +5 -0
  171. package/lite/message.d.ts.map +1 -0
  172. package/lite/message.js +51 -0
  173. package/lite/message.js.map +1 -0
  174. package/lite/origin.d.ts +25 -0
  175. package/lite/origin.d.ts.map +1 -0
  176. package/lite/origin.js +35 -0
  177. package/lite/origin.js.map +1 -0
  178. package/lite/probe.d.ts +12 -0
  179. package/lite/probe.d.ts.map +1 -0
  180. package/lite/probe.js +60 -0
  181. package/lite/probe.js.map +1 -0
  182. package/lite/publisher.d.ts +63 -0
  183. package/lite/publisher.d.ts.map +1 -0
  184. package/lite/publisher.js +350 -0
  185. package/lite/publisher.js.map +1 -0
  186. package/lite/session.d.ts +36 -0
  187. package/lite/session.d.ts.map +1 -0
  188. package/lite/session.js +130 -0
  189. package/lite/session.js.map +1 -0
  190. package/lite/setup.d.ts +18 -0
  191. package/lite/setup.d.ts.map +1 -0
  192. package/lite/setup.js +55 -0
  193. package/lite/setup.js.map +1 -0
  194. package/lite/stream.d.ts +23 -0
  195. package/lite/stream.d.ts.map +1 -0
  196. package/lite/stream.js +20 -0
  197. package/lite/stream.js.map +1 -0
  198. package/lite/subscribe.d.ts +111 -0
  199. package/lite/subscribe.d.ts.map +1 -0
  200. package/lite/subscribe.js +341 -0
  201. package/lite/subscribe.js.map +1 -0
  202. package/lite/subscriber.d.ts +80 -0
  203. package/lite/subscriber.d.ts.map +1 -0
  204. package/lite/subscriber.js +316 -0
  205. package/lite/subscriber.js.map +1 -0
  206. package/lite/track.d.ts +38 -0
  207. package/lite/track.d.ts.map +1 -0
  208. package/lite/track.js +81 -0
  209. package/lite/track.js.map +1 -0
  210. package/lite/track.test.d.ts +2 -0
  211. package/lite/track.test.d.ts.map +1 -0
  212. package/lite/track.test.js +53 -0
  213. package/lite/track.test.js.map +1 -0
  214. package/lite/version.d.ts +16 -0
  215. package/lite/version.d.ts.map +1 -0
  216. package/lite/version.js +41 -0
  217. package/lite/version.js.map +1 -0
  218. package/mock.d.ts +16 -0
  219. package/mock.d.ts.map +1 -0
  220. package/mock.js +154 -0
  221. package/mock.js.map +1 -0
  222. package/package.json +27 -0
  223. package/path.d.ts +111 -0
  224. package/path.d.ts.map +1 -0
  225. package/path.js +133 -0
  226. package/path.js.map +1 -0
  227. package/path.test.d.ts +2 -0
  228. package/path.test.d.ts.map +1 -0
  229. package/path.test.js +169 -0
  230. package/path.test.js.map +1 -0
  231. package/stream.d.ts +57 -0
  232. package/stream.d.ts.map +1 -0
  233. package/stream.js +326 -0
  234. package/stream.js.map +1 -0
  235. package/stream.test.d.ts +2 -0
  236. package/stream.test.d.ts.map +1 -0
  237. package/stream.test.js +210 -0
  238. package/stream.test.js.map +1 -0
  239. package/time.d.ts +109 -0
  240. package/time.d.ts.map +1 -0
  241. package/time.js +94 -0
  242. package/time.js.map +1 -0
  243. package/track.d.ts +85 -0
  244. package/track.d.ts.map +1 -0
  245. package/track.js +227 -0
  246. package/track.js.map +1 -0
  247. package/track.test.d.ts +2 -0
  248. package/track.test.d.ts.map +1 -0
  249. package/track.test.js +56 -0
  250. package/track.test.js.map +1 -0
  251. package/util/error.d.ts +3 -0
  252. package/util/error.d.ts.map +1 -0
  253. package/util/error.js +9 -0
  254. package/util/error.js.map +1 -0
  255. package/util/hex.d.ts +3 -0
  256. package/util/hex.d.ts.map +1 -0
  257. package/util/hex.js +16 -0
  258. package/util/hex.js.map +1 -0
  259. package/util/index.d.ts +2 -0
  260. package/util/index.d.ts.map +1 -0
  261. package/util/index.js +3 -0
  262. package/util/index.js.map +1 -0
  263. package/varint.d.ts +36 -0
  264. package/varint.d.ts.map +1 -0
  265. package/varint.js +288 -0
  266. package/varint.js.map +1 -0
  267. package/varint.test.d.ts +2 -0
  268. package/varint.test.d.ts.map +1 -0
  269. package/varint.test.js +106 -0
  270. package/varint.test.js.map +1 -0
  271. package/zod.d.ts +13 -0
  272. package/zod.d.ts.map +1 -0
  273. package/zod.js +19 -0
  274. package/zod.js.map +1 -0
package/lite/origin.js ADDED
@@ -0,0 +1,35 @@
1
+ /* @ts-self-types="./origin.d.ts" */
2
+ import * as z from "zod/mini";
3
+ /**
4
+ * A relay origin id, encoded as a 62-bit varint on the wire.
5
+ *
6
+ * The {@link OriginSchema} validates any incoming value and brands it so the
7
+ * type system enforces "only validated origins flow into hop lists." Internal
8
+ * code that synthesizes an id (e.g. {@link randomOrigin}) uses
9
+ * `OriginSchema.parse(...)` to produce a branded value from the raw bigint.
10
+ */
11
+ export const OriginSchema = z
12
+ .bigint()
13
+ .check(z.refine((value) => value >= 0n && value < 1n << 62n, "Origin must be a non-negative 62-bit integer"))
14
+ .brand("Origin");
15
+ /**
16
+ * Generate a fresh origin with a random non-zero id.
17
+ *
18
+ * `crypto.getRandomValues` is overkill for best-effort loop detection, but
19
+ * used for slightly better distribution than `Math.random` at negligible cost.
20
+ *
21
+ * TEMPORARY: the wire format allows 62 bits, but older `@moq/lite` JS clients
22
+ * decode `AnnounceInterest.exclude_hop` as a u53 (number) and throw on anything
23
+ * > 2^53-1. To keep those clients alive against fresh peers, we cap the random
24
+ * id at 53 bits. Restore to 62 bits once the u62 fix has propagated to deployed
25
+ * bundles. Mirrors `Origin::random` in rs/moq-net.
26
+ */
27
+ export function randomOrigin() {
28
+ const buf = new BigUint64Array(1);
29
+ crypto.getRandomValues(buf);
30
+ // Mask to 53 bits.
31
+ const raw = buf[0] & 0x1fffffffffffffn;
32
+ // Guard against the (astronomically unlikely) zero draw.
33
+ return OriginSchema.parse(raw === 0n ? 1n : raw);
34
+ }
35
+ //# sourceMappingURL=origin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"origin.js","sourceRoot":"","sources":["../../src/lite/origin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAE9B;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC;KAC3B,MAAM,EAAE;KACR,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,IAAI,EAAE,IAAI,KAAK,GAAG,EAAE,IAAI,GAAG,EAAE,8CAA8C,CAAC,CAAC;KAC5G,KAAK,CAAC,QAAQ,CAAC,CAAC;AAIlB;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,YAAY;IAC3B,MAAM,GAAG,GAAG,IAAI,cAAc,CAAC,CAAC,CAAC,CAAC;IAClC,MAAM,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;IAC5B,mBAAmB;IACnB,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,iBAAoB,CAAC;IAC1C,yDAAyD;IACzD,OAAO,YAAY,CAAC,KAAK,CAAC,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAClD,CAAC","sourcesContent":["import * as z from \"zod/mini\";\n\n/**\n * A relay origin id, encoded as a 62-bit varint on the wire.\n *\n * The {@link OriginSchema} validates any incoming value and brands it so the\n * type system enforces \"only validated origins flow into hop lists.\" Internal\n * code that synthesizes an id (e.g. {@link randomOrigin}) uses\n * `OriginSchema.parse(...)` to produce a branded value from the raw bigint.\n */\nexport const OriginSchema = z\n\t.bigint()\n\t.check(z.refine((value) => value >= 0n && value < 1n << 62n, \"Origin must be a non-negative 62-bit integer\"))\n\t.brand(\"Origin\");\n\nexport type Origin = z.infer<typeof OriginSchema>;\n\n/**\n * Generate a fresh origin with a random non-zero id.\n *\n * `crypto.getRandomValues` is overkill for best-effort loop detection, but\n * used for slightly better distribution than `Math.random` at negligible cost.\n *\n * TEMPORARY: the wire format allows 62 bits, but older `@moq/lite` JS clients\n * decode `AnnounceInterest.exclude_hop` as a u53 (number) and throw on anything\n * > 2^53-1. To keep those clients alive against fresh peers, we cap the random\n * id at 53 bits. Restore to 62 bits once the u62 fix has propagated to deployed\n * bundles. Mirrors `Origin::random` in rs/moq-net.\n */\nexport function randomOrigin(): Origin {\n\tconst buf = new BigUint64Array(1);\n\tcrypto.getRandomValues(buf);\n\t// Mask to 53 bits.\n\tconst raw = buf[0] & 0x1f_ffff_ffff_ffffn;\n\t// Guard against the (astronomically unlikely) zero draw.\n\treturn OriginSchema.parse(raw === 0n ? 1n : raw);\n}\n"]}
@@ -0,0 +1,12 @@
1
+ import type { Reader, Writer } from "../stream";
2
+ import { Version } from "./version";
3
+ export declare class Probe {
4
+ #private;
5
+ bitrate: number;
6
+ rtt?: number;
7
+ constructor(bitrate: number, rtt?: number);
8
+ encode(w: Writer, version: Version): Promise<void>;
9
+ static decode(r: Reader, version: Version): Promise<Probe>;
10
+ static decodeMaybe(r: Reader, version: Version): Promise<Probe | undefined>;
11
+ }
12
+ //# sourceMappingURL=probe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"probe.d.ts","sourceRoot":"","sources":["../../src/lite/probe.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEnD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAYvC,qBAAa,KAAK;;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,YAAY,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,EAGxC;IA+BK,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAGvD;IAED,OAAa,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAG/D;IAED,OAAa,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,CAGhF;CACD"}
package/lite/probe.js ADDED
@@ -0,0 +1,60 @@
1
+ /* @ts-self-types="./probe.d.ts" */
2
+ import * as Message from "./message.js";
3
+ import { Version } from "./version.js";
4
+ function guardProbe(version) {
5
+ switch (version) {
6
+ case Version.DRAFT_01:
7
+ case Version.DRAFT_02:
8
+ throw new Error("probe not supported for this version");
9
+ default:
10
+ break;
11
+ }
12
+ }
13
+ export class Probe {
14
+ bitrate;
15
+ rtt;
16
+ constructor(bitrate, rtt) {
17
+ this.bitrate = bitrate;
18
+ this.rtt = rtt;
19
+ }
20
+ async #encode(w, version) {
21
+ await w.u53(this.bitrate);
22
+ switch (version) {
23
+ case Version.DRAFT_03:
24
+ break;
25
+ default: {
26
+ // 0 means unknown; round Some(0) up to 1.
27
+ const wire = this.rtt !== undefined ? Math.max(this.rtt, 1) : 0;
28
+ await w.u53(wire);
29
+ break;
30
+ }
31
+ }
32
+ }
33
+ static async #decode(r, version) {
34
+ const bitrate = await r.u53();
35
+ let rtt;
36
+ switch (version) {
37
+ case Version.DRAFT_03:
38
+ break;
39
+ default: {
40
+ const wire = await r.u53();
41
+ rtt = wire === 0 ? undefined : wire;
42
+ break;
43
+ }
44
+ }
45
+ return new Probe(bitrate, rtt);
46
+ }
47
+ async encode(w, version) {
48
+ guardProbe(version);
49
+ return Message.encode(w, (w) => this.#encode(w, version));
50
+ }
51
+ static async decode(r, version) {
52
+ guardProbe(version);
53
+ return Message.decode(r, (r) => Probe.#decode(r, version));
54
+ }
55
+ static async decodeMaybe(r, version) {
56
+ guardProbe(version);
57
+ return Message.decodeMaybe(r, (r) => Probe.#decode(r, version));
58
+ }
59
+ }
60
+ //# sourceMappingURL=probe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"probe.js","sourceRoot":"","sources":["../../src/lite/probe.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,SAAS,UAAU,CAAC,OAAgB;IACnC,QAAQ,OAAO,EAAE,CAAC;QACjB,KAAK,OAAO,CAAC,QAAQ,CAAC;QACtB,KAAK,OAAO,CAAC,QAAQ;YACpB,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QACzD;YACC,MAAM;IACR,CAAC;AACF,CAAC;AAED,MAAM,OAAO,KAAK;IACjB,OAAO,CAAS;IAChB,GAAG,CAAU;IAEb,YAAY,OAAe,EAAE,GAAY;QACxC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,CAAS,EAAE,OAAgB;QACxC,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC1B,QAAQ,OAAO,EAAE,CAAC;YACjB,KAAK,OAAO,CAAC,QAAQ;gBACpB,MAAM;YACP,SAAS,CAAC;gBACT,0CAA0C;gBAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAChE,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBAClB,MAAM;YACP,CAAC;QACF,CAAC;IACF,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAS,EAAE,OAAgB;QAC/C,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC;QAC9B,IAAI,GAAuB,CAAC;QAC5B,QAAQ,OAAO,EAAE,CAAC;YACjB,KAAK,OAAO,CAAC,QAAQ;gBACpB,MAAM;YACP,SAAS,CAAC;gBACT,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC;gBAC3B,GAAG,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;gBACpC,MAAM;YACP,CAAC;QACF,CAAC;QACD,OAAO,IAAI,KAAK,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,CAAS,EAAE,OAAgB;QACvC,UAAU,CAAC,OAAO,CAAC,CAAC;QACpB,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;IAC3D,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAS,EAAE,OAAgB;QAC9C,UAAU,CAAC,OAAO,CAAC,CAAC;QACpB,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;IAC5D,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAS,EAAE,OAAgB;QACnD,UAAU,CAAC,OAAO,CAAC,CAAC;QACpB,OAAO,OAAO,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;IACjE,CAAC;CACD","sourcesContent":["import type { Reader, Writer } from \"../stream.ts\";\nimport * as Message from \"./message.ts\";\nimport { Version } from \"./version.ts\";\n\nfunction guardProbe(version: Version) {\n\tswitch (version) {\n\t\tcase Version.DRAFT_01:\n\t\tcase Version.DRAFT_02:\n\t\t\tthrow new Error(\"probe not supported for this version\");\n\t\tdefault:\n\t\t\tbreak;\n\t}\n}\n\nexport class Probe {\n\tbitrate: number;\n\trtt?: number;\n\n\tconstructor(bitrate: number, rtt?: number) {\n\t\tthis.bitrate = bitrate;\n\t\tthis.rtt = rtt;\n\t}\n\n\tasync #encode(w: Writer, version: Version) {\n\t\tawait w.u53(this.bitrate);\n\t\tswitch (version) {\n\t\t\tcase Version.DRAFT_03:\n\t\t\t\tbreak;\n\t\t\tdefault: {\n\t\t\t\t// 0 means unknown; round Some(0) up to 1.\n\t\t\t\tconst wire = this.rtt !== undefined ? Math.max(this.rtt, 1) : 0;\n\t\t\t\tawait w.u53(wire);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tstatic async #decode(r: Reader, version: Version): Promise<Probe> {\n\t\tconst bitrate = await r.u53();\n\t\tlet rtt: number | undefined;\n\t\tswitch (version) {\n\t\t\tcase Version.DRAFT_03:\n\t\t\t\tbreak;\n\t\t\tdefault: {\n\t\t\t\tconst wire = await r.u53();\n\t\t\t\trtt = wire === 0 ? undefined : wire;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\treturn new Probe(bitrate, rtt);\n\t}\n\n\tasync encode(w: Writer, version: Version): Promise<void> {\n\t\tguardProbe(version);\n\t\treturn Message.encode(w, (w) => this.#encode(w, version));\n\t}\n\n\tstatic async decode(r: Reader, version: Version): Promise<Probe> {\n\t\tguardProbe(version);\n\t\treturn Message.decode(r, (r) => Probe.#decode(r, version));\n\t}\n\n\tstatic async decodeMaybe(r: Reader, version: Version): Promise<Probe | undefined> {\n\t\tguardProbe(version);\n\t\treturn Message.decodeMaybe(r, (r) => Probe.#decode(r, version));\n\t}\n}\n"]}
@@ -0,0 +1,63 @@
1
+ import type { Broadcast } from "../broadcast";
2
+ import * as Path from "../path";
3
+ import { type Stream } from "../stream";
4
+ import { type AnnounceInterest } from "./announce";
5
+ import type { Origin } from "./origin";
6
+ import { type Subscribe } from "./subscribe";
7
+ import type { Track as TrackMessage } from "./track";
8
+ import { Version } from "./version";
9
+ /**
10
+ * Handles publishing broadcasts and managing their lifecycle.
11
+ *
12
+ * @internal
13
+ */
14
+ export declare class Publisher {
15
+ #private;
16
+ readonly version: Version;
17
+ readonly origin: Origin;
18
+ /**
19
+ * Creates a new Publisher instance.
20
+ * @param quic - The WebTransport session to use
21
+ * @param version - Negotiated protocol version
22
+ * @param origin - Origin id shared with the Subscriber
23
+ *
24
+ * @internal
25
+ */
26
+ constructor(quic: WebTransport, version: Version, origin: Origin);
27
+ /**
28
+ * Publishes a broadcast with any associated tracks.
29
+ * @param name - The broadcast to publish
30
+ */
31
+ publish(path: Path.Valid, broadcast: Broadcast): void;
32
+ /**
33
+ * Handles an announce interest message.
34
+ * @param msg - The announce interest message
35
+ * @param stream - The stream to write announcements to
36
+ *
37
+ * @internal
38
+ */
39
+ runAnnounce(msg: AnnounceInterest, stream: Stream): Promise<void>;
40
+ /**
41
+ * Handles a subscribe message.
42
+ * @param msg - The subscribe message
43
+ * @param stream - The stream to write track data to
44
+ *
45
+ * @internal
46
+ */
47
+ runSubscribe(msg: Subscribe, stream: Stream): Promise<void>;
48
+ /**
49
+ * Serves a Track stream (moq-lite-05+): replies with the track's immutable TRACK_INFO.
50
+ *
51
+ * @internal
52
+ */
53
+ runTrackInfo(msg: TrackMessage, stream: Stream): Promise<void>;
54
+ /**
55
+ * Handles a probe stream by periodically reporting estimated bitrate.
56
+ * @param stream - The probe bidi stream
57
+ *
58
+ * @internal
59
+ */
60
+ runProbe(stream: Stream): Promise<void>;
61
+ close(): void;
62
+ }
63
+ //# sourceMappingURL=publisher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publisher.d.ts","sourceRoot":"","sources":["../../src/lite/publisher.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,KAAK,IAAI,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,KAAK,MAAM,EAAU,MAAM,cAAc,CAAC;AAGnD,OAAO,EAA0B,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAE9E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAA2B,KAAK,SAAS,EAA8C,MAAM,gBAAgB,CAAC;AACrH,OAAO,KAAK,EAAE,KAAK,IAAI,YAAY,EAAE,MAAM,YAAY,CAAC;AAExD,OAAO,EAAkB,OAAO,EAAE,MAAM,cAAc,CAAC;AAMvD;;;;GAIG;AACH,qBAAa,SAAS;;IAErB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAM1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAQxB;;;;;;;OAOG;IACH,YAAY,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAI/D;IAED;;;OAGG;IACH,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,SAAS,QAY7C;IAED;;;;;;OAMG;IACG,WAAW,CAAC,GAAG,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,iBA0EtD;IAED;;;;;;OAMG;IACG,YAAY,CAAC,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,iBA6ChD;IAED;;;;OAIG;IACG,YAAY,CAAC,GAAG,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,iBAUnD;IAmGD;;;;;OAKG;IACG,QAAQ,CAAC,MAAM,EAAE,MAAM,iBAmD5B;IAED,KAAK,SAOJ;CACD"}
@@ -0,0 +1,350 @@
1
+ /* @ts-self-types="./publisher.d.ts" */
2
+ import { Signal } from "@norskvideo/moq-signals";
3
+ import * as Path from "../path.js";
4
+ import { Writer } from "../stream.js";
5
+ import { error } from "../util/error.js";
6
+ import { Announce, AnnounceInit } from "./announce.js";
7
+ import { Group as GroupMessage } from "./group.js";
8
+ import { Probe } from "./probe.js";
9
+ import { encodeSubscribeResponse, SubscribeEnd, SubscribeOk, SubscribeUpdate } from "./subscribe.js";
10
+ import { TrackInfo } from "./track.js";
11
+ import { hasTrackStream, Version } from "./version.js";
12
+ const PROBE_INTERVAL = 100; // ms
13
+ const PROBE_MAX_AGE = 10_000; // ms
14
+ const PROBE_MAX_DELTA = 0.25;
15
+ /**
16
+ * Handles publishing broadcasts and managing their lifecycle.
17
+ *
18
+ * @internal
19
+ */
20
+ export class Publisher {
21
+ // The version of the connection.
22
+ version;
23
+ // Per-connection origin appended to outbound Announce hops, so the peer
24
+ // can detect loops and prefer shorter paths. Created by Connection and
25
+ // shared with Subscriber, which can optionally use it to filter out its
26
+ // own announcements.
27
+ origin;
28
+ #quic;
29
+ // Our published broadcasts.
30
+ // It's a signal so we can live update any announce streams.
31
+ #broadcasts = new Signal(new Map());
32
+ /**
33
+ * Creates a new Publisher instance.
34
+ * @param quic - The WebTransport session to use
35
+ * @param version - Negotiated protocol version
36
+ * @param origin - Origin id shared with the Subscriber
37
+ *
38
+ * @internal
39
+ */
40
+ constructor(quic, version, origin) {
41
+ this.#quic = quic;
42
+ this.version = version;
43
+ this.origin = origin;
44
+ }
45
+ /**
46
+ * Publishes a broadcast with any associated tracks.
47
+ * @param name - The broadcast to publish
48
+ */
49
+ publish(path, broadcast) {
50
+ this.#broadcasts.mutate((broadcasts) => {
51
+ if (!broadcasts)
52
+ throw new Error("closed");
53
+ broadcasts.set(path, broadcast);
54
+ });
55
+ // Remove the broadcast from the lookup when it's closed.
56
+ void broadcast.closed.finally(() => {
57
+ this.#broadcasts.mutate((broadcasts) => {
58
+ broadcasts?.delete(path);
59
+ });
60
+ });
61
+ }
62
+ /**
63
+ * Handles an announce interest message.
64
+ * @param msg - The announce interest message
65
+ * @param stream - The stream to write announcements to
66
+ *
67
+ * @internal
68
+ */
69
+ async runAnnounce(msg, stream) {
70
+ console.debug(`announce: prefix=${msg.prefix}`);
71
+ // Send initial announcements
72
+ let active = new Set();
73
+ const broadcasts = this.#broadcasts.peek();
74
+ if (!broadcasts)
75
+ return; // closed
76
+ for (const name of broadcasts.keys()) {
77
+ const suffix = Path.stripPrefix(msg.prefix, name);
78
+ if (suffix === null)
79
+ continue;
80
+ console.debug(`announce: broadcast=${name} active=true`);
81
+ active.add(suffix);
82
+ }
83
+ switch (this.version) {
84
+ case Version.DRAFT_01:
85
+ case Version.DRAFT_02: {
86
+ const init = new AnnounceInit([...active]);
87
+ await init.encode(stream.writer, this.version);
88
+ break;
89
+ }
90
+ default:
91
+ // Draft03+: send individual Announce messages for initial state.
92
+ for (const suffix of active) {
93
+ const wire = new Announce({ suffix, active: true, hops: [this.origin] });
94
+ await wire.encode(stream.writer, this.version);
95
+ }
96
+ break;
97
+ }
98
+ // Wait for updates to the broadcasts.
99
+ for (;;) {
100
+ // TODO Make a better helper within Signals.
101
+ let dispose;
102
+ const changed = new Promise((resolve) => {
103
+ dispose = this.#broadcasts.changed(resolve);
104
+ });
105
+ // Wait until the map of broadcasts changes.
106
+ const broadcasts = await Promise.race([changed, stream.reader.closed]);
107
+ dispose();
108
+ if (!broadcasts)
109
+ break;
110
+ // Create a new set of active broadcasts.
111
+ // This is SLOW, but it's not worth optimizing because we often have just 1 broadcast anyway.
112
+ const newActive = new Set();
113
+ for (const name of broadcasts.keys()) {
114
+ const suffix = Path.stripPrefix(msg.prefix, name);
115
+ if (suffix === null)
116
+ continue; // Not our prefix.
117
+ newActive.add(suffix);
118
+ }
119
+ // Announce any new broadcasts.
120
+ for (const added of newActive.difference(active)) {
121
+ console.debug(`announce: broadcast=${added} active=true`);
122
+ const wire = new Announce({ suffix: added, active: true, hops: [this.origin] });
123
+ await wire.encode(stream.writer, this.version);
124
+ }
125
+ // Announce any removed broadcasts.
126
+ // Ended announces don't need hops — the peer matches on path only.
127
+ for (const removed of active.difference(newActive)) {
128
+ console.debug(`announce: broadcast=${removed} active=false`);
129
+ const wire = new Announce({ suffix: removed, active: false });
130
+ await wire.encode(stream.writer, this.version);
131
+ }
132
+ // NOTE: This is kind of a hack that won't work with a rapid UNANNOUNCE/ANNOUNCE cycle.
133
+ // However, our client doesn't do that anyway.
134
+ active = newActive;
135
+ }
136
+ }
137
+ /**
138
+ * Handles a subscribe message.
139
+ * @param msg - The subscribe message
140
+ * @param stream - The stream to write track data to
141
+ *
142
+ * @internal
143
+ */
144
+ async runSubscribe(msg, stream) {
145
+ const broadcast = this.#broadcasts.peek()?.get(msg.broadcast);
146
+ if (!broadcast) {
147
+ console.debug(`publish unknown: broadcast=${msg.broadcast}`);
148
+ stream.writer.reset(new Error("not found"));
149
+ return;
150
+ }
151
+ const track = broadcast.subscribe(msg.track, msg.priority);
152
+ try {
153
+ // moq-lite-05+ trims SUBSCRIBE_OK to the resolved start group; the publisher
154
+ // properties move to TRACK_INFO. Earlier versions echo the priority inline.
155
+ const info = hasTrackStream(this.version)
156
+ ? new SubscribeOk({ startGroup: msg.startGroup ?? 0 })
157
+ : new SubscribeOk({ priority: msg.priority });
158
+ await encodeSubscribeResponse(stream.writer, { ok: info }, this.version);
159
+ console.debug(`publish ok: broadcast=${msg.broadcast} track=${track.name}`);
160
+ const serving = this.#runTrack(msg.id, msg.broadcast, track, stream.writer);
161
+ for (;;) {
162
+ const decode = SubscribeUpdate.decodeMaybe(stream.reader, this.version);
163
+ const result = await Promise.any([serving, decode]);
164
+ if (!result)
165
+ break;
166
+ if (result instanceof SubscribeUpdate) {
167
+ console.debug(`subscribe update: broadcast=${msg.broadcast} track=${track.name} priority=${result.priority}`);
168
+ track.updatePriority(result.priority);
169
+ }
170
+ }
171
+ console.debug(`publish done: broadcast=${msg.broadcast} track=${track.name}`);
172
+ stream.close();
173
+ track.close();
174
+ }
175
+ catch (err) {
176
+ const e = error(err);
177
+ console.warn(`publish error: broadcast=${msg.broadcast} track=${track.name} error=${e.message}`);
178
+ track.close(e);
179
+ stream.abort(e);
180
+ }
181
+ }
182
+ /**
183
+ * Serves a Track stream (moq-lite-05+): replies with the track's immutable TRACK_INFO.
184
+ *
185
+ * @internal
186
+ */
187
+ async runTrackInfo(msg, stream) {
188
+ const broadcast = this.#broadcasts.peek()?.get(msg.broadcast);
189
+ if (!broadcast) {
190
+ throw new Error("not found");
191
+ }
192
+ // The publisher properties aren't tracked in the browser model yet; report
193
+ // defaults with a millisecond timescale matching the wall-clock frame timestamps.
194
+ const info = new TrackInfo({ timescale: 1000 });
195
+ await info.encode(stream.writer, this.version);
196
+ }
197
+ /**
198
+ * Runs a track and sends its data to the stream.
199
+ * @param sub - The subscription ID
200
+ * @param broadcast - The broadcast name
201
+ * @param track - The track to run
202
+ * @param stream - The stream to write to
203
+ *
204
+ * @internal
205
+ */
206
+ async #runTrack(sub, broadcast, track, stream) {
207
+ try {
208
+ let lastSequence;
209
+ let trackEnded = false;
210
+ for (;;) {
211
+ const next = track.recvGroup();
212
+ const res = await Promise.race([
213
+ next.then((group) => ({ group })),
214
+ stream.closed.then(() => "closed"),
215
+ ]);
216
+ if (res === "closed") {
217
+ next.then((group) => group?.close()).catch(() => { });
218
+ break;
219
+ }
220
+ if (!res.group) {
221
+ trackEnded = true;
222
+ break;
223
+ }
224
+ lastSequence = res.group.sequence;
225
+ void this.#runGroup(sub, res.group);
226
+ }
227
+ // moq-lite-05+: signal end-of-track before the subscribe stream FINs.
228
+ if (trackEnded && hasTrackStream(this.version)) {
229
+ const end = new SubscribeEnd({ group: lastSequence ?? 0 });
230
+ await encodeSubscribeResponse(stream, { end }, this.version);
231
+ }
232
+ console.debug(`publish close: broadcast=${broadcast} track=${track.name}`);
233
+ track.close();
234
+ stream.close();
235
+ }
236
+ catch (err) {
237
+ const e = error(err);
238
+ console.warn(`publish error: broadcast=${broadcast} track=${track.name} error=${e.message}`);
239
+ track.close(e);
240
+ stream.reset(e);
241
+ }
242
+ }
243
+ /**
244
+ * Runs a group and sends its frames to the stream.
245
+ * @param sub - The subscription ID
246
+ * @param group - The group to run
247
+ *
248
+ * @internal
249
+ */
250
+ async #runGroup(sub, group) {
251
+ const msg = new GroupMessage(sub, group.sequence);
252
+ try {
253
+ const stream = await Writer.open(this.#quic);
254
+ await stream.u8(0); // stream type
255
+ await msg.encode(stream);
256
+ try {
257
+ // moq-lite-05+ stamps each frame with a wall-clock millisecond timestamp, sent
258
+ // as a zigzag delta from the previous frame (the first frame is a delta from 0).
259
+ let prevTimestamp = 0n;
260
+ for (;;) {
261
+ const frame = await Promise.race([group.readFrame(), stream.closed]);
262
+ if (!frame)
263
+ break;
264
+ if (hasTrackStream(this.version)) {
265
+ const now = BigInt(Date.now());
266
+ const delta = now - prevTimestamp;
267
+ prevTimestamp = now;
268
+ await stream.u62((delta << 1n) ^ (delta >> 63n));
269
+ }
270
+ await stream.u53(frame.byteLength);
271
+ await stream.write(frame);
272
+ }
273
+ stream.close();
274
+ group.close();
275
+ }
276
+ catch (err) {
277
+ const e = error(err);
278
+ stream.reset(e);
279
+ group.close(e);
280
+ }
281
+ }
282
+ catch (err) {
283
+ const e = error(err);
284
+ group.close(e);
285
+ }
286
+ }
287
+ /**
288
+ * Handles a probe stream by periodically reporting estimated bitrate.
289
+ * @param stream - The probe bidi stream
290
+ *
291
+ * @internal
292
+ */
293
+ async runProbe(stream) {
294
+ // getStats is not yet in the TypeScript WebTransport type definitions.
295
+ const quic = this.#quic;
296
+ if (!quic.getStats) {
297
+ // Best-effort: we can't supply bandwidth estimates, so close the
298
+ // whole bidi (FIN + STOP_SENDING) to let the peer release its end.
299
+ stream.close();
300
+ return;
301
+ }
302
+ let lastSentBitrate;
303
+ let lastSentTime;
304
+ try {
305
+ for (;;) {
306
+ const timeout = new Promise((resolve) => setTimeout(() => resolve("timeout"), PROBE_INTERVAL));
307
+ const result = await Promise.race([timeout, stream.reader.closed]);
308
+ if (result !== "timeout")
309
+ break;
310
+ const stats = await quic.getStats();
311
+ const bitrate = stats.estimatedSendRate;
312
+ if (bitrate == null)
313
+ continue;
314
+ let shouldSend;
315
+ if (lastSentBitrate === undefined || lastSentTime === undefined) {
316
+ shouldSend = true;
317
+ }
318
+ else if (lastSentBitrate === 0) {
319
+ shouldSend = bitrate > 0;
320
+ }
321
+ else {
322
+ const elapsed = performance.now() - lastSentTime;
323
+ const t = Math.max(PROBE_INTERVAL, Math.min(PROBE_MAX_AGE, elapsed));
324
+ const range = PROBE_MAX_AGE - PROBE_INTERVAL;
325
+ const threshold = (PROBE_MAX_DELTA * (PROBE_MAX_AGE - t)) / range;
326
+ const change = Math.abs(bitrate - lastSentBitrate) / lastSentBitrate;
327
+ shouldSend = change >= threshold;
328
+ }
329
+ if (shouldSend) {
330
+ await new Probe(bitrate).encode(stream.writer, this.version);
331
+ lastSentBitrate = bitrate;
332
+ lastSentTime = performance.now();
333
+ }
334
+ }
335
+ }
336
+ catch (err) {
337
+ console.warn("probe stream error", err);
338
+ stream.close();
339
+ }
340
+ }
341
+ close() {
342
+ this.#broadcasts.update((broadcasts) => {
343
+ for (const broadcast of broadcasts?.values() ?? []) {
344
+ broadcast.close();
345
+ }
346
+ return undefined;
347
+ });
348
+ }
349
+ }
350
+ //# sourceMappingURL=publisher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publisher.js","sourceRoot":"","sources":["../../src/lite/publisher.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Dispose, Signal } from \"@moq/signals\";\nimport type { Broadcast } from \"../broadcast.ts\";\nimport type { Group } from \"../group.ts\";\nimport * as Path from \"../path.ts\";\nimport { type Stream, Writer } from \"../stream.ts\";\nimport type { Track } from \"../track.ts\";\nimport { error } from \"../util/error.ts\";\nimport { Announce, AnnounceInit, type AnnounceInterest } from \"./announce.ts\";\nimport { Group as GroupMessage } from \"./group.ts\";\nimport type { Origin } from \"./origin.ts\";\nimport { Probe } from \"./probe.ts\";\nimport { encodeSubscribeResponse, type Subscribe, SubscribeEnd, SubscribeOk, SubscribeUpdate } from \"./subscribe.ts\";\nimport type { Track as TrackMessage } from \"./track.ts\";\nimport { TrackInfo } from \"./track.ts\";\nimport { hasTrackStream, Version } from \"./version.ts\";\n\nconst PROBE_INTERVAL = 100; // ms\nconst PROBE_MAX_AGE = 10_000; // ms\nconst PROBE_MAX_DELTA = 0.25;\n\n/**\n * Handles publishing broadcasts and managing their lifecycle.\n *\n * @internal\n */\nexport class Publisher {\n\t// The version of the connection.\n\treadonly version: Version;\n\n\t// Per-connection origin appended to outbound Announce hops, so the peer\n\t// can detect loops and prefer shorter paths. Created by Connection and\n\t// shared with Subscriber, which can optionally use it to filter out its\n\t// own announcements.\n\treadonly origin: Origin;\n\n\t#quic: WebTransport;\n\n\t// Our published broadcasts.\n\t// It's a signal so we can live update any announce streams.\n\t#broadcasts = new Signal<Map<Path.Valid, Broadcast> | undefined>(new Map());\n\n\t/**\n\t * Creates a new Publisher instance.\n\t * @param quic - The WebTransport session to use\n\t * @param version - Negotiated protocol version\n\t * @param origin - Origin id shared with the Subscriber\n\t *\n\t * @internal\n\t */\n\tconstructor(quic: WebTransport, version: Version, origin: Origin) {\n\t\tthis.#quic = quic;\n\t\tthis.version = version;\n\t\tthis.origin = origin;\n\t}\n\n\t/**\n\t * Publishes a broadcast with any associated tracks.\n\t * @param name - The broadcast to publish\n\t */\n\tpublish(path: Path.Valid, broadcast: Broadcast) {\n\t\tthis.#broadcasts.mutate((broadcasts) => {\n\t\t\tif (!broadcasts) throw new Error(\"closed\");\n\t\t\tbroadcasts.set(path, broadcast);\n\t\t});\n\n\t\t// Remove the broadcast from the lookup when it's closed.\n\t\tvoid broadcast.closed.finally(() => {\n\t\t\tthis.#broadcasts.mutate((broadcasts) => {\n\t\t\t\tbroadcasts?.delete(path);\n\t\t\t});\n\t\t});\n\t}\n\n\t/**\n\t * Handles an announce interest message.\n\t * @param msg - The announce interest message\n\t * @param stream - The stream to write announcements to\n\t *\n\t * @internal\n\t */\n\tasync runAnnounce(msg: AnnounceInterest, stream: Stream) {\n\t\tconsole.debug(`announce: prefix=${msg.prefix}`);\n\n\t\t// Send initial announcements\n\t\tlet active = new Set<Path.Valid>();\n\n\t\tconst broadcasts = this.#broadcasts.peek();\n\t\tif (!broadcasts) return; // closed\n\n\t\tfor (const name of broadcasts.keys()) {\n\t\t\tconst suffix = Path.stripPrefix(msg.prefix, name);\n\t\t\tif (suffix === null) continue;\n\t\t\tconsole.debug(`announce: broadcast=${name} active=true`);\n\t\t\tactive.add(suffix);\n\t\t}\n\n\t\tswitch (this.version) {\n\t\t\tcase Version.DRAFT_01:\n\t\t\tcase Version.DRAFT_02: {\n\t\t\t\tconst init = new AnnounceInit([...active]);\n\t\t\t\tawait init.encode(stream.writer, this.version);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\t// Draft03+: send individual Announce messages for initial state.\n\t\t\t\tfor (const suffix of active) {\n\t\t\t\t\tconst wire = new Announce({ suffix, active: true, hops: [this.origin] });\n\t\t\t\t\tawait wire.encode(stream.writer, this.version);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\n\t\t// Wait for updates to the broadcasts.\n\t\tfor (;;) {\n\t\t\t// TODO Make a better helper within Signals.\n\t\t\tlet dispose!: Dispose;\n\t\t\tconst changed = new Promise<Map<Path.Valid, Broadcast> | undefined>((resolve) => {\n\t\t\t\tdispose = this.#broadcasts.changed(resolve);\n\t\t\t});\n\n\t\t\t// Wait until the map of broadcasts changes.\n\t\t\tconst broadcasts = await Promise.race([changed, stream.reader.closed]);\n\t\t\tdispose();\n\t\t\tif (!broadcasts) break;\n\n\t\t\t// Create a new set of active broadcasts.\n\t\t\t// This is SLOW, but it's not worth optimizing because we often have just 1 broadcast anyway.\n\t\t\tconst newActive = new Set<Path.Valid>();\n\t\t\tfor (const name of broadcasts.keys()) {\n\t\t\t\tconst suffix = Path.stripPrefix(msg.prefix, name);\n\t\t\t\tif (suffix === null) continue; // Not our prefix.\n\t\t\t\tnewActive.add(suffix);\n\t\t\t}\n\n\t\t\t// Announce any new broadcasts.\n\t\t\tfor (const added of newActive.difference(active)) {\n\t\t\t\tconsole.debug(`announce: broadcast=${added} active=true`);\n\t\t\t\tconst wire = new Announce({ suffix: added, active: true, hops: [this.origin] });\n\t\t\t\tawait wire.encode(stream.writer, this.version);\n\t\t\t}\n\n\t\t\t// Announce any removed broadcasts.\n\t\t\t// Ended announces don't need hops — the peer matches on path only.\n\t\t\tfor (const removed of active.difference(newActive)) {\n\t\t\t\tconsole.debug(`announce: broadcast=${removed} active=false`);\n\t\t\t\tconst wire = new Announce({ suffix: removed, active: false });\n\t\t\t\tawait wire.encode(stream.writer, this.version);\n\t\t\t}\n\n\t\t\t// NOTE: This is kind of a hack that won't work with a rapid UNANNOUNCE/ANNOUNCE cycle.\n\t\t\t// However, our client doesn't do that anyway.\n\n\t\t\tactive = newActive;\n\t\t}\n\t}\n\n\t/**\n\t * Handles a subscribe message.\n\t * @param msg - The subscribe message\n\t * @param stream - The stream to write track data to\n\t *\n\t * @internal\n\t */\n\tasync runSubscribe(msg: Subscribe, stream: Stream) {\n\t\tconst broadcast = this.#broadcasts.peek()?.get(msg.broadcast);\n\t\tif (!broadcast) {\n\t\t\tconsole.debug(`publish unknown: broadcast=${msg.broadcast}`);\n\t\t\tstream.writer.reset(new Error(\"not found\"));\n\t\t\treturn;\n\t\t}\n\n\t\tconst track = broadcast.subscribe(msg.track, msg.priority);\n\n\t\ttry {\n\t\t\t// moq-lite-05+ trims SUBSCRIBE_OK to the resolved start group; the publisher\n\t\t\t// properties move to TRACK_INFO. Earlier versions echo the priority inline.\n\t\t\tconst info = hasTrackStream(this.version)\n\t\t\t\t? new SubscribeOk({ startGroup: msg.startGroup ?? 0 })\n\t\t\t\t: new SubscribeOk({ priority: msg.priority });\n\t\t\tawait encodeSubscribeResponse(stream.writer, { ok: info }, this.version);\n\n\t\t\tconsole.debug(`publish ok: broadcast=${msg.broadcast} track=${track.name}`);\n\n\t\t\tconst serving = this.#runTrack(msg.id, msg.broadcast, track, stream.writer);\n\n\t\t\tfor (;;) {\n\t\t\t\tconst decode = SubscribeUpdate.decodeMaybe(stream.reader, this.version);\n\n\t\t\t\tconst result = await Promise.any([serving, decode]);\n\t\t\t\tif (!result) break;\n\n\t\t\t\tif (result instanceof SubscribeUpdate) {\n\t\t\t\t\tconsole.debug(\n\t\t\t\t\t\t`subscribe update: broadcast=${msg.broadcast} track=${track.name} priority=${result.priority}`,\n\t\t\t\t\t);\n\t\t\t\t\ttrack.updatePriority(result.priority);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconsole.debug(`publish done: broadcast=${msg.broadcast} track=${track.name}`);\n\t\t\tstream.close();\n\t\t\ttrack.close();\n\t\t} catch (err: unknown) {\n\t\t\tconst e = error(err);\n\t\t\tconsole.warn(`publish error: broadcast=${msg.broadcast} track=${track.name} error=${e.message}`);\n\t\t\ttrack.close(e);\n\t\t\tstream.abort(e);\n\t\t}\n\t}\n\n\t/**\n\t * Serves a Track stream (moq-lite-05+): replies with the track's immutable TRACK_INFO.\n\t *\n\t * @internal\n\t */\n\tasync runTrackInfo(msg: TrackMessage, stream: Stream) {\n\t\tconst broadcast = this.#broadcasts.peek()?.get(msg.broadcast);\n\t\tif (!broadcast) {\n\t\t\tthrow new Error(\"not found\");\n\t\t}\n\n\t\t// The publisher properties aren't tracked in the browser model yet; report\n\t\t// defaults with a millisecond timescale matching the wall-clock frame timestamps.\n\t\tconst info = new TrackInfo({ timescale: 1000 });\n\t\tawait info.encode(stream.writer, this.version);\n\t}\n\n\t/**\n\t * Runs a track and sends its data to the stream.\n\t * @param sub - The subscription ID\n\t * @param broadcast - The broadcast name\n\t * @param track - The track to run\n\t * @param stream - The stream to write to\n\t *\n\t * @internal\n\t */\n\tasync #runTrack(sub: bigint, broadcast: Path.Valid, track: Track, stream: Writer) {\n\t\ttry {\n\t\t\tlet lastSequence: number | undefined;\n\t\t\tlet trackEnded = false;\n\n\t\t\tfor (;;) {\n\t\t\t\tconst next = track.recvGroup();\n\t\t\t\tconst res = await Promise.race([\n\t\t\t\t\tnext.then((group) => ({ group })),\n\t\t\t\t\tstream.closed.then(() => \"closed\" as const),\n\t\t\t\t]);\n\t\t\t\tif (res === \"closed\") {\n\t\t\t\t\tnext.then((group) => group?.close()).catch(() => {});\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif (!res.group) {\n\t\t\t\t\ttrackEnded = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tlastSequence = res.group.sequence;\n\t\t\t\tvoid this.#runGroup(sub, res.group);\n\t\t\t}\n\n\t\t\t// moq-lite-05+: signal end-of-track before the subscribe stream FINs.\n\t\t\tif (trackEnded && hasTrackStream(this.version)) {\n\t\t\t\tconst end = new SubscribeEnd({ group: lastSequence ?? 0 });\n\t\t\t\tawait encodeSubscribeResponse(stream, { end }, this.version);\n\t\t\t}\n\n\t\t\tconsole.debug(`publish close: broadcast=${broadcast} track=${track.name}`);\n\t\t\ttrack.close();\n\t\t\tstream.close();\n\t\t} catch (err: unknown) {\n\t\t\tconst e = error(err);\n\t\t\tconsole.warn(`publish error: broadcast=${broadcast} track=${track.name} error=${e.message}`);\n\t\t\ttrack.close(e);\n\t\t\tstream.reset(e);\n\t\t}\n\t}\n\n\t/**\n\t * Runs a group and sends its frames to the stream.\n\t * @param sub - The subscription ID\n\t * @param group - The group to run\n\t *\n\t * @internal\n\t */\n\tasync #runGroup(sub: bigint, group: Group) {\n\t\tconst msg = new GroupMessage(sub, group.sequence);\n\t\ttry {\n\t\t\tconst stream = await Writer.open(this.#quic);\n\t\t\tawait stream.u8(0); // stream type\n\t\t\tawait msg.encode(stream);\n\n\t\t\ttry {\n\t\t\t\t// moq-lite-05+ stamps each frame with a wall-clock millisecond timestamp, sent\n\t\t\t\t// as a zigzag delta from the previous frame (the first frame is a delta from 0).\n\t\t\t\tlet prevTimestamp = 0n;\n\n\t\t\t\tfor (;;) {\n\t\t\t\t\tconst frame = await Promise.race([group.readFrame(), stream.closed]);\n\t\t\t\t\tif (!frame) break;\n\n\t\t\t\t\tif (hasTrackStream(this.version)) {\n\t\t\t\t\t\tconst now = BigInt(Date.now());\n\t\t\t\t\t\tconst delta = now - prevTimestamp;\n\t\t\t\t\t\tprevTimestamp = now;\n\t\t\t\t\t\tawait stream.u62((delta << 1n) ^ (delta >> 63n));\n\t\t\t\t\t}\n\n\t\t\t\t\tawait stream.u53(frame.byteLength);\n\t\t\t\t\tawait stream.write(frame);\n\t\t\t\t}\n\n\t\t\t\tstream.close();\n\t\t\t\tgroup.close();\n\t\t\t} catch (err: unknown) {\n\t\t\t\tconst e = error(err);\n\t\t\t\tstream.reset(e);\n\t\t\t\tgroup.close(e);\n\t\t\t}\n\t\t} catch (err: unknown) {\n\t\t\tconst e = error(err);\n\t\t\tgroup.close(e);\n\t\t}\n\t}\n\n\t/**\n\t * Handles a probe stream by periodically reporting estimated bitrate.\n\t * @param stream - The probe bidi stream\n\t *\n\t * @internal\n\t */\n\tasync runProbe(stream: Stream) {\n\t\t// getStats is not yet in the TypeScript WebTransport type definitions.\n\t\tconst quic = this.#quic as unknown as {\n\t\t\tgetStats?: () => Promise<{ estimatedSendRate: number | null }>;\n\t\t};\n\t\tif (!quic.getStats) {\n\t\t\t// Best-effort: we can't supply bandwidth estimates, so close the\n\t\t\t// whole bidi (FIN + STOP_SENDING) to let the peer release its end.\n\t\t\tstream.close();\n\t\t\treturn;\n\t\t}\n\n\t\tlet lastSentBitrate: number | undefined;\n\t\tlet lastSentTime: number | undefined;\n\n\t\ttry {\n\t\t\tfor (;;) {\n\t\t\t\tconst timeout = new Promise<\"timeout\">((resolve) =>\n\t\t\t\t\tsetTimeout(() => resolve(\"timeout\"), PROBE_INTERVAL),\n\t\t\t\t);\n\t\t\t\tconst result = await Promise.race([timeout, stream.reader.closed]);\n\t\t\t\tif (result !== \"timeout\") break;\n\n\t\t\t\tconst stats = await quic.getStats();\n\t\t\t\tconst bitrate = stats.estimatedSendRate;\n\t\t\t\tif (bitrate == null) continue;\n\n\t\t\t\tlet shouldSend: boolean;\n\t\t\t\tif (lastSentBitrate === undefined || lastSentTime === undefined) {\n\t\t\t\t\tshouldSend = true;\n\t\t\t\t} else if (lastSentBitrate === 0) {\n\t\t\t\t\tshouldSend = bitrate > 0;\n\t\t\t\t} else {\n\t\t\t\t\tconst elapsed = performance.now() - lastSentTime;\n\t\t\t\t\tconst t = Math.max(PROBE_INTERVAL, Math.min(PROBE_MAX_AGE, elapsed));\n\t\t\t\t\tconst range = PROBE_MAX_AGE - PROBE_INTERVAL;\n\t\t\t\t\tconst threshold = (PROBE_MAX_DELTA * (PROBE_MAX_AGE - t)) / range;\n\t\t\t\t\tconst change = Math.abs(bitrate - lastSentBitrate) / lastSentBitrate;\n\t\t\t\t\tshouldSend = change >= threshold;\n\t\t\t\t}\n\n\t\t\t\tif (shouldSend) {\n\t\t\t\t\tawait new Probe(bitrate).encode(stream.writer, this.version);\n\t\t\t\t\tlastSentBitrate = bitrate;\n\t\t\t\t\tlastSentTime = performance.now();\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (err: unknown) {\n\t\t\tconsole.warn(\"probe stream error\", err);\n\t\t\tstream.close();\n\t\t}\n\t}\n\n\tclose() {\n\t\tthis.#broadcasts.update((broadcasts) => {\n\t\t\tfor (const broadcast of broadcasts?.values() ?? []) {\n\t\t\t\tbroadcast.close();\n\t\t\t}\n\t\t\treturn undefined;\n\t\t});\n\t}\n}\n"]}
@@ -0,0 +1,36 @@
1
+ import type { Reader, Writer } from "../stream";
2
+ import { Version } from "./version";
3
+ export declare class Extensions {
4
+ entries: Map<bigint, Uint8Array>;
5
+ constructor();
6
+ set(id: bigint, value: Uint8Array): void;
7
+ get(id: bigint): Uint8Array | undefined;
8
+ remove(id: bigint): Uint8Array | undefined;
9
+ encode(w: Writer): Promise<void>;
10
+ static decode(r: Reader): Promise<Extensions>;
11
+ }
12
+ export declare class SessionClient {
13
+ #private;
14
+ versions: number[];
15
+ extensions: Extensions;
16
+ constructor(versions: number[], extensions?: Extensions);
17
+ encode(w: Writer): Promise<void>;
18
+ static decode(r: Reader): Promise<SessionClient>;
19
+ }
20
+ export declare class SessionServer {
21
+ #private;
22
+ version: number;
23
+ extensions: Extensions;
24
+ constructor(version: number, extensions?: Extensions);
25
+ encode(w: Writer): Promise<void>;
26
+ static decode(r: Reader): Promise<SessionServer>;
27
+ }
28
+ export declare class SessionInfo {
29
+ #private;
30
+ bitrate: number;
31
+ constructor(bitrate: number);
32
+ encode(w: Writer, version: Version): Promise<void>;
33
+ static decode(r: Reader, version: Version): Promise<SessionInfo>;
34
+ static decodeMaybe(r: Reader, version: Version): Promise<SessionInfo | undefined>;
35
+ }
36
+ //# sourceMappingURL=session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/lite/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEnD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,qBAAa,UAAU;IACtB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAEjC,cAEC;IAED,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,QAEhC;IAED,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAEtC;IAED,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAIzC;IAEK,MAAM,CAAC,CAAC,EAAE,MAAM,iBAOrB;IAED,OAAa,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAiBlD;CACD;AAED,qBAAa,aAAa;;IACzB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,UAAU,EAAE,UAAU,CAAC;IAEvB,YAAY,QAAQ,EAAE,MAAM,EAAE,EAAE,UAAU,aAAmB,EAG5D;IAsBK,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAErC;IAED,OAAa,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAErD;CACD;AAED,qBAAa,aAAa;;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,UAAU,CAAC;IAEvB,YAAY,OAAO,EAAE,MAAM,EAAE,UAAU,aAAmB,EAGzD;IAaK,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAErC;IAED,OAAa,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAErD;CACD;AAED,qBAAa,WAAW;;IACvB,OAAO,EAAE,MAAM,CAAC;IAEhB,YAAY,OAAO,EAAE,MAAM,EAE1B;IAqBK,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAGvD;IAED,OAAa,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC,CAGrE;IAED,OAAa,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAGtF;CACD"}