werift 0.18.7 → 0.18.9

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.
@@ -1,11 +1,10 @@
1
1
  /// <reference types="node" />
2
- import { RtpPacket } from "../../rtp/src";
3
2
  import { Direction } from "./media/rtpTransceiver";
3
+ import { MediaStreamTrack } from "./media/track";
4
4
  import { RTCIceServer } from "./peerConnection";
5
5
  export declare function fingerprint(file: Buffer, hashName: string): any;
6
6
  export declare function isDtls(buf: Buffer): boolean;
7
- export declare function isMedia(buf: Buffer): boolean;
8
- export declare function reverseSimulcastDirection(dir: "recv" | "send"): "recv" | "send";
7
+ export declare function reverseSimulcastDirection(dir: "recv" | "send"): "send" | "recv";
9
8
  export declare const andDirection: (a: Direction, b: Direction) => "inactive" | "sendonly" | "recvonly" | "sendrecv";
10
9
  export declare function reverseDirection(dir: Direction): Direction;
11
10
  export declare const microTime: () => number;
@@ -25,11 +24,6 @@ export declare function parseIceServers(iceServers: RTCIceServer[]): {
25
24
  turnUsername: string | undefined;
26
25
  turnPassword: string | undefined;
27
26
  };
28
- export declare class RtpBuilder {
29
- sequenceNumber: number;
30
- timestamp: number;
31
- create(payload: Buffer): RtpPacket;
32
- }
33
27
  /**
34
28
  *
35
29
  * @param signatureHash
@@ -40,3 +34,9 @@ export declare const createSelfSignedCertificate: (signatureHash: import(".").Si
40
34
  keyPem: string;
41
35
  signatureHash: import(".").SignatureHash;
42
36
  }>;
37
+ export declare class MediaStreamTrackFactory {
38
+ static rtpSource({ port, kind, }: {
39
+ port?: number;
40
+ kind: "audio" | "video";
41
+ }): Promise<readonly [MediaStreamTrack, number, () => void]>;
42
+ }
@@ -3,15 +3,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.createSelfSignedCertificate = exports.RtpBuilder = exports.parseIceServers = exports.compactNtp = exports.ntpTime = exports.timestampSeconds = exports.milliTime = exports.microTime = exports.reverseDirection = exports.andDirection = exports.reverseSimulcastDirection = exports.isMedia = exports.isDtls = exports.fingerprint = void 0;
6
+ exports.MediaStreamTrackFactory = exports.createSelfSignedCertificate = exports.parseIceServers = exports.compactNtp = exports.ntpTime = exports.timestampSeconds = exports.milliTime = exports.microTime = exports.reverseDirection = exports.andDirection = exports.reverseSimulcastDirection = exports.isDtls = exports.fingerprint = void 0;
7
7
  /* eslint-disable prefer-const */
8
8
  const crypto_1 = require("crypto");
9
9
  const debug_1 = __importDefault(require("debug"));
10
+ const dgram_1 = require("dgram");
10
11
  const perf_hooks_1 = require("perf_hooks");
11
12
  const src_1 = require("../../common/src");
12
13
  const cipher_1 = require("../../dtls/src/context/cipher");
13
- const src_2 = require("../../rtp/src");
14
14
  const rtpTransceiver_1 = require("./media/rtpTransceiver");
15
+ const track_1 = require("./media/track");
15
16
  const now = require("nano-time");
16
17
  const log = (0, debug_1.default)("werift:packages/webrtc/src/utils.ts");
