werift 0.23.0 → 0.24.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.
Files changed (169) hide show
  1. package/README.md +46 -0
  2. package/lib/common/src/binary.js +2 -3
  3. package/lib/common/src/binary.js.map +1 -1
  4. package/lib/common/src/transport.d.ts +22 -9
  5. package/lib/common/src/transport.js +152 -25
  6. package/lib/common/src/transport.js.map +1 -1
  7. package/lib/ice/src/candidate.d.ts +16 -1
  8. package/lib/ice/src/candidate.js +99 -15
  9. package/lib/ice/src/candidate.js.map +1 -1
  10. package/lib/ice/src/ice.d.ts +2 -0
  11. package/lib/ice/src/ice.js +175 -50
  12. package/lib/ice/src/ice.js.map +1 -1
  13. package/lib/ice/src/iceBase.d.ts +23 -2
  14. package/lib/ice/src/iceBase.js +63 -1
  15. package/lib/ice/src/iceBase.js.map +1 -1
  16. package/lib/ice/src/index.d.ts +2 -0
  17. package/lib/ice/src/index.js +2 -0
  18. package/lib/ice/src/index.js.map +1 -1
  19. package/lib/ice/src/internal/selectAddresses.d.ts +9 -0
  20. package/lib/ice/src/internal/selectAddresses.js +40 -0
  21. package/lib/ice/src/internal/selectAddresses.js.map +1 -0
  22. package/lib/ice/src/stun/const.d.ts +1 -26
  23. package/lib/ice/src/stun/const.js +15 -54
  24. package/lib/ice/src/stun/const.js.map +1 -1
  25. package/lib/ice/src/stun/message.d.ts +1 -25
  26. package/lib/ice/src/stun/message.js +15 -149
  27. package/lib/ice/src/stun/message.js.map +1 -1
  28. package/lib/ice/src/stun/protocol.d.ts +1 -1
  29. package/lib/ice/src/stun/protocol.js +2 -2
  30. package/lib/ice/src/stun/protocol.js.map +1 -1
  31. package/lib/ice/src/stun/tcpFrame.d.ts +5 -0
  32. package/lib/ice/src/stun/tcpFrame.js +26 -0
  33. package/lib/ice/src/stun/tcpFrame.js.map +1 -0
  34. package/lib/ice/src/stun/tcpProtocol.d.ts +51 -0
  35. package/lib/ice/src/stun/tcpProtocol.js +326 -0
  36. package/lib/ice/src/stun/tcpProtocol.js.map +1 -0
  37. package/lib/ice/src/stun/transaction.d.ts +2 -1
  38. package/lib/ice/src/stun/transaction.js +9 -3
  39. package/lib/ice/src/stun/transaction.js.map +1 -1
  40. package/lib/ice/src/turn/frame.d.ts +1 -0
  41. package/lib/ice/src/turn/frame.js +18 -0
  42. package/lib/ice/src/turn/frame.js.map +1 -0
  43. package/lib/ice/src/turn/protocol.d.ts +9 -7
  44. package/lib/ice/src/turn/protocol.js +32 -44
  45. package/lib/ice/src/turn/protocol.js.map +1 -1
  46. package/lib/ice/src/types/model.d.ts +1 -1
  47. package/lib/ice/src/types/model.js.map +1 -1
  48. package/lib/ice/src/utils.js +2 -31
  49. package/lib/ice/src/utils.js.map +1 -1
  50. package/lib/{ice → ice-server}/src/stun/attributes.d.ts +12 -5
  51. package/lib/{ice → ice-server}/src/stun/attributes.js +69 -66
  52. package/lib/ice-server/src/stun/attributes.js.map +1 -0
  53. package/lib/ice-server/src/stun/const.d.ts +28 -0
  54. package/lib/ice-server/src/stun/const.js +88 -0
  55. package/lib/ice-server/src/stun/const.js.map +1 -0
  56. package/lib/ice-server/src/stun/ip.d.ts +12 -0
  57. package/lib/ice-server/src/stun/ip.js +88 -0
  58. package/lib/ice-server/src/stun/ip.js.map +1 -0
  59. package/lib/ice-server/src/stun/message.d.ts +37 -0
  60. package/lib/ice-server/src/stun/message.js +190 -0
  61. package/lib/ice-server/src/stun/message.js.map +1 -0
  62. package/lib/ice-server/src/turn/auth.d.ts +1 -0
  63. package/lib/ice-server/src/turn/auth.js +10 -0
  64. package/lib/ice-server/src/turn/auth.js.map +1 -0
  65. package/lib/ice-server/src/turn/frame.d.ts +13 -0
  66. package/lib/ice-server/src/turn/frame.js +69 -0
  67. package/lib/ice-server/src/turn/frame.js.map +1 -0
  68. package/lib/index.mjs +2866 -946
  69. package/lib/nonstandard/index.mjs +1872 -455
  70. package/lib/rtp/src/codec/av1.js +11 -5
  71. package/lib/rtp/src/codec/av1.js.map +1 -1
  72. package/lib/rtp/src/codec/leb128.d.ts +5 -0
  73. package/lib/rtp/src/codec/leb128.js +24 -0
  74. package/lib/rtp/src/codec/leb128.js.map +1 -0
  75. package/lib/rtp/src/extra/container/mp4/container.d.ts +9 -6
  76. package/lib/rtp/src/extra/container/mp4/container.js +258 -173
  77. package/lib/rtp/src/extra/container/mp4/container.js.map +1 -1
  78. package/lib/rtp/src/extra/container/mp4/h264.d.ts +1 -0
  79. package/lib/rtp/src/extra/container/mp4/h264.js +13 -0
  80. package/lib/rtp/src/extra/container/mp4/h264.js.map +1 -1
  81. package/lib/rtp/src/extra/processor/mp4.d.ts +11 -7
  82. package/lib/rtp/src/extra/processor/mp4.js +115 -60
  83. package/lib/rtp/src/extra/processor/mp4.js.map +1 -1
  84. package/lib/rtp/src/extra/processor/mp4Callback.d.ts +2 -3
  85. package/lib/rtp/src/extra/processor/mp4Callback.js +5 -3
  86. package/lib/rtp/src/extra/processor/mp4Callback.js.map +1 -1
  87. package/lib/rtp/src/rtp/rtx.js +4 -6
  88. package/lib/rtp/src/rtp/rtx.js.map +1 -1
  89. package/lib/rtp/src/srtp/context/context.d.ts +2 -0
  90. package/lib/rtp/src/srtp/context/context.js +12 -12
  91. package/lib/rtp/src/srtp/context/context.js.map +1 -1
  92. package/lib/sctp/src/param.js +31 -15
  93. package/lib/sctp/src/param.js.map +1 -1
  94. package/lib/sctp/src/sctp.js +10 -9
  95. package/lib/sctp/src/sctp.js.map +1 -1
  96. package/lib/webrtc/src/dataChannel.d.ts +3 -2
  97. package/lib/webrtc/src/dataChannel.js +9 -2
  98. package/lib/webrtc/src/dataChannel.js.map +1 -1
  99. package/lib/webrtc/src/errors.d.ts +3 -0
  100. package/lib/webrtc/src/errors.js +11 -0
  101. package/lib/webrtc/src/errors.js.map +1 -0
  102. package/lib/webrtc/src/helper.d.ts +5 -1
  103. package/lib/webrtc/src/helper.js +33 -1
  104. package/lib/webrtc/src/helper.js.map +1 -1
  105. package/lib/webrtc/src/media/receiver/statistics.d.ts +4 -1
  106. package/lib/webrtc/src/media/receiver/statistics.js +22 -0
  107. package/lib/webrtc/src/media/receiver/statistics.js.map +1 -1
  108. package/lib/webrtc/src/media/rtpReceiver.d.ts +15 -2
  109. package/lib/webrtc/src/media/rtpReceiver.js +135 -20
  110. package/lib/webrtc/src/media/rtpReceiver.js.map +1 -1
  111. package/lib/webrtc/src/media/rtpSender.d.ts +32 -7
  112. package/lib/webrtc/src/media/rtpSender.js +179 -31
  113. package/lib/webrtc/src/media/rtpSender.js.map +1 -1
  114. package/lib/webrtc/src/media/rtpTransceiver.d.ts +13 -4
  115. package/lib/webrtc/src/media/rtpTransceiver.js +26 -5
  116. package/lib/webrtc/src/media/rtpTransceiver.js.map +1 -1
  117. package/lib/webrtc/src/media/stats.d.ts +15 -1
  118. package/lib/webrtc/src/media/stats.js +55 -1
  119. package/lib/webrtc/src/media/stats.js.map +1 -1
  120. package/lib/webrtc/src/media/track.d.ts +2 -1
  121. package/lib/webrtc/src/media/track.js +7 -1
  122. package/lib/webrtc/src/media/track.js.map +1 -1
  123. package/lib/webrtc/src/nonstandard/dummyMedia.d.ts +19 -0
  124. package/lib/webrtc/src/nonstandard/dummyMedia.js +157 -0
  125. package/lib/webrtc/src/nonstandard/dummyMedia.js.map +1 -0
  126. package/lib/webrtc/src/nonstandard/navigator.d.ts +18 -8
  127. package/lib/webrtc/src/nonstandard/navigator.js +96 -32
  128. package/lib/webrtc/src/nonstandard/navigator.js.map +1 -1
  129. package/lib/webrtc/src/nonstandard/userMedia/packetizer.d.ts +16 -0
  130. package/lib/webrtc/src/nonstandard/userMedia/packetizer.js +360 -0
  131. package/lib/webrtc/src/nonstandard/userMedia/packetizer.js.map +1 -0
  132. package/lib/webrtc/src/nonstandard/userMedia.d.ts +71 -31
  133. package/lib/webrtc/src/nonstandard/userMedia.js +454 -108
  134. package/lib/webrtc/src/nonstandard/userMedia.js.map +1 -1
  135. package/lib/webrtc/src/peerConnection.d.ts +183 -50
  136. package/lib/webrtc/src/peerConnection.js +458 -109
  137. package/lib/webrtc/src/peerConnection.js.map +1 -1
  138. package/lib/webrtc/src/sctpManager.d.ts +1 -1
  139. package/lib/webrtc/src/sctpManager.js +27 -7
  140. package/lib/webrtc/src/sctpManager.js.map +1 -1
  141. package/lib/webrtc/src/sdp.d.ts +10 -7
  142. package/lib/webrtc/src/sdp.js +40 -44
  143. package/lib/webrtc/src/sdp.js.map +1 -1
  144. package/lib/webrtc/src/sdpManager.d.ts +4 -3
  145. package/lib/webrtc/src/sdpManager.js +50 -27
  146. package/lib/webrtc/src/sdpManager.js.map +1 -1
  147. package/lib/webrtc/src/secureTransportManager.d.ts +13 -4
  148. package/lib/webrtc/src/secureTransportManager.js +100 -22
  149. package/lib/webrtc/src/secureTransportManager.js.map +1 -1
  150. package/lib/webrtc/src/transceiverManager.d.ts +5 -4
  151. package/lib/webrtc/src/transceiverManager.js +61 -62
  152. package/lib/webrtc/src/transceiverManager.js.map +1 -1
  153. package/lib/webrtc/src/transport/dtls.d.ts +15 -4
  154. package/lib/webrtc/src/transport/dtls.js +91 -23
  155. package/lib/webrtc/src/transport/dtls.js.map +1 -1
  156. package/lib/webrtc/src/transport/ice.d.ts +21 -3
  157. package/lib/webrtc/src/transport/ice.js +159 -30
  158. package/lib/webrtc/src/transport/ice.js.map +1 -1
  159. package/lib/webrtc/src/transport/sctp.d.ts +1 -0
  160. package/lib/webrtc/src/transport/sctp.js +26 -22
  161. package/lib/webrtc/src/transport/sctp.js.map +1 -1
  162. package/lib/webrtc/src/utils.d.ts +12 -4
  163. package/lib/webrtc/src/utils.js +118 -16
  164. package/lib/webrtc/src/utils.js.map +1 -1
  165. package/package.json +7 -10
  166. package/lib/ice/src/stun/attributes.js.map +0 -1
  167. package/lib/rtp/src/extra/container/mp4/mp4box.d.ts +0 -5
  168. package/lib/rtp/src/extra/container/mp4/mp4box.js +0 -32
  169. package/lib/rtp/src/extra/container/mp4/mp4box.js.map +0 -1
