werift 0.23.0 → 0.24.1

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 (169) hide show
  1. package/README.md +46 -0
  2. package/lib/common/src/binary.js +2 -3
  3. package/lib/common/src/binary.js.map +1 -1
  4. package/lib/common/src/transport.d.ts +22 -9
  5. package/lib/common/src/transport.js +152 -25
  6. package/lib/common/src/transport.js.map +1 -1
  7. package/lib/ice/src/candidate.d.ts +16 -1
  8. package/lib/ice/src/candidate.js +99 -15
  9. package/lib/ice/src/candidate.js.map +1 -1
  10. package/lib/ice/src/ice.d.ts +2 -0
  11. package/lib/ice/src/ice.js +175 -50
  12. package/lib/ice/src/ice.js.map +1 -1
  13. package/lib/ice/src/iceBase.d.ts +23 -2
  14. package/lib/ice/src/iceBase.js +63 -1
  15. package/lib/ice/src/iceBase.js.map +1 -1
  16. package/lib/ice/src/index.d.ts +2 -0
  17. package/lib/ice/src/index.js +2 -0
  18. package/lib/ice/src/index.js.map +1 -1
  19. package/lib/ice/src/internal/selectAddresses.d.ts +9 -0
  20. package/lib/ice/src/internal/selectAddresses.js +40 -0
  21. package/lib/ice/src/internal/selectAddresses.js.map +1 -0
  22. package/lib/ice/src/stun/const.d.ts +1 -26
  23. package/lib/ice/src/stun/const.js +15 -54
  24. package/lib/ice/src/stun/const.js.map +1 -1
  25. package/lib/ice/src/stun/message.d.ts +1 -25
  26. package/lib/ice/src/stun/message.js +15 -149
  27. package/lib/ice/src/stun/message.js.map +1 -1
  28. package/lib/ice/src/stun/protocol.d.ts +1 -1
  29. package/lib/ice/src/stun/protocol.js +2 -2
  30. package/lib/ice/src/stun/protocol.js.map +1 -1
  31. package/lib/ice/src/stun/tcpFrame.d.ts +5 -0
  32. package/lib/ice/src/stun/tcpFrame.js +26 -0
  33. package/lib/ice/src/stun/tcpFrame.js.map +1 -0
  34. package/lib/ice/src/stun/tcpProtocol.d.ts +51 -0
  35. package/lib/ice/src/stun/tcpProtocol.js +326 -0
  36. package/lib/ice/src/stun/tcpProtocol.js.map +1 -0
  37. package/lib/ice/src/stun/transaction.d.ts +2 -1
  38. package/lib/ice/src/stun/transaction.js +9 -3
  39. package/lib/ice/src/stun/transaction.js.map +1 -1
  40. package/lib/ice/src/turn/frame.d.ts +1 -0
  41. package/lib/ice/src/turn/frame.js +18 -0
  42. package/lib/ice/src/turn/frame.js.map +1 -0
  43. package/lib/ice/src/turn/protocol.d.ts +9 -7
  44. package/lib/ice/src/turn/protocol.js +32 -44
  45. package/lib/ice/src/turn/protocol.js.map +1 -1
  46. package/lib/ice/src/types/model.d.ts +1 -1
  47. package/lib/ice/src/types/model.js.map +1 -1
  48. package/lib/ice/src/utils.js +2 -31
  49. package/lib/ice/src/utils.js.map +1 -1
  50. package/lib/{ice → ice-server}/src/stun/attributes.d.ts +12 -5
  51. package/lib/{ice → ice-server}/src/stun/attributes.js +69 -66
  52. package/lib/ice-server/src/stun/attributes.js.map +1 -0
  53. package/lib/ice-server/src/stun/const.d.ts +28 -0
  54. package/lib/ice-server/src/stun/const.js +88 -0
  55. package/lib/ice-server/src/stun/const.js.map +1 -0
  56. package/lib/ice-server/src/stun/ip.d.ts +12 -0
  57. package/lib/ice-server/src/stun/ip.js +88 -0
  58. package/lib/ice-server/src/stun/ip.js.map +1 -0
  59. package/lib/ice-server/src/stun/message.d.ts +37 -0
  60. package/lib/ice-server/src/stun/message.js +190 -0
  61. package/lib/ice-server/src/stun/message.js.map +1 -0
  62. package/lib/ice-server/src/turn/auth.d.ts +1 -0
  63. package/lib/ice-server/src/turn/auth.js +10 -0
  64. package/lib/ice-server/src/turn/auth.js.map +1 -0
  65. package/lib/ice-server/src/turn/frame.d.ts +13 -0
  66. package/lib/ice-server/src/turn/frame.js +69 -0
  67. package/lib/ice-server/src/turn/frame.js.map +1 -0
  68. package/lib/index.mjs +2866 -946
  69. package/lib/nonstandard/index.mjs +1872 -455
  70. package/lib/rtp/src/codec/av1.js +11 -5
  71. package/lib/rtp/src/codec/av1.js.map +1 -1
  72. package/lib/rtp/src/codec/leb128.d.ts +5 -0
  73. package/lib/rtp/src/codec/leb128.js +24 -0
  74. package/lib/rtp/src/codec/leb128.js.map +1 -0
  75. package/lib/rtp/src/extra/container/mp4/container.d.ts +9 -6
  76. package/lib/rtp/src/extra/container/mp4/container.js +258 -173
  77. package/lib/rtp/src/extra/container/mp4/container.js.map +1 -1
  78. package/lib/rtp/src/extra/container/mp4/h264.d.ts +1 -0
  79. package/lib/rtp/src/extra/container/mp4/h264.js +13 -0
  80. package/lib/rtp/src/extra/container/mp4/h264.js.map +1 -1
  81. package/lib/rtp/src/extra/processor/mp4.d.ts +11 -7
  82. package/lib/rtp/src/extra/processor/mp4.js +115 -60
  83. package/lib/rtp/src/extra/processor/mp4.js.map +1 -1
  84. package/lib/rtp/src/extra/processor/mp4Callback.d.ts +2 -3
  85. package/lib/rtp/src/extra/processor/mp4Callback.js +5 -3
  86. package/lib/rtp/src/extra/processor/mp4Callback.js.map +1 -1
  87. package/lib/rtp/src/rtp/rtx.js +4 -6
  88. package/lib/rtp/src/rtp/rtx.js.map +1 -1
  89. package/lib/rtp/src/srtp/context/context.d.ts +2 -0
  90. package/lib/rtp/src/srtp/context/context.js +12 -12
  91. package/lib/rtp/src/srtp/context/context.js.map +1 -1
  92. package/lib/sctp/src/param.js +31 -15
  93. package/lib/sctp/src/param.js.map +1 -1
  94. package/lib/sctp/src/sctp.js +10 -9
  95. package/lib/sctp/src/sctp.js.map +1 -1
  96. package/lib/webrtc/src/dataChannel.d.ts +3 -2
  97. package/lib/webrtc/src/dataChannel.js +9 -2
  98. package/lib/webrtc/src/dataChannel.js.map +1 -1
  99. package/lib/webrtc/src/errors.d.ts +3 -0
  100. package/lib/webrtc/src/errors.js +11 -0
  101. package/lib/webrtc/src/errors.js.map +1 -0
  102. package/lib/webrtc/src/helper.d.ts +5 -1
  103. package/lib/webrtc/src/helper.js +33 -1
  104. package/lib/webrtc/src/helper.js.map +1 -1
  105. package/lib/webrtc/src/media/receiver/statistics.d.ts +4 -1
  106. package/lib/webrtc/src/media/receiver/statistics.js +22 -0
  107. package/lib/webrtc/src/media/receiver/statistics.js.map +1 -1
  108. package/lib/webrtc/src/media/rtpReceiver.d.ts +15 -2
  109. package/lib/webrtc/src/media/rtpReceiver.js +135 -20
  110. package/lib/webrtc/src/media/rtpReceiver.js.map +1 -1
  111. package/lib/webrtc/src/media/rtpSender.d.ts +32 -7
  112. package/lib/webrtc/src/media/rtpSender.js +179 -31
  113. package/lib/webrtc/src/media/rtpSender.js.map +1 -1
  114. package/lib/webrtc/src/media/rtpTransceiver.d.ts +13 -4
  115. package/lib/webrtc/src/media/rtpTransceiver.js +26 -5
  116. package/lib/webrtc/src/media/rtpTransceiver.js.map +1 -1
  117. package/lib/webrtc/src/media/stats.d.ts +15 -1
  118. package/lib/webrtc/src/media/stats.js +55 -1
  119. package/lib/webrtc/src/media/stats.js.map +1 -1
  120. package/lib/webrtc/src/media/track.d.ts +2 -1
  121. package/lib/webrtc/src/media/track.js +7 -1
  122. package/lib/webrtc/src/media/track.js.map +1 -1
  123. package/lib/webrtc/src/nonstandard/dummyMedia.d.ts +19 -0
  124. package/lib/webrtc/src/nonstandard/dummyMedia.js +157 -0
  125. package/lib/webrtc/src/nonstandard/dummyMedia.js.map +1 -0
  126. package/lib/webrtc/src/nonstandard/navigator.d.ts +18 -8
  127. package/lib/webrtc/src/nonstandard/navigator.js +96 -32
  128. package/lib/webrtc/src/nonstandard/navigator.js.map +1 -1
  129. package/lib/webrtc/src/nonstandard/userMedia/packetizer.d.ts +16 -0
  130. package/lib/webrtc/src/nonstandard/userMedia/packetizer.js +360 -0
  131. package/lib/webrtc/src/nonstandard/userMedia/packetizer.js.map +1 -0
  132. package/lib/webrtc/src/nonstandard/userMedia.d.ts +71 -31
  133. package/lib/webrtc/src/nonstandard/userMedia.js +454 -108
  134. package/lib/webrtc/src/nonstandard/userMedia.js.map +1 -1
  135. package/lib/webrtc/src/peerConnection.d.ts +183 -50
  136. package/lib/webrtc/src/peerConnection.js +458 -109
  137. package/lib/webrtc/src/peerConnection.js.map +1 -1
  138. package/lib/webrtc/src/sctpManager.d.ts +1 -1
  139. package/lib/webrtc/src/sctpManager.js +27 -7
  140. package/lib/webrtc/src/sctpManager.js.map +1 -1
  141. package/lib/webrtc/src/sdp.d.ts +10 -7
  142. package/lib/webrtc/src/sdp.js +40 -44
  143. package/lib/webrtc/src/sdp.js.map +1 -1
  144. package/lib/webrtc/src/sdpManager.d.ts +4 -3
  145. package/lib/webrtc/src/sdpManager.js +50 -27
  146. package/lib/webrtc/src/sdpManager.js.map +1 -1
  147. package/lib/webrtc/src/secureTransportManager.d.ts +13 -4
  148. package/lib/webrtc/src/secureTransportManager.js +100 -22
  149. package/lib/webrtc/src/secureTransportManager.js.map +1 -1
  150. package/lib/webrtc/src/transceiverManager.d.ts +5 -4
  151. package/lib/webrtc/src/transceiverManager.js +61 -62
  152. package/lib/webrtc/src/transceiverManager.js.map +1 -1
  153. package/lib/webrtc/src/transport/dtls.d.ts +15 -4
  154. package/lib/webrtc/src/transport/dtls.js +91 -23
  155. package/lib/webrtc/src/transport/dtls.js.map +1 -1
  156. package/lib/webrtc/src/transport/ice.d.ts +21 -3
  157. package/lib/webrtc/src/transport/ice.js +159 -30
  158. package/lib/webrtc/src/transport/ice.js.map +1 -1
  159. package/lib/webrtc/src/transport/sctp.d.ts +1 -0
  160. package/lib/webrtc/src/transport/sctp.js +26 -22
  161. package/lib/webrtc/src/transport/sctp.js.map +1 -1
  162. package/lib/webrtc/src/utils.d.ts +12 -4
  163. package/lib/webrtc/src/utils.js +118 -16
  164. package/lib/webrtc/src/utils.js.map +1 -1
  165. package/package.json +7 -10
  166. package/lib/ice/src/stun/attributes.js.map +0 -1
  167. package/lib/rtp/src/extra/container/mp4/mp4box.d.ts +0 -5
  168. package/lib/rtp/src/extra/container/mp4/mp4box.js +0 -32
  169. package/lib/rtp/src/extra/container/mp4/mp4box.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"rtpTransceiver.js","sourceRoot":"","sources":["../../../../src/media/rtpTransceiver.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"crypto\";\nimport { Event } from \"../imports/common\";\n\nimport type { RTCDtlsTransport } from \"..\";\nimport { SenderDirections } from \"../const\";\nimport type { Kind } from \"../types/domain\";\nimport type {\n RTCRtpCodecParameters,\n RTCRtpHeaderExtensionParameters,\n} from \"./parameters\";\nimport type { RTCRtpReceiver } from \"./rtpReceiver\";\nimport type { RTCRtpSender } from \"./rtpSender\";\nimport {\n type RTCCodecStats,\n type RTCStats,\n generateStatsId,\n getStatsTimestamp,\n} from \"./stats\";\nimport type { MediaStream, MediaStreamTrack } from \"./track\";\n\nexport class RTCRtpTransceiver {\n readonly id = randomUUID().toString();\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?: MediaDirection;\n offerDirection!: MediaDirection;\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 | undefined,\n public receiver: RTCRtpReceiver,\n public sender: RTCRtpSender,\n /**RFC 8829 4.2.4. direction the transceiver was initialized with */\n private _direction: MediaDirection,\n ) {\n if (dtlsTransport) {\n this.setDtlsTransport(dtlsTransport);\n }\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: MediaDirection) {\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(): MediaDirection | undefined {\n return this._currentDirection;\n }\n\n setCurrentDirection(direction: MediaDirection | 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 getCodecStats(): RTCStats[] {\n const timestamp = getStatsTimestamp();\n const stats: RTCStats[] = [];\n\n if (!this.dtlsTransport) {\n return stats;\n }\n\n const transportId = generateStatsId(\"transport\", this.dtlsTransport.id);\n\n // Add codec stats for each codec\n for (const codec of this.codecs) {\n const codecStats: RTCCodecStats = {\n type: \"codec\",\n id: generateStatsId(\"codec\", codec.payloadType, transportId),\n timestamp,\n payloadType: codec.payloadType,\n transportId,\n mimeType: codec.mimeType,\n clockRate: codec.clockRate,\n channels: codec.channels,\n sdpFmtpLine: codec.parameters,\n };\n stats.push(codecStats);\n }\n\n return stats;\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 MediaDirection = (typeof Directions)[number];\n\ntype SimulcastDirection = \"send\" | \"recv\";\n\nexport interface TransceiverOptions {\n direction: MediaDirection;\n simulcast: { direction: SimulcastDirection; rid: string }[];\n streams: MediaStream[];\n}\n"]}
