@gjsify/webrtc 0.1.15

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 (117) hide show
  1. package/lib/esm/get-user-media.js +93 -0
  2. package/lib/esm/gst-enum-maps.js +88 -0
  3. package/lib/esm/gst-init.js +34 -0
  4. package/lib/esm/gst-stats-parser.js +79 -0
  5. package/lib/esm/gst-utils.js +16 -0
  6. package/lib/esm/index.js +53 -0
  7. package/lib/esm/media-device-info.js +23 -0
  8. package/lib/esm/media-devices.js +147 -0
  9. package/lib/esm/media-stream-track.js +142 -0
  10. package/lib/esm/media-stream.js +78 -0
  11. package/lib/esm/register/data-channel.js +8 -0
  12. package/lib/esm/register/error.js +8 -0
  13. package/lib/esm/register/media-devices.js +7 -0
  14. package/lib/esm/register/media.js +12 -0
  15. package/lib/esm/register/peer-connection.js +16 -0
  16. package/lib/esm/register.js +5 -0
  17. package/lib/esm/rtc-certificate.js +70 -0
  18. package/lib/esm/rtc-data-channel.js +266 -0
  19. package/lib/esm/rtc-dtls-transport.js +41 -0
  20. package/lib/esm/rtc-dtmf-sender.js +109 -0
  21. package/lib/esm/rtc-error.js +24 -0
  22. package/lib/esm/rtc-events.js +35 -0
  23. package/lib/esm/rtc-ice-candidate.js +75 -0
  24. package/lib/esm/rtc-ice-transport.js +96 -0
  25. package/lib/esm/rtc-peer-connection.js +855 -0
  26. package/lib/esm/rtc-rtp-receiver.js +91 -0
  27. package/lib/esm/rtc-rtp-sender.js +298 -0
  28. package/lib/esm/rtc-rtp-transceiver.js +97 -0
  29. package/lib/esm/rtc-sctp-transport.js +40 -0
  30. package/lib/esm/rtc-session-description.js +57 -0
  31. package/lib/esm/rtc-stats-report.js +35 -0
  32. package/lib/esm/rtc-track-event.js +29 -0
  33. package/lib/esm/rtp-capabilities.js +41 -0
  34. package/lib/esm/tee-multiplexer.js +62 -0
  35. package/lib/esm/wpt-helpers.js +122 -0
  36. package/lib/types/get-user-media.d.ts +14 -0
  37. package/lib/types/gst-enum-maps.d.ts +10 -0
  38. package/lib/types/gst-init.d.ts +5 -0
  39. package/lib/types/gst-stats-parser.d.ts +16 -0
  40. package/lib/types/gst-utils.d.ts +11 -0
  41. package/lib/types/index.d.ts +41 -0
  42. package/lib/types/media-device-info.d.ts +14 -0
  43. package/lib/types/media-devices.d.ts +12 -0
  44. package/lib/types/media-stream-track.d.ts +59 -0
  45. package/lib/types/media-stream.d.ts +28 -0
  46. package/lib/types/register/data-channel.d.ts +1 -0
  47. package/lib/types/register/error.d.ts +1 -0
  48. package/lib/types/register/media-devices.d.ts +1 -0
  49. package/lib/types/register/media.d.ts +1 -0
  50. package/lib/types/register/peer-connection.d.ts +1 -0
  51. package/lib/types/register.d.ts +5 -0
  52. package/lib/types/register.spec.d.ts +3 -0
  53. package/lib/types/rtc-certificate.d.ts +23 -0
  54. package/lib/types/rtc-data-channel.d.ts +64 -0
  55. package/lib/types/rtc-dtls-transport.d.ts +20 -0
  56. package/lib/types/rtc-dtmf-sender.d.ts +31 -0
  57. package/lib/types/rtc-error.d.ts +19 -0
  58. package/lib/types/rtc-events.d.ts +27 -0
  59. package/lib/types/rtc-ice-candidate.d.ts +28 -0
  60. package/lib/types/rtc-ice-transport.d.ts +56 -0
  61. package/lib/types/rtc-peer-connection.d.ts +165 -0
  62. package/lib/types/rtc-rtp-receiver.d.ts +45 -0
  63. package/lib/types/rtc-rtp-sender.d.ts +98 -0
  64. package/lib/types/rtc-rtp-transceiver.d.ts +20 -0
  65. package/lib/types/rtc-sctp-transport.d.ts +20 -0
  66. package/lib/types/rtc-session-description.d.ts +18 -0
  67. package/lib/types/rtc-stats-report.d.ts +22 -0
  68. package/lib/types/rtc-track-event.d.ts +18 -0
  69. package/lib/types/rtp-capabilities.d.ts +3 -0
  70. package/lib/types/tee-multiplexer.d.ts +25 -0
  71. package/lib/types/webrtc.spec.d.ts +2 -0
  72. package/lib/types/wpt-helpers.d.ts +30 -0
  73. package/lib/types/wpt-media.spec.d.ts +2 -0
  74. package/lib/types/wpt.spec.d.ts +2 -0
  75. package/package.json +74 -0
  76. package/src/get-user-media.ts +131 -0
  77. package/src/gst-enum-maps.ts +125 -0
  78. package/src/gst-init.ts +52 -0
  79. package/src/gst-stats-parser.ts +137 -0
  80. package/src/gst-utils.ts +41 -0
  81. package/src/index.ts +104 -0
  82. package/src/media-device-info.ts +33 -0
  83. package/src/media-devices.ts +191 -0
  84. package/src/media-stream-track.ts +159 -0
  85. package/src/media-stream.ts +96 -0
  86. package/src/register/data-channel.ts +11 -0
  87. package/src/register/error.ts +11 -0
  88. package/src/register/media-devices.ts +10 -0
  89. package/src/register/media.ts +15 -0
  90. package/src/register/peer-connection.ts +20 -0
  91. package/src/register.spec.ts +55 -0
  92. package/src/register.ts +10 -0
  93. package/src/rtc-certificate.ts +110 -0
  94. package/src/rtc-data-channel.ts +284 -0
  95. package/src/rtc-dtls-transport.ts +48 -0
  96. package/src/rtc-dtmf-sender.ts +146 -0
  97. package/src/rtc-error.ts +49 -0
  98. package/src/rtc-events.ts +64 -0
  99. package/src/rtc-ice-candidate.ts +115 -0
  100. package/src/rtc-ice-transport.ts +104 -0
  101. package/src/rtc-peer-connection.ts +1017 -0
  102. package/src/rtc-rtp-receiver.ts +122 -0
  103. package/src/rtc-rtp-sender.ts +444 -0
  104. package/src/rtc-rtp-transceiver.ts +127 -0
  105. package/src/rtc-sctp-transport.ts +48 -0
  106. package/src/rtc-session-description.ts +64 -0
  107. package/src/rtc-stats-report.ts +39 -0
  108. package/src/rtc-track-event.ts +45 -0
  109. package/src/rtp-capabilities.ts +48 -0
  110. package/src/tee-multiplexer.ts +75 -0
  111. package/src/test.mts +11 -0
  112. package/src/webrtc.spec.ts +1186 -0
  113. package/src/wpt-helpers.ts +156 -0
  114. package/src/wpt-media.spec.ts +1154 -0
  115. package/src/wpt.spec.ts +1136 -0
  116. package/tsconfig.json +36 -0
  117. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,48 @@
