node-av 6.2.0-beta.1 → 6.2.0-beta.11

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 (84) hide show
  1. package/README.md +29 -0
  2. package/dist/api/audio-frame-buffer.d.ts +73 -1
  3. package/dist/api/audio-frame-buffer.js +127 -1
  4. package/dist/api/audio-frame-buffer.js.map +1 -1
  5. package/dist/api/bitstream-filter.d.ts +82 -4
  6. package/dist/api/bitstream-filter.js +197 -100
  7. package/dist/api/bitstream-filter.js.map +1 -1
  8. package/dist/api/decoder.d.ts +5 -0
  9. package/dist/api/decoder.js +12 -5
  10. package/dist/api/decoder.js.map +1 -1
  11. package/dist/api/demuxer.d.ts +15 -1
  12. package/dist/api/demuxer.js +159 -42
  13. package/dist/api/demuxer.js.map +1 -1
  14. package/dist/api/encoder-pool.d.ts +43 -1
  15. package/dist/api/encoder-pool.js +113 -9
  16. package/dist/api/encoder-pool.js.map +1 -1
  17. package/dist/api/encoder.d.ts +2 -0
  18. package/dist/api/encoder.js +105 -41
  19. package/dist/api/encoder.js.map +1 -1
  20. package/dist/api/filter.js +15 -6
  21. package/dist/api/filter.js.map +1 -1
  22. package/dist/api/fmp4-stream.d.ts +166 -3
  23. package/dist/api/fmp4-stream.js +404 -87
  24. package/dist/api/fmp4-stream.js.map +1 -1
  25. package/dist/api/hardware.js +4 -3
  26. package/dist/api/hardware.js.map +1 -1
  27. package/dist/api/io-stream.js +61 -5
  28. package/dist/api/io-stream.js.map +1 -1
  29. package/dist/api/muxer.d.ts +14 -0
  30. package/dist/api/muxer.js +102 -36
  31. package/dist/api/muxer.js.map +1 -1
  32. package/dist/api/pipeline.d.ts +2 -0
  33. package/dist/api/pipeline.js +23 -5
  34. package/dist/api/pipeline.js.map +1 -1
  35. package/dist/api/rtp-stream.d.ts +51 -6
  36. package/dist/api/rtp-stream.js +220 -76
  37. package/dist/api/rtp-stream.js.map +1 -1
  38. package/dist/api/scaler.d.ts +102 -16
  39. package/dist/api/scaler.js +316 -106
  40. package/dist/api/scaler.js.map +1 -1
  41. package/dist/api/utilities/async-queue.d.ts +3 -0
  42. package/dist/api/utilities/async-queue.js +8 -0
  43. package/dist/api/utilities/async-queue.js.map +1 -1
  44. package/dist/api/webrtc-stream.d.ts +2 -0
  45. package/dist/api/webrtc-stream.js +46 -12
  46. package/dist/api/webrtc-stream.js.map +1 -1
  47. package/dist/api/whisper.d.ts +2 -0
  48. package/dist/api/whisper.js +63 -23
  49. package/dist/api/whisper.js.map +1 -1
  50. package/dist/ffmpeg/install.js +115 -29
  51. package/dist/ffmpeg/install.js.map +1 -1
  52. package/dist/lib/binding.d.ts +1 -0
  53. package/dist/lib/binding.js.map +1 -1
  54. package/dist/lib/codec-context.d.ts +0 -2
  55. package/dist/lib/codec-context.js +4 -22
  56. package/dist/lib/codec-context.js.map +1 -1
  57. package/dist/lib/filter-context.d.ts +0 -1
  58. package/dist/lib/filter-context.js +2 -11
  59. package/dist/lib/filter-context.js.map +1 -1
  60. package/dist/lib/format-context.d.ts +47 -4
  61. package/dist/lib/format-context.js +52 -16
  62. package/dist/lib/format-context.js.map +1 -1
  63. package/dist/lib/frame.d.ts +12 -12
  64. package/dist/lib/frame.js +13 -20
  65. package/dist/lib/frame.js.map +1 -1
  66. package/dist/lib/hardware-frames-context.d.ts +0 -1
  67. package/dist/lib/hardware-frames-context.js +2 -8
  68. package/dist/lib/hardware-frames-context.js.map +1 -1
  69. package/dist/lib/io-context.d.ts +4 -2
  70. package/dist/lib/io-context.js +4 -2
  71. package/dist/lib/io-context.js.map +1 -1
  72. package/dist/lib/native-types.d.ts +2 -2
  73. package/dist/lib/option.d.ts +26 -0
  74. package/dist/lib/option.js +42 -18
  75. package/dist/lib/option.js.map +1 -1
  76. package/dist/lib/packet.d.ts +7 -1
  77. package/dist/lib/packet.js +9 -2
  78. package/dist/lib/packet.js.map +1 -1
  79. package/dist/lib/stream.d.ts +3 -4
  80. package/dist/lib/stream.js +17 -24
  81. package/dist/lib/stream.js.map +1 -1
  82. package/install/check.js +26 -63
  83. package/package.json +38 -21
  84. package/build_mac_local.sh +0 -69