1
+ {"version":3,"file":"rtpTransceiver.js","sourceRoot":"","sources":["../../../../src/media/rtpTransceiver.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"crypto\";\nimport { Event } from \"../imports/common\";\n\nimport type { RTCDtlsTransport } from \"..\";\nimport { SenderDirections } from \"../const\";\nimport type { Kind } from \"../types/domain\";\nimport type {\n RTCRtpCodecParameters,\n RTCRtpHeaderExtensionParameters,\n} from \"./parameters\";\nimport type { RTCRtpReceiver } from \"./rtpReceiver\";\nimport type { RTCRtpSender } from \"./rtpSender\";\nimport {\n type RTCCodecStats,\n type RTCStats,\n generateCodecStatsId,\n generateStatsId,\n getStatsTimestamp,\n} from \"./stats\";\nimport type { MediaStream, MediaStreamTrack } from \"./track\";\n\nexport class RTCRtpTransceiver {\n readonly id = randomUUID().toString();\n readonly onTrack = new Event<[MediaStreamTrack, RTCRtpTransceiver]>();\n mid: string | null = null;\n mLineIndex?: number;\n /**should not be reused because it has been used for sending before. */\n usedForSender = false;\n private _currentDirection?: CurrentDirection;\n offerDirection!: MediaDirection;\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 | undefined,\n public receiver: RTCRtpReceiver,\n public sender: RTCRtpSender,\n /**RFC 8829 4.2.4. direction the transceiver was initialized with */\n private _direction: MediaDirection,\n ) {\n if (dtlsTransport) {\n this.setDtlsTransport(dtlsTransport);\n }\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 set direction(direction: MediaDirection) {\n this.setDirection(direction);\n }\n\n setDirection(direction: MediaDirection) {\n this._direction = direction;\n if (\n this._currentDirection &&\n this._currentDirection !== \"stopped\" &&\n SenderDirections.includes(this._currentDirection)\n ) {\n this.usedForSender = true;\n }\n }\n\n /**RFC 8829 4.2.5. last negotiated direction */\n get currentDirection(): CurrentDirection | null {\n return this._currentDirection ?? null;\n }\n\n setCurrentDirection(direction: CurrentDirection | 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.msids[0];\n }\n\n get msids() {\n return this.sender.streamIds.map(\n (streamId) => `${streamId} ${this.sender.trackId}`,\n );\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 forceStop() {\n if (this.stopped) {\n return;\n }\n\n this.stopping = true;\n this.stopped = true;\n this.setCurrentDirection(\"stopped\");\n this.receiver.stop();\n this.sender.stop();\n }\n\n getPayloadType(mimeType: string) {\n return this.codecs.find((codec) =>\n codec.mimeType.toLowerCase().includes(mimeType.toLowerCase()),\n )?.payloadType;\n }\n\n getCodecStats(): RTCStats[] {\n const timestamp = getStatsTimestamp();\n return this.collectCodecStats(timestamp);\n }\n\n collectCodecStats(timestamp: number): RTCStats[] {\n const stats: RTCStats[] = [];\n\n if (!this.dtlsTransport) {\n return stats;\n }\n\n const transportId = generateStatsId(\"transport\", this.dtlsTransport.id);\n\n // Add codec stats for each codec\n for (const codec of this.codecs) {\n const codecStats: RTCCodecStats = {\n type: \"codec\",\n id: generateCodecStatsId(transportId, codec.payloadType, this.id),\n timestamp,\n payloadType: codec.payloadType,\n transportId,\n mimeType: codec.mimeType,\n clockRate: codec.clockRate,\n channels: codec.channels,\n sdpFmtpLine: codec.parameters,\n };\n stats.push(codecStats);\n }\n\n return stats;\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 MediaDirection = (typeof Directions)[number];\nexport type CurrentDirection = MediaDirection | \"stopped\";\n\ntype SimulcastDirection = \"send\" | \"recv\";\n\nexport interface RTCRtpEncodingParameters {\n active?: boolean;\n}\n\nexport interface TransceiverOptions {\n direction: MediaDirection;\n sendEncodings: RTCRtpEncodingParameters[];\n simulcast: { direction: SimulcastDirection; rid: string }[];\n streams: MediaStream[];\n}\n"]}
@@ -2,7 +2,7 @@
2
2
  * WebRTC Statistics API implementation
