@gjsify/webrtc 0.3.21 → 0.4.3

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 (76) hide show
  1. package/lib/esm/_virtual/_rolldown/runtime.js +1 -0
  2. package/lib/esm/get-user-media.js +1 -1
  3. package/lib/esm/gst-enum-maps.js +1 -1
  4. package/lib/esm/gst-init.js +1 -1
  5. package/lib/esm/gst-stats-parser.js +1 -1
  6. package/lib/esm/gst-utils.js +1 -1
  7. package/lib/esm/internal/gst-types.js +1 -0
  8. package/lib/esm/media-device-info.js +1 -1
  9. package/lib/esm/media-devices.js +1 -1
  10. package/lib/esm/media-stream-track.js +1 -1
  11. package/lib/esm/media-stream.js +1 -1
  12. package/lib/esm/rtc-certificate.js +1 -1
  13. package/lib/esm/rtc-data-channel.js +1 -1
  14. package/lib/esm/rtc-dtls-transport.js +1 -1
  15. package/lib/esm/rtc-dtmf-sender.js +1 -1
  16. package/lib/esm/rtc-error.js +1 -1
  17. package/lib/esm/rtc-events.js +1 -1
  18. package/lib/esm/rtc-ice-candidate.js +1 -1
  19. package/lib/esm/rtc-ice-transport.js +1 -1
  20. package/lib/esm/rtc-peer-connection.js +1 -1
  21. package/lib/esm/rtc-rtp-receiver.js +1 -1
  22. package/lib/esm/rtc-rtp-sender.js +1 -1
  23. package/lib/esm/rtc-rtp-transceiver.js +1 -1
  24. package/lib/esm/rtc-sctp-transport.js +1 -1
  25. package/lib/esm/rtc-session-description.js +1 -1
  26. package/lib/esm/rtc-stats-report.js +1 -1
  27. package/lib/esm/rtc-track-event.js +1 -1
  28. package/lib/esm/rtp-capabilities.js +1 -1
  29. package/lib/esm/tee-multiplexer.js +1 -1
  30. package/lib/esm/wpt-helpers.js +1 -1
  31. package/lib/types/gst-enum-maps.d.ts +2 -1
  32. package/lib/types/internal/gst-types.d.ts +83 -0
  33. package/lib/types/rtc-rtp-sender.d.ts +3 -2
  34. package/package.json +73 -70
  35. package/src/get-user-media.ts +0 -131
  36. package/src/gst-enum-maps.ts +0 -125
  37. package/src/gst-init.ts +0 -49
  38. package/src/gst-stats-parser.ts +0 -137
  39. package/src/gst-utils.ts +0 -41
  40. package/src/index.ts +0 -104
  41. package/src/media-device-info.ts +0 -33
  42. package/src/media-devices.ts +0 -191
  43. package/src/media-stream-track.ts +0 -159
  44. package/src/media-stream.ts +0 -96
  45. package/src/register/data-channel.ts +0 -11
  46. package/src/register/error.ts +0 -11
  47. package/src/register/media-devices.ts +0 -10
  48. package/src/register/media.ts +0 -15
  49. package/src/register/peer-connection.ts +0 -20
  50. package/src/register.spec.ts +0 -55
  51. package/src/register.ts +0 -10
  52. package/src/rtc-certificate.ts +0 -110
  53. package/src/rtc-data-channel.ts +0 -283
  54. package/src/rtc-dtls-transport.ts +0 -48
  55. package/src/rtc-dtmf-sender.ts +0 -146
  56. package/src/rtc-error.ts +0 -49
  57. package/src/rtc-events.ts +0 -64
  58. package/src/rtc-ice-candidate.ts +0 -115
  59. package/src/rtc-ice-transport.ts +0 -104
  60. package/src/rtc-peer-connection.ts +0 -1023
  61. package/src/rtc-rtp-receiver.ts +0 -122
  62. package/src/rtc-rtp-sender.ts +0 -444
  63. package/src/rtc-rtp-transceiver.ts +0 -127
  64. package/src/rtc-sctp-transport.ts +0 -48
  65. package/src/rtc-session-description.ts +0 -64
  66. package/src/rtc-stats-report.ts +0 -39
  67. package/src/rtc-track-event.ts +0 -45
  68. package/src/rtp-capabilities.ts +0 -48
  69. package/src/tee-multiplexer.ts +0 -75
  70. package/src/test.mts +0 -11
  71. package/src/webrtc.spec.ts +0 -1186
  72. package/src/wpt-helpers.ts +0 -156
  73. package/src/wpt-media.spec.ts +0 -1154
  74. package/src/wpt.spec.ts +0 -1136
  75. package/tsconfig.json +0 -36
  76. package/tsconfig.tsbuildinfo +0 -1