package/README.md CHANGED
@@ -129,11 +129,33 @@ while (true) {
129
129
  console.log(`Decoded frame ${frame.pts}, size: ${frame.width}x${frame.height}`);
130
130
 
131
131
  // Process frame data...
132
+
133
+ frame.unref();
132
134
  }
133
135
  }
134
136
 
135
137
  packet.unref();
136
138
  }
139
+
140
+ // Flush the decoder - codecs buffer frames internally (B-frames, threading),
141
+ // so the last frames only come out after signaling EOF with a null packet.
142
+ ret = await decoderCtx.sendPacket(null);
143
+ if (ret < 0 && ret !== AVERROR_EOF) {
144
+ FFmpegError.throwIfError(ret, 'Failed to flush decoder');
145
+ }
146
+
147
+ while (true) {
148
+ const ret = await decoderCtx.receiveFrame(frame);
149
+ if (ret === AVERROR_EOF || ret < 0) {
150
+ break;
151
+ }
152
+
153
+ console.log(`Decoded frame ${frame.pts}, size: ${frame.width}x${frame.height}`);
154
+
155
+ // Process frame data...
156
+
157
+ frame.unref();
158
+ }
137
159
  ```
138
160
 
139
161
  ### High-Level API
@@ -505,6 +527,13 @@ The key difference: Async methods don't block the Node.js event loop, allowing o
505
527
 
506
528
  NodeAV provides direct bindings to FFmpeg's C APIs, which work with raw memory pointers. The high-level API adds safety abstractions and automatic resource management, but incorrect usage can still cause crashes. Common issues include mismatched video dimensions, incompatible pixel formats, or improper frame buffer handling. The library validates parameters where possible, but can't guarantee complete memory safety without limiting functionality. When using the low-level API, pay attention to parameter consistency, resource cleanup, and format compatibility. Following the documented patterns helps avoid memory-related issues.
507
529
 
530
+ ## Worker Threads and the libuv Thread Pool
531
+
532
+ NodeAV works inside `worker_threads`, with two caveats:
533
+
534
+ - **Prefer graceful shutdown over `worker.terminate()`.** Terminating a worker while native calls are in flight is mitigated (pending completions are dropped safely instead of aborting), but a termination that lands exactly inside a running synchronous native call can still abort the process — a limitation of Node-API error handling during isolate teardown. Signal the worker to close its NodeAV resources and exit on its own. For test runners, process isolation (e.g. vitest `pool: 'forks'`) is the most robust choice.
535
+ - **Async operations share the libuv thread pool** (default: 4 threads, process-wide across all workers). A custom IO read callback that never settles parks one pool thread until it resolves; enough of them stall every async NodeAV operation in the entire process. Make custom IO callbacks always settle (return `null` for EOF, throw on error), and raise `UV_THREADPOOL_SIZE` when running many parallel live inputs.
536
+
508
537
  ## Electron
509
538
 
510
539
  NodeAV fully supports Electron applications. The prebuilt binaries are ABI-compatible with Electron, so no native rebuild is required during packaging. Both the native bindings and the bundled FFmpeg CLI binaries work seamlessly within Electron's main process.
@@ -29,18 +29,25 @@ import type { ChannelLayout } from '../lib/types.js';
29
29
  * }
30
30
  * }
31
31
  *
32
- * // Flush remaining samples
32
+ * // Flush remaining samples (final partial frame is padded with silence)
33
33
  * let outputFrame;
34
34
  * while ((outputFrame = await buffer.pull()) !== null) {
35
35
  * await encoder.encode(outputFrame);
36
36
  * outputFrame.free();
37
37
  * }
38
+ * const tail = await buffer.pullPartial();
39
+ * if (tail) {
40
+ * await encoder.encode(tail);
41
+ * tail.free();
42
+ * }
38
43
  * ```
