@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.
- package/lib/esm/get-user-media.js +95 -80
- package/lib/esm/gst-enum-maps.js +55 -59
- package/lib/esm/gst-init.js +19 -22
- package/lib/esm/gst-stats-parser.js +94 -67
- package/lib/esm/gst-utils.js +24 -13
- package/lib/esm/index.js +13 -43
- package/lib/esm/media-device-info.js +23 -22
- package/lib/esm/media-devices.js +150 -139
- package/lib/esm/media-stream-track.js +136 -139
- package/lib/esm/media-stream.js +76 -75
- package/lib/esm/register/data-channel.js +7 -3
- package/lib/esm/register/error.js +6 -2
- package/lib/esm/register/media-devices.js +6 -2
- package/lib/esm/register/media.js +8 -4
- package/lib/esm/register/peer-connection.js +9 -5
- package/lib/esm/rtc-certificate.js +62 -66
- package/lib/esm/rtc-data-channel.js +240 -251
- package/lib/esm/rtc-dtls-transport.js +40 -39
- package/lib/esm/rtc-dtmf-sender.js +92 -100
- package/lib/esm/rtc-error.js +24 -22
- package/lib/esm/rtc-events.js +33 -33
- package/lib/esm/rtc-ice-candidate.js +71 -72
- package/lib/esm/rtc-ice-transport.js +95 -94
- package/lib/esm/rtc-peer-connection.js +796 -845
- package/lib/esm/rtc-rtp-receiver.js +89 -87
- package/lib/esm/rtc-rtp-sender.js +282 -290
- package/lib/esm/rtc-rtp-transceiver.js +92 -93
- package/lib/esm/rtc-sctp-transport.js +38 -38
- package/lib/esm/rtc-session-description.js +47 -51
- package/lib/esm/rtc-stats-report.js +39 -34
- package/lib/esm/rtc-track-event.js +29 -27
- package/lib/esm/rtp-capabilities.js +81 -35
- package/lib/esm/tee-multiplexer.js +58 -60
- package/lib/esm/wpt-helpers.js +128 -112
- package/package.json +13 -13
- package/tsconfig.tsbuildinfo +1 -1
package/lib/esm/index.js
CHANGED
|
@@ -1,53 +1,23 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
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
|
-
|
|
8
|
-
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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 };
|
package/lib/esm/media-devices.js
CHANGED
|
@@ -1,147 +1,158 @@
|
|
|
1
|
-
import "
|
|
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
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
|
|
146
|
-
|
|
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 };
|