werift 0.24.4 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +116 -113
- package/lib/common/src/transport.d.ts +22 -2
- package/lib/common/src/transport.js +84 -26
- package/lib/common/src/transport.js.map +1 -1
- package/lib/ice/src/exceptions.d.ts +9 -0
- package/lib/ice/src/exceptions.js +23 -1
- package/lib/ice/src/exceptions.js.map +1 -1
- package/lib/ice/src/ice.d.ts +40 -0
- package/lib/ice/src/ice.js +194 -28
- package/lib/ice/src/ice.js.map +1 -1
- package/lib/ice/src/iceBase.d.ts +26 -0
- package/lib/ice/src/iceBase.js.map +1 -1
- package/lib/ice/src/stun/const.d.ts +7 -0
- package/lib/ice/src/stun/const.js +8 -0
- package/lib/ice/src/stun/const.js.map +1 -1
- package/lib/ice/src/stun/protocol.js +1 -4
- package/lib/ice/src/stun/protocol.js.map +1 -1
- package/lib/ice/src/stun/tcpProtocol.d.ts +7 -1
- package/lib/ice/src/stun/tcpProtocol.js +65 -14
- package/lib/ice/src/stun/tcpProtocol.js.map +1 -1
- package/lib/ice/src/stun/transaction.d.ts +12 -1
- package/lib/ice/src/stun/transaction.js +37 -4
- package/lib/ice/src/stun/transaction.js.map +1 -1
- package/lib/ice/src/turn/protocol.d.ts +40 -15
- package/lib/ice/src/turn/protocol.js +141 -32
- package/lib/ice/src/turn/protocol.js.map +1 -1
- package/lib/ice/src/types/model.d.ts +8 -0
- package/lib/ice/src/types/model.js.map +1 -1
- package/lib/index.mjs +6175 -4073
- package/lib/nonstandard/index.mjs +286 -1003
- package/lib/polyfill/dom.mjs +23794 -0
- package/lib/polyfill/index.mjs +23794 -0
- package/lib/rtp/src/extra/container/mp4/container.js +12 -4
- package/lib/rtp/src/extra/container/mp4/container.js.map +1 -1
- package/lib/rtp/src/extra/processor/mp4.js +8 -3
- package/lib/rtp/src/extra/processor/mp4.js.map +1 -1
- package/lib/rtp/src/extra/processor/mp4Callback.js +3 -1
- package/lib/rtp/src/extra/processor/mp4Callback.js.map +1 -1
- package/lib/sctp/src/chunk.d.ts +5 -0
- package/lib/sctp/src/chunk.js +16 -11
- package/lib/sctp/src/chunk.js.map +1 -1
- package/lib/sctp/src/index.d.ts +3 -1
- package/lib/sctp/src/index.js +10 -1
- package/lib/sctp/src/index.js.map +1 -1
- package/lib/sctp/src/sctp.d.ts +12 -3
- package/lib/sctp/src/sctp.js +51 -18
- package/lib/sctp/src/sctp.js.map +1 -1
- package/lib/webrtc/src/const.js +2 -0
- package/lib/webrtc/src/const.js.map +1 -1
- package/lib/webrtc/src/errors.d.ts +9 -1
- package/lib/webrtc/src/errors.js +19 -0
- package/lib/webrtc/src/errors.js.map +1 -1
- package/lib/webrtc/src/media/codec.d.ts +5 -0
- package/lib/webrtc/src/media/codec.js +21 -0
- package/lib/webrtc/src/media/codec.js.map +1 -1
- package/lib/webrtc/src/media/codecCompatibility.d.ts +23 -0
- package/lib/webrtc/src/media/codecCompatibility.js +138 -0
- package/lib/webrtc/src/media/codecCompatibility.js.map +1 -0
- package/lib/webrtc/src/media/index.d.ts +1 -0
- package/lib/webrtc/src/media/index.js +1 -0
- package/lib/webrtc/src/media/index.js.map +1 -1
- package/lib/webrtc/src/media/router.d.ts +2 -0
- package/lib/webrtc/src/media/router.js +23 -3
- package/lib/webrtc/src/media/router.js.map +1 -1
- package/lib/webrtc/src/media/rtpReceiver.d.ts +12 -0
- package/lib/webrtc/src/media/rtpReceiver.js +35 -0
- package/lib/webrtc/src/media/rtpReceiver.js.map +1 -1
- package/lib/webrtc/src/media/rtpSender.d.ts +65 -4
- package/lib/webrtc/src/media/rtpSender.js +264 -35
- package/lib/webrtc/src/media/rtpSender.js.map +1 -1
- package/lib/webrtc/src/media/rtpTransceiver.d.ts +42 -0
- package/lib/webrtc/src/media/rtpTransceiver.js +157 -4
- package/lib/webrtc/src/media/rtpTransceiver.js.map +1 -1
- package/lib/webrtc/src/media/track.d.ts +29 -1
- package/lib/webrtc/src/media/track.js +164 -5
- package/lib/webrtc/src/media/track.js.map +1 -1
- package/lib/webrtc/src/nonstandard/index.d.ts +0 -1
- package/lib/webrtc/src/nonstandard/index.js +0 -1
- package/lib/webrtc/src/nonstandard/index.js.map +1 -1
- package/lib/webrtc/src/nonstandard/recorder/writer/webm.js +2 -1
- package/lib/webrtc/src/nonstandard/recorder/writer/webm.js.map +1 -1
- package/lib/webrtc/src/nonstandard/userMedia.d.ts +1 -2
- package/lib/webrtc/src/nonstandard/userMedia.js +30 -14
- package/lib/webrtc/src/nonstandard/userMedia.js.map +1 -1
- package/lib/webrtc/src/peerConnection.d.ts +126 -5
- package/lib/webrtc/src/peerConnection.js +609 -136
- package/lib/webrtc/src/peerConnection.js.map +1 -1
- package/lib/webrtc/src/polyfill/api.d.ts +14 -0
- package/lib/webrtc/src/polyfill/api.js +23 -0
- package/lib/webrtc/src/polyfill/api.js.map +1 -0
- package/lib/webrtc/src/polyfill/browserIdentity.d.ts +11 -0
- package/lib/webrtc/src/polyfill/browserIdentity.js +59 -0
- package/lib/webrtc/src/polyfill/browserIdentity.js.map +1 -0
- package/lib/webrtc/src/polyfill/dom.d.ts +11 -0
- package/lib/webrtc/src/polyfill/dom.js +18 -0
- package/lib/webrtc/src/polyfill/dom.js.map +1 -0
- package/lib/webrtc/src/polyfill/existingMediaDevices.d.ts +2 -0
- package/lib/webrtc/src/polyfill/existingMediaDevices.js +22 -0
- package/lib/webrtc/src/polyfill/existingMediaDevices.js.map +1 -0
- package/lib/webrtc/src/polyfill/globals.d.ts +28 -0
- package/lib/webrtc/src/polyfill/globals.js +3 -0
- package/lib/webrtc/src/polyfill/globals.js.map +1 -0
- package/lib/webrtc/src/polyfill/index.d.ts +2 -0
- package/lib/webrtc/src/polyfill/index.js +19 -0
- package/lib/webrtc/src/polyfill/index.js.map +1 -0
- package/lib/webrtc/src/polyfill/install.d.ts +13 -0
- package/lib/webrtc/src/polyfill/install.js +266 -0
- package/lib/webrtc/src/polyfill/install.js.map +1 -0
- package/lib/webrtc/src/polyfill/mediaDevices.d.ts +38 -0
- package/lib/webrtc/src/polyfill/mediaDevices.js +228 -0
- package/lib/webrtc/src/polyfill/mediaDevices.js.map +1 -0
- package/lib/webrtc/src/polyfill/mediaRegister.d.ts +51 -0
- package/lib/webrtc/src/polyfill/mediaRegister.js +14 -0
- package/lib/webrtc/src/polyfill/mediaRegister.js.map +1 -0
- package/lib/webrtc/src/polyfill/peerConnectionConfig.d.ts +3 -0
- package/lib/webrtc/src/polyfill/peerConnectionConfig.js +52 -0
- package/lib/webrtc/src/polyfill/peerConnectionConfig.js.map +1 -0
- package/lib/webrtc/src/polyfill/registers/callback.d.ts +16 -0
- package/lib/webrtc/src/polyfill/registers/callback.js +57 -0
- package/lib/webrtc/src/polyfill/registers/callback.js.map +1 -0
- package/lib/webrtc/src/polyfill/registers/empty.d.ts +2 -0
- package/lib/webrtc/src/polyfill/registers/empty.js +28 -0
- package/lib/webrtc/src/polyfill/registers/empty.js.map +1 -0
- package/lib/webrtc/src/polyfill/registers/mp4Webm.d.ts +36 -0
- package/lib/webrtc/src/polyfill/registers/mp4Webm.js +242 -0
- package/lib/webrtc/src/polyfill/registers/mp4Webm.js.map +1 -0
- package/lib/webrtc/src/polyfill/registers/rtpRtcp.d.ts +17 -0
- package/lib/webrtc/src/polyfill/registers/rtpRtcp.js +143 -0
- package/lib/webrtc/src/polyfill/registers/rtpRtcp.js.map +1 -0
- package/lib/webrtc/src/polyfill/rtcSessionDescription.d.ts +18 -0
- package/lib/webrtc/src/polyfill/rtcSessionDescription.js +36 -0
- package/lib/webrtc/src/polyfill/rtcSessionDescription.js.map +1 -0
- package/lib/webrtc/src/polyfill/rtpCodec.d.ts +17 -0
- package/lib/webrtc/src/polyfill/rtpCodec.js +93 -0
- package/lib/webrtc/src/polyfill/rtpCodec.js.map +1 -0
- package/lib/webrtc/src/polyfill/selectSettings.d.ts +31 -0
- package/lib/webrtc/src/polyfill/selectSettings.js +156 -0
- package/lib/webrtc/src/polyfill/selectSettings.js.map +1 -0
- package/lib/webrtc/src/polyfill/sourceIo.d.ts +21 -0
- package/lib/webrtc/src/polyfill/sourceIo.js +298 -0
- package/lib/webrtc/src/polyfill/sourceIo.js.map +1 -0
- package/lib/webrtc/src/polyfill/trackStop.d.ts +4 -0
- package/lib/webrtc/src/polyfill/trackStop.js +16 -0
- package/lib/webrtc/src/polyfill/trackStop.js.map +1 -0
- package/lib/webrtc/src/sctpManager.d.ts +2 -1
- package/lib/webrtc/src/sctpManager.js +5 -2
- package/lib/webrtc/src/sctpManager.js.map +1 -1
- package/lib/webrtc/src/sdp.d.ts +1 -1
- package/lib/webrtc/src/sdp.js +5 -6
- package/lib/webrtc/src/sdp.js.map +1 -1
- package/lib/webrtc/src/sdpManager.d.ts +38 -1
- package/lib/webrtc/src/sdpManager.js +236 -30
- package/lib/webrtc/src/sdpManager.js.map +1 -1
- package/lib/webrtc/src/secureTransportManager.d.ts +43 -12
- package/lib/webrtc/src/secureTransportManager.js +123 -47
- package/lib/webrtc/src/secureTransportManager.js.map +1 -1
- package/lib/webrtc/src/transceiverManager.d.ts +91 -6
- package/lib/webrtc/src/transceiverManager.js +477 -62
- package/lib/webrtc/src/transceiverManager.js.map +1 -1
- package/lib/webrtc/src/transport/ice.d.ts +8 -0
- package/lib/webrtc/src/transport/ice.js +17 -1
- package/lib/webrtc/src/transport/ice.js.map +1 -1
- package/lib/webrtc/src/transport/sctp.d.ts +3 -2
- package/lib/webrtc/src/transport/sctp.js +8 -2
- package/lib/webrtc/src/transport/sctp.js.map +1 -1
- package/package.json +13 -3
|
@@ -26,7 +26,17 @@ import type { Kind } from "../types/domain";
|
|
|
26
26
|
import type { RTCRtpCodecParameters, RTCRtpSendParameters } from "./parameters";
|
|
27
27
|
import { SenderBandwidthEstimator } from "./sender/senderBWE";
|
|
28
28
|
import { type RTCStats, type RTCStatsReport } from "./stats";
|
|
29
|
-
import type
|
|
29
|
+
import { type MediaStream, type MediaStreamTrack } from "./track";
|
|
30
|
+
export type PendingRtpOptions = {
|
|
31
|
+
/** Queue RTP until DTLS is connected and a codec is set. Default true when this object is passed. */
|
|
32
|
+
enabled?: boolean;
|
|
33
|
+
/** Max queued packets when enabled. Oldest packets are dropped. Default 256. */
|
|
34
|
+
maxLength?: number;
|
|
35
|
+
};
|
|
36
|
+
export type RTCRtpSenderOptions = {
|
|
37
|
+
/** Pending RTP cache. Disabled by default. Pass `true` or `{ maxLength }` to enable. */
|
|
38
|
+
pendingRtp?: boolean | PendingRtpOptions;
|
|
39
|
+
};
|
|
30
40
|
export declare class RTCRtpSender {
|
|
31
41
|
trackOrKind: Kind | MediaStreamTrack;
|
|
32
42
|
readonly type = "sender";
|
|
@@ -73,8 +83,16 @@ export declare class RTCRtpSender {
|
|
|
73
83
|
private timestamp?;
|
|
74
84
|
private timestampOffset;
|
|
75
85
|
private seqOffset;
|
|
86
|
+
private rtpContinuityPending;
|
|
87
|
+
private pendingTimestampStep;
|
|
76
88
|
private rtpCache;
|
|
89
|
+
private pendingRtp;
|
|
90
|
+
private drainingPendingRtp;
|
|
91
|
+
private readonly pendingRtpEnabled;
|
|
92
|
+
private readonly pendingRtpMaxLength;
|
|
77
93
|
codec?: RTCRtpCodecParameters;
|
|
94
|
+
private negotiatedCodecs;
|
|
95
|
+
private sendPrimaryCodec?;
|
|
78
96
|
dtlsTransport: RTCDtlsTransport;
|
|
79
97
|
private dtlsDisposer;
|
|
80
98
|
track: MediaStreamTrack | null;
|
|
@@ -82,7 +100,7 @@ export declare class RTCRtpSender {
|
|
|
82
100
|
stopped: boolean;
|
|
83
101
|
rtcpRunning: boolean;
|
|
84
102
|
private rtcpCancel;
|
|
85
|
-
constructor(trackOrKind: Kind | MediaStreamTrack);
|
|
103
|
+
constructor(trackOrKind: Kind | MediaStreamTrack, options?: RTCRtpSenderOptions);
|
|
86
104
|
get transport(): RTCDtlsTransport;
|
|
87
105
|
get streamId(): string | undefined;
|
|
88
106
|
set streamId(value: string | undefined);
|
|
@@ -90,14 +108,57 @@ export declare class RTCRtpSender {
|
|
|
90
108
|
get redDistance(): number;
|
|
91
109
|
set redDistance(n: number);
|
|
92
110
|
prepareSend(params: RTCRtpSendParameters): void;
|
|
111
|
+
private canSendRtp;
|
|
112
|
+
private settlePendingRtp;
|
|
113
|
+
private discardPendingRtp;
|
|
114
|
+
private enqueuePendingRtp;
|
|
115
|
+
/**
|
|
116
|
+
* Send queued RTP once DTLS is connected and a codec is set. Used only when
|
|
117
|
+
* pending RTP is enabled: `writeRtp` / `sendRtp` may run before ICE/DTLS
|
|
118
|
+
* completes; dropping those packets would lose the start of a media source.
|
|
119
|
+
* `drainingPendingRtp` blocks re-entry while `dispatchRtp` is awaited;
|
|
120
|
+
* packets enqueued during that wait are drained by the recursive call after
|
|
121
|
+
* the flag is cleared.
|
|
122
|
+
*/
|
|
123
|
+
private drainPendingRtp;
|
|
93
124
|
registerTrack(track: MediaStreamTrack): void;
|
|
94
125
|
setStreams(streams?: MediaStream[]): void;
|
|
95
126
|
setSendEncodings(encodings?: Array<Record<string, unknown>>): void;
|
|
96
127
|
replaceTrack(track: MediaStreamTrack | null): Promise<void>;
|
|
97
|
-
|
|
128
|
+
/**
|
|
129
|
+
* Detach the current track without stopping the sender (`removeTrack`).
|
|
130
|
+
* The same sender can resume sending after `replaceTrack(track)`.
|
|
131
|
+
*/
|
|
132
|
+
detachTrack(): void;
|
|
133
|
+
stop({ keepTrack }?: {
|
|
134
|
+
keepTrack?: boolean;
|
|
135
|
+
}): void;
|
|
98
136
|
runRtcp(): Promise<void>;
|
|
99
|
-
|
|
137
|
+
/**
|
|
138
|
+
* Send an RTP packet. Pending RTP is disabled by default: the packet is
|
|
139
|
+
* written immediately if DTLS is connected and a codec is set, otherwise
|
|
140
|
+
* dropped.
|
|
141
|
+
*
|
|
142
|
+
* When pending RTP is enabled, the packet is queued until it can be sent.
|
|
143
|
+
* The returned promise then settles for this packet only:
|
|
144
|
+
* - resolve: DTLS send completed, or the packet was dropped by `stop()`,
|
|
145
|
+
* `replaceTrack(null)`, or pending-queue overflow
|
|
146
|
+
* - reject: DTLS send threw while writing this packet
|
|
147
|
+
*
|
|
148
|
+
* Later `sendRtp()` calls stay pending until their own packet is sent or
|
|
149
|
+
* dropped, even if a drain is already in progress.
|
|
150
|
+
*/
|
|
100
151
|
sendRtp(rtp: Buffer | RtpPacket): Promise<void>;
|
|
152
|
+
/**
|
|
153
|
+
* Schedule RTP continuity rewrite for the next packet that is actually sent.
|
|
154
|
+
* The header argument is kept for API compatibility and is not used to compute
|
|
155
|
+
* offsets. `discontinuity` does not change sequence or timestamp mapping.
|
|
156
|
+
* `timestampStep` (default 1) is the only way to choose the timestamp increment
|
|
157
|
+
* at the source-switch boundary.
|
|
158
|
+
*/
|
|
159
|
+
replaceRTP(header: Pick<RtpHeader, "sequenceNumber" | "timestamp">, discontinuity?: boolean, timestampStep?: number): void;
|
|
160
|
+
private scheduleRtpContinuity;
|
|
161
|
+
private dispatchRtp;
|
|
101
162
|
handleRtcpPacket(rtcpPacket: RtcpPacket): void;
|
|
102
163
|
getParameters(): {
|
|
103
164
|
encodings: {
|
|
@@ -27,15 +27,39 @@ const crypto_2 = require("crypto");
|
|
|
27
27
|
const promises_1 = require("timers/promises");
|
|
28
28
|
const common_1 = require("../imports/common");
|
|
29
29
|
const __1 = require("..");
|
|
30
|
+
const errors_1 = require("../errors");
|
|
30
31
|
const rtp_1 = require("../imports/rtp");
|
|
31
32
|
const utils_1 = require("../utils");
|
|
33
|
+
const codecCompatibility_1 = require("./codecCompatibility");
|
|
32
34
|
const senderBWE_1 = require("./sender/senderBWE");
|
|
33
35
|
const stats_1 = require("./stats");
|
|
36
|
+
const track_1 = require("./track");
|
|
34
37
|
const log = (0, rtp_1.debug)("werift:packages/webrtc/src/media/rtpSender.ts");
|
|
35
38
|
const RTP_HISTORY_SIZE = 128;
|
|
39
|
+
const DEFAULT_PENDING_RTP_MAX_LENGTH = 256;
|
|
36
40
|
const RTT_ALPHA = 0.85;
|
|
41
|
+
function resolvePendingRtpOptions(pendingRtp) {
|
|
42
|
+
if (pendingRtp === true) {
|
|
43
|
+
return { enabled: true, maxLength: DEFAULT_PENDING_RTP_MAX_LENGTH };
|
|
44
|
+
}
|
|
45
|
+
if (pendingRtp == undefined || pendingRtp === false) {
|
|
46
|
+
return { enabled: false, maxLength: DEFAULT_PENDING_RTP_MAX_LENGTH };
|
|
47
|
+
}
|
|
48
|
+
const maxLength = typeof pendingRtp.maxLength === "number" &&
|
|
49
|
+
Number.isFinite(pendingRtp.maxLength) &&
|
|
50
|
+
pendingRtp.maxLength >= 1
|
|
51
|
+
? Math.floor(pendingRtp.maxLength)
|
|
52
|
+
: DEFAULT_PENDING_RTP_MAX_LENGTH;
|
|
53
|
+
return { enabled: pendingRtp.enabled ?? true, maxLength };
|
|
54
|
+
}
|
|
55
|
+
function freezeRtpContinuityOffsets(lastOutputSeq, lastOutputTimestamp, firstInputSeq, firstInputTimestamp, timestampStep) {
|
|
56
|
+
return {
|
|
57
|
+
seqOffset: (0, common_1.uint16Add)((0, common_1.uint16Add)(lastOutputSeq, 1), -firstInputSeq),
|
|
58
|
+
timestampOffset: (0, common_1.uint32Add)((0, common_1.uint32Add)(lastOutputTimestamp, timestampStep), -firstInputTimestamp),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
37
61
|
class RTCRtpSender {
|
|
38
|
-
constructor(trackOrKind) {
|
|
62
|
+
constructor(trackOrKind, options = {}) {
|
|
39
63
|
Object.defineProperty(this, "trackOrKind", {
|
|
40
64
|
enumerable: true,
|
|
41
65
|
configurable: true,
|
|
@@ -308,18 +332,66 @@ class RTCRtpSender {
|
|
|
308
332
|
writable: true,
|
|
309
333
|
value: 0
|
|
310
334
|
});
|
|
335
|
+
Object.defineProperty(this, "rtpContinuityPending", {
|
|
336
|
+
enumerable: true,
|
|
337
|
+
configurable: true,
|
|
338
|
+
writable: true,
|
|
339
|
+
value: false
|
|
340
|
+
});
|
|
341
|
+
Object.defineProperty(this, "pendingTimestampStep", {
|
|
342
|
+
enumerable: true,
|
|
343
|
+
configurable: true,
|
|
344
|
+
writable: true,
|
|
345
|
+
value: 1
|
|
346
|
+
});
|
|
311
347
|
Object.defineProperty(this, "rtpCache", {
|
|
312
348
|
enumerable: true,
|
|
313
349
|
configurable: true,
|
|
314
350
|
writable: true,
|
|
315
351
|
value: []
|
|
316
352
|
});
|
|
353
|
+
Object.defineProperty(this, "pendingRtp", {
|
|
354
|
+
enumerable: true,
|
|
355
|
+
configurable: true,
|
|
356
|
+
writable: true,
|
|
357
|
+
value: []
|
|
358
|
+
});
|
|
359
|
+
Object.defineProperty(this, "drainingPendingRtp", {
|
|
360
|
+
enumerable: true,
|
|
361
|
+
configurable: true,
|
|
362
|
+
writable: true,
|
|
363
|
+
value: false
|
|
364
|
+
});
|
|
365
|
+
Object.defineProperty(this, "pendingRtpEnabled", {
|
|
366
|
+
enumerable: true,
|
|
367
|
+
configurable: true,
|
|
368
|
+
writable: true,
|
|
369
|
+
value: void 0
|
|
370
|
+
});
|
|
371
|
+
Object.defineProperty(this, "pendingRtpMaxLength", {
|
|
372
|
+
enumerable: true,
|
|
373
|
+
configurable: true,
|
|
374
|
+
writable: true,
|
|
375
|
+
value: void 0
|
|
376
|
+
});
|
|
317
377
|
Object.defineProperty(this, "codec", {
|
|
318
378
|
enumerable: true,
|
|
319
379
|
configurable: true,
|
|
320
380
|
writable: true,
|
|
321
381
|
value: void 0
|
|
322
382
|
});
|
|
383
|
+
Object.defineProperty(this, "negotiatedCodecs", {
|
|
384
|
+
enumerable: true,
|
|
385
|
+
configurable: true,
|
|
386
|
+
writable: true,
|
|
387
|
+
value: []
|
|
388
|
+
});
|
|
389
|
+
Object.defineProperty(this, "sendPrimaryCodec", {
|
|
390
|
+
enumerable: true,
|
|
391
|
+
configurable: true,
|
|
392
|
+
writable: true,
|
|
393
|
+
value: void 0
|
|
394
|
+
});
|
|
323
395
|
Object.defineProperty(this, "dtlsTransport", {
|
|
324
396
|
enumerable: true,
|
|
325
397
|
configurable: true,
|
|
@@ -362,6 +434,9 @@ class RTCRtpSender {
|
|
|
362
434
|
writable: true,
|
|
363
435
|
value: new AbortController()
|
|
364
436
|
});
|
|
437
|
+
const pendingRtp = resolvePendingRtpOptions(options.pendingRtp);
|
|
438
|
+
this.pendingRtpEnabled = pendingRtp.enabled;
|
|
439
|
+
this.pendingRtpMaxLength = pendingRtp.maxLength;
|
|
365
440
|
this.kind =
|
|
366
441
|
typeof this.trackOrKind === "string"
|
|
367
442
|
? this.trackOrKind
|
|
@@ -388,6 +463,7 @@ class RTCRtpSender {
|
|
|
388
463
|
this.dtlsTransport.onStateChange.subscribe((state) => {
|
|
389
464
|
if (state === "connected") {
|
|
390
465
|
this.onReady.execute();
|
|
466
|
+
void this.drainPendingRtp();
|
|
391
467
|
}
|
|
392
468
|
}).unSubscribe,
|
|
393
469
|
];
|
|
@@ -403,41 +479,124 @@ class RTCRtpSender {
|
|
|
403
479
|
this.cname = params.rtcp?.cname;
|
|
404
480
|
this.mid = params.muxId;
|
|
405
481
|
this.headerExtensions = params.headerExtensions;
|
|
406
|
-
this.rtpStreamId = params.rtpStreamId;
|
|
482
|
+
this.rtpStreamId = params.rtpStreamId ?? this.rtpStreamId;
|
|
407
483
|
this.repairedRtpStreamId = params.repairedRtpStreamId;
|
|
408
|
-
this.
|
|
484
|
+
this.negotiatedCodecs = [...params.codecs];
|
|
485
|
+
this.codec =
|
|
486
|
+
params.codecs.find((codec) => codec.name.toLowerCase() !== "rtx") ??
|
|
487
|
+
params.codecs[0];
|
|
488
|
+
const redPrimaryPayloadType = this.codec?.name.toLowerCase() === "red"
|
|
489
|
+
? Number((this.codec.parameters ?? "").split("/")[0])
|
|
490
|
+
: undefined;
|
|
491
|
+
this.sendPrimaryCodec =
|
|
492
|
+
this.codec?.name.toLowerCase() === "red"
|
|
493
|
+
? params.codecs.find((codec) => !["red", "rtx"].includes(codec.name.toLowerCase()) &&
|
|
494
|
+
codec.payloadType === redPrimaryPayloadType)
|
|
495
|
+
: this.codec;
|
|
409
496
|
if (this.track) {
|
|
410
497
|
this.track.codec = this.codec;
|
|
411
498
|
}
|
|
499
|
+
this.rtxPayloadType = undefined;
|
|
500
|
+
this.redRedundantPayloadType = undefined;
|
|
412
501
|
params.codecs.forEach((codec) => {
|
|
413
502
|
const codecParams = (0, __1.codecParametersFromString)(codec.parameters ?? "");
|
|
414
503
|
if (codec.name.toLowerCase() === "rtx" &&
|
|
415
|
-
codecParams["apt"]
|
|
504
|
+
this.sendPrimaryCodec?.payloadType === codecParams["apt"]) {
|
|
416
505
|
this.rtxPayloadType = codec.payloadType;
|
|
417
506
|
}
|
|
418
|
-
if (codec.name.toLowerCase() === "red") {
|
|
419
|
-
this.redRedundantPayloadType = Number((codec.parameters ?? "").split("/")[0]);
|
|
420
|
-
}
|
|
421
507
|
});
|
|
508
|
+
if (this.codec?.name.toLowerCase() === "red" &&
|
|
509
|
+
this.sendPrimaryCodec != undefined) {
|
|
510
|
+
this.redRedundantPayloadType = this.sendPrimaryCodec.payloadType;
|
|
511
|
+
}
|
|
512
|
+
void this.drainPendingRtp();
|
|
513
|
+
}
|
|
514
|
+
canSendRtp() {
|
|
515
|
+
return (!this.stopped && this.dtlsTransport?.state === "connected" && !!this.codec);
|
|
516
|
+
}
|
|
517
|
+
settlePendingRtp(item, error) {
|
|
518
|
+
if (error == undefined) {
|
|
519
|
+
item.resolve();
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
item.reject(error);
|
|
523
|
+
}
|
|
524
|
+
discardPendingRtp() {
|
|
525
|
+
const dropped = this.pendingRtp.splice(0);
|
|
526
|
+
for (const item of dropped) {
|
|
527
|
+
this.settlePendingRtp(item);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
enqueuePendingRtp(rtp, resolve, reject) {
|
|
531
|
+
const packet = Buffer.isBuffer(rtp)
|
|
532
|
+
? rtp_1.RtpPacket.deSerialize(rtp)
|
|
533
|
+
: rtp.clone();
|
|
534
|
+
this.pendingRtp.push({ packet, resolve, reject });
|
|
535
|
+
while (this.pendingRtp.length > this.pendingRtpMaxLength) {
|
|
536
|
+
const dropped = this.pendingRtp.shift();
|
|
537
|
+
if (dropped) {
|
|
538
|
+
this.settlePendingRtp(dropped);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* Send queued RTP once DTLS is connected and a codec is set. Used only when
|
|
544
|
+
* pending RTP is enabled: `writeRtp` / `sendRtp` may run before ICE/DTLS
|
|
545
|
+
* completes; dropping those packets would lose the start of a media source.
|
|
546
|
+
* `drainingPendingRtp` blocks re-entry while `dispatchRtp` is awaited;
|
|
547
|
+
* packets enqueued during that wait are drained by the recursive call after
|
|
548
|
+
* the flag is cleared.
|
|
549
|
+
*/
|
|
550
|
+
async drainPendingRtp() {
|
|
551
|
+
if (this.drainingPendingRtp) {
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
this.drainingPendingRtp = true;
|
|
555
|
+
try {
|
|
556
|
+
while (this.pendingRtp.length > 0 && this.canSendRtp()) {
|
|
557
|
+
const item = this.pendingRtp.shift();
|
|
558
|
+
if (!this.canSendRtp()) {
|
|
559
|
+
this.settlePendingRtp(item);
|
|
560
|
+
continue;
|
|
561
|
+
}
|
|
562
|
+
try {
|
|
563
|
+
await this.dispatchRtp(item.packet);
|
|
564
|
+
this.settlePendingRtp(item);
|
|
565
|
+
}
|
|
566
|
+
catch (error) {
|
|
567
|
+
this.settlePendingRtp(item, error);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
finally {
|
|
572
|
+
this.drainingPendingRtp = false;
|
|
573
|
+
}
|
|
574
|
+
if (this.pendingRtp.length > 0 && this.canSendRtp()) {
|
|
575
|
+
await this.drainPendingRtp();
|
|
576
|
+
}
|
|
422
577
|
}
|
|
423
578
|
registerTrack(track) {
|
|
424
579
|
if (track.stopped)
|
|
425
580
|
throw new Error("track is ended");
|
|
581
|
+
(0, track_1.captureTrackSourceCodecs)(track);
|
|
426
582
|
if (this.disposeTrack) {
|
|
427
583
|
this.disposeTrack();
|
|
428
584
|
}
|
|
429
585
|
track.id = this.trackId;
|
|
430
|
-
const { unSubscribe } = track.onReceiveRtp.subscribe(async (rtp) => {
|
|
586
|
+
const { unSubscribe: unSubscribeRtp } = track.onReceiveRtp.subscribe(async (rtp) => {
|
|
431
587
|
await this.sendRtp(rtp);
|
|
432
588
|
});
|
|
589
|
+
const { unSubscribe: unSubscribeSourceChanged } = track.onSourceChanged.subscribe((header) => {
|
|
590
|
+
this.replaceRTP(header);
|
|
591
|
+
});
|
|
433
592
|
this.track = track;
|
|
434
|
-
this.disposeTrack =
|
|
593
|
+
this.disposeTrack = () => {
|
|
594
|
+
unSubscribeRtp();
|
|
595
|
+
unSubscribeSourceChanged();
|
|
596
|
+
};
|
|
435
597
|
if (this.codec) {
|
|
436
598
|
track.codec = this.codec;
|
|
437
599
|
}
|
|
438
|
-
track.onSourceChanged.subscribe((header) => {
|
|
439
|
-
this.replaceRTP(header);
|
|
440
|
-
});
|
|
441
600
|
}
|
|
442
601
|
setStreams(streams = []) {
|
|
443
602
|
this.streamIds = [...new Set(streams.map((stream) => stream.id))];
|
|
@@ -447,32 +606,57 @@ class RTCRtpSender {
|
|
|
447
606
|
encodings.length > 0
|
|
448
607
|
? encodings.map((encoding) => ({ ...encoding }))
|
|
449
608
|
: [{}];
|
|
609
|
+
const rid = this.sendEncodings.find((encoding) => typeof encoding.rid === "string")?.rid;
|
|
610
|
+
if (typeof rid === "string") {
|
|
611
|
+
this.rtpStreamId = rid;
|
|
612
|
+
}
|
|
450
613
|
}
|
|
451
614
|
async replaceTrack(track) {
|
|
452
615
|
if (track === null) {
|
|
453
|
-
|
|
454
|
-
this.disposeTrack();
|
|
455
|
-
}
|
|
456
|
-
this.track = null;
|
|
616
|
+
this.detachTrack();
|
|
457
617
|
return;
|
|
458
618
|
}
|
|
459
619
|
if (track.stopped)
|
|
460
620
|
throw new Error("track is ended");
|
|
621
|
+
(0, track_1.captureTrackSourceCodecs)(track);
|
|
622
|
+
const sourceCodecs = (0, track_1.getTrackSourceCodecs)(track);
|
|
623
|
+
if (this.sendPrimaryCodec != undefined &&
|
|
624
|
+
sourceCodecs != undefined &&
|
|
625
|
+
!sourceCodecs.some((source) => (0, codecCompatibility_1.isCodecCompatible)(source, this.sendPrimaryCodec))) {
|
|
626
|
+
throw (0, errors_1.createWebRtcDomException)("InvalidModificationError", `Track codec ${sourceCodecs.map((codec) => codec.mimeType).join(", ")} is incompatible with negotiated codecs ${this.negotiatedCodecs.map((codec) => codec.mimeType).join(", ")}`);
|
|
627
|
+
}
|
|
461
628
|
if (this.sequenceNumber != undefined) {
|
|
462
|
-
|
|
463
|
-
this.replaceRTP(header);
|
|
629
|
+
this.scheduleRtpContinuity();
|
|
464
630
|
}
|
|
465
631
|
this.registerTrack(track);
|
|
466
632
|
log("replaceTrack", "ssrc", track.ssrc, "rid", track.rid);
|
|
467
633
|
}
|
|
468
|
-
|
|
634
|
+
/**
|
|
635
|
+
* Detach the current track without stopping the sender (`removeTrack`).
|
|
636
|
+
* The same sender can resume sending after `replaceTrack(track)`.
|
|
637
|
+
*/
|
|
638
|
+
detachTrack() {
|
|
639
|
+
this.rtpContinuityPending = false;
|
|
640
|
+
this.discardPendingRtp();
|
|
641
|
+
if (this.disposeTrack) {
|
|
642
|
+
this.disposeTrack();
|
|
643
|
+
this.disposeTrack = undefined;
|
|
644
|
+
}
|
|
645
|
+
this.track = null;
|
|
646
|
+
}
|
|
647
|
+
stop({ keepTrack = false } = {}) {
|
|
469
648
|
this.stopped = true;
|
|
649
|
+
this.rtpContinuityPending = false;
|
|
650
|
+
this.discardPendingRtp();
|
|
470
651
|
this.rtcpRunning = false;
|
|
471
652
|
this.rtcpCancel.abort();
|
|
472
653
|
if (this.disposeTrack) {
|
|
473
654
|
this.disposeTrack();
|
|
655
|
+
this.disposeTrack = undefined;
|
|
656
|
+
}
|
|
657
|
+
if (!keepTrack) {
|
|
658
|
+
this.track = null;
|
|
474
659
|
}
|
|
475
|
-
this.track = null;
|
|
476
660
|
}
|
|
477
661
|
async runRtcp() {
|
|
478
662
|
if (this.rtcpRunning || this.stopped)
|
|
@@ -519,30 +703,75 @@ class RTCRtpSender {
|
|
|
519
703
|
}
|
|
520
704
|
catch (error) { }
|
|
521
705
|
}
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
706
|
+
/**
|
|
707
|
+
* Send an RTP packet. Pending RTP is disabled by default: the packet is
|
|
708
|
+
* written immediately if DTLS is connected and a codec is set, otherwise
|
|
709
|
+
* dropped.
|
|
710
|
+
*
|
|
711
|
+
* When pending RTP is enabled, the packet is queued until it can be sent.
|
|
712
|
+
* The returned promise then settles for this packet only:
|
|
713
|
+
* - resolve: DTLS send completed, or the packet was dropped by `stop()`,
|
|
714
|
+
* `replaceTrack(null)`, or pending-queue overflow
|
|
715
|
+
* - reject: DTLS send threw while writing this packet
|
|
716
|
+
*
|
|
717
|
+
* Later `sendRtp()` calls stay pending until their own packet is sent or
|
|
718
|
+
* dropped, even if a drain is already in progress.
|
|
719
|
+
*/
|
|
720
|
+
async sendRtp(rtp) {
|
|
721
|
+
if (this.stopped) {
|
|
722
|
+
return;
|
|
528
723
|
}
|
|
529
|
-
if (this.
|
|
530
|
-
this.
|
|
531
|
-
|
|
532
|
-
this.timestampOffset = (0, common_1.uint16Add)(this.timestampOffset, 1);
|
|
724
|
+
if (!this.pendingRtpEnabled) {
|
|
725
|
+
if (!this.canSendRtp()) {
|
|
726
|
+
return;
|
|
533
727
|
}
|
|
728
|
+
await this.dispatchRtp(rtp);
|
|
729
|
+
return;
|
|
534
730
|
}
|
|
731
|
+
await new Promise((resolve, reject) => {
|
|
732
|
+
this.enqueuePendingRtp(rtp, resolve, reject);
|
|
733
|
+
void this.drainPendingRtp();
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
/**
|
|
737
|
+
* Schedule RTP continuity rewrite for the next packet that is actually sent.
|
|
738
|
+
* The header argument is kept for API compatibility and is not used to compute
|
|
739
|
+
* offsets. `discontinuity` does not change sequence or timestamp mapping.
|
|
740
|
+
* `timestampStep` (default 1) is the only way to choose the timestamp increment
|
|
741
|
+
* at the source-switch boundary.
|
|
742
|
+
*/
|
|
743
|
+
replaceRTP(header, discontinuity = false, timestampStep = 1) {
|
|
744
|
+
this.scheduleRtpContinuity(timestampStep);
|
|
745
|
+
log("replaceRTP", this.sequenceNumber, header.sequenceNumber, discontinuity, timestampStep);
|
|
746
|
+
}
|
|
747
|
+
scheduleRtpContinuity(timestampStep = 1) {
|
|
748
|
+
this.rtpContinuityPending = true;
|
|
749
|
+
this.pendingTimestampStep = timestampStep;
|
|
535
750
|
this.rtpCache = [];
|
|
536
|
-
log("replaceRTP", this.sequenceNumber, sequenceNumber, this.seqOffset);
|
|
537
751
|
}
|
|
538
|
-
async
|
|
539
|
-
if (
|
|
752
|
+
async dispatchRtp(rtp) {
|
|
753
|
+
if (!this.canSendRtp()) {
|
|
754
|
+
return;
|
|
755
|
+
}
|
|
756
|
+
const codec = this.codec;
|
|
757
|
+
if (!codec) {
|
|
540
758
|
return;
|
|
541
759
|
}
|
|
542
|
-
rtp = Buffer.isBuffer(rtp) ? rtp_1.RtpPacket.deSerialize(rtp) : rtp;
|
|
760
|
+
rtp = Buffer.isBuffer(rtp) ? rtp_1.RtpPacket.deSerialize(rtp) : rtp.clone();
|
|
543
761
|
const { header, payload } = rtp;
|
|
762
|
+
const inputSequenceNumber = header.sequenceNumber;
|
|
763
|
+
const inputTimestamp = header.timestamp;
|
|
764
|
+
if (this.rtpContinuityPending) {
|
|
765
|
+
if (this.sequenceNumber != undefined && this.timestamp != undefined) {
|
|
766
|
+
const offsets = freezeRtpContinuityOffsets(this.sequenceNumber, this.timestamp, inputSequenceNumber, inputTimestamp, this.pendingTimestampStep);
|
|
767
|
+
this.seqOffset = offsets.seqOffset;
|
|
768
|
+
this.timestampOffset = offsets.timestampOffset;
|
|
769
|
+
}
|
|
770
|
+
this.rtpContinuityPending = false;
|
|
771
|
+
this.pendingTimestampStep = 1;
|
|
772
|
+
}
|
|
544
773
|
header.ssrc = this.ssrc;
|
|
545
|
-
header.payloadType =
|
|
774
|
+
header.payloadType = codec.payloadType;
|
|
546
775
|
header.timestamp = (0, common_1.uint32Add)(header.timestamp, this.timestampOffset);
|
|
547
776
|
header.sequenceNumber = (0, common_1.uint16Add)(header.sequenceNumber, this.seqOffset);
|
|
548
777
|
this.timestamp = header.timestamp;
|