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.
Files changed (168) hide show
  1. package/README.md +116 -113
  2. package/lib/common/src/event.js +2 -1
  3. package/lib/common/src/event.js.map +1 -1
  4. package/lib/common/src/transport.d.ts +22 -2
  5. package/lib/common/src/transport.js +84 -26
  6. package/lib/common/src/transport.js.map +1 -1
  7. package/lib/ice/src/exceptions.d.ts +9 -0
  8. package/lib/ice/src/exceptions.js +23 -1
  9. package/lib/ice/src/exceptions.js.map +1 -1
  10. package/lib/ice/src/ice.d.ts +40 -0
  11. package/lib/ice/src/ice.js +194 -28
  12. package/lib/ice/src/ice.js.map +1 -1
  13. package/lib/ice/src/iceBase.d.ts +26 -0
  14. package/lib/ice/src/iceBase.js.map +1 -1
  15. package/lib/ice/src/stun/const.d.ts +7 -0
  16. package/lib/ice/src/stun/const.js +8 -0
  17. package/lib/ice/src/stun/const.js.map +1 -1
  18. package/lib/ice/src/stun/protocol.js +1 -4
  19. package/lib/ice/src/stun/protocol.js.map +1 -1
  20. package/lib/ice/src/stun/tcpProtocol.d.ts +7 -1
  21. package/lib/ice/src/stun/tcpProtocol.js +65 -14
  22. package/lib/ice/src/stun/tcpProtocol.js.map +1 -1
  23. package/lib/ice/src/stun/transaction.d.ts +12 -1
  24. package/lib/ice/src/stun/transaction.js +37 -4
  25. package/lib/ice/src/stun/transaction.js.map +1 -1
  26. package/lib/ice/src/turn/protocol.d.ts +79 -22
  27. package/lib/ice/src/turn/protocol.js +282 -78
  28. package/lib/ice/src/turn/protocol.js.map +1 -1
  29. package/lib/ice/src/types/model.d.ts +8 -0
  30. package/lib/ice/src/types/model.js.map +1 -1
  31. package/lib/index.mjs +5646 -3451
  32. package/lib/nonstandard/index.mjs +287 -1004
  33. package/lib/polyfill/dom.mjs +23794 -0
  34. package/lib/polyfill/index.mjs +23794 -0
  35. package/lib/rtp/src/extra/container/mp4/container.js +12 -4
  36. package/lib/rtp/src/extra/container/mp4/container.js.map +1 -1
  37. package/lib/rtp/src/extra/processor/mp4.js +8 -3
  38. package/lib/rtp/src/extra/processor/mp4.js.map +1 -1
  39. package/lib/rtp/src/extra/processor/mp4Callback.js +3 -1
  40. package/lib/rtp/src/extra/processor/mp4Callback.js.map +1 -1
  41. package/lib/sctp/src/chunk.d.ts +5 -0
  42. package/lib/sctp/src/chunk.js +16 -11
  43. package/lib/sctp/src/chunk.js.map +1 -1
  44. package/lib/sctp/src/index.d.ts +3 -1
  45. package/lib/sctp/src/index.js +10 -1
  46. package/lib/sctp/src/index.js.map +1 -1
  47. package/lib/sctp/src/sctp.d.ts +12 -3
  48. package/lib/sctp/src/sctp.js +51 -18
  49. package/lib/sctp/src/sctp.js.map +1 -1
  50. package/lib/webrtc/src/const.js +2 -0
  51. package/lib/webrtc/src/const.js.map +1 -1
  52. package/lib/webrtc/src/errors.d.ts +9 -1
  53. package/lib/webrtc/src/errors.js +19 -0
  54. package/lib/webrtc/src/errors.js.map +1 -1
  55. package/lib/webrtc/src/media/codec.d.ts +5 -0
  56. package/lib/webrtc/src/media/codec.js +21 -0
  57. package/lib/webrtc/src/media/codec.js.map +1 -1
  58. package/lib/webrtc/src/media/codecCompatibility.d.ts +23 -0
  59. package/lib/webrtc/src/media/codecCompatibility.js +138 -0
  60. package/lib/webrtc/src/media/codecCompatibility.js.map +1 -0
  61. package/lib/webrtc/src/media/index.d.ts +1 -0
  62. package/lib/webrtc/src/media/index.js +1 -0
  63. package/lib/webrtc/src/media/index.js.map +1 -1
  64. package/lib/webrtc/src/media/router.d.ts +2 -0
  65. package/lib/webrtc/src/media/router.js +23 -3
  66. package/lib/webrtc/src/media/router.js.map +1 -1
  67. package/lib/webrtc/src/media/rtpReceiver.d.ts +12 -0
  68. package/lib/webrtc/src/media/rtpReceiver.js +35 -0
  69. package/lib/webrtc/src/media/rtpReceiver.js.map +1 -1
  70. package/lib/webrtc/src/media/rtpSender.d.ts +65 -4
  71. package/lib/webrtc/src/media/rtpSender.js +264 -35
  72. package/lib/webrtc/src/media/rtpSender.js.map +1 -1
  73. package/lib/webrtc/src/media/rtpTransceiver.d.ts +42 -0
  74. package/lib/webrtc/src/media/rtpTransceiver.js +157 -4
  75. package/lib/webrtc/src/media/rtpTransceiver.js.map +1 -1
  76. package/lib/webrtc/src/media/track.d.ts +29 -1
  77. package/lib/webrtc/src/media/track.js +164 -5
  78. package/lib/webrtc/src/media/track.js.map +1 -1
  79. package/lib/webrtc/src/nonstandard/index.d.ts +0 -1
  80. package/lib/webrtc/src/nonstandard/index.js +0 -1
  81. package/lib/webrtc/src/nonstandard/index.js.map +1 -1
  82. package/lib/webrtc/src/nonstandard/recorder/writer/webm.js +2 -1
  83. package/lib/webrtc/src/nonstandard/recorder/writer/webm.js.map +1 -1
  84. package/lib/webrtc/src/nonstandard/userMedia.d.ts +1 -2
  85. package/lib/webrtc/src/nonstandard/userMedia.js +30 -14
  86. package/lib/webrtc/src/nonstandard/userMedia.js.map +1 -1
  87. package/lib/webrtc/src/peerConnection.d.ts +127 -5
  88. package/lib/webrtc/src/peerConnection.js +629 -143
  89. package/lib/webrtc/src/peerConnection.js.map +1 -1
  90. package/lib/webrtc/src/polyfill/api.d.ts +14 -0
  91. package/lib/webrtc/src/polyfill/api.js +23 -0
  92. package/lib/webrtc/src/polyfill/api.js.map +1 -0
  93. package/lib/webrtc/src/polyfill/browserIdentity.d.ts +11 -0
  94. package/lib/webrtc/src/polyfill/browserIdentity.js +59 -0
  95. package/lib/webrtc/src/polyfill/browserIdentity.js.map +1 -0
  96. package/lib/webrtc/src/polyfill/dom.d.ts +11 -0
  97. package/lib/webrtc/src/polyfill/dom.js +18 -0
  98. package/lib/webrtc/src/polyfill/dom.js.map +1 -0
  99. package/lib/webrtc/src/polyfill/existingMediaDevices.d.ts +2 -0
  100. package/lib/webrtc/src/polyfill/existingMediaDevices.js +22 -0
  101. package/lib/webrtc/src/polyfill/existingMediaDevices.js.map +1 -0
  102. package/lib/webrtc/src/polyfill/globals.d.ts +28 -0
  103. package/lib/webrtc/src/polyfill/globals.js +3 -0
  104. package/lib/webrtc/src/polyfill/globals.js.map +1 -0
  105. package/lib/webrtc/src/polyfill/index.d.ts +2 -0
  106. package/lib/webrtc/src/polyfill/index.js +19 -0
  107. package/lib/webrtc/src/polyfill/index.js.map +1 -0
  108. package/lib/webrtc/src/polyfill/install.d.ts +13 -0
  109. package/lib/webrtc/src/polyfill/install.js +266 -0
  110. package/lib/webrtc/src/polyfill/install.js.map +1 -0
  111. package/lib/webrtc/src/polyfill/mediaDevices.d.ts +38 -0
  112. package/lib/webrtc/src/polyfill/mediaDevices.js +228 -0
  113. package/lib/webrtc/src/polyfill/mediaDevices.js.map +1 -0
  114. package/lib/webrtc/src/polyfill/mediaRegister.d.ts +51 -0
  115. package/lib/webrtc/src/polyfill/mediaRegister.js +14 -0
  116. package/lib/webrtc/src/polyfill/mediaRegister.js.map +1 -0
  117. package/lib/webrtc/src/polyfill/peerConnectionConfig.d.ts +3 -0
  118. package/lib/webrtc/src/polyfill/peerConnectionConfig.js +52 -0
  119. package/lib/webrtc/src/polyfill/peerConnectionConfig.js.map +1 -0
  120. package/lib/webrtc/src/polyfill/registers/callback.d.ts +16 -0
  121. package/lib/webrtc/src/polyfill/registers/callback.js +57 -0
  122. package/lib/webrtc/src/polyfill/registers/callback.js.map +1 -0
  123. package/lib/webrtc/src/polyfill/registers/empty.d.ts +2 -0
  124. package/lib/webrtc/src/polyfill/registers/empty.js +28 -0
  125. package/lib/webrtc/src/polyfill/registers/empty.js.map +1 -0
  126. package/lib/webrtc/src/polyfill/registers/mp4Webm.d.ts +36 -0
  127. package/lib/webrtc/src/polyfill/registers/mp4Webm.js +242 -0
  128. package/lib/webrtc/src/polyfill/registers/mp4Webm.js.map +1 -0
  129. package/lib/webrtc/src/polyfill/registers/rtpRtcp.d.ts +17 -0
  130. package/lib/webrtc/src/polyfill/registers/rtpRtcp.js +143 -0
  131. package/lib/webrtc/src/polyfill/registers/rtpRtcp.js.map +1 -0
  132. package/lib/webrtc/src/polyfill/rtcSessionDescription.d.ts +18 -0
  133. package/lib/webrtc/src/polyfill/rtcSessionDescription.js +36 -0
  134. package/lib/webrtc/src/polyfill/rtcSessionDescription.js.map +1 -0
  135. package/lib/webrtc/src/polyfill/rtpCodec.d.ts +17 -0
  136. package/lib/webrtc/src/polyfill/rtpCodec.js +93 -0
  137. package/lib/webrtc/src/polyfill/rtpCodec.js.map +1 -0
  138. package/lib/webrtc/src/polyfill/selectSettings.d.ts +31 -0
  139. package/lib/webrtc/src/polyfill/selectSettings.js +156 -0
  140. package/lib/webrtc/src/polyfill/selectSettings.js.map +1 -0
  141. package/lib/webrtc/src/polyfill/sourceIo.d.ts +21 -0
  142. package/lib/webrtc/src/polyfill/sourceIo.js +298 -0
  143. package/lib/webrtc/src/polyfill/sourceIo.js.map +1 -0
  144. package/lib/webrtc/src/polyfill/trackStop.d.ts +4 -0
  145. package/lib/webrtc/src/polyfill/trackStop.js +16 -0
  146. package/lib/webrtc/src/polyfill/trackStop.js.map +1 -0
  147. package/lib/webrtc/src/sctpManager.d.ts +2 -1
  148. package/lib/webrtc/src/sctpManager.js +5 -2
  149. package/lib/webrtc/src/sctpManager.js.map +1 -1
  150. package/lib/webrtc/src/sdp.d.ts +1 -1
  151. package/lib/webrtc/src/sdp.js +5 -6
  152. package/lib/webrtc/src/sdp.js.map +1 -1
  153. package/lib/webrtc/src/sdpManager.d.ts +38 -1
  154. package/lib/webrtc/src/sdpManager.js +236 -30
  155. package/lib/webrtc/src/sdpManager.js.map +1 -1
  156. package/lib/webrtc/src/secureTransportManager.d.ts +43 -12
  157. package/lib/webrtc/src/secureTransportManager.js +123 -47
  158. package/lib/webrtc/src/secureTransportManager.js.map +1 -1
  159. package/lib/webrtc/src/transceiverManager.d.ts +91 -6
  160. package/lib/webrtc/src/transceiverManager.js +477 -62
  161. package/lib/webrtc/src/transceiverManager.js.map +1 -1
  162. package/lib/webrtc/src/transport/ice.d.ts +8 -0
  163. package/lib/webrtc/src/transport/ice.js +17 -1
  164. package/lib/webrtc/src/transport/ice.js.map +1 -1
  165. package/lib/webrtc/src/transport/sctp.d.ts +3 -2
  166. package/lib/webrtc/src/transport/sctp.js +8 -2
  167. package/lib/webrtc/src/transport/sctp.js.map +1 -1
  168. 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
- media.port = 0;
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
- if (m.direction === "inactive") {
226
- description.media.push(m);
227
- return;
228
- }
229
- throw new Error("transceiver not found");
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) => !description.media.find((m) => m.rtp.muxId === t.mid))) {
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
- if (transceiver.mLineIndex === undefined) {
242
- transceiver.mLineIndex = description.media.length;
243
- description.media.push(mediaDescription);
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
- description.media[transceiver.mLineIndex] = mediaDescription;
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
- for (const remoteMedia of this._remoteDescription.media) {
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
- media = this.createMediaDescriptionForTransceiver(transceiver, (0, utils_1.andDirection)(transceiver.direction, transceiver.offerDirection));
289
- dtlsTransport = transceiver.dtlsTransport;
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 (remoteMedia.simulcastParameters &&
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
- const bundle = new sdp_1.GroupDescription("BUNDLE", []);
322
- for (const media of description.media) {
323
- if (media.rtp.muxId) {
324
- bundle.items.push(media.rtp.muxId);
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
- description.media
404
- .filter((m) => ["audio", "video"].includes(m.kind))
405
- .forEach((m, i) => {
406
- const transceiver = transceiverByMLineIndex.get(i) ?? transceivers[i];
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"]}