3
3
  * Based on: https://www.w3.org/TR/webrtc-stats/
4
4
  */
5
- export type RTCStatsType = "codec" | "inbound-rtp" | "outbound-rtp" | "remote-inbound-rtp" | "remote-outbound-rtp" | "media-source" | "peer-connection" | "data-channel" | "transport" | "candidate-pair" | "local-candidate" | "remote-candidate" | "certificate";
5
+ export type RTCStatsType = "codec" | "inbound-rtp" | "outbound-rtp" | "remote-inbound-rtp" | "remote-outbound-rtp" | "media-source" | "media-playout" | "peer-connection" | "data-channel" | "transport" | "candidate-pair" | "local-candidate" | "remote-candidate" | "certificate";
6
6
  export interface RTCStats {
7
7
  timestamp: number;
8
8
  type: RTCStatsType;
@@ -16,6 +16,7 @@ export interface RTCRtpStreamStats extends RTCStats {
16
16
  }
17
17
  export interface RTCReceivedRtpStreamStats extends RTCRtpStreamStats {
18
18
  packetsReceived?: number;
19
+ bytesReceived?: number;
19
20
  packetsLost?: number;
20
21
  jitter?: number;
21
22
  packetsDiscarded?: number;
@@ -148,6 +149,15 @@ export interface RTCVideoSourceStats extends RTCMediaSourceStats {
148
149
  frames?: number;
149
150
  framesPerSecond?: number;
150
151
  }
152
+ export interface RTCAudioPlayoutStats extends RTCStats {
153
+ type: "media-playout";
154
+ kind: "audio";
155
+ synthesizedSamplesDuration?: number;
156
+ synthesizedSamplesEvents?: number;
157
+ totalSamplesDuration?: number;
158
+ totalPlayoutDelay?: number;
159
+ totalSamplesCount?: number;
160
+ }
151
161
  export interface RTCAudioSourceStats extends RTCMediaSourceStats {
152
162
  audioLevel?: number;
153
163
  totalAudioEnergy?: number;
@@ -226,6 +236,7 @@ export interface RTCIceCandidatePairStats extends RTCStats {
226
236
  lastPacketReceivedTimestamp?: number;
227
237
  totalRoundTripTime?: number;
228
238
  currentRoundTripTime?: number;
239
+ roundTripTimeMeasurements?: number;
229
240
  availableOutgoingBitrate?: number;
230
241
  availableIncomingBitrate?: number;
231
242
  requestsReceived?: number;
@@ -273,7 +284,10 @@ export declare class RTCStatsReport extends Map<string, RTCStats> {
273
284
  * Generate a unique ID for a statistics object
274
285
  */
275
286
  export declare function generateStatsId(type: string, ...parts: (string | number | undefined)[]): string;
287
+ export declare function generateCodecStatsId(transportId: string, payloadType: number, scopeId: string): string;
276
288
  /**
277
289
  * Get current timestamp in milliseconds (DOMHighResTimeStamp)
278
290
  */
279
291
  export declare function getStatsTimestamp(): number;
292
+ export declare function getReferencedStatsIds(stat: RTCStats): string[];
293
+ export declare function buildStatsReport(stats: Iterable<RTCStats>, rootIds?: Iterable<string>): RTCStatsReport;
@@ -6,7 +6,10 @@
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.RTCStatsReport = void 0;
8
8
  exports.generateStatsId = generateStatsId;
9
+ exports.generateCodecStatsId = generateCodecStatsId;
9
10
  exports.getStatsTimestamp = getStatsTimestamp;
11
+ exports.getReferencedStatsIds = getReferencedStatsIds;
12
+ exports.buildStatsReport = buildStatsReport;
10
13
  /**
11
14
  * RTCStatsReport is a Map-like object that holds WebRTC statistics
12
15
  */
@@ -28,10 +31,61 @@ function generateStatsId(type, ...parts) {
28
31
  const validParts = parts.filter((p) => p !== undefined);
29
32
  return `${type}_${validParts.join("_")}`;
30
33
  }
34
+ function generateCodecStatsId(transportId, payloadType, scopeId) {
35
+ return generateStatsId("codec", transportId, payloadType, scopeId);
36
+ }
31
37
  /**
32
38
  * Get current timestamp in milliseconds (DOMHighResTimeStamp)
33
39
  */
34
40
  function getStatsTimestamp() {
35
- return performance.now();
41
+ return performance.timeOrigin + performance.now();
42
+ }
43
+ function getReferencedStatsIds(stat) {
44
+ const references = [];
45
+ for (const [key, value] of Object.entries(stat)) {
46
+ if (key === "id") {
47
+ continue;
48
+ }
49
+ if (key.endsWith("Id")) {
50
+ if (typeof value === "string") {
51
+ references.push(value);
52
+ }
53
+ continue;
54
+ }
55
+ if (key.endsWith("Ids") && Array.isArray(value)) {
56
+ for (const entry of value) {
57
+ if (typeof entry === "string") {
58
+ references.push(entry);
59
+ }
60
+ }
61
+ }
62
+ }
63
+ return references;
64
+ }
65
+ function buildStatsReport(stats, rootIds) {
66
+ const index = new Map();
67
+ for (const stat of stats) {
68
+ index.set(stat.id, stat);
69
+ }
70
+ if (!rootIds) {
71
+ return new RTCStatsReport([...index.values()]);
72
+ }
73
+ const includedIds = new Set();
74
+ const queue = [...new Set(Array.from(rootIds))];
75
+ while (queue.length > 0) {
76
+ const id = queue.shift();
77
+ if (!id || includedIds.has(id)) {
78
+ continue;
79
+ }
80
+ const stat = index.get(id);
81
+ if (!stat) {
82
+ continue;
83
+ }
84
+ includedIds.add(id);
85
+ queue.push(...getReferencedStatsIds(stat));
86
+ }
87
+ return new RTCStatsReport([...includedIds]
88
+ .map((id) => index.get(id))
89
+ .filter((stat) => !!stat));
36
90
  }
37
91
  //# sourceMappingURL=stats.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"stats.js","sourceRoot":"","sources":["../../../../src/media/stats.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AA4UH,0CAMC;AAKD,8CAEC;AA9BD;;GAEG;AACH,MAAa,cAAe,SAAQ,GAAqB;IACvD,YAAY,KAAuB;QACjC,KAAK,EAAE,CAAC;QACR,IAAI,KAAK,EAAE,CAAC;YACV,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;YAC1B,CAAC;QACH,CAAC;IACH,CAAC;CACF;AATD,wCASC;AAED;;GAEG;AACH,SAAgB,eAAe,CAC7B,IAAY,EACZ,GAAG,KAAsC;IAEzC,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;IACxD,OAAO,GAAG,IAAI,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;AAC3C,CAAC;AAED;;GAEG;AACH,SAAgB,iBAAiB;IAC/B,OAAO,WAAW,CAAC,GAAG,EAAE,CAAC;AAC3B,CAAC","sourcesContent":["/**\n * WebRTC Statistics API implementation\n * Based on: https://www.w3.org/TR/webrtc-stats/\n */\n\nexport type RTCStatsType =\n | \"codec\"\n | \"inbound-rtp\"\n | \"outbound-rtp\"\n | \"remote-inbound-rtp\"\n | \"remote-outbound-rtp\"\n | \"media-source\"\n | \"peer-connection\"\n | \"data-channel\"\n | \"transport\"\n | \"candidate-pair\"\n | \"local-candidate\"\n | \"remote-candidate\"\n | \"certificate\";\n\nexport interface RTCStats {\n timestamp: number;\n type: RTCStatsType;\n id: string;\n}\n\nexport interface RTCRtpStreamStats extends RTCStats {\n ssrc: number;\n kind: string;\n transportId?: string;\n codecId?: string;\n}\n\nexport interface RTCReceivedRtpStreamStats extends RTCRtpStreamStats {\n packetsReceived?: number;\n packetsLost?: number;\n jitter?: number;\n packetsDiscarded?: number;\n packetsRepaired?: number;\n burstPacketsLost?: number;\n burstPacketsDiscarded?: number;\n burstLossCount?: number;\n burstDiscardCount?: number;\n burstLossRate?: number;\n burstDiscardRate?: number;\n gapLossRate?: number;\n gapDiscardRate?: number;\n framesDropped?: number;\n partialFramesLost?: number;\n fullFramesLost?: number;\n}\n\nexport interface RTCInboundRtpStreamStats extends RTCReceivedRtpStreamStats {\n type: \"inbound-rtp\";\n trackIdentifier?: string;\n mid?: string;\n remoteId?: string;\n framesDecoded?: number;\n keyFramesDecoded?: number;\n frameWidth?: number;\n frameHeight?: number;\n frameBitDepth?: number;\n framesPerSecond?: number;\n qpSum?: number;\n totalDecodeTime?: number;\n totalInterFrameDelay?: number;\n totalSquaredInterFrameDelay?: number;\n lastPacketReceivedTimestamp?: number;\n headerBytesReceived?: number;\n packetsFailedDecryption?: number;\n packetsDuplicated?: number;\n perDscpPacketsReceived?: Record<string, number>;\n nackCount?: number;\n firCount?: number;\n pliCount?: number;\n totalProcessingDelay?: number;\n estimatedPlayoutTimestamp?: number;\n jitterBufferDelay?: number;\n jitterBufferTargetDelay?: number;\n jitterBufferEmittedCount?: number;\n jitterBufferMinimumDelay?: number;\n totalSamplesReceived?: number;\n concealedSamples?: number;\n silentConcealedSamples?: number;\n concealmentEvents?: number;\n insertedSamplesForDeceleration?: number;\n removedSamplesForAcceleration?: number;\n audioLevel?: number;\n totalAudioEnergy?: number;\n totalSamplesDuration?: number;\n framesReceived?: number;\n decoderImplementation?: string;\n playoutId?: string;\n powerEfficientDecoder?: boolean;\n framesAssembledFromMultiplePackets?: number;\n totalAssemblyTime?: number;\n retransmittedPacketsReceived?: number;\n retransmittedBytesReceived?: number;\n rtxSsrc?: number;\n fecSsrc?: number;\n}\n\nexport interface RTCSentRtpStreamStats extends RTCRtpStreamStats {\n packetsSent?: number;\n bytesSent?: number;\n}\n\nexport interface RTCOutboundRtpStreamStats extends RTCSentRtpStreamStats {\n type: \"outbound-rtp\";\n mid?: string;\n mediaSourceId?: string;\n remoteId?: string;\n rid?: string;\n headerBytesSent?: number;\n retransmittedPacketsSent?: number;\n retransmittedBytesSent?: number;\n rtxSsrc?: number;\n targetBitrate?: number;\n totalEncodedBytesTarget?: number;\n frameWidth?: number;\n frameHeight?: number;\n frameBitDepth?: number;\n framesPerSecond?: number;\n framesSent?: number;\n hugeFramesSent?: number;\n framesEncoded?: number;\n keyFramesEncoded?: number;\n qpSum?: number;\n totalEncodeTime?: number;\n totalPacketSendDelay?: number;\n qualityLimitationReason?: string;\n qualityLimitationDurations?: Record<string, number>;\n qualityLimitationResolutionChanges?: number;\n perDscpPacketsSent?: Record<string, number>;\n nackCount?: number;\n firCount?: number;\n pliCount?: number;\n encoderImplementation?: string;\n powerEfficientEncoder?: boolean;\n active?: boolean;\n scalabilityMode?: string;\n}\n\nexport interface RTCRemoteInboundRtpStreamStats\n extends RTCReceivedRtpStreamStats {\n type: \"remote-inbound-rtp\";\n localId?: string;\n roundTripTime?: number;\n totalRoundTripTime?: number;\n fractionLost?: number;\n roundTripTimeMeasurements?: number;\n}\n\nexport interface RTCRemoteOutboundRtpStreamStats extends RTCSentRtpStreamStats {\n type: \"remote-outbound-rtp\";\n localId?: string;\n remoteTimestamp?: number;\n reportsSent?: number;\n roundTripTime?: number;\n totalRoundTripTime?: number;\n roundTripTimeMeasurements?: number;\n}\n\nexport interface RTCMediaSourceStats extends RTCStats {\n type: \"media-source\";\n trackIdentifier: string;\n kind: string;\n}\n\nexport interface RTCVideoSourceStats extends RTCMediaSourceStats {\n width?: number;\n height?: number;\n frames?: number;\n framesPerSecond?: number;\n}\n\nexport interface RTCAudioSourceStats extends RTCMediaSourceStats {\n audioLevel?: number;\n totalAudioEnergy?: number;\n totalSamplesDuration?: number;\n echoReturnLoss?: number;\n echoReturnLossEnhancement?: number;\n droppedSamplesDuration?: number;\n droppedSamplesEvents?: number;\n totalCaptureDelay?: number;\n totalSamplesCaptured?: number;\n}\n\nexport interface RTCPeerConnectionStats extends RTCStats {\n type: \"peer-connection\";\n dataChannelsOpened?: number;\n dataChannelsClosed?: number;\n}\n\nexport interface RTCDataChannelStats extends RTCStats {\n type: \"data-channel\";\n label?: string;\n protocol?: string;\n dataChannelIdentifier?: number;\n state: RTCDataChannelState;\n messagesSent?: number;\n bytesSent?: number;\n messagesReceived?: number;\n bytesReceived?: number;\n}\n\nexport interface RTCTransportStats extends RTCStats {\n type: \"transport\";\n bytesSent?: number;\n packetsSent?: number;\n bytesReceived?: number;\n packetsReceived?: number;\n rtcpTransportStatsId?: string;\n iceRole?: RTCIceRole;\n iceLocalUsernameFragment?: string;\n dtlsState: RTCDtlsTransportState;\n iceState?: RTCIceTransportState;\n selectedCandidatePairId?: string;\n localCertificateId?: string;\n remoteCertificateId?: string;\n tlsVersion?: string;\n dtlsCipher?: string;\n dtlsRole?: RTCDtlsRole;\n srtpCipher?: string;\n selectedCandidatePairChanges?: number;\n iceRestarts?: number;\n}\n\nexport interface RTCIceCandidateStats extends RTCStats {\n transportId?: string;\n address?: string;\n port?: number;\n protocol?: string;\n candidateType: RTCIceCandidateType;\n priority?: number;\n url?: string;\n relayProtocol?: string;\n foundation?: string;\n relatedAddress?: string;\n relatedPort?: number;\n usernameFragment?: string;\n tcpType?: RTCIceTcpCandidateType;\n}\n\nexport interface RTCIceCandidatePairStats extends RTCStats {\n type: \"candidate-pair\";\n transportId?: string;\n localCandidateId: string;\n remoteCandidateId: string;\n state: RTCStatsIceCandidatePairState;\n nominated?: boolean;\n packetsSent?: number;\n packetsReceived?: number;\n bytesSent?: number;\n bytesReceived?: number;\n lastPacketSentTimestamp?: number;\n lastPacketReceivedTimestamp?: number;\n totalRoundTripTime?: number;\n currentRoundTripTime?: number;\n availableOutgoingBitrate?: number;\n availableIncomingBitrate?: number;\n requestsReceived?: number;\n requestsSent?: number;\n responsesReceived?: number;\n responsesSent?: number;\n retransmissionsReceived?: number;\n retransmissionsSent?: number;\n consentRequestsSent?: number;\n consentExpiredTimestamp?: number;\n packetsDiscardedOnSend?: number;\n bytesDiscardedOnSend?: number;\n}\n\nexport interface RTCCertificateStats extends RTCStats {\n type: \"certificate\";\n fingerprint: string;\n fingerprintAlgorithm: string;\n base64Certificate: string;\n issuerCertificateId?: string;\n}\n\nexport interface RTCCodecStats extends RTCStats {\n type: \"codec\";\n payloadType: number;\n transportId: string;\n mimeType: string;\n clockRate?: number;\n channels?: number;\n sdpFmtpLine?: string;\n}\n\n// Type definitions\nexport type RTCDataChannelState = \"connecting\" | \"open\" | \"closing\" | \"closed\";\nexport type RTCDtlsTransportState =\n | \"new\"\n | \"connecting\"\n | \"connected\"\n | \"closed\"\n | \"failed\";\nexport type RTCIceTransportState =\n | \"new\"\n | \"checking\"\n | \"connected\"\n | \"completed\"\n | \"disconnected\"\n | \"failed\"\n | \"closed\";\nexport type RTCIceRole = \"controlling\" | \"controlled\";\nexport type RTCDtlsRole = \"client\" | \"server\";\nexport type RTCIceCandidateType = \"host\" | \"srflx\" | \"prflx\" | \"relay\";\nexport type RTCIceTcpCandidateType = \"active\" | \"passive\" | \"so\";\nexport type RTCStatsIceCandidatePairState =\n | \"frozen\"\n | \"waiting\"\n | \"in-progress\"\n | \"failed\"\n | \"succeeded\";\n\n/**\n * RTCStatsReport is a Map-like object that holds WebRTC statistics\n */\nexport class RTCStatsReport extends Map<string, RTCStats> {\n constructor(stats?: Array<RTCStats>) {\n super();\n if (stats) {\n for (const stat of stats) {\n this.set(stat.id, stat);\n }\n }\n }\n}\n\n/**\n * Generate a unique ID for a statistics object\n */\nexport function generateStatsId(\n type: string,\n ...parts: (string | number | undefined)[]\n): string {\n const validParts = parts.filter((p) => p !== undefined);\n return `${type}_${validParts.join(\"_\")}`;\n}\n\n/**\n * Get current timestamp in milliseconds (DOMHighResTimeStamp)\n */\nexport function getStatsTimestamp(): number {\n return performance.now();\n}\n"]}
1
+ {"version":3,"file":"stats.js","sourceRoot":"","sources":["../../../../src/media/stats.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * WebRTC Statistics API implementation\n * Based on: https://www.w3.org/TR/webrtc-stats/\n */\n\nexport type RTCStatsType =\n | \"codec\"\n | \"inbound-rtp\"\n | \"outbound-rtp\"\n | \"remote-inbound-rtp\"\n | \"remote-outbound-rtp\"\n | \"media-source\"\n | \"media-playout\"\n | \"peer-connection\"\n | \"data-channel\"\n | \"transport\"\n | \"candidate-pair\"\n | \"local-candidate\"\n | \"remote-candidate\"\n | \"certificate\";\n\nexport interface RTCStats {\n timestamp: number;\n type: RTCStatsType;\n id: string;\n}\n\nexport interface RTCRtpStreamStats extends RTCStats {\n ssrc: number;\n kind: string;\n transportId?: string;\n codecId?: string;\n}\n\nexport interface RTCReceivedRtpStreamStats extends RTCRtpStreamStats {\n packetsReceived?: number;\n bytesReceived?: number;\n packetsLost?: number;\n jitter?: number;\n packetsDiscarded?: number;\n packetsRepaired?: number;\n burstPacketsLost?: number;\n burstPacketsDiscarded?: number;\n burstLossCount?: number;\n burstDiscardCount?: number;\n burstLossRate?: number;\n burstDiscardRate?: number;\n gapLossRate?: number;\n gapDiscardRate?: number;\n framesDropped?: number;\n partialFramesLost?: number;\n fullFramesLost?: number;\n}\n\nexport interface RTCInboundRtpStreamStats extends RTCReceivedRtpStreamStats {\n type: \"inbound-rtp\";\n trackIdentifier?: string;\n mid?: string;\n remoteId?: string;\n framesDecoded?: number;\n keyFramesDecoded?: number;\n frameWidth?: number;\n frameHeight?: number;\n frameBitDepth?: number;\n framesPerSecond?: number;\n qpSum?: number;\n totalDecodeTime?: number;\n totalInterFrameDelay?: number;\n totalSquaredInterFrameDelay?: number;\n lastPacketReceivedTimestamp?: number;\n headerBytesReceived?: number;\n packetsFailedDecryption?: number;\n packetsDuplicated?: number;\n perDscpPacketsReceived?: Record<string, number>;\n nackCount?: number;\n firCount?: number;\n pliCount?: number;\n totalProcessingDelay?: number;\n estimatedPlayoutTimestamp?: number;\n jitterBufferDelay?: number;\n jitterBufferTargetDelay?: number;\n jitterBufferEmittedCount?: number;\n jitterBufferMinimumDelay?: number;\n totalSamplesReceived?: number;\n concealedSamples?: number;\n silentConcealedSamples?: number;\n concealmentEvents?: number;\n insertedSamplesForDeceleration?: number;\n removedSamplesForAcceleration?: number;\n audioLevel?: number;\n totalAudioEnergy?: number;\n totalSamplesDuration?: number;\n framesReceived?: number;\n decoderImplementation?: string;\n playoutId?: string;\n powerEfficientDecoder?: boolean;\n framesAssembledFromMultiplePackets?: number;\n totalAssemblyTime?: number;\n retransmittedPacketsReceived?: number;\n retransmittedBytesReceived?: number;\n rtxSsrc?: number;\n fecSsrc?: number;\n}\n\nexport interface RTCSentRtpStreamStats extends RTCRtpStreamStats {\n packetsSent?: number;\n bytesSent?: number;\n}\n\nexport interface RTCOutboundRtpStreamStats extends RTCSentRtpStreamStats {\n type: \"outbound-rtp\";\n mid?: string;\n mediaSourceId?: string;\n remoteId?: string;\n rid?: string;\n headerBytesSent?: number;\n retransmittedPacketsSent?: number;\n retransmittedBytesSent?: number;\n rtxSsrc?: number;\n targetBitrate?: number;\n totalEncodedBytesTarget?: number;\n frameWidth?: number;\n frameHeight?: number;\n frameBitDepth?: number;\n framesPerSecond?: number;\n framesSent?: number;\n hugeFramesSent?: number;\n framesEncoded?: number;\n keyFramesEncoded?: number;\n qpSum?: number;\n totalEncodeTime?: number;\n totalPacketSendDelay?: number;\n qualityLimitationReason?: string;\n qualityLimitationDurations?: Record<string, number>;\n qualityLimitationResolutionChanges?: number;\n perDscpPacketsSent?: Record<string, number>;\n nackCount?: number;\n firCount?: number;\n pliCount?: number;\n encoderImplementation?: string;\n powerEfficientEncoder?: boolean;\n active?: boolean;\n scalabilityMode?: string;\n}\n\nexport interface RTCRemoteInboundRtpStreamStats\n extends RTCReceivedRtpStreamStats {\n type: \"remote-inbound-rtp\";\n localId?: string;\n roundTripTime?: number;\n totalRoundTripTime?: number;\n fractionLost?: number;\n roundTripTimeMeasurements?: number;\n}\n\nexport interface RTCRemoteOutboundRtpStreamStats extends RTCSentRtpStreamStats {\n type: \"remote-outbound-rtp\";\n localId?: string;\n remoteTimestamp?: number;\n reportsSent?: number;\n roundTripTime?: number;\n totalRoundTripTime?: number;\n roundTripTimeMeasurements?: number;\n}\n\nexport interface RTCMediaSourceStats extends RTCStats {\n type: \"media-source\";\n trackIdentifier: string;\n kind: string;\n}\n\nexport interface RTCVideoSourceStats extends RTCMediaSourceStats {\n width?: number;\n height?: number;\n frames?: number;\n framesPerSecond?: number;\n}\n\nexport interface RTCAudioPlayoutStats extends RTCStats {\n type: \"media-playout\";\n kind: \"audio\";\n synthesizedSamplesDuration?: number;\n synthesizedSamplesEvents?: number;\n totalSamplesDuration?: number;\n totalPlayoutDelay?: number;\n totalSamplesCount?: number;\n}\n\nexport interface RTCAudioSourceStats extends RTCMediaSourceStats {\n audioLevel?: number;\n totalAudioEnergy?: number;\n totalSamplesDuration?: number;\n echoReturnLoss?: number;\n echoReturnLossEnhancement?: number;\n droppedSamplesDuration?: number;\n droppedSamplesEvents?: number;\n totalCaptureDelay?: number;\n totalSamplesCaptured?: number;\n}\n\nexport interface RTCPeerConnectionStats extends RTCStats {\n type: \"peer-connection\";\n dataChannelsOpened?: number;\n dataChannelsClosed?: number;\n}\n\nexport interface RTCDataChannelStats extends RTCStats {\n type: \"data-channel\";\n label?: string;\n protocol?: string;\n dataChannelIdentifier?: number;\n state: RTCDataChannelState;\n messagesSent?: number;\n bytesSent?: number;\n messagesReceived?: number;\n bytesReceived?: number;\n}\n\nexport interface RTCTransportStats extends RTCStats {\n type: \"transport\";\n bytesSent?: number;\n packetsSent?: number;\n bytesReceived?: number;\n packetsReceived?: number;\n rtcpTransportStatsId?: string;\n iceRole?: RTCIceRole;\n iceLocalUsernameFragment?: string;\n dtlsState: RTCDtlsTransportState;\n iceState?: RTCIceTransportState;\n selectedCandidatePairId?: string;\n localCertificateId?: string;\n remoteCertificateId?: string;\n tlsVersion?: string;\n dtlsCipher?: string;\n dtlsRole?: RTCDtlsRole;\n srtpCipher?: string;\n selectedCandidatePairChanges?: number;\n iceRestarts?: number;\n}\n\nexport interface RTCIceCandidateStats extends RTCStats {\n transportId?: string;\n address?: string;\n port?: number;\n protocol?: string;\n candidateType: RTCIceCandidateType;\n priority?: number;\n url?: string;\n relayProtocol?: string;\n foundation?: string;\n relatedAddress?: string;\n relatedPort?: number;\n usernameFragment?: string;\n tcpType?: RTCIceTcpCandidateType;\n}\n\nexport interface RTCIceCandidatePairStats extends RTCStats {\n type: \"candidate-pair\";\n transportId?: string;\n localCandidateId: string;\n remoteCandidateId: string;\n state: RTCStatsIceCandidatePairState;\n nominated?: boolean;\n packetsSent?: number;\n packetsReceived?: number;\n bytesSent?: number;\n bytesReceived?: number;\n lastPacketSentTimestamp?: number;\n lastPacketReceivedTimestamp?: number;\n totalRoundTripTime?: number;\n currentRoundTripTime?: number;\n roundTripTimeMeasurements?: number;\n availableOutgoingBitrate?: number;\n availableIncomingBitrate?: number;\n requestsReceived?: number;\n requestsSent?: number;\n responsesReceived?: number;\n responsesSent?: number;\n retransmissionsReceived?: number;\n retransmissionsSent?: number;\n consentRequestsSent?: number;\n consentExpiredTimestamp?: number;\n packetsDiscardedOnSend?: number;\n bytesDiscardedOnSend?: number;\n}\n\nexport interface RTCCertificateStats extends RTCStats {\n type: \"certificate\";\n fingerprint: string;\n fingerprintAlgorithm: string;\n base64Certificate: string;\n issuerCertificateId?: string;\n}\n\nexport interface RTCCodecStats extends RTCStats {\n type: \"codec\";\n payloadType: number;\n transportId: string;\n mimeType: string;\n clockRate?: number;\n channels?: number;\n sdpFmtpLine?: string;\n}\n\n// Type definitions\nexport type RTCDataChannelState = \"connecting\" | \"open\" | \"closing\" | \"closed\";\nexport type RTCDtlsTransportState =\n | \"new\"\n | \"connecting\"\n | \"connected\"\n | \"closed\"\n | \"failed\";\nexport type RTCIceTransportState =\n | \"new\"\n | \"checking\"\n | \"connected\"\n | \"completed\"\n | \"disconnected\"\n | \"failed\"\n | \"closed\";\nexport type RTCIceRole = \"controlling\" | \"controlled\";\nexport type RTCDtlsRole = \"client\" | \"server\";\nexport type RTCIceCandidateType = \"host\" | \"srflx\" | \"prflx\" | \"relay\";\nexport type RTCIceTcpCandidateType = \"active\" | \"passive\" | \"so\";\nexport type RTCStatsIceCandidatePairState =\n | \"frozen\"\n | \"waiting\"\n | \"in-progress\"\n | \"failed\"\n | \"succeeded\";\n\n/**\n * RTCStatsReport is a Map-like object that holds WebRTC statistics\n */\nexport class RTCStatsReport extends Map<string, RTCStats> {\n constructor(stats?: Array<RTCStats>) {\n super();\n if (stats) {\n for (const stat of stats) {\n this.set(stat.id, stat);\n }\n }\n }\n}\n\n/**\n * Generate a unique ID for a statistics object\n */\nexport function generateStatsId(\n type: string,\n ...parts: (string | number | undefined)[]\n): string {\n const validParts = parts.filter((p) => p !== undefined);\n return `${type}_${validParts.join(\"_\")}`;\n}\n\nexport function generateCodecStatsId(\n transportId: string,\n payloadType: number,\n scopeId: string,\n) {\n return generateStatsId(\"codec\", transportId, payloadType, scopeId);\n}\n\n/**\n * Get current timestamp in milliseconds (DOMHighResTimeStamp)\n */\nexport function getStatsTimestamp(): number {\n return performance.timeOrigin + performance.now();\n}\n\nexport function getReferencedStatsIds(stat: RTCStats): string[] {\n const references: string[] = [];\n\n for (const [key, value] of Object.entries(\n stat as unknown as Record<string, unknown>,\n )) {\n if (key === \"id\") {\n continue;\n }\n\n if (key.endsWith(\"Id\")) {\n if (typeof value === \"string\") {\n references.push(value);\n }\n continue;\n }\n\n if (key.endsWith(\"Ids\") && Array.isArray(value)) {\n for (const entry of value) {\n if (typeof entry === \"string\") {\n references.push(entry);\n }\n }\n }\n }\n\n return references;\n}\n\nexport function buildStatsReport(\n stats: Iterable<RTCStats>,\n rootIds?: Iterable<string>,\n): RTCStatsReport {\n const index = new Map<string, RTCStats>();\n for (const stat of stats) {\n index.set(stat.id, stat);\n }\n\n if (!rootIds) {\n return new RTCStatsReport([...index.values()]);\n }\n\n const includedIds = new Set<string>();\n const queue = [...new Set(Array.from(rootIds))];\n\n while (queue.length > 0) {\n const id = queue.shift();\n if (!id || includedIds.has(id)) {\n continue;\n }\n\n const stat = index.get(id);\n if (!stat) {\n continue;\n }\n\n includedIds.add(id);\n queue.push(...getReferencedStatsIds(stat));\n }\n\n return new RTCStatsReport(\n [...includedIds]\n .map((id) => index.get(id))\n .filter((stat): stat is RTCStats => !!stat),\n );\n}\n"]}
@@ -30,8 +30,9 @@ export declare class MediaStreamTrack extends EventTarget {
30
30
  export declare class MediaStream {
31
31
  id: string;
32
32
  tracks: MediaStreamTrack[];
33
- constructor(props: Partial<MediaStream> | MediaStreamTrack[]);
33
+ constructor(props?: Partial<MediaStream> | MediaStreamTrack[]);
34
34
  addTrack(track: MediaStreamTrack): void;
35
+ removeTrack(track: MediaStreamTrack): void;
35
36
  getTracks(): MediaStreamTrack[];
36
37
  getAudioTracks(): MediaStreamTrack[];
37
38
  getVideoTracks(): MediaStreamTrack[];
@@ -145,7 +145,7 @@ class MediaStreamTrack extends helper_1.EventTarget {
145
145
  }
146
146
  exports.MediaStreamTrack = MediaStreamTrack;
147
147
  class MediaStream {
148
- constructor(props) {
148
+ constructor(props = {}) {
149
149
  Object.defineProperty(this, "id", {
150
150
  enumerable: true,
151
151
  configurable: true,
@@ -170,6 +170,12 @@ class MediaStream {
170
170
  track.streamId = this.id;
171
171
  this.tracks.push(track);
172
172
  }
173
+ removeTrack(track) {
174
+ this.tracks = this.tracks.filter((currentTrack) => currentTrack !== track);
175
+ if (track.streamId === this.id) {
176
+ track.streamId = undefined;
177
+ }
178
+ }
173
179
  getTracks() {
174
180
  return this.tracks;
175
181
  }
@@ -1 +1 @@
1
- {"version":3,"file":"track.js","sourceRoot":"","sources":["../../../../src/media/track.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"crypto\";\nimport { Event } from \"../imports/common\";\n\nimport { EventTarget } from \"../helper\";\nimport {\n type Extensions,\n type RtcpPacket,\n type RtpHeader,\n RtpPacket,\n} from \"../imports/rtp\";\nimport type { Kind } from \"../types/domain\";\nimport type { RTCRtpCodecParameters } from \"./parameters\";\n\nexport class MediaStreamTrack extends EventTarget {\n readonly uuid = randomUUID().toString();\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, Extensions?]>();\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 this.emit(\"ended\");\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> | MediaStreamTrack[]) {\n if (Array.isArray(props)) {\n this.tracks = props;\n } else {\n Object.assign(this, props);\n }\n this.id ??= randomUUID().toString();\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 getAudioTracks() {\n return this.tracks.filter((track) => track.kind === \"audio\");\n }\n\n getVideoTracks() {\n return this.tracks.filter((track) => track.kind === \"video\");\n }\n}\n"]}
1
+ {"version":3,"file":"track.js","sourceRoot":"","sources":["../../../../src/media/track.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"crypto\";\nimport { Event } from \"../imports/common\";\n\nimport { EventTarget } from \"../helper\";\nimport {\n type Extensions,\n type RtcpPacket,\n type RtpHeader,\n RtpPacket,\n} from \"../imports/rtp\";\nimport type { Kind } from \"../types/domain\";\nimport type { RTCRtpCodecParameters } from \"./parameters\";\n\nexport class MediaStreamTrack extends EventTarget {\n readonly uuid = randomUUID().toString();\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, Extensions?]>();\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 this.emit(\"ended\");\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> | MediaStreamTrack[] = {}) {\n if (Array.isArray(props)) {\n this.tracks = props;\n } else {\n Object.assign(this, props);\n }\n this.id ??= randomUUID().toString();\n }\n\n addTrack(track: MediaStreamTrack) {\n track.streamId = this.id;\n this.tracks.push(track);\n }\n\n removeTrack(track: MediaStreamTrack) {\n this.tracks = this.tracks.filter((currentTrack) => currentTrack !== track);\n if (track.streamId === this.id) {\n track.streamId = undefined;\n }\n }\n\n getTracks() {\n return this.tracks;\n }\n\n getAudioTracks() {\n return this.tracks.filter((track) => track.kind === \"audio\");\n }\n\n getVideoTracks() {\n return this.tracks.filter((track) => track.kind === \"video\");\n }\n}\n"]}
@@ -0,0 +1,19 @@
1
+ import { MediaStreamTrack } from "../media/track";
2
+ export interface DummyAudioOptions {
3
+ packetIntervalMs: number;
4
+ }
5
+ export interface DummyVideoOptions {
6
+ fps: number;
7
+ keyframeIntervalFrames: number;
8
+ }
9
+ export interface DummySource {
10
+ stop(): void;
11
+ }
12
+ export declare function createDummyAudioTrack(options?: Partial<DummyAudioOptions>): {
13
+ track: MediaStreamTrack;
14
+ source: DummySource;
15
+ };
16
+ export declare function createDummyVideoTrack(options?: Partial<DummyVideoOptions>): {
17
+ track: MediaStreamTrack;
18
+ source: DummySource;
19
+ };
@@ -0,0 +1,157 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createDummyAudioTrack = createDummyAudioTrack;
4
+ exports.createDummyVideoTrack = createDummyVideoTrack;
5
+ const rtp_1 = require("../imports/rtp");
6
+ const track_1 = require("../media/track");
7
+ const AUDIO_PACKET_MS = 20;
8
+ const AUDIO_TIMESTAMP_STEP = 960;
9
+ const AUDIO_PAYLOAD = Buffer.from([0xf8, 0xff, 0xfe]);
10
+ const DEFAULT_VIDEO_FPS = 30;
11
+ const VIDEO_TIMESTAMP_STEP = 3000;
12
+ const DUMMY_SSRC_BASE = 0x1a2b3c00;
13
+ const DUMMY_SEQUENCE_BASE = 0x4000;
14
+ const DUMMY_SEQUENCE_STEP = 0x0100;
15
+ let nextDummySourceId = 0;
16
+ const VP8_KEYFRAME = Buffer.from([
17
+ 0x10, 0x10, 0x00, 0x00, 0x9d, 0x01, 0x2a, 0x02, 0x00, 0x02, 0x00,
18
+ ]);
19
+ const VP8_DELTA_FRAME = Buffer.from([0x10, 0x11, 0x00, 0x00]);
20
+ function createDummyAudioTrack(options = {}) {
21
+ const track = new track_1.MediaStreamTrack({ kind: "audio" });
22
+ const source = new ScheduledRtpSource({
23
+ track,
24
+ intervalMs: options.packetIntervalMs ?? AUDIO_PACKET_MS,
25
+ buildPacket: ({ sequenceNumber, timestamp, ssrc }) => new rtp_1.RtpPacket(new rtp_1.RtpHeader({
26
+ version: 2,
27
+ payloadType: 111,
28
+ sequenceNumber,
29
+ timestamp,
30
+ ssrc,
31
+ marker: true,
32
+ }), Buffer.from(AUDIO_PAYLOAD)),
33
+ nextTimestamp: (timestamp) => timestamp + AUDIO_TIMESTAMP_STEP,
34
+ });
35
+ source.start();
36
+ return { track, source };
37
+ }
38
+ function createDummyVideoTrack(options = {}) {
39
+ const fps = options.fps ?? DEFAULT_VIDEO_FPS;
40
+ const keyframeIntervalFrames = options.keyframeIntervalFrames ?? fps;
41
+ const intervalMs = 1000 / fps;
42
+ const track = new track_1.MediaStreamTrack({ kind: "video" });
43
+ const source = new ScheduledRtpSource({
44
+ track,
45
+ intervalMs,
46
+ buildPacket: ({ sequenceNumber, timestamp, ssrc, iteration }) => {
47
+ const isKeyframe = iteration % keyframeIntervalFrames === 0;
48
+ return new rtp_1.RtpPacket(new rtp_1.RtpHeader({
49
+ version: 2,
50
+ payloadType: 96,
51
+ sequenceNumber,
52
+ timestamp,
53
+ ssrc,
54
+ marker: true,
55
+ }), Buffer.from(isKeyframe ? VP8_KEYFRAME : VP8_DELTA_FRAME));
56
+ },
57
+ nextTimestamp: (timestamp) => timestamp + VIDEO_TIMESTAMP_STEP,
58
+ });
59
+ source.start();
60
+ return { track, source };
61
+ }
62
+ class ScheduledRtpSource {
63
+ constructor(props) {
64
+ Object.defineProperty(this, "props", {
65
+ enumerable: true,
66
+ configurable: true,
67
+ writable: true,
68
+ value: props
69
+ });
70
+ Object.defineProperty(this, "sourceId", {
71
+ enumerable: true,
72
+ configurable: true,
73
+ writable: true,
74
+ value: nextDummySourceId++
75
+ });
76
+ Object.defineProperty(this, "ssrc", {
77
+ enumerable: true,
78
+ configurable: true,
79
+ writable: true,
80
+ value: (DUMMY_SSRC_BASE + this.sourceId) >>> 0
81
+ });
82
+ Object.defineProperty(this, "sequenceNumber", {
83
+ enumerable: true,
84
+ configurable: true,
85
+ writable: true,
86
+ value: (DUMMY_SEQUENCE_BASE + this.sourceId * DUMMY_SEQUENCE_STEP) & 0xffff
87
+ });
88
+ Object.defineProperty(this, "timestamp", {
89
+ enumerable: true,
90
+ configurable: true,
91
+ writable: true,
92
+ value: 0
93
+ });
94
+ Object.defineProperty(this, "iteration", {
95
+ enumerable: true,
96
+ configurable: true,
97
+ writable: true,
98
+ value: 0
99
+ });
100
+ Object.defineProperty(this, "nextTickAt", {
101
+ enumerable: true,
102
+ configurable: true,
103
+ writable: true,
104
+ value: void 0
105
+ });
106
+ Object.defineProperty(this, "timer", {
107
+ enumerable: true,
108
+ configurable: true,
109
+ writable: true,
110
+ value: void 0
111
+ });
112
+ Object.defineProperty(this, "stopped", {
113
+ enumerable: true,
114
+ configurable: true,
115
+ writable: true,
116
+ value: false
117
+ });
118
+ }
119
+ start() {
120
+ this.nextTickAt = performance.now();
121
+ this.schedule();
122
+ }
123
+ stop() {
124
+ this.stopped = true;
125
+ if (this.timer) {
126
+ clearTimeout(this.timer);
127
+ this.timer = undefined;
128
+ }
129
+ }
130
+ schedule() {
131
+ if (this.stopped || this.props.track.stopped) {
132
+ this.stop();
133
+ return;
134
+ }
135
+ this.nextTickAt =
136
+ (this.nextTickAt ?? performance.now()) + this.props.intervalMs;
137
+ const delay = Math.max(0, this.nextTickAt - performance.now());
138
+ this.timer = setTimeout(() => {
139
+ if (this.stopped || this.props.track.stopped) {
140
+ this.stop();
141
+ return;
142
+ }
143
+ const packet = this.props.buildPacket({
144
+ sequenceNumber: this.sequenceNumber,
145
+ timestamp: this.timestamp,
146
+ ssrc: this.ssrc,
147
+ iteration: this.iteration,
148
+ });
149
+ this.props.track.writeRtp(packet);
150
+ this.sequenceNumber = (this.sequenceNumber + 1) & 0xffff;
151
+ this.timestamp = this.props.nextTimestamp(this.timestamp) >>> 0;
152
+ this.iteration += 1;
153
+ this.schedule();
154
+ }, delay);
155
+ }
156
+ }
157
+ //# sourceMappingURL=dummyMedia.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dummyMedia.js","sourceRoot":"","sources":["../../../../src/nonstandard/dummyMedia.ts"],"names":[],"mappings":"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","sourcesContent":["import { RtpHeader, RtpPacket } from \"../imports/rtp\";\nimport { MediaStreamTrack } from \"../media/track\";\n\nconst AUDIO_PACKET_MS = 20;\nconst AUDIO_TIMESTAMP_STEP = 960;\nconst AUDIO_PAYLOAD = Buffer.from([0xf8, 0xff, 0xfe]);\n\nconst DEFAULT_VIDEO_FPS = 30;\nconst VIDEO_TIMESTAMP_STEP = 3_000;\nconst DUMMY_SSRC_BASE = 0x1a2b3c00;\nconst DUMMY_SEQUENCE_BASE = 0x4000;\nconst DUMMY_SEQUENCE_STEP = 0x0100;\nlet nextDummySourceId = 0;\n\nconst VP8_KEYFRAME = Buffer.from([\n 0x10, 0x10, 0x00, 0x00, 0x9d, 0x01, 0x2a, 0x02, 0x00, 0x02, 0x00,\n]);\nconst VP8_DELTA_FRAME = Buffer.from([0x10, 0x11, 0x00, 0x00]);\n\nexport interface DummyAudioOptions {\n packetIntervalMs: number;\n}\n\nexport interface DummyVideoOptions {\n fps: number;\n keyframeIntervalFrames: number;\n}\n\nexport interface DummySource {\n stop(): void;\n}\n\nexport function createDummyAudioTrack(\n options: Partial<DummyAudioOptions> = {},\n): { track: MediaStreamTrack; source: DummySource } {\n const track = new MediaStreamTrack({ kind: \"audio\" });\n const source = new ScheduledRtpSource({\n track,\n intervalMs: options.packetIntervalMs ?? AUDIO_PACKET_MS,\n buildPacket: ({ sequenceNumber, timestamp, ssrc }) =>\n new RtpPacket(\n new RtpHeader({\n version: 2,\n payloadType: 111,\n sequenceNumber,\n timestamp,\n ssrc,\n marker: true,\n }),\n Buffer.from(AUDIO_PAYLOAD),\n ),\n nextTimestamp: (timestamp) => timestamp + AUDIO_TIMESTAMP_STEP,\n });\n source.start();\n return { track, source };\n}\n\nexport function createDummyVideoTrack(\n options: Partial<DummyVideoOptions> = {},\n): { track: MediaStreamTrack; source: DummySource } {\n const fps = options.fps ?? DEFAULT_VIDEO_FPS;\n const keyframeIntervalFrames = options.keyframeIntervalFrames ?? fps;\n const intervalMs = 1_000 / fps;\n const track = new MediaStreamTrack({ kind: \"video\" });\n\n const source = new ScheduledRtpSource({\n track,\n intervalMs,\n buildPacket: ({ sequenceNumber, timestamp, ssrc, iteration }) => {\n const isKeyframe = iteration % keyframeIntervalFrames === 0;\n return new RtpPacket(\n new RtpHeader({\n version: 2,\n payloadType: 96,\n sequenceNumber,\n timestamp,\n ssrc,\n marker: true,\n }),\n Buffer.from(isKeyframe ? VP8_KEYFRAME : VP8_DELTA_FRAME),\n );\n },\n nextTimestamp: (timestamp) => timestamp + VIDEO_TIMESTAMP_STEP,\n });\n source.start();\n return { track, source };\n}\n\nclass ScheduledRtpSource implements DummySource {\n private readonly sourceId = nextDummySourceId++;\n private readonly ssrc = (DUMMY_SSRC_BASE + this.sourceId) >>> 0;\n private sequenceNumber =\n (DUMMY_SEQUENCE_BASE + this.sourceId * DUMMY_SEQUENCE_STEP) & 0xffff;\n private timestamp = 0;\n private iteration = 0;\n private nextTickAt?: number;\n private timer?: NodeJS.Timeout;\n private stopped = false;\n\n constructor(\n private readonly props: {\n track: MediaStreamTrack;\n intervalMs: number;\n buildPacket(args: {\n sequenceNumber: number;\n timestamp: number;\n ssrc: number;\n iteration: number;\n }): RtpPacket;\n nextTimestamp(timestamp: number): number;\n },\n ) {}\n\n start() {\n this.nextTickAt = performance.now();\n this.schedule();\n }\n\n stop() {\n this.stopped = true;\n if (this.timer) {\n clearTimeout(this.timer);\n this.timer = undefined;\n }\n }\n\n private schedule() {\n if (this.stopped || this.props.track.stopped) {\n this.stop();\n return;\n }\n\n this.nextTickAt =\n (this.nextTickAt ?? performance.now()) + this.props.intervalMs;\n const delay = Math.max(0, this.nextTickAt - performance.now());\n this.timer = setTimeout(() => {\n if (this.stopped || this.props.track.stopped) {\n this.stop();\n return;\n }\n\n const packet = this.props.buildPacket({\n sequenceNumber: this.sequenceNumber,\n timestamp: this.timestamp,\n ssrc: this.ssrc,\n iteration: this.iteration,\n });\n this.props.track.writeRtp(packet);\n\n this.sequenceNumber = (this.sequenceNumber + 1) & 0xffff;\n this.timestamp = this.props.nextTimestamp(this.timestamp) >>> 0;\n this.iteration += 1;\n this.schedule();\n }, delay);\n }\n}\n"]}
@@ -1,20 +1,16 @@
1
1
  import { RTCRtpCodecParameters } from "..";
2
2
  import { MediaStream, MediaStreamTrack } from "../media/track";
3
+ import { type DummyAudioOptions, type DummyVideoOptions } from "./dummyMedia";
3
4
  export declare class Navigator {
4
5
  mediaDevices: MediaDevices;
5
6
  constructor(props?: ConstructorParameters<typeof MediaDevices>[0]);
6
7
  }
7
8
  export declare class MediaDevices extends EventTarget {
8
- readonly props: {
9
- video?: MediaStreamTrack;
10
- audio?: MediaStreamTrack;
11
- };
9
+ readonly props: MediaDeviceProps;
12
10
  video?: MediaStreamTrack;
13
11
  audio?: MediaStreamTrack;
14
- constructor(props: {
15
- video?: MediaStreamTrack;
16
- audio?: MediaStreamTrack;
17
- });
12
+ private readonly activeSourceStops;
13
+ constructor(props?: MediaDeviceProps);
18
14
  readonly getUserMedia: (constraints: MediaStreamConstraints) => Promise<MediaStream>;
19
15
  readonly getDisplayMedia: (constraints: MediaStreamConstraints) => Promise<MediaStream>;
20
16
  readonly getUdpMedia: ({ port, codec, }: {
@@ -24,6 +20,20 @@ export declare class MediaDevices extends EventTarget {
24
20
  track: MediaStreamTrack;
25
21
  disposer: () => void;
26
22
  };
23
+ cleanup(): void;
24
+ private createTrack;
25
+ private createClonedTrack;
26
+ private createDummyTrack;
27
+ private attachTrackStop;
28
+ }
29
+ interface MediaDeviceProps {
30
+ video?: MediaStreamTrack;
31
+ audio?: MediaStreamTrack;
32
+ dummyMedia?: {
33
+ enabled: boolean;
34
+ audio?: Partial<DummyAudioOptions>;
35
+ video?: Partial<DummyVideoOptions>;
36
+ };
27
37
  }
28
38
  interface MediaStreamConstraints {
29
39
  audio?: boolean | MediaTrackConstraints;