node-av-lgpl 0.0.0 → 7.1.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +22 -0
- package/README.md +711 -0
- package/dist/api/audio-frame-buffer.d.ts +636 -0
- package/dist/api/audio-frame-buffer.js +1027 -0
- package/dist/api/audio-frame-buffer.js.map +1 -0
- package/dist/api/bitstream-filter.d.ts +938 -0
- package/dist/api/bitstream-filter.js +1427 -0
- package/dist/api/bitstream-filter.js.map +1 -0
- package/dist/api/constants.d.ts +44 -0
- package/dist/api/constants.js +45 -0
- package/dist/api/constants.js.map +1 -0
- package/dist/api/data/test_av1.ivf +0 -0
- package/dist/api/data/test_h264.h264 +0 -0
- package/dist/api/data/test_hevc.h265 +0 -0
- package/dist/api/data/test_mjpeg.mjpeg +0 -0
- package/dist/api/data/test_vp8.ivf +0 -0
- package/dist/api/data/test_vp9.ivf +0 -0
- package/dist/api/decoder.d.ts +1413 -0
- package/dist/api/decoder.js +2367 -0
- package/dist/api/decoder.js.map +1 -0
- package/dist/api/demuxer.d.ts +1295 -0
- package/dist/api/demuxer.js +2344 -0
- package/dist/api/demuxer.js.map +1 -0
- package/dist/api/device.d.ts +589 -0
- package/dist/api/device.js +964 -0
- package/dist/api/device.js.map +1 -0
- package/dist/api/encoder-pool.d.ts +262 -0
- package/dist/api/encoder-pool.js +397 -0
- package/dist/api/encoder-pool.js.map +1 -0
- package/dist/api/encoder.d.ts +1509 -0
- package/dist/api/encoder.js +2619 -0
- package/dist/api/encoder.js.map +1 -0
- package/dist/api/filter-complex.d.ts +828 -0
- package/dist/api/filter-complex.js +1661 -0
- package/dist/api/filter-complex.js.map +1 -0
- package/dist/api/filter-presets.d.ts +800 -0
- package/dist/api/filter-presets.js +1554 -0
- package/dist/api/filter-presets.js.map +1 -0
- package/dist/api/filter.d.ts +1339 -0
- package/dist/api/filter.js +2075 -0
- package/dist/api/filter.js.map +1 -0
- package/dist/api/fmp4-stream.d.ts +797 -0
- package/dist/api/fmp4-stream.js +1428 -0
- package/dist/api/fmp4-stream.js.map +1 -0
- package/dist/api/hardware.d.ts +677 -0
- package/dist/api/hardware.js +1300 -0
- package/dist/api/hardware.js.map +1 -0
- package/dist/api/index.d.ts +21 -0
- package/dist/api/index.js +38 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/io-stream.d.ts +308 -0
- package/dist/api/io-stream.js +358 -0
- package/dist/api/io-stream.js.map +1 -0
- package/dist/api/muxer.d.ts +1311 -0
- package/dist/api/muxer.js +2672 -0
- package/dist/api/muxer.js.map +1 -0
- package/dist/api/pipeline.d.ts +801 -0
- package/dist/api/pipeline.js +1344 -0
- package/dist/api/pipeline.js.map +1 -0
- package/dist/api/probe.d.ts +128 -0
- package/dist/api/probe.js +227 -0
- package/dist/api/probe.js.map +1 -0
- package/dist/api/rtp-stream.d.ts +497 -0
- package/dist/api/rtp-stream.js +1131 -0
- package/dist/api/rtp-stream.js.map +1 -0
- package/dist/api/scaler.d.ts +561 -0
- package/dist/api/scaler.js +918 -0
- package/dist/api/scaler.js.map +1 -0
- package/dist/api/types.d.ts +17 -0
- package/dist/api/types.js +2 -0
- package/dist/api/types.js.map +1 -0
- package/dist/api/utilities/async-queue.d.ts +149 -0
- package/dist/api/utilities/async-queue.js +254 -0
- package/dist/api/utilities/async-queue.js.map +1 -0
- package/dist/api/utilities/audio-sample.d.ts +117 -0
- package/dist/api/utilities/audio-sample.js +112 -0
- package/dist/api/utilities/audio-sample.js.map +1 -0
- package/dist/api/utilities/audio-transcode.d.ts +20 -0
- package/dist/api/utilities/audio-transcode.js +27 -0
- package/dist/api/utilities/audio-transcode.js.map +1 -0
- package/dist/api/utilities/channel-layout.d.ts +76 -0
- package/dist/api/utilities/channel-layout.js +80 -0
- package/dist/api/utilities/channel-layout.js.map +1 -0
- package/dist/api/utilities/codec-format.d.ts +87 -0
- package/dist/api/utilities/codec-format.js +117 -0
- package/dist/api/utilities/codec-format.js.map +1 -0
- package/dist/api/utilities/context-options.d.ts +25 -0
- package/dist/api/utilities/context-options.js +23 -0
- package/dist/api/utilities/context-options.js.map +1 -0
- package/dist/api/utilities/electron-shared-texture.d.ts +368 -0
- package/dist/api/utilities/electron-shared-texture.js +540 -0
- package/dist/api/utilities/electron-shared-texture.js.map +1 -0
- package/dist/api/utilities/image.d.ts +207 -0
- package/dist/api/utilities/image.js +213 -0
- package/dist/api/utilities/image.js.map +1 -0
- package/dist/api/utilities/index.d.ts +14 -0
- package/dist/api/utilities/index.js +27 -0
- package/dist/api/utilities/index.js.map +1 -0
- package/dist/api/utilities/live-decoding.d.ts +15 -0
- package/dist/api/utilities/live-decoding.js +32 -0
- package/dist/api/utilities/live-decoding.js.map +1 -0
- package/dist/api/utilities/media-type.d.ts +49 -0
- package/dist/api/utilities/media-type.js +53 -0
- package/dist/api/utilities/media-type.js.map +1 -0
- package/dist/api/utilities/packet-age-watchdog.d.ts +198 -0
- package/dist/api/utilities/packet-age-watchdog.js +594 -0
- package/dist/api/utilities/packet-age-watchdog.js.map +1 -0
- package/dist/api/utilities/pixel-format.d.ts +89 -0
- package/dist/api/utilities/pixel-format.js +97 -0
- package/dist/api/utilities/pixel-format.js.map +1 -0
- package/dist/api/utilities/sample-format.d.ts +129 -0
- package/dist/api/utilities/sample-format.js +141 -0
- package/dist/api/utilities/sample-format.js.map +1 -0
- package/dist/api/utilities/scale-size.d.ts +51 -0
- package/dist/api/utilities/scale-size.js +55 -0
- package/dist/api/utilities/scale-size.js.map +1 -0
- package/dist/api/utilities/scheduler.d.ts +138 -0
- package/dist/api/utilities/scheduler.js +98 -0
- package/dist/api/utilities/scheduler.js.map +1 -0
- package/dist/api/utilities/streaming.d.ts +186 -0
- package/dist/api/utilities/streaming.js +309 -0
- package/dist/api/utilities/streaming.js.map +1 -0
- package/dist/api/utilities/timestamp.d.ts +193 -0
- package/dist/api/utilities/timestamp.js +206 -0
- package/dist/api/utilities/timestamp.js.map +1 -0
- package/dist/api/utilities/video-transcode.d.ts +218 -0
- package/dist/api/utilities/video-transcode.js +624 -0
- package/dist/api/utilities/video-transcode.js.map +1 -0
- package/dist/api/utilities/whisper-model.d.ts +330 -0
- package/dist/api/utilities/whisper-model.js +587 -0
- package/dist/api/utilities/whisper-model.js.map +1 -0
- package/dist/api/utils.d.ts +19 -0
- package/dist/api/utils.js +39 -0
- package/dist/api/utils.js.map +1 -0
- package/dist/api/webrtc-stream.d.ts +294 -0
- package/dist/api/webrtc-stream.js +546 -0
- package/dist/api/webrtc-stream.js.map +1 -0
- package/dist/api/whisper.d.ts +326 -0
- package/dist/api/whisper.js +402 -0
- package/dist/api/whisper.js.map +1 -0
- package/dist/constants/bsf-options.d.ts +364 -0
- package/dist/constants/bsf-options.js +7 -0
- package/dist/constants/bsf-options.js.map +1 -0
- package/dist/constants/channel-layouts.d.ts +53 -0
- package/dist/constants/channel-layouts.js +57 -0
- package/dist/constants/channel-layouts.js.map +1 -0
- package/dist/constants/constants.d.ts +2435 -0
- package/dist/constants/constants.js +1989 -0
- package/dist/constants/constants.js.map +1 -0
- package/dist/constants/decoders.d.ts +651 -0
- package/dist/constants/decoders.js +641 -0
- package/dist/constants/decoders.js.map +1 -0
- package/dist/constants/encoders.d.ts +314 -0
- package/dist/constants/encoders.js +309 -0
- package/dist/constants/encoders.js.map +1 -0
- package/dist/constants/filter-options.d.ts +12099 -0
- package/dist/constants/filter-options.js +7 -0
- package/dist/constants/filter-options.js.map +1 -0
- package/dist/constants/format-options.d.ts +4319 -0
- package/dist/constants/format-options.js +7 -0
- package/dist/constants/format-options.js.map +1 -0
- package/dist/constants/formats.d.ts +18 -0
- package/dist/constants/formats.js +7 -0
- package/dist/constants/formats.js.map +1 -0
- package/dist/constants/hardware.d.ts +26 -0
- package/dist/constants/hardware.js +27 -0
- package/dist/constants/hardware.js.map +1 -0
- package/dist/constants/index.d.ts +10 -0
- package/dist/constants/index.js +6 -0
- package/dist/constants/index.js.map +1 -0
- package/dist/constants/options.d.ts +6217 -0
- package/dist/constants/options.js +7 -0
- package/dist/constants/options.js.map +1 -0
- package/dist/ffmpeg/index.d.ts +101 -0
- package/dist/ffmpeg/index.js +161 -0
- package/dist/ffmpeg/index.js.map +1 -0
- package/dist/ffmpeg/version.d.ts +6 -0
- package/dist/ffmpeg/version.js +7 -0
- package/dist/ffmpeg/version.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/audio-fifo.d.ts +399 -0
- package/dist/lib/audio-fifo.js +431 -0
- package/dist/lib/audio-fifo.js.map +1 -0
- package/dist/lib/binding.d.ts +242 -0
- package/dist/lib/binding.js +102 -0
- package/dist/lib/binding.js.map +1 -0
- package/dist/lib/bitstream-filter-context.d.ts +381 -0
- package/dist/lib/bitstream-filter-context.js +443 -0
- package/dist/lib/bitstream-filter-context.js.map +1 -0
- package/dist/lib/bitstream-filter.d.ts +140 -0
- package/dist/lib/bitstream-filter.js +154 -0
- package/dist/lib/bitstream-filter.js.map +1 -0
- package/dist/lib/codec-context.d.ts +1069 -0
- package/dist/lib/codec-context.js +1336 -0
- package/dist/lib/codec-context.js.map +1 -0
- package/dist/lib/codec-parameters.d.ts +664 -0
- package/dist/lib/codec-parameters.js +813 -0
- package/dist/lib/codec-parameters.js.map +1 -0
- package/dist/lib/codec-parser.d.ts +201 -0
- package/dist/lib/codec-parser.js +213 -0
- package/dist/lib/codec-parser.js.map +1 -0
- package/dist/lib/codec.d.ts +617 -0
- package/dist/lib/codec.js +746 -0
- package/dist/lib/codec.js.map +1 -0
- package/dist/lib/device.d.ts +294 -0
- package/dist/lib/device.js +326 -0
- package/dist/lib/device.js.map +1 -0
- package/dist/lib/dictionary.d.ts +333 -0
- package/dist/lib/dictionary.js +372 -0
- package/dist/lib/dictionary.js.map +1 -0
- package/dist/lib/error.d.ts +311 -0
- package/dist/lib/error.js +395 -0
- package/dist/lib/error.js.map +1 -0
- package/dist/lib/fifo.d.ts +416 -0
- package/dist/lib/fifo.js +453 -0
- package/dist/lib/fifo.js.map +1 -0
- package/dist/lib/filter-context.d.ts +714 -0
- package/dist/lib/filter-context.js +783 -0
- package/dist/lib/filter-context.js.map +1 -0
- package/dist/lib/filter-graph-segment.d.ts +161 -0
- package/dist/lib/filter-graph-segment.js +172 -0
- package/dist/lib/filter-graph-segment.js.map +1 -0
- package/dist/lib/filter-graph.d.ts +641 -0
- package/dist/lib/filter-graph.js +704 -0
- package/dist/lib/filter-graph.js.map +1 -0
- package/dist/lib/filter-inout.d.ts +202 -0
- package/dist/lib/filter-inout.js +261 -0
- package/dist/lib/filter-inout.js.map +1 -0
- package/dist/lib/filter.d.ts +243 -0
- package/dist/lib/filter.js +272 -0
- package/dist/lib/filter.js.map +1 -0
- package/dist/lib/format-context.d.ts +1335 -0
- package/dist/lib/format-context.js +1455 -0
- package/dist/lib/format-context.js.map +1 -0
- package/dist/lib/frame-utils.d.ts +116 -0
- package/dist/lib/frame-utils.js +98 -0
- package/dist/lib/frame-utils.js.map +1 -0
- package/dist/lib/frame.d.ts +1315 -0
- package/dist/lib/frame.js +1535 -0
- package/dist/lib/frame.js.map +1 -0
- package/dist/lib/hardware-device-context.d.ts +362 -0
- package/dist/lib/hardware-device-context.js +383 -0
- package/dist/lib/hardware-device-context.js.map +1 -0
- package/dist/lib/hardware-frames-context.d.ts +418 -0
- package/dist/lib/hardware-frames-context.js +471 -0
- package/dist/lib/hardware-frames-context.js.map +1 -0
- package/dist/lib/index.d.ts +35 -0
- package/dist/lib/index.js +60 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/input-format.d.ts +249 -0
- package/dist/lib/input-format.js +306 -0
- package/dist/lib/input-format.js.map +1 -0
- package/dist/lib/io-context.d.ts +698 -0
- package/dist/lib/io-context.js +771 -0
- package/dist/lib/io-context.js.map +1 -0
- package/dist/lib/log.d.ts +174 -0
- package/dist/lib/log.js +184 -0
- package/dist/lib/log.js.map +1 -0
- package/dist/lib/native-types.d.ts +1024 -0
- package/dist/lib/native-types.js +2 -0
- package/dist/lib/native-types.js.map +1 -0
- package/dist/lib/option.d.ts +953 -0
- package/dist/lib/option.js +1607 -0
- package/dist/lib/option.js.map +1 -0
- package/dist/lib/output-format.d.ts +222 -0
- package/dist/lib/output-format.js +259 -0
- package/dist/lib/output-format.js.map +1 -0
- package/dist/lib/packet.d.ts +521 -0
- package/dist/lib/packet.js +613 -0
- package/dist/lib/packet.js.map +1 -0
- package/dist/lib/rational.d.ts +251 -0
- package/dist/lib/rational.js +278 -0
- package/dist/lib/rational.js.map +1 -0
- package/dist/lib/software-resample-context.d.ts +552 -0
- package/dist/lib/software-resample-context.js +592 -0
- package/dist/lib/software-resample-context.js.map +1 -0
- package/dist/lib/software-scale-context.d.ts +344 -0
- package/dist/lib/software-scale-context.js +366 -0
- package/dist/lib/software-scale-context.js.map +1 -0
- package/dist/lib/stream.d.ts +384 -0
- package/dist/lib/stream.js +525 -0
- package/dist/lib/stream.js.map +1 -0
- package/dist/lib/sync-queue.d.ts +179 -0
- package/dist/lib/sync-queue.js +197 -0
- package/dist/lib/sync-queue.js.map +1 -0
- package/dist/lib/types.d.ts +34 -0
- package/dist/lib/types.js +2 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/lib/utilities.d.ts +1198 -0
- package/dist/lib/utilities.js +1302 -0
- package/dist/lib/utilities.js.map +1 -0
- package/dist/utils/electron.d.ts +49 -0
- package/dist/utils/electron.js +63 -0
- package/dist/utils/electron.js.map +1 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.js +7 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/libc.d.ts +11 -0
- package/dist/utils/libc.js +35 -0
- package/dist/utils/libc.js.map +1 -0
- package/dist/utils/variant.d.ts +26 -0
- package/dist/utils/variant.js +31 -0
- package/dist/utils/variant.js.map +1 -0
- package/dist/webrtc/index.d.ts +4 -0
- package/dist/webrtc/index.js +7 -0
- package/dist/webrtc/index.js.map +1 -0
- package/install/check.js +124 -0
- package/install/ffmpeg.js +66 -0
- package/package.json +165 -3
|
@@ -0,0 +1,546 @@
|
|
|
1
|
+
import { MediaStreamTrack, RTCIceCandidate, RTCPeerConnection, RTCRtpCodecParameters, RTCSessionDescription } from 'werift';
|
|
2
|
+
import { AV_CODEC_ID_AV1, AV_CODEC_ID_H264, AV_CODEC_ID_HEVC, AV_CODEC_ID_OPUS, AV_CODEC_ID_PCM_ALAW, AV_CODEC_ID_PCM_MULAW, AV_CODEC_ID_VP8, AV_CODEC_ID_VP9, } from '../constants/constants.js';
|
|
3
|
+
import { isMediaFrameSource, RTPStream } from './rtp-stream.js';
|
|
4
|
+
/**
|
|
5
|
+
* Complete WebRTC session management with werift integration.
|
|
6
|
+
*
|
|
7
|
+
* Provides end-to-end WebRTC streaming with automatic SDP negotiation,
|
|
8
|
+
* ICE candidate handling, and peer connection management.
|
|
9
|
+
* Built on top of {@link RTPStream} for generic RTP streaming with WebRTC-specific
|
|
10
|
+
* protocol details handled automatically.
|
|
11
|
+
* Integrates with werift library for RTCPeerConnection and media track handling.
|
|
12
|
+
* Ideal for building complete WebRTC streaming applications with minimal code.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* import { WebRTCStream } from 'node-av/api';
|
|
17
|
+
*
|
|
18
|
+
* // Create session from media source
|
|
19
|
+
* const session = await WebRTCStream.create('rtsp://camera.local/stream', {
|
|
20
|
+
* mtu: 1200,
|
|
21
|
+
* hardware: 'auto',
|
|
22
|
+
* iceServers: [{ urls: 'stun:stun.l.google.com:19302' }],
|
|
23
|
+
* onIceCandidate: (candidate) => {
|
|
24
|
+
* sendToClient({ type: 'candidate', value: candidate });
|
|
25
|
+
* }
|
|
26
|
+
* });
|
|
27
|
+
*
|
|
28
|
+
* // Process SDP offer from client
|
|
29
|
+
* const answer = await session.setOffer(clientOffer);
|
|
30
|
+
* sendToClient({ type: 'answer', value: answer });
|
|
31
|
+
*
|
|
32
|
+
* // Start streaming
|
|
33
|
+
* await session.start();
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* // Complete WebSocket signaling server
|
|
39
|
+
* import { WebSocket } from 'ws';
|
|
40
|
+
*
|
|
41
|
+
* ws.on('message', async (data) => {
|
|
42
|
+
* const msg = JSON.parse(data);
|
|
43
|
+
*
|
|
44
|
+
* if (msg.type === 'offer') {
|
|
45
|
+
* const session = await WebRTCStream.create(msg.url, {
|
|
46
|
+
* hardware: 'auto',
|
|
47
|
+
* onIceCandidate: (candidate) => {
|
|
48
|
+
* ws.send(JSON.stringify({ type: 'candidate', value: candidate }));
|
|
49
|
+
* }
|
|
50
|
+
* });
|
|
51
|
+
*
|
|
52
|
+
* const answer = await session.setOffer(msg.value);
|
|
53
|
+
* ws.send(JSON.stringify({ type: 'answer', value: answer }));
|
|
54
|
+
*
|
|
55
|
+
* await session.start();
|
|
56
|
+
* } else if (msg.type === 'candidate') {
|
|
57
|
+
* session.addIceCandidate(msg.value);
|
|
58
|
+
* }
|
|
59
|
+
* });
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* @see {@link RTPStream} For library-agnostic RTP streaming
|
|
63
|
+
* @see {@link Demuxer} For input media handling
|
|
64
|
+
*/
|
|
65
|
+
export class WebRTCStream {
|
|
66
|
+
stream;
|
|
67
|
+
pc = null;
|
|
68
|
+
videoTrack = null;
|
|
69
|
+
audioTrack = null;
|
|
70
|
+
options;
|
|
71
|
+
pendingIceCandidates = [];
|
|
72
|
+
frameSource;
|
|
73
|
+
stopping = false;
|
|
74
|
+
/**
|
|
75
|
+
* @param options - Session configuration options
|
|
76
|
+
*
|
|
77
|
+
* Use {@link create} factory method
|
|
78
|
+
*
|
|
79
|
+
* @internal
|
|
80
|
+
*/
|
|
81
|
+
constructor(options) {
|
|
82
|
+
this.options = {
|
|
83
|
+
onIceCandidate: options.onIceCandidate ?? (() => { }),
|
|
84
|
+
onClose: options.onClose ?? (() => { }),
|
|
85
|
+
iceServers: options.iceServers ?? [],
|
|
86
|
+
...options,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Create a WebRTC session from a media source.
|
|
91
|
+
*
|
|
92
|
+
* Opens the input media, creates internal streaming components, and prepares
|
|
93
|
+
* for WebRTC peer connection negotiation. Does not start streaming yet.
|
|
94
|
+
* Call {@link setOffer} to negotiate SDP and {@link start} to begin streaming.
|
|
95
|
+
*
|
|
96
|
+
* @param input - Media source URL (RTSP, file path, HTTP, etc.) or a pre-opened {@link Demuxer}
|
|
97
|
+
*
|
|
98
|
+
* @param options - Session configuration options
|
|
99
|
+
*
|
|
100
|
+
* @returns Configured WebRTC session instance
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* ```typescript
|
|
104
|
+
* const session = WebRTCStream.create('rtsp://camera.local/stream', {
|
|
105
|
+
* mtu: 1200,
|
|
106
|
+
* hardware: 'auto',
|
|
107
|
+
* iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
|
|
108
|
+
* });
|
|
109
|
+
* ```
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```typescript
|
|
113
|
+
* // Session from a pre-opened Demuxer (e.g. screen capture)
|
|
114
|
+
* const demuxer = await Device.openScreen({ frameRate: 30 });
|
|
115
|
+
* const session = WebRTCStream.create(demuxer, {
|
|
116
|
+
* hardware: 'auto'
|
|
117
|
+
* });
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
static create(input, options = {}) {
|
|
121
|
+
const session = new WebRTCStream(options);
|
|
122
|
+
// Remember a frame source so negotiation can advertise the encoder's target
|
|
123
|
+
// codecs (there's no input stream to read a codec from).
|
|
124
|
+
if (isMediaFrameSource(input)) {
|
|
125
|
+
session.frameSource = input;
|
|
126
|
+
}
|
|
127
|
+
// Create stream with WebRTC-specific codec support
|
|
128
|
+
session.stream = RTPStream.create(input, {
|
|
129
|
+
video: options.video,
|
|
130
|
+
audio: options.audio,
|
|
131
|
+
hardware: options.hardware,
|
|
132
|
+
inputOptions: options.inputOptions,
|
|
133
|
+
supportedVideoCodecs: [AV_CODEC_ID_H264, AV_CODEC_ID_HEVC, AV_CODEC_ID_VP8, AV_CODEC_ID_VP9, AV_CODEC_ID_AV1],
|
|
134
|
+
supportedAudioCodecs: [AV_CODEC_ID_OPUS, AV_CODEC_ID_PCM_ALAW, AV_CODEC_ID_PCM_MULAW],
|
|
135
|
+
onVideoPacket: (rtp) => {
|
|
136
|
+
session.videoTrack?.writeRtp(rtp);
|
|
137
|
+
},
|
|
138
|
+
onAudioPacket: (rtp) => {
|
|
139
|
+
session.audioTrack?.writeRtp(rtp);
|
|
140
|
+
},
|
|
141
|
+
onClose: (error) => {
|
|
142
|
+
session.options.onClose?.(error);
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
return session;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Start streaming media to the WebRTC peer connection.
|
|
149
|
+
*
|
|
150
|
+
* Begins the media processing pipeline, reading packets from input,
|
|
151
|
+
* transcoding if necessary, and sending RTP packets to the media tracks.
|
|
152
|
+
* {@link setOffer} calls this automatically after negotiating, so calling it
|
|
153
|
+
* explicitly is optional. It is idempotent - a useful pattern for demuxer
|
|
154
|
+
* inputs is calling `start()` *before* `setOffer()` so the input is open and
|
|
155
|
+
* its actual codecs are advertised in the answer.
|
|
156
|
+
*
|
|
157
|
+
* @returns Promise that resolves once streaming has started (runs in the background)
|
|
158
|
+
*
|
|
159
|
+
* @throws {FFmpegError} If transcoding or muxing fails
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* ```typescript
|
|
163
|
+
* const session = WebRTCStream.create('rtsp://camera.local/stream');
|
|
164
|
+
*
|
|
165
|
+
* await session.start(); // open input so getCodecs() sees the real codecs
|
|
166
|
+
* const answer = await session.setOffer(remoteOffer);
|
|
167
|
+
* sendToRemote(answer);
|
|
168
|
+
* ```
|
|
169
|
+
*
|
|
170
|
+
* @see {@link setOffer} Which starts the stream automatically after negotiation
|
|
171
|
+
*/
|
|
172
|
+
async start() {
|
|
173
|
+
await this.stream.start();
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Stop streaming gracefully and clean up all resources.
|
|
177
|
+
*
|
|
178
|
+
* Stops the stream, closes peer connection, and releases all resources.
|
|
179
|
+
* Safe to call multiple times. After stopping, you can call start() again
|
|
180
|
+
* to restart the session.
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* ```typescript
|
|
184
|
+
* const session = await WebRTCStream.create('input.mp4');
|
|
185
|
+
* await session.start();
|
|
186
|
+
*
|
|
187
|
+
* // Stop after 10 seconds
|
|
188
|
+
* setTimeout(async () => await session.stop(), 10000);
|
|
189
|
+
* ```
|
|
190
|
+
*/
|
|
191
|
+
async stop() {
|
|
192
|
+
if (this.stopping) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
this.stopping = true;
|
|
196
|
+
try {
|
|
197
|
+
await this.stream.stop();
|
|
198
|
+
try {
|
|
199
|
+
await this.pc?.close();
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
// Peer connection may already be closed.
|
|
203
|
+
}
|
|
204
|
+
this.videoTrack = null;
|
|
205
|
+
this.audioTrack = null;
|
|
206
|
+
this.pc = null;
|
|
207
|
+
this.pendingIceCandidates = [];
|
|
208
|
+
}
|
|
209
|
+
finally {
|
|
210
|
+
this.stopping = false;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Get detected codec information.
|
|
215
|
+
*
|
|
216
|
+
* Returns RTP codec parameters and FFmpeg codec IDs for video and audio.
|
|
217
|
+
* Useful for inspecting what codecs will be used in the WebRTC session.
|
|
218
|
+
* The input is automatically opened during {@link create}, so codecs can be
|
|
219
|
+
* detected immediately after session creation.
|
|
220
|
+
*
|
|
221
|
+
* @returns Codec configuration for video and audio streams
|
|
222
|
+
*
|
|
223
|
+
* @example
|
|
224
|
+
* ```typescript
|
|
225
|
+
* const session = await WebRTCStream.create('input.mp4');
|
|
226
|
+
* const codecs = session.getCodecs();
|
|
227
|
+
*
|
|
228
|
+
* console.log('Video:', codecs.video.mimeType);
|
|
229
|
+
* console.log('Audio:', codecs.audio?.mimeType);
|
|
230
|
+
* ```
|
|
231
|
+
*/
|
|
232
|
+
getCodecs() {
|
|
233
|
+
// Frame source: no input stream - advertise the encoder's target codecs
|
|
234
|
+
// (RTPStream's frame path encodes video to H264 and audio to OPUS), gated on
|
|
235
|
+
// which frame streams are present.
|
|
236
|
+
if (this.frameSource) {
|
|
237
|
+
return {
|
|
238
|
+
video: this.frameSource.video ? this.getVideoCodecConfig(AV_CODEC_ID_H264) : undefined,
|
|
239
|
+
audio: this.frameSource.audio ? this.getAudioCodecConfig(AV_CODEC_ID_OPUS) : undefined,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
const input = this.stream.getInput();
|
|
243
|
+
if (!input) {
|
|
244
|
+
return {
|
|
245
|
+
video: undefined,
|
|
246
|
+
audio: undefined,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
const videoStream = input.video();
|
|
250
|
+
const audioStream = input.audio();
|
|
251
|
+
// Try the input codec first; if unsupported (e.g. rawvideo from device capture),
|
|
252
|
+
// fall back to the first supported video codec (the transcode target)
|
|
253
|
+
let videoConfig = this.getVideoCodecConfig(videoStream?.codecpar.codecId);
|
|
254
|
+
if (!videoConfig && videoStream) {
|
|
255
|
+
const supportedVideoCodecs = [AV_CODEC_ID_H264, AV_CODEC_ID_HEVC, AV_CODEC_ID_VP8, AV_CODEC_ID_VP9, AV_CODEC_ID_AV1];
|
|
256
|
+
for (const codecId of supportedVideoCodecs) {
|
|
257
|
+
videoConfig = this.getVideoCodecConfig(codecId);
|
|
258
|
+
if (videoConfig)
|
|
259
|
+
break;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return {
|
|
263
|
+
video: videoConfig,
|
|
264
|
+
audio: this.getAudioCodecConfig(audioStream?.codecpar.codecId),
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Process SDP offer from remote peer and generate SDP answer.
|
|
269
|
+
*
|
|
270
|
+
* Creates RTCPeerConnection with detected codecs, sets up media tracks,
|
|
271
|
+
* processes the remote SDP offer, and generates a local SDP answer.
|
|
272
|
+
* Also configures ICE candidate handling via `onIceCandidate` callback in options.
|
|
273
|
+
* Must be called before {@link start}.
|
|
274
|
+
* Calling it again renegotiates: the previous peer connection is closed and
|
|
275
|
+
* replaced by a new one built from the new offer, while streaming continues.
|
|
276
|
+
*
|
|
277
|
+
* @param offerSdp - SDP offer string from remote WebRTC peer
|
|
278
|
+
*
|
|
279
|
+
* @returns SDP answer string to send back to remote peer
|
|
280
|
+
*
|
|
281
|
+
* @example
|
|
282
|
+
* ```typescript
|
|
283
|
+
* const session = await WebRTCStream.create('input.mp4');
|
|
284
|
+
*
|
|
285
|
+
* // Setup ICE candidate handler first
|
|
286
|
+
* session.onIceCandidate = (candidate) => {
|
|
287
|
+
* sendToRemote({ type: 'candidate', value: candidate });
|
|
288
|
+
* };
|
|
289
|
+
*
|
|
290
|
+
* // Process offer and send answer
|
|
291
|
+
* const answer = await session.setOffer(remoteOffer);
|
|
292
|
+
* sendToRemote({ type: 'answer', value: answer });
|
|
293
|
+
*
|
|
294
|
+
* // Start streaming
|
|
295
|
+
* await session.start();
|
|
296
|
+
* ```
|
|
297
|
+
*/
|
|
298
|
+
async setOffer(offerSdp) {
|
|
299
|
+
// Renegotiation: dispose any previous peer connection first. Left alive, its
|
|
300
|
+
// connectionstatechange handler would later report 'failed'/'closed' and tear
|
|
301
|
+
// down the new session via stop(). Buffered candidates belong to the old ICE
|
|
302
|
+
// session, so drop them too.
|
|
303
|
+
if (this.pc) {
|
|
304
|
+
const oldPc = this.pc;
|
|
305
|
+
this.pc = null;
|
|
306
|
+
this.videoTrack = null;
|
|
307
|
+
this.audioTrack = null;
|
|
308
|
+
this.pendingIceCandidates = [];
|
|
309
|
+
try {
|
|
310
|
+
await oldPc.close();
|
|
311
|
+
}
|
|
312
|
+
catch {
|
|
313
|
+
// Old connection may already be gone - proceed with the new one.
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
const codecs = this.getCodecs();
|
|
317
|
+
const videoConfig = codecs.video ?? {
|
|
318
|
+
mimeType: 'video/H264',
|
|
319
|
+
clockRate: 90000,
|
|
320
|
+
payloadType: 96,
|
|
321
|
+
};
|
|
322
|
+
delete videoConfig.codecId;
|
|
323
|
+
const audioConfig = codecs.audio ?? {
|
|
324
|
+
mimeType: 'audio/opus',
|
|
325
|
+
clockRate: 48000,
|
|
326
|
+
channels: 2,
|
|
327
|
+
payloadType: 111,
|
|
328
|
+
};
|
|
329
|
+
delete audioConfig.codecId;
|
|
330
|
+
// Create PeerConnection with detected codecs
|
|
331
|
+
const codecParams = {
|
|
332
|
+
video: [
|
|
333
|
+
new RTCRtpCodecParameters({
|
|
334
|
+
...videoConfig,
|
|
335
|
+
}),
|
|
336
|
+
],
|
|
337
|
+
audio: [
|
|
338
|
+
new RTCRtpCodecParameters({
|
|
339
|
+
...audioConfig,
|
|
340
|
+
}),
|
|
341
|
+
],
|
|
342
|
+
};
|
|
343
|
+
const pc = new RTCPeerConnection({
|
|
344
|
+
codecs: codecParams,
|
|
345
|
+
iceServers: this.options.iceServers,
|
|
346
|
+
});
|
|
347
|
+
this.pc = pc;
|
|
348
|
+
// Tear down when the peer goes away. werift verifies ICE consent (RFC 7675)
|
|
349
|
+
// and reports 'failed' once the browser disconnects (tab closed/reloaded) -
|
|
350
|
+
// without this, the pipeline would keep encoding into the void forever.
|
|
351
|
+
pc.connectionStateChange.subscribe((state) => {
|
|
352
|
+
// Ignore stale events from a connection that was replaced by a newer
|
|
353
|
+
// setOffer() - they must not tear down the current session.
|
|
354
|
+
if (this.pc !== pc) {
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
if ((state === 'failed' || state === 'closed') && !this.stopping) {
|
|
358
|
+
this.stop().catch(() => {
|
|
359
|
+
// Best-effort teardown - errors already surface via onClose(error).
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
// Setup ICE candidate handling
|
|
364
|
+
pc.onIceCandidate.subscribe((candidate) => {
|
|
365
|
+
if (candidate?.candidate && this.options.onIceCandidate) {
|
|
366
|
+
this.options.onIceCandidate(candidate.candidate);
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
// Setup tracks
|
|
370
|
+
pc.onRemoteTransceiverAdded.subscribe(async (transceiver) => {
|
|
371
|
+
if (transceiver.kind === 'video') {
|
|
372
|
+
this.videoTrack = new MediaStreamTrack({ kind: 'video' });
|
|
373
|
+
transceiver.sender.replaceTrack(this.videoTrack);
|
|
374
|
+
transceiver.setDirection('sendonly');
|
|
375
|
+
// Answer PLI feedback with a fresh keyframe - a receiver that connected
|
|
376
|
+
// after the stream started (or lost packets) can't decode until the next
|
|
377
|
+
// IDR, and it asks for one via RTCP PLI.
|
|
378
|
+
transceiver.sender.onPictureLossIndication.subscribe(() => {
|
|
379
|
+
this.stream.requestVideoKeyframe();
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
else if (transceiver.kind === 'audio' && this.audioTrack === null) {
|
|
383
|
+
this.audioTrack = new MediaStreamTrack({ kind: 'audio' });
|
|
384
|
+
transceiver.sender.replaceTrack(this.audioTrack);
|
|
385
|
+
transceiver.setDirection('sendonly');
|
|
386
|
+
}
|
|
387
|
+
else if (transceiver.kind === 'audio') {
|
|
388
|
+
// Backchannel
|
|
389
|
+
const [track] = await transceiver.onTrack.asPromise();
|
|
390
|
+
const input = this.stream.getInput();
|
|
391
|
+
const ctx = input?.getFormatContext();
|
|
392
|
+
const streams = ctx?.getRTSPStreamInfo();
|
|
393
|
+
const backchannel = streams?.find((s) => s.direction === 'sendonly' && s.mediaType === 'audio');
|
|
394
|
+
track.onReceiveRtp.subscribe(async (rtp) => {
|
|
395
|
+
if (backchannel && this.stream.isStreamActive) {
|
|
396
|
+
try {
|
|
397
|
+
await ctx?.sendRTSPPacket(backchannel.streamIndex, rtp.serialize());
|
|
398
|
+
}
|
|
399
|
+
catch {
|
|
400
|
+
// Ignore send errors
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
// Set remote description and create answer
|
|
407
|
+
await pc.setRemoteDescription(new RTCSessionDescription(offerSdp, 'offer'));
|
|
408
|
+
// The sender transmits with the FIRST negotiated codec, and browsers offer
|
|
409
|
+
// several H264 variants (packetization-mode=1 and =0). FFmpeg's RTP payloader
|
|
410
|
+
// fragments large NALs (FU-A), which is invalid under packetization-mode=0 -
|
|
411
|
+
// if that entry happened to be first, the receiver would silently discard
|
|
412
|
+
// every fragmented (key)frame. Prefer a packetization-mode=1 H264 entry.
|
|
413
|
+
for (const transceiver of pc.getTransceivers()) {
|
|
414
|
+
if (transceiver.kind !== 'video') {
|
|
415
|
+
continue;
|
|
416
|
+
}
|
|
417
|
+
transceiver.codecs = [...transceiver.codecs].sort((a, b) => {
|
|
418
|
+
const score = (codec) => codec.mimeType.toLowerCase() === 'video/h264' && !(codec.parameters ?? '').includes('packetization-mode=1') ? 1 : 0;
|
|
419
|
+
return score(a) - score(b);
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
const answer = await pc.createAnswer();
|
|
423
|
+
// Must be awaited: localDescription is only complete afterwards, and an
|
|
424
|
+
// un-awaited rejection would otherwise be unhandled.
|
|
425
|
+
await pc.setLocalDescription(answer);
|
|
426
|
+
// Apply any buffered ICE candidates now that remote description is set
|
|
427
|
+
if (this.pendingIceCandidates.length > 0) {
|
|
428
|
+
for (const candidate of this.pendingIceCandidates) {
|
|
429
|
+
pc.addIceCandidate(new RTCIceCandidate({ candidate }));
|
|
430
|
+
}
|
|
431
|
+
this.pendingIceCandidates = [];
|
|
432
|
+
}
|
|
433
|
+
// Start streaming - negotiation is done and the tracks exist, so the caller
|
|
434
|
+
// doesn't have to sequence start() themselves. Idempotent: calling start()
|
|
435
|
+
// before setOffer() (e.g. to have the input open for codec detection) is fine.
|
|
436
|
+
await this.start();
|
|
437
|
+
return pc.localDescription?.sdp ?? '';
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Add ICE candidate from remote peer.
|
|
441
|
+
*
|
|
442
|
+
* Processes ICE candidates received from the remote peer via signaling channel.
|
|
443
|
+
* Should be called whenever a new candidate message arrives from remote peer.
|
|
444
|
+
* Can be called multiple times as candidates are discovered.
|
|
445
|
+
*
|
|
446
|
+
* Supports ICE trickling: If called before {@link setOffer}, candidates are buffered
|
|
447
|
+
* and applied automatically once the remote description is set.
|
|
448
|
+
*
|
|
449
|
+
* @param candidate - ICE candidate string from remote peer
|
|
450
|
+
*
|
|
451
|
+
* @example
|
|
452
|
+
* ```typescript
|
|
453
|
+
* // In signaling message handler
|
|
454
|
+
* if (msg.type === 'candidate') {
|
|
455
|
+
* session.addIceCandidate(msg.value);
|
|
456
|
+
* }
|
|
457
|
+
* ```
|
|
458
|
+
*/
|
|
459
|
+
addIceCandidate(candidate) {
|
|
460
|
+
// Buffer candidates if peer connection not ready yet (ICE trickling)
|
|
461
|
+
if (!this.pc?.remoteDescription) {
|
|
462
|
+
this.pendingIceCandidates.push(candidate);
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
// Apply candidate immediately if peer connection is ready
|
|
466
|
+
this.pc.addIceCandidate(new RTCIceCandidate({ candidate }));
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* Get video codec configuration from input stream.
|
|
470
|
+
*
|
|
471
|
+
* @param codecId - FFmpeg codec ID
|
|
472
|
+
*
|
|
473
|
+
* @returns RTP codec parameters with codec ID or undefined if unsupported
|
|
474
|
+
*
|
|
475
|
+
* @internal
|
|
476
|
+
*/
|
|
477
|
+
getVideoCodecConfig(codecId) {
|
|
478
|
+
let mimeType;
|
|
479
|
+
const clockRate = 90000;
|
|
480
|
+
let payloadType;
|
|
481
|
+
switch (codecId) {
|
|
482
|
+
case AV_CODEC_ID_H264:
|
|
483
|
+
mimeType = 'video/H264';
|
|
484
|
+
payloadType = 96;
|
|
485
|
+
break;
|
|
486
|
+
case AV_CODEC_ID_HEVC:
|
|
487
|
+
mimeType = 'video/H265';
|
|
488
|
+
payloadType = 96;
|
|
489
|
+
break;
|
|
490
|
+
case AV_CODEC_ID_VP8:
|
|
491
|
+
mimeType = 'video/VP8';
|
|
492
|
+
payloadType = 96;
|
|
493
|
+
break;
|
|
494
|
+
case AV_CODEC_ID_VP9:
|
|
495
|
+
mimeType = 'video/VP9';
|
|
496
|
+
payloadType = 98;
|
|
497
|
+
break;
|
|
498
|
+
case AV_CODEC_ID_AV1:
|
|
499
|
+
mimeType = 'video/AV1';
|
|
500
|
+
payloadType = 98;
|
|
501
|
+
break;
|
|
502
|
+
default:
|
|
503
|
+
return undefined;
|
|
504
|
+
}
|
|
505
|
+
return { mimeType, clockRate, payloadType, codecId };
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* Get audio codec configuration from input stream.
|
|
509
|
+
*
|
|
510
|
+
* @param codecId - FFmpeg codec ID
|
|
511
|
+
*
|
|
512
|
+
* @returns RTP codec parameters with codec ID or undefined if unsupported
|
|
513
|
+
*
|
|
514
|
+
* @internal
|
|
515
|
+
*/
|
|
516
|
+
getAudioCodecConfig(codecId) {
|
|
517
|
+
let mimeType;
|
|
518
|
+
let clockRate;
|
|
519
|
+
let channels;
|
|
520
|
+
let payloadType;
|
|
521
|
+
switch (codecId) {
|
|
522
|
+
case AV_CODEC_ID_OPUS:
|
|
523
|
+
mimeType = 'audio/opus';
|
|
524
|
+
clockRate = 48000;
|
|
525
|
+
channels = 2;
|
|
526
|
+
payloadType = 111;
|
|
527
|
+
break;
|
|
528
|
+
case AV_CODEC_ID_PCM_ALAW:
|
|
529
|
+
mimeType = 'audio/PCMA';
|
|
530
|
+
clockRate = 8000;
|
|
531
|
+
channels = 1;
|
|
532
|
+
payloadType = 8;
|
|
533
|
+
break;
|
|
534
|
+
case AV_CODEC_ID_PCM_MULAW:
|
|
535
|
+
mimeType = 'audio/PCMU';
|
|
536
|
+
clockRate = 8000;
|
|
537
|
+
channels = 1;
|
|
538
|
+
payloadType = 0;
|
|
539
|
+
break;
|
|
540
|
+
default:
|
|
541
|
+
return undefined;
|
|
542
|
+
}
|
|
543
|
+
return { mimeType, clockRate, channels, payloadType, codecId };
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
//# sourceMappingURL=webrtc-stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webrtc-stream.js","sourceRoot":"","sources":["../../src/api/webrtc-stream.ts"],"names":[],"mappings":"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"}
|