39
44
  */
40
45
  export declare class AudioFrameBuffer implements Disposable {
41
46
  private fifo;
42
47
  private frame;
43
48
  private frameSize;
49
+ private sampleFormat;
50
+ private channels;
44
51
  private nextPts;
45
52
  private firstFramePts;
46
53
  /**
@@ -184,6 +191,71 @@ export declare class AudioFrameBuffer implements Disposable {
184
191
  * @see {@link pull} For async version
185
192
  */
186
193
  pullSync(): Frame | null;
194
+ /**
195
+ * Pull the final partial frame from the buffer asynchronously.
196
+ *
197
+ * Reads the remaining samples (fewer than frameSize) and pads the tail with
198
+ * silence so the returned frame still carries exactly frameSize samples.
199
+ * Intended for end-of-stream flushing only - without it the tail (up to
200
+ * frameSize - 1 samples) would be dropped. Returns null if the buffer is
201
+ * empty, or while a complete frame is still available (drain those with
202
+ * pull() first).
203
+ *
204
+ * @returns Silence-padded audio frame with frameSize samples, or null if nothing to drain
205
+ *
206
+ * @throws {Error} If frame cloning fails (out of memory)
207
+ *
208
+ * @example
209
+ * ```typescript
210
+ * // At end of stream, after pull() has returned null
211
+ * using tail = await buffer.pullPartial();
212
+ * if (tail) {
213
+ * await encoder.encode(tail);
214
+ * }
215
+ * ```
216
+ *
217
+ * @see {@link pullPartialSync} For synchronous version
218
+ * @see {@link pull} For pulling complete frames
219
+ */
220
+ pullPartial(): Promise<Frame | null>;
221
+ /**
222
+ * Pull the final partial frame from the buffer synchronously.
223
+ * Synchronous version of pullPartial.
224
+ *
225
+ * Reads the remaining samples (fewer than frameSize) and pads the tail with
226
+ * silence so the returned frame still carries exactly frameSize samples.
227
+ * Intended for end-of-stream flushing only. Returns null if the buffer is
228
+ * empty, or while a complete frame is still available.
229
+ *
230
+ * @returns Silence-padded audio frame with frameSize samples, or null if nothing to drain
231
+ *
232
+ * @throws {Error} If frame cloning fails (out of memory)
233
+ *
234
+ * @example
235
+ * ```typescript
236
+ * // At end of stream, after pullSync() has returned null
237
+ * using tail = buffer.pullPartialSync();
238
+ * if (tail) {
239
+ * encoder.encodeSync(tail);
240
+ * }
241
+ * ```
242
+ *
243
+ * @see {@link pullPartial} For async version
244
+ * @see {@link pullSync} For pulling complete frames
245
+ */
246
+ pullPartialSync(): Frame | null;
247
+ /**
248
+ * Fill the reusable frame's sample range [fromSample, frameSize) with silence.
249
+ *
250
+ * Follows av_samples_set_silence() semantics: unsigned 8-bit formats use 0x80
251
+ * as the silence value, every other format uses 0. Planar frames carry one
252
+ * channel per plane; packed frames interleave all channels in plane 0.
253
+ *
254
+ * @param fromSample - First sample index to silence
255
+ *
256
+ * @internal
257
+ */
258
+ private padWithSilence;
187
259
  /**
188
260
  * Reset the buffer, discarding all buffered samples.
189
261
  *
@@ -1,5 +1,8 @@
1
+ import { AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_U8P } from '../constants/constants.js';
1
2
  import { AudioFifo } from '../lib/audio-fifo.js';
2
3
  import { Frame } from '../lib/frame.js';
4
+ import { Rational } from '../lib/rational.js';
5
+ import { avGetBytesPerSample, avSampleFmtIsPlanar } from '../lib/utilities.js';
3
6
  /**
4
7
  * Audio frame buffering utility for encoders with fixed frame size requirements.
5
8
  *
@@ -28,18 +31,25 @@ import { Frame } from '../lib/frame.js';
28
31
  * }
29
32
  * }
30
33
  *
31
- * // Flush remaining samples
34
+ * // Flush remaining samples (final partial frame is padded with silence)
32
35
  * let outputFrame;
33
36
  * while ((outputFrame = await buffer.pull()) !== null) {
34
37
  * await encoder.encode(outputFrame);
35
38
  * outputFrame.free();
36
39
  * }
40
+ * const tail = await buffer.pullPartial();
41
+ * if (tail) {
42
+ * await encoder.encode(tail);
43
+ * tail.free();
44
+ * }
37
45
  * ```
38
46
  */
39
47
  export class AudioFrameBuffer {
40
48
  fifo;
41
49
  frame;
42
50
  frameSize;
51
+ sampleFormat;
52
+ channels;
43
53
  nextPts = 0n;
44
54
  firstFramePts = null;
45
55
  /**
@@ -58,12 +68,17 @@ export class AudioFrameBuffer {
58
68
  constructor(fifo, frameSize, sampleFormat, sampleRate, channelLayout) {
59
69
  this.fifo = fifo;
60
70
  this.frameSize = frameSize;
71
+ this.sampleFormat = sampleFormat;
72
+ this.channels = channelLayout.nbChannels;
61
73
  this.frame = new Frame();
62
74
  this.frame.alloc();
63
75
  this.frame.nbSamples = frameSize;
64
76
  this.frame.format = sampleFormat;
65
77
  this.frame.sampleRate = sampleRate;
66
78
  this.frame.channelLayout = channelLayout;
79
+ // Output PTS is a running sample counter, so the matching timebase is
80
+ // 1/sample_rate; pulled frames go to the codec without further rescaling.
81
+ this.frame.timeBase = new Rational(1, sampleRate);
67
82
  this.frame.getBuffer(0); // Allocate buffer once
68
83
  }
69
84
  /**
@@ -258,6 +273,117 @@ export class AudioFrameBuffer {
258
273
  }
259
274
  return cloned;
260
275
  }
276
+ /**
277
+ * Pull the final partial frame from the buffer asynchronously.
278
+ *
279
+ * Reads the remaining samples (fewer than frameSize) and pads the tail with
280
+ * silence so the returned frame still carries exactly frameSize samples.
281
+ * Intended for end-of-stream flushing only - without it the tail (up to
282
+ * frameSize - 1 samples) would be dropped. Returns null if the buffer is
283
+ * empty, or while a complete frame is still available (drain those with
284
+ * pull() first).
285
+ *
286
+ * @returns Silence-padded audio frame with frameSize samples, or null if nothing to drain
287
+ *
288
+ * @throws {Error} If frame cloning fails (out of memory)
289
+ *
290
+ * @example
291
+ * ```typescript
292
+ * // At end of stream, after pull() has returned null
293
+ * using tail = await buffer.pullPartial();
294
+ * if (tail) {
295
+ * await encoder.encode(tail);
296
+ * }
297
+ * ```
298
+ *
299
+ * @see {@link pullPartialSync} For synchronous version
300
+ * @see {@link pull} For pulling complete frames
301
+ */
302
+ async pullPartial() {
303
+ const remaining = this.fifo.size;
304
+ if (remaining <= 0 || remaining >= this.frameSize) {
305
+ return null;
306
+ }
307
+ // Update PTS
308
+ this.frame.pts = this.nextPts;
309
+ // Read the remaining samples into the head of the reusable frame
310
+ await this.fifo.read(this.frame.data, remaining);
311
+ // Pad the tail with silence up to frameSize
312
+ this.padWithSilence(remaining);
313
+ // Update PTS for next frame
314
+ this.nextPts += BigInt(this.frameSize);
315
+ // Clone frame for user (like Decoder does)
316
+ const cloned = this.frame.clone();
317
+ if (!cloned) {
318
+ throw new Error('Failed to clone frame (out of memory)');
319
+ }
320
+ return cloned;
321
+ }
322
+ /**
323
+ * Pull the final partial frame from the buffer synchronously.
324
+ * Synchronous version of pullPartial.
325
+ *
326
+ * Reads the remaining samples (fewer than frameSize) and pads the tail with
327
+ * silence so the returned frame still carries exactly frameSize samples.
328
+ * Intended for end-of-stream flushing only. Returns null if the buffer is
329
+ * empty, or while a complete frame is still available.
330
+ *
331
+ * @returns Silence-padded audio frame with frameSize samples, or null if nothing to drain
332
+ *
333
+ * @throws {Error} If frame cloning fails (out of memory)
334
+ *
335
+ * @example
336
+ * ```typescript
337
+ * // At end of stream, after pullSync() has returned null
338
+ * using tail = buffer.pullPartialSync();
339
+ * if (tail) {
340
+ * encoder.encodeSync(tail);
341
+ * }
342
+ * ```
343
+ *
344
+ * @see {@link pullPartial} For async version
345
+ * @see {@link pullSync} For pulling complete frames
346
+ */
347
+ pullPartialSync() {
348
+ const remaining = this.fifo.size;
349
+ if (remaining <= 0 || remaining >= this.frameSize) {
350
+ return null;
351
+ }
352
+ // Update PTS
353
+ this.frame.pts = this.nextPts;
354
+ // Read the remaining samples into the head of the reusable frame
355
+ this.fifo.readSync(this.frame.data, remaining);
356
+ // Pad the tail with silence up to frameSize
357
+ this.padWithSilence(remaining);
358
+ // Update PTS for next frame
359
+ this.nextPts += BigInt(this.frameSize);
360
+ // Clone frame for user
361
+ const cloned = this.frame.clone();
362
+ if (!cloned) {
363
+ throw new Error('Failed to clone frame (out of memory)');
364
+ }
365
+ return cloned;
366
+ }
367
+ /**
368
+ * Fill the reusable frame's sample range [fromSample, frameSize) with silence.
369
+ *
370
+ * Follows av_samples_set_silence() semantics: unsigned 8-bit formats use 0x80
371
+ * as the silence value, every other format uses 0. Planar frames carry one
372
+ * channel per plane; packed frames interleave all channels in plane 0.
373
+ *
374
+ * @param fromSample - First sample index to silence
375
+ *
376
+ * @internal
377
+ */
378
+ padWithSilence(fromSample) {
379
+ const silence = this.sampleFormat === AV_SAMPLE_FMT_U8 || this.sampleFormat === AV_SAMPLE_FMT_U8P ? 0x80 : 0;
380
+ const bytesPerSample = avGetBytesPerSample(this.sampleFormat);
381
+ const stride = avSampleFmtIsPlanar(this.sampleFormat) ? bytesPerSample : bytesPerSample * this.channels;
382
+ const planes = this.frame.data ?? [];
383
+ for (const plane of planes) {
384
+ plane.fill(silence, fromSample * stride, this.frameSize * stride);
385
+ }
386
+ }
261
387
  /**
262
388
  * Reset the buffer, discarding all buffered samples.
263
389
  *
@@ -1 +1 @@
1
- {"version":3,"file":"audio-frame-buffer.js","sourceRoot":"","sources":["../../src/api/audio-frame-buffer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"audio-frame-buffer.js","sourceRoot":"","sources":["../../src/api/audio-frame-buffer.ts"],"names":[],"mappings":"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"}
@@ -72,6 +72,7 @@ export declare class BitStreamFilterAPI implements Disposable {
72
72
  private source;
73
73
  private initialized;
74
74
  private packet;
75
+ private pendingOutput;
75
76
  private isClosed;
76
77
  private inputQueue;
77
78
  private outputQueue;
@@ -526,8 +527,9 @@ export declare class BitStreamFilterAPI implements Disposable {
526
527
  * Sends null packet to filter to signal end-of-stream.
527
528
  * Does nothing if filter is closed.
528
529
  * Must call receive() or flushPackets() to get remaining buffered packets.
530
+ * Does not reset filter state - use {@link reset} for that.
529
531
  *
530
- * Direct mapping to av_bsf_send_packet(NULL) and av_bsf_flush().
532
+ * Direct mapping to av_bsf_send_packet(NULL).
531
533
  *
532
534
  * @throws {FFmpegError} If flush fails
533
535
  *
@@ -558,8 +560,9 @@ export declare class BitStreamFilterAPI implements Disposable {
558
560
  * Sends null packet to filter to signal end-of-stream.
559
561
  * Does nothing if filter is closed.
560
562
  * Must call receiveSync() or flushPacketsSync() to get remaining buffered packets.
563
+ * Does not reset filter state - use {@link reset} for that.
561
564
  *
562
- * Direct mapping to av_bsf_send_packet(NULL) and av_bsf_flush().
565
+ * Direct mapping to av_bsf_send_packet(NULL).
563
566
  *
564
567
  * @throws {FFmpegError} If flush fails
565
568
  *
@@ -734,7 +737,7 @@ export declare class BitStreamFilterAPI implements Disposable {
734
737
  * Synchronous version of flushPackets.
735
738
  *
736
739
  * Convenient sync iteration over remaining packets.
737
- * Automatically retrieves buffered packets after flush.
740
+ * Automatically sends flush signal and retrieves buffered packets.
738
741
  * Useful for end-of-stream processing.
739
742
  *
740
743
  * @yields {Packet} Buffered packets
@@ -768,7 +771,7 @@ export declare class BitStreamFilterAPI implements Disposable {
768
771
  * filter.reset();
769
772
  * ```
770
773
  *
771
- * @see {@link flush} For reset with packet retrieval
774
+ * @see {@link flush} For end-of-stream signaling with packet retrieval
772
775
  */
773
776
  reset(): void;
774
777
  /**
@@ -808,6 +811,81 @@ export declare class BitStreamFilterAPI implements Disposable {
808
811
  * @internal
809
812
  */
810
813
  private ensureInitialized;
814
+ /**
815
+ * Send a packet to the filter context, retrying once on EAGAIN.
816
+ *
817
+ * av_bsf_send_packet() returning EAGAIN means the packet was NOT consumed:
818
+ * the filter holds output that must be received before it accepts more
819
+ * input. That output is drained into pendingOutput (delivered by subsequent
820
+ * receive() calls in FIFO order) and the send is retried, mirroring how the
821
+ * FFmpeg CLI interleaves send/receive.
822
+ *
823
+ * @param packet - Packet to send, or null to signal EOF
824
+ *
825
+ * @throws {FFmpegError} If sending fails
826
+ *
827
+ * @internal
828
+ */
829
+ private sendPacketWithRetry;
830
+ /**
831
+ * Send a packet to the filter context, retrying once on EAGAIN.
832
+ * Synchronous version of sendPacketWithRetry.
833
+ *
834
+ * @param packet - Packet to send, or null to signal EOF
835
+ *
836
+ * @throws {FFmpegError} If sending fails
837
+ *
838
+ * @internal
839
+ */
840
+ private sendPacketWithRetrySync;
841
+ /**
842
+ * Receive one packet directly from the filter context.
843
+ *
844
+ * Bypasses pendingOutput so an EAGAIN drain can buffer packets without
845
+ * re-reading them.
846
+ *
847
+ * @returns Cloned packet or null if no packets available
848
+ *
849
+ * @throws {FFmpegError} If receive fails
850
+ *
851
+ * @throws {Error} If packet cloning fails (out of memory)
852
+ *
853
+ * @internal
854
+ */
855
+ private receiveFromContext;
856
+ /**
857
+ * Receive one packet directly from the filter context.
858
+ * Synchronous version of receiveFromContext.
859
+ *
860
+ * @returns Cloned packet or null if no packets available
861
+ *
862
+ * @throws {FFmpegError} If receive fails
863
+ *
864
+ * @throws {Error} If packet cloning fails (out of memory)
865
+ *
866
+ * @internal
867
+ */
868
+ private receiveFromContextSync;
869
+ /**
870
+ * Convert a receive return code into a cloned output packet.
871
+ *
872
+ * @param recvRet - Return code of av_bsf_receive_packet()
873
+ *
874
+ * @returns Cloned packet, or null on EAGAIN/EOF
875
+ *
876
+ * @throws {FFmpegError} If the return code is any other error
877
+ *
878
+ * @throws {Error} If packet cloning fails (out of memory)
879
+ *
880
+ * @internal
881
+ */
882
+ private consumeReceived;
883
+ /**
884
+ * Free and clear any packets buffered by an EAGAIN drain.
885
+ *
886
+ * @internal
887
+ */
888
+ private clearPendingOutput;
811
889
  /**
812
890
  * Send packet to input queue or flush the pipeline.
813
891
  *