werift 0.24.3 → 0.25.0-alpha.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/event.js +2 -1
- package/lib/common/src/event.js.map +1 -1
- 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 +79 -22
- package/lib/ice/src/turn/protocol.js +282 -78
- 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 +5646 -3451
- package/lib/nonstandard/index.mjs +287 -1004
- 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 +127 -5
- package/lib/webrtc/src/peerConnection.js +629 -143
- 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 +14 -3
|
@@ -7,7 +7,7 @@ const parameters_1 = require("./media/parameters");
|
|
|
7
7
|
const sdp_1 = require("./sdp");
|
|
8
8
|
const utils_1 = require("./utils");
|
|
9
9
|
class SDPManager {
|
|
10
|
-
constructor({ cname, midSuffix, bundlePolicy, }) {
|
|
10
|
+
constructor({ cname, midSuffix, bundlePolicy, mLineReuse, }) {
|
|
11
11
|
Object.defineProperty(this, "currentLocalDescription", {
|
|
12
12
|
enumerable: true,
|
|
13
13
|
configurable: true,
|
|
@@ -50,6 +50,12 @@ class SDPManager {
|
|
|
50
50
|
writable: true,
|
|
51
51
|
value: void 0
|
|
52
52
|
});
|
|
53
|
+
Object.defineProperty(this, "mLineReuse", {
|
|
54
|
+
enumerable: true,
|
|
55
|
+
configurable: true,
|
|
56
|
+
writable: true,
|
|
57
|
+
value: void 0
|
|
58
|
+
});
|
|
53
59
|
Object.defineProperty(this, "seenMid", {
|
|
54
60
|
enumerable: true,
|
|
55
61
|
configurable: true,
|
|
@@ -59,6 +65,7 @@ class SDPManager {
|
|
|
59
65
|
this.cname = cname;
|
|
60
66
|
this.midSuffix = midSuffix ?? false;
|
|
61
67
|
this.bundlePolicy = bundlePolicy;
|
|
68
|
+
this.mLineReuse = mLineReuse ?? "compatible";
|
|
62
69
|
}
|
|
63
70
|
get localDescription() {
|
|
64
71
|
if (!this._localDescription) {
|
|
@@ -119,6 +126,30 @@ class SDPManager {
|
|
|
119
126
|
this.addTransportDescription(media, transceiver.dtlsTransport);
|
|
120
127
|
return media;
|
|
121
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* 拒否 / 停止した m-line を作成する (RFC 3264 §6 / RFC 8829 §5.3.1)。
|
|
131
|
+
* port は 0、proto と MID は元の m-line を保ち、fmt は少なくとも 1 token 残す。
|
|
132
|
+
*/
|
|
133
|
+
createRejectedMediaDescription(source, dtlsTransport) {
|
|
134
|
+
const format = source.fmt[0] ?? source.codecs[0]?.payloadType ?? 0;
|
|
135
|
+
const media = new sdp_1.MediaDescription(source.kind, 0, source.profile, [
|
|
136
|
+
format,
|
|
137
|
+
]);
|
|
138
|
+
media.host = const_1.DISCARD_HOST;
|
|
139
|
+
media.direction = "inactive";
|
|
140
|
+
media.rtp = {
|
|
141
|
+
codecs: source.codecs.filter((codec) => codec.payloadType?.toString() === format.toString()),
|
|
142
|
+
headerExtensions: [],
|
|
143
|
+
muxId: source.mid,
|
|
144
|
+
};
|
|
145
|
+
media.rtcpMux = true;
|
|
146
|
+
if (dtlsTransport) {
|
|
147
|
+
// 候補は載せず、ICE / DTLS の識別子だけを残す
|
|
148
|
+
media.iceParams = dtlsTransport.iceTransport.localParameters;
|
|
149
|
+
media.dtlsParams = dtlsTransport.localParameters;
|
|
150
|
+
}
|
|
151
|
+
return media;
|
|
152
|
+
}
|
|
122
153
|
/**
|
|
123
154
|
* MediaDescriptionをSCTP用に作成
|
|
124
155
|
*/
|
|
@@ -142,7 +173,10 @@ class SDPManager {
|
|
|
142
173
|
media.host = const_1.DISCARD_HOST;
|
|
143
174
|
media.port = const_1.DISCARD_PORT;
|
|
144
175
|
if (media.direction === "inactive") {
|
|
145
|
-
|
|
176
|
+
// compatible は受け入れた inactive を拒否と区別するため非ゼロ port を保つ
|
|
177
|
+
if (this.mLineReuse === "aggressive") {
|
|
178
|
+
media.port = 0;
|
|
179
|
+
}
|
|
146
180
|
media.msids = [];
|
|
147
181
|
}
|
|
148
182
|
if (!media.dtlsParams) {
|
|
@@ -205,8 +239,11 @@ class SDPManager {
|
|
|
205
239
|
buildOfferSdp(transceivers, sctpTransport) {
|
|
206
240
|
const description = new sdp_1.SessionDescription();
|
|
207
241
|
(0, sdp_1.addSDPHeader)("offer", description);
|
|
242
|
+
const fallbackDtlsTransport = this.findLiveDtlsTransport(transceivers, sctpTransport);
|
|
208
243
|
// # handle existing transceivers / sctp
|
|
209
244
|
const currentMedia = this.currentLocalDescription?.media ?? [];
|
|
245
|
+
/**過去の m-line を引き継ぐ停止済みの位置 (新しい transceiver が再利用できる) */
|
|
246
|
+
const placeholderIndices = new Set();
|
|
210
247
|
currentMedia.forEach((m, i) => {
|
|
211
248
|
const mid = m.rtp.muxId;
|
|
212
249
|
if (!mid) {
|
|
@@ -222,28 +259,51 @@ class SDPManager {
|
|
|
222
259
|
else {
|
|
223
260
|
const transceiver = transceivers.find((t) => t.mid === mid);
|
|
224
261
|
if (!transceiver) {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
262
|
+
// 再利用で transceiver が外れた位置は、新しい transceiver が来るまで port 0 で保つ
|
|
263
|
+
placeholderIndices.add(i);
|
|
264
|
+
description.media.push(this.createRejectedMediaDescription({
|
|
265
|
+
kind: m.kind,
|
|
266
|
+
profile: m.profile,
|
|
267
|
+
fmt: m.fmt,
|
|
268
|
+
codecs: m.rtp.codecs,
|
|
269
|
+
mid,
|
|
270
|
+
}, fallbackDtlsTransport));
|
|
271
|
+
return;
|
|
230
272
|
}
|
|
231
273
|
transceiver.mLineIndex = i;
|
|
274
|
+
if (transceiver.stopping || transceiver.stopped) {
|
|
275
|
+
// stop() / 拒否の確定した m-line は自分の offer で port 0 にする
|
|
276
|
+
description.media.push(this.createRejectedMediaDescription({
|
|
277
|
+
kind: m.kind,
|
|
278
|
+
profile: m.profile,
|
|
279
|
+
fmt: m.fmt,
|
|
280
|
+
codecs: m.rtp.codecs,
|
|
281
|
+
mid,
|
|
282
|
+
}, this.liveTransportOr(transceiver.dtlsTransport, fallbackDtlsTransport)));
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
232
285
|
description.media.push(this.createMediaDescriptionForTransceiver(transceiver, transceiver.direction));
|
|
233
286
|
}
|
|
234
287
|
});
|
|
235
288
|
// # handle new transceivers / sctp
|
|
236
|
-
for (const transceiver of transceivers.filter((t) => !
|
|
289
|
+
for (const transceiver of transceivers.filter((t) => !t.stopping &&
|
|
290
|
+
!t.stopped &&
|
|
291
|
+
!description.media.find((m) => m.rtp.muxId === t.mid))) {
|
|
237
292
|
if (transceiver.mid == undefined) {
|
|
238
293
|
transceiver.mid = this.allocateMid(this.midSuffix ? "av" : "");
|
|
239
294
|
}
|
|
240
295
|
const mediaDescription = this.createMediaDescriptionForTransceiver(transceiver, transceiver.direction);
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
296
|
+
const reservedIndex = transceiver.mLineIndex;
|
|
297
|
+
if (reservedIndex != undefined &&
|
|
298
|
+
placeholderIndices.has(reservedIndex) &&
|
|
299
|
+
description.media[reservedIndex]?.kind === transceiver.kind) {
|
|
300
|
+
// 確定済みの port 0 位置を新しい MID で再利用する
|
|
301
|
+
placeholderIndices.delete(reservedIndex);
|
|
302
|
+
description.media[reservedIndex] = mediaDescription;
|
|
244
303
|
}
|
|
245
304
|
else {
|
|
246
|
-
|
|
305
|
+
transceiver.mLineIndex = description.media.length;
|
|
306
|
+
description.media.push(mediaDescription);
|
|
247
307
|
}
|
|
248
308
|
}
|
|
249
309
|
if (sctpTransport &&
|
|
@@ -255,16 +315,40 @@ class SDPManager {
|
|
|
255
315
|
description.media.push(this.createMediaDescriptionForSctp(sctpTransport));
|
|
256
316
|
}
|
|
257
317
|
if (this.bundlePolicy !== "disable") {
|
|
318
|
+
// RFC 8843: port 0 の m-line は BUNDLE group に含めない
|
|
258
319
|
const mids = description.media
|
|
320
|
+
.filter((m) => m.port !== 0)
|
|
259
321
|
.map((m) => m.rtp.muxId)
|
|
260
322
|
.filter((v) => v);
|
|
261
323
|
if (mids.length) {
|
|
262
|
-
const bundle = new sdp_1.GroupDescription("BUNDLE", mids);
|
|
324
|
+
const bundle = new sdp_1.GroupDescription("BUNDLE", orderBundleMids(mids, this.negotiatedBundleTag));
|
|
263
325
|
description.group.push(bundle);
|
|
264
326
|
}
|
|
265
327
|
}
|
|
266
328
|
return description;
|
|
267
329
|
}
|
|
330
|
+
liveTransportOr(dtlsTransport, fallback) {
|
|
331
|
+
return dtlsTransport && dtlsTransport.state !== "closed"
|
|
332
|
+
? dtlsTransport
|
|
333
|
+
: fallback;
|
|
334
|
+
}
|
|
335
|
+
findLiveDtlsTransport(transceivers, sctpTransport) {
|
|
336
|
+
return [
|
|
337
|
+
...transceivers
|
|
338
|
+
.filter((t) => !t.stopped && !t.pendingRejection)
|
|
339
|
+
.map((t) => t.dtlsTransport),
|
|
340
|
+
sctpTransport?.dtlsTransport,
|
|
341
|
+
...transceivers.map((t) => t.dtlsTransport),
|
|
342
|
+
].find((t) => !!t && t.state !== "closed");
|
|
343
|
+
}
|
|
344
|
+
/**確定済み answer の BUNDLE tag (先頭 MID) */
|
|
345
|
+
get negotiatedBundleTag() {
|
|
346
|
+
const answer = [
|
|
347
|
+
this.currentLocalDescription,
|
|
348
|
+
this.currentRemoteDescription,
|
|
349
|
+
].find((d) => d?.type === "answer");
|
|
350
|
+
return answer?.group.find((g) => g.semantic === "BUNDLE")?.items[0];
|
|
351
|
+
}
|
|
268
352
|
/**
|
|
269
353
|
* アンサーSDPを構築
|
|
270
354
|
*/
|
|
@@ -277,16 +361,39 @@ class SDPManager {
|
|
|
277
361
|
}
|
|
278
362
|
const description = new sdp_1.SessionDescription();
|
|
279
363
|
(0, sdp_1.addSDPHeader)("answer", description);
|
|
280
|
-
|
|
364
|
+
const remoteDescription = this._remoteDescription;
|
|
365
|
+
const fallbackDtlsTransport = this.findLiveDtlsTransport(transceivers, sctpTransport);
|
|
366
|
+
for (const remoteMedia of remoteDescription.media) {
|
|
281
367
|
let dtlsTransport;
|
|
282
368
|
let media;
|
|
369
|
+
let accepted = true;
|
|
283
370
|
if (["audio", "video"].includes(remoteMedia.kind)) {
|
|
284
|
-
const transceiver = transceivers.find((t) => t.mid === remoteMedia.rtp.muxId);
|
|
285
|
-
if (!transceiver) {
|
|
371
|
+
const transceiver = transceivers.find((t) => t.mid != undefined && t.mid === remoteMedia.rtp.muxId);
|
|
372
|
+
if (!transceiver && remoteMedia.port !== 0) {
|
|
286
373
|
throw new Error(`Transceiver with mid=${remoteMedia.rtp.muxId} not found`);
|
|
287
374
|
}
|
|
288
|
-
|
|
289
|
-
|
|
375
|
+
if (!transceiver ||
|
|
376
|
+
remoteMedia.port === 0 ||
|
|
377
|
+
transceiver.stopped ||
|
|
378
|
+
transceiver.pendingRejection) {
|
|
379
|
+
// 非対応 / remote port 0 / 停止確定の section は同じ位置で port 0 にする
|
|
380
|
+
accepted = false;
|
|
381
|
+
dtlsTransport = this.liveTransportOr(transceiver?.dtlsTransport, fallbackDtlsTransport);
|
|
382
|
+
media = this.createRejectedMediaDescription({
|
|
383
|
+
kind: remoteMedia.kind,
|
|
384
|
+
profile: remoteMedia.profile,
|
|
385
|
+
fmt: remoteMedia.fmt,
|
|
386
|
+
codecs: remoteMedia.rtp.codecs,
|
|
387
|
+
mid: remoteMedia.rtp.muxId,
|
|
388
|
+
}, dtlsTransport);
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
// answerer の stop() だけでは port 0 にせず、次の自分の offer で停止を交渉する
|
|
392
|
+
media = this.createMediaDescriptionForTransceiver(transceiver, transceiver.stopping
|
|
393
|
+
? "inactive"
|
|
394
|
+
: (0, utils_1.andDirection)(transceiver.direction, transceiver.offerDirection));
|
|
395
|
+
dtlsTransport = transceiver.dtlsTransport;
|
|
396
|
+
}
|
|
290
397
|
}
|
|
291
398
|
else if (remoteMedia.kind === "application") {
|
|
292
399
|
if (!sctpTransport || !sctpTransport.mid) {
|
|
@@ -299,7 +406,7 @@ class SDPManager {
|
|
|
299
406
|
throw new Error("invalid kind");
|
|
300
407
|
}
|
|
301
408
|
// # determine DTLS role, or preserve the currently configured role
|
|
302
|
-
if (media.dtlsParams) {
|
|
409
|
+
if (media.dtlsParams && dtlsTransport) {
|
|
303
410
|
if (dtlsTransport.role === "auto") {
|
|
304
411
|
media.dtlsParams.role = "client";
|
|
305
412
|
}
|
|
@@ -308,7 +415,8 @@ class SDPManager {
|
|
|
308
415
|
}
|
|
309
416
|
}
|
|
310
417
|
// Simulcastに関する処理
|
|
311
|
-
if (
|
|
418
|
+
if (accepted &&
|
|
419
|
+
remoteMedia.simulcastParameters &&
|
|
312
420
|
remoteMedia.simulcastParameters.length > 0) {
|
|
313
421
|
media.simulcastParameters = remoteMedia.simulcastParameters.map((v) => ({
|
|
314
422
|
...v,
|
|
@@ -318,15 +426,87 @@ class SDPManager {
|
|
|
318
426
|
description.media.push(media);
|
|
319
427
|
}
|
|
320
428
|
if (this.bundlePolicy !== "disable") {
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
429
|
+
description.group.push(...this.buildAnswerBundleGroups(remoteDescription, description));
|
|
430
|
+
}
|
|
431
|
+
return description;
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* RFC 8843 §7.3: offered BUNDLE group の member のうち受け入れた MID だけで
|
|
435
|
+
* answer の group を作る。確立済みの tag は保持し、初回 answer で
|
|
436
|
+
* offerer-tagged を拒否した場合は受け入れた先頭 member を answerer-tagged にする。
|
|
437
|
+
* 全 member を拒否した group は省略する。
|
|
438
|
+
*/
|
|
439
|
+
buildAnswerBundleGroups(remoteDescription, answer) {
|
|
440
|
+
const acceptedMids = new Set(answer.media
|
|
441
|
+
.filter((m) => m.port !== 0 && m.rtp.muxId)
|
|
442
|
+
.map((m) => m.rtp.muxId));
|
|
443
|
+
const negotiatedTag = this.negotiatedBundleTag;
|
|
444
|
+
return remoteDescription.group
|
|
445
|
+
.filter((group) => group.semantic === "BUNDLE")
|
|
446
|
+
.map((group) => group.items.filter((mid, index, items) => {
|
|
447
|
+
return acceptedMids.has(mid) && items.indexOf(mid) === index;
|
|
448
|
+
}))
|
|
449
|
+
.filter((mids) => mids.length > 0)
|
|
450
|
+
.map((mids) => new sdp_1.GroupDescription("BUNDLE", orderBundleMids(mids, negotiatedTag)));
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* remote answer / pranswer を適用する前の検証。
|
|
454
|
+
* 非ゼロ port の RTP m-line が pending local offer と共通 codec を持たなければ拒否する。
|
|
455
|
+
*/
|
|
456
|
+
assertRemoteAnswerCodecs(remoteSdp) {
|
|
457
|
+
if (!["answer", "pranswer"].includes(remoteSdp.type)) {
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
const offer = this.pendingLocalDescription;
|
|
461
|
+
if (!offer) {
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
remoteSdp.media.forEach((media, index) => {
|
|
465
|
+
if (!["audio", "video"].includes(media.kind) || media.port === 0) {
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
const offered = offer.media[index];
|
|
469
|
+
if (!offered || offered.port === 0 || offered.kind !== media.kind) {
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
const hasCommonCodec = media.rtp.codecs.some((codec) => codec.name.toLowerCase() !== "rtx" &&
|
|
473
|
+
offered.rtp.codecs.some((offeredCodec) => offeredCodec.mimeType.toLowerCase() ===
|
|
474
|
+
codec.mimeType.toLowerCase()));
|
|
475
|
+
if (!hasCommonCodec) {
|
|
476
|
+
throw (0, errors_1.createWebRtcDomException)("InvalidAccessError", `No common codec for m-line ${index} (mid=${media.rtp.muxId}) in remote ${remoteSdp.type}`);
|
|
477
|
+
}
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* 確立済み BUNDLE の transport を共有している m-line を、re-offer が
|
|
482
|
+
* group の外へ出したり別々の group に分割したりすることはできない
|
|
483
|
+
* (共有 transport を分割できない)。状態を変更する前に拒否する。
|
|
484
|
+
*/
|
|
485
|
+
assertBundlePreserved(remoteSdp) {
|
|
486
|
+
if (remoteSdp.type !== "offer" || this.bundlePolicy === "disable") {
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
const negotiatedGroups = [this.currentLocalDescription, this.currentRemoteDescription]
|
|
490
|
+
.find((d) => d?.type === "answer")
|
|
491
|
+
?.group.filter((g) => g.semantic === "BUNDLE") ?? [];
|
|
492
|
+
const offeredGroups = remoteSdp.group.filter((g) => g.semantic === "BUNDLE");
|
|
493
|
+
for (const negotiated of negotiatedGroups) {
|
|
494
|
+
let sharedGroup;
|
|
495
|
+
for (const mid of negotiated.items) {
|
|
496
|
+
const media = remoteSdp.media.find((m) => m.rtp.muxId === mid);
|
|
497
|
+
if (!media || media.port === 0) {
|
|
498
|
+
continue;
|
|
499
|
+
}
|
|
500
|
+
const offeredGroup = offeredGroups.find((g) => g.items.includes(mid));
|
|
501
|
+
if (!offeredGroup) {
|
|
502
|
+
throw (0, errors_1.createWebRtcDomException)("InvalidAccessError", `BUNDLE transport of mid=${mid} cannot be preserved by the remote offer`);
|
|
503
|
+
}
|
|
504
|
+
sharedGroup ?? (sharedGroup = offeredGroup);
|
|
505
|
+
if (offeredGroup !== sharedGroup) {
|
|
506
|
+
throw (0, errors_1.createWebRtcDomException)("InvalidAccessError", `BUNDLE transport of mid=${mid} cannot be split into another BUNDLE group by the remote offer`);
|
|
325
507
|
}
|
|
326
508
|
}
|
|
327
|
-
description.group.push(bundle);
|
|
328
509
|
}
|
|
329
|
-
return description;
|
|
330
510
|
}
|
|
331
511
|
setLocalDescription(description) {
|
|
332
512
|
if (description.type === "offer" || description.type === "pranswer") {
|
|
@@ -362,6 +542,9 @@ class SDPManager {
|
|
|
362
542
|
signalingState,
|
|
363
543
|
type: sessionDescription.type,
|
|
364
544
|
});
|
|
545
|
+
// 状態を変更する前に検証し、失敗時は signaling state / descriptions を保つ
|
|
546
|
+
this.assertRemoteAnswerCodecs(remoteSdp);
|
|
547
|
+
this.assertBundlePreserved(remoteSdp);
|
|
365
548
|
if (remoteSdp.type === "offer" || remoteSdp.type === "pranswer") {
|
|
366
549
|
this.pendingRemoteDescription = remoteSdp;
|
|
367
550
|
}
|
|
@@ -400,15 +583,31 @@ class SDPManager {
|
|
|
400
583
|
const transceiverByMLineIndex = new Map(transceivers.map((transceiver) => [transceiver?.mLineIndex, transceiver]));
|
|
401
584
|
const fallbackDtlsTransport = transceivers.find((transceiver) => transceiver?.dtlsTransport)
|
|
402
585
|
?.dtlsTransport ?? sctpTransport?.dtlsTransport;
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
.
|
|
406
|
-
|
|
586
|
+
// SCTP が RTP より先にある SDP でも元の m-line index で transceiver を引く
|
|
587
|
+
description.media.forEach((m, i) => {
|
|
588
|
+
if (!["audio", "video"].includes(m.kind)) {
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
591
|
+
const transceiver = transceivers.find((t) => t?.mid != undefined && t.mid === m.rtp.muxId) ?? transceiverByMLineIndex.get(i);
|
|
592
|
+
if (m.port === 0) {
|
|
593
|
+
const live = transceiver &&
|
|
594
|
+
!transceiver.stopping &&
|
|
595
|
+
!transceiver.stopped &&
|
|
596
|
+
!transceiver.pendingRejection;
|
|
597
|
+
if (!live) {
|
|
598
|
+
// 拒否 / 停止した m-line には transport 情報を追加しない
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
}
|
|
407
602
|
const dtlsTransport = transceiver?.dtlsTransport ?? fallbackDtlsTransport;
|
|
408
603
|
if (!dtlsTransport) {
|
|
409
604
|
throw new Error(`dtls transport not found for media index ${i}`);
|
|
410
605
|
}
|
|
606
|
+
const port = m.port;
|
|
411
607
|
this.addTransportDescription(m, dtlsTransport);
|
|
608
|
+
if (port === 0) {
|
|
609
|
+
m.port = 0;
|
|
610
|
+
}
|
|
412
611
|
});
|
|
413
612
|
const sctpMedia = description.media.find((m) => m.kind === "application");
|
|
414
613
|
if (sctpTransport && sctpMedia) {
|
|
@@ -418,4 +617,11 @@ class SDPManager {
|
|
|
418
617
|
}
|
|
419
618
|
}
|
|
420
619
|
exports.SDPManager = SDPManager;
|
|
620
|
+
/**確立済み tag が含まれていれば先頭に置き、それ以外は元の順序を保つ */
|
|
621
|
+
function orderBundleMids(mids, preferredTag) {
|
|
622
|
+
if (!preferredTag || !mids.includes(preferredTag)) {
|
|
623
|
+
return mids;
|
|
624
|
+
}
|
|
625
|
+
return [preferredTag, ...mids.filter((mid) => mid !== preferredTag)];
|
|
626
|
+
}
|
|
421
627
|
//# sourceMappingURL=sdpManager.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdpManager.js","sourceRoot":"","sources":["../../../src/sdpManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { DISCARD_HOST, DISCARD_PORT } from \"./const\";\nimport { createWebRtcDomException } from \"./errors\";\nimport type { RTCRtpTransceiver } from \"./media\";\nimport { RTCRtpSimulcastParameters } from \"./media/parameters\";\nimport type { MediaDirection } from \"./media/rtpTransceiver\";\nimport {\n type BundlePolicy,\n GroupDescription,\n MediaDescription,\n SessionDescription,\n SsrcDescription,\n addSDPHeader,\n} from \"./sdp\";\nimport type { RTCDtlsTransport } from \"./transport/dtls\";\nimport type { RTCSctpTransport } from \"./transport/sctp\";\nimport { andDirection } from \"./utils\";\n\nexport class SDPManager {\n currentLocalDescription?: SessionDescription;\n currentRemoteDescription?: SessionDescription;\n pendingLocalDescription?: SessionDescription;\n pendingRemoteDescription?: SessionDescription;\n readonly cname: string;\n readonly midSuffix: boolean;\n readonly bundlePolicy?: BundlePolicy;\n\n private seenMid = new Set<string>();\n\n constructor({\n cname,\n midSuffix,\n bundlePolicy,\n }: { cname: string; midSuffix?: boolean; bundlePolicy?: BundlePolicy }) {\n this.cname = cname;\n this.midSuffix = midSuffix ?? false;\n this.bundlePolicy = bundlePolicy;\n }\n\n get localDescription() {\n if (!this._localDescription) {\n return undefined;\n }\n return this._localDescription.toJSON();\n }\n\n get remoteDescription() {\n if (!this._remoteDescription) {\n return undefined;\n }\n return this._remoteDescription.toJSON();\n }\n\n /**@private */\n get _localDescription() {\n return this.pendingLocalDescription || this.currentLocalDescription;\n }\n\n /**@private */\n get _remoteDescription() {\n return this.pendingRemoteDescription || this.currentRemoteDescription;\n }\n\n get inactiveRemoteMedia() {\n return this._remoteDescription?.media?.find?.(\n (m) => m.direction === \"inactive\",\n );\n }\n\n /**\n * MediaDescriptionをトランシーバー用に作成\n */\n createMediaDescriptionForTransceiver(\n transceiver: RTCRtpTransceiver,\n direction: MediaDirection,\n ): MediaDescription {\n const media = new MediaDescription(\n transceiver.kind,\n 9,\n \"UDP/TLS/RTP/SAVPF\",\n transceiver.codecs.map((c) => c.payloadType),\n );\n media.direction = direction;\n media.msids = transceiver.msids;\n media.rtp = {\n codecs: transceiver.codecs,\n headerExtensions: transceiver.headerExtensions,\n muxId: transceiver.mid ?? undefined,\n };\n media.rtcpHost = \"0.0.0.0\";\n media.rtcpPort = 9;\n media.rtcpMux = true;\n media.ssrc = [\n new SsrcDescription({ ssrc: transceiver.sender.ssrc, cname: this.cname }),\n ];\n\n if (transceiver.options.simulcast) {\n media.simulcastParameters = transceiver.options.simulcast.map(\n (o) => new RTCRtpSimulcastParameters(o),\n );\n }\n\n if (media.rtp.codecs.find((c) => c.name.toLowerCase() === \"rtx\")) {\n media.ssrc.push(\n new SsrcDescription({\n ssrc: transceiver.sender.rtxSsrc,\n cname: this.cname,\n }),\n );\n media.ssrcGroup = [\n new GroupDescription(\"FID\", [\n transceiver.sender.ssrc.toString(),\n transceiver.sender.rtxSsrc.toString(),\n ]),\n ];\n }\n\n this.addTransportDescription(media, transceiver.dtlsTransport);\n return media;\n }\n\n /**\n * MediaDescriptionをSCTP用に作成\n */\n createMediaDescriptionForSctp(sctp: RTCSctpTransport): MediaDescription {\n const media = new MediaDescription(\n \"application\",\n DISCARD_PORT,\n \"UDP/DTLS/SCTP\",\n [\"webrtc-datachannel\"],\n );\n media.sctpPort = sctp.port;\n media.rtp.muxId = sctp.mid;\n media.sctpCapabilities = sctp.getCapabilities();\n\n this.addTransportDescription(media, sctp.dtlsTransport);\n return media;\n }\n\n /**\n * トランスポートの情報をMediaDescriptionに追加\n */\n addTransportDescription(\n media: MediaDescription,\n dtlsTransport: RTCDtlsTransport,\n ): void {\n const iceTransport = dtlsTransport.iceTransport;\n\n media.iceCandidates = iceTransport.localCandidates;\n media.iceCandidatesComplete = iceTransport.gatheringState === \"complete\";\n media.iceParams = iceTransport.localParameters;\n media.iceOptions = \"trickle\";\n\n media.host = DISCARD_HOST;\n media.port = DISCARD_PORT;\n\n if (media.direction === \"inactive\") {\n media.port = 0;\n media.msids = [];\n }\n\n if (!media.dtlsParams) {\n media.dtlsParams = dtlsTransport.localParameters;\n if (!media.dtlsParams.fingerprints) {\n media.dtlsParams.fingerprints =\n dtlsTransport.localParameters.fingerprints;\n }\n }\n }\n\n /**\n * 一意のMIDを割り当て\n */\n allocateMid(type: \"dc\" | \"av\" | \"\" = \"\"): string {\n let mid = \"\";\n for (let i = 0; ; ) {\n // rfc9143.html#name-security-considerations\n // SHOULD be 3 bytes or fewer to allow them to efficiently fit into the MID RTP header extension\n mid = (i++).toString() + type;\n if (!this.seenMid.has(mid)) break;\n }\n this.seenMid.add(mid);\n return mid;\n }\n\n parseSdp({\n sdp,\n isLocal,\n signalingState,\n type,\n }: {\n sdp: string;\n isLocal: boolean;\n signalingState: string;\n type: \"offer\" | \"answer\" | \"pranswer\";\n }): SessionDescription {\n const description = SessionDescription.parse(sdp);\n this.validateDescription({ description, isLocal, signalingState, type });\n description.type = type;\n return description;\n }\n\n private validateDescription({\n description,\n isLocal,\n signalingState,\n type,\n }: {\n description: SessionDescription;\n isLocal: boolean;\n signalingState: string;\n type: \"offer\" | \"answer\" | \"pranswer\";\n }) {\n if (isLocal) {\n if (type === \"offer\") {\n if (![\"stable\", \"have-local-offer\"].includes(signalingState))\n throw createWebRtcDomException(\n \"InvalidStateError\",\n \"Cannot handle offer in signaling state\",\n );\n } else if ([\"answer\", \"pranswer\"].includes(type)) {\n if (\n ![\"have-remote-offer\", \"have-local-pranswer\"].includes(signalingState)\n ) {\n throw createWebRtcDomException(\n \"InvalidStateError\",\n \"Cannot handle answer in signaling state\",\n );\n }\n }\n } else {\n if (type === \"offer\") {\n if (\n ![\"stable\", \"have-remote-offer\", \"have-local-offer\"].includes(\n signalingState,\n )\n ) {\n throw createWebRtcDomException(\n \"InvalidStateError\",\n \"Cannot handle offer in signaling state\",\n );\n }\n } else if ([\"answer\", \"pranswer\"].includes(type)) {\n if (\n ![\"have-local-offer\", \"have-remote-pranswer\"].includes(signalingState)\n ) {\n throw createWebRtcDomException(\n \"InvalidStateError\",\n \"Cannot handle answer in signaling state\",\n );\n }\n }\n }\n }\n\n /**\n * オファーSDPを構築\n */\n buildOfferSdp(\n transceivers: RTCRtpTransceiver[],\n sctpTransport: RTCSctpTransport | undefined,\n ): SessionDescription {\n const description = new SessionDescription();\n addSDPHeader(\"offer\", description);\n\n // # handle existing transceivers / sctp\n const currentMedia = this.currentLocalDescription?.media ?? [];\n\n currentMedia.forEach((m, i) => {\n const mid = m.rtp.muxId;\n if (!mid) {\n return;\n }\n if (m.kind === \"application\") {\n if (!sctpTransport) {\n throw new Error(\"sctpTransport not found\");\n }\n sctpTransport.mLineIndex = i;\n description.media.push(\n this.createMediaDescriptionForSctp(sctpTransport),\n );\n } else {\n const transceiver = transceivers.find((t) => t.mid === mid);\n if (!transceiver) {\n if (m.direction === \"inactive\") {\n description.media.push(m);\n return;\n }\n throw new Error(\"transceiver not found\");\n }\n transceiver.mLineIndex = i;\n description.media.push(\n this.createMediaDescriptionForTransceiver(\n transceiver,\n transceiver.direction,\n ),\n );\n }\n });\n\n // # handle new transceivers / sctp\n for (const transceiver of transceivers.filter(\n (t) => !description.media.find((m) => m.rtp.muxId === t.mid),\n )) {\n if (transceiver.mid == undefined) {\n transceiver.mid = this.allocateMid(this.midSuffix ? \"av\" : \"\");\n }\n const mediaDescription = this.createMediaDescriptionForTransceiver(\n transceiver,\n transceiver.direction,\n );\n if (transceiver.mLineIndex === undefined) {\n transceiver.mLineIndex = description.media.length;\n description.media.push(mediaDescription);\n } else {\n description.media[transceiver.mLineIndex] = mediaDescription;\n }\n }\n\n if (\n sctpTransport &&\n !description.media.find((m) => m.kind === \"application\")\n ) {\n sctpTransport.mLineIndex = description.media.length;\n if (sctpTransport.mid == undefined) {\n sctpTransport.mid = this.allocateMid(this.midSuffix ? \"dc\" : \"\");\n }\n description.media.push(this.createMediaDescriptionForSctp(sctpTransport));\n }\n\n if (this.bundlePolicy !== \"disable\") {\n const mids = description.media\n .map((m) => m.rtp.muxId)\n .filter((v) => v) as string[];\n if (mids.length) {\n const bundle = new GroupDescription(\"BUNDLE\", mids);\n description.group.push(bundle);\n }\n }\n\n return description;\n }\n\n /**\n * アンサーSDPを構築\n */\n buildAnswerSdp({\n transceivers,\n sctpTransport,\n signalingState,\n }: {\n transceivers: RTCRtpTransceiver[];\n sctpTransport: RTCSctpTransport | undefined;\n\n signalingState: string;\n }): SessionDescription {\n if (\n ![\"have-remote-offer\", \"have-local-pranswer\"].includes(signalingState)\n ) {\n throw new Error(\"createAnswer failed\");\n }\n if (!this._remoteDescription) {\n throw new Error(\"wrong state\");\n }\n\n const description = new SessionDescription();\n addSDPHeader(\"answer\", description);\n\n for (const remoteMedia of this._remoteDescription.media) {\n let dtlsTransport!: RTCDtlsTransport;\n let media: MediaDescription;\n\n if ([\"audio\", \"video\"].includes(remoteMedia.kind)) {\n const transceiver = transceivers.find(\n (t) => t.mid === remoteMedia.rtp.muxId,\n );\n if (!transceiver) {\n throw new Error(\n `Transceiver with mid=${remoteMedia.rtp.muxId} not found`,\n );\n }\n media = this.createMediaDescriptionForTransceiver(\n transceiver,\n andDirection(transceiver.direction, transceiver.offerDirection),\n );\n dtlsTransport = transceiver.dtlsTransport;\n } else if (remoteMedia.kind === \"application\") {\n if (!sctpTransport || !sctpTransport.mid) {\n throw new Error(\"sctpTransport not found\");\n }\n media = this.createMediaDescriptionForSctp(sctpTransport);\n\n dtlsTransport = sctpTransport.dtlsTransport;\n } else {\n throw new Error(\"invalid kind\");\n }\n\n // # determine DTLS role, or preserve the currently configured role\n if (media.dtlsParams) {\n if (dtlsTransport.role === \"auto\") {\n media.dtlsParams.role = \"client\";\n } else {\n media.dtlsParams.role = dtlsTransport.role;\n }\n }\n\n // Simulcastに関する処理\n if (\n remoteMedia.simulcastParameters &&\n remoteMedia.simulcastParameters.length > 0\n ) {\n media.simulcastParameters = remoteMedia.simulcastParameters.map(\n (v) => ({\n ...v,\n direction: v.direction === \"send\" ? \"recv\" : \"send\",\n }),\n );\n }\n\n description.media.push(media);\n }\n\n if (this.bundlePolicy !== \"disable\") {\n const bundle = new GroupDescription(\"BUNDLE\", []);\n for (const media of description.media) {\n if (media.rtp.muxId) {\n bundle.items.push(media.rtp.muxId!);\n }\n }\n description.group.push(bundle);\n }\n\n return description;\n }\n\n setLocalDescription(description: SessionDescription) {\n if (description.type === \"offer\" || description.type === \"pranswer\") {\n this.pendingLocalDescription = description;\n return;\n }\n\n this.currentLocalDescription = description;\n if (this.pendingRemoteDescription) {\n this.currentRemoteDescription = this.pendingRemoteDescription;\n }\n this.pendingLocalDescription = undefined;\n this.pendingRemoteDescription = undefined;\n }\n\n setRemoteDescription(\n sessionDescription: RTCSessionDescriptionInit,\n signalingState: string,\n ) {\n if (!sessionDescription.type) {\n throw new Error(\"invalid sessionDescription\");\n }\n\n if (sessionDescription.type === \"rollback\") {\n if (\n ![\"have-remote-offer\", \"have-local-pranswer\"].includes(signalingState)\n ) {\n throw createWebRtcDomException(\n \"InvalidStateError\",\n \"Cannot rollback remote description in signaling state\",\n );\n }\n this.pendingLocalDescription = undefined;\n this.pendingRemoteDescription = undefined;\n return;\n }\n\n if (!sessionDescription.sdp) {\n throw new Error(\"invalid sessionDescription\");\n }\n\n // # parse and validate description\n const remoteSdp = this.parseSdp({\n sdp: sessionDescription.sdp,\n isLocal: false,\n signalingState,\n type: sessionDescription.type,\n });\n\n if (remoteSdp.type === \"offer\" || remoteSdp.type === \"pranswer\") {\n this.pendingRemoteDescription = remoteSdp;\n } else {\n if (this.pendingLocalDescription) {\n this.currentLocalDescription = this.pendingLocalDescription;\n }\n this.currentRemoteDescription = remoteSdp;\n this.pendingRemoteDescription = undefined;\n this.pendingLocalDescription = undefined;\n }\n\n return remoteSdp;\n }\n\n rollbackLocalDescription(signalingState: string) {\n if (![\"have-local-offer\", \"have-local-pranswer\"].includes(signalingState)) {\n throw createWebRtcDomException(\n \"InvalidStateError\",\n \"Cannot rollback local description in signaling state\",\n );\n }\n this.pendingLocalDescription = undefined;\n this.pendingRemoteDescription = undefined;\n }\n\n registerMid(mid: string): void {\n this.seenMid.add(mid);\n }\n\n get remoteIsBundled() {\n const remoteSdp = this._remoteDescription;\n if (!remoteSdp) {\n return undefined;\n }\n const bundle = remoteSdp.group.find(\n (g) => g.semantic === \"BUNDLE\" && this.bundlePolicy !== \"disable\",\n );\n return bundle;\n }\n\n /**\n * ローカルセッション記述を設定し、トランスポート情報を追加する\n */\n setLocal(\n description: SessionDescription,\n transceivers: RTCRtpTransceiver[],\n sctpTransport?: { dtlsTransport: RTCDtlsTransport; mid?: string },\n ) {\n const transceiverByMLineIndex = new Map(\n transceivers.map((transceiver) => [transceiver?.mLineIndex, transceiver]),\n );\n const fallbackDtlsTransport =\n transceivers.find((transceiver) => transceiver?.dtlsTransport)\n ?.dtlsTransport ?? sctpTransport?.dtlsTransport;\n description.media\n .filter((m) => [\"audio\", \"video\"].includes(m.kind))\n .forEach((m, i) => {\n const transceiver = transceiverByMLineIndex.get(i) ?? transceivers[i];\n const dtlsTransport =\n transceiver?.dtlsTransport ?? fallbackDtlsTransport;\n if (!dtlsTransport) {\n throw new Error(`dtls transport not found for media index ${i}`);\n }\n this.addTransportDescription(m, dtlsTransport);\n });\n const sctpMedia = description.media.find((m) => m.kind === \"application\");\n if (sctpTransport && sctpMedia) {\n this.addTransportDescription(sctpMedia, sctpTransport.dtlsTransport);\n }\n\n this.setLocalDescription(description);\n }\n}\n\nexport interface RTCSessionDescriptionInit {\n sdp?: string;\n type?: RTCSdpType;\n}\nexport type RTCSdpType = \"answer\" | \"offer\" | \"pranswer\" | \"rollback\";\n"]}
|
|
1
|
+
{"version":3,"file":"sdpManager.js","sourceRoot":"","sources":["../../../src/sdpManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { DISCARD_HOST, DISCARD_PORT } from \"./const\";\nimport { createWebRtcDomException } from \"./errors\";\nimport type { RTCRtpTransceiver } from \"./media\";\nimport {\n type RTCRtpCodecParameters,\n RTCRtpSimulcastParameters,\n} from \"./media/parameters\";\nimport type { MediaDirection } from \"./media/rtpTransceiver\";\nimport {\n type BundlePolicy,\n GroupDescription,\n MediaDescription,\n SessionDescription,\n SsrcDescription,\n addSDPHeader,\n} from \"./sdp\";\nimport type { RTCDtlsTransport } from \"./transport/dtls\";\nimport type { RTCSctpTransport } from \"./transport/sctp\";\nimport { andDirection } from \"./utils\";\n\nexport class SDPManager {\n currentLocalDescription?: SessionDescription;\n currentRemoteDescription?: SessionDescription;\n pendingLocalDescription?: SessionDescription;\n pendingRemoteDescription?: SessionDescription;\n readonly cname: string;\n readonly midSuffix: boolean;\n readonly bundlePolicy?: BundlePolicy;\n readonly mLineReuse: MLineReuse;\n\n private seenMid = new Set<string>();\n\n constructor({\n cname,\n midSuffix,\n bundlePolicy,\n mLineReuse,\n }: {\n cname: string;\n midSuffix?: boolean;\n bundlePolicy?: BundlePolicy;\n mLineReuse?: MLineReuse;\n }) {\n this.cname = cname;\n this.midSuffix = midSuffix ?? false;\n this.bundlePolicy = bundlePolicy;\n this.mLineReuse = mLineReuse ?? \"compatible\";\n }\n\n get localDescription() {\n if (!this._localDescription) {\n return undefined;\n }\n return this._localDescription.toJSON();\n }\n\n get remoteDescription() {\n if (!this._remoteDescription) {\n return undefined;\n }\n return this._remoteDescription.toJSON();\n }\n\n /**@private */\n get _localDescription() {\n return this.pendingLocalDescription || this.currentLocalDescription;\n }\n\n /**@private */\n get _remoteDescription() {\n return this.pendingRemoteDescription || this.currentRemoteDescription;\n }\n\n get inactiveRemoteMedia() {\n return this._remoteDescription?.media?.find?.(\n (m) => m.direction === \"inactive\",\n );\n }\n\n /**\n * MediaDescriptionをトランシーバー用に作成\n */\n createMediaDescriptionForTransceiver(\n transceiver: RTCRtpTransceiver,\n direction: MediaDirection,\n ): MediaDescription {\n const media = new MediaDescription(\n transceiver.kind,\n 9,\n \"UDP/TLS/RTP/SAVPF\",\n transceiver.codecs.map((c) => c.payloadType),\n );\n media.direction = direction;\n media.msids = transceiver.msids;\n media.rtp = {\n codecs: transceiver.codecs,\n headerExtensions: transceiver.headerExtensions,\n muxId: transceiver.mid ?? undefined,\n };\n media.rtcpHost = \"0.0.0.0\";\n media.rtcpPort = 9;\n media.rtcpMux = true;\n media.ssrc = [\n new SsrcDescription({ ssrc: transceiver.sender.ssrc, cname: this.cname }),\n ];\n\n if (transceiver.options.simulcast) {\n media.simulcastParameters = transceiver.options.simulcast.map(\n (o) => new RTCRtpSimulcastParameters(o),\n );\n }\n\n if (media.rtp.codecs.find((c) => c.name.toLowerCase() === \"rtx\")) {\n media.ssrc.push(\n new SsrcDescription({\n ssrc: transceiver.sender.rtxSsrc,\n cname: this.cname,\n }),\n );\n media.ssrcGroup = [\n new GroupDescription(\"FID\", [\n transceiver.sender.ssrc.toString(),\n transceiver.sender.rtxSsrc.toString(),\n ]),\n ];\n }\n\n this.addTransportDescription(media, transceiver.dtlsTransport);\n return media;\n }\n\n /**\n * 拒否 / 停止した m-line を作成する (RFC 3264 §6 / RFC 8829 §5.3.1)。\n * port は 0、proto と MID は元の m-line を保ち、fmt は少なくとも 1 token 残す。\n */\n createRejectedMediaDescription(\n source: {\n kind: MediaDescription[\"kind\"];\n profile: string;\n fmt: (string | number)[];\n codecs: RTCRtpCodecParameters[];\n mid?: string;\n },\n dtlsTransport?: RTCDtlsTransport,\n ): MediaDescription {\n const format = source.fmt[0] ?? source.codecs[0]?.payloadType ?? 0;\n const media = new MediaDescription(source.kind, 0, source.profile, [\n format,\n ] as string[] | number[]);\n media.host = DISCARD_HOST;\n media.direction = \"inactive\";\n media.rtp = {\n codecs: source.codecs.filter(\n (codec) => codec.payloadType?.toString() === format.toString(),\n ),\n headerExtensions: [],\n muxId: source.mid,\n };\n media.rtcpMux = true;\n if (dtlsTransport) {\n // 候補は載せず、ICE / DTLS の識別子だけを残す\n media.iceParams = dtlsTransport.iceTransport.localParameters;\n media.dtlsParams = dtlsTransport.localParameters;\n }\n return media;\n }\n\n /**\n * MediaDescriptionをSCTP用に作成\n */\n createMediaDescriptionForSctp(sctp: RTCSctpTransport): MediaDescription {\n const media = new MediaDescription(\n \"application\",\n DISCARD_PORT,\n \"UDP/DTLS/SCTP\",\n [\"webrtc-datachannel\"],\n );\n media.sctpPort = sctp.port;\n media.rtp.muxId = sctp.mid;\n media.sctpCapabilities = sctp.getCapabilities();\n\n this.addTransportDescription(media, sctp.dtlsTransport);\n return media;\n }\n\n /**\n * トランスポートの情報をMediaDescriptionに追加\n */\n addTransportDescription(\n media: MediaDescription,\n dtlsTransport: RTCDtlsTransport,\n ): void {\n const iceTransport = dtlsTransport.iceTransport;\n\n media.iceCandidates = iceTransport.localCandidates;\n media.iceCandidatesComplete = iceTransport.gatheringState === \"complete\";\n media.iceParams = iceTransport.localParameters;\n media.iceOptions = \"trickle\";\n\n media.host = DISCARD_HOST;\n media.port = DISCARD_PORT;\n\n if (media.direction === \"inactive\") {\n // compatible は受け入れた inactive を拒否と区別するため非ゼロ port を保つ\n if (this.mLineReuse === \"aggressive\") {\n media.port = 0;\n }\n media.msids = [];\n }\n\n if (!media.dtlsParams) {\n media.dtlsParams = dtlsTransport.localParameters;\n if (!media.dtlsParams.fingerprints) {\n media.dtlsParams.fingerprints =\n dtlsTransport.localParameters.fingerprints;\n }\n }\n }\n\n /**\n * 一意のMIDを割り当て\n */\n allocateMid(type: \"dc\" | \"av\" | \"\" = \"\"): string {\n let mid = \"\";\n for (let i = 0; ; ) {\n // rfc9143.html#name-security-considerations\n // SHOULD be 3 bytes or fewer to allow them to efficiently fit into the MID RTP header extension\n mid = (i++).toString() + type;\n if (!this.seenMid.has(mid)) break;\n }\n this.seenMid.add(mid);\n return mid;\n }\n\n parseSdp({\n sdp,\n isLocal,\n signalingState,\n type,\n }: {\n sdp: string;\n isLocal: boolean;\n signalingState: string;\n type: \"offer\" | \"answer\" | \"pranswer\";\n }): SessionDescription {\n const description = SessionDescription.parse(sdp);\n this.validateDescription({ description, isLocal, signalingState, type });\n description.type = type;\n return description;\n }\n\n private validateDescription({\n description,\n isLocal,\n signalingState,\n type,\n }: {\n description: SessionDescription;\n isLocal: boolean;\n signalingState: string;\n type: \"offer\" | \"answer\" | \"pranswer\";\n }) {\n if (isLocal) {\n if (type === \"offer\") {\n if (![\"stable\", \"have-local-offer\"].includes(signalingState))\n throw createWebRtcDomException(\n \"InvalidStateError\",\n \"Cannot handle offer in signaling state\",\n );\n } else if ([\"answer\", \"pranswer\"].includes(type)) {\n if (\n ![\"have-remote-offer\", \"have-local-pranswer\"].includes(signalingState)\n ) {\n throw createWebRtcDomException(\n \"InvalidStateError\",\n \"Cannot handle answer in signaling state\",\n );\n }\n }\n } else {\n if (type === \"offer\") {\n if (\n ![\"stable\", \"have-remote-offer\", \"have-local-offer\"].includes(\n signalingState,\n )\n ) {\n throw createWebRtcDomException(\n \"InvalidStateError\",\n \"Cannot handle offer in signaling state\",\n );\n }\n } else if ([\"answer\", \"pranswer\"].includes(type)) {\n if (\n ![\"have-local-offer\", \"have-remote-pranswer\"].includes(signalingState)\n ) {\n throw createWebRtcDomException(\n \"InvalidStateError\",\n \"Cannot handle answer in signaling state\",\n );\n }\n }\n }\n }\n\n /**\n * オファーSDPを構築\n */\n buildOfferSdp(\n transceivers: RTCRtpTransceiver[],\n sctpTransport: RTCSctpTransport | undefined,\n ): SessionDescription {\n const description = new SessionDescription();\n addSDPHeader(\"offer\", description);\n\n const fallbackDtlsTransport = this.findLiveDtlsTransport(\n transceivers,\n sctpTransport,\n );\n\n // # handle existing transceivers / sctp\n const currentMedia = this.currentLocalDescription?.media ?? [];\n /**過去の m-line を引き継ぐ停止済みの位置 (新しい transceiver が再利用できる) */\n const placeholderIndices = new Set<number>();\n\n currentMedia.forEach((m, i) => {\n const mid = m.rtp.muxId;\n if (!mid) {\n return;\n }\n if (m.kind === \"application\") {\n if (!sctpTransport) {\n throw new Error(\"sctpTransport not found\");\n }\n sctpTransport.mLineIndex = i;\n description.media.push(\n this.createMediaDescriptionForSctp(sctpTransport),\n );\n } else {\n const transceiver = transceivers.find((t) => t.mid === mid);\n if (!transceiver) {\n // 再利用で transceiver が外れた位置は、新しい transceiver が来るまで port 0 で保つ\n placeholderIndices.add(i);\n description.media.push(\n this.createRejectedMediaDescription(\n {\n kind: m.kind,\n profile: m.profile,\n fmt: m.fmt,\n codecs: m.rtp.codecs,\n mid,\n },\n fallbackDtlsTransport,\n ),\n );\n return;\n }\n transceiver.mLineIndex = i;\n if (transceiver.stopping || transceiver.stopped) {\n // stop() / 拒否の確定した m-line は自分の offer で port 0 にする\n description.media.push(\n this.createRejectedMediaDescription(\n {\n kind: m.kind,\n profile: m.profile,\n fmt: m.fmt,\n codecs: m.rtp.codecs,\n mid,\n },\n this.liveTransportOr(\n transceiver.dtlsTransport,\n fallbackDtlsTransport,\n ),\n ),\n );\n return;\n }\n description.media.push(\n this.createMediaDescriptionForTransceiver(\n transceiver,\n transceiver.direction,\n ),\n );\n }\n });\n\n // # handle new transceivers / sctp\n for (const transceiver of transceivers.filter(\n (t) =>\n !t.stopping &&\n !t.stopped &&\n !description.media.find((m) => m.rtp.muxId === t.mid),\n )) {\n if (transceiver.mid == undefined) {\n transceiver.mid = this.allocateMid(this.midSuffix ? \"av\" : \"\");\n }\n const mediaDescription = this.createMediaDescriptionForTransceiver(\n transceiver,\n transceiver.direction,\n );\n const reservedIndex = transceiver.mLineIndex;\n if (\n reservedIndex != undefined &&\n placeholderIndices.has(reservedIndex) &&\n description.media[reservedIndex]?.kind === transceiver.kind\n ) {\n // 確定済みの port 0 位置を新しい MID で再利用する\n placeholderIndices.delete(reservedIndex);\n description.media[reservedIndex] = mediaDescription;\n } else {\n transceiver.mLineIndex = description.media.length;\n description.media.push(mediaDescription);\n }\n }\n\n if (\n sctpTransport &&\n !description.media.find((m) => m.kind === \"application\")\n ) {\n sctpTransport.mLineIndex = description.media.length;\n if (sctpTransport.mid == undefined) {\n sctpTransport.mid = this.allocateMid(this.midSuffix ? \"dc\" : \"\");\n }\n description.media.push(this.createMediaDescriptionForSctp(sctpTransport));\n }\n\n if (this.bundlePolicy !== \"disable\") {\n // RFC 8843: port 0 の m-line は BUNDLE group に含めない\n const mids = description.media\n .filter((m) => m.port !== 0)\n .map((m) => m.rtp.muxId)\n .filter((v) => v) as string[];\n if (mids.length) {\n const bundle = new GroupDescription(\n \"BUNDLE\",\n orderBundleMids(mids, this.negotiatedBundleTag),\n );\n description.group.push(bundle);\n }\n }\n\n return description;\n }\n\n private liveTransportOr(\n dtlsTransport: RTCDtlsTransport | undefined,\n fallback: RTCDtlsTransport | undefined,\n ) {\n return dtlsTransport && dtlsTransport.state !== \"closed\"\n ? dtlsTransport\n : fallback;\n }\n\n private findLiveDtlsTransport(\n transceivers: RTCRtpTransceiver[],\n sctpTransport: RTCSctpTransport | undefined,\n ) {\n return [\n ...transceivers\n .filter((t) => !t.stopped && !t.pendingRejection)\n .map((t) => t.dtlsTransport),\n sctpTransport?.dtlsTransport,\n ...transceivers.map((t) => t.dtlsTransport),\n ].find((t): t is RTCDtlsTransport => !!t && t.state !== \"closed\");\n }\n\n /**確定済み answer の BUNDLE tag (先頭 MID) */\n get negotiatedBundleTag(): string | undefined {\n const answer = [\n this.currentLocalDescription,\n this.currentRemoteDescription,\n ].find((d) => d?.type === \"answer\");\n return answer?.group.find((g) => g.semantic === \"BUNDLE\")?.items[0];\n }\n\n /**\n * アンサーSDPを構築\n */\n buildAnswerSdp({\n transceivers,\n sctpTransport,\n signalingState,\n }: {\n transceivers: RTCRtpTransceiver[];\n sctpTransport: RTCSctpTransport | undefined;\n\n signalingState: string;\n }): SessionDescription {\n if (\n ![\"have-remote-offer\", \"have-local-pranswer\"].includes(signalingState)\n ) {\n throw new Error(\"createAnswer failed\");\n }\n if (!this._remoteDescription) {\n throw new Error(\"wrong state\");\n }\n\n const description = new SessionDescription();\n addSDPHeader(\"answer\", description);\n\n const remoteDescription = this._remoteDescription;\n const fallbackDtlsTransport = this.findLiveDtlsTransport(\n transceivers,\n sctpTransport,\n );\n\n for (const remoteMedia of remoteDescription.media) {\n let dtlsTransport: RTCDtlsTransport | undefined;\n let media: MediaDescription;\n let accepted = true;\n\n if ([\"audio\", \"video\"].includes(remoteMedia.kind)) {\n const transceiver = transceivers.find(\n (t) => t.mid != undefined && t.mid === remoteMedia.rtp.muxId,\n );\n if (!transceiver && remoteMedia.port !== 0) {\n throw new Error(\n `Transceiver with mid=${remoteMedia.rtp.muxId} not found`,\n );\n }\n if (\n !transceiver ||\n remoteMedia.port === 0 ||\n transceiver.stopped ||\n transceiver.pendingRejection\n ) {\n // 非対応 / remote port 0 / 停止確定の section は同じ位置で port 0 にする\n accepted = false;\n dtlsTransport = this.liveTransportOr(\n transceiver?.dtlsTransport,\n fallbackDtlsTransport,\n );\n media = this.createRejectedMediaDescription(\n {\n kind: remoteMedia.kind,\n profile: remoteMedia.profile,\n fmt: remoteMedia.fmt,\n codecs: remoteMedia.rtp.codecs,\n mid: remoteMedia.rtp.muxId,\n },\n dtlsTransport,\n );\n } else {\n // answerer の stop() だけでは port 0 にせず、次の自分の offer で停止を交渉する\n media = this.createMediaDescriptionForTransceiver(\n transceiver,\n transceiver.stopping\n ? \"inactive\"\n : andDirection(transceiver.direction, transceiver.offerDirection),\n );\n dtlsTransport = transceiver.dtlsTransport;\n }\n } else if (remoteMedia.kind === \"application\") {\n if (!sctpTransport || !sctpTransport.mid) {\n throw new Error(\"sctpTransport not found\");\n }\n media = this.createMediaDescriptionForSctp(sctpTransport);\n\n dtlsTransport = sctpTransport.dtlsTransport;\n } else {\n throw new Error(\"invalid kind\");\n }\n\n // # determine DTLS role, or preserve the currently configured role\n if (media.dtlsParams && dtlsTransport) {\n if (dtlsTransport.role === \"auto\") {\n media.dtlsParams.role = \"client\";\n } else {\n media.dtlsParams.role = dtlsTransport.role;\n }\n }\n\n // Simulcastに関する処理\n if (\n accepted &&\n remoteMedia.simulcastParameters &&\n remoteMedia.simulcastParameters.length > 0\n ) {\n media.simulcastParameters = remoteMedia.simulcastParameters.map(\n (v) => ({\n ...v,\n direction: v.direction === \"send\" ? \"recv\" : \"send\",\n }),\n );\n }\n\n description.media.push(media);\n }\n\n if (this.bundlePolicy !== \"disable\") {\n description.group.push(\n ...this.buildAnswerBundleGroups(remoteDescription, description),\n );\n }\n\n return description;\n }\n\n /**\n * RFC 8843 §7.3: offered BUNDLE group の member のうち受け入れた MID だけで\n * answer の group を作る。確立済みの tag は保持し、初回 answer で\n * offerer-tagged を拒否した場合は受け入れた先頭 member を answerer-tagged にする。\n * 全 member を拒否した group は省略する。\n */\n private buildAnswerBundleGroups(\n remoteDescription: SessionDescription,\n answer: SessionDescription,\n ) {\n const acceptedMids = new Set(\n answer.media\n .filter((m) => m.port !== 0 && m.rtp.muxId)\n .map((m) => m.rtp.muxId!),\n );\n const negotiatedTag = this.negotiatedBundleTag;\n\n return remoteDescription.group\n .filter((group) => group.semantic === \"BUNDLE\")\n .map((group) =>\n group.items.filter((mid, index, items) => {\n return acceptedMids.has(mid) && items.indexOf(mid) === index;\n }),\n )\n .filter((mids) => mids.length > 0)\n .map(\n (mids) =>\n new GroupDescription(\"BUNDLE\", orderBundleMids(mids, negotiatedTag)),\n );\n }\n\n /**\n * remote answer / pranswer を適用する前の検証。\n * 非ゼロ port の RTP m-line が pending local offer と共通 codec を持たなければ拒否する。\n */\n private assertRemoteAnswerCodecs(remoteSdp: SessionDescription) {\n if (![\"answer\", \"pranswer\"].includes(remoteSdp.type)) {\n return;\n }\n const offer = this.pendingLocalDescription;\n if (!offer) {\n return;\n }\n remoteSdp.media.forEach((media, index) => {\n if (![\"audio\", \"video\"].includes(media.kind) || media.port === 0) {\n return;\n }\n const offered = offer.media[index];\n if (!offered || offered.port === 0 || offered.kind !== media.kind) {\n return;\n }\n const hasCommonCodec = media.rtp.codecs.some(\n (codec) =>\n codec.name.toLowerCase() !== \"rtx\" &&\n offered.rtp.codecs.some(\n (offeredCodec) =>\n offeredCodec.mimeType.toLowerCase() ===\n codec.mimeType.toLowerCase(),\n ),\n );\n if (!hasCommonCodec) {\n throw createWebRtcDomException(\n \"InvalidAccessError\",\n `No common codec for m-line ${index} (mid=${media.rtp.muxId}) in remote ${remoteSdp.type}`,\n );\n }\n });\n }\n\n /**\n * 確立済み BUNDLE の transport を共有している m-line を、re-offer が\n * group の外へ出したり別々の group に分割したりすることはできない\n * (共有 transport を分割できない)。状態を変更する前に拒否する。\n */\n private assertBundlePreserved(remoteSdp: SessionDescription) {\n if (remoteSdp.type !== \"offer\" || this.bundlePolicy === \"disable\") {\n return;\n }\n const negotiatedGroups =\n [this.currentLocalDescription, this.currentRemoteDescription]\n .find((d) => d?.type === \"answer\")\n ?.group.filter((g) => g.semantic === \"BUNDLE\") ?? [];\n const offeredGroups = remoteSdp.group.filter(\n (g) => g.semantic === \"BUNDLE\",\n );\n for (const negotiated of negotiatedGroups) {\n let sharedGroup: GroupDescription | undefined;\n for (const mid of negotiated.items) {\n const media = remoteSdp.media.find((m) => m.rtp.muxId === mid);\n if (!media || media.port === 0) {\n continue;\n }\n const offeredGroup = offeredGroups.find((g) => g.items.includes(mid));\n if (!offeredGroup) {\n throw createWebRtcDomException(\n \"InvalidAccessError\",\n `BUNDLE transport of mid=${mid} cannot be preserved by the remote offer`,\n );\n }\n sharedGroup ??= offeredGroup;\n if (offeredGroup !== sharedGroup) {\n throw createWebRtcDomException(\n \"InvalidAccessError\",\n `BUNDLE transport of mid=${mid} cannot be split into another BUNDLE group by the remote offer`,\n );\n }\n }\n }\n }\n\n setLocalDescription(description: SessionDescription) {\n if (description.type === \"offer\" || description.type === \"pranswer\") {\n this.pendingLocalDescription = description;\n return;\n }\n\n this.currentLocalDescription = description;\n if (this.pendingRemoteDescription) {\n this.currentRemoteDescription = this.pendingRemoteDescription;\n }\n this.pendingLocalDescription = undefined;\n this.pendingRemoteDescription = undefined;\n }\n\n setRemoteDescription(\n sessionDescription: RTCSessionDescriptionInit,\n signalingState: string,\n ) {\n if (!sessionDescription.type) {\n throw new Error(\"invalid sessionDescription\");\n }\n\n if (sessionDescription.type === \"rollback\") {\n if (\n ![\"have-remote-offer\", \"have-local-pranswer\"].includes(signalingState)\n ) {\n throw createWebRtcDomException(\n \"InvalidStateError\",\n \"Cannot rollback remote description in signaling state\",\n );\n }\n this.pendingLocalDescription = undefined;\n this.pendingRemoteDescription = undefined;\n return;\n }\n\n if (!sessionDescription.sdp) {\n throw new Error(\"invalid sessionDescription\");\n }\n\n // # parse and validate description\n const remoteSdp = this.parseSdp({\n sdp: sessionDescription.sdp,\n isLocal: false,\n signalingState,\n type: sessionDescription.type,\n });\n // 状態を変更する前に検証し、失敗時は signaling state / descriptions を保つ\n this.assertRemoteAnswerCodecs(remoteSdp);\n this.assertBundlePreserved(remoteSdp);\n\n if (remoteSdp.type === \"offer\" || remoteSdp.type === \"pranswer\") {\n this.pendingRemoteDescription = remoteSdp;\n } else {\n if (this.pendingLocalDescription) {\n this.currentLocalDescription = this.pendingLocalDescription;\n }\n this.currentRemoteDescription = remoteSdp;\n this.pendingRemoteDescription = undefined;\n this.pendingLocalDescription = undefined;\n }\n\n return remoteSdp;\n }\n\n rollbackLocalDescription(signalingState: string) {\n if (![\"have-local-offer\", \"have-local-pranswer\"].includes(signalingState)) {\n throw createWebRtcDomException(\n \"InvalidStateError\",\n \"Cannot rollback local description in signaling state\",\n );\n }\n this.pendingLocalDescription = undefined;\n this.pendingRemoteDescription = undefined;\n }\n\n registerMid(mid: string): void {\n this.seenMid.add(mid);\n }\n\n get remoteIsBundled() {\n const remoteSdp = this._remoteDescription;\n if (!remoteSdp) {\n return undefined;\n }\n const bundle = remoteSdp.group.find(\n (g) => g.semantic === \"BUNDLE\" && this.bundlePolicy !== \"disable\",\n );\n return bundle;\n }\n\n /**\n * ローカルセッション記述を設定し、トランスポート情報を追加する\n */\n setLocal(\n description: SessionDescription,\n transceivers: RTCRtpTransceiver[],\n sctpTransport?: { dtlsTransport: RTCDtlsTransport; mid?: string },\n ) {\n const transceiverByMLineIndex = new Map(\n transceivers.map((transceiver) => [transceiver?.mLineIndex, transceiver]),\n );\n const fallbackDtlsTransport =\n transceivers.find((transceiver) => transceiver?.dtlsTransport)\n ?.dtlsTransport ?? sctpTransport?.dtlsTransport;\n // SCTP が RTP より先にある SDP でも元の m-line index で transceiver を引く\n description.media.forEach((m, i) => {\n if (![\"audio\", \"video\"].includes(m.kind)) {\n return;\n }\n const transceiver =\n transceivers.find(\n (t) => t?.mid != undefined && t.mid === m.rtp.muxId,\n ) ?? transceiverByMLineIndex.get(i);\n if (m.port === 0) {\n const live =\n transceiver &&\n !transceiver.stopping &&\n !transceiver.stopped &&\n !transceiver.pendingRejection;\n if (!live) {\n // 拒否 / 停止した m-line には transport 情報を追加しない\n return;\n }\n }\n const dtlsTransport = transceiver?.dtlsTransport ?? fallbackDtlsTransport;\n if (!dtlsTransport) {\n throw new Error(`dtls transport not found for media index ${i}`);\n }\n const port = m.port;\n this.addTransportDescription(m, dtlsTransport);\n if (port === 0) {\n m.port = 0;\n }\n });\n const sctpMedia = description.media.find((m) => m.kind === \"application\");\n if (sctpTransport && sctpMedia) {\n this.addTransportDescription(sctpMedia, sctpTransport.dtlsTransport);\n }\n\n this.setLocalDescription(description);\n }\n}\n\n/**確立済み tag が含まれていれば先頭に置き、それ以外は元の順序を保つ */\nfunction orderBundleMids(mids: string[], preferredTag?: string) {\n if (!preferredTag || !mids.includes(preferredTag)) {\n return mids;\n }\n return [preferredTag, ...mids.filter((mid) => mid !== preferredTag)];\n}\n\nexport type MLineReuse = \"compatible\" | \"aggressive\";\n\nexport interface RTCSessionDescriptionInit {\n sdp?: string;\n type?: RTCSdpType;\n}\nexport type RTCSdpType = \"answer\" | \"offer\" | \"pranswer\" | \"rollback\";\n"]}
|