@gjsify/webrtc 0.3.13 → 0.3.14

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 (36) hide show
  1. package/lib/esm/get-user-media.js +95 -80
  2. package/lib/esm/gst-enum-maps.js +55 -59
  3. package/lib/esm/gst-init.js +19 -22
  4. package/lib/esm/gst-stats-parser.js +94 -67
  5. package/lib/esm/gst-utils.js +24 -13
  6. package/lib/esm/index.js +13 -43
  7. package/lib/esm/media-device-info.js +23 -22
  8. package/lib/esm/media-devices.js +150 -139
  9. package/lib/esm/media-stream-track.js +136 -139
  10. package/lib/esm/media-stream.js +76 -75
  11. package/lib/esm/register/data-channel.js +7 -3
  12. package/lib/esm/register/error.js +6 -2
  13. package/lib/esm/register/media-devices.js +6 -2
  14. package/lib/esm/register/media.js +8 -4
  15. package/lib/esm/register/peer-connection.js +9 -5
  16. package/lib/esm/rtc-certificate.js +62 -66
  17. package/lib/esm/rtc-data-channel.js +240 -251
  18. package/lib/esm/rtc-dtls-transport.js +40 -39
  19. package/lib/esm/rtc-dtmf-sender.js +92 -100
  20. package/lib/esm/rtc-error.js +24 -22
  21. package/lib/esm/rtc-events.js +33 -33
  22. package/lib/esm/rtc-ice-candidate.js +71 -72
  23. package/lib/esm/rtc-ice-transport.js +95 -94
  24. package/lib/esm/rtc-peer-connection.js +796 -845
  25. package/lib/esm/rtc-rtp-receiver.js +89 -87
  26. package/lib/esm/rtc-rtp-sender.js +282 -290
  27. package/lib/esm/rtc-rtp-transceiver.js +92 -93
  28. package/lib/esm/rtc-sctp-transport.js +38 -38
  29. package/lib/esm/rtc-session-description.js +47 -51
  30. package/lib/esm/rtc-stats-report.js +39 -34
  31. package/lib/esm/rtc-track-event.js +29 -27
  32. package/lib/esm/rtp-capabilities.js +81 -35
  33. package/lib/esm/tee-multiplexer.js +58 -60
  34. package/lib/esm/wpt-helpers.js +128 -112
  35. package/package.json +13 -13
  36. package/tsconfig.tsbuildinfo +1 -1
package/lib/esm/index.js CHANGED
@@ -1,53 +1,23 @@
1
- import { RTCPeerConnection } from "./rtc-peer-connection.js";
2
- import { RTCDataChannel } from "./rtc-data-channel.js";
1
+ import { MediaStreamTrack } from "./media-stream-track.js";
2
+ import { MediaStream, MediaStreamTrackEvent } from "./media-stream.js";
3
+ import { getUserMedia } from "./get-user-media.js";
4
+ import { RTCStatsReport } from "./rtc-stats-report.js";
3
5
  import { RTCSessionDescription } from "./rtc-session-description.js";
4
6
  import { RTCIceCandidate } from "./rtc-ice-candidate.js";
5
7
  import { RTCError } from "./rtc-error.js";
6
- import {
7
- RTCPeerConnectionIceEvent,
8
- RTCDataChannelEvent,
9
- RTCErrorEvent
10
- } from "./rtc-events.js";
8
+ import { RTCDataChannelEvent, RTCErrorEvent, RTCPeerConnectionIceEvent } from "./rtc-events.js";
9
+ import { RTCDataChannel } from "./rtc-data-channel.js";
10
+ import { RTCDTMFSender, RTCDTMFToneChangeEvent } from "./rtc-dtmf-sender.js";
11
11
  import { RTCRtpSender } from "./rtc-rtp-sender.js";
12
12
  import { RTCRtpReceiver } from "./rtc-rtp-receiver.js";
13
13
  import { RTCRtpTransceiver } from "./rtc-rtp-transceiver.js";
14
- import { MediaStream } from "./media-stream.js";
15
- import { MediaStreamTrackEvent } from "./media-stream.js";
16
- import { MediaStreamTrack } from "./media-stream-track.js";
17
14
  import { RTCTrackEvent } from "./rtc-track-event.js";
18
- import { getUserMedia } from "./get-user-media.js";
19
- import { MediaDevices } from "./media-devices.js";
20
- import { MediaDeviceInfo } from "./media-device-info.js";
21
- import { RTCStatsReport } from "./rtc-stats-report.js";
22
- import { RTCDtlsTransport } from "./rtc-dtls-transport.js";
23
15
  import { RTCIceTransport } from "./rtc-ice-transport.js";
