werift 0.17.0 → 0.17.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/lib/ice/src/ice.d.ts +10 -1
  2. package/lib/ice/src/ice.js +15 -3
  3. package/lib/ice/src/ice.js.map +1 -1
  4. package/lib/rtp/src/container/ebml/ebml.d.ts +32 -0
  5. package/lib/rtp/src/container/ebml/ebml.js +115 -0
  6. package/lib/rtp/src/container/ebml/ebml.js.map +1 -0
  7. package/lib/rtp/src/container/ebml/id.d.ts +221 -0
  8. package/lib/rtp/src/container/ebml/id.js +225 -0
  9. package/lib/rtp/src/container/ebml/id.js.map +1 -0
  10. package/lib/rtp/src/container/ebml/index.d.ts +3 -0
  11. package/lib/rtp/src/container/ebml/index.js +20 -0
  12. package/lib/rtp/src/container/ebml/index.js.map +1 -0
  13. package/lib/rtp/src/container/ebml/typedArrayUtils.d.ts +7 -0
  14. package/lib/rtp/src/container/ebml/typedArrayUtils.js +109 -0
  15. package/lib/rtp/src/container/ebml/typedArrayUtils.js.map +1 -0
  16. package/lib/rtp/src/container/webm.d.ts +10 -4
  17. package/lib/rtp/src/container/webm.js +56 -7
  18. package/lib/rtp/src/container/webm.js.map +1 -1
  19. package/lib/rtp/src/index.d.ts +1 -0
  20. package/lib/rtp/src/index.js +1 -0
  21. package/lib/rtp/src/index.js.map +1 -1
  22. package/lib/rtp/src/processor/avBuffer.d.ts +28 -0
  23. package/lib/rtp/src/processor/avBuffer.js +91 -0
  24. package/lib/rtp/src/processor/avBuffer.js.map +1 -0
  25. package/lib/rtp/src/processor/avBufferCallback.d.ts +10 -0
  26. package/lib/rtp/src/processor/avBufferCallback.js +27 -0
  27. package/lib/rtp/src/processor/avBufferCallback.js.map +1 -0
  28. package/lib/rtp/src/processor/depacketizer.d.ts +1 -1
  29. package/lib/rtp/src/processor/depacketizer.js.map +1 -1
  30. package/lib/rtp/src/processor/depacketizerCallback.d.ts +1 -3
  31. package/lib/rtp/src/processor/depacketizerCallback.js +2 -2
  32. package/lib/rtp/src/processor/depacketizerCallback.js.map +1 -1
  33. package/lib/rtp/src/processor/depacketizerTransformer.d.ts +1 -1
  34. package/lib/rtp/src/processor/index.d.ts +3 -0
  35. package/lib/rtp/src/processor/index.js +3 -0
  36. package/lib/rtp/src/processor/index.js.map +1 -1
  37. package/lib/rtp/src/processor/jitterBuffer.d.ts +1 -1
  38. package/lib/rtp/src/processor/jitterBuffer.js.map +1 -1
  39. package/lib/rtp/src/processor/jitterBufferCallback.d.ts +1 -3
  40. package/lib/rtp/src/processor/jitterBufferCallback.js +2 -2
  41. package/lib/rtp/src/processor/jitterBufferCallback.js.map +1 -1
  42. package/lib/rtp/src/processor/jitterBufferTransformer.d.ts +1 -1
  43. package/lib/rtp/src/processor/source/index.d.ts +2 -2
  44. package/lib/rtp/src/processor/source/index.js +16 -3
  45. package/lib/rtp/src/processor/source/index.js.map +1 -1
  46. package/lib/rtp/src/processor/source/rtpCallback.d.ts +17 -0
  47. package/lib/rtp/src/processor/source/rtpCallback.js +33 -0
  48. package/lib/rtp/src/processor/source/rtpCallback.js.map +1 -0
  49. package/lib/rtp/src/processor/source/{rtp.d.ts → rtpStream.d.ts} +2 -5
  50. package/lib/rtp/src/processor/source/{rtp.js → rtpStream.js} +12 -12
  51. package/lib/rtp/src/processor/source/rtpStream.js.map +1 -0
  52. package/lib/rtp/src/processor/webm.d.ts +17 -2
  53. package/lib/rtp/src/processor/webm.js +83 -33
  54. package/lib/rtp/src/processor/webm.js.map +1 -1
  55. package/lib/rtp/src/processor/webmCallback.d.ts +16 -0
  56. package/lib/rtp/src/processor/webmCallback.js +21 -0
  57. package/lib/rtp/src/processor/webmCallback.js.map +1 -0
  58. package/lib/rtp/src/processor/webmStream.d.ts +5 -16
  59. package/lib/rtp/src/processor/webmStream.js.map +1 -1
  60. package/lib/{webrtc/src/media/receiver/red.d.ts → rtp/src/rtp/red/handler.d.ts} +2 -2
  61. package/lib/{webrtc/src/media/receiver/red.js → rtp/src/rtp/red/handler.js} +10 -10
  62. package/lib/rtp/src/rtp/red/handler.js.map +1 -0
  63. package/lib/webrtc/src/const.d.ts +1 -1
  64. package/lib/webrtc/src/const.js +2 -2
  65. package/lib/webrtc/src/const.js.map +1 -1
  66. package/lib/webrtc/src/media/receiver/nack.d.ts +1 -0
  67. package/lib/webrtc/src/media/receiver/nack.js +29 -16
  68. package/lib/webrtc/src/media/receiver/nack.js.map +1 -1
  69. package/lib/webrtc/src/media/router.js +17 -13
  70. package/lib/webrtc/src/media/router.js.map +1 -1
  71. package/lib/webrtc/src/media/rtpReceiver.d.ts +1 -1
  72. package/lib/webrtc/src/media/rtpReceiver.js +14 -9
  73. package/lib/webrtc/src/media/rtpReceiver.js.map +1 -1
  74. package/lib/webrtc/src/media/rtpTransceiver.d.ts +10 -6
  75. package/lib/webrtc/src/media/rtpTransceiver.js +23 -14
  76. package/lib/webrtc/src/media/rtpTransceiver.js.map +1 -1
  77. package/lib/webrtc/src/media/track.js +3 -2
  78. package/lib/webrtc/src/media/track.js.map +1 -1
  79. package/lib/webrtc/src/nonstandard/recorder/writer/webm.js.map +1 -1
  80. package/lib/webrtc/src/nonstandard/userMedia.d.ts +20 -3
  81. package/lib/webrtc/src/nonstandard/userMedia.js +79 -8
  82. package/lib/webrtc/src/nonstandard/userMedia.js.map +1 -1
  83. package/lib/webrtc/src/peerConnection.d.ts +5 -2
  84. package/lib/webrtc/src/peerConnection.js +72 -46
  85. package/lib/webrtc/src/peerConnection.js.map +1 -1
  86. package/lib/webrtc/src/sdp.js +2 -2
  87. package/lib/webrtc/src/sdp.js.map +1 -1
  88. package/lib/webrtc/src/transport/ice.js +10 -3
  89. package/lib/webrtc/src/transport/ice.js.map +1 -1
  90. package/lib/webrtc/src/utils.d.ts +0 -1
  91. package/lib/webrtc/src/utils.js +1 -3
  92. package/lib/webrtc/src/utils.js.map +1 -1
  93. package/package.json +1 -1
  94. package/src/const.ts +1 -1
  95. package/src/media/receiver/nack.ts +33 -17
  96. package/src/media/router.ts +16 -13
  97. package/src/media/rtpReceiver.ts +21 -9
  98. package/src/media/rtpTransceiver.ts +28 -15
  99. package/src/media/track.ts +3 -2
  100. package/src/nonstandard/recorder/writer/webm.ts +2 -2
  101. package/src/nonstandard/userMedia.ts +89 -7
  102. package/src/peerConnection.ts +88 -51
  103. package/src/sdp.ts +2 -2
  104. package/src/transport/ice.ts +13 -3
  105. package/src/utils.ts +0 -3
  106. package/lib/rtp/src/processor/source/rtp.js.map +0 -1
  107. package/lib/webrtc/src/media/receiver/red.js.map +0 -1
  108. package/src/media/receiver/red.ts +0 -70