17
18
  function fingerprint(file, hashName) {
@@ -26,11 +27,6 @@ function isDtls(buf) {
26
27
  return firstByte > 19 && firstByte < 64;
27
28
  }
28
29
  exports.isDtls = isDtls;
29
- function isMedia(buf) {
30
- const firstByte = buf[0];
31
- return firstByte > 127 && firstByte < 192;
32
- }
33
- exports.isMedia = isMedia;
34
30
  function reverseSimulcastDirection(dir) {
35
31
  if (dir === "recv")
36
32
  return "send";
@@ -93,41 +89,28 @@ function parseIceServers(iceServers) {
93
89
  return options;
94
90
  }
95
91
  exports.parseIceServers = parseIceServers;
96
- class RtpBuilder {
97
- constructor() {
98
- Object.defineProperty(this, "sequenceNumber", {
99
- enumerable: true,
100
- configurable: true,
101
- writable: true,
102
- value: (0, src_1.random16)()
103
- });
104
- Object.defineProperty(this, "timestamp", {
105
- enumerable: true,
106
- configurable: true,
107
- writable: true,
108
- value: (0, src_1.random32)()
109
- });
110
- }
111
- create(payload) {
112
- this.sequenceNumber = (0, src_1.uint16Add)(this.sequenceNumber, 1);
113
- this.timestamp = (0, src_1.uint32Add)(this.timestamp, 960);
114
- const header = new src_2.RtpHeader({
115
- sequenceNumber: this.sequenceNumber,
116
- timestamp: Number(this.timestamp),
117
- payloadType: 96,
118
- extension: true,
119
- marker: false,
120
- padding: false,
121
- });
122
- const rtp = new src_2.RtpPacket(header, payload);
123
- return rtp;
124
- }
125
- }
126
- exports.RtpBuilder = RtpBuilder;
127
92
  /**
128
93
  *
129
94
  * @param signatureHash
130
95
  * @param namedCurveAlgorithm necessary when use ecdsa
131
96
  */
132
97
  exports.createSelfSignedCertificate = cipher_1.CipherContext.createSelfSignedCertificateWithKey;
98
+ class MediaStreamTrackFactory {
99
+ static async rtpSource({ port, kind, }) {
100
+ port ?? (port = await (0, src_1.randomPort)());
101
+ const track = new track_1.MediaStreamTrack({ kind });
102
+ const udp = (0, dgram_1.createSocket)("udp4");
103
+ udp.bind(port);
104
+ const onMessage = (msg, rinfo) => {
105
+ track.writeRtp(msg);
106
+ };
107
+ udp.addListener("message", onMessage);
108
+ const dispose = () => {
109
+ udp.removeListener("message", onMessage);
110
+ udp.close();
111
+ };
112
+ return [track, port, dispose];
113
+ }
114
+ }
115
+ exports.MediaStreamTrackFactory = MediaStreamTrackFactory;
133
116
  //# sourceMappingURL=utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/utils.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable prefer-const */\nimport { createHash } from \"crypto\";\nimport debug from \"debug\";\nimport { performance } from \"perf_hooks\";\n\nimport {\n bufferReader,\n bufferWriter,\n random16,\n random32,\n uint16Add,\n uint32Add,\n} from \"../../common/src\";\nimport { CipherContext } from \"../../dtls/src/context/cipher\";\nimport { Address } from \"../../ice/src\";\nimport { RtpHeader, RtpPacket } from \"../../rtp/src\";\nimport { Direction, Directions } from \"./media/rtpTransceiver\";\nimport { RTCIceServer } from \"./peerConnection\";\nconst now = require(\"nano-time\");\n\nconst log = debug(\"werift:packages/webrtc/src/utils.ts\");\n\nexport function fingerprint(file: Buffer, hashName: string) {\n const upper = (s: string) => s.toUpperCase();\n const colon = (s: any) => s.match(/(.{2})/g).join(\":\");\n\n const hash = createHash(hashName).update(file).digest(\"hex\");\n\n return colon(upper(hash));\n}\n\nexport function isDtls(buf: Buffer) {\n const firstByte = buf[0];\n return firstByte > 19 && firstByte < 64;\n}\n\nexport function isMedia(buf: Buffer) {\n const firstByte = buf[0];\n return firstByte > 127 && firstByte < 192;\n}\n\nexport function reverseSimulcastDirection(dir: \"recv\" | \"send\") {\n if (dir === \"recv\") return \"send\";\n return \"recv\";\n}\n\nexport const andDirection = (a: Direction, b: Direction) =>\n Directions[Directions.indexOf(a) & Directions.indexOf(b)];\n\nexport function reverseDirection(dir: Direction): Direction {\n if (dir === \"sendonly\") return \"recvonly\";\n if (dir === \"recvonly\") return \"sendonly\";\n return dir;\n}\n\nexport const microTime = () => now.micro() as number;\n\nexport const milliTime = () => new Date().getTime();\n\nexport const timestampSeconds = () => Date.now() / 1000;\n\n/**https://datatracker.ietf.org/doc/html/rfc3550#section-4 */\nexport const ntpTime = () => {\n const now = performance.timeOrigin + performance.now() - Date.UTC(1900, 0, 1);\n\n const seconds = now / 1000;\n const [sec, msec] = seconds.toString().split(\".\").map(Number);\n\n const buf = bufferWriter([4, 4], [sec, msec]);\n\n return buf.readBigUInt64BE();\n};\n\n/**\n * https://datatracker.ietf.org/doc/html/rfc3550#section-4\n * @param ntp\n * @returns 32bit\n */\nexport const compactNtp = (ntp: bigint) => {\n const buf = bufferWriter([8], [ntp]);\n const [, sec, msec] = bufferReader(buf, [2, 2, 2, 2]);\n return bufferWriter([2, 2], [sec, msec]).readUInt32BE();\n};\n\nexport function parseIceServers(iceServers: RTCIceServer[]) {\n const url2Address = (url?: string) => {\n if (!url) return;\n const [address, port] = url.split(\":\");\n return [address, parseInt(port)] as Address;\n };\n\n const stunServer = url2Address(\n iceServers.find(({ urls }) => urls.includes(\"stun:\"))?.urls.slice(5)\n );\n const turnServer = url2Address(\n iceServers.find(({ urls }) => urls.includes(\"turn:\"))?.urls.slice(5)\n );\n const { credential, username } =\n iceServers.find(({ urls }) => urls.includes(\"turn:\")) || {};\n\n const options = {\n stunServer,\n turnServer,\n turnUsername: username,\n turnPassword: credential,\n };\n log(\"iceOptions\", options);\n return options;\n}\n\nexport class RtpBuilder {\n sequenceNumber = random16();\n timestamp = random32();\n\n create(payload: Buffer) {\n this.sequenceNumber = uint16Add(this.sequenceNumber, 1);\n this.timestamp = uint32Add(this.timestamp, 960);\n\n const header = new RtpHeader({\n sequenceNumber: this.sequenceNumber,\n timestamp: Number(this.timestamp),\n payloadType: 96,\n extension: true,\n marker: false,\n padding: false,\n });\n const rtp = new RtpPacket(header, payload);\n return rtp;\n }\n}\n\n/**\n *\n * @param signatureHash\n * @param namedCurveAlgorithm necessary when use ecdsa\n */\nexport const createSelfSignedCertificate =\n CipherContext.createSelfSignedCertificateWithKey;\n"]}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/utils.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable prefer-const */\nimport { createHash } from \"crypto\";\nimport debug from \"debug\";\nimport { createSocket, RemoteInfo } from \"dgram\";\nimport { performance } from \"perf_hooks\";\n\nimport { bufferReader, bufferWriter, randomPort } from \"../../common/src\";\nimport { CipherContext } from \"../../dtls/src/context/cipher\";\nimport { Address } from \"../../ice/src\";\nimport { Direction, Directions } from \"./media/rtpTransceiver\";\nimport { MediaStreamTrack } from \"./media/track\";\nimport { RTCIceServer } from \"./peerConnection\";\nconst now = require(\"nano-time\");\n\nconst log = debug(\"werift:packages/webrtc/src/utils.ts\");\n\nexport function fingerprint(file: Buffer, hashName: string) {\n const upper = (s: string) => s.toUpperCase();\n const colon = (s: any) => s.match(/(.{2})/g).join(\":\");\n\n const hash = createHash(hashName).update(file).digest(\"hex\");\n\n return colon(upper(hash));\n}\n\nexport function isDtls(buf: Buffer) {\n const firstByte = buf[0];\n return firstByte > 19 && firstByte < 64;\n}\n\nexport function reverseSimulcastDirection(dir: \"recv\" | \"send\") {\n if (dir === \"recv\") return \"send\";\n return \"recv\";\n}\n\nexport const andDirection = (a: Direction, b: Direction) =>\n Directions[Directions.indexOf(a) & Directions.indexOf(b)];\n\nexport function reverseDirection(dir: Direction): Direction {\n if (dir === \"sendonly\") return \"recvonly\";\n if (dir === \"recvonly\") return \"sendonly\";\n return dir;\n}\n\nexport const microTime = () => now.micro() as number;\n\nexport const milliTime = () => new Date().getTime();\n\nexport const timestampSeconds = () => Date.now() / 1000;\n\n/**https://datatracker.ietf.org/doc/html/rfc3550#section-4 */\nexport const ntpTime = () => {\n const now = performance.timeOrigin + performance.now() - Date.UTC(1900, 0, 1);\n\n const seconds = now / 1000;\n const [sec, msec] = seconds.toString().split(\".\").map(Number);\n\n const buf = bufferWriter([4, 4], [sec, msec]);\n\n return buf.readBigUInt64BE();\n};\n\n/**\n * https://datatracker.ietf.org/doc/html/rfc3550#section-4\n * @param ntp\n * @returns 32bit\n */\nexport const compactNtp = (ntp: bigint) => {\n const buf = bufferWriter([8], [ntp]);\n const [, sec, msec] = bufferReader(buf, [2, 2, 2, 2]);\n return bufferWriter([2, 2], [sec, msec]).readUInt32BE();\n};\n\nexport function parseIceServers(iceServers: RTCIceServer[]) {\n const url2Address = (url?: string) => {\n if (!url) return;\n const [address, port] = url.split(\":\");\n return [address, parseInt(port)] as Address;\n };\n\n const stunServer = url2Address(\n iceServers.find(({ urls }) => urls.includes(\"stun:\"))?.urls.slice(5)\n );\n const turnServer = url2Address(\n iceServers.find(({ urls }) => urls.includes(\"turn:\"))?.urls.slice(5)\n );\n const { credential, username } =\n iceServers.find(({ urls }) => urls.includes(\"turn:\")) || {};\n\n const options = {\n stunServer,\n turnServer,\n turnUsername: username,\n turnPassword: credential,\n };\n log(\"iceOptions\", options);\n return options;\n}\n\n/**\n *\n * @param signatureHash\n * @param namedCurveAlgorithm necessary when use ecdsa\n */\nexport const createSelfSignedCertificate =\n CipherContext.createSelfSignedCertificateWithKey;\n\nexport class MediaStreamTrackFactory {\n static async rtpSource({\n port,\n kind,\n }: {\n port?: number;\n kind: \"audio\" | \"video\";\n }) {\n port ??= await randomPort();\n const track = new MediaStreamTrack({ kind });\n\n const udp = createSocket(\"udp4\");\n udp.bind(port);\n const onMessage = (msg: Buffer, rinfo: RemoteInfo) => {\n track.writeRtp(msg);\n };\n udp.addListener(\"message\", onMessage);\n\n const dispose = () => {\n udp.removeListener(\"message\", onMessage);\n udp.close();\n };\n\n return [track, port, dispose] as const;\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "werift",
3
- "version": "0.18.7",
3
+ "version": "0.18.9",
4
4
  "description": "WebRTC Implementation for TypeScript (Node.js)",
5
5
  "keywords": [
6
6
  "WebRTC",
package/src/index.ts CHANGED
@@ -6,6 +6,8 @@ export * from "./dataChannel";
6
6
  export * from "./media/extension/rtcpFeedback";
7
7
  export * from "./media/extension/rtpExtension";
8
8
  export * from "./media/parameters";
9
+ export * from "./media/rtpReceiver";
10
+ export * from "./media/rtpSender";
9
11
  export * from "./media/rtpTransceiver";
10
12
  export * from "./media/track";
11
13
  export * from "./nonstandard/recorder";
@@ -9,6 +9,7 @@ import { Message } from "../../ice/src/stun/message";
9
9
  import { Protocol } from "../../ice/src/types/model";
10
10
  import {
11
11
  Address,
12
+ CandidatePair,
12
13
  deepMerge,
13
14
  InterfaceAddresses,
14
15
  Recvonly,
@@ -481,6 +482,7 @@ export class RTCPeerConnection extends EventTarget {
481
482
  interfaceAddresses: this.config.iceInterfaceAddresses,
482
483
  additionalHostAddresses: this.config.iceAdditionalHostAddresses,
483
484
  filterStunResponse: this.config.iceFilterStunResponse,
485
+ filterCandidatePair: this.config.iceFilterCandidatePair,
484
486
  useIpv4: this.config.iceUseIpv4,
485
487
  useIpv6: this.config.iceUseIpv6,
486
488
  });
@@ -835,10 +837,16 @@ export class RTCPeerConnection extends EventTarget {
835
837
  return bundle;
836
838
  }
837
839
 
838
- async setRemoteDescription(sessionDescription: {
839
- type: "offer" | "answer";
840
- sdp: string;
841
- }) {
840
+ async setRemoteDescription(sessionDescription: RTCSessionDescriptionInit) {
841
+ if (
842
+ !sessionDescription.sdp ||
843
+ !sessionDescription.type ||
844
+ sessionDescription.type === "rollback" ||
845
+ sessionDescription.type === "pranswer"
846
+ ) {
847
+ throw new Error("invalid sessionDescription");
848
+ }
849
+
842
850
  // # parse and validate description
843
851
  const remoteSdp = SessionDescription.parse(sessionDescription.sdp);
844
852
  remoteSdp.type = sessionDescription.type;
@@ -1646,6 +1654,7 @@ export interface PeerConfig {
1646
1654
  iceFilterStunResponse:
1647
1655
  | ((message: Message, addr: Address, protocol: Protocol) => boolean)
1648
1656
  | undefined;
1657
+ iceFilterCandidatePair: ((pair: CandidatePair) => boolean) | undefined;
1649
1658
  dtls: Partial<{
1650
1659
  keys: DtlsKeys;
1651
1660
  }>;
@@ -1715,6 +1724,7 @@ export const defaultPeerConfig: PeerConfig = {
1715
1724
  iceUseIpv4: true,
1716
1725
  iceUseIpv6: true,
1717
1726
  iceFilterStunResponse: undefined,
1727
+ iceFilterCandidatePair: undefined,
1718
1728
  dtls: {},
1719
1729
  bundlePolicy: "max-compat",
1720
1730
  debug: {},
@@ -1737,3 +1747,9 @@ export interface RTCPeerConnectionIceEvent {
1737
1747
  }
1738
1748
 
1739
1749
  type Media = "audio" | "video";
1750
+
1751
+ export interface RTCSessionDescriptionInit {
1752
+ sdp?: string;
1753
+ type: RTCSdpType;
1754
+ }
1755
+ export type RTCSdpType = "answer" | "offer" | "pranswer" | "rollback";
@@ -20,6 +20,7 @@ import { CipherContext } from "../../../dtls/src/context/cipher";
20
20
  import { Profile } from "../../../dtls/src/context/srtp";
21
21
  import { Connection } from "../../../ice/src";
22
22
  import {
23
+ isMedia,
23
24
  isRtcp,
24
25
  RtcpPacket,
25
26
  RtcpPacketConverter,
@@ -31,7 +32,7 @@ import {
31
32
  import { keyLength, saltLength } from "../../../rtp/src/srtp/const";
32
33
  import { RtpRouter } from "../media/router";
33
34
  import { PeerConfig } from "../peerConnection";
34
- import { fingerprint, isDtls, isMedia } from "../utils";
35
+ import { fingerprint, isDtls } from "../utils";
35
36
  import { RTCIceTransport } from "./ice";
36
37
 
37
38
  const log = debug("werift:packages/webrtc/src/transport/dtls.ts");
package/src/utils.ts CHANGED
@@ -1,20 +1,14 @@
1
1
  /* eslint-disable prefer-const */
2
2
  import { createHash } from "crypto";
3
3
  import debug from "debug";
4
+ import { createSocket, RemoteInfo } from "dgram";
4
5
  import { performance } from "perf_hooks";
5
6
 
6
- import {
7
- bufferReader,
8
- bufferWriter,
9
- random16,
10
- random32,
11
- uint16Add,
12
- uint32Add,
13
- } from "../../common/src";
7
+ import { bufferReader, bufferWriter, randomPort } from "../../common/src";
14
8
  import { CipherContext } from "../../dtls/src/context/cipher";
15
9
  import { Address } from "../../ice/src";
16
- import { RtpHeader, RtpPacket } from "../../rtp/src";
17
10
  import { Direction, Directions } from "./media/rtpTransceiver";
11
+ import { MediaStreamTrack } from "./media/track";
18
12
  import { RTCIceServer } from "./peerConnection";
19
13
  const now = require("nano-time");
20
14
 
@@ -34,11 +28,6 @@ export function isDtls(buf: Buffer) {
34
28
  return firstByte > 19 && firstByte < 64;
35
29
  }
36
30
 
37
- export function isMedia(buf: Buffer) {
38
- const firstByte = buf[0];
39
- return firstByte > 127 && firstByte < 192;
40
- }
41
-
42
31
  export function reverseSimulcastDirection(dir: "recv" | "send") {
43
32
  if (dir === "recv") return "send";
44
33
  return "recv";
@@ -108,27 +97,6 @@ export function parseIceServers(iceServers: RTCIceServer[]) {
108
97
  return options;
109
98
  }
110
99
 
111
- export class RtpBuilder {
112
- sequenceNumber = random16();
113
- timestamp = random32();
114
-
115
- create(payload: Buffer) {
116
- this.sequenceNumber = uint16Add(this.sequenceNumber, 1);
117
- this.timestamp = uint32Add(this.timestamp, 960);
118
-
119
- const header = new RtpHeader({
120
- sequenceNumber: this.sequenceNumber,
121
- timestamp: Number(this.timestamp),
122
- payloadType: 96,
123
- extension: true,
124
- marker: false,
125
- padding: false,
126
- });
127
- const rtp = new RtpPacket(header, payload);
128
- return rtp;
129
- }
130
- }
131
-
132
100
  /**
133
101
  *
134
102
  * @param signatureHash
@@ -136,3 +104,30 @@ export class RtpBuilder {
136
104
  */
137
105
  export const createSelfSignedCertificate =
138
106
  CipherContext.createSelfSignedCertificateWithKey;
107
+
108
+ export class MediaStreamTrackFactory {
109
+ static async rtpSource({
110
+ port,
111
+ kind,
112
+ }: {
113
+ port?: number;
114
+ kind: "audio" | "video";
115
+ }) {
116
+ port ??= await randomPort();
117
+ const track = new MediaStreamTrack({ kind });
118
+
119
+ const udp = createSocket("udp4");
120
+ udp.bind(port);
121
+ const onMessage = (msg: Buffer, rinfo: RemoteInfo) => {
122
+ track.writeRtp(msg);
123
+ };
124
+ udp.addListener("message", onMessage);
125
+
126
+ const dispose = () => {
127
+ udp.removeListener("message", onMessage);
128
+ udp.close();
129
+ };
130
+
131
+ return [track, port, dispose] as const;
132
+ }
133
+ }