package/src/index.ts DELETED
@@ -1,104 +0,0 @@
1
- // W3C WebRTC API for GJS — backed by GStreamer webrtcbin.
2
- //
3
- // This module has no side effects. Importing @gjsify/webrtc gives named
4
- // access to the classes but does NOT register globals. Use
5
- // @gjsify/webrtc/register (or a granular subpath) to set globalThis.RTCPeerConnection etc.
6
-
7
- export { RTCPeerConnection } from './rtc-peer-connection.js';
8
- export type {
9
- RTCConfiguration,
10
- RTCIceServer,
11
- RTCOfferOptions,
12
- RTCAnswerOptions,
13
- RTCDataChannelInit,
14
- RTCSignalingState,
15
- RTCPeerConnectionState,
16
- RTCIceConnectionState,
17
- RTCIceGatheringState,
18
- RTCIceTransportPolicy,
19
- RTCBundlePolicy,
20
- RTCRtcpMuxPolicy,
21
- } from './rtc-peer-connection.js';
22
-
23
- export { RTCDataChannel } from './rtc-data-channel.js';
24
- export type { RTCDataChannelState, BinaryType } from './rtc-data-channel.js';
25
-
26
- export { RTCSessionDescription } from './rtc-session-description.js';
27
- export type { RTCSessionDescriptionInit, RTCSdpType } from './rtc-session-description.js';
28
-
29
- export { RTCIceCandidate } from './rtc-ice-candidate.js';
30
- export type {
31
- RTCIceCandidateInit,
32
- RTCIceComponent,
33
- RTCIceProtocol,
34
- RTCIceCandidateType,
35
- RTCIceTcpCandidateType,
36
- } from './rtc-ice-candidate.js';
37
-
38
- export { RTCError } from './rtc-error.js';
39
- export type { RTCErrorInit, RTCErrorDetailType } from './rtc-error.js';
40
-
41
- export {
42
- RTCPeerConnectionIceEvent,
43
- RTCDataChannelEvent,
44
- RTCErrorEvent,
45
- } from './rtc-events.js';
46
- export type {
47
- RTCPeerConnectionIceEventInit,
48
- RTCDataChannelEventInit,
49
- RTCErrorEventInit,
50
- } from './rtc-events.js';
51
-
52
- export { RTCRtpSender } from './rtc-rtp-sender.js';
53
- export type {
54
- RTCRtpTransceiverDirection,
55
- RTCRtpCapabilities,
56
- RTCRtpCodecCapability,
57
- RTCRtpHeaderExtensionCapability,
58
- RTCRtpSendParameters,
59
- RTCRtpEncodingParameters,
60
- RTCRtpCodecParameters,
61
- RTCRtpHeaderExtensionParameters,
62
- RTCRtcpParameters,
63
- } from './rtc-rtp-sender.js';
64
-
65
- export { RTCRtpReceiver } from './rtc-rtp-receiver.js';
66
- export type { RTCRtpReceiveParameters } from './rtc-rtp-receiver.js';
67
-
68
- export { RTCRtpTransceiver } from './rtc-rtp-transceiver.js';
69
-
70
- export { MediaStream } from './media-stream.js';
71
- export { MediaStreamTrackEvent } from './media-stream.js';
72
-
73
- export { MediaStreamTrack } from './media-stream-track.js';
74
- export type { MediaStreamTrackInit } from './media-stream-track.js';
75
-
76
- export { RTCTrackEvent } from './rtc-track-event.js';
77
- export type { RTCTrackEventInit } from './rtc-track-event.js';
78
-
79
- export type { RTCRtpTransceiverInit } from './rtc-peer-connection.js';
80
-
81
- export { getUserMedia } from './get-user-media.js';
82
- export type { MediaStreamConstraints, MediaTrackConstraints } from './get-user-media.js';
83
-
84
- export { MediaDevices } from './media-devices.js';
85
- export { MediaDeviceInfo } from './media-device-info.js';
86
- export type { MediaDeviceKind } from './media-device-info.js';
87
-
88
- export { RTCStatsReport } from './rtc-stats-report.js';
89
- export type { RTCStats } from './rtc-stats-report.js';
90
-
91
- export { RTCDtlsTransport } from './rtc-dtls-transport.js';
92
- export type { RTCDtlsTransportState } from './rtc-dtls-transport.js';
93
-
94
- export { RTCIceTransport } from './rtc-ice-transport.js';
95
- export type { RTCIceTransportState, RTCIceRole, RTCIceParameters, RTCIceCandidatePair } from './rtc-ice-transport.js';
96
-
97
- export { RTCSctpTransport } from './rtc-sctp-transport.js';
98
- export type { RTCSctpTransportState } from './rtc-sctp-transport.js';
99
-
100
- export { RTCDTMFSender, RTCDTMFToneChangeEvent } from './rtc-dtmf-sender.js';
101
- export type { RTCDTMFToneChangeEventInit } from './rtc-dtmf-sender.js';
102
-
103
- export { RTCCertificate } from './rtc-certificate.js';
104
- export type { RTCDtlsFingerprint, AlgorithmIdentifier } from './rtc-certificate.js';
@@ -1,33 +0,0 @@
1
- // W3C MediaDeviceInfo for GJS — backed by GStreamer Device Monitor.
2
- //
3
- // Reference: W3C Media Capture and Streams spec § 10.2.1
4
-
5
- export type MediaDeviceKind = 'audioinput' | 'audiooutput' | 'videoinput';
6
-
7
- export class MediaDeviceInfo {
8
- readonly deviceId: string;
9
- readonly kind: MediaDeviceKind;
10
- readonly label: string;
11
- readonly groupId: string;
12
-
13
- constructor(init: {
14
- deviceId: string;
15
- kind: MediaDeviceKind;
16
- label: string;
17
- groupId?: string;
18
- }) {
19
- this.deviceId = init.deviceId;
20
- this.kind = init.kind;
21
- this.label = init.label;
22
- this.groupId = init.groupId ?? '';
23
- }
24
-
25
- toJSON(): object {
26
- return {
27
- deviceId: this.deviceId,
28
- kind: this.kind,
29
- label: this.label,
30
- groupId: this.groupId,
31
- };
32
- }
33
- }
@@ -1,191 +0,0 @@
1
- // W3C MediaDevices for GJS.
2
- //
3
- // Phase 3: getUserMedia via GStreamer sources.
4
- // Phase 4.3: enumerateDevices via GStreamer Device Monitor,
5
- // getSupportedConstraints returns supported constraints.
6
- //
7
- // Reference: W3C Media Capture and Streams spec § 10.2
8
- // Reference: refs/webkit/Source/WebCore/platform/mediastream/gstreamer/GStreamerCaptureDeviceManager.cpp
9
-
10
- import '@gjsify/dom-events/register/event-target';
11
-
12
- import { ensureGstInit, Gst } from './gst-init.js';
13
- import { getUserMedia, type MediaStreamConstraints } from './get-user-media.js';
14
- import { MediaDeviceInfo, type MediaDeviceKind } from './media-device-info.js';
15
- import type { MediaStream } from './media-stream.js';
16
-
17
- /** Map GStreamer device class strings to W3C MediaDeviceKind. */
18
- const DEVICE_CLASS_MAP: Record<string, MediaDeviceKind> = {
19
- 'Audio/Source': 'audioinput',
20
- 'Video/Source': 'videoinput',
21
- 'Audio/Sink': 'audiooutput',
22
- };
23
-
24
- /** Whether getUserMedia has been successfully called (unlocks full device info). */
25
- let _permissionGranted = false;
26
-
27
- /**
28
- * Check if GStreamer device monitoring is safe to use.
29
- * On some GJS/GStreamer combinations (e.g. Fedora 44 / GJS 1.88 in Docker),
30
- * DeviceMonitor and DeviceProviderFactory can SIGSEGV in native code — a crash
31
- * that JS error handling cannot intercept. We skip device monitoring entirely
32
- * when DISPLAY is absent (headless/CI) since there are typically no audio/video
33
- * devices in containers anyway.
34
- */
35
- function isDeviceMonitorSafe(): boolean {
36
- try {
37
- // Import GLib to check environment — avoid crashing GStreamer APIs
38
- const GLib = imports.gi.GLib;
39
- // Skip in CI environments or headless containers
40
- if (GLib.getenv('CI')) return false;
41
- // No display = likely a container without devices
42
- if (!GLib.getenv('DISPLAY') && !GLib.getenv('WAYLAND_DISPLAY')) return false;
43
- return true;
44
- } catch {
45
- return false;
46
- }
47
- }
48
-
49
- export class MediaDevices extends EventTarget {
50
- private _ondevicechange: ((ev: Event) => void) | null = null;
51
-
52
- get ondevicechange(): ((ev: Event) => void) | null { return this._ondevicechange; }
53
- set ondevicechange(v: ((ev: Event) => void) | null) { this._ondevicechange = v; }
54
-
55
- async getUserMedia(constraints?: MediaStreamConstraints): Promise<MediaStream> {
56
- if (!constraints) {
57
- throw new TypeError(
58
- "Failed to execute 'getUserMedia' on 'MediaDevices': At least one of audio or video must be requested",
59
- );
60
- }
61
- const stream = await getUserMedia(constraints);
62
- _permissionGranted = true;
63
- return stream;
64
- }
65
-
66
- async enumerateDevices(): Promise<MediaDeviceInfo[]> {
67
- ensureGstInit();
68
-
69
- let monitor: InstanceType<typeof Gst.DeviceMonitor> | null = null;
70
- const result: MediaDeviceInfo[] = [];
71
-
72
- try {
73
- // Guard: on CI containers without PipeWire/PulseAudio, DeviceMonitor
74
- // can SIGSEGV in native GStreamer code. Check for device providers first.
75
- if (!isDeviceMonitorSafe()) {
76
- return result;
77
- }
78
-
79
- monitor = new Gst.DeviceMonitor();
80
- monitor.set_show_all_devices(true);
81
- const audioCaps = Gst.Caps.from_string('audio/x-raw');
82
- const videoCaps = Gst.Caps.from_string('video/x-raw');
83
- if (audioCaps) {
84
- monitor.add_filter('Audio/Source', audioCaps);
85
- monitor.add_filter('Audio/Sink', audioCaps);
86
- }
87
- if (videoCaps) {
88
- monitor.add_filter('Video/Source', videoCaps);
89
- }
90
-
91
- if (!monitor.start()) {
92
- // DeviceMonitor failed to start — return empty list gracefully
93
- return result;
94
- }
95
-
96
- let gstDevices: any[];
97
- try {
98
- gstDevices = monitor.get_devices() ?? [];
99
- } catch {
100
- // get_devices() can crash on some GStreamer/GJS versions — return empty
101
- return result;
102
- }
103
-
104
- for (const device of gstDevices) {
105
- const deviceClass = device.get_device_class?.() ?? '';
106
- const kind = DEVICE_CLASS_MAP[deviceClass];
107
- if (!kind) continue;
108
-
109
- const displayName = device.get_display_name?.() ?? '';
110
- let deviceId = '';
111
- let groupId = '';
112
-
113
- // Extract persistent-id from device properties if available
114
- try {
115
- const props = device.get_properties?.();
116
- if (props) {
117
- const n = props.n_fields();
118
- for (let i = 0; i < n; i++) {
119
- const name = props.nth_field_name(i);
120
- if (name === 'persistent-id' || name === 'node.name') {
121
- const val = props.get_value(name);
122
- if (val && !deviceId) deviceId = String(val);
123
- }
124
- if (name === 'group-id') {
125
- const val = props.get_value(name);
126
- if (val) groupId = String(val);
127
- }
128
- }
129
- }
130
- } catch { /* properties may not be available */ }
131
-
132
- // Fallback deviceId from display name hash
133
- if (!deviceId) {
134
- deviceId = displayName || `${kind}-${result.length}`;
135
- }
136
-
137
- // Per W3C: before getUserMedia permission, expose only empty
138
- // deviceId/label/groupId (one device per kind max).
139
- if (_permissionGranted) {
140
- result.push(new MediaDeviceInfo({
141
- deviceId,
142
- kind,
143
- label: displayName,
144
- groupId,
145
- }));
146
- } else {
147
- // Check if we already have a device of this kind
148
- if (!result.some(d => d.kind === kind)) {
149
- result.push(new MediaDeviceInfo({
150
- deviceId: '',
151
- kind,
152
- label: '',
153
- groupId: '',
154
- }));
155
- }
156
- }
157
- }
158
- } catch {
159
- // DeviceMonitor or device enumeration crashed — return whatever we have
160
- return result;
161
- } finally {
162
- try { monitor?.stop(); } catch { /* ignore stop errors */ }
163
- }
164
-
165
- // W3C ordering: audioinput first, then videoinput, then audiooutput
166
- const order: Record<string, number> = { audioinput: 0, videoinput: 1, audiooutput: 2 };
167
- result.sort((a, b) => (order[a.kind] ?? 3) - (order[b.kind] ?? 3));
168
-
169
- return result;
170
- }
171
-
172
- getSupportedConstraints(): Record<string, boolean> {
173
- return {
174
- deviceId: true,
175
- width: true,
176
- height: true,
177
- frameRate: true,
178
- sampleRate: true,
179
- channelCount: true,
180
- // Not yet supported — return false
181
- aspectRatio: false,
182
- facingMode: false,
183
- resizeMode: false,
184
- echoCancellation: false,
185
- autoGainControl: false,
186
- noiseSuppression: false,
187
- latency: false,
188
- groupId: false,
189
- };
190
- }
191
- }
@@ -1,159 +0,0 @@
1
- // W3C MediaStreamTrack for GJS.
2
- //
3
- // Phase 2: lightweight API surface with event dispatch.
4
- // Phase 3: optional GStreamer source integration — tracks created by
5
- // getUserMedia carry a GStreamer source element reference that the
6
- // RTCRtpSender wires into the webrtcbin pipeline.
7
- //
8
- // Reference: refs/node-gst-webrtc/src/media/MediaStreamTrack.ts (ISC)
9
- // Reference: W3C MediaStreamTrack spec
10
-
11
- import '@gjsify/dom-events/register/event-target';
12
-
13
- import GLib from 'gi://GLib?version=2.0';
14
-
15
- import { Gst } from './gst-init.js';
16
-
17
- /** @internal GStreamer backing for tracks created by getUserMedia */
18
- export interface MediaStreamTrackGstInit {
19
- source: any; // Gst.Element
20
- pipeline: any; // Gst.Pipeline
21
- }
22
-
23
- export interface MediaStreamTrackInit {
24
- kind: 'audio' | 'video';
25
- label?: string;
26
- id?: string;
27
- muted?: boolean;
28
- /** @internal */
29
- _gst?: MediaStreamTrackGstInit;
30
- }
31
-
32
- export class MediaStreamTrack extends EventTarget {
33
- readonly id: string;
34
- readonly kind: 'audio' | 'video';
35
- readonly label: string;
36
-
37
- private _enabled = true;
38
- private _muted: boolean;
39
- private _ended = false;
40
- private _contentHint = '';
41
-
42
- private _onended: ((ev: Event) => void) | null = null;
43
- private _onmute: ((ev: Event) => void) | null = null;
44
- private _onunmute: ((ev: Event) => void) | null = null;
45
-
46
- /** @internal GStreamer source element (e.g. pulsesrc, audiotestsrc) */
47
- _gstSource: any = null;
48
- /** @internal Pipeline the source currently lives in (updated by VideoBridge) */
49
- _gstPipeline: any = null;
50
- /** @internal Tee element inserted by VideoBridge for preview fan-out */
51
- _gstTee: any = null;
52
- /** @internal TeeMultiplexer for multi-PC fan-out (created on second addTrack) */
53
- _teeMultiplexer: any = null;
54
- /** @internal Callback set by RTCRtpSender to control valve drop property */
55
- private _enableCallback: ((enabled: boolean) => void) | null = null;
56
-
57
- constructor(init: MediaStreamTrackInit) {
58
- super();
59
- this.id = init.id ?? GLib.uuid_string_random();
60
- this.kind = init.kind;
61
- this.label = init.label ?? '';
62
- this._muted = init.muted ?? false;
63
-
64
- if (init._gst) {
65
- this._gstSource = init._gst.source;
66
- this._gstPipeline = init._gst.pipeline;
67
- }
68
- }
69
-
70
- get enabled(): boolean { return this._enabled; }
71
- set enabled(v: boolean) {
72
- const val = !!v;
73
- if (this._enabled === val) return;
74
- this._enabled = val;
75
- this._enableCallback?.(val);
76
- }
77
-
78
- get muted(): boolean { return this._muted; }
79
-
80
- get readyState(): 'live' | 'ended' { return this._ended ? 'ended' : 'live'; }
81
-
82
- get contentHint(): string { return this._contentHint; }
83
- set contentHint(v: string) {
84
- if (this.kind === 'audio') {
85
- if (v !== '' && v !== 'speech' && v !== 'speech-recognition' && v !== 'music') return;
86
- } else {
87
- if (v !== '' && v !== 'motion' && v !== 'detail' && v !== 'text') return;
88
- }
89
- this._contentHint = v;
90
- }
91
-
92
- get onended(): ((ev: Event) => void) | null { return this._onended; }
93
- set onended(v: ((ev: Event) => void) | null) { this._onended = v; }
94
- get onmute(): ((ev: Event) => void) | null { return this._onmute; }
95
- set onmute(v: ((ev: Event) => void) | null) { this._onmute = v; }
96
- get onunmute(): ((ev: Event) => void) | null { return this._onunmute; }
97
- set onunmute(v: ((ev: Event) => void) | null) { this._onunmute = v; }
98
-
99
- clone(): MediaStreamTrack {
100
- const cloned = new MediaStreamTrack({
101
- kind: this.kind,
102
- label: this.label,
103
- muted: this._muted,
104
- });
105
- cloned._enabled = this._enabled;
106
- return cloned;
107
- }
108
-
109
- stop(): void {
110
- if (this._ended) return;
111
- this._ended = true;
112
-
113
- // Clean up GStreamer source and pipeline if present
114
- if (this._gstSource || this._gstPipeline) {
115
- try {
116
- // Set pipeline to NULL first (this stops all children)
117
- this._gstPipeline?.set_state(Gst.State.NULL);
118
- } catch { /* ignore */ }
119
- try {
120
- this._gstSource?.set_state(Gst.State.NULL);
121
- } catch { /* ignore */ }
122
- this._gstSource = null;
123
- this._gstPipeline = null;
124
- }
125
-
126
- const ev = new Event('ended');
127
- this._onended?.call(this, ev);
128
- this.dispatchEvent(ev);
129
- }
130
-
131
- getCapabilities(): Record<string, unknown> { return {}; }
132
- getConstraints(): Record<string, unknown> { return {}; }
133
- getSettings(): Record<string, unknown> { return {}; }
134
-
135
- applyConstraints(_constraints?: unknown): Promise<void> {
136
- return Promise.reject(new DOMException(
137
- 'applyConstraints is not supported',
138
- 'NotSupportedError',
139
- ));
140
- }
141
-
142
- /** @internal — used by RTCRtpReceiver to toggle mute state */
143
- _setMuted(muted: boolean): void {
144
- if (this._muted === muted) return;
145
- this._muted = muted;
146
- const ev = new Event(muted ? 'mute' : 'unmute');
147
- if (muted) {
148
- this._onmute?.call(this, ev);
149
- } else {
150
- this._onunmute?.call(this, ev);
151
- }
152
- this.dispatchEvent(ev);
153
- }
154
-
155
- /** @internal — called by RTCRtpSender to wire valve control */
156
- _setEnableCallback(cb: ((enabled: boolean) => void) | null): void {
157
- this._enableCallback = cb;
158
- }
159
- }
@@ -1,96 +0,0 @@
1
- // W3C MediaStream for GJS.
2
- //
3
- // Pure-JS collection container for MediaStreamTrack instances.
4
- // No GStreamer pipeline integration — that is Phase 2.5.
5
- //
6
- // Reference: refs/node-gst-webrtc/src/media/MediaStream.ts (ISC)
7
- // Reference: W3C MediaStream spec
8
-
9
- import '@gjsify/dom-events/register/event-target';
10
-
11
- import GLib from 'gi://GLib?version=2.0';
12
-
13
- import { MediaStreamTrack } from './media-stream-track.js';
14
-
15
- export class MediaStream extends EventTarget {
16
- readonly id: string;
17
- private _tracks = new Map<string, MediaStreamTrack>();
18
-
19
- private _onaddtrack: ((ev: Event) => void) | null = null;
20
- private _onremovetrack: ((ev: Event) => void) | null = null;
21
-
22
- constructor(streamOrTracks?: MediaStream | MediaStreamTrack[]) {
23
- super();
24
- this.id = GLib.uuid_string_random();
25
-
26
- if (streamOrTracks instanceof MediaStream) {
27
- for (const track of streamOrTracks.getTracks()) {
28
- this._tracks.set(track.id, track.clone());
29
- }
30
- } else if (Array.isArray(streamOrTracks)) {
31
- for (const track of streamOrTracks) {
32
- this._tracks.set(track.id, track);
33
- }
34
- }
35
- }
36
-
37
- get active(): boolean {
38
- for (const track of this._tracks.values()) {
39
- if (track.readyState === 'live') return true;
40
- }
41
- return false;
42
- }
43
-
44
- get onaddtrack(): ((ev: Event) => void) | null { return this._onaddtrack; }
45
- set onaddtrack(v: ((ev: Event) => void) | null) { this._onaddtrack = v; }
46
- get onremovetrack(): ((ev: Event) => void) | null { return this._onremovetrack; }
47
- set onremovetrack(v: ((ev: Event) => void) | null) { this._onremovetrack = v; }
48
-
49
- getTracks(): MediaStreamTrack[] {
50
- return [...this._tracks.values()];
51
- }
52
-
53
- getAudioTracks(): MediaStreamTrack[] {
54
- return this.getTracks().filter((t) => t.kind === 'audio');
55
- }
56
-
57
- getVideoTracks(): MediaStreamTrack[] {
58
- return this.getTracks().filter((t) => t.kind === 'video');
59
- }
60
-
61
- getTrackById(id: string): MediaStreamTrack | null {
62
- return this._tracks.get(id) ?? null;
63
- }
64
-
65
- addTrack(track: MediaStreamTrack): void {
66
- if (this._tracks.has(track.id)) return;
67
- this._tracks.set(track.id, track);
68
- const ev = new MediaStreamTrackEvent('addtrack', { track });
69
- this._onaddtrack?.call(this, ev);
70
- this.dispatchEvent(ev);
71
- }
72
-
73
- removeTrack(track: MediaStreamTrack): void {
74
- if (!this._tracks.delete(track.id)) return;
75
- const ev = new MediaStreamTrackEvent('removetrack', { track });
76
- this._onremovetrack?.call(this, ev);
77
- this.dispatchEvent(ev);
78
- }
79
-
80
- clone(): MediaStream {
81
- return new MediaStream(this);
82
- }
83
- }
84
-
85
- export interface MediaStreamTrackEventInit extends EventInit {
86
- track: MediaStreamTrack;
87
- }
88
-
89
- export class MediaStreamTrackEvent extends Event {
90
- readonly track: MediaStreamTrack;
91
-
92
- constructor(type: string, init: MediaStreamTrackEventInit) {
93
- super(type, init);
94
- this.track = init.track;
95
- }
96
- }
@@ -1,11 +0,0 @@
1
- // Registers: RTCDataChannel, RTCDataChannelEvent.
2
-
3
- import { RTCDataChannel } from '../rtc-data-channel.js';
4
- import { RTCDataChannelEvent } from '../rtc-events.js';
5
-
6
- if (typeof (globalThis as any).RTCDataChannel === 'undefined') {
7
- (globalThis as any).RTCDataChannel = RTCDataChannel;
8
- }
9
- if (typeof (globalThis as any).RTCDataChannelEvent === 'undefined') {
10
- (globalThis as any).RTCDataChannelEvent = RTCDataChannelEvent;
11
- }
@@ -1,11 +0,0 @@
1
- // Registers: RTCError, RTCErrorEvent.
2
-
3
- import { RTCError } from '../rtc-error.js';
4
- import { RTCErrorEvent } from '../rtc-events.js';
5
-
6
- if (typeof (globalThis as any).RTCError === 'undefined') {
7
- (globalThis as any).RTCError = RTCError;
8
- }
9
- if (typeof (globalThis as any).RTCErrorEvent === 'undefined') {
10
- (globalThis as any).RTCErrorEvent = RTCErrorEvent;
11
- }
@@ -1,10 +0,0 @@
1
- // Register navigator.mediaDevices on globalThis for GJS.
2
-
3
- import { MediaDevices } from '../media-devices.js';
4
-
5
- if (typeof (globalThis as any).navigator === 'undefined') {
6
- (globalThis as any).navigator = {} as any;
7
- }
8
- if (typeof (globalThis as any).navigator.mediaDevices === 'undefined') {
9
- (globalThis as any).navigator.mediaDevices = new MediaDevices();
10
- }
@@ -1,15 +0,0 @@
1
- // Registers: MediaStream, MediaStreamTrack, RTCTrackEvent.
2
-
3
- import { MediaStream } from '../media-stream.js';
4
- import { MediaStreamTrack } from '../media-stream-track.js';
5
- import { RTCTrackEvent } from '../rtc-track-event.js';
6
-
7
- if (typeof (globalThis as any).MediaStream === 'undefined') {
8
- (globalThis as any).MediaStream = MediaStream;
9
- }
10
- if (typeof (globalThis as any).MediaStreamTrack === 'undefined') {
11
- (globalThis as any).MediaStreamTrack = MediaStreamTrack;
12
- }
13
- if (typeof (globalThis as any).RTCTrackEvent === 'undefined') {
14
- (globalThis as any).RTCTrackEvent = RTCTrackEvent;
15
- }
@@ -1,20 +0,0 @@
1
- // Registers: RTCPeerConnection, RTCSessionDescription, RTCIceCandidate,
2
- // RTCPeerConnectionIceEvent.
3
-
4
- import { RTCPeerConnection } from '../rtc-peer-connection.js';
5
- import { RTCSessionDescription } from '../rtc-session-description.js';
6
- import { RTCIceCandidate } from '../rtc-ice-candidate.js';
7
- import { RTCPeerConnectionIceEvent } from '../rtc-events.js';
8
-
9
- if (typeof (globalThis as any).RTCPeerConnection === 'undefined') {
10
- (globalThis as any).RTCPeerConnection = RTCPeerConnection;
11
- }
12
- if (typeof (globalThis as any).RTCSessionDescription === 'undefined') {
13
- (globalThis as any).RTCSessionDescription = RTCSessionDescription;
14
- }
15
- if (typeof (globalThis as any).RTCIceCandidate === 'undefined') {
16
- (globalThis as any).RTCIceCandidate = RTCIceCandidate;
17
- }
18
- if (typeof (globalThis as any).RTCPeerConnectionIceEvent === 'undefined') {
19
- (globalThis as any).RTCPeerConnectionIceEvent = RTCPeerConnectionIceEvent;
20
- }