@@ -1 +1 @@
1
- {"version":3,"file":"rtpTransceiver.js","sourceRoot":"","sources":["../../../../src/media/rtpTransceiver.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,sDAA4B;AAC5B,2CAA6B;AAG7B,oCAA4C;AAU5C,MAAa,iBAAiB;IA+B5B,YACkB,IAAU,EAC1B,aAA+B,EACxB,QAAwB,EACxB,MAAoB;IAC3B,qEAAqE;IAC9D,SAAoB;QALX,SAAI,GAAJ,IAAI,CAAM;QAEnB,aAAQ,GAAR,QAAQ,CAAgB;QACxB,WAAM,GAAN,MAAM,CAAc;QAEpB,cAAS,GAAT,SAAS,CAAW;QApCpB,SAAI,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC;QACjB,YAAO,GAAG,IAAI,iBAAK,EAAyC,CAAC;QAGtE,kBAAa,GAAG,KAAK,CAAC;QActB,YAAO,GAA4B,EAAE,CAAC;QAOtC,qBAAgB,GAAsC,EAAE,CAAC;QACzD,YAAO,GAAgC,EAAE,CAAC;QAC1C,aAAQ,GAAG,KAAK,CAAC;QACjB,YAAO,GAAG,KAAK,CAAC;QAUd,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,CAAC;IACvC,CAAC;IAjCD,IAAI,gBAAgB,CAAC,SAA4C;QAC/D,IAAI,CAAC,iBAAiB,GAAG,SAAS,CAAC;QACnC,IAAI,wBAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC,iBAAiB,IAAI,EAAE,CAAC,EAAE;YAC3D,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;SAC3B;IACH,CAAC;IACD,+CAA+C;IAC/C,IAAI,gBAAgB;QAClB,OAAO,IAAI,CAAC,iBAAiB,CAAC;IAChC,CAAC;IAID,IAAI,MAAM,CAAC,MAA+B;QACxC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;IACxB,CAAC;IACD,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAiBD,IAAI,aAAa;QACf,OAAO,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC;IACrC,CAAC;IAED,gBAAgB,CAAC,IAAsB;QACrC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC;IAED,IAAI,IAAI;QACN,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;IAC1D,CAAC;IAED,QAAQ,CAAC,KAAuB;QAC9B,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC1C,IAAI,GAAG,EAAE;YACP,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;SACnC;IACH,CAAC;IAED,YAAY;IACZ,0CAA0C;IAC1C,IAAI;QACF,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO;QAE1B,oDAAoD;QAEpD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;IACvB,CAAC;IAED,cAAc,CAAC,QAAgB;QAC7B,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAChC,KAAK,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,CAC9D,EAAE,WAAW,CAAC;IACjB,CAAC;CACF;AA7ED,8CA6EC;AAEY,QAAA,QAAQ,GAAG,UAAU,CAAC;AACtB,QAAA,QAAQ,GAAG,UAAU,CAAC;AACtB,QAAA,QAAQ,GAAG,UAAU,CAAC;AACtB,QAAA,QAAQ,GAAG,UAAU,CAAC;AAEtB,QAAA,UAAU,GAAG,CAAC,gBAAQ,EAAE,gBAAQ,EAAE,gBAAQ,EAAE,gBAAQ,CAAU,CAAC","sourcesContent":["import Event from \"rx.mini\";\nimport * as uuid from \"uuid\";\n\nimport { RTCDtlsTransport } from \"..\";\nimport { SenderDirections } from \"../const\";\nimport { Kind } from \"../types/domain\";\nimport {\n RTCRtpCodecParameters,\n RTCRtpHeaderExtensionParameters,\n} from \"./parameters\";\nimport { RTCRtpReceiver } from \"./rtpReceiver\";\nimport { RTCRtpSender } from \"./rtpSender\";\nimport { MediaStreamTrack } from \"./track\";\n\nexport class RTCRtpTransceiver {\n readonly uuid = uuid.v4();\n readonly onTrack = new Event<[MediaStreamTrack, RTCRtpTransceiver]>();\n mid?: string;\n mLineIndex?: number;\n usedForSender = false;\n private _currentDirection?: Direction | \"stopped\";\n set currentDirection(direction: Direction | \"stopped\" | undefined) {\n this._currentDirection = direction;\n if (SenderDirections.includes(this._currentDirection || \"\")) {\n this.usedForSender = true;\n }\n }\n /**RFC 8829 4.2.5. last negotiated direction */\n get currentDirection(): Direction | \"stopped\" | undefined {\n return this._currentDirection;\n }\n\n offerDirection!: Direction;\n _codecs: RTCRtpCodecParameters[] = [];\n set codecs(codecs: RTCRtpCodecParameters[]) {\n this._codecs = codecs;\n }\n get codecs() {\n return this._codecs;\n }\n headerExtensions: RTCRtpHeaderExtensionParameters[] = [];\n options: Partial<TransceiverOptions> = {};\n stopping = false;\n stopped = false;\n\n constructor(\n public readonly kind: Kind,\n dtlsTransport: RTCDtlsTransport,\n public receiver: RTCRtpReceiver,\n public sender: RTCRtpSender,\n /**RFC 8829 4.2.4. direction the transceiver was initialized with */\n public direction: Direction\n ) {\n this.setDtlsTransport(dtlsTransport);\n }\n\n get dtlsTransport() {\n return this.receiver.dtlsTransport;\n }\n\n setDtlsTransport(dtls: RTCDtlsTransport) {\n this.receiver.setDtlsTransport(dtls);\n this.sender.setDtlsTransport(dtls);\n }\n\n get msid() {\n return `${this.sender.streamId} ${this.sender.trackId}`;\n }\n\n addTrack(track: MediaStreamTrack) {\n const res = this.receiver.addTrack(track);\n if (res) {\n this.onTrack.execute(track, this);\n }\n }\n\n // todo impl\n // https://www.w3.org/TR/webrtc/#methods-8\n stop() {\n if (this.stopping) return;\n\n // todo Stop sending and receiving with transceiver.\n\n this.stopping = true;\n }\n\n getPayloadType(mimeType: string) {\n return this.codecs.find((codec) =>\n codec.mimeType.toLowerCase().includes(mimeType.toLowerCase())\n )?.payloadType;\n }\n}\n\nexport const Inactive = \"inactive\";\nexport const Sendonly = \"sendonly\";\nexport const Recvonly = \"recvonly\";\nexport const Sendrecv = \"sendrecv\";\n\nexport const Directions = [Inactive, Sendonly, Recvonly, Sendrecv] as const;\n\nexport type Direction = typeof Directions[number];\n\ntype SimulcastDirection = \"send\" | \"recv\";\n\nexport interface TransceiverOptions {\n direction: Direction;\n simulcast: { direction: SimulcastDirection; rid: string }[];\n}\n"]}
1
+ {"version":3,"file":"rtpTransceiver.js","sourceRoot":"","sources":["../../../../src/media/rtpTransceiver.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,sDAA4B;AAC5B,2CAA6B;AAG7B,oCAA4C;AAU5C,MAAa,iBAAiB;IAqB5B,YACkB,IAAU,EAC1B,aAA+B,EACxB,QAAwB,EACxB,MAAoB;IAC3B,qEAAqE;IAC7D,UAAqB;QALb,SAAI,GAAJ,IAAI,CAAM;QAEnB,aAAQ,GAAR,QAAQ,CAAgB;QACxB,WAAM,GAAN,MAAM,CAAc;QAEnB,eAAU,GAAV,UAAU,CAAW;QA1BtB,OAAE,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC;QACf,YAAO,GAAG,IAAI,iBAAK,EAAyC,CAAC;QAGtE,uEAAuE;QACvE,kBAAa,GAAG,KAAK,CAAC;QAGtB,YAAO,GAA4B,EAAE,CAAC;QAOtC,qBAAgB,GAAsC,EAAE,CAAC;QACzD,YAAO,GAAgC,EAAE,CAAC;QAC1C,aAAQ,GAAG,KAAK,CAAC;QACjB,YAAO,GAAG,KAAK,CAAC;QAUd,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,CAAC;IACvC,CAAC;IApBD,IAAI,MAAM,CAAC,MAA+B;QACxC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;IACxB,CAAC;IACD,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAiBD,IAAI,aAAa;QACf,OAAO,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC;IACrC,CAAC;IAED,gDAAgD;IAChD,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED,YAAY,CAAC,SAAoB;QAC/B,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;QAC5B,IAAI,wBAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC,iBAAiB,IAAI,EAAE,CAAC,EAAE;YAC3D,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;SAC3B;IACH,CAAC;IAED,+CAA+C;IAC/C,IAAI,gBAAgB;QAClB,OAAO,IAAI,CAAC,iBAAiB,CAAC;IAChC,CAAC;IAED,mBAAmB,CAAC,SAAgC;QAClD,IAAI,CAAC,iBAAiB,GAAG,SAAS,CAAC;IACrC,CAAC;IAED,gBAAgB,CAAC,IAAsB;QACrC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC;IAED,IAAI,IAAI;QACN,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;IAC1D,CAAC;IAED,QAAQ,CAAC,KAAuB;QAC9B,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC1C,IAAI,GAAG,EAAE;YACP,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;SACnC;IACH,CAAC;IAED,YAAY;IACZ,0CAA0C;IAC1C,IAAI;QACF,IAAI,IAAI,CAAC,QAAQ,EAAE;YACjB,OAAO;SACR;QAED,oDAAoD;QAEpD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;IACvB,CAAC;IAED,cAAc,CAAC,QAAgB;QAC7B,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAChC,KAAK,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,CAC9D,EAAE,WAAW,CAAC;IACjB,CAAC;CACF;AA1FD,8CA0FC;AAEY,QAAA,QAAQ,GAAG,UAAU,CAAC;AACtB,QAAA,QAAQ,GAAG,UAAU,CAAC;AACtB,QAAA,QAAQ,GAAG,UAAU,CAAC;AACtB,QAAA,QAAQ,GAAG,UAAU,CAAC;AAEtB,QAAA,UAAU,GAAG,CAAC,gBAAQ,EAAE,gBAAQ,EAAE,gBAAQ,EAAE,gBAAQ,CAAU,CAAC","sourcesContent":["import Event from \"rx.mini\";\nimport * as uuid from \"uuid\";\n\nimport { RTCDtlsTransport } from \"..\";\nimport { SenderDirections } from \"../const\";\nimport { Kind } from \"../types/domain\";\nimport {\n RTCRtpCodecParameters,\n RTCRtpHeaderExtensionParameters,\n} from \"./parameters\";\nimport { RTCRtpReceiver } from \"./rtpReceiver\";\nimport { RTCRtpSender } from \"./rtpSender\";\nimport { MediaStreamTrack } from \"./track\";\n\nexport class RTCRtpTransceiver {\n readonly id = uuid.v4();\n readonly onTrack = new Event<[MediaStreamTrack, RTCRtpTransceiver]>();\n mid?: string;\n mLineIndex?: number;\n /**should not be reused because it has been used for sending before. */\n usedForSender = false;\n private _currentDirection?: Direction;\n offerDirection!: Direction;\n _codecs: RTCRtpCodecParameters[] = [];\n set codecs(codecs: RTCRtpCodecParameters[]) {\n this._codecs = codecs;\n }\n get codecs() {\n return this._codecs;\n }\n headerExtensions: RTCRtpHeaderExtensionParameters[] = [];\n options: Partial<TransceiverOptions> = {};\n stopping = false;\n stopped = false;\n\n constructor(\n public readonly kind: Kind,\n dtlsTransport: RTCDtlsTransport,\n public receiver: RTCRtpReceiver,\n public sender: RTCRtpSender,\n /**RFC 8829 4.2.4. direction the transceiver was initialized with */\n private _direction: Direction\n ) {\n this.setDtlsTransport(dtlsTransport);\n }\n\n get dtlsTransport() {\n return this.receiver.dtlsTransport;\n }\n\n /**RFC 8829 4.2.4. setDirectionに渡された最後の値を示します */\n get direction() {\n return this._direction;\n }\n\n setDirection(direction: Direction) {\n this._direction = direction;\n if (SenderDirections.includes(this._currentDirection ?? \"\")) {\n this.usedForSender = true;\n }\n }\n\n /**RFC 8829 4.2.5. last negotiated direction */\n get currentDirection(): Direction | undefined {\n return this._currentDirection;\n }\n\n setCurrentDirection(direction: Direction | undefined) {\n this._currentDirection = direction;\n }\n\n setDtlsTransport(dtls: RTCDtlsTransport) {\n this.receiver.setDtlsTransport(dtls);\n this.sender.setDtlsTransport(dtls);\n }\n\n get msid() {\n return `${this.sender.streamId} ${this.sender.trackId}`;\n }\n\n addTrack(track: MediaStreamTrack) {\n const res = this.receiver.addTrack(track);\n if (res) {\n this.onTrack.execute(track, this);\n }\n }\n\n // todo impl\n // https://www.w3.org/TR/webrtc/#methods-8\n stop() {\n if (this.stopping) {\n return;\n }\n\n // todo Stop sending and receiving with transceiver.\n\n this.stopping = true;\n }\n\n getPayloadType(mimeType: string) {\n return this.codecs.find((codec) =>\n codec.mimeType.toLowerCase().includes(mimeType.toLowerCase())\n )?.payloadType;\n }\n}\n\nexport const Inactive = \"inactive\";\nexport const Sendonly = \"sendonly\";\nexport const Recvonly = \"recvonly\";\nexport const Sendrecv = \"sendrecv\";\n\nexport const Directions = [Inactive, Sendonly, Recvonly, Sendrecv] as const;\n\nexport type Direction = typeof Directions[number];\n\ntype SimulcastDirection = \"send\" | \"recv\";\n\nexport interface TransceiverOptions {\n direction: Direction;\n simulcast: { direction: SimulcastDirection; rid: string }[];\n}\n"]}
@@ -29,11 +29,12 @@ class MediaStreamTrack extends helper_1.EventTarget {
29
29
  if (this.remote) {
30
30
  throw new Error("this is remoteTrack");
31
31
  }
32
- if (!this.codec || this.stopped) {
32
+ if (this.stopped) {
33
33
  return;
34
34
  }
35
35
  const packet = Buffer.isBuffer(rtp) ? src_1.RtpPacket.deSerialize(rtp) : rtp;
36
- packet.header.payloadType = this.codec.payloadType;
36
+ packet.header.payloadType =
37
+ this.codec?.payloadType ?? packet.header.payloadType;
37
38
  this.onReceiveRtp.execute(packet);
38
39
  };
39
40
  Object.assign(this, props);
@@ -1 +1 @@
1
- {"version":3,"file":"track.js","sourceRoot":"","sources":["../../../../src/media/track.ts"],"names":[],"mappings":";;;;;;AAAA,sDAA4B;AAC5B,+BAA0B;AAE1B,0CAAoE;AACpE,sCAAwC;AAIxC,MAAa,gBAAiB,SAAQ,oBAAW;IAyB/C,YACE,KAAiE;QAEjE,KAAK,EAAE,CAAC;QA3BD,SAAI,GAAG,IAAA,SAAE,GAAE,CAAC;QAGrB,WAAM,GAAG,KAAK,CAAC;QASf,eAAe;QACf,YAAO,GAAG,IAAI,CAAC;QAEN,iBAAY,GAAG,IAAI,iBAAK,EAAe,CAAC;QACxC,kBAAa,GAAG,IAAI,iBAAK,EAAgB,CAAC;QAC1C,oBAAe,GAAG,IAAI,iBAAK,EAEjC,CAAC;QAEJ,YAAO,GAAG,KAAK,CAAC;QAChB,UAAK,GAAG,IAAI,CAAC;QAgBb,SAAI,GAAG,GAAG,EAAE;YACV,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACpB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;YAClB,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,CAAC;QAC/B,CAAC,CAAC;QAEF,aAAQ,GAAG,CAAC,GAAuB,EAAE,EAAE;YACrC,IAAI,IAAI,CAAC,MAAM,EAAE;gBACf,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;aACxC;YACD,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE;gBAC/B,OAAO;aACR;YAED,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,eAAS,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;YACvE,MAAM,CAAC,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC;YACnD,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACpC,CAAC,CAAC;QA3BA,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAE3B,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,GAAG,EAAE,EAAE;YAClC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;YACnB,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;QAC3B,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,KAAK,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;IAClE,CAAC;CAoBF;AAzDD,4CAyDC;AAED,MAAa,WAAW;IAItB,YAAY,KAAqD;QAFjE,WAAM,GAAuB,EAAE,CAAC;QAG9B,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC7B,CAAC;IAED,QAAQ,CAAC,KAAuB;QAC9B,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAC;QACzB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;CACF;AAhBD,kCAgBC","sourcesContent":["import Event from \"rx.mini\";\nimport { v4 } from \"uuid\";\n\nimport { RtcpPacket, RtpHeader, RtpPacket } from \"../../../rtp/src\";\nimport { EventTarget } from \"../helper\";\nimport { Kind } from \"../types/domain\";\nimport { RTCRtpCodecParameters } from \"./parameters\";\n\nexport class MediaStreamTrack extends EventTarget {\n readonly uuid = v4();\n /**MediaStream ID*/\n streamId?: string;\n remote = false;\n label: string;\n kind!: Kind;\n id?: string;\n /**mediaSsrc */\n ssrc?: number;\n rid?: string;\n header?: RtpHeader;\n codec?: RTCRtpCodecParameters;\n /**todo impl */\n enabled = true;\n\n readonly onReceiveRtp = new Event<[RtpPacket]>();\n readonly onReceiveRtcp = new Event<[RtcpPacket]>();\n readonly onSourceChanged = new Event<\n [Pick<RtpHeader, \"sequenceNumber\" | \"timestamp\">]\n >();\n\n stopped = false;\n muted = true;\n\n constructor(\n props: Partial<MediaStreamTrack> & Pick<MediaStreamTrack, \"kind\">\n ) {\n super();\n Object.assign(this, props);\n\n this.onReceiveRtp.subscribe((rtp) => {\n this.muted = false;\n this.header = rtp.header;\n });\n\n this.label = `${this.remote ? \"remote\" : \"local\"} ${this.kind}`;\n }\n\n stop = () => {\n this.stopped = true;\n this.muted = true;\n this.onReceiveRtp.complete();\n };\n\n writeRtp = (rtp: RtpPacket | Buffer) => {\n if (this.remote) {\n throw new Error(\"this is remoteTrack\");\n }\n if (!this.codec || this.stopped) {\n return;\n }\n\n const packet = Buffer.isBuffer(rtp) ? RtpPacket.deSerialize(rtp) : rtp;\n packet.header.payloadType = this.codec.payloadType;\n this.onReceiveRtp.execute(packet);\n };\n}\n\nexport class MediaStream {\n id!: string;\n tracks: MediaStreamTrack[] = [];\n\n constructor(props: Partial<MediaStream> & Pick<MediaStream, \"id\">) {\n Object.assign(this, props);\n }\n\n addTrack(track: MediaStreamTrack) {\n track.streamId = this.id;\n this.tracks.push(track);\n }\n\n getTracks() {\n return this.tracks;\n }\n}\n"]}
1
+ {"version":3,"file":"track.js","sourceRoot":"","sources":["../../../../src/media/track.ts"],"names":[],"mappings":";;;;;;AAAA,sDAA4B;AAC5B,+BAA0B;AAE1B,0CAAoE;AACpE,sCAAwC;AAIxC,MAAa,gBAAiB,SAAQ,oBAAW;IAyB/C,YACE,KAAiE;QAEjE,KAAK,EAAE,CAAC;QA3BD,SAAI,GAAG,IAAA,SAAE,GAAE,CAAC;QAGrB,WAAM,GAAG,KAAK,CAAC;QASf,eAAe;QACf,YAAO,GAAG,IAAI,CAAC;QAEN,iBAAY,GAAG,IAAI,iBAAK,EAAe,CAAC;QACxC,kBAAa,GAAG,IAAI,iBAAK,EAAgB,CAAC;QAC1C,oBAAe,GAAG,IAAI,iBAAK,EAEjC,CAAC;QAEJ,YAAO,GAAG,KAAK,CAAC;QAChB,UAAK,GAAG,IAAI,CAAC;QAgBb,SAAI,GAAG,GAAG,EAAE;YACV,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACpB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;YAClB,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,CAAC;QAC/B,CAAC,CAAC;QAEF,aAAQ,GAAG,CAAC,GAAuB,EAAE,EAAE;YACrC,IAAI,IAAI,CAAC,MAAM,EAAE;gBACf,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;aACxC;YACD,IAAI,IAAI,CAAC,OAAO,EAAE;gBAChB,OAAO;aACR;YAED,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,eAAS,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;YACvE,MAAM,CAAC,MAAM,CAAC,WAAW;gBACvB,IAAI,CAAC,KAAK,EAAE,WAAW,IAAI,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC;YACvD,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACpC,CAAC,CAAC;QA5BA,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAE3B,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,GAAG,EAAE,EAAE;YAClC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;YACnB,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;QAC3B,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,KAAK,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;IAClE,CAAC;CAqBF;AA1DD,4CA0DC;AAED,MAAa,WAAW;IAItB,YAAY,KAAqD;QAFjE,WAAM,GAAuB,EAAE,CAAC;QAG9B,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC7B,CAAC;IAED,QAAQ,CAAC,KAAuB;QAC9B,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAC;QACzB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;CACF;AAhBD,kCAgBC","sourcesContent":["import Event from \"rx.mini\";\nimport { v4 } from \"uuid\";\n\nimport { RtcpPacket, RtpHeader, RtpPacket } from \"../../../rtp/src\";\nimport { EventTarget } from \"../helper\";\nimport { Kind } from \"../types/domain\";\nimport { RTCRtpCodecParameters } from \"./parameters\";\n\nexport class MediaStreamTrack extends EventTarget {\n readonly uuid = v4();\n /**MediaStream ID*/\n streamId?: string;\n remote = false;\n label: string;\n kind!: Kind;\n id?: string;\n /**mediaSsrc */\n ssrc?: number;\n rid?: string;\n header?: RtpHeader;\n codec?: RTCRtpCodecParameters;\n /**todo impl */\n enabled = true;\n\n readonly onReceiveRtp = new Event<[RtpPacket]>();\n readonly onReceiveRtcp = new Event<[RtcpPacket]>();\n readonly onSourceChanged = new Event<\n [Pick<RtpHeader, \"sequenceNumber\" | \"timestamp\">]\n >();\n\n stopped = false;\n muted = true;\n\n constructor(\n props: Partial<MediaStreamTrack> & Pick<MediaStreamTrack, \"kind\">\n ) {\n super();\n Object.assign(this, props);\n\n this.onReceiveRtp.subscribe((rtp) => {\n this.muted = false;\n this.header = rtp.header;\n });\n\n this.label = `${this.remote ? \"remote\" : \"local\"} ${this.kind}`;\n }\n\n stop = () => {\n this.stopped = true;\n this.muted = true;\n this.onReceiveRtp.complete();\n };\n\n writeRtp = (rtp: RtpPacket | Buffer) => {\n if (this.remote) {\n throw new Error(\"this is remoteTrack\");\n }\n if (this.stopped) {\n return;\n }\n\n const packet = Buffer.isBuffer(rtp) ? RtpPacket.deSerialize(rtp) : rtp;\n packet.header.payloadType =\n this.codec?.payloadType ?? packet.header.payloadType;\n this.onReceiveRtp.execute(packet);\n };\n}\n\nexport class MediaStream {\n id!: string;\n tracks: MediaStreamTrack[] = [];\n\n constructor(props: Partial<MediaStream> & Pick<MediaStream, \"id\">) {\n Object.assign(this, props);\n }\n\n addTrack(track: MediaStreamTrack) {\n track.streamId = this.id;\n this.tracks.push(track);\n }\n\n getTracks() {\n return this.tracks;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"webm.js","sourceRoot":"","sources":["../../../../../../src/nonstandard/recorder/writer/webm.ts"],"names":[],"mappings":"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","sourcesContent":["import { appendFile, open, unlink } from \"fs/promises\";\nimport { ReadableStreamDefaultReadResult } from \"stream/web\";\n\nimport { SupportedCodec } from \"../../../../../rtp/src/container/webm\";\nimport {\n depacketizeTransformer,\n jitterBufferTransformer,\n MediaStreamTrack,\n RtpSourceStream,\n WebmLiveOutput,\n WebmStream,\n WeriftError,\n} from \"../../..\";\nimport { MediaWriter } from \".\";\n\nconst sourcePath = \"packages/webrtc/src/nonstandard/recorder/writer/webm.ts\";\n\nexport class WebmFactory extends MediaWriter {\n rtpSources: RtpSourceStream[] = [];\n\n async start(tracks: MediaStreamTrack[]) {\n await unlink(this.path).catch((e) => e);\n\n const inputTracks = tracks.map((track, i) => {\n const trackNumber = i + 1;\n const payloadType = track.codec!.payloadType;\n\n if (track.kind === \"video\") {\n const codec = ((): SupportedCodec => {\n switch (track.codec?.name.toLowerCase() as SupportedVideoCodec) {\n case \"vp8\":\n return \"VP8\";\n case \"vp9\":\n return \"VP9\";\n case \"h264\":\n return \"MPEG4/ISO/AVC\";\n case \"av1x\":\n return \"AV1\";\n default:\n throw new WeriftError({\n message: \"unsupported codec\",\n payload: { track, path: sourcePath },\n });\n }\n })();\n return {\n kind: \"video\" as const,\n codec,\n clockRate: 90000,\n trackNumber,\n width: this.options.width,\n height: this.options.height,\n payloadType,\n track,\n };\n } else {\n return {\n kind: \"audio\" as const,\n codec: \"OPUS\" as const,\n clockRate: 48000,\n trackNumber,\n payloadType,\n track,\n };\n }\n });\n\n const webm = new WebmStream(inputTracks, {\n duration: this.options.defaultDuration ?? 1000 * 60 * 60 * 24,\n });\n\n this.rtpSources = inputTracks.map(({ track, clockRate, codec }) => {\n const rtpSource = new RtpSourceStream();\n track.onReceiveRtp.subscribe((r) => rtpSource.push(r));\n\n const jitterBuffer = jitterBufferTransformer(clockRate, {\n latency: this.options.jitterBufferLatency,\n bufferSize: this.options.jitterBufferSize,\n });\n\n if (track.kind === \"video\") {\n rtpSource.readable\n .pipeThrough(jitterBuffer)\n .pipeThrough(\n depacketizeTransformer(codec, {\n waitForKeyframe: this.options.waitForKeyframe,\n isFinalPacketInSequence: (h) => h.marker,\n })\n )\n .pipeTo(webm.videoStream);\n } else {\n rtpSource.readable\n .pipeThrough(jitterBuffer)\n .pipeThrough(depacketizeTransformer(codec))\n .pipeTo(webm.audioStream);\n }\n\n return rtpSource;\n });\n\n const reader = webm.webmStream.getReader();\n const readChunk = async ({\n value,\n done,\n }: ReadableStreamDefaultReadResult<WebmLiveOutput>) => {\n if (done) return;\n\n if (value.saveToFile) {\n await appendFile(this.path, value.saveToFile);\n } else if (value.eol) {\n const { durationElement } = value.eol;\n const handler = await open(this.path, \"r+\");\n await handler.write(durationElement, 0, durationElement.length, 83);\n await handler.close();\n }\n reader.read().then(readChunk);\n };\n reader.read().then(readChunk);\n }\n\n async stop() {\n await Promise.all(this.rtpSources.map((r) => r.stop()));\n }\n}\n\nconst supportedVideoCodecs = [\"h264\", \"vp8\", \"vp9\", \"av1x\"] as const;\ntype SupportedVideoCodec = typeof supportedVideoCodecs[number];\n"]}
1
+ {"version":3,"file":"webm.js","sourceRoot":"","sources":["../../../../../../src/nonstandard/recorder/writer/webm.ts"],"names":[],"mappings":";;;AAAA,0CAAuD;AAIvD,gCAQkB;AAClB,wBAAgC;AAEhC,MAAM,UAAU,GAAG,yDAAyD,CAAC;AAE7E,MAAa,WAAY,SAAQ,cAAW;IAA5C;;QACE,eAAU,GAAsB,EAAE,CAAC;IAyGrC,CAAC;IAvGC,KAAK,CAAC,KAAK,CAAC,MAA0B;QACpC,MAAM,IAAA,iBAAM,EAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;QAExC,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;YAC1C,MAAM,WAAW,GAAG,CAAC,GAAG,CAAC,CAAC;YAC1B,MAAM,WAAW,GAAG,KAAK,CAAC,KAAM,CAAC,WAAW,CAAC;YAE7C,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE;gBAC1B,MAAM,KAAK,GAAG,CAAC,GAAmB,EAAE;oBAClC,QAAQ,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,EAAyB,EAAE;wBAC9D,KAAK,KAAK;4BACR,OAAO,KAAK,CAAC;wBACf,KAAK,KAAK;4BACR,OAAO,KAAK,CAAC;wBACf,KAAK,MAAM;4BACT,OAAO,eAAe,CAAC;wBACzB,KAAK,MAAM;4BACT,OAAO,KAAK,CAAC;wBACf;4BACE,MAAM,IAAI,eAAW,CAAC;gCACpB,OAAO,EAAE,mBAAmB;gCAC5B,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE;6BACrC,CAAC,CAAC;qBACN;gBACH,CAAC,CAAC,EAAE,CAAC;gBACL,OAAO;oBACL,IAAI,EAAE,OAAgB;oBACtB,KAAK;oBACL,SAAS,EAAE,KAAK;oBAChB,WAAW;oBACX,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK;oBACzB,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM;oBAC3B,WAAW;oBACX,KAAK;iBACN,CAAC;aACH;iBAAM;gBACL,OAAO;oBACL,IAAI,EAAE,OAAgB;oBACtB,KAAK,EAAE,MAAe;oBACtB,SAAS,EAAE,KAAK;oBAChB,WAAW;oBACX,WAAW;oBACX,KAAK;iBACN,CAAC;aACH;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,IAAI,cAAU,CAAC,WAAW,EAAE;YACvC,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,eAAe,IAAI,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;SAC9D,CAAC,CAAC;QAEH,IAAI,CAAC,UAAU,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,EAAE;YAChE,MAAM,SAAS,GAAG,IAAI,mBAAe,EAAE,CAAC;YACxC,KAAK,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YAEvD,MAAM,YAAY,GAAG,IAAA,2BAAuB,EAAC,SAAS,EAAE;gBACtD,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,mBAAmB;gBACzC,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,gBAAgB;aAC1C,CAAC,CAAC;YAEH,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE;gBAC1B,SAAS,CAAC,QAAQ;qBACf,WAAW,CAAC,YAAY,CAAC;qBACzB,WAAW,CACV,IAAA,0BAAsB,EAAC,KAAK,EAAE;oBAC5B,eAAe,EAAE,IAAI,CAAC,OAAO,CAAC,eAAe;oBAC7C,uBAAuB,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM;iBACzC,CAAC,CACH;qBACA,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;aAC7B;iBAAM;gBACL,SAAS,CAAC,QAAQ;qBACf,WAAW,CAAC,YAAY,CAAC;qBACzB,WAAW,CAAC,IAAA,0BAAsB,EAAC,KAAK,CAAC,CAAC;qBAC1C,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;aAC7B;YAED,OAAO,SAAS,CAAC;QACnB,CAAC,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,CAAC;QAC3C,MAAM,SAAS,GAAG,KAAK,EAAE,EACvB,KAAK,EACL,IAAI,GAC8C,EAAE,EAAE;YACtD,IAAI,IAAI;gBAAE,OAAO;YAEjB,IAAI,KAAK,CAAC,UAAU,EAAE;gBACpB,MAAM,IAAA,qBAAU,EAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;aAC/C;iBAAM,IAAI,KAAK,CAAC,GAAG,EAAE;gBACpB,MAAM,EAAE,eAAe,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC;gBACtC,MAAM,OAAO,GAAG,MAAM,IAAA,eAAI,EAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;gBAC5C,MAAM,OAAO,CAAC,KAAK,CAAC,eAAe,EAAE,CAAC,EAAE,eAAe,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;gBACpE,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;aACvB;YACD,MAAM,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAChC,CAAC,CAAC;QACF,MAAM,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,IAAI;QACR,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAC1D,CAAC;CACF;AA1GD,kCA0GC;AAED,MAAM,oBAAoB,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAU,CAAC","sourcesContent":["import { appendFile, open, unlink } from \"fs/promises\";\nimport { ReadableStreamDefaultReadResult } from \"stream/web\";\n\nimport { SupportedCodec } from \"../../../../../rtp/src/container/webm\";\nimport {\n depacketizeTransformer,\n jitterBufferTransformer,\n MediaStreamTrack,\n RtpSourceStream,\n WebmStream,\n WebmStreamOutput,\n WeriftError,\n} from \"../../..\";\nimport { MediaWriter } from \".\";\n\nconst sourcePath = \"packages/webrtc/src/nonstandard/recorder/writer/webm.ts\";\n\nexport class WebmFactory extends MediaWriter {\n rtpSources: RtpSourceStream[] = [];\n\n async start(tracks: MediaStreamTrack[]) {\n await unlink(this.path).catch((e) => e);\n\n const inputTracks = tracks.map((track, i) => {\n const trackNumber = i + 1;\n const payloadType = track.codec!.payloadType;\n\n if (track.kind === \"video\") {\n const codec = ((): SupportedCodec => {\n switch (track.codec?.name.toLowerCase() as SupportedVideoCodec) {\n case \"vp8\":\n return \"VP8\";\n case \"vp9\":\n return \"VP9\";\n case \"h264\":\n return \"MPEG4/ISO/AVC\";\n case \"av1x\":\n return \"AV1\";\n default:\n throw new WeriftError({\n message: \"unsupported codec\",\n payload: { track, path: sourcePath },\n });\n }\n })();\n return {\n kind: \"video\" as const,\n codec,\n clockRate: 90000,\n trackNumber,\n width: this.options.width,\n height: this.options.height,\n payloadType,\n track,\n };\n } else {\n return {\n kind: \"audio\" as const,\n codec: \"OPUS\" as const,\n clockRate: 48000,\n trackNumber,\n payloadType,\n track,\n };\n }\n });\n\n const webm = new WebmStream(inputTracks, {\n duration: this.options.defaultDuration ?? 1000 * 60 * 60 * 24,\n });\n\n this.rtpSources = inputTracks.map(({ track, clockRate, codec }) => {\n const rtpSource = new RtpSourceStream();\n track.onReceiveRtp.subscribe((r) => rtpSource.push(r));\n\n const jitterBuffer = jitterBufferTransformer(clockRate, {\n latency: this.options.jitterBufferLatency,\n bufferSize: this.options.jitterBufferSize,\n });\n\n if (track.kind === \"video\") {\n rtpSource.readable\n .pipeThrough(jitterBuffer)\n .pipeThrough(\n depacketizeTransformer(codec, {\n waitForKeyframe: this.options.waitForKeyframe,\n isFinalPacketInSequence: (h) => h.marker,\n })\n )\n .pipeTo(webm.videoStream);\n } else {\n rtpSource.readable\n .pipeThrough(jitterBuffer)\n .pipeThrough(depacketizeTransformer(codec))\n .pipeTo(webm.audioStream);\n }\n\n return rtpSource;\n });\n\n const reader = webm.webmStream.getReader();\n const readChunk = async ({\n value,\n done,\n }: ReadableStreamDefaultReadResult<WebmStreamOutput>) => {\n if (done) return;\n\n if (value.saveToFile) {\n await appendFile(this.path, value.saveToFile);\n } else if (value.eol) {\n const { durationElement } = value.eol;\n const handler = await open(this.path, \"r+\");\n await handler.write(durationElement, 0, durationElement.length, 83);\n await handler.close();\n }\n reader.read().then(readChunk);\n };\n reader.read().then(readChunk);\n }\n\n async stop() {\n await Promise.all(this.rtpSources.map((r) => r.stop()));\n }\n}\n\nconst supportedVideoCodecs = [\"h264\", \"vp8\", \"vp9\", \"av1x\"] as const;\ntype SupportedVideoCodec = typeof supportedVideoCodecs[number];\n"]}
@@ -1,6 +1,6 @@
1
1
  import { MediaStreamTrack } from "../media/track";
2
- export declare const getUserMp4: (path: string, loop?: boolean) => Promise<MediaMp4>;
3
- declare class MediaMp4 {
2
+ export declare const getUserMedia: (path: string, loop?: boolean) => Promise<MediaPlayerMp4 | MediaPlayerWebm>;
3
+ export declare class MediaPlayerMp4 {
4
4
  private videoPort;
5
5
  private audioPort;
6
6
  private path;
@@ -8,8 +8,25 @@ declare class MediaMp4 {
8
8
  private streamId;
9
9
  audio: MediaStreamTrack;
10
10
  video: MediaStreamTrack;
11
+ private process;
12
+ stopped: boolean;
11
13
  constructor(videoPort: number, audioPort: number, path: string, loop?: boolean | undefined);
12
14
  private setupTrack;
13
15
  start(): Promise<void>;
16
+ stop(): void;
17
+ }
18
+ export declare class MediaPlayerWebm {
19
+ private videoPort;
20
+ private audioPort;
21
+ private path;
22
+ private loop?;
23
+ private streamId;
24
+ audio: MediaStreamTrack;
25
+ video: MediaStreamTrack;
26
+ private process;
27
+ stopped: boolean;
28
+ constructor(videoPort: number, audioPort: number, path: string, loop?: boolean | undefined);
29
+ private setupTrack;
30
+ start(): Promise<void>;
31
+ stop(): void;
14
32
  }
15
- export {};
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getUserMp4 = void 0;
3
+ exports.MediaPlayerWebm = exports.MediaPlayerMp4 = exports.getUserMedia = void 0;
4
4
  const child_process_1 = require("child_process");
5
5
  const dgram_1 = require("dgram");
6
6
  const promises_1 = require("timers/promises");
@@ -8,13 +8,18 @@ const uuid_1 = require("uuid");
8
8
  const src_1 = require("../../../common/src");
9
9
  const src_2 = require("../../../rtp/src");
10
10
  const track_1 = require("../media/track");
11
- const getUserMp4 = async (path, loop) => {
11
+ const getUserMedia = async (path, loop) => {
12
12
  const audioPort = await (0, src_1.randomPort)();
13
13
  const videoPort = await (0, src_1.randomPort)();
14
- return new MediaMp4(audioPort, videoPort, path, loop);
14
+ if (path.endsWith(".mp4")) {
15
+ return new MediaPlayerMp4(audioPort, videoPort, path, loop);
16
+ }
17
+ else {
18
+ return new MediaPlayerWebm(audioPort, videoPort, path, loop);
19
+ }
15
20
  };
16
- exports.getUserMp4 = getUserMp4;
17
- class MediaMp4 {
21
+ exports.getUserMedia = getUserMedia;
22
+ class MediaPlayerMp4 {
18
23
  constructor(videoPort, audioPort, path, loop) {
19
24
  this.videoPort = videoPort;
20
25
  this.audioPort = audioPort;
@@ -23,6 +28,7 @@ class MediaMp4 {
23
28
  this.streamId = (0, uuid_1.v4)();
24
29
  this.audio = new track_1.MediaStreamTrack({ kind: "audio", streamId: this.streamId });
25
30
  this.video = new track_1.MediaStreamTrack({ kind: "video", streamId: this.streamId });
31
+ this.stopped = false;
26
32
  this.setupTrack = (port, track) => {
27
33
  let payloadType = 0;
28
34
  const socket = (0, dgram_1.createSocket)("udp4");
@@ -54,14 +60,79 @@ queue ! h264parse ! rtph264pay config-interval=10 pt=${payloadType++} ! \
54
60
  udpsink host=127.0.0.1 port=${this.videoPort} d. ! \
55
61
  queue ! aacparse ! avdec_aac ! audioresample ! audioconvert ! opusenc ! rtpopuspay pt=${payloadType++} ! \
56
62
  udpsink host=127.0.0.1 port=${this.audioPort}`;
57
- const process = (0, child_process_1.exec)(cmd);
63
+ this.process = (0, child_process_1.exec)(cmd);
58
64
  if (this.loop) {
59
- await new Promise((r) => process.on("close", r));
60
- run();
65
+ await new Promise((r) => this.process.on("close", r));
66
+ if (!this.stopped) {
67
+ run();
68
+ }
61
69
  }
62
70
  };
63
71
  await (0, promises_1.setImmediate)();
64
72
  run();
65
73
  }
74
+ stop() {
75
+ this.stopped = true;
76
+ this.process.kill("SIGINT");
77
+ }
78
+ }
79
+ exports.MediaPlayerMp4 = MediaPlayerMp4;
80
+ class MediaPlayerWebm {
81
+ constructor(videoPort, audioPort, path, loop) {
82
+ this.videoPort = videoPort;
83
+ this.audioPort = audioPort;
84
+ this.path = path;
85
+ this.loop = loop;
86
+ this.streamId = (0, uuid_1.v4)();
87
+ this.audio = new track_1.MediaStreamTrack({ kind: "audio", streamId: this.streamId });
88
+ this.video = new track_1.MediaStreamTrack({ kind: "video", streamId: this.streamId });
89
+ this.stopped = false;
90
+ this.setupTrack = (port, track) => {
91
+ let payloadType = 0;
92
+ const socket = (0, dgram_1.createSocket)("udp4");
93
+ socket.bind(port);
94
+ socket.on("message", async (buf) => {
95
+ const rtp = src_2.RtpPacket.deSerialize(buf);
96
+ if (!payloadType) {
97
+ payloadType = rtp.header.payloadType;
98
+ }
99
+ // detect gStreamer restarted
100
+ if (payloadType !== rtp.header.payloadType) {
101
+ payloadType = rtp.header.payloadType;
102
+ track.onSourceChanged.execute(rtp.header);
103
+ }
104
+ track.writeRtp(buf);
105
+ });
106
+ };
107
+ this.setupTrack(audioPort, this.audio);
108
+ this.setupTrack(videoPort, this.video);
109
+ }
110
+ async start() {
111
+ let payloadType = 96;
112
+ const run = async () => {
113
+ if (payloadType > 100)
114
+ payloadType = 96;
115
+ const cmd = `gst-launch-1.0 filesrc location=${this.path} ! matroskademux name=d \
116
+ d.video_0 ! queue ! rtpvp8pay pt=${payloadType++} ! \
117
+ udpsink host=127.0.0.1 port=${this.videoPort} \
118
+ d.audio_0 ! queue ! rtpopuspay pt=${payloadType++} ! \
119
+ udpsink host=127.0.0.1 port=${this.audioPort}`;
120
+ this.process = (0, child_process_1.exec)(cmd);
121
+ console.log(cmd);
122
+ if (this.loop) {
123
+ await new Promise((r) => this.process.on("close", r));
124
+ if (!this.stopped) {
125
+ run();
126
+ }
127
+ }
128
+ };
129
+ await (0, promises_1.setImmediate)();
130
+ run();
131
+ }
132
+ stop() {
133
+ this.stopped = true;
134
+ this.process.kill("SIGINT");
135
+ }
66
136
  }
137
+ exports.MediaPlayerWebm = MediaPlayerWebm;
67
138
  //# sourceMappingURL=userMedia.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"userMedia.js","sourceRoot":"","sources":["../../../../src/nonstandard/userMedia.ts"],"names":[],"mappings":"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","sourcesContent":["import { exec } from \"child_process\";\nimport { createSocket } from \"dgram\";\nimport { setImmediate } from \"timers/promises\";\nimport { v4 } from \"uuid\";\n\nimport { randomPort } from \"../../../common/src\";\nimport { RtpPacket } from \"../../../rtp/src\";\nimport { MediaStreamTrack } from \"../media/track\";\n\nexport const getUserMp4 = async (path: string, loop?: boolean) => {\n const audioPort = await randomPort();\n const videoPort = await randomPort();\n\n return new MediaMp4(audioPort, videoPort, path, loop);\n};\n\nclass MediaMp4 {\n private streamId = v4();\n audio = new MediaStreamTrack({ kind: \"audio\", streamId: this.streamId });\n video = new MediaStreamTrack({ kind: \"video\", streamId: this.streamId });\n\n constructor(\n private videoPort: number,\n private audioPort: number,\n private path: string,\n private loop?: boolean\n ) {\n this.setupTrack(audioPort, this.audio);\n this.setupTrack(videoPort, this.video);\n }\n\n private setupTrack = (port: number, track: MediaStreamTrack) => {\n let payloadType = 0;\n\n const socket = createSocket(\"udp4\");\n socket.bind(port);\n socket.on(\"message\", async (buf) => {\n const rtp = RtpPacket.deSerialize(buf);\n if (!payloadType) {\n payloadType = rtp.header.payloadType;\n }\n\n // detect gStreamer restarted\n if (payloadType !== rtp.header.payloadType) {\n payloadType = rtp.header.payloadType;\n track.onSourceChanged.execute(rtp.header);\n }\n\n track.writeRtp(buf);\n });\n };\n\n async start() {\n let payloadType = 96;\n const run = async () => {\n if (payloadType > 100) payloadType = 96;\n\n const cmd = `gst-launch-1.0 filesrc location= ${this.path} ! \\\nqtdemux name=d ! \\\nqueue ! h264parse ! rtph264pay config-interval=10 pt=${payloadType++} ! \\\nudpsink host=127.0.0.1 port=${this.videoPort} d. ! \\\nqueue ! aacparse ! avdec_aac ! audioresample ! audioconvert ! opusenc ! rtpopuspay pt=${payloadType++} ! \\\nudpsink host=127.0.0.1 port=${this.audioPort}`;\n const process = exec(cmd);\n\n if (this.loop) {\n await new Promise((r) => process.on(\"close\", r));\n run();\n }\n };\n await setImmediate();\n run();\n }\n}\n"]}
1
+ {"version":3,"file":"userMedia.js","sourceRoot":"","sources":["../../../../src/nonstandard/userMedia.ts"],"names":[],"mappings":";;;AAAA,iDAAmD;AACnD,iCAAqC;AACrC,8CAA+C;AAC/C,+BAA0B;AAE1B,6CAAiD;AACjD,0CAA6C;AAC7C,0CAAkD;AAE3C,MAAM,YAAY,GAAG,KAAK,EAAE,IAAY,EAAE,IAAc,EAAE,EAAE;IACjE,MAAM,SAAS,GAAG,MAAM,IAAA,gBAAU,GAAE,CAAC;IACrC,MAAM,SAAS,GAAG,MAAM,IAAA,gBAAU,GAAE,CAAC;IAErC,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE;QACzB,OAAO,IAAI,cAAc,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;KAC7D;SAAM;QACL,OAAO,IAAI,eAAe,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;KAC9D;AACH,CAAC,CAAC;AATW,QAAA,YAAY,gBASvB;AAEF,MAAa,cAAc;IAOzB,YACU,SAAiB,EACjB,SAAiB,EACjB,IAAY,EACZ,IAAc;QAHd,cAAS,GAAT,SAAS,CAAQ;QACjB,cAAS,GAAT,SAAS,CAAQ;QACjB,SAAI,GAAJ,IAAI,CAAQ;QACZ,SAAI,GAAJ,IAAI,CAAU;QAVhB,aAAQ,GAAG,IAAA,SAAE,GAAE,CAAC;QACxB,UAAK,GAAG,IAAI,wBAAgB,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;QACzE,UAAK,GAAG,IAAI,wBAAgB,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;QAEzE,YAAO,GAAG,KAAK,CAAC;QAYR,eAAU,GAAG,CAAC,IAAY,EAAE,KAAuB,EAAE,EAAE;YAC7D,IAAI,WAAW,GAAG,CAAC,CAAC;YAEpB,MAAM,MAAM,GAAG,IAAA,oBAAY,EAAC,MAAM,CAAC,CAAC;YACpC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClB,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;gBACjC,MAAM,GAAG,GAAG,eAAS,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;gBACvC,IAAI,CAAC,WAAW,EAAE;oBAChB,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC;iBACtC;gBAED,6BAA6B;gBAC7B,IAAI,WAAW,KAAK,GAAG,CAAC,MAAM,CAAC,WAAW,EAAE;oBAC1C,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC;oBACrC,KAAK,CAAC,eAAe,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;iBAC3C;gBAED,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YACtB,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;QAvBA,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IACzC,CAAC;IAuBD,KAAK,CAAC,KAAK;QACT,IAAI,WAAW,GAAG,EAAE,CAAC;QACrB,MAAM,GAAG,GAAG,KAAK,IAAI,EAAE;YACrB,IAAI,WAAW,GAAG,GAAG;gBAAE,WAAW,GAAG,EAAE,CAAC;YAExC,MAAM,GAAG,GAAG,oCAAoC,IAAI,CAAC,IAAI;;uDAER,WAAW,EAAE;8BACtC,IAAI,CAAC,SAAS;wFAC4C,WAAW,EAAE;8BACvE,IAAI,CAAC,SAAS,EAAE,CAAC;YACzC,IAAI,CAAC,OAAO,GAAG,IAAA,oBAAI,EAAC,GAAG,CAAC,CAAC;YAEzB,IAAI,IAAI,CAAC,IAAI,EAAE;gBACb,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;gBACtD,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;oBACjB,GAAG,EAAE,CAAC;iBACP;aACF;QACH,CAAC,CAAC;QACF,MAAM,IAAA,uBAAY,GAAE,CAAC;QACrB,GAAG,EAAE,CAAC;IACR,CAAC;IAED,IAAI;QACF,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC9B,CAAC;CACF;AAlED,wCAkEC;AAED,MAAa,eAAe;IAO1B,YACU,SAAiB,EACjB,SAAiB,EACjB,IAAY,EACZ,IAAc;QAHd,cAAS,GAAT,SAAS,CAAQ;QACjB,cAAS,GAAT,SAAS,CAAQ;QACjB,SAAI,GAAJ,IAAI,CAAQ;QACZ,SAAI,GAAJ,IAAI,CAAU;QAVhB,aAAQ,GAAG,IAAA,SAAE,GAAE,CAAC;QACxB,UAAK,GAAG,IAAI,wBAAgB,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;QACzE,UAAK,GAAG,IAAI,wBAAgB,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;QAEzE,YAAO,GAAG,KAAK,CAAC;QAYR,eAAU,GAAG,CAAC,IAAY,EAAE,KAAuB,EAAE,EAAE;YAC7D,IAAI,WAAW,GAAG,CAAC,CAAC;YAEpB,MAAM,MAAM,GAAG,IAAA,oBAAY,EAAC,MAAM,CAAC,CAAC;YACpC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClB,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;gBACjC,MAAM,GAAG,GAAG,eAAS,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;gBACvC,IAAI,CAAC,WAAW,EAAE;oBAChB,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC;iBACtC;gBAED,6BAA6B;gBAC7B,IAAI,WAAW,KAAK,GAAG,CAAC,MAAM,CAAC,WAAW,EAAE;oBAC1C,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC;oBACrC,KAAK,CAAC,eAAe,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;iBAC3C;gBACD,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YACtB,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;QAtBA,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IACzC,CAAC;IAsBD,KAAK,CAAC,KAAK;QACT,IAAI,WAAW,GAAG,EAAE,CAAC;QACrB,MAAM,GAAG,GAAG,KAAK,IAAI,EAAE;YACrB,IAAI,WAAW,GAAG,GAAG;gBAAE,WAAW,GAAG,EAAE,CAAC;YAExC,MAAM,GAAG,GAAG,mCACV,IAAI,CAAC,IACP;mCAC6B,WAAW,EAAE;8BAClB,IAAI,CAAC,SAAS;oCACR,WAAW,EAAE;8BACnB,IAAI,CAAC,SAAS,EAAE,CAAC;YACzC,IAAI,CAAC,OAAO,GAAG,IAAA,oBAAI,EAAC,GAAG,CAAC,CAAC;YACzB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAEjB,IAAI,IAAI,CAAC,IAAI,EAAE;gBACb,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;gBACtD,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;oBACjB,GAAG,EAAE,CAAC;iBACP;aACF;QACH,CAAC,CAAC;QACF,MAAM,IAAA,uBAAY,GAAE,CAAC;QACrB,GAAG,EAAE,CAAC;IACR,CAAC;IAED,IAAI;QACF,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC9B,CAAC;CACF;AAnED,0CAmEC","sourcesContent":["import { ChildProcess, exec } from \"child_process\";\nimport { createSocket } from \"dgram\";\nimport { setImmediate } from \"timers/promises\";\nimport { v4 } from \"uuid\";\n\nimport { randomPort } from \"../../../common/src\";\nimport { RtpPacket } from \"../../../rtp/src\";\nimport { MediaStreamTrack } from \"../media/track\";\n\nexport const getUserMedia = async (path: string, loop?: boolean) => {\n const audioPort = await randomPort();\n const videoPort = await randomPort();\n\n if (path.endsWith(\".mp4\")) {\n return new MediaPlayerMp4(audioPort, videoPort, path, loop);\n } else {\n return new MediaPlayerWebm(audioPort, videoPort, path, loop);\n }\n};\n\nexport class MediaPlayerMp4 {\n private streamId = v4();\n audio = new MediaStreamTrack({ kind: \"audio\", streamId: this.streamId });\n video = new MediaStreamTrack({ kind: \"video\", streamId: this.streamId });\n private process!: ChildProcess;\n stopped = false;\n\n constructor(\n private videoPort: number,\n private audioPort: number,\n private path: string,\n private loop?: boolean\n ) {\n this.setupTrack(audioPort, this.audio);\n this.setupTrack(videoPort, this.video);\n }\n\n private setupTrack = (port: number, track: MediaStreamTrack) => {\n let payloadType = 0;\n\n const socket = createSocket(\"udp4\");\n socket.bind(port);\n socket.on(\"message\", async (buf) => {\n const rtp = RtpPacket.deSerialize(buf);\n if (!payloadType) {\n payloadType = rtp.header.payloadType;\n }\n\n // detect gStreamer restarted\n if (payloadType !== rtp.header.payloadType) {\n payloadType = rtp.header.payloadType;\n track.onSourceChanged.execute(rtp.header);\n }\n\n track.writeRtp(buf);\n });\n };\n\n async start() {\n let payloadType = 96;\n const run = async () => {\n if (payloadType > 100) payloadType = 96;\n\n const cmd = `gst-launch-1.0 filesrc location= ${this.path} ! \\\nqtdemux name=d ! \\\nqueue ! h264parse ! rtph264pay config-interval=10 pt=${payloadType++} ! \\\nudpsink host=127.0.0.1 port=${this.videoPort} d. ! \\\nqueue ! aacparse ! avdec_aac ! audioresample ! audioconvert ! opusenc ! rtpopuspay pt=${payloadType++} ! \\\nudpsink host=127.0.0.1 port=${this.audioPort}`;\n this.process = exec(cmd);\n\n if (this.loop) {\n await new Promise((r) => this.process.on(\"close\", r));\n if (!this.stopped) {\n run();\n }\n }\n };\n await setImmediate();\n run();\n }\n\n stop() {\n this.stopped = true;\n this.process.kill(\"SIGINT\");\n }\n}\n\nexport class MediaPlayerWebm {\n private streamId = v4();\n audio = new MediaStreamTrack({ kind: \"audio\", streamId: this.streamId });\n video = new MediaStreamTrack({ kind: \"video\", streamId: this.streamId });\n private process!: ChildProcess;\n stopped = false;\n\n constructor(\n private videoPort: number,\n private audioPort: number,\n private path: string,\n private loop?: boolean\n ) {\n this.setupTrack(audioPort, this.audio);\n this.setupTrack(videoPort, this.video);\n }\n\n private setupTrack = (port: number, track: MediaStreamTrack) => {\n let payloadType = 0;\n\n const socket = createSocket(\"udp4\");\n socket.bind(port);\n socket.on(\"message\", async (buf) => {\n const rtp = RtpPacket.deSerialize(buf);\n if (!payloadType) {\n payloadType = rtp.header.payloadType;\n }\n\n // detect gStreamer restarted\n if (payloadType !== rtp.header.payloadType) {\n payloadType = rtp.header.payloadType;\n track.onSourceChanged.execute(rtp.header);\n }\n track.writeRtp(buf);\n });\n };\n\n async start() {\n let payloadType = 96;\n const run = async () => {\n if (payloadType > 100) payloadType = 96;\n\n const cmd = `gst-launch-1.0 filesrc location=${\n this.path\n } ! matroskademux name=d \\\nd.video_0 ! queue ! rtpvp8pay pt=${payloadType++} ! \\\nudpsink host=127.0.0.1 port=${this.videoPort} \\\nd.audio_0 ! queue ! rtpopuspay pt=${payloadType++} ! \\\nudpsink host=127.0.0.1 port=${this.audioPort}`;\n this.process = exec(cmd);\n console.log(cmd);\n\n if (this.loop) {\n await new Promise((r) => this.process.on(\"close\", r));\n if (!this.stopped) {\n run();\n }\n }\n };\n await setImmediate();\n run();\n }\n\n stop() {\n this.stopped = true;\n this.process.kill(\"SIGINT\");\n }\n}\n"]}
@@ -19,14 +19,16 @@ import { Callback, CallbackWithValue } from "./types/util";
19
19
  export declare class RTCPeerConnection extends EventTarget {
20
20
  readonly cname: string;
21
21
  sctpTransport?: RTCSctpTransport;
22
- masterTransportEstablished: boolean;
22
+ transportEstablished: boolean;
23
23
  config: Required<PeerConfig>;
24
24
  connectionState: ConnectionState;
25
25
  iceConnectionState: RTCIceConnectionState;
26
26
  iceGatheringState: IceGathererState;
27
27
  signalingState: RTCSignalingState;
28
28
  negotiationneeded: boolean;
29
- readonly transceivers: RTCRtpTransceiver[];
29
+ private readonly transceivers;
30
+ private pushTransceiver;
31
+ private replaceTransceiver;
30
32
  candidatesSent: Set<string>;
31
33
  readonly iceGatheringStateChange: Event<["new" | "complete" | "gathering"]>;
32
34
  readonly iceConnectionStateChange: Event<["disconnected" | "closed" | "completed" | "new" | "connected" | "failed" | "checking"]>;
@@ -99,6 +101,7 @@ export declare class RTCPeerConnection extends EventTarget {
99
101
  private validateDescription;
100
102
  private fireOnTrack;
101
103
  addTransceiver(trackOrKind: Kind | MediaStreamTrack, options?: Partial<TransceiverOptions>): RTCRtpTransceiver;
104
+ private _addTransceiver;
102
105
  getTransceivers(): RTCRtpTransceiver[];
103
106
  getSenders(): RTCRtpSender[];
104
107
  getReceivers(): RTCRtpReceiver[];
@@ -53,7 +53,7 @@ class RTCPeerConnection extends helper_1.EventTarget {
53
53
  constructor(config = {}) {
54
54
  super();
55
55
  this.cname = uuid.v4();
56
- this.masterTransportEstablished = false;
56
+ this.transportEstablished = false;
57
57
  this.config = (0, cloneDeep_1.default)(exports.defaultPeerConfig);
58
58
  this.connectionState = "new";
59
59
  this.iceConnectionState = "new";
@@ -145,6 +145,12 @@ class RTCPeerConnection extends helper_1.EventTarget {
145
145
  }
146
146
  });
147
147
  }
148
+ pushTransceiver(t) {
149
+ this.transceivers.push(t);
150
+ }
151
+ replaceTransceiver(t, index) {
152
+ this.transceivers[index] = t;
153
+ }
148
154
  get dtlsTransports() {
149
155
  const transports = this.transceivers.map((t) => t.dtlsTransport);
150
156
  if (this.sctpTransport) {
@@ -191,12 +197,12 @@ class RTCPeerConnection extends helper_1.EventTarget {
191
197
  const codecs = this.config.codecs[transceiver.kind].filter((codecCandidate) => {
192
198
  switch (codecCandidate.direction) {
193
199
  case "recvonly": {
194
- if ([_1.Recvonly, _1.Sendrecv].includes(transceiver.direction))
200
+ if (const_1.ReceiverDirection.includes(transceiver.direction))
195
201
  return true;
196
202
  return false;
197
203
  }
198
204
  case "sendonly": {
199
- if ([_1.Sendonly, _1.Sendrecv].includes(transceiver.direction))
205
+ if (const_1.SenderDirections.includes(transceiver.direction))
200
206
  return true;
201
207
  return false;
202
208
  }
@@ -320,8 +326,9 @@ class RTCPeerConnection extends helper_1.EventTarget {
320
326
  removeTrack(sender) {
321
327
  if (this.isClosed)
322
328
  throw new Error("peer closed");
323
- if (!this.getSenders().find(({ ssrc }) => sender.ssrc === ssrc))
329
+ if (!this.getSenders().find(({ ssrc }) => sender.ssrc === ssrc)) {
324
330
  throw new Error("unExist");
331
+ }
325
332
  const transceiver = this.transceivers.find(({ sender: { ssrc } }) => sender.ssrc === ssrc);
326
333
  if (!transceiver)
327
334
  throw new Error("unExist");
@@ -331,15 +338,15 @@ class RTCPeerConnection extends helper_1.EventTarget {
331
338
  return;
332
339
  }
333
340
  if (transceiver.stopping || transceiver.stopped) {
334
- transceiver.direction = "inactive";
341
+ transceiver.setDirection("inactive");
335
342
  }
336
343
  else {
337
344
  if (transceiver.direction === "sendrecv") {
338
- transceiver.direction = "recvonly";
345
+ transceiver.setDirection("recvonly");
339
346
  }
340
347
  else if (transceiver.direction === "sendonly" ||
341
348
  transceiver.direction === "recvonly") {
342
- transceiver.direction = "inactive";
349
+ transceiver.setDirection("inactive");
343
350
  }
344
351
  }
345
352
  this.needNegotiation();
@@ -485,24 +492,30 @@ class RTCPeerConnection extends helper_1.EventTarget {
485
492
  };
486
493
  this.dtlsTransports.forEach((d) => setupRole(d));
487
494
  // # configure direction
488
- this.transceivers.forEach((t) => {
489
- if (["answer", "pranswer"].includes(description.type)) {
495
+ if (["answer", "pranswer"].includes(description.type)) {
496
+ this.transceivers.forEach((t) => {
490
497
  const direction = (0, utils_1.andDirection)(t.direction, t.offerDirection);
491
- t.currentDirection = direction;
492
- }
493
- });
498
+ t.setCurrentDirection(direction);
499
+ });
500
+ }
494
501
  // for trickle ice
495
502
  this.setLocal(description);
496
503
  // connect transports
497
504
  if (description.type === "answer") {
498
- log("callee start connect");
499
505
  this.connect().catch((err) => {
500
506
  log("connect failed", err);
501
507
  this.setConnectionState("failed");
502
508
  });
503
509
  }
504
510
  // # gather candidates
505
- await Promise.all(this.iceTransports.map((iceTransport) => iceTransport.iceGather.gather()));
511
+ const connected = this.iceTransports.find((transport) => transport.state === "connected");
512
+ if (this.remoteIsBundled && connected) {
513
+ // no need to gather ice candidates on an existing bundled connection
514
+ await connected.iceGather.gather();
515
+ }
516
+ else {
517
+ await Promise.all(this.iceTransports.map((iceTransport) => iceTransport.iceGather.gather()));
518
+ }
506
519
  description.media
507
520
  .filter((m) => ["audio", "video"].includes(m.kind))
508
521
  .forEach((m, i) => {
@@ -570,8 +583,10 @@ class RTCPeerConnection extends helper_1.EventTarget {
570
583
  }
571
584
  }
572
585
  async connect() {
573
- if (this.masterTransportEstablished)
586
+ if (this.transportEstablished) {
574
587
  return;
588
+ }
589
+ log("start connect");
575
590
  this.setConnectionState("connecting");
576
591
  await Promise.all(this.dtlsTransports.map(async (dtlsTransport) => {
577
592
  const { iceTransport } = dtlsTransport;
@@ -591,7 +606,7 @@ class RTCPeerConnection extends helper_1.EventTarget {
591
606
  log("sctp connected");
592
607
  }
593
608
  }));
594
- this.masterTransportEstablished = true;
609
+ this.transportEstablished = true;
595
610
  this.setConnectionState("connected");
596
611
  }
597
612
  getLocalRtpParams(transceiver) {
@@ -652,13 +667,13 @@ class RTCPeerConnection extends helper_1.EventTarget {
652
667
  // # apply description
653
668
  const matchTransceiverWithMedia = (transceiver, media) => transceiver.kind === media.kind &&
654
669
  [undefined, media.rtp.muxId].includes(transceiver.mid);
655
- let transports = (0, helper_1.enumerate)(remoteSdp.media).map(([i, remoteMedia]) => {
670
+ let transports = remoteSdp.media.map((remoteMedia, i) => {
656
671
  let dtlsTransport;
657
672
  if (["audio", "video"].includes(remoteMedia.kind)) {
658
673
  let transceiver = this.transceivers.find((t) => matchTransceiverWithMedia(t, remoteMedia));
659
674
  if (!transceiver) {
660
675
  // create remote transceiver
661
- transceiver = this.addTransceiver(remoteMedia.kind, {
676
+ transceiver = this._addTransceiver(remoteMedia.kind, {
662
677
  direction: "recvonly",
663
678
  });
664
679
  transceiver.mid = remoteMedia.rtp.muxId;
@@ -667,7 +682,9 @@ class RTCPeerConnection extends helper_1.EventTarget {
667
682
  else {
668
683
  if (transceiver.direction === "inactive" && transceiver.stopping) {
669
684
  transceiver.stopped = true;
670
- transceiver.currentDirection = "inactive";
685
+ if (sessionDescription.type === "answer") {
686
+ transceiver.setCurrentDirection("inactive");
687
+ }
671
688
  return;
672
689
  }
673
690
  }
@@ -749,9 +766,14 @@ class RTCPeerConnection extends helper_1.EventTarget {
749
766
  this.setConnectionState("failed");
750
767
  });
751
768
  }
752
- await Promise.all(transports.map(async (iceTransport) => {
753
- await iceTransport.iceGather.gather();
754
- }));
769
+ const connected = this.iceTransports.find((transport) => transport.state === "connected");
770
+ if (this.remoteIsBundled && connected) {
771
+ // no need to gather ice candidates on an existing bundled connection
772
+ await connected.iceGather.gather();
773
+ }
774
+ else {
775
+ await Promise.all(transports.map((iceTransport) => iceTransport.iceGather.gather()));
776
+ }
755
777
  this.negotiationneeded = false;
756
778
  if (this.shouldNegotiationneeded) {
757
779
  this.needNegotiation();
@@ -760,8 +782,8 @@ class RTCPeerConnection extends helper_1.EventTarget {
760
782
  setRemoteRTP(transceiver, remoteMedia, type, mLineIndex) {
761
783
  if (!transceiver.mid) {
762
784
  transceiver.mid = remoteMedia.rtp.muxId;
763
- transceiver.mLineIndex = mLineIndex;
764
785
  }
786
+ transceiver.mLineIndex = mLineIndex;
765
787
  // # negotiate codecs
766
788
  transceiver.codecs = remoteMedia.rtp.codecs.filter((remoteCodec) => {
767
789
  const localCodecs = this.config.codecs[remoteMedia.kind] || [];
@@ -784,10 +806,10 @@ class RTCPeerConnection extends helper_1.EventTarget {
784
806
  }
785
807
  transceiver.headerExtensions = remoteMedia.rtp.headerExtensions.filter((extension) => (this.config.headerExtensions[remoteMedia.kind] || []).find((v) => v.uri === extension.uri));
786
808
  // # configure direction
787
- const mediaDirection = remoteMedia.direction || "inactive";
809
+ const mediaDirection = remoteMedia.direction ?? "inactive";
788
810
  const direction = (0, utils_1.reverseDirection)(mediaDirection);
789
811
  if (["answer", "pranswer"].includes(type)) {
790
- transceiver.currentDirection = direction;
812
+ transceiver.setCurrentDirection(direction);
791
813
  }
792
814
  else {
793
815
  transceiver.offerDirection = direction;
@@ -888,6 +910,9 @@ class RTCPeerConnection extends helper_1.EventTarget {
888
910
  this.ontrack(event);
889
911
  }
890
912
  addTransceiver(trackOrKind, options = {}) {
913
+ return this._addTransceiver(trackOrKind, options);
914
+ }
915
+ _addTransceiver(trackOrKind, options = {}) {
891
916
  const kind = typeof trackOrKind === "string" ? trackOrKind : trackOrKind.kind;
892
917
  const direction = options.direction || "sendrecv";
893
918
  const dtlsTransport = this.createTransport([
@@ -896,24 +921,24 @@ class RTCPeerConnection extends helper_1.EventTarget {
896
921
  ]);
897
922
  const sender = new rtpSender_1.RTCRtpSender(trackOrKind);
898
923
  const receiver = new rtpReceiver_1.RTCRtpReceiver(this.config, kind, sender.ssrc);
899
- const transceiver = new rtpTransceiver_1.RTCRtpTransceiver(kind, dtlsTransport, receiver, sender, direction);
900
- transceiver.options = options;
901
- this.router.registerRtpSender(transceiver.sender);
924
+ const newTransceiver = new rtpTransceiver_1.RTCRtpTransceiver(kind, dtlsTransport, receiver, sender, direction);
925
+ newTransceiver.options = options;
926
+ this.router.registerRtpSender(newTransceiver.sender);
902
927
  // reuse inactive
903
928
  const inactiveTransceiverIndex = this.transceivers.findIndex((t) => t.currentDirection === "inactive");
904
929
  const inactiveTransceiver = this.transceivers.find((t) => t.currentDirection === "inactive");
905
- if (inactiveTransceiverIndex > -1) {
906
- this.transceivers[inactiveTransceiverIndex] = transceiver;
907
- transceiver.mLineIndex = inactiveTransceiver.mLineIndex;
908
- inactiveTransceiver.currentDirection = "stopped";
930
+ if (inactiveTransceiverIndex > -1 && inactiveTransceiver) {
931
+ this.replaceTransceiver(newTransceiver, inactiveTransceiverIndex);
932
+ newTransceiver.mLineIndex = inactiveTransceiver.mLineIndex;
933
+ inactiveTransceiver.setCurrentDirection(undefined);
909
934
  }
910
935
  else {
911
- this.transceivers.push(transceiver);
936
+ this.pushTransceiver(newTransceiver);
912
937
  }
913
- this.onTransceiverAdded.execute(transceiver);
938
+ this.onTransceiverAdded.execute(newTransceiver);
914
939
  this.updateIceConnectionState();
915
940
  this.needNegotiation();
916
- return transceiver;
941
+ return newTransceiver;
917
942
  }
918
943
  getTransceivers() {
919
944
  return this.transceivers;
@@ -951,17 +976,19 @@ class RTCPeerConnection extends helper_1.EventTarget {
951
976
  sender.registerTrack(track);
952
977
  switch (notSendTransceiver.direction) {
953
978
  case "recvonly":
954
- notSendTransceiver.direction = "sendrecv";
979
+ notSendTransceiver.setDirection("sendrecv");
955
980
  break;
956
981
  case "inactive":
957
- notSendTransceiver.direction = "sendonly";
982
+ notSendTransceiver.setDirection("sendonly");
958
983
  break;
959
984
  }
960
985
  this.needNegotiation();
961
986
  return sender;
962
987
  }
963
988
  else {
964
- const transceiver = this.addTransceiver(track, { direction: "sendrecv" });
989
+ const transceiver = this._addTransceiver(track, {
990
+ direction: "sendrecv",
991
+ });
965
992
  this.needNegotiation();
966
993
  return transceiver.sender;
967
994
  }
@@ -1014,14 +1041,13 @@ class RTCPeerConnection extends helper_1.EventTarget {
1014
1041
  throw new Error("invalid kind");
1015
1042
  }
1016
1043
  // # determine DTLS role, or preserve the currently configured role
1017
- if (!media.dtlsParams) {
1018
- throw new Error("dtlsParams missing");
1019
- }
1020
- if (dtlsTransport.role === "auto") {
1021
- media.dtlsParams.role = "client";
1022
- }
1023
- else {
1024
- media.dtlsParams.role = dtlsTransport.role;
1044
+ if (media.dtlsParams) {
1045
+ if (dtlsTransport.role === "auto") {
1046
+ media.dtlsParams.role = "client";
1047
+ }
1048
+ else {
1049
+ media.dtlsParams.role = dtlsTransport.role;
1050
+ }
1025
1051
  }
1026
1052
  media.simulcastParameters = remoteMedia.simulcastParameters.map((v) => ({
1027
1053
  ...v,