16
+ import { RTCDtlsTransport } from "./rtc-dtls-transport.js";
24
17
  import { RTCSctpTransport } from "./rtc-sctp-transport.js";
25
- import { RTCDTMFSender, RTCDTMFToneChangeEvent } from "./rtc-dtmf-sender.js";
26
18
  import { RTCCertificate } from "./rtc-certificate.js";
27
- export {
28
- MediaDeviceInfo,
29
- MediaDevices,
30
- MediaStream,
31
- MediaStreamTrack,
32
- MediaStreamTrackEvent,
33
- RTCCertificate,
34
- RTCDTMFSender,
35
- RTCDTMFToneChangeEvent,
36
- RTCDataChannel,
37
- RTCDataChannelEvent,
38
- RTCDtlsTransport,
39
- RTCError,
40
- RTCErrorEvent,
41
- RTCIceCandidate,
42
- RTCIceTransport,
43
- RTCPeerConnection,
44
- RTCPeerConnectionIceEvent,
45
- RTCRtpReceiver,
46
- RTCRtpSender,
47
- RTCRtpTransceiver,
48
- RTCSctpTransport,
49
- RTCSessionDescription,
50
- RTCStatsReport,
51
- RTCTrackEvent,
52
- getUserMedia
53
- };
19
+ import { RTCPeerConnection } from "./rtc-peer-connection.js";
20
+ import { MediaDeviceInfo } from "./media-device-info.js";
21
+ import { MediaDevices } from "./media-devices.js";
22
+
23
+ export { MediaDeviceInfo, MediaDevices, MediaStream, MediaStreamTrack, MediaStreamTrackEvent, RTCCertificate, RTCDTMFSender, RTCDTMFToneChangeEvent, RTCDataChannel, RTCDataChannelEvent, RTCDtlsTransport, RTCError, RTCErrorEvent, RTCIceCandidate, RTCIceTransport, RTCPeerConnection, RTCPeerConnectionIceEvent, RTCRtpReceiver, RTCRtpSender, RTCRtpTransceiver, RTCSctpTransport, RTCSessionDescription, RTCStatsReport, RTCTrackEvent, getUserMedia };
@@ -1,23 +1,24 @@
1
- class MediaDeviceInfo {
2
- deviceId;
3
- kind;
4
- label;
5
- groupId;
6
- constructor(init) {
7
- this.deviceId = init.deviceId;
8
- this.kind = init.kind;
9
- this.label = init.label;
10
- this.groupId = init.groupId ?? "";
11
- }
12
- toJSON() {
13
- return {
14
- deviceId: this.deviceId,
15
- kind: this.kind,
16
- label: this.label,
17
- groupId: this.groupId
18
- };
19
- }
20
- }
21
- export {
22
- MediaDeviceInfo
1
+ //#region src/media-device-info.ts
2
+ var MediaDeviceInfo = class {
3
+ deviceId;
4
+ kind;
5
+ label;
6
+ groupId;
7
+ constructor(init) {
8
+ this.deviceId = init.deviceId;
9
+ this.kind = init.kind;
10
+ this.label = init.label;
11
+ this.groupId = init.groupId ?? "";
12
+ }
13
+ toJSON() {
14
+ return {
15
+ deviceId: this.deviceId,
16
+ kind: this.kind,
17
+ label: this.label,
18
+ groupId: this.groupId
19
+ };
20
+ }
23
21
  };
22
+
23
+ //#endregion
24
+ export { MediaDeviceInfo };
@@ -1,147 +1,158 @@
1
- import "@gjsify/dom-events/register/event-target";
2
- import { ensureGstInit, Gst } from "./gst-init.js";
1
+ import { Gst, ensureGstInit } from "./gst-init.js";
3
2
  import { getUserMedia } from "./get-user-media.js";
4
3
  import { MediaDeviceInfo } from "./media-device-info.js";
4
+ import "@gjsify/dom-events/register/event-target";
5
+
6
+ //#region src/media-devices.ts
7
+ /** Map GStreamer device class strings to W3C MediaDeviceKind. */
5
8
  const DEVICE_CLASS_MAP = {
6
- "Audio/Source": "audioinput",
7
- "Video/Source": "videoinput",
8
- "Audio/Sink": "audiooutput"
9
+ "Audio/Source": "audioinput",
10
+ "Video/Source": "videoinput",
11
+ "Audio/Sink": "audiooutput"
9
12
  };
13
+ /** Whether getUserMedia has been successfully called (unlocks full device info). */
10
14
  let _permissionGranted = false;
15
+ /**
16
+ * Check if GStreamer device monitoring is safe to use.
17
+ * On some GJS/GStreamer combinations (e.g. Fedora 44 / GJS 1.88 in Docker),
18
+ * DeviceMonitor and DeviceProviderFactory can SIGSEGV in native code — a crash
19
+ * that JS error handling cannot intercept. We skip device monitoring entirely
20
+ * when DISPLAY is absent (headless/CI) since there are typically no audio/video
21
+ * devices in containers anyway.
22
+ */
11
23
  function isDeviceMonitorSafe() {
12
- try {
13
- const GLib = imports.gi.GLib;
14
- if (GLib.getenv("CI")) return false;
15
- if (!GLib.getenv("DISPLAY") && !GLib.getenv("WAYLAND_DISPLAY")) return false;
16
- return true;
17
- } catch {
18
- return false;
19
- }
20
- }
21
- class MediaDevices extends EventTarget {
22
- _ondevicechange = null;
23
- get ondevicechange() {
24
- return this._ondevicechange;
25
- }
26
- set ondevicechange(v) {
27
- this._ondevicechange = v;
28
- }
29
- async getUserMedia(constraints) {
30
- if (!constraints) {
31
- throw new TypeError(
32
- "Failed to execute 'getUserMedia' on 'MediaDevices': At least one of audio or video must be requested"
33
- );
34
- }
35
- const stream = await getUserMedia(constraints);
36
- _permissionGranted = true;
37
- return stream;
38
- }
39
- async enumerateDevices() {
40
- ensureGstInit();
41
- let monitor = null;
42
- const result = [];
43
- try {
44
- if (!isDeviceMonitorSafe()) {
45
- return result;
46
- }
47
- monitor = new Gst.DeviceMonitor();
48
- monitor.set_show_all_devices(true);
49
- const audioCaps = Gst.Caps.from_string("audio/x-raw");
50
- const videoCaps = Gst.Caps.from_string("video/x-raw");
51
- if (audioCaps) {
52
- monitor.add_filter("Audio/Source", audioCaps);
53
- monitor.add_filter("Audio/Sink", audioCaps);
54
- }
55
- if (videoCaps) {
56
- monitor.add_filter("Video/Source", videoCaps);
57
- }
58
- if (!monitor.start()) {
59
- return result;
60
- }
61
- let gstDevices;
62
- try {
63
- gstDevices = monitor.get_devices() ?? [];
64
- } catch {
65
- return result;
66
- }
67
- for (const device of gstDevices) {
68
- const deviceClass = device.get_device_class?.() ?? "";
69
- const kind = DEVICE_CLASS_MAP[deviceClass];
70
- if (!kind) continue;
71
- const displayName = device.get_display_name?.() ?? "";
72
- let deviceId = "";
73
- let groupId = "";
74
- try {
75
- const props = device.get_properties?.();
76
- if (props) {
77
- const n = props.n_fields();
78
- for (let i = 0; i < n; i++) {
79
- const name = props.nth_field_name(i);
80
- if (name === "persistent-id" || name === "node.name") {
81
- const val = props.get_value(name);
82
- if (val && !deviceId) deviceId = String(val);
83
- }
84
- if (name === "group-id") {
85
- const val = props.get_value(name);
86
- if (val) groupId = String(val);
87
- }
88
- }
89
- }
90
- } catch {
91
- }
92
- if (!deviceId) {
93
- deviceId = displayName || `${kind}-${result.length}`;
94
- }
95
- if (_permissionGranted) {
96
- result.push(new MediaDeviceInfo({
97
- deviceId,
98
- kind,
99
- label: displayName,
100
- groupId
101
- }));
102
- } else {
103
- if (!result.some((d) => d.kind === kind)) {
104
- result.push(new MediaDeviceInfo({
105
- deviceId: "",
106
- kind,
107
- label: "",
108
- groupId: ""
109
- }));
110
- }
111
- }
112
- }
113
- } catch {
114
- return result;
115
- } finally {
116
- try {
117
- monitor?.stop();
118
- } catch {
119
- }
120
- }
121
- const order = { audioinput: 0, videoinput: 1, audiooutput: 2 };
122
- result.sort((a, b) => (order[a.kind] ?? 3) - (order[b.kind] ?? 3));
123
- return result;
124
- }
125
- getSupportedConstraints() {
126
- return {
127
- deviceId: true,
128
- width: true,
129
- height: true,
130
- frameRate: true,
131
- sampleRate: true,
132
- channelCount: true,
133
- // Not yet supported — return false
134
- aspectRatio: false,
135
- facingMode: false,
136
- resizeMode: false,
137
- echoCancellation: false,
138
- autoGainControl: false,
139
- noiseSuppression: false,
140
- latency: false,
141
- groupId: false
142
- };
143
- }
24
+ try {
25
+ const GLib = imports.gi.GLib;
26
+ if (GLib.getenv("CI")) return false;
27
+ if (!GLib.getenv("DISPLAY") && !GLib.getenv("WAYLAND_DISPLAY")) return false;
28
+ return true;
29
+ } catch {
30
+ return false;
31
+ }
144
32
  }
145
- export {
146
- MediaDevices
33
+ var MediaDevices = class extends EventTarget {
34
+ _ondevicechange = null;
35
+ get ondevicechange() {
36
+ return this._ondevicechange;
37
+ }
38
+ set ondevicechange(v) {
39
+ this._ondevicechange = v;
40
+ }
41
+ async getUserMedia(constraints) {
42
+ if (!constraints) {
43
+ throw new TypeError("Failed to execute 'getUserMedia' on 'MediaDevices': At least one of audio or video must be requested");
44
+ }
45
+ const stream = await getUserMedia(constraints);
46
+ _permissionGranted = true;
47
+ return stream;
48
+ }
49
+ async enumerateDevices() {
50
+ ensureGstInit();
51
+ let monitor = null;
52
+ const result = [];
53
+ try {
54
+ if (!isDeviceMonitorSafe()) {
55
+ return result;
56
+ }
57
+ monitor = new Gst.DeviceMonitor();
58
+ monitor.set_show_all_devices(true);
59
+ const audioCaps = Gst.Caps.from_string("audio/x-raw");
60
+ const videoCaps = Gst.Caps.from_string("video/x-raw");
61
+ if (audioCaps) {
62
+ monitor.add_filter("Audio/Source", audioCaps);
63
+ monitor.add_filter("Audio/Sink", audioCaps);
64
+ }
65
+ if (videoCaps) {
66
+ monitor.add_filter("Video/Source", videoCaps);
67
+ }
68
+ if (!monitor.start()) {
69
+ return result;
70
+ }
71
+ let gstDevices;
72
+ try {
73
+ gstDevices = monitor.get_devices() ?? [];
74
+ } catch {
75
+ return result;
76
+ }
77
+ for (const device of gstDevices) {
78
+ const deviceClass = device.get_device_class?.() ?? "";
79
+ const kind = DEVICE_CLASS_MAP[deviceClass];
80
+ if (!kind) continue;
81
+ const displayName = device.get_display_name?.() ?? "";
82
+ let deviceId = "";
83
+ let groupId = "";
84
+ try {
85
+ const props = device.get_properties?.();
86
+ if (props) {
87
+ const n = props.n_fields();
88
+ for (let i = 0; i < n; i++) {
89
+ const name = props.nth_field_name(i);
90
+ if (name === "persistent-id" || name === "node.name") {
91
+ const val = props.get_value(name);
92
+ if (val && !deviceId) deviceId = String(val);
93
+ }
94
+ if (name === "group-id") {
95
+ const val = props.get_value(name);
96
+ if (val) groupId = String(val);
97
+ }
98
+ }
99
+ }
100
+ } catch {}
101
+ if (!deviceId) {
102
+ deviceId = displayName || `${kind}-${result.length}`;
103
+ }
104
+ if (_permissionGranted) {
105
+ result.push(new MediaDeviceInfo({
106
+ deviceId,
107
+ kind,
108
+ label: displayName,
109
+ groupId
110
+ }));
111
+ } else {
112
+ if (!result.some((d) => d.kind === kind)) {
113
+ result.push(new MediaDeviceInfo({
114
+ deviceId: "",
115
+ kind,
116
+ label: "",
117
+ groupId: ""
118
+ }));
119
+ }
120
+ }
121
+ }
122
+ } catch {
123
+ return result;
124
+ } finally {
125
+ try {
126
+ monitor?.stop();
127
+ } catch {}
128
+ }
129
+ const order = {
130
+ audioinput: 0,
131
+ videoinput: 1,
132
+ audiooutput: 2
133
+ };
134
+ result.sort((a, b) => (order[a.kind] ?? 3) - (order[b.kind] ?? 3));
135
+ return result;
136
+ }
137
+ getSupportedConstraints() {
138
+ return {
139
+ deviceId: true,
140
+ width: true,
141
+ height: true,
142
+ frameRate: true,
143
+ sampleRate: true,
144
+ channelCount: true,
145
+ aspectRatio: false,
146
+ facingMode: false,
147
+ resizeMode: false,
148
+ echoCancellation: false,
149
+ autoGainControl: false,
150
+ noiseSuppression: false,
151
+ latency: false,
152
+ groupId: false
153
+ };
154
+ }
147
155
  };
156
+
157
+ //#endregion
158
+ export { MediaDevices };