@gjsify/webrtc 0.4.0 → 0.4.4

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 (44) hide show
  1. package/package.json +73 -70
  2. package/src/get-user-media.ts +0 -131
  3. package/src/gst-enum-maps.ts +0 -125
  4. package/src/gst-init.ts +0 -49
  5. package/src/gst-stats-parser.ts +0 -137
  6. package/src/gst-utils.ts +0 -41
  7. package/src/index.ts +0 -104
  8. package/src/internal/gst-types.ts +0 -122
  9. package/src/media-device-info.ts +0 -33
  10. package/src/media-devices.ts +0 -191
  11. package/src/media-stream-track.ts +0 -159
  12. package/src/media-stream.ts +0 -96
  13. package/src/register/data-channel.ts +0 -11
  14. package/src/register/error.ts +0 -11
  15. package/src/register/media-devices.ts +0 -10
  16. package/src/register/media.ts +0 -15
  17. package/src/register/peer-connection.ts +0 -20
  18. package/src/register.spec.ts +0 -55
  19. package/src/register.ts +0 -10
  20. package/src/rtc-certificate.ts +0 -110
  21. package/src/rtc-data-channel.ts +0 -283
  22. package/src/rtc-dtls-transport.ts +0 -48
  23. package/src/rtc-dtmf-sender.ts +0 -146
  24. package/src/rtc-error.ts +0 -49
  25. package/src/rtc-events.ts +0 -64
  26. package/src/rtc-ice-candidate.ts +0 -115
  27. package/src/rtc-ice-transport.ts +0 -104
  28. package/src/rtc-peer-connection.ts +0 -1039
  29. package/src/rtc-rtp-receiver.ts +0 -122
  30. package/src/rtc-rtp-sender.ts +0 -471
  31. package/src/rtc-rtp-transceiver.ts +0 -131
  32. package/src/rtc-sctp-transport.ts +0 -48
  33. package/src/rtc-session-description.ts +0 -64
  34. package/src/rtc-stats-report.ts +0 -39
  35. package/src/rtc-track-event.ts +0 -45
  36. package/src/rtp-capabilities.ts +0 -48
  37. package/src/tee-multiplexer.ts +0 -75
  38. package/src/test.mts +0 -11
  39. package/src/webrtc.spec.ts +0 -1186
  40. package/src/wpt-helpers.ts +0 -156
  41. package/src/wpt-media.spec.ts +0 -1154
  42. package/src/wpt.spec.ts +0 -1136
  43. package/tsconfig.json +0 -36
  44. package/tsconfig.tsbuildinfo +0 -1