1
+ // W3C RTCSctpTransport for GJS.
2
+ //
3
+ // Created when a data channel is negotiated. Wraps the SCTP association
4
+ // over the DTLS transport. State transitions from connecting → connected
5
+ // when the first data channel opens.
6
+ //
7
+ // Reference: W3C WebRTC spec § 6.1
8
+ // Reference: refs/wpt/webrtc/RTCSctpTransport-constructor.html
9
+
10
+ import '@gjsify/dom-events/register/event-target';
11
+
12
+ import { RTCDtlsTransport } from './rtc-dtls-transport.js';
13
+
14
+ export type RTCSctpTransportState = 'connecting' | 'connected' | 'closed';
15
+
16
+ type EventHandler = ((ev: Event) => void) | null;
17
+
18
+ export class RTCSctpTransport extends EventTarget {
19
+ readonly transport: RTCDtlsTransport;
20
+ private _state: RTCSctpTransportState = 'connecting';
21
+ private _maxMessageSize: number = 262144; // 256 KB default per SCTP
22
+ private _maxChannels: number | null = 65535;
23
+
24
+ private _onstatechange: EventHandler = null;
25
+
26
+ constructor(dtlsTransport: RTCDtlsTransport) {
27
+ super();
28
+ this.transport = dtlsTransport;
29
+ }
30
+
31
+ get state(): RTCSctpTransportState { return this._state; }
32
+ get maxMessageSize(): number { return this._maxMessageSize; }
33
+ get maxChannels(): number | null { return this._maxChannels; }
34
+
35
+ get onstatechange(): EventHandler { return this._onstatechange; }
36
+ set onstatechange(v: EventHandler) { this._onstatechange = v; }
37
+
38
+ // ---- Internal setters (called by RTCPeerConnection) ---------------------
39
+
40
+ /** @internal */
41
+ _setState(state: RTCSctpTransportState): void {
42
+ if (this._state === state) return;
43
+ this._state = state;
44
+ const ev = new Event('statechange');
45
+ this._onstatechange?.call(this, ev);
46
+ this.dispatchEvent(ev);
47
+ }
48
+ }
@@ -0,0 +1,64 @@
1
+ // RTCSessionDescription — W3C WebRTC session description (offer/answer/rollback).
2
+ //
3
+ // Reference: refs/node-gst-webrtc/src/webrtc/RTCSessionDescription.ts (ISC)
4
+ // Adapted for GJS using GstSdp + GstWebRTC.
5
+
6
+ import GstSdp from 'gi://GstSdp?version=1.0';
7
+ import GstWebRTC from 'gi://GstWebRTC?version=1.0';
8
+
9
+ export type RTCSdpType = 'offer' | 'pranswer' | 'answer' | 'rollback';
10
+
11
+ export interface RTCSessionDescriptionInit {
12
+ type?: RTCSdpType;
13
+ sdp?: string;
14
+ }
15
+
16
+ function sdpTypeToGst(type: RTCSdpType): GstWebRTC.WebRTCSDPType {
17
+ switch (type) {
18
+ case 'offer': return GstWebRTC.WebRTCSDPType.OFFER;
19
+ case 'pranswer': return GstWebRTC.WebRTCSDPType.PRANSWER;
20
+ case 'answer': return GstWebRTC.WebRTCSDPType.ANSWER;
21
+ case 'rollback': return GstWebRTC.WebRTCSDPType.ROLLBACK;
22
+ }
23
+ }
24
+
25
+ function sdpTypeFromGst(type: GstWebRTC.WebRTCSDPType): RTCSdpType {
26
+ switch (type) {
27
+ case GstWebRTC.WebRTCSDPType.OFFER: return 'offer';
28
+ case GstWebRTC.WebRTCSDPType.PRANSWER: return 'pranswer';
29
+ case GstWebRTC.WebRTCSDPType.ANSWER: return 'answer';
30
+ case GstWebRTC.WebRTCSDPType.ROLLBACK: return 'rollback';
31
+ default: return 'offer';
32
+ }
33
+ }
34
+
35
+ export class RTCSessionDescription {
36
+ readonly type: RTCSdpType;
37
+ readonly sdp: string;
38
+
39
+ constructor(init?: RTCSessionDescriptionInit) {
40
+ this.type = (init?.type ?? 'offer') as RTCSdpType;
41
+ this.sdp = init?.sdp ?? '';
42
+ }
43
+
44
+ toJSON(): { type: RTCSdpType; sdp: string } {
45
+ return { type: this.type, sdp: this.sdp };
46
+ }
47
+
48
+ /** Build a GstWebRTC.WebRTCSessionDescription for use with webrtcbin signals. */
49
+ toGstDesc(): GstWebRTC.WebRTCSessionDescription {
50
+ const [ret, sdp] = GstSdp.SDPMessage.new_from_text(this.sdp);
51
+ if (ret !== GstSdp.SDPResult.OK) {
52
+ throw new Error(`Failed to parse SDP text (GstSDPResult=${ret})`);
53
+ }
54
+ return GstWebRTC.WebRTCSessionDescription.new(sdpTypeToGst(this.type), sdp);
55
+ }
56
+
57
+ static fromGstDesc(desc: GstWebRTC.WebRTCSessionDescription): RTCSessionDescription {
58
+ const sdpText = desc.sdp?.as_text?.() ?? '';
59
+ return new RTCSessionDescription({
60
+ type: sdpTypeFromGst(desc.type),
61
+ sdp: sdpText,
62
+ });
63
+ }
64
+ }
@@ -0,0 +1,39 @@
1
+ // W3C RTCStatsReport — read-only Map<string, object> of WebRTC statistics.
2
+ //
3
+ // Reference: W3C WebRTC spec § 8.5
4
+ // The report is a frozen snapshot; .set()/.delete()/.clear() are no-ops.
5
+
6
+ export interface RTCStats {
7
+ timestamp: number;
8
+ type: string;
9
+ id: string;
10
+ [key: string]: unknown;
11
+ }
12
+
13
+ /**
14
+ * Read-only Map-like collection of stats entries keyed by id.
15
+ * W3C requires iteration support but not mutation.
16
+ */
17
+ export class RTCStatsReport {
18
+ private readonly _map: Map<string, RTCStats>;
19
+
20
+ constructor(entries?: Iterable<[string, RTCStats]>) {
21
+ this._map = new Map(entries);
22
+ }
23
+
24
+ get size(): number { return this._map.size; }
25
+
26
+ get(key: string): RTCStats | undefined { return this._map.get(key); }
27
+ has(key: string): boolean { return this._map.has(key); }
28
+
29
+ forEach(callbackfn: (value: RTCStats, key: string, map: RTCStatsReport) => void, thisArg?: unknown): void {
30
+ this._map.forEach((value, key) => {
31
+ callbackfn.call(thisArg, value, key, this);
32
+ });
33
+ }
34
+
35
+ entries(): IterableIterator<[string, RTCStats]> { return this._map.entries(); }
36
+ keys(): IterableIterator<string> { return this._map.keys(); }
37
+ values(): IterableIterator<RTCStats> { return this._map.values(); }
38
+ [Symbol.iterator](): IterableIterator<[string, RTCStats]> { return this._map.entries(); }
39
+ }
@@ -0,0 +1,45 @@
1
+ // W3C RTCTrackEvent for GJS.
2
+ //
3
+ // Ported from refs/wpt/webrtc/RTCTrackEvent-constructor.html (W3C, BSD-3-Clause)
4
+ // Reference: W3C WebRTC spec § 5.7
5
+
6
+ import '@gjsify/dom-events/register/event-target';
7
+
8
+ import type { RTCRtpReceiver } from './rtc-rtp-receiver.js';
9
+ import type { RTCRtpTransceiver } from './rtc-rtp-transceiver.js';
10
+ import type { MediaStreamTrack } from './media-stream-track.js';
11
+ import type { MediaStream } from './media-stream.js';
12
+
13
+ export interface RTCTrackEventInit extends EventInit {
14
+ receiver: RTCRtpReceiver;
15
+ track: MediaStreamTrack;
16
+ streams?: MediaStream[];
17
+ transceiver: RTCRtpTransceiver;
18
+ }
19
+
20
+ export class RTCTrackEvent extends Event {
21
+ readonly receiver: RTCRtpReceiver;
22
+ readonly track: MediaStreamTrack;
23
+ readonly streams: ReadonlyArray<MediaStream>;
24
+ readonly transceiver: RTCRtpTransceiver;
25
+
26
+ constructor(type: string, init: RTCTrackEventInit) {
27
+ super(type, init);
28
+ if (!init || typeof init !== 'object') {
29
+ throw new TypeError('RTCTrackEventInit is required');
30
+ }
31
+ if (!('receiver' in init)) {
32
+ throw new TypeError("Failed to construct 'RTCTrackEvent': required member receiver is not provided.");
33
+ }
34
+ if (!('track' in init)) {
35
+ throw new TypeError("Failed to construct 'RTCTrackEvent': required member track is not provided.");
36
+ }
37
+ if (!('transceiver' in init)) {
38
+ throw new TypeError("Failed to construct 'RTCTrackEvent': required member transceiver is not provided.");
39
+ }
40
+ this.receiver = init.receiver;
41
+ this.track = init.track;
42
+ this.streams = Object.freeze(init.streams ? [...init.streams] : []);
43
+ this.transceiver = init.transceiver;
44
+ }
45
+ }
@@ -0,0 +1,48 @@
1
+ // Shared RTP codec capabilities for RTCRtpSender and RTCRtpReceiver.
2
+ //
3
+ // Both classes expose identical getCapabilities(kind) static methods per
4
+ // W3C WebRTC spec §§ 5.2 and 5.3. This module deduplicates the data.
5
+
6
+ import type { RTCRtpCapabilities } from './rtc-rtp-sender.js';
7
+
8
+ const AUDIO_CAPABILITIES: RTCRtpCapabilities = {
9
+ codecs: [
10
+ { mimeType: 'audio/opus', clockRate: 48000, channels: 2, sdpFmtpLine: 'minptime=10;useinbandfec=1' },
11
+ { mimeType: 'audio/G722', clockRate: 8000, channels: 1 },
12
+ { mimeType: 'audio/PCMU', clockRate: 8000, channels: 1 },
13
+ { mimeType: 'audio/PCMA', clockRate: 8000, channels: 1 },
14
+ { mimeType: 'audio/telephone-event', clockRate: 8000, channels: 1 },
15
+ { mimeType: 'audio/red', clockRate: 48000, channels: 2 },
16
+ ],
17
+ headerExtensions: [
18
+ { uri: 'urn:ietf:params:rtp-hdrext:ssrc-audio-level' },
19
+ { uri: 'http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time' },
20
+ { uri: 'urn:ietf:params:rtp-hdrext:sdes:mid' },
21
+ ],
22
+ };
23
+
24
+ const VIDEO_CAPABILITIES: RTCRtpCapabilities = {
25
+ codecs: [
26
+ { mimeType: 'video/VP8', clockRate: 90000 },
27
+ { mimeType: 'video/rtx', clockRate: 90000 },
28
+ { mimeType: 'video/H264', clockRate: 90000, sdpFmtpLine: 'level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f' },
29
+ { mimeType: 'video/VP9', clockRate: 90000 },
30
+ { mimeType: 'video/red', clockRate: 90000 },
31
+ { mimeType: 'video/ulpfec', clockRate: 90000 },
32
+ ],
33
+ headerExtensions: [
34
+ { uri: 'urn:ietf:params:rtp-hdrext:toffset' },
35
+ { uri: 'http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time' },
36
+ { uri: 'urn:3gpp:video-orientation' },
37
+ { uri: 'urn:ietf:params:rtp-hdrext:sdes:mid' },
38
+ { uri: 'urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id' },
39
+ { uri: 'urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id' },
40
+ ],
41
+ };
42
+
43
+ /** Shared implementation for RTCRtpSender.getCapabilities / RTCRtpReceiver.getCapabilities. */
44
+ export function getRtpCapabilities(kind: string): RTCRtpCapabilities | null {
45
+ if (kind === 'audio') return AUDIO_CAPABILITIES;
46
+ if (kind === 'video') return VIDEO_CAPABILITIES;
47
+ return null;
48
+ }
@@ -0,0 +1,75 @@
1
+ // GStreamer tee element manager for multi-PC fan-out.
2
+ //
3
+ // When a single MediaStreamTrack (backed by a GStreamer source) needs to
4
+ // feed multiple RTCPeerConnections, a tee element is inserted after the
5
+ // source. Each PC gets its own branch (encoder chain → webrtcbin sink).
6
+ //
7
+ // Reference: refs/node-gst-webrtc/src/media/TeeMultiplexer.ts (ISC)
8
+ // Reference: packages/web/webrtc-native/src/vala/receiver-bridge.vala (tee pattern)
9
+
10
+ import { Gst } from './gst-init.js';
11
+
12
+ /**
13
+ * Manages a GStreamer `tee` element that fans out one source to multiple
14
+ * consumer branches. Each branch gets its own src pad from the tee.
15
+ */
16
+ export class TeeMultiplexer {
17
+ private _tee: any; // Gst.Element
18
+ private _pipeline: any; // Gst.Pipeline
19
+ private _branchCount = 0;
20
+
21
+ /**
22
+ * Create a tee in the given pipeline and link it to the source's output.
23
+ * The source must already be in the pipeline.
24
+ */
25
+ constructor(pipeline: any, source: any) {
26
+ this._pipeline = pipeline;
27
+ this._tee = Gst.ElementFactory.make('tee', null)!;
28
+ (this._tee as any).allow_not_linked = true;
29
+
30
+ pipeline.add(this._tee);
31
+ this._tee.sync_state_with_parent();
32
+
33
+ // Link source → tee
34
+ source.link(this._tee);
35
+ }
36
+
37
+ /** Request a new src pad from the tee for a consumer branch. */
38
+ requestSrcPad(): any /* Gst.Pad */ {
39
+ const padName = 'src_%u';
40
+ const srcPad = this._tee.request_pad_simple
41
+ ? this._tee.request_pad_simple(padName)
42
+ : this._tee.get_request_pad(padName);
43
+ if (srcPad) this._branchCount++;
44
+ return srcPad;
45
+ }
46
+
47
+ /**
48
+ * Release a branch's src pad from the tee.
49
+ * Adds a DROP probe before unlinking to prevent errors.
50
+ */
51
+ releaseSrcPad(srcPad: any): void {
52
+ if (!srcPad) return;
53
+ try {
54
+ // Block data on the pad before unlinking
55
+ srcPad.add_probe(
56
+ Gst.PadProbeType.BLOCK_DOWNSTREAM,
57
+ () => Gst.PadProbeReturn.DROP,
58
+ );
59
+ } catch { /* ignore if probe fails */ }
60
+ try {
61
+ const peer = srcPad.get_peer();
62
+ if (peer) srcPad.unlink(peer);
63
+ } catch { /* ignore */ }
64
+ try {
65
+ this._tee.release_request_pad(srcPad);
66
+ } catch { /* ignore */ }
67
+ this._branchCount--;
68
+ }
69
+
70
+ /** Number of active branches. */
71
+ get branchCount(): number { return this._branchCount; }
72
+
73
+ /** The tee element (for pipeline queries). */
74
+ get element(): any { return this._tee; }
75
+ }
package/src/test.mts ADDED
@@ -0,0 +1,11 @@
1
+ import webrtcSpec from './webrtc.spec.js';
2
+ import wptSpec from './wpt.spec.js';
3
+ import wptMediaSpec from './wpt-media.spec.js';
4
+ import registerSpec from './register.spec.js';
5
+
6
+ const results = {
7
+ webrtc: await webrtcSpec(),
8
+ wpt: await wptSpec(),
9
+ wptMedia: await wptMediaSpec(),
10
+ register: await registerSpec(),
11
+ };