@@ -1,11 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.navigator = exports.MediaDevices = exports.Navigator = void 0;
4
- const crypto_1 = require("crypto");
5
4
  const dgram_1 = require("dgram");
6
- const jspack_1 = require("@shinyoshiaki/jspack");
7
5
  const __1 = require("..");
8
6
  const track_1 = require("../media/track");
7
+ const dummyMedia_1 = require("./dummyMedia");
9
8
  class Navigator {
10
9
  constructor(props = {}) {
11
10
  Object.defineProperty(this, "mediaDevices", {
@@ -19,7 +18,7 @@ class Navigator {
19
18
  }
20
19
  exports.Navigator = Navigator;
21
20
  class MediaDevices extends EventTarget {
22
- constructor(props) {
21
+ constructor(props = {}) {
23
22
  super();
24
23
  Object.defineProperty(this, "props", {
25
24
  enumerable: true,
@@ -39,41 +38,29 @@ class MediaDevices extends EventTarget {
39
38
  writable: true,
40
39
  value: void 0
41
40
  });
41
+ Object.defineProperty(this, "activeSourceStops", {
42
+ enumerable: true,
43
+ configurable: true,
44
+ writable: true,
45
+ value: new Map()
46
+ });
42
47
  Object.defineProperty(this, "getUserMedia", {
43
48
  enumerable: true,
44
49
  configurable: true,
45
50
  writable: true,
46
51
  value: async (constraints) => {
47
- const video = constraints.video
48
- ? new track_1.MediaStreamTrack({ kind: "video" })
49
- : undefined;
50
- if (video) {
51
- this.video?.onReceiveRtp.subscribe((rtp) => {
52
- const cloned = rtp.clone();
53
- cloned.header.ssrc = jspack_1.jspack.Unpack("!L", (0, crypto_1.randomBytes)(4))[0];
54
- video.onReceiveRtp.execute(cloned);
55
- });
56
- }
57
- const audio = constraints.audio
58
- ? new track_1.MediaStreamTrack({ kind: "audio" })
59
- : undefined;
60
- if (audio) {
61
- this.audio?.onReceiveRtp.subscribe((rtp) => {
62
- const cloned = rtp.clone();
63
- cloned.header.ssrc = jspack_1.jspack.Unpack("!L", (0, crypto_1.randomBytes)(4))[0];
64
- audio.onReceiveRtp.execute(cloned);
65
- });
52
+ const tracks = [
53
+ ...(constraints.audio
54
+ ? [this.createTrack("audio", constraints.audio)]
55
+ : []),
56
+ ...(constraints.video
57
+ ? [this.createTrack("video", constraints.video)]
58
+ : []),
59
+ ];
60
+ if (tracks.length === 0) {
61
+ throw new Error("At least one audio or video track is required");
66
62
  }
67
- if (constraints.video && constraints.audio) {
68
- return new track_1.MediaStream([video, audio]);
69
- }
70
- else if (constraints.audio) {
71
- return new track_1.MediaStream([audio]);
72
- }
73
- else if (constraints.video) {
74
- return new track_1.MediaStream([video]);
75
- }
76
- throw new Error("Not implemented");
63
+ return new track_1.MediaStream(tracks);
77
64
  }
78
65
  });
79
66
  Object.defineProperty(this, "getDisplayMedia", {
@@ -108,7 +95,84 @@ class MediaDevices extends EventTarget {
108
95
  this.video = props.video;
109
96
  this.audio = props.audio;
110
97
  }
98
+ cleanup() {
99
+ for (const stop of this.activeSourceStops.values()) {
100
+ stop();
101
+ }
102
+ this.activeSourceStops.clear();
103
+ }
104
+ createTrack(kind, constraints) {
105
+ const existingTrack = kind === "audio" ? this.audio : this.video;
106
+ if (existingTrack) {
107
+ return this.createClonedTrack(kind, existingTrack);
108
+ }
109
+ if (this.props.dummyMedia?.enabled) {
110
+ return this.createDummyTrack(kind, constraints);
111
+ }
112
+ throw new Error(`No ${kind} source configured for getUserMedia`);
113
+ }
114
+ createClonedTrack(kind, sourceTrack) {
115
+ const track = new track_1.MediaStreamTrack({ kind });
116
+ const { unSubscribe } = sourceTrack.onReceiveRtp.subscribe((rtp) => {
117
+ track.onReceiveRtp.execute(rtp.clone());
118
+ });
119
+ this.attachTrackStop(track, () => {
120
+ unSubscribe();
121
+ });
122
+ return track;
123
+ }
124
+ createDummyTrack(kind, constraints) {
125
+ const dummy = kind === "audio"
126
+ ? (0, dummyMedia_1.createDummyAudioTrack)(this.props.dummyMedia?.audio)
127
+ : (0, dummyMedia_1.createDummyVideoTrack)({
128
+ ...this.props.dummyMedia?.video,
129
+ ...resolveVideoOptions(constraints),
130
+ });
131
+ this.attachTrackStop(dummy.track, () => {
132
+ dummy.source.stop();
133
+ });
134
+ return dummy.track;
135
+ }
136
+ attachTrackStop(track, stop) {
137
+ let disposed = false;
138
+ const originalStop = track.stop;
139
+ const dispose = () => {
140
+ if (disposed) {
141
+ return;
142
+ }
143
+ disposed = true;
144
+ stop();
145
+ this.activeSourceStops.delete(track);
146
+ };
147
+ track.stop = () => {
148
+ dispose();
149
+ originalStop();
150
+ };
151
+ this.activeSourceStops.set(track, dispose);
152
+ }
111
153
  }
112
154
  exports.MediaDevices = MediaDevices;
113
155
  exports.navigator = new Navigator();
156
+ function resolveVideoOptions(constraints) {
157
+ if (typeof constraints === "boolean") {
158
+ return {};
159
+ }
160
+ const fps = resolveConstrainNumber(constraints.frameRate);
161
+ if (!fps) {
162
+ return {};
163
+ }
164
+ return {
165
+ fps,
166
+ keyframeIntervalFrames: Math.max(1, Math.round(fps)),
167
+ };
168
+ }
169
+ function resolveConstrainNumber(value) {
170
+ if (typeof value === "number") {
171
+ return value;
172
+ }
173
+ if (!value || typeof value !== "object") {
174
+ return;
175
+ }
176
+ return value.exact ?? value.ideal ?? value.max ?? value.min;
177
+ }
114
178
  //# sourceMappingURL=navigator.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"navigator.js","sourceRoot":"","sources":["../../../../src/nonstandard/navigator.ts"],"names":[],"mappings":";;;AAAA,mCAAqC;AACrC,iCAAqC;AACrC,iDAA8C;AAC9C,0BAA2C;AAC3C,0CAA+D;AAE/D,MAAa,SAAS;IAGpB,YAAY,QAAuD,EAAE;QAFrE;;;;;WAA2B;QAGzB,IAAI,CAAC,YAAY,GAAG,IAAI,YAAY,CAAC,KAAK,CAAC,CAAC;IAC9C,CAAC;CACF;AAND,8BAMC;AAED,MAAa,YAAa,SAAQ,WAAW;IAI3C,YACW,KAA6D;QAEtE,KAAK,EAAE,CAAC;QAFR;;;;mBAAS,KAAK;WAAwD;QAJxE;;;;;WAAyB;QACzB;;;;;WAAyB;QAUhB;;;;mBAAe,KAAK,EAC3B,WAAmC,EACb,EAAE;gBACxB,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK;oBAC7B,CAAC,CAAC,IAAI,wBAAgB,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;oBACzC,CAAC,CAAC,SAAS,CAAC;gBACd,IAAI,KAAK,EAAE,CAAC;oBACV,IAAI,CAAC,KAAK,EAAE,YAAY,CAAC,SAAS,CAAC,CAAC,GAAG,EAAE,EAAE;wBACzC,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC;wBAC3B,MAAM,CAAC,MAAM,CAAC,IAAI,GAAG,eAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAA,oBAAW,EAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;wBAC5D,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;oBACrC,CAAC,CAAC,CAAC;gBACL,CAAC;gBACD,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK;oBAC7B,CAAC,CAAC,IAAI,wBAAgB,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;oBACzC,CAAC,CAAC,SAAS,CAAC;gBACd,IAAI,KAAK,EAAE,CAAC;oBACV,IAAI,CAAC,KAAK,EAAE,YAAY,CAAC,SAAS,CAAC,CAAC,GAAG,EAAE,EAAE;wBACzC,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC;wBAC3B,MAAM,CAAC,MAAM,CAAC,IAAI,GAAG,eAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAA,oBAAW,EAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;wBAC5D,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;oBACrC,CAAC,CAAC,CAAC;gBACL,CAAC;gBAED,IAAI,WAAW,CAAC,KAAK,IAAI,WAAW,CAAC,KAAK,EAAE,CAAC;oBAC3C,OAAO,IAAI,mBAAW,CAAC,CAAC,KAAM,EAAE,KAAM,CAAC,CAAC,CAAC;gBAC3C,CAAC;qBAAM,IAAI,WAAW,CAAC,KAAK,EAAE,CAAC;oBAC7B,OAAO,IAAI,mBAAW,CAAC,CAAC,KAAM,CAAC,CAAC,CAAC;gBACnC,CAAC;qBAAM,IAAI,WAAW,CAAC,KAAK,EAAE,CAAC;oBAC7B,OAAO,IAAI,mBAAW,CAAC,CAAC,KAAM,CAAC,CAAC,CAAC;gBACnC,CAAC;gBAED,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;YACrC,CAAC;WAAC;QAEO;;;;mBAAkB,IAAI,CAAC,YAAY;WAAC;QAEpC;;;;mBAAc,CAAC,EACtB,IAAI,EACJ,KAAK,GAIN,EAAE,EAAE;gBACH,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC;oBACzD,CAAC,CAAC,OAAO;oBACT,CAAC,CAAC,OAAO,CAAC;gBACZ,MAAM,KAAK,GAAG,IAAI,wBAAgB,CAAC;oBACjC,IAAI;oBACJ,KAAK,EAAE,IAAI,yBAAqB,CAAC,KAAK,CAAC;iBACxC,CAAC,CAAC;gBAEH,MAAM,GAAG,GAAG,IAAA,oBAAY,EAAC,MAAM,CAAC,CAAC;gBACjC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACf,GAAG,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE;oBACzB,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;gBACvB,CAAC,CAAC,CAAC;gBAEH,MAAM,QAAQ,GAAG,GAAG,EAAE;oBACpB,GAAG,CAAC,KAAK,EAAE,CAAC;gBACd,CAAC,CAAC;gBAEF,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;YAC7B,CAAC;WAAC;QAnEA,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;QACzB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IAC3B,CAAC;CAkEF;AA5ED,oCA4EC;AA2DY,QAAA,SAAS,GAAG,IAAI,SAAS,EAAE,CAAC","sourcesContent":["import { randomBytes } from \"crypto\";\nimport { createSocket } from \"dgram\";\nimport { jspack } from \"@shinyoshiaki/jspack\";\nimport { RTCRtpCodecParameters } from \"..\";\nimport { MediaStream, MediaStreamTrack } from \"../media/track\";\n\nexport class Navigator {\n mediaDevices: MediaDevices;\n\n constructor(props: ConstructorParameters<typeof MediaDevices>[0] = {}) {\n this.mediaDevices = new MediaDevices(props);\n }\n}\n\nexport class MediaDevices extends EventTarget {\n video?: MediaStreamTrack;\n audio?: MediaStreamTrack;\n\n constructor(\n readonly props: { video?: MediaStreamTrack; audio?: MediaStreamTrack },\n ) {\n super();\n this.video = props.video;\n this.audio = props.audio;\n }\n\n readonly getUserMedia = async (\n constraints: MediaStreamConstraints,\n ): Promise<MediaStream> => {\n const video = constraints.video\n ? new MediaStreamTrack({ kind: \"video\" })\n : undefined;\n if (video) {\n this.video?.onReceiveRtp.subscribe((rtp) => {\n const cloned = rtp.clone();\n cloned.header.ssrc = jspack.Unpack(\"!L\", randomBytes(4))[0];\n video.onReceiveRtp.execute(cloned);\n });\n }\n const audio = constraints.audio\n ? new MediaStreamTrack({ kind: \"audio\" })\n : undefined;\n if (audio) {\n this.audio?.onReceiveRtp.subscribe((rtp) => {\n const cloned = rtp.clone();\n cloned.header.ssrc = jspack.Unpack(\"!L\", randomBytes(4))[0];\n audio.onReceiveRtp.execute(cloned);\n });\n }\n\n if (constraints.video && constraints.audio) {\n return new MediaStream([video!, audio!]);\n } else if (constraints.audio) {\n return new MediaStream([audio!]);\n } else if (constraints.video) {\n return new MediaStream([video!]);\n }\n\n throw new Error(\"Not implemented\");\n };\n\n readonly getDisplayMedia = this.getUserMedia;\n\n readonly getUdpMedia = ({\n port,\n codec,\n }: {\n port: number;\n codec: ConstructorParameters<typeof RTCRtpCodecParameters>[0];\n }) => {\n const kind = codec.mimeType.toLowerCase().includes(\"video\")\n ? \"video\"\n : \"audio\";\n const track = new MediaStreamTrack({\n kind,\n codec: new RTCRtpCodecParameters(codec),\n });\n\n const udp = createSocket(\"udp4\");\n udp.bind(port);\n udp.on(\"message\", (data) => {\n track.writeRtp(data);\n });\n\n const disposer = () => {\n udp.close();\n };\n\n return { track, disposer };\n };\n}\n\ninterface MediaStreamConstraints {\n audio?: boolean | MediaTrackConstraints;\n peerIdentity?: string;\n preferCurrentTab?: boolean;\n video?: boolean | MediaTrackConstraints;\n}\n\ninterface MediaTrackConstraints extends MediaTrackConstraintSet {\n advanced?: MediaTrackConstraintSet[];\n}\n\ninterface MediaTrackConstraintSet {\n aspectRatio?: ConstrainDouble;\n autoGainControl?: ConstrainBoolean;\n channelCount?: ConstrainULong;\n deviceId?: ConstrainDOMString;\n displaySurface?: ConstrainDOMString;\n echoCancellation?: ConstrainBoolean;\n facingMode?: ConstrainDOMString;\n frameRate?: ConstrainDouble;\n groupId?: ConstrainDOMString;\n height?: ConstrainULong;\n noiseSuppression?: ConstrainBoolean;\n sampleRate?: ConstrainULong;\n sampleSize?: ConstrainULong;\n width?: ConstrainULong;\n}\n\ntype ConstrainDOMString = string | string[] | ConstrainDOMStringParameters;\ninterface ConstrainDOMStringParameters {\n exact?: string | string[];\n ideal?: string | string[];\n}\ntype ConstrainBoolean = boolean | ConstrainBooleanParameters;\ninterface ConstrainBooleanParameters {\n exact?: boolean;\n ideal?: boolean;\n}\ntype ConstrainULong = number | ConstrainULongRange;\ninterface ConstrainULongRange extends ULongRange {\n exact?: number;\n ideal?: number;\n}\ninterface ULongRange {\n max?: number;\n min?: number;\n}\ntype ConstrainDouble = number | ConstrainDoubleRange;\ninterface ConstrainDoubleRange extends DoubleRange {\n exact?: number;\n ideal?: number;\n}\ninterface DoubleRange {\n max?: number;\n min?: number;\n}\n\nexport const navigator = new Navigator();\n"]}
1
+ {"version":3,"file":"navigator.js","sourceRoot":"","sources":["../../../../src/nonstandard/navigator.ts"],"names":[],"mappings":"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","sourcesContent":["import { createSocket } from \"dgram\";\nimport { RTCRtpCodecParameters } from \"..\";\nimport { MediaStream, MediaStreamTrack } from \"../media/track\";\nimport {\n type DummyAudioOptions,\n type DummyVideoOptions,\n createDummyAudioTrack,\n createDummyVideoTrack,\n} from \"./dummyMedia\";\n\nexport class Navigator {\n mediaDevices: MediaDevices;\n\n constructor(props: ConstructorParameters<typeof MediaDevices>[0] = {}) {\n this.mediaDevices = new MediaDevices(props);\n }\n}\n\nexport class MediaDevices extends EventTarget {\n video?: MediaStreamTrack;\n audio?: MediaStreamTrack;\n private readonly activeSourceStops = new Map<MediaStreamTrack, () => void>();\n\n constructor(readonly props: MediaDeviceProps = {}) {\n super();\n this.video = props.video;\n this.audio = props.audio;\n }\n\n readonly getUserMedia = async (\n constraints: MediaStreamConstraints,\n ): Promise<MediaStream> => {\n const tracks = [\n ...(constraints.audio\n ? [this.createTrack(\"audio\", constraints.audio)]\n : []),\n ...(constraints.video\n ? [this.createTrack(\"video\", constraints.video)]\n : []),\n ];\n\n if (tracks.length === 0) {\n throw new Error(\"At least one audio or video track is required\");\n }\n\n return new MediaStream(tracks);\n };\n\n readonly getDisplayMedia = this.getUserMedia;\n\n readonly getUdpMedia = ({\n port,\n codec,\n }: {\n port: number;\n codec: ConstructorParameters<typeof RTCRtpCodecParameters>[0];\n }) => {\n const kind = codec.mimeType.toLowerCase().includes(\"video\")\n ? \"video\"\n : \"audio\";\n const track = new MediaStreamTrack({\n kind,\n codec: new RTCRtpCodecParameters(codec),\n });\n\n const udp = createSocket(\"udp4\");\n udp.bind(port);\n udp.on(\"message\", (data) => {\n track.writeRtp(data);\n });\n\n const disposer = () => {\n udp.close();\n };\n\n return { track, disposer };\n };\n\n cleanup() {\n for (const stop of this.activeSourceStops.values()) {\n stop();\n }\n this.activeSourceStops.clear();\n }\n\n private createTrack(\n kind: \"audio\" | \"video\",\n constraints: boolean | MediaTrackConstraints,\n ) {\n const existingTrack = kind === \"audio\" ? this.audio : this.video;\n if (existingTrack) {\n return this.createClonedTrack(kind, existingTrack);\n }\n if (this.props.dummyMedia?.enabled) {\n return this.createDummyTrack(kind, constraints);\n }\n throw new Error(`No ${kind} source configured for getUserMedia`);\n }\n\n private createClonedTrack(\n kind: \"audio\" | \"video\",\n sourceTrack: MediaStreamTrack,\n ) {\n const track = new MediaStreamTrack({ kind });\n const { unSubscribe } = sourceTrack.onReceiveRtp.subscribe((rtp) => {\n track.onReceiveRtp.execute(rtp.clone());\n });\n this.attachTrackStop(track, () => {\n unSubscribe();\n });\n return track;\n }\n\n private createDummyTrack(\n kind: \"audio\" | \"video\",\n constraints: boolean | MediaTrackConstraints,\n ) {\n const dummy =\n kind === \"audio\"\n ? createDummyAudioTrack(this.props.dummyMedia?.audio)\n : createDummyVideoTrack({\n ...this.props.dummyMedia?.video,\n ...resolveVideoOptions(constraints),\n });\n\n this.attachTrackStop(dummy.track, () => {\n dummy.source.stop();\n });\n\n return dummy.track;\n }\n\n private attachTrackStop(track: MediaStreamTrack, stop: () => void) {\n let disposed = false;\n const originalStop = track.stop;\n const dispose = () => {\n if (disposed) {\n return;\n }\n disposed = true;\n stop();\n this.activeSourceStops.delete(track);\n };\n\n track.stop = () => {\n dispose();\n originalStop();\n };\n\n this.activeSourceStops.set(track, dispose);\n }\n}\n\ninterface MediaDeviceProps {\n video?: MediaStreamTrack;\n audio?: MediaStreamTrack;\n dummyMedia?: {\n enabled: boolean;\n audio?: Partial<DummyAudioOptions>;\n video?: Partial<DummyVideoOptions>;\n };\n}\n\ninterface MediaStreamConstraints {\n audio?: boolean | MediaTrackConstraints;\n peerIdentity?: string;\n preferCurrentTab?: boolean;\n video?: boolean | MediaTrackConstraints;\n}\n\ninterface MediaTrackConstraints extends MediaTrackConstraintSet {\n advanced?: MediaTrackConstraintSet[];\n}\n\ninterface MediaTrackConstraintSet {\n aspectRatio?: ConstrainDouble;\n autoGainControl?: ConstrainBoolean;\n channelCount?: ConstrainULong;\n deviceId?: ConstrainDOMString;\n displaySurface?: ConstrainDOMString;\n echoCancellation?: ConstrainBoolean;\n facingMode?: ConstrainDOMString;\n frameRate?: ConstrainDouble;\n groupId?: ConstrainDOMString;\n height?: ConstrainULong;\n noiseSuppression?: ConstrainBoolean;\n sampleRate?: ConstrainULong;\n sampleSize?: ConstrainULong;\n width?: ConstrainULong;\n}\n\ntype ConstrainDOMString = string | string[] | ConstrainDOMStringParameters;\ninterface ConstrainDOMStringParameters {\n exact?: string | string[];\n ideal?: string | string[];\n}\ntype ConstrainBoolean = boolean | ConstrainBooleanParameters;\ninterface ConstrainBooleanParameters {\n exact?: boolean;\n ideal?: boolean;\n}\ntype ConstrainULong = number | ConstrainULongRange;\ninterface ConstrainULongRange extends ULongRange {\n exact?: number;\n ideal?: number;\n}\ninterface ULongRange {\n max?: number;\n min?: number;\n}\ntype ConstrainDouble = number | ConstrainDoubleRange;\ninterface ConstrainDoubleRange extends DoubleRange {\n exact?: number;\n ideal?: number;\n}\ninterface DoubleRange {\n max?: number;\n min?: number;\n}\n\nexport const navigator = new Navigator();\n\nfunction resolveVideoOptions(\n constraints: boolean | MediaTrackConstraints,\n): Partial<DummyVideoOptions> {\n if (typeof constraints === \"boolean\") {\n return {};\n }\n\n const fps = resolveConstrainNumber(constraints.frameRate);\n if (!fps) {\n return {};\n }\n\n return {\n fps,\n keyframeIntervalFrames: Math.max(1, Math.round(fps)),\n };\n}\n\nfunction resolveConstrainNumber(\n value?: ConstrainDouble | ConstrainULong,\n): number | undefined {\n if (typeof value === \"number\") {\n return value;\n }\n if (!value || typeof value !== \"object\") {\n return;\n }\n return value.exact ?? value.ideal ?? value.max ?? value.min;\n}\n"]}
@@ -0,0 +1,16 @@
1
+ import { RtpPacket } from "../../imports/rtp";
2
+ import type { RTCRtpCodecParameters } from "../../media/parameters";
3
+ import type { EncodedPacket } from "mediabunny";
4
+ export declare const supportedSourceCodecs: readonly ["avc", "vp8", "vp9", "av1", "opus"];
5
+ export type SupportedSourceCodec = (typeof supportedSourceCodecs)[number];
6
+ type SupportedMimeType = "video/h264" | "video/vp8" | "video/vp9" | "video/av1x" | "audio/opus";
7
+ export interface Packetizer {
8
+ packetize(packet: EncodedPacket, rtpTimestamp: number): RtpPacket[];
9
+ }
10
+ export declare function toSupportedMimeType(codec: SupportedSourceCodec): SupportedMimeType;
11
+ export declare function createPacketizer({ codec, sourceCodec, decoderDescription, }: {
12
+ codec: RTCRtpCodecParameters;
13
+ sourceCodec: SupportedSourceCodec;
14
+ decoderDescription?: ArrayBuffer | ArrayBufferView | null;
15
+ }): Packetizer;
16
+ export {};
@@ -0,0 +1,360 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.supportedSourceCodecs = void 0;
4
+ exports.toSupportedMimeType = toSupportedMimeType;
5
+ exports.createPacketizer = createPacketizer;
6
+ const rtp_1 = require("../../imports/rtp");
7
+ const rtpExtra_1 = require("../../imports/rtpExtra");
8
+ const DEFAULT_MAX_RTP_PAYLOAD_SIZE = 1200;
9
+ exports.supportedSourceCodecs = [
10
+ "avc",
11
+ "vp8",
12
+ "vp9",
13
+ "av1",
14
+ "opus",
15
+ ];
16
+ function toSupportedMimeType(codec) {
17
+ switch (codec) {
18
+ case "avc":
19
+ return "video/h264";
20
+ case "vp8":
21
+ return "video/vp8";
22
+ case "vp9":
23
+ return "video/vp9";
24
+ case "av1":
25
+ return "video/av1x";
26
+ case "opus":
27
+ return "audio/opus";
28
+ }
29
+ }
30
+ function createPacketizer({ codec, sourceCodec, decoderDescription, }) {
31
+ switch (sourceCodec) {
32
+ case "avc":
33
+ return new H264Packetizer(codec, decoderDescription ?? null);
34
+ case "vp8":
35
+ return new Vp8Packetizer(codec);
36
+ case "vp9":
37
+ return new Vp9Packetizer(codec);
38
+ case "av1":
39
+ return new Av1Packetizer(codec);
40
+ case "opus":
41
+ return new OpusPacketizer(codec);
42
+ }
43
+ }
44
+ class BasePacketizer {
45
+ constructor(codec, maxPayloadSize = DEFAULT_MAX_RTP_PAYLOAD_SIZE) {
46
+ Object.defineProperty(this, "codec", {
47
+ enumerable: true,
48
+ configurable: true,
49
+ writable: true,
50
+ value: codec
51
+ });
52
+ Object.defineProperty(this, "maxPayloadSize", {
53
+ enumerable: true,
54
+ configurable: true,
55
+ writable: true,
56
+ value: maxPayloadSize
57
+ });
58
+ Object.defineProperty(this, "sequenceNumber", {
59
+ enumerable: true,
60
+ configurable: true,
61
+ writable: true,
62
+ value: (0, rtp_1.random16)()
63
+ });
64
+ }
65
+ buildPacket(payload, timestamp, marker) {
66
+ const packet = new rtp_1.RtpPacket(new rtp_1.RtpHeader({
67
+ payloadType: this.codec.payloadType ?? 96,
68
+ sequenceNumber: this.sequenceNumber,
69
+ timestamp,
70
+ marker,
71
+ }), payload);
72
+ this.sequenceNumber = (this.sequenceNumber + 1) & 0xffff;
73
+ return packet;
74
+ }
75
+ }
76
+ class OpusPacketizer extends BasePacketizer {
77
+ packetize(packet, rtpTimestamp) {
78
+ return [this.buildPacket(toBuffer(packet.data), rtpTimestamp, true)];
79
+ }
80
+ }
81
+ class Vp8Packetizer extends BasePacketizer {
82
+ packetize(packet, rtpTimestamp) {
83
+ const frame = toBuffer(packet.data);
84
+ const chunkSize = this.maxPayloadSize - 1;
85
+ if (chunkSize <= 0) {
86
+ throw new Error("invalid VP8 RTP payload size");
87
+ }
88
+ const packets = [];
89
+ for (let offset = 0; offset < frame.length; offset += chunkSize) {
90
+ const chunk = frame.subarray(offset, Math.min(frame.length, offset + chunkSize));
91
+ const descriptor = Buffer.from([offset === 0 ? 0x10 : 0x00]);
92
+ packets.push(this.buildPacket(Buffer.concat([descriptor, chunk]), rtpTimestamp, offset + chunk.length >= frame.length));
93
+ }
94
+ return packets;
95
+ }
96
+ }
97
+ class Vp9Packetizer extends BasePacketizer {
98
+ packetize(packet, rtpTimestamp) {
99
+ const frame = toBuffer(packet.data);
100
+ const chunkSize = this.maxPayloadSize - 1;
101
+ if (chunkSize <= 0) {
102
+ throw new Error("invalid VP9 RTP payload size");
103
+ }
104
+ const packets = [];
105
+ for (let offset = 0; offset < frame.length; offset += chunkSize) {
106
+ const chunk = frame.subarray(offset, Math.min(frame.length, offset + chunkSize));
107
+ const descriptor = new rtp_1.BitWriter(8)
108
+ .set(1, 0, 0)
109
+ .set(1, 1, packet.type === "delta" ? 1 : 0)
110
+ .set(1, 2, 0)
111
+ .set(1, 3, 0)
112
+ .set(1, 4, offset === 0 ? 1 : 0)
113
+ .set(1, 5, offset + chunk.length >= frame.length ? 1 : 0)
114
+ .set(1, 6, 0)
115
+ .set(1, 7, 0).buffer;
116
+ packets.push(this.buildPacket(Buffer.concat([descriptor, chunk]), rtpTimestamp, offset + chunk.length >= frame.length));
117
+ }
118
+ return packets;
119
+ }
120
+ }
121
+ class Av1Packetizer extends BasePacketizer {
122
+ packetize(packet, rtpTimestamp) {
123
+ const obus = splitAv1Obus(toBuffer(packet.data));
124
+ const packets = [];
125
+ const fragmentSize = this.maxPayloadSize - 1;
126
+ if (fragmentSize <= 0) {
127
+ throw new Error("invalid AV1 RTP payload size");
128
+ }
129
+ let firstPacketInFrame = true;
130
+ const startsNewCodedVideoSequence = packet.type === "key";
131
+ for (const obu of obus) {
132
+ if (obu.length <= fragmentSize) {
133
+ const aggregationHeader = createAv1AggregationHeader({
134
+ startsWithFragment: false,
135
+ endsWithFragment: false,
136
+ startsNewCodedVideoSequence: firstPacketInFrame && startsNewCodedVideoSequence,
137
+ });
138
+ packets.push(this.buildPacket(Buffer.concat([aggregationHeader, obu]), rtpTimestamp, false));
139
+ firstPacketInFrame = false;
140
+ continue;
141
+ }
142
+ for (let offset = 0; offset < obu.length; offset += fragmentSize) {
143
+ const chunk = obu.subarray(offset, Math.min(obu.length, offset + fragmentSize));
144
+ const aggregationHeader = createAv1AggregationHeader({
145
+ startsWithFragment: offset > 0,
146
+ endsWithFragment: offset + chunk.length < obu.length,
147
+ startsNewCodedVideoSequence: firstPacketInFrame && startsNewCodedVideoSequence,
148
+ });
149
+ packets.push(this.buildPacket(Buffer.concat([aggregationHeader, chunk]), rtpTimestamp, false));
150
+ firstPacketInFrame = false;
151
+ }
152
+ }
153
+ if (packets.length === 0) {
154
+ throw new Error("AV1 sample did not contain any OBU data");
155
+ }
156
+ packets.at(-1).header.marker = true;
157
+ return packets;
158
+ }
159
+ }
160
+ class H264Packetizer extends BasePacketizer {
161
+ constructor(codec, decoderDescription) {
162
+ super(codec);
163
+ Object.defineProperty(this, "naluLengthSize", {
164
+ enumerable: true,
165
+ configurable: true,
166
+ writable: true,
167
+ value: void 0
168
+ });
169
+ Object.defineProperty(this, "parameterSets", {
170
+ enumerable: true,
171
+ configurable: true,
172
+ writable: true,
173
+ value: void 0
174
+ });
175
+ const packetizationMode = getH264PacketizationMode(codec.parameters);
176
+ if (packetizationMode !== 1) {
177
+ throw new Error(`Unsupported H264 packetization-mode=${packetizationMode}. File playback requires packetization-mode=1.`);
178
+ }
179
+ const avcConfig = parseAvcDecoderConfiguration(decoderDescription);
180
+ this.naluLengthSize = avcConfig?.naluLengthSize ?? 4;
181
+ this.parameterSets = avcConfig
182
+ ? [...avcConfig.sps.map(Buffer.from), ...avcConfig.pps.map(Buffer.from)]
183
+ : [];
184
+ }
185
+ packetize(packet, rtpTimestamp) {
186
+ let nalUnits = splitH264Sample(toBuffer(packet.data), this.naluLengthSize);
187
+ if (packet.type === "key" &&
188
+ this.parameterSets.length > 0 &&
189
+ !containsH264ParameterSets(nalUnits)) {
190
+ nalUnits = [...this.parameterSets, ...nalUnits];
191
+ }
192
+ const packets = [];
193
+ nalUnits.forEach((nalUnit, index) => {
194
+ const marker = index === nalUnits.length - 1;
195
+ if (nalUnit.length <= this.maxPayloadSize) {
196
+ packets.push(this.buildPacket(nalUnit, rtpTimestamp, marker));
197
+ return;
198
+ }
199
+ const nalHeader = nalUnit[0];
200
+ const fragmentPayload = nalUnit.subarray(1);
201
+ const fragmentSize = this.maxPayloadSize - 2;
202
+ if (fragmentSize <= 0) {
203
+ throw new Error("invalid H264 RTP payload size");
204
+ }
205
+ const fuIndicator = (nalHeader & 0xe0) | 28;
206
+ const nalType = nalHeader & 0x1f;
207
+ for (let offset = 0; offset < fragmentPayload.length; offset += fragmentSize) {
208
+ const chunk = fragmentPayload.subarray(offset, Math.min(fragmentPayload.length, offset + fragmentSize));
209
+ const fuHeader = Buffer.from([
210
+ (offset === 0 ? 0x80 : 0x00) |
211
+ (offset + chunk.length >= fragmentPayload.length ? 0x40 : 0x00) |
212
+ nalType,
213
+ ]);
214
+ packets.push(this.buildPacket(Buffer.concat([Buffer.from([fuIndicator]), fuHeader, chunk]), rtpTimestamp, marker && offset + chunk.length >= fragmentPayload.length));
215
+ }
216
+ });
217
+ return packets;
218
+ }
219
+ }
220
+ function createAv1AggregationHeader({ startsWithFragment, endsWithFragment, startsNewCodedVideoSequence, }) {
221
+ return new rtp_1.BitWriter(8)
222
+ .set(1, 0, startsWithFragment ? 1 : 0)
223
+ .set(1, 1, endsWithFragment ? 1 : 0)
224
+ .set(2, 2, 1)
225
+ .set(1, 4, startsNewCodedVideoSequence ? 1 : 0)
226
+ .set(3, 5, 0).buffer;
227
+ }
228
+ function parseAvcDecoderConfiguration(decoderDescription) {
229
+ if (!decoderDescription) {
230
+ return null;
231
+ }
232
+ const description = toDescriptionBuffer(decoderDescription);
233
+ if (description.length < 7) {
234
+ throw new Error("invalid H264 decoder configuration");
235
+ }
236
+ const naluLengthSize = (description[4] & 0x03) + 1;
237
+ const spsCount = description[5] & 0x1f;
238
+ let offset = 6;
239
+ const sps = [];
240
+ for (let index = 0; index < spsCount; index++) {
241
+ const length = description.readUInt16BE(offset);
242
+ offset += 2;
243
+ sps.push(description.subarray(offset, offset + length));
244
+ offset += length;
245
+ }
246
+ const ppsCount = description[offset] ?? 0;
247
+ offset++;
248
+ const pps = [];
249
+ for (let index = 0; index < ppsCount; index++) {
250
+ const length = description.readUInt16BE(offset);
251
+ offset += 2;
252
+ pps.push(description.subarray(offset, offset + length));
253
+ offset += length;
254
+ }
255
+ return { naluLengthSize, sps, pps };
256
+ }
257
+ function splitH264Sample(sample, naluLengthSize) {
258
+ if (looksLikeAnnexB(sample)) {
259
+ const nalUnits = [];
260
+ const parser = new rtpExtra_1.H264AnnexBParser(sample);
261
+ let payload = parser.readNextNaluPayload();
262
+ while (payload) {
263
+ nalUnits.push(Buffer.from(payload.data));
264
+ payload = parser.readNextNaluPayload();
265
+ }
266
+ return nalUnits;
267
+ }
268
+ const nalUnits = [];
269
+ let offset = 0;
270
+ while (offset < sample.length) {
271
+ const length = readUintLength(sample, offset, naluLengthSize);
272
+ offset += naluLengthSize;
273
+ const end = offset + length;
274
+ if (end > sample.length) {
275
+ throw new Error("invalid H264 sample length");
276
+ }
277
+ nalUnits.push(sample.subarray(offset, end));
278
+ offset = end;
279
+ }
280
+ return nalUnits;
281
+ }
282
+ function splitAv1Obus(sample) {
283
+ const obus = [];
284
+ let offset = 0;
285
+ while (offset < sample.length) {
286
+ const start = offset;
287
+ const header = sample[offset];
288
+ offset += 1;
289
+ if (header == undefined) {
290
+ break;
291
+ }
292
+ const extensionFlag = (0, rtp_1.getBit)(header, 5);
293
+ const hasSizeField = (0, rtp_1.getBit)(header, 6);
294
+ if (extensionFlag) {
295
+ offset += 1;
296
+ }
297
+ if (!hasSizeField) {
298
+ obus.push(sample.subarray(start));
299
+ break;
300
+ }
301
+ const [obuSize, leb128Length] = (0, rtp_1.leb128decode)(sample.subarray(offset));
302
+ offset += leb128Length;
303
+ const end = offset + obuSize;
304
+ if (end > sample.length) {
305
+ throw new Error("invalid AV1 OBU size");
306
+ }
307
+ obus.push(sample.subarray(start, end));
308
+ offset = end;
309
+ }
310
+ return obus;
311
+ }
312
+ function containsH264ParameterSets(nalUnits) {
313
+ return nalUnits.some((nalUnit) => {
314
+ const nalType = nalUnit[0] & 0x1f;
315
+ return nalType === 7 || nalType === 8;
316
+ });
317
+ }
318
+ function looksLikeAnnexB(sample) {
319
+ return (sample.length >= 4 &&
320
+ sample[0] === 0x00 &&
321
+ sample[1] === 0x00 &&
322
+ ((sample[2] === 0x00 && sample[3] === 0x01) || sample[2] === 0x01));
323
+ }
324
+ function readUintLength(buffer, offset, length) {
325
+ switch (length) {
326
+ case 1:
327
+ return buffer.readUInt8(offset);
328
+ case 2:
329
+ return buffer.readUInt16BE(offset);
330
+ case 3:
331
+ return buffer.readUIntBE(offset, 3);
332
+ case 4:
333
+ return buffer.readUInt32BE(offset);
334
+ default:
335
+ throw new Error(`unsupported H264 NALU length size: ${length}`);
336
+ }
337
+ }
338
+ function getH264PacketizationMode(parameters) {
339
+ if (!parameters) {
340
+ return 1;
341
+ }
342
+ const packetizationMode = parameters
343
+ .split(";")
344
+ .map((part) => part.trim())
345
+ .find((part) => part.startsWith("packetization-mode="));
346
+ if (!packetizationMode) {
347
+ return 1;
348
+ }
349
+ return Number(packetizationMode.split("=")[1] ?? 1);
350
+ }
351
+ function toDescriptionBuffer(decoderDescription) {
352
+ if (ArrayBuffer.isView(decoderDescription)) {
353
+ return Buffer.from(decoderDescription.buffer, decoderDescription.byteOffset, decoderDescription.byteLength);
354
+ }
355
+ return Buffer.from(decoderDescription);
356
+ }
357
+ function toBuffer(data) {
358
+ return Buffer.from(data.buffer, data.byteOffset, data.byteLength);
359
+ }
360
+ //# sourceMappingURL=packetizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"packetizer.js","sourceRoot":"","sources":["../../../../../src/nonstandard/userMedia/packetizer.ts"],"names":[],"mappings":";;;AAmCA,kDAeC;AAED,4CAqBC;AAzED,2CAO2B;AAC3B,qDAA0D;AAK1D,MAAM,4BAA4B,GAAG,IAAK,CAAC;AAE9B,QAAA,qBAAqB,GAAG;IACnC,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,MAAM;CACE,CAAC;AAcX,SAAgB,mBAAmB,CACjC,KAA2B;IAE3B,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,KAAK;YACR,OAAO,YAAY,CAAC;QACtB,KAAK,KAAK;YACR,OAAO,WAAW,CAAC;QACrB,KAAK,KAAK;YACR,OAAO,WAAW,CAAC;QACrB,KAAK,KAAK;YACR,OAAO,YAAY,CAAC;QACtB,KAAK,MAAM;YACT,OAAO,YAAY,CAAC;IACxB,CAAC;AACH,CAAC;AAED,SAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,WAAW,EACX,kBAAkB,GAKnB;IACC,QAAQ,WAAW,EAAE,CAAC;QACpB,KAAK,KAAK;YACR,OAAO,IAAI,cAAc,CAAC,KAAK,EAAE,kBAAkB,IAAI,IAAI,CAAC,CAAC;QAC/D,KAAK,KAAK;YACR,OAAO,IAAI,aAAa,CAAC,KAAK,CAAC,CAAC;QAClC,KAAK,KAAK;YACR,OAAO,IAAI,aAAa,CAAC,KAAK,CAAC,CAAC;QAClC,KAAK,KAAK;YACR,OAAO,IAAI,aAAa,CAAC,KAAK,CAAC,CAAC;QAClC,KAAK,MAAM;YACT,OAAO,IAAI,cAAc,CAAC,KAAK,CAAC,CAAC;IACrC,CAAC;AACH,CAAC;AAED,MAAe,cAAc;IAG3B,YACqB,KAA4B,EAC5B,iBAAiB,4BAA4B;QADhE;;;;mBAAmB,KAAK;WAAuB;QAC/C;;;;mBAAmB,cAAc;WAA+B;QAJxD;;;;mBAAiB,IAAA,cAAQ,GAAE;WAAC;IAKnC,CAAC;IAIM,WAAW,CACnB,OAAe,EACf,SAAiB,EACjB,MAAe;QAEf,MAAM,MAAM,GAAG,IAAI,eAAS,CAC1B,IAAI,eAAS,CAAC;YACZ,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,IAAI,EAAE;YACzC,cAAc,EAAE,IAAI,CAAC,cAAc;YACnC,SAAS;YACT,MAAM;SACP,CAAC,EACF,OAAO,CACR,CAAC;QACF,IAAI,CAAC,cAAc,GAAG,CAAC,IAAI,CAAC,cAAc,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC;QACzD,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AAED,MAAM,cAAe,SAAQ,cAAc;IACzC,SAAS,CAAC,MAAqB,EAAE,YAAoB;QACnD,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,CAAC,CAAC;IACvE,CAAC;CACF;AAED,MAAM,aAAc,SAAQ,cAAc;IACxC,SAAS,CAAC,MAAqB,EAAE,YAAoB;QACnD,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,SAAS,GAAG,IAAI,CAAC,cAAc,GAAG,CAAC,CAAC;QAC1C,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAClD,CAAC;QAED,MAAM,OAAO,GAAgB,EAAE,CAAC;QAChC,KAAK,IAAI,MAAM,GAAG,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,MAAM,EAAE,MAAM,IAAI,SAAS,EAAE,CAAC;YAChE,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,CAC1B,MAAM,EACN,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAC3C,CAAC;YACF,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;YAC7D,OAAO,CAAC,IAAI,CACV,IAAI,CAAC,WAAW,CACd,MAAM,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,EAClC,YAAY,EACZ,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,CACtC,CACF,CAAC;QACJ,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;CACF;AAED,MAAM,aAAc,SAAQ,cAAc;IACxC,SAAS,CAAC,MAAqB,EAAE,YAAoB;QACnD,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,SAAS,GAAG,IAAI,CAAC,cAAc,GAAG,CAAC,CAAC;QAC1C,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAClD,CAAC;QAED,MAAM,OAAO,GAAgB,EAAE,CAAC;QAChC,KAAK,IAAI,MAAM,GAAG,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,MAAM,EAAE,MAAM,IAAI,SAAS,EAAE,CAAC;YAChE,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,CAC1B,MAAM,EACN,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAC3C,CAAC;YACF,MAAM,UAAU,GAAG,IAAI,eAAS,CAAC,CAAC,CAAC;iBAChC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;iBACZ,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;iBAC1C,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;iBACZ,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;iBACZ,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;iBAC/B,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;iBACxD,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;iBACZ,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;YACvB,OAAO,CAAC,IAAI,CACV,IAAI,CAAC,WAAW,CACd,MAAM,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,EAClC,YAAY,EACZ,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,CACtC,CACF,CAAC;QACJ,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;CACF;AAED,MAAM,aAAc,SAAQ,cAAc;IACxC,SAAS,CAAC,MAAqB,EAAE,YAAoB;QACnD,MAAM,IAAI,GAAG,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;QACjD,MAAM,OAAO,GAAgB,EAAE,CAAC;QAChC,MAAM,YAAY,GAAG,IAAI,CAAC,cAAc,GAAG,CAAC,CAAC;QAC7C,IAAI,YAAY,IAAI,CAAC,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAClD,CAAC;QAED,IAAI,kBAAkB,GAAG,IAAI,CAAC;QAC9B,MAAM,2BAA2B,GAAG,MAAM,CAAC,IAAI,KAAK,KAAK,CAAC;QAC1D,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,GAAG,CAAC,MAAM,IAAI,YAAY,EAAE,CAAC;gBAC/B,MAAM,iBAAiB,GAAG,0BAA0B,CAAC;oBACnD,kBAAkB,EAAE,KAAK;oBACzB,gBAAgB,EAAE,KAAK;oBACvB,2BAA2B,EACzB,kBAAkB,IAAI,2BAA2B;iBACpD,CAAC,CAAC;gBACH,OAAO,CAAC,IAAI,CACV,IAAI,CAAC,WAAW,CACd,MAAM,CAAC,MAAM,CAAC,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC,EACvC,YAAY,EACZ,KAAK,CACN,CACF,CAAC;gBACF,kBAAkB,GAAG,KAAK,CAAC;gBAC3B,SAAS;YACX,CAAC;YAED,KAAK,IAAI,MAAM,GAAG,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,IAAI,YAAY,EAAE,CAAC;gBACjE,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CACxB,MAAM,EACN,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,CAAC,CAC5C,CAAC;gBACF,MAAM,iBAAiB,GAAG,0BAA0B,CAAC;oBACnD,kBAAkB,EAAE,MAAM,GAAG,CAAC;oBAC9B,gBAAgB,EAAE,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM;oBACpD,2BAA2B,EACzB,kBAAkB,IAAI,2BAA2B;iBACpD,CAAC,CAAC;gBACH,OAAO,CAAC,IAAI,CACV,IAAI,CAAC,WAAW,CACd,MAAM,CAAC,MAAM,CAAC,CAAC,iBAAiB,EAAE,KAAK,CAAC,CAAC,EACzC,YAAY,EACZ,KAAK,CACN,CACF,CAAC;gBACF,kBAAkB,GAAG,KAAK,CAAC;YAC7B,CAAC;QACH,CAAC;QAED,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;QAC7D,CAAC;QAED,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAE,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC;QACrC,OAAO,OAAO,CAAC;IACjB,CAAC;CACF;AAED,MAAM,cAAe,SAAQ,cAAc;IAIzC,YACE,KAA4B,EAC5B,kBAAwD;QAExD,KAAK,CAAC,KAAK,CAAC,CAAC;QAPE;;;;;WAAuB;QACvB;;;;;WAAwB;QAQvC,MAAM,iBAAiB,GAAG,wBAAwB,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QACrE,IAAI,iBAAiB,KAAK,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CACb,uCAAuC,iBAAiB,gDAAgD,CACzG,CAAC;QACJ,CAAC;QAED,MAAM,SAAS,GAAG,4BAA4B,CAAC,kBAAkB,CAAC,CAAC;QACnE,IAAI,CAAC,cAAc,GAAG,SAAS,EAAE,cAAc,IAAI,CAAC,CAAC;QACrD,IAAI,CAAC,aAAa,GAAG,SAAS;YAC5B,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACxE,CAAC,CAAC,EAAE,CAAC;IACT,CAAC;IAED,SAAS,CAAC,MAAqB,EAAE,YAAoB;QACnD,IAAI,QAAQ,GAAG,eAAe,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;QAC3E,IACE,MAAM,CAAC,IAAI,KAAK,KAAK;YACrB,IAAI,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC;YAC7B,CAAC,yBAAyB,CAAC,QAAQ,CAAC,EACpC,CAAC;YACD,QAAQ,GAAG,CAAC,GAAG,IAAI,CAAC,aAAa,EAAE,GAAG,QAAQ,CAAC,CAAC;QAClD,CAAC;QAED,MAAM,OAAO,GAAgB,EAAE,CAAC;QAEhC,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE;YAClC,MAAM,MAAM,GAAG,KAAK,KAAK,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;YAC7C,IAAI,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;gBAC1C,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC;gBAC9D,OAAO;YACT,CAAC;YAED,MAAM,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;YAC7B,MAAM,eAAe,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YAC5C,MAAM,YAAY,GAAG,IAAI,CAAC,cAAc,GAAG,CAAC,CAAC;YAC7C,IAAI,YAAY,IAAI,CAAC,EAAE,CAAC;gBACtB,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;YACnD,CAAC;YAED,MAAM,WAAW,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC5C,MAAM,OAAO,GAAG,SAAS,GAAG,IAAI,CAAC;YAEjC,KACE,IAAI,MAAM,GAAG,CAAC,EACd,MAAM,GAAG,eAAe,CAAC,MAAM,EAC/B,MAAM,IAAI,YAAY,EACtB,CAAC;gBACD,MAAM,KAAK,GAAG,eAAe,CAAC,QAAQ,CACpC,MAAM,EACN,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,CAAC,CACxD,CAAC;gBACF,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC;oBAC3B,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;wBAC1B,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;wBAC/D,OAAO;iBACV,CAAC,CAAC;gBACH,OAAO,CAAC,IAAI,CACV,IAAI,CAAC,WAAW,CACd,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,EAC5D,YAAY,EACZ,MAAM,IAAI,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,eAAe,CAAC,MAAM,CAC1D,CACF,CAAC;YACJ,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,OAAO,OAAO,CAAC;IACjB,CAAC;CACF;AAED,SAAS,0BAA0B,CAAC,EAClC,kBAAkB,EAClB,gBAAgB,EAChB,2BAA2B,GAK5B;IACC,OAAO,IAAI,eAAS,CAAC,CAAC,CAAC;SACpB,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SACrC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SACnC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;SACZ,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,2BAA2B,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SAC9C,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;AACzB,CAAC;AAED,SAAS,4BAA4B,CACnC,kBAAwD;IAExD,IAAI,CAAC,kBAAkB,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,WAAW,GAAG,mBAAmB,CAAC,kBAAkB,CAAC,CAAC;IAC5D,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;IACxD,CAAC;IAED,MAAM,cAAc,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;IACnD,MAAM,QAAQ,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IACvC,IAAI,MAAM,GAAG,CAAC,CAAC;IAEf,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,QAAQ,EAAE,KAAK,EAAE,EAAE,CAAC;QAC9C,MAAM,MAAM,GAAG,WAAW,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QAChD,MAAM,IAAI,CAAC,CAAC;QACZ,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC;QACxD,MAAM,IAAI,MAAM,CAAC;IACnB,CAAC;IAED,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC1C,MAAM,EAAE,CAAC;IAET,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,QAAQ,EAAE,KAAK,EAAE,EAAE,CAAC;QAC9C,MAAM,MAAM,GAAG,WAAW,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QAChD,MAAM,IAAI,CAAC,CAAC;QACZ,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC;QACxD,MAAM,IAAI,MAAM,CAAC;IACnB,CAAC;IAED,OAAO,EAAE,cAAc,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AACtC,CAAC;AAED,SAAS,eAAe,CAAC,MAAc,EAAE,cAAsB;IAC7D,IAAI,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAG,IAAI,2BAAgB,CAAC,MAAM,CAAC,CAAC;QAC5C,IAAI,OAAO,GAAG,MAAM,CAAC,mBAAmB,EAAE,CAAC;QAC3C,OAAO,OAAO,EAAE,CAAC;YACf,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;YACzC,OAAO,GAAG,MAAM,CAAC,mBAAmB,EAAE,CAAC;QACzC,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,MAAM,GAAG,CAAC,CAAC;IAEf,OAAO,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAG,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,CAAC,CAAC;QAC9D,MAAM,IAAI,cAAc,CAAC;QACzB,MAAM,GAAG,GAAG,MAAM,GAAG,MAAM,CAAC;QAC5B,IAAI,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAChD,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;QAC5C,MAAM,GAAG,GAAG,CAAC;IACf,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,YAAY,CAAC,MAAc;IAClC,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,IAAI,MAAM,GAAG,CAAC,CAAC;IAEf,OAAO,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;QAC9B,MAAM,KAAK,GAAG,MAAM,CAAC;QACrB,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;QAC9B,MAAM,IAAI,CAAC,CAAC;QACZ,IAAI,MAAM,IAAI,SAAS,EAAE,CAAC;YACxB,MAAM;QACR,CAAC;QAED,MAAM,aAAa,GAAG,IAAA,YAAM,EAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACxC,MAAM,YAAY,GAAG,IAAA,YAAM,EAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACvC,IAAI,aAAa,EAAE,CAAC;YAClB,MAAM,IAAI,CAAC,CAAC;QACd,CAAC;QAED,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;YAClC,MAAM;QACR,CAAC;QAED,MAAM,CAAC,OAAO,EAAE,YAAY,CAAC,GAAG,IAAA,kBAAY,EAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;QACtE,MAAM,IAAI,YAAY,CAAC;QACvB,MAAM,GAAG,GAAG,MAAM,GAAG,OAAO,CAAC;QAC7B,IAAI,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;QAC1C,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;QACvC,MAAM,GAAG,GAAG,CAAC;IACf,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,yBAAyB,CAAC,QAAkB;IACnD,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE;QAC/B,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;QAClC,OAAO,OAAO,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,eAAe,CAAC,MAAc;IACrC,OAAO,CACL,MAAM,CAAC,MAAM,IAAI,CAAC;QAClB,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI;QAClB,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI;QAClB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CACnE,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,MAAc,EAAE,MAAc,EAAE,MAAc;IACpE,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,CAAC;YACJ,OAAO,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAClC,KAAK,CAAC;YACJ,OAAO,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QACrC,KAAK,CAAC;YACJ,OAAO,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACtC,KAAK,CAAC;YACJ,OAAO,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QACrC;YACE,MAAM,IAAI,KAAK,CAAC,sCAAsC,MAAM,EAAE,CAAC,CAAC;IACpE,CAAC;AACH,CAAC;AAED,SAAS,wBAAwB,CAAC,UAAmB;IACnD,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,iBAAiB,GAAG,UAAU;SACjC,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,qBAAqB,CAAC,CAAC,CAAC;IAE1D,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACvB,OAAO,CAAC,CAAC;IACX,CAAC;IAED,OAAO,MAAM,CAAC,iBAAiB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACtD,CAAC;AAED,SAAS,mBAAmB,CAC1B,kBAAiD;IAEjD,IAAI,WAAW,CAAC,MAAM,CAAC,kBAAkB,CAAC,EAAE,CAAC;QAC3C,OAAO,MAAM,CAAC,IAAI,CAChB,kBAAkB,CAAC,MAAM,EACzB,kBAAkB,CAAC,UAAU,EAC7B,kBAAkB,CAAC,UAAU,CAC9B,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;AACzC,CAAC;AAED,SAAS,QAAQ,CAAC,IAAgB;IAChC,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;AACpE,CAAC","sourcesContent":["import {\n BitWriter,\n RtpHeader,\n RtpPacket,\n getBit,\n leb128decode,\n random16,\n} from \"../../imports/rtp\";\nimport { H264AnnexBParser } from \"../../imports/rtpExtra\";\nimport type { RTCRtpCodecParameters } from \"../../media/parameters\";\n\nimport type { EncodedPacket } from \"mediabunny\";\n\nconst DEFAULT_MAX_RTP_PAYLOAD_SIZE = 1_200;\n\nexport const supportedSourceCodecs = [\n \"avc\",\n \"vp8\",\n \"vp9\",\n \"av1\",\n \"opus\",\n] as const;\nexport type SupportedSourceCodec = (typeof supportedSourceCodecs)[number];\n\ntype SupportedMimeType =\n | \"video/h264\"\n | \"video/vp8\"\n | \"video/vp9\"\n | \"video/av1x\"\n | \"audio/opus\";\n\nexport interface Packetizer {\n packetize(packet: EncodedPacket, rtpTimestamp: number): RtpPacket[];\n}\n\nexport function toSupportedMimeType(\n codec: SupportedSourceCodec,\n): SupportedMimeType {\n switch (codec) {\n case \"avc\":\n return \"video/h264\";\n case \"vp8\":\n return \"video/vp8\";\n case \"vp9\":\n return \"video/vp9\";\n case \"av1\":\n return \"video/av1x\";\n case \"opus\":\n return \"audio/opus\";\n }\n}\n\nexport function createPacketizer({\n codec,\n sourceCodec,\n decoderDescription,\n}: {\n codec: RTCRtpCodecParameters;\n sourceCodec: SupportedSourceCodec;\n decoderDescription?: ArrayBuffer | ArrayBufferView | null;\n}): Packetizer {\n switch (sourceCodec) {\n case \"avc\":\n return new H264Packetizer(codec, decoderDescription ?? null);\n case \"vp8\":\n return new Vp8Packetizer(codec);\n case \"vp9\":\n return new Vp9Packetizer(codec);\n case \"av1\":\n return new Av1Packetizer(codec);\n case \"opus\":\n return new OpusPacketizer(codec);\n }\n}\n\nabstract class BasePacketizer implements Packetizer {\n protected sequenceNumber = random16();\n\n constructor(\n protected readonly codec: RTCRtpCodecParameters,\n protected readonly maxPayloadSize = DEFAULT_MAX_RTP_PAYLOAD_SIZE,\n ) {}\n\n abstract packetize(packet: EncodedPacket, rtpTimestamp: number): RtpPacket[];\n\n protected buildPacket(\n payload: Buffer,\n timestamp: number,\n marker: boolean,\n ): RtpPacket {\n const packet = new RtpPacket(\n new RtpHeader({\n payloadType: this.codec.payloadType ?? 96,\n sequenceNumber: this.sequenceNumber,\n timestamp,\n marker,\n }),\n payload,\n );\n this.sequenceNumber = (this.sequenceNumber + 1) & 0xffff;\n return packet;\n }\n}\n\nclass OpusPacketizer extends BasePacketizer {\n packetize(packet: EncodedPacket, rtpTimestamp: number): RtpPacket[] {\n return [this.buildPacket(toBuffer(packet.data), rtpTimestamp, true)];\n }\n}\n\nclass Vp8Packetizer extends BasePacketizer {\n packetize(packet: EncodedPacket, rtpTimestamp: number): RtpPacket[] {\n const frame = toBuffer(packet.data);\n const chunkSize = this.maxPayloadSize - 1;\n if (chunkSize <= 0) {\n throw new Error(\"invalid VP8 RTP payload size\");\n }\n\n const packets: RtpPacket[] = [];\n for (let offset = 0; offset < frame.length; offset += chunkSize) {\n const chunk = frame.subarray(\n offset,\n Math.min(frame.length, offset + chunkSize),\n );\n const descriptor = Buffer.from([offset === 0 ? 0x10 : 0x00]);\n packets.push(\n this.buildPacket(\n Buffer.concat([descriptor, chunk]),\n rtpTimestamp,\n offset + chunk.length >= frame.length,\n ),\n );\n }\n return packets;\n }\n}\n\nclass Vp9Packetizer extends BasePacketizer {\n packetize(packet: EncodedPacket, rtpTimestamp: number): RtpPacket[] {\n const frame = toBuffer(packet.data);\n const chunkSize = this.maxPayloadSize - 1;\n if (chunkSize <= 0) {\n throw new Error(\"invalid VP9 RTP payload size\");\n }\n\n const packets: RtpPacket[] = [];\n for (let offset = 0; offset < frame.length; offset += chunkSize) {\n const chunk = frame.subarray(\n offset,\n Math.min(frame.length, offset + chunkSize),\n );\n const descriptor = new BitWriter(8)\n .set(1, 0, 0)\n .set(1, 1, packet.type === \"delta\" ? 1 : 0)\n .set(1, 2, 0)\n .set(1, 3, 0)\n .set(1, 4, offset === 0 ? 1 : 0)\n .set(1, 5, offset + chunk.length >= frame.length ? 1 : 0)\n .set(1, 6, 0)\n .set(1, 7, 0).buffer;\n packets.push(\n this.buildPacket(\n Buffer.concat([descriptor, chunk]),\n rtpTimestamp,\n offset + chunk.length >= frame.length,\n ),\n );\n }\n return packets;\n }\n}\n\nclass Av1Packetizer extends BasePacketizer {\n packetize(packet: EncodedPacket, rtpTimestamp: number): RtpPacket[] {\n const obus = splitAv1Obus(toBuffer(packet.data));\n const packets: RtpPacket[] = [];\n const fragmentSize = this.maxPayloadSize - 1;\n if (fragmentSize <= 0) {\n throw new Error(\"invalid AV1 RTP payload size\");\n }\n\n let firstPacketInFrame = true;\n const startsNewCodedVideoSequence = packet.type === \"key\";\n for (const obu of obus) {\n if (obu.length <= fragmentSize) {\n const aggregationHeader = createAv1AggregationHeader({\n startsWithFragment: false,\n endsWithFragment: false,\n startsNewCodedVideoSequence:\n firstPacketInFrame && startsNewCodedVideoSequence,\n });\n packets.push(\n this.buildPacket(\n Buffer.concat([aggregationHeader, obu]),\n rtpTimestamp,\n false,\n ),\n );\n firstPacketInFrame = false;\n continue;\n }\n\n for (let offset = 0; offset < obu.length; offset += fragmentSize) {\n const chunk = obu.subarray(\n offset,\n Math.min(obu.length, offset + fragmentSize),\n );\n const aggregationHeader = createAv1AggregationHeader({\n startsWithFragment: offset > 0,\n endsWithFragment: offset + chunk.length < obu.length,\n startsNewCodedVideoSequence:\n firstPacketInFrame && startsNewCodedVideoSequence,\n });\n packets.push(\n this.buildPacket(\n Buffer.concat([aggregationHeader, chunk]),\n rtpTimestamp,\n false,\n ),\n );\n firstPacketInFrame = false;\n }\n }\n\n if (packets.length === 0) {\n throw new Error(\"AV1 sample did not contain any OBU data\");\n }\n\n packets.at(-1)!.header.marker = true;\n return packets;\n }\n}\n\nclass H264Packetizer extends BasePacketizer {\n private readonly naluLengthSize: number;\n private readonly parameterSets: Buffer[];\n\n constructor(\n codec: RTCRtpCodecParameters,\n decoderDescription: ArrayBuffer | ArrayBufferView | null,\n ) {\n super(codec);\n\n const packetizationMode = getH264PacketizationMode(codec.parameters);\n if (packetizationMode !== 1) {\n throw new Error(\n `Unsupported H264 packetization-mode=${packetizationMode}. File playback requires packetization-mode=1.`,\n );\n }\n\n const avcConfig = parseAvcDecoderConfiguration(decoderDescription);\n this.naluLengthSize = avcConfig?.naluLengthSize ?? 4;\n this.parameterSets = avcConfig\n ? [...avcConfig.sps.map(Buffer.from), ...avcConfig.pps.map(Buffer.from)]\n : [];\n }\n\n packetize(packet: EncodedPacket, rtpTimestamp: number): RtpPacket[] {\n let nalUnits = splitH264Sample(toBuffer(packet.data), this.naluLengthSize);\n if (\n packet.type === \"key\" &&\n this.parameterSets.length > 0 &&\n !containsH264ParameterSets(nalUnits)\n ) {\n nalUnits = [...this.parameterSets, ...nalUnits];\n }\n\n const packets: RtpPacket[] = [];\n\n nalUnits.forEach((nalUnit, index) => {\n const marker = index === nalUnits.length - 1;\n if (nalUnit.length <= this.maxPayloadSize) {\n packets.push(this.buildPacket(nalUnit, rtpTimestamp, marker));\n return;\n }\n\n const nalHeader = nalUnit[0];\n const fragmentPayload = nalUnit.subarray(1);\n const fragmentSize = this.maxPayloadSize - 2;\n if (fragmentSize <= 0) {\n throw new Error(\"invalid H264 RTP payload size\");\n }\n\n const fuIndicator = (nalHeader & 0xe0) | 28;\n const nalType = nalHeader & 0x1f;\n\n for (\n let offset = 0;\n offset < fragmentPayload.length;\n offset += fragmentSize\n ) {\n const chunk = fragmentPayload.subarray(\n offset,\n Math.min(fragmentPayload.length, offset + fragmentSize),\n );\n const fuHeader = Buffer.from([\n (offset === 0 ? 0x80 : 0x00) |\n (offset + chunk.length >= fragmentPayload.length ? 0x40 : 0x00) |\n nalType,\n ]);\n packets.push(\n this.buildPacket(\n Buffer.concat([Buffer.from([fuIndicator]), fuHeader, chunk]),\n rtpTimestamp,\n marker && offset + chunk.length >= fragmentPayload.length,\n ),\n );\n }\n });\n\n return packets;\n }\n}\n\nfunction createAv1AggregationHeader({\n startsWithFragment,\n endsWithFragment,\n startsNewCodedVideoSequence,\n}: {\n startsWithFragment: boolean;\n endsWithFragment: boolean;\n startsNewCodedVideoSequence: boolean;\n}) {\n return new BitWriter(8)\n .set(1, 0, startsWithFragment ? 1 : 0)\n .set(1, 1, endsWithFragment ? 1 : 0)\n .set(2, 2, 1)\n .set(1, 4, startsNewCodedVideoSequence ? 1 : 0)\n .set(3, 5, 0).buffer;\n}\n\nfunction parseAvcDecoderConfiguration(\n decoderDescription: ArrayBuffer | ArrayBufferView | null,\n) {\n if (!decoderDescription) {\n return null;\n }\n\n const description = toDescriptionBuffer(decoderDescription);\n if (description.length < 7) {\n throw new Error(\"invalid H264 decoder configuration\");\n }\n\n const naluLengthSize = (description[4] & 0x03) + 1;\n const spsCount = description[5] & 0x1f;\n let offset = 6;\n\n const sps: Buffer[] = [];\n for (let index = 0; index < spsCount; index++) {\n const length = description.readUInt16BE(offset);\n offset += 2;\n sps.push(description.subarray(offset, offset + length));\n offset += length;\n }\n\n const ppsCount = description[offset] ?? 0;\n offset++;\n\n const pps: Buffer[] = [];\n for (let index = 0; index < ppsCount; index++) {\n const length = description.readUInt16BE(offset);\n offset += 2;\n pps.push(description.subarray(offset, offset + length));\n offset += length;\n }\n\n return { naluLengthSize, sps, pps };\n}\n\nfunction splitH264Sample(sample: Buffer, naluLengthSize: number) {\n if (looksLikeAnnexB(sample)) {\n const nalUnits: Buffer[] = [];\n const parser = new H264AnnexBParser(sample);\n let payload = parser.readNextNaluPayload();\n while (payload) {\n nalUnits.push(Buffer.from(payload.data));\n payload = parser.readNextNaluPayload();\n }\n return nalUnits;\n }\n\n const nalUnits: Buffer[] = [];\n let offset = 0;\n\n while (offset < sample.length) {\n const length = readUintLength(sample, offset, naluLengthSize);\n offset += naluLengthSize;\n const end = offset + length;\n if (end > sample.length) {\n throw new Error(\"invalid H264 sample length\");\n }\n nalUnits.push(sample.subarray(offset, end));\n offset = end;\n }\n\n return nalUnits;\n}\n\nfunction splitAv1Obus(sample: Buffer) {\n const obus: Buffer[] = [];\n let offset = 0;\n\n while (offset < sample.length) {\n const start = offset;\n const header = sample[offset];\n offset += 1;\n if (header == undefined) {\n break;\n }\n\n const extensionFlag = getBit(header, 5);\n const hasSizeField = getBit(header, 6);\n if (extensionFlag) {\n offset += 1;\n }\n\n if (!hasSizeField) {\n obus.push(sample.subarray(start));\n break;\n }\n\n const [obuSize, leb128Length] = leb128decode(sample.subarray(offset));\n offset += leb128Length;\n const end = offset + obuSize;\n if (end > sample.length) {\n throw new Error(\"invalid AV1 OBU size\");\n }\n obus.push(sample.subarray(start, end));\n offset = end;\n }\n\n return obus;\n}\n\nfunction containsH264ParameterSets(nalUnits: Buffer[]) {\n return nalUnits.some((nalUnit) => {\n const nalType = nalUnit[0] & 0x1f;\n return nalType === 7 || nalType === 8;\n });\n}\n\nfunction looksLikeAnnexB(sample: Buffer) {\n return (\n sample.length >= 4 &&\n sample[0] === 0x00 &&\n sample[1] === 0x00 &&\n ((sample[2] === 0x00 && sample[3] === 0x01) || sample[2] === 0x01)\n );\n}\n\nfunction readUintLength(buffer: Buffer, offset: number, length: number) {\n switch (length) {\n case 1:\n return buffer.readUInt8(offset);\n case 2:\n return buffer.readUInt16BE(offset);\n case 3:\n return buffer.readUIntBE(offset, 3);\n case 4:\n return buffer.readUInt32BE(offset);\n default:\n throw new Error(`unsupported H264 NALU length size: ${length}`);\n }\n}\n\nfunction getH264PacketizationMode(parameters?: string) {\n if (!parameters) {\n return 1;\n }\n\n const packetizationMode = parameters\n .split(\";\")\n .map((part) => part.trim())\n .find((part) => part.startsWith(\"packetization-mode=\"));\n\n if (!packetizationMode) {\n return 1;\n }\n\n return Number(packetizationMode.split(\"=\")[1] ?? 1);\n}\n\nfunction toDescriptionBuffer(\n decoderDescription: ArrayBuffer | ArrayBufferView,\n) {\n if (ArrayBuffer.isView(decoderDescription)) {\n return Buffer.from(\n decoderDescription.buffer,\n decoderDescription.byteOffset,\n decoderDescription.byteLength,\n );\n }\n\n return Buffer.from(decoderDescription);\n}\n\nfunction toBuffer(data: Uint8Array) {\n return Buffer.from(data.buffer, data.byteOffset, data.byteLength);\n}\n"]}