@@ -1,131 +0,0 @@
1
- // W3C RTCRtpTransceiver for GJS.
2
- //
3
- // Wraps GstWebRTC.WebRTCRTPTransceiver. Reads mid, direction, currentDirection
4
- // from the native object. direction setter maps back to GStreamer enum.
5
- //
6
- // Reference: refs/node-gst-webrtc/src/webrtc/RTCRtpTransceiver.ts (ISC)
7
- // Reference: W3C WebRTC spec § 5.4
8
-
9
- import type GstWebRTC from 'gi://GstWebRTC?version=1.0';
10
-
11
- import { gstDirectionToW3C, w3cDirectionToGst } from './gst-enum-maps.js';
12
- import { RTCRtpSender, type RTCRtpTransceiverDirection, type RTCRtpCodecCapability } from './rtc-rtp-sender.js';
13
- import { RTCRtpReceiver } from './rtc-rtp-receiver.js';
14
-
15
- export class RTCRtpTransceiver {
16
- private _gstTrans: GstWebRTC.WebRTCRTPTransceiver;
17
- readonly sender: RTCRtpSender;
18
- readonly receiver: RTCRtpReceiver;
19
- private _stopped = false;
20
- private _codecPreferences: RTCRtpCodecCapability[] = [];
21
-
22
- constructor(
23
- gstTrans: GstWebRTC.WebRTCRTPTransceiver,
24
- sender: RTCRtpSender,
25
- receiver: RTCRtpReceiver,
26
- ) {
27
- this._gstTrans = gstTrans;
28
- this.sender = sender;
29
- this.receiver = receiver;
30
- }
31
-
32
- get mid(): string | null {
33
- if (this._stopped) return null;
34
- const m = this._gstTrans.mid;
35
- return (m === '' || m == null) ? null : String(m);
36
- }
37
-
38
- get direction(): RTCRtpTransceiverDirection {
39
- if (this._stopped) return 'stopped';
40
- return gstDirectionToW3C(this._gstTrans.direction);
41
- }
42
-
43
- set direction(d: RTCRtpTransceiverDirection) {
44
- if (this._stopped) {
45
- throw new DOMException(
46
- "Cannot set direction on a stopped transceiver",
47
- 'InvalidStateError',
48
- );
49
- }
50
- if (d === 'stopped') {
51
- throw new TypeError("The provided value 'stopped' is not a valid enum value of type RTCRtpTransceiverDirection.");
52
- }
53
- const valid: RTCRtpTransceiverDirection[] = ['sendrecv', 'sendonly', 'recvonly', 'inactive'];
54
- if (!valid.includes(d)) {
55
- throw new TypeError(`The provided value '${d}' is not a valid enum value of type RTCRtpTransceiverDirection.`);
56
- }
57
- this._gstTrans.direction = w3cDirectionToGst(d);
58
- }
59
-
60
- get currentDirection(): RTCRtpTransceiverDirection | null {
61
- if (this._stopped) return null;
62
- // GIR exposes both snake_case `current_direction` and camelCase
63
- // `currentDirection` getters — they refer to the same GObject
64
- // property. Read snake_case first; fall back to camelCase for
65
- // older GstWebRTC bindings that omitted the snake_case alias.
66
- const cd = this._gstTrans.current_direction ?? this._gstTrans.currentDirection;
67
- if (cd == null) return null;
68
- const w3c = gstDirectionToW3C(cd);
69
- return w3c === 'inactive' ? null : w3c;
70
- }
71
-
72
- get stopped(): boolean {
73
- return this._stopped;
74
- }
75
-
76
- stop(): void {
77
- if (this._stopped) return;
78
- this._stopped = true;
79
- }
80
-
81
- setCodecPreferences(codecs: RTCRtpCodecCapability[]): void {
82
- if (!Array.isArray(codecs)) {
83
- throw new TypeError('codecs must be an array');
84
- }
85
- if (codecs.length === 0) {
86
- this._codecPreferences = [];
87
- return;
88
- }
89
-
90
- const kind = this.receiver.track.kind;
91
- const recvCaps = RTCRtpReceiver.getCapabilities(kind);
92
- const sendCaps = RTCRtpSender.getCapabilities(kind);
93
- if (!recvCaps || !sendCaps) {
94
- throw new DOMException('No capabilities available', 'InvalidModificationError');
95
- }
96
-
97
- const allCaps = [...recvCaps.codecs, ...sendCaps.codecs];
98
-
99
- for (const codec of codecs) {
100
- if (!codec || typeof codec !== 'object') {
101
- throw new TypeError('Each codec must be an object');
102
- }
103
- if (typeof codec.mimeType !== 'string' || typeof codec.clockRate !== 'number') {
104
- throw new TypeError('codec must have mimeType (string) and clockRate (number)');
105
- }
106
-
107
- const isResiliency = /\/(rtx|red|ulpfec)$/i.test(codec.mimeType);
108
- if (isResiliency) continue;
109
-
110
- const match = allCaps.find((c) =>
111
- c.mimeType.toLowerCase() === codec.mimeType.toLowerCase() &&
112
- c.clockRate === codec.clockRate &&
113
- (codec.channels === undefined || c.channels === codec.channels) &&
114
- (codec.sdpFmtpLine === undefined || c.sdpFmtpLine === codec.sdpFmtpLine)
115
- );
116
- if (!match) {
117
- throw new DOMException(
118
- `Codec ${codec.mimeType} ${codec.clockRate} is not in capabilities`,
119
- 'InvalidModificationError',
120
- );
121
- }
122
- }
123
-
124
- this._codecPreferences = [...codecs];
125
- }
126
-
127
- /** @internal */
128
- get _nativeTransceiver(): GstWebRTC.WebRTCRTPTransceiver {
129
- return this._gstTrans;
130
- }
131
- }
@@ -1,48 +0,0 @@
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
- }
@@ -1,64 +0,0 @@
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
- }
@@ -1,39 +0,0 @@
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
- }
@@ -1,45 +0,0 @@
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
- }
@@ -1,48 +0,0 @@
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
- }
@@ -1,75 +0,0 @@
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 DELETED
@@ -1,11 +0,0 